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,
1233abedf29SRichard 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;
145*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, 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