134d97308SThomas Huth /* 234d97308SThomas Huth * QEMU USB OHCI Emulation 334d97308SThomas Huth * Copyright (c) 2004 Gianni Tedesco 434d97308SThomas Huth * Copyright (c) 2006 CodeSourcery 534d97308SThomas Huth * Copyright (c) 2006 Openedhand Ltd. 634d97308SThomas Huth * 734d97308SThomas Huth * This library is free software; you can redistribute it and/or 834d97308SThomas Huth * modify it under the terms of the GNU Lesser General Public 934d97308SThomas Huth * License as published by the Free Software Foundation; either 1034d97308SThomas Huth * version 2.1 of the License, or (at your option) any later version. 1134d97308SThomas Huth * 1234d97308SThomas Huth * This library is distributed in the hope that it will be useful, 1334d97308SThomas Huth * but WITHOUT ANY WARRANTY; without even the implied warranty of 1434d97308SThomas Huth * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1534d97308SThomas Huth * Lesser General Public License for more details. 1634d97308SThomas Huth * 1734d97308SThomas Huth * You should have received a copy of the GNU Lesser General Public 1834d97308SThomas Huth * License along with this library; if not, see <http://www.gnu.org/licenses/>. 1934d97308SThomas Huth */ 2034d97308SThomas Huth 2134d97308SThomas Huth #include "qemu/osdep.h" 2234d97308SThomas Huth #include "qapi/error.h" 2334d97308SThomas Huth #include "qemu/timer.h" 2434d97308SThomas Huth #include "hw/usb.h" 25d6454270SMarkus Armbruster #include "migration/vmstate.h" 2634d97308SThomas Huth #include "hw/pci/pci.h" 2734d97308SThomas Huth #include "hw/sysbus.h" 2834d97308SThomas Huth #include "hw/qdev-dma.h" 29a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 3034d97308SThomas Huth #include "trace.h" 3134d97308SThomas Huth #include "hcd-ohci.h" 3234d97308SThomas Huth 3334d97308SThomas Huth #define TYPE_PCI_OHCI "pci-ohci" 3434d97308SThomas Huth #define PCI_OHCI(obj) OBJECT_CHECK(OHCIPCIState, (obj), TYPE_PCI_OHCI) 3534d97308SThomas Huth 3634d97308SThomas Huth typedef struct { 3734d97308SThomas Huth /*< private >*/ 3834d97308SThomas Huth PCIDevice parent_obj; 3934d97308SThomas Huth /*< public >*/ 4034d97308SThomas Huth 4134d97308SThomas Huth OHCIState state; 4234d97308SThomas Huth char *masterbus; 4334d97308SThomas Huth uint32_t num_ports; 4434d97308SThomas Huth uint32_t firstport; 4534d97308SThomas Huth } OHCIPCIState; 4634d97308SThomas Huth 4734d97308SThomas Huth /** 4834d97308SThomas Huth * A typical PCI OHCI will additionally set PERR in its configspace to 4934d97308SThomas Huth * signal that it got an error. 5034d97308SThomas Huth */ 5134d97308SThomas Huth static void ohci_pci_die(struct OHCIState *ohci) 5234d97308SThomas Huth { 5334d97308SThomas Huth OHCIPCIState *dev = container_of(ohci, OHCIPCIState, state); 5434d97308SThomas Huth 5534d97308SThomas Huth ohci_sysbus_die(ohci); 5634d97308SThomas Huth 5734d97308SThomas Huth pci_set_word(dev->parent_obj.config + PCI_STATUS, 5834d97308SThomas Huth PCI_STATUS_DETECTED_PARITY); 5934d97308SThomas Huth } 6034d97308SThomas Huth 6134d97308SThomas Huth static void usb_ohci_realize_pci(PCIDevice *dev, Error **errp) 6234d97308SThomas Huth { 6334d97308SThomas Huth Error *err = NULL; 6434d97308SThomas Huth OHCIPCIState *ohci = PCI_OHCI(dev); 6534d97308SThomas Huth 6634d97308SThomas Huth dev->config[PCI_CLASS_PROG] = 0x10; /* OHCI */ 6734d97308SThomas Huth dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */ 6834d97308SThomas Huth 6934d97308SThomas Huth usb_ohci_init(&ohci->state, DEVICE(dev), ohci->num_ports, 0, 7034d97308SThomas Huth ohci->masterbus, ohci->firstport, 7134d97308SThomas Huth pci_get_address_space(dev), ohci_pci_die, &err); 7234d97308SThomas Huth if (err) { 7334d97308SThomas Huth error_propagate(errp, err); 7434d97308SThomas Huth return; 7534d97308SThomas Huth } 7634d97308SThomas Huth 7734d97308SThomas Huth ohci->state.irq = pci_allocate_irq(dev); 7834d97308SThomas Huth pci_register_bar(dev, 0, 0, &ohci->state.mem); 7934d97308SThomas Huth } 8034d97308SThomas Huth 8134d97308SThomas Huth static void usb_ohci_exit(PCIDevice *dev) 8234d97308SThomas Huth { 8334d97308SThomas Huth OHCIPCIState *ohci = PCI_OHCI(dev); 8434d97308SThomas Huth OHCIState *s = &ohci->state; 8534d97308SThomas Huth 8634d97308SThomas Huth trace_usb_ohci_exit(s->name); 8734d97308SThomas Huth ohci_bus_stop(s); 8834d97308SThomas Huth 8934d97308SThomas Huth if (s->async_td) { 9034d97308SThomas Huth usb_cancel_packet(&s->usb_packet); 9134d97308SThomas Huth s->async_td = 0; 9234d97308SThomas Huth } 9334d97308SThomas Huth ohci_stop_endpoints(s); 9434d97308SThomas Huth 9534d97308SThomas Huth if (!ohci->masterbus) { 9634d97308SThomas Huth usb_bus_release(&s->bus); 9734d97308SThomas Huth } 9834d97308SThomas Huth 9934d97308SThomas Huth timer_del(s->eof_timer); 10034d97308SThomas Huth timer_free(s->eof_timer); 10134d97308SThomas Huth } 10234d97308SThomas Huth 10334d97308SThomas Huth static void usb_ohci_reset_pci(DeviceState *d) 10434d97308SThomas Huth { 10534d97308SThomas Huth PCIDevice *dev = PCI_DEVICE(d); 10634d97308SThomas Huth OHCIPCIState *ohci = PCI_OHCI(dev); 10734d97308SThomas Huth OHCIState *s = &ohci->state; 10834d97308SThomas Huth 10934d97308SThomas Huth ohci_hard_reset(s); 11034d97308SThomas Huth } 11134d97308SThomas Huth 11234d97308SThomas Huth static Property ohci_pci_properties[] = { 11334d97308SThomas Huth DEFINE_PROP_STRING("masterbus", OHCIPCIState, masterbus), 11434d97308SThomas Huth DEFINE_PROP_UINT32("num-ports", OHCIPCIState, num_ports, 3), 11534d97308SThomas Huth DEFINE_PROP_UINT32("firstport", OHCIPCIState, firstport, 0), 11634d97308SThomas Huth DEFINE_PROP_END_OF_LIST(), 11734d97308SThomas Huth }; 11834d97308SThomas Huth 11934d97308SThomas Huth static const VMStateDescription vmstate_ohci = { 12034d97308SThomas Huth .name = "ohci", 12134d97308SThomas Huth .version_id = 1, 12234d97308SThomas Huth .minimum_version_id = 1, 12334d97308SThomas Huth .fields = (VMStateField[]) { 12434d97308SThomas Huth VMSTATE_PCI_DEVICE(parent_obj, OHCIPCIState), 12534d97308SThomas Huth VMSTATE_STRUCT(state, OHCIPCIState, 1, vmstate_ohci_state, OHCIState), 12634d97308SThomas Huth VMSTATE_END_OF_LIST() 12734d97308SThomas Huth } 12834d97308SThomas Huth }; 12934d97308SThomas Huth 13034d97308SThomas Huth static void ohci_pci_class_init(ObjectClass *klass, void *data) 13134d97308SThomas Huth { 13234d97308SThomas Huth DeviceClass *dc = DEVICE_CLASS(klass); 13334d97308SThomas Huth PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 13434d97308SThomas Huth 13534d97308SThomas Huth k->realize = usb_ohci_realize_pci; 13634d97308SThomas Huth k->exit = usb_ohci_exit; 13734d97308SThomas Huth k->vendor_id = PCI_VENDOR_ID_APPLE; 13834d97308SThomas Huth k->device_id = PCI_DEVICE_ID_APPLE_IPID_USB; 13934d97308SThomas Huth k->class_id = PCI_CLASS_SERIAL_USB; 14034d97308SThomas Huth set_bit(DEVICE_CATEGORY_USB, dc->categories); 14134d97308SThomas Huth dc->desc = "Apple USB Controller"; 142*4f67d30bSMarc-André Lureau device_class_set_props(dc, ohci_pci_properties); 14334d97308SThomas Huth dc->hotpluggable = false; 14434d97308SThomas Huth dc->vmsd = &vmstate_ohci; 14534d97308SThomas Huth dc->reset = usb_ohci_reset_pci; 14634d97308SThomas Huth } 14734d97308SThomas Huth 14834d97308SThomas Huth static const TypeInfo ohci_pci_info = { 14934d97308SThomas Huth .name = TYPE_PCI_OHCI, 15034d97308SThomas Huth .parent = TYPE_PCI_DEVICE, 15134d97308SThomas Huth .instance_size = sizeof(OHCIPCIState), 15234d97308SThomas Huth .class_init = ohci_pci_class_init, 15334d97308SThomas Huth .interfaces = (InterfaceInfo[]) { 15434d97308SThomas Huth { INTERFACE_CONVENTIONAL_PCI_DEVICE }, 15534d97308SThomas Huth { }, 15634d97308SThomas Huth }, 15734d97308SThomas Huth }; 15834d97308SThomas Huth 15934d97308SThomas Huth static void ohci_pci_register_types(void) 16034d97308SThomas Huth { 16134d97308SThomas Huth type_register_static(&ohci_pci_info); 16234d97308SThomas Huth } 16334d97308SThomas Huth 16434d97308SThomas Huth type_init(ohci_pci_register_types) 165