1 /*
2 * USB UHCI controller emulation
3 * PCI code
4 *
5 * Copyright (c) 2005 Fabrice Bellard
6 *
7 * Copyright (c) 2008 Max Krasnyansky
8 * Magor rewrite of the UHCI data structures parser and frame processor
9 * Support for fully async operation and multiple outstanding transactions
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this software and associated documentation files (the "Software"), to deal
13 * in the Software without restriction, including without limitation the rights
14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 * copies of the Software, and to permit persons to whom the Software is
16 * furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 * THE SOFTWARE.
28 */
29
30 #include "qemu/osdep.h"
31 #include "hw/irq.h"
32 #include "hw/usb.h"
33 #include "migration/vmstate.h"
34 #include "hw/pci/pci.h"
35 #include "hw/qdev-properties.h"
36 #include "qapi/error.h"
37 #include "qemu/main-loop.h"
38 #include "qemu/module.h"
39 #include "qom/object.h"
40 #include "hcd-uhci-pci.h"
41
42 struct UHCIPCIDeviceClass {
43 PCIDeviceClass parent_class;
44 UHCIPCIInfo info;
45 };
46
47 static const VMStateDescription vmstate_uhci = {
48 .name = "pci_uhci",
49 .version_id = 1,
50 .minimum_version_id = 1,
51 .fields = (const VMStateField[]) {
52 VMSTATE_PCI_DEVICE(dev, UHCIPCIState),
53 VMSTATE_STRUCT(state, UHCIPCIState, 1, vmstate_uhci_state, UHCIState),
54 VMSTATE_END_OF_LIST()
55 }
56 };
57
uhci_pci_reset(UHCIState * uhci)58 static void uhci_pci_reset(UHCIState *uhci)
59 {
60 UHCIPCIState *pstate = container_of(uhci, UHCIPCIState, state);
61 PCIDevice *d = &pstate->dev;
62
63 d->config[0x6a] = 0x01; /* usb clock */
64 d->config[0x6b] = 0x00;
65
66 uhci_state_reset(uhci);
67 }
68
usb_uhci_common_realize_pci(PCIDevice * dev,Error ** errp)69 void usb_uhci_common_realize_pci(PCIDevice *dev, Error **errp)
70 {
71 Error *err = NULL;
72 UHCIPCIDeviceClass *u = UHCI_PCI_GET_CLASS(dev);
73 UHCIPCIState *uhci = UHCI_PCI(dev);
74 UHCIState *s = &uhci->state;
75 uint8_t *pci_conf = dev->config;
76
77 pci_conf[PCI_CLASS_PROG] = 0x00;
78 /* TODO: reset value should be 0. */
79 pci_conf[USB_SBRN] = USB_RELEASE_1; /* release number */
80 pci_config_set_interrupt_pin(pci_conf, u->info.irq_pin + 1);
81
82 s->irq = pci_allocate_irq(dev);
83 s->masterbus = uhci->masterbus;
84 s->firstport = uhci->firstport;
85 s->maxframes = uhci->maxframes;
86 s->frame_bandwidth = uhci->frame_bandwidth;
87 s->as = pci_get_address_space(dev);
88 s->uhci_reset = uhci_pci_reset;
89
90 usb_uhci_init(s, DEVICE(dev), &err);
91
92 /*
93 * Use region 4 for consistency with real hardware. BSD guests seem
94 * to rely on this.
95 */
96 pci_register_bar(dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &s->mem);
97 }
98
uhci_pci_reset_pci(DeviceState * dev)99 static void uhci_pci_reset_pci(DeviceState *dev)
100 {
101 PCIDevice *d = PCI_DEVICE(dev);
102 UHCIPCIState *uhci = UHCI_PCI(d);
103
104 uhci_pci_reset(&uhci->state);
105 }
106
usb_uhci_pci_exit(PCIDevice * dev)107 static void usb_uhci_pci_exit(PCIDevice *dev)
108 {
109 UHCIPCIState *uhci = UHCI_PCI(dev);
110 UHCIState *s = &uhci->state;
111
112 usb_uhci_exit(s);
113
114 qemu_free_irq(s->irq);
115 }
116
117 static Property uhci_properties_companion[] = {
118 DEFINE_PROP_STRING("masterbus", UHCIPCIState, masterbus),
119 DEFINE_PROP_UINT32("firstport", UHCIPCIState, firstport, 0),
120 DEFINE_PROP_UINT32("bandwidth", UHCIPCIState, frame_bandwidth, 1280),
121 DEFINE_PROP_UINT32("maxframes", UHCIPCIState, maxframes, 128),
122 DEFINE_PROP_END_OF_LIST(),
123 };
124 static Property uhci_properties_standalone[] = {
125 DEFINE_PROP_UINT32("bandwidth", UHCIPCIState, frame_bandwidth, 1280),
126 DEFINE_PROP_UINT32("maxframes", UHCIPCIState, maxframes, 128),
127 DEFINE_PROP_END_OF_LIST(),
128 };
129
uhci_pci_class_init(ObjectClass * klass,void * data)130 static void uhci_pci_class_init(ObjectClass *klass, void *data)
131 {
132 DeviceClass *dc = DEVICE_CLASS(klass);
133 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
134
135 k->class_id = PCI_CLASS_SERIAL_USB;
136 dc->vmsd = &vmstate_uhci;
137 device_class_set_legacy_reset(dc, uhci_pci_reset_pci);
138 set_bit(DEVICE_CATEGORY_USB, dc->categories);
139 }
140
141 static const TypeInfo uhci_pci_type_info = {
142 .name = TYPE_UHCI_PCI,
143 .parent = TYPE_PCI_DEVICE,
144 .instance_size = sizeof(UHCIPCIState),
145 .class_size = sizeof(UHCIPCIDeviceClass),
146 .class_init = uhci_pci_class_init,
147 .interfaces = (InterfaceInfo[]) {
148 { INTERFACE_CONVENTIONAL_PCI_DEVICE },
149 { },
150 },
151 };
152
uhci_pci_data_class_init(ObjectClass * klass,void * data)153 void uhci_pci_data_class_init(ObjectClass *klass, void *data)
154 {
155 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
156 DeviceClass *dc = DEVICE_CLASS(klass);
157 UHCIPCIDeviceClass *u = UHCI_PCI_CLASS(klass);
158 UHCIPCIInfo *info = data;
159
160 k->realize = info->realize ? info->realize : usb_uhci_common_realize_pci;
161 k->exit = info->unplug ? usb_uhci_pci_exit : NULL;
162 k->vendor_id = info->vendor_id;
163 k->device_id = info->device_id;
164 k->revision = info->revision;
165 if (!info->unplug) {
166 /* uhci controllers in companion setups can't be hotplugged */
167 dc->hotpluggable = false;
168 device_class_set_props(dc, uhci_properties_companion);
169 } else {
170 device_class_set_props(dc, uhci_properties_standalone);
171 }
172 if (info->notuser) {
173 dc->user_creatable = false;
174 }
175 u->info = *info;
176 }
177
178 static UHCIPCIInfo uhci_pci_info[] = {
179 {
180 .name = TYPE_PIIX3_USB_UHCI,
181 .vendor_id = PCI_VENDOR_ID_INTEL,
182 .device_id = PCI_DEVICE_ID_INTEL_82371SB_2,
183 .revision = 0x01,
184 .irq_pin = 3,
185 .unplug = true,
186 },{
187 .name = TYPE_PIIX4_USB_UHCI,
188 .vendor_id = PCI_VENDOR_ID_INTEL,
189 .device_id = PCI_DEVICE_ID_INTEL_82371AB_2,
190 .revision = 0x01,
191 .irq_pin = 3,
192 .unplug = true,
193 },{
194 .name = TYPE_ICH9_USB_UHCI(1), /* 00:1d.0 */
195 .vendor_id = PCI_VENDOR_ID_INTEL,
196 .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI1,
197 .revision = 0x03,
198 .irq_pin = 0,
199 .unplug = false,
200 },{
201 .name = TYPE_ICH9_USB_UHCI(2), /* 00:1d.1 */
202 .vendor_id = PCI_VENDOR_ID_INTEL,
203 .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI2,
204 .revision = 0x03,
205 .irq_pin = 1,
206 .unplug = false,
207 },{
208 .name = TYPE_ICH9_USB_UHCI(3), /* 00:1d.2 */
209 .vendor_id = PCI_VENDOR_ID_INTEL,
210 .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI3,
211 .revision = 0x03,
212 .irq_pin = 2,
213 .unplug = false,
214 },{
215 .name = TYPE_ICH9_USB_UHCI(4), /* 00:1a.0 */
216 .vendor_id = PCI_VENDOR_ID_INTEL,
217 .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI4,
218 .revision = 0x03,
219 .irq_pin = 0,
220 .unplug = false,
221 },{
222 .name = TYPE_ICH9_USB_UHCI(5), /* 00:1a.1 */
223 .vendor_id = PCI_VENDOR_ID_INTEL,
224 .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI5,
225 .revision = 0x03,
226 .irq_pin = 1,
227 .unplug = false,
228 },{
229 .name = TYPE_ICH9_USB_UHCI(6), /* 00:1a.2 */
230 .vendor_id = PCI_VENDOR_ID_INTEL,
231 .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI6,
232 .revision = 0x03,
233 .irq_pin = 2,
234 .unplug = false,
235 }
236 };
237
uhci_pci_register_types(void)238 static void uhci_pci_register_types(void)
239 {
240 TypeInfo type_info = {
241 .parent = TYPE_UHCI_PCI,
242 .class_init = uhci_pci_data_class_init,
243 };
244 int i;
245
246 type_register_static(&uhci_pci_type_info);
247
248 for (i = 0; i < ARRAY_SIZE(uhci_pci_info); i++) {
249 type_info.name = uhci_pci_info[i].name;
250 type_info.class_data = uhci_pci_info + i;
251 type_register(&type_info);
252 }
253 }
254
255 type_init(uhci_pci_register_types)
256