]>
Commit | Line | Data |
---|---|---|
34d97308 TH |
1 | /* |
2 | * QEMU USB OHCI Emulation | |
3 | * Copyright (c) 2004 Gianni Tedesco | |
4 | * Copyright (c) 2006 CodeSourcery | |
5 | * Copyright (c) 2006 Openedhand Ltd. | |
6 | * | |
7 | * This library is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2.1 of the License, or (at your option) any later version. | |
11 | * | |
12 | * This library is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
19 | */ | |
20 | ||
21 | #include "qemu/osdep.h" | |
34d97308 TH |
22 | #include "qapi/error.h" |
23 | #include "qemu/timer.h" | |
24 | #include "hw/usb.h" | |
d6454270 | 25 | #include "migration/vmstate.h" |
34d97308 TH |
26 | #include "hw/pci/pci.h" |
27 | #include "hw/sysbus.h" | |
28 | #include "hw/qdev-dma.h" | |
a27bd6c7 | 29 | #include "hw/qdev-properties.h" |
34d97308 TH |
30 | #include "trace.h" |
31 | #include "hcd-ohci.h" | |
32 | ||
33 | #define TYPE_PCI_OHCI "pci-ohci" | |
34 | #define PCI_OHCI(obj) OBJECT_CHECK(OHCIPCIState, (obj), TYPE_PCI_OHCI) | |
35 | ||
36 | typedef struct { | |
37 | /*< private >*/ | |
38 | PCIDevice parent_obj; | |
39 | /*< public >*/ | |
40 | ||
41 | OHCIState state; | |
42 | char *masterbus; | |
43 | uint32_t num_ports; | |
44 | uint32_t firstport; | |
45 | } OHCIPCIState; | |
46 | ||
47 | /** | |
48 | * A typical PCI OHCI will additionally set PERR in its configspace to | |
49 | * signal that it got an error. | |
50 | */ | |
51 | static void ohci_pci_die(struct OHCIState *ohci) | |
52 | { | |
53 | OHCIPCIState *dev = container_of(ohci, OHCIPCIState, state); | |
54 | ||
55 | ohci_sysbus_die(ohci); | |
56 | ||
57 | pci_set_word(dev->parent_obj.config + PCI_STATUS, | |
58 | PCI_STATUS_DETECTED_PARITY); | |
59 | } | |
60 | ||
61 | static void usb_ohci_realize_pci(PCIDevice *dev, Error **errp) | |
62 | { | |
63 | Error *err = NULL; | |
64 | OHCIPCIState *ohci = PCI_OHCI(dev); | |
65 | ||
66 | dev->config[PCI_CLASS_PROG] = 0x10; /* OHCI */ | |
67 | dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */ | |
68 | ||
69 | usb_ohci_init(&ohci->state, DEVICE(dev), ohci->num_ports, 0, | |
70 | ohci->masterbus, ohci->firstport, | |
71 | pci_get_address_space(dev), ohci_pci_die, &err); | |
72 | if (err) { | |
73 | error_propagate(errp, err); | |
74 | return; | |
75 | } | |
76 | ||
77 | ohci->state.irq = pci_allocate_irq(dev); | |
78 | pci_register_bar(dev, 0, 0, &ohci->state.mem); | |
79 | } | |
80 | ||
81 | static void usb_ohci_exit(PCIDevice *dev) | |
82 | { | |
83 | OHCIPCIState *ohci = PCI_OHCI(dev); | |
84 | OHCIState *s = &ohci->state; | |
85 | ||
86 | trace_usb_ohci_exit(s->name); | |
87 | ohci_bus_stop(s); | |
88 | ||
89 | if (s->async_td) { | |
90 | usb_cancel_packet(&s->usb_packet); | |
91 | s->async_td = 0; | |
92 | } | |
93 | ohci_stop_endpoints(s); | |
94 | ||
95 | if (!ohci->masterbus) { | |
96 | usb_bus_release(&s->bus); | |
97 | } | |
98 | ||
99 | timer_del(s->eof_timer); | |
100 | timer_free(s->eof_timer); | |
101 | } | |
102 | ||
103 | static void usb_ohci_reset_pci(DeviceState *d) | |
104 | { | |
105 | PCIDevice *dev = PCI_DEVICE(d); | |
106 | OHCIPCIState *ohci = PCI_OHCI(dev); | |
107 | OHCIState *s = &ohci->state; | |
108 | ||
109 | ohci_hard_reset(s); | |
110 | } | |
111 | ||
112 | static Property ohci_pci_properties[] = { | |
113 | DEFINE_PROP_STRING("masterbus", OHCIPCIState, masterbus), | |
114 | DEFINE_PROP_UINT32("num-ports", OHCIPCIState, num_ports, 3), | |
115 | DEFINE_PROP_UINT32("firstport", OHCIPCIState, firstport, 0), | |
116 | DEFINE_PROP_END_OF_LIST(), | |
117 | }; | |
118 | ||
119 | static const VMStateDescription vmstate_ohci = { | |
120 | .name = "ohci", | |
121 | .version_id = 1, | |
122 | .minimum_version_id = 1, | |
123 | .fields = (VMStateField[]) { | |
124 | VMSTATE_PCI_DEVICE(parent_obj, OHCIPCIState), | |
125 | VMSTATE_STRUCT(state, OHCIPCIState, 1, vmstate_ohci_state, OHCIState), | |
126 | VMSTATE_END_OF_LIST() | |
127 | } | |
128 | }; | |
129 | ||
130 | static void ohci_pci_class_init(ObjectClass *klass, void *data) | |
131 | { | |
132 | DeviceClass *dc = DEVICE_CLASS(klass); | |
133 | PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); | |
134 | ||
135 | k->realize = usb_ohci_realize_pci; | |
136 | k->exit = usb_ohci_exit; | |
137 | k->vendor_id = PCI_VENDOR_ID_APPLE; | |
138 | k->device_id = PCI_DEVICE_ID_APPLE_IPID_USB; | |
139 | k->class_id = PCI_CLASS_SERIAL_USB; | |
140 | set_bit(DEVICE_CATEGORY_USB, dc->categories); | |
141 | dc->desc = "Apple USB Controller"; | |
142 | dc->props = ohci_pci_properties; | |
143 | dc->hotpluggable = false; | |
144 | dc->vmsd = &vmstate_ohci; | |
145 | dc->reset = usb_ohci_reset_pci; | |
146 | } | |
147 | ||
148 | static const TypeInfo ohci_pci_info = { | |
149 | .name = TYPE_PCI_OHCI, | |
150 | .parent = TYPE_PCI_DEVICE, | |
151 | .instance_size = sizeof(OHCIPCIState), | |
152 | .class_init = ohci_pci_class_init, | |
153 | .interfaces = (InterfaceInfo[]) { | |
154 | { INTERFACE_CONVENTIONAL_PCI_DEVICE }, | |
155 | { }, | |
156 | }, | |
157 | }; | |
158 | ||
159 | static void ohci_pci_register_types(void) | |
160 | { | |
161 | type_register_static(&ohci_pci_info); | |
162 | } | |
163 | ||
164 | type_init(ohci_pci_register_types) |