1 | /* |
2 | * QEMU USB EHCI Emulation |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2.1 of the License, or (at your option) any later version. |
8 | * |
9 | * This library is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General Public License |
15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
16 | */ |
17 | |
18 | #include "qemu/osdep.h" |
19 | #include "hw/qdev-properties.h" |
20 | #include "hw/usb/hcd-ehci.h" |
21 | #include "migration/vmstate.h" |
22 | #include "qemu/module.h" |
23 | #include "qemu/range.h" |
24 | |
25 | typedef struct EHCIPCIInfo { |
26 | const char *name; |
27 | uint16_t vendor_id; |
28 | uint16_t device_id; |
29 | uint8_t revision; |
30 | bool companion; |
31 | } EHCIPCIInfo; |
32 | |
33 | static void usb_ehci_pci_realize(PCIDevice *dev, Error **errp) |
34 | { |
35 | EHCIPCIState *i = PCI_EHCI(dev); |
36 | EHCIState *s = &i->ehci; |
37 | uint8_t *pci_conf = dev->config; |
38 | |
39 | pci_set_byte(&pci_conf[PCI_CLASS_PROG], 0x20); |
40 | |
41 | /* capabilities pointer */ |
42 | pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x00); |
43 | /* pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x50); */ |
44 | |
45 | pci_set_byte(&pci_conf[PCI_INTERRUPT_PIN], 4); /* interrupt pin D */ |
46 | pci_set_byte(&pci_conf[PCI_MIN_GNT], 0); |
47 | pci_set_byte(&pci_conf[PCI_MAX_LAT], 0); |
48 | |
49 | /* pci_conf[0x50] = 0x01; *//* power management caps */ |
50 | |
51 | pci_set_byte(&pci_conf[USB_SBRN], USB_RELEASE_2); /* release # (2.1.4) */ |
52 | pci_set_byte(&pci_conf[0x61], 0x20); /* frame length adjustment (2.1.5) */ |
53 | pci_set_word(&pci_conf[0x62], 0x00); /* port wake up capability (2.1.6) */ |
54 | |
55 | pci_conf[0x64] = 0x00; |
56 | pci_conf[0x65] = 0x00; |
57 | pci_conf[0x66] = 0x00; |
58 | pci_conf[0x67] = 0x00; |
59 | pci_conf[0x68] = 0x01; |
60 | pci_conf[0x69] = 0x00; |
61 | pci_conf[0x6a] = 0x00; |
62 | pci_conf[0x6b] = 0x00; /* USBLEGSUP */ |
63 | pci_conf[0x6c] = 0x00; |
64 | pci_conf[0x6d] = 0x00; |
65 | pci_conf[0x6e] = 0x00; |
66 | pci_conf[0x6f] = 0xc0; /* USBLEFCTLSTS */ |
67 | |
68 | s->irq = pci_allocate_irq(dev); |
69 | s->as = pci_get_address_space(dev); |
70 | |
71 | usb_ehci_realize(s, DEVICE(dev), NULL); |
72 | pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem); |
73 | } |
74 | |
75 | static void usb_ehci_pci_init(Object *obj) |
76 | { |
77 | DeviceClass *dc = OBJECT_GET_CLASS(DeviceClass, obj, TYPE_DEVICE); |
78 | EHCIPCIState *i = PCI_EHCI(obj); |
79 | EHCIState *s = &i->ehci; |
80 | |
81 | s->caps[0x09] = 0x68; /* EECP */ |
82 | |
83 | s->capsbase = 0x00; |
84 | s->opregbase = 0x20; |
85 | s->portscbase = 0x44; |
86 | s->portnr = NB_PORTS; |
87 | |
88 | if (!dc->hotpluggable) { |
89 | s->companion_enable = true; |
90 | } |
91 | |
92 | usb_ehci_init(s, DEVICE(obj)); |
93 | } |
94 | |
95 | static void usb_ehci_pci_finalize(Object *obj) |
96 | { |
97 | EHCIPCIState *i = PCI_EHCI(obj); |
98 | EHCIState *s = &i->ehci; |
99 | |
100 | usb_ehci_finalize(s); |
101 | } |
102 | |
103 | static void usb_ehci_pci_exit(PCIDevice *dev) |
104 | { |
105 | EHCIPCIState *i = PCI_EHCI(dev); |
106 | EHCIState *s = &i->ehci; |
107 | |
108 | usb_ehci_unrealize(s, DEVICE(dev), NULL); |
109 | |
110 | g_free(s->irq); |
111 | s->irq = NULL; |
112 | } |
113 | |
114 | static void usb_ehci_pci_reset(DeviceState *dev) |
115 | { |
116 | PCIDevice *pci_dev = PCI_DEVICE(dev); |
117 | EHCIPCIState *i = PCI_EHCI(pci_dev); |
118 | EHCIState *s = &i->ehci; |
119 | |
120 | ehci_reset(s); |
121 | } |
122 | |
123 | static void usb_ehci_pci_write_config(PCIDevice *dev, uint32_t addr, |
124 | uint32_t val, int l) |
125 | { |
126 | EHCIPCIState *i = PCI_EHCI(dev); |
127 | bool busmaster; |
128 | |
129 | pci_default_write_config(dev, addr, val, l); |
130 | |
131 | if (!range_covers_byte(addr, l, PCI_COMMAND)) { |
132 | return; |
133 | } |
134 | busmaster = pci_get_word(dev->config + PCI_COMMAND) & PCI_COMMAND_MASTER; |
135 | i->ehci.as = busmaster ? pci_get_address_space(dev) : &address_space_memory; |
136 | } |
137 | |
138 | static Property ehci_pci_properties[] = { |
139 | DEFINE_PROP_UINT32("maxframes" , EHCIPCIState, ehci.maxframes, 128), |
140 | DEFINE_PROP_END_OF_LIST(), |
141 | }; |
142 | |
143 | static const VMStateDescription vmstate_ehci_pci = { |
144 | .name = "ehci" , |
145 | .version_id = 2, |
146 | .minimum_version_id = 1, |
147 | .fields = (VMStateField[]) { |
148 | VMSTATE_PCI_DEVICE(pcidev, EHCIPCIState), |
149 | VMSTATE_STRUCT(ehci, EHCIPCIState, 2, vmstate_ehci, EHCIState), |
150 | VMSTATE_END_OF_LIST() |
151 | } |
152 | }; |
153 | |
154 | static void ehci_class_init(ObjectClass *klass, void *data) |
155 | { |
156 | DeviceClass *dc = DEVICE_CLASS(klass); |
157 | PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); |
158 | |
159 | k->realize = usb_ehci_pci_realize; |
160 | k->exit = usb_ehci_pci_exit; |
161 | k->class_id = PCI_CLASS_SERIAL_USB; |
162 | k->config_write = usb_ehci_pci_write_config; |
163 | dc->vmsd = &vmstate_ehci_pci; |
164 | dc->props = ehci_pci_properties; |
165 | dc->reset = usb_ehci_pci_reset; |
166 | } |
167 | |
168 | static const TypeInfo ehci_pci_type_info = { |
169 | .name = TYPE_PCI_EHCI, |
170 | .parent = TYPE_PCI_DEVICE, |
171 | .instance_size = sizeof(EHCIPCIState), |
172 | .instance_init = usb_ehci_pci_init, |
173 | .instance_finalize = usb_ehci_pci_finalize, |
174 | .abstract = true, |
175 | .class_init = ehci_class_init, |
176 | .interfaces = (InterfaceInfo[]) { |
177 | { INTERFACE_CONVENTIONAL_PCI_DEVICE }, |
178 | { }, |
179 | }, |
180 | }; |
181 | |
182 | static void ehci_data_class_init(ObjectClass *klass, void *data) |
183 | { |
184 | PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); |
185 | DeviceClass *dc = DEVICE_CLASS(klass); |
186 | EHCIPCIInfo *i = data; |
187 | |
188 | k->vendor_id = i->vendor_id; |
189 | k->device_id = i->device_id; |
190 | k->revision = i->revision; |
191 | set_bit(DEVICE_CATEGORY_USB, dc->categories); |
192 | if (i->companion) { |
193 | dc->hotpluggable = false; |
194 | } |
195 | } |
196 | |
197 | static struct EHCIPCIInfo ehci_pci_info[] = { |
198 | { |
199 | .name = "usb-ehci" , |
200 | .vendor_id = PCI_VENDOR_ID_INTEL, |
201 | .device_id = PCI_DEVICE_ID_INTEL_82801D, /* ich4 */ |
202 | .revision = 0x10, |
203 | },{ |
204 | .name = "ich9-usb-ehci1" , /* 00:1d.7 */ |
205 | .vendor_id = PCI_VENDOR_ID_INTEL, |
206 | .device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1, |
207 | .revision = 0x03, |
208 | .companion = true, |
209 | },{ |
210 | .name = "ich9-usb-ehci2" , /* 00:1a.7 */ |
211 | .vendor_id = PCI_VENDOR_ID_INTEL, |
212 | .device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI2, |
213 | .revision = 0x03, |
214 | .companion = true, |
215 | } |
216 | }; |
217 | |
218 | static void ehci_pci_register_types(void) |
219 | { |
220 | TypeInfo ehci_type_info = { |
221 | .parent = TYPE_PCI_EHCI, |
222 | .class_init = ehci_data_class_init, |
223 | }; |
224 | int i; |
225 | |
226 | type_register_static(&ehci_pci_type_info); |
227 | |
228 | for (i = 0; i < ARRAY_SIZE(ehci_pci_info); i++) { |
229 | ehci_type_info.name = ehci_pci_info[i].name; |
230 | ehci_type_info.class_data = ehci_pci_info + i; |
231 | type_register(&ehci_type_info); |
232 | } |
233 | } |
234 | |
235 | type_init(ehci_pci_register_types) |
236 | |