root / hw / usb / hcd-ehci-pci.c @ ae12e3a6
History | View | Annotate | Download (6.5 kB)
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 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 General Public License
|
15 |
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
16 |
*/
|
17 |
|
18 |
#include "hw/usb/hcd-ehci.h" |
19 |
#include "qemu/range.h" |
20 |
|
21 |
typedef struct EHCIPCIInfo { |
22 |
const char *name; |
23 |
uint16_t vendor_id; |
24 |
uint16_t device_id; |
25 |
uint8_t revision; |
26 |
} EHCIPCIInfo; |
27 |
|
28 |
static int usb_ehci_pci_initfn(PCIDevice *dev) |
29 |
{ |
30 |
EHCIPCIState *i = PCI_EHCI(dev); |
31 |
EHCIState *s = &i->ehci; |
32 |
uint8_t *pci_conf = dev->config; |
33 |
|
34 |
pci_set_byte(&pci_conf[PCI_CLASS_PROG], 0x20);
|
35 |
|
36 |
/* capabilities pointer */
|
37 |
pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x00);
|
38 |
/* pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x50); */
|
39 |
|
40 |
pci_set_byte(&pci_conf[PCI_INTERRUPT_PIN], 4); /* interrupt pin D */ |
41 |
pci_set_byte(&pci_conf[PCI_MIN_GNT], 0);
|
42 |
pci_set_byte(&pci_conf[PCI_MAX_LAT], 0);
|
43 |
|
44 |
/* pci_conf[0x50] = 0x01; *//* power management caps */ |
45 |
|
46 |
pci_set_byte(&pci_conf[USB_SBRN], USB_RELEASE_2); /* release # (2.1.4) */
|
47 |
pci_set_byte(&pci_conf[0x61], 0x20); /* frame length adjustment (2.1.5) */ |
48 |
pci_set_word(&pci_conf[0x62], 0x00); /* port wake up capability (2.1.6) */ |
49 |
|
50 |
pci_conf[0x64] = 0x00; |
51 |
pci_conf[0x65] = 0x00; |
52 |
pci_conf[0x66] = 0x00; |
53 |
pci_conf[0x67] = 0x00; |
54 |
pci_conf[0x68] = 0x01; |
55 |
pci_conf[0x69] = 0x00; |
56 |
pci_conf[0x6a] = 0x00; |
57 |
pci_conf[0x6b] = 0x00; /* USBLEGSUP */ |
58 |
pci_conf[0x6c] = 0x00; |
59 |
pci_conf[0x6d] = 0x00; |
60 |
pci_conf[0x6e] = 0x00; |
61 |
pci_conf[0x6f] = 0xc0; /* USBLEFCTLSTS */ |
62 |
|
63 |
s->caps[0x09] = 0x68; /* EECP */ |
64 |
|
65 |
s->irq = dev->irq[3];
|
66 |
s->dma = pci_dma_context(dev); |
67 |
|
68 |
s->capsbase = 0x00;
|
69 |
s->opregbase = 0x20;
|
70 |
|
71 |
usb_ehci_initfn(s, DEVICE(dev)); |
72 |
pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
|
73 |
|
74 |
return 0; |
75 |
} |
76 |
|
77 |
static void usb_ehci_pci_write_config(PCIDevice *dev, uint32_t addr, |
78 |
uint32_t val, int l)
|
79 |
{ |
80 |
EHCIPCIState *i = PCI_EHCI(dev); |
81 |
bool busmaster;
|
82 |
|
83 |
pci_default_write_config(dev, addr, val, l); |
84 |
|
85 |
if (!range_covers_byte(addr, l, PCI_COMMAND)) {
|
86 |
return;
|
87 |
} |
88 |
busmaster = pci_get_word(dev->config + PCI_COMMAND) & PCI_COMMAND_MASTER; |
89 |
i->ehci.dma = busmaster ? pci_dma_context(dev) : NULL;
|
90 |
} |
91 |
|
92 |
static Property ehci_pci_properties[] = {
|
93 |
DEFINE_PROP_UINT32("maxframes", EHCIPCIState, ehci.maxframes, 128), |
94 |
DEFINE_PROP_END_OF_LIST(), |
95 |
}; |
96 |
|
97 |
static const VMStateDescription vmstate_ehci_pci = { |
98 |
.name = "ehci",
|
99 |
.version_id = 2,
|
100 |
.minimum_version_id = 1,
|
101 |
.fields = (VMStateField[]) { |
102 |
VMSTATE_PCI_DEVICE(pcidev, EHCIPCIState), |
103 |
VMSTATE_STRUCT(ehci, EHCIPCIState, 2, vmstate_ehci, EHCIState),
|
104 |
VMSTATE_END_OF_LIST() |
105 |
} |
106 |
}; |
107 |
|
108 |
static void ehci_class_init(ObjectClass *klass, void *data) |
109 |
{ |
110 |
DeviceClass *dc = DEVICE_CLASS(klass); |
111 |
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); |
112 |
|
113 |
k->init = usb_ehci_pci_initfn; |
114 |
k->class_id = PCI_CLASS_SERIAL_USB; |
115 |
k->config_write = usb_ehci_pci_write_config; |
116 |
k->no_hotplug = 1;
|
117 |
dc->vmsd = &vmstate_ehci_pci; |
118 |
dc->props = ehci_pci_properties; |
119 |
} |
120 |
|
121 |
static const TypeInfo ehci_pci_type_info = { |
122 |
.name = TYPE_PCI_EHCI, |
123 |
.parent = TYPE_PCI_DEVICE, |
124 |
.instance_size = sizeof(EHCIPCIState),
|
125 |
.abstract = true,
|
126 |
.class_init = ehci_class_init, |
127 |
}; |
128 |
|
129 |
static void ehci_data_class_init(ObjectClass *klass, void *data) |
130 |
{ |
131 |
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); |
132 |
EHCIPCIInfo *i = data; |
133 |
|
134 |
k->vendor_id = i->vendor_id; |
135 |
k->device_id = i->device_id; |
136 |
k->revision = i->revision; |
137 |
} |
138 |
|
139 |
static struct EHCIPCIInfo ehci_pci_info[] = { |
140 |
{ |
141 |
.name = "usb-ehci",
|
142 |
.vendor_id = PCI_VENDOR_ID_INTEL, |
143 |
.device_id = PCI_DEVICE_ID_INTEL_82801D, /* ich4 */
|
144 |
.revision = 0x10,
|
145 |
},{ |
146 |
.name = "ich9-usb-ehci1", /* 00:1d.7 */ |
147 |
.vendor_id = PCI_VENDOR_ID_INTEL, |
148 |
.device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1, |
149 |
.revision = 0x03,
|
150 |
},{ |
151 |
.name = "ich9-usb-ehci2", /* 00:1a.7 */ |
152 |
.vendor_id = PCI_VENDOR_ID_INTEL, |
153 |
.device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI2, |
154 |
.revision = 0x03,
|
155 |
} |
156 |
}; |
157 |
|
158 |
static void ehci_pci_register_types(void) |
159 |
{ |
160 |
TypeInfo ehci_type_info = { |
161 |
.parent = TYPE_PCI_EHCI, |
162 |
.class_init = ehci_data_class_init, |
163 |
}; |
164 |
int i;
|
165 |
|
166 |
type_register_static(&ehci_pci_type_info); |
167 |
|
168 |
for (i = 0; i < ARRAY_SIZE(ehci_pci_info); i++) { |
169 |
ehci_type_info.name = ehci_pci_info[i].name; |
170 |
ehci_type_info.class_data = ehci_pci_info + i; |
171 |
type_register(&ehci_type_info); |
172 |
} |
173 |
} |
174 |
|
175 |
type_init(ehci_pci_register_types) |
176 |
|
177 |
struct ehci_companions {
|
178 |
const char *name; |
179 |
int func;
|
180 |
int port;
|
181 |
}; |
182 |
|
183 |
static const struct ehci_companions ich9_1d[] = { |
184 |
{ .name = "ich9-usb-uhci1", .func = 0, .port = 0 }, |
185 |
{ .name = "ich9-usb-uhci2", .func = 1, .port = 2 }, |
186 |
{ .name = "ich9-usb-uhci3", .func = 2, .port = 4 }, |
187 |
}; |
188 |
|
189 |
static const struct ehci_companions ich9_1a[] = { |
190 |
{ .name = "ich9-usb-uhci4", .func = 0, .port = 0 }, |
191 |
{ .name = "ich9-usb-uhci5", .func = 1, .port = 2 }, |
192 |
{ .name = "ich9-usb-uhci6", .func = 2, .port = 4 }, |
193 |
}; |
194 |
|
195 |
int ehci_create_ich9_with_companions(PCIBus *bus, int slot) |
196 |
{ |
197 |
const struct ehci_companions *comp; |
198 |
PCIDevice *ehci, *uhci; |
199 |
BusState *usbbus; |
200 |
const char *name; |
201 |
int i;
|
202 |
|
203 |
switch (slot) {
|
204 |
case 0x1d: |
205 |
name = "ich9-usb-ehci1";
|
206 |
comp = ich9_1d; |
207 |
break;
|
208 |
case 0x1a: |
209 |
name = "ich9-usb-ehci2";
|
210 |
comp = ich9_1a; |
211 |
break;
|
212 |
default:
|
213 |
return -1; |
214 |
} |
215 |
|
216 |
ehci = pci_create_multifunction(bus, PCI_DEVFN(slot, 7), true, name); |
217 |
qdev_init_nofail(&ehci->qdev); |
218 |
usbbus = QLIST_FIRST(&ehci->qdev.child_bus); |
219 |
|
220 |
for (i = 0; i < 3; i++) { |
221 |
uhci = pci_create_multifunction(bus, PCI_DEVFN(slot, comp[i].func), |
222 |
true, comp[i].name);
|
223 |
qdev_prop_set_string(&uhci->qdev, "masterbus", usbbus->name);
|
224 |
qdev_prop_set_uint32(&uhci->qdev, "firstport", comp[i].port);
|
225 |
qdev_init_nofail(&uhci->qdev); |
226 |
} |
227 |
return 0; |
228 |
} |