xref: /qemu/hw/usb/hcd-ohci-pci.c (revision 3abedf29)
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"
26edf5ca5dSMarkus Armbruster #include "hw/pci/pci_device.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"
32db1015e9SEduardo Habkost #include "qom/object.h"
3334d97308SThomas Huth 
3434d97308SThomas Huth #define TYPE_PCI_OHCI "pci-ohci"
358063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(OHCIPCIState, PCI_OHCI)
3634d97308SThomas Huth 
37db1015e9SEduardo Habkost struct OHCIPCIState {
3834d97308SThomas Huth     /*< private >*/
3934d97308SThomas Huth     PCIDevice parent_obj;
4034d97308SThomas Huth     /*< public >*/
4134d97308SThomas Huth 
4234d97308SThomas Huth     OHCIState state;
4334d97308SThomas Huth     char *masterbus;
4434d97308SThomas Huth     uint32_t num_ports;
4534d97308SThomas Huth     uint32_t firstport;
46db1015e9SEduardo Habkost };
4734d97308SThomas Huth 
4834d97308SThomas Huth /**
4934d97308SThomas Huth  * A typical PCI OHCI will additionally set PERR in its configspace to
5034d97308SThomas Huth  * signal that it got an error.
5134d97308SThomas Huth  */
ohci_pci_die(struct OHCIState * ohci)5234d97308SThomas Huth static void ohci_pci_die(struct OHCIState *ohci)
5334d97308SThomas Huth {
5434d97308SThomas Huth     OHCIPCIState *dev = container_of(ohci, OHCIPCIState, state);
5534d97308SThomas Huth 
5634d97308SThomas Huth     ohci_sysbus_die(ohci);
5734d97308SThomas Huth 
5834d97308SThomas Huth     pci_set_word(dev->parent_obj.config + PCI_STATUS,
5934d97308SThomas Huth                  PCI_STATUS_DETECTED_PARITY);
6034d97308SThomas Huth }
6134d97308SThomas Huth 
usb_ohci_realize_pci(PCIDevice * dev,Error ** errp)6234d97308SThomas Huth static void usb_ohci_realize_pci(PCIDevice *dev, Error **errp)
6334d97308SThomas Huth {
6434d97308SThomas Huth     Error *err = NULL;
6534d97308SThomas Huth     OHCIPCIState *ohci = PCI_OHCI(dev);
6634d97308SThomas Huth 
6734d97308SThomas Huth     dev->config[PCI_CLASS_PROG] = 0x10; /* OHCI */
6834d97308SThomas Huth     dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
6934d97308SThomas Huth 
7034d97308SThomas Huth     usb_ohci_init(&ohci->state, DEVICE(dev), ohci->num_ports, 0,
7134d97308SThomas Huth                   ohci->masterbus, ohci->firstport,
7234d97308SThomas Huth                   pci_get_address_space(dev), ohci_pci_die, &err);
7334d97308SThomas Huth     if (err) {
7434d97308SThomas Huth         error_propagate(errp, err);
7534d97308SThomas Huth         return;
7634d97308SThomas Huth     }
7734d97308SThomas Huth 
7834d97308SThomas Huth     ohci->state.irq = pci_allocate_irq(dev);
7934d97308SThomas Huth     pci_register_bar(dev, 0, 0, &ohci->state.mem);
8034d97308SThomas Huth }
8134d97308SThomas Huth 
usb_ohci_exit(PCIDevice * dev)8234d97308SThomas Huth static void usb_ohci_exit(PCIDevice *dev)
8334d97308SThomas Huth {
8434d97308SThomas Huth     OHCIPCIState *ohci = PCI_OHCI(dev);
8534d97308SThomas Huth     OHCIState *s = &ohci->state;
8634d97308SThomas Huth 
8734d97308SThomas Huth     trace_usb_ohci_exit(s->name);
8834d97308SThomas Huth     ohci_bus_stop(s);
8934d97308SThomas Huth 
9034d97308SThomas Huth     if (s->async_td) {
9134d97308SThomas Huth         usb_cancel_packet(&s->usb_packet);
9234d97308SThomas Huth         s->async_td = 0;
9334d97308SThomas Huth     }
9434d97308SThomas Huth     ohci_stop_endpoints(s);
9534d97308SThomas Huth 
9634d97308SThomas Huth     if (!ohci->masterbus) {
9734d97308SThomas Huth         usb_bus_release(&s->bus);
9834d97308SThomas Huth     }
9934d97308SThomas Huth 
10034d97308SThomas Huth     timer_free(s->eof_timer);
10134d97308SThomas Huth }
10234d97308SThomas Huth 
usb_ohci_reset_pci(DeviceState * d)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,
123*3abedf29SRichard Henderson     .fields = (const 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 
ohci_pci_class_init(ObjectClass * klass,void * data)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";
1424f67d30bSMarc-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 
ohci_pci_register_types(void)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