Commit | Line | Data |
---|---|---|
12bd3c8b SW |
1 | /*- |
2 | * Copyright (c) 1998 The NetBSD Foundation, Inc. | |
3 | * All rights reserved. | |
4 | * | |
5 | * This code is derived from software contributed to The NetBSD Foundation | |
6 | * by Lennart Augustsson (augustss@carlstedt.se) at | |
7 | * Carlstedt Research & Technology. | |
8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
12 | * 1. Redistributions of source code must retain the above copyright | |
13 | * notice, this list of conditions and the following disclaimer. | |
14 | * 2. Redistributions in binary form must reproduce the above copyright | |
15 | * notice, this list of conditions and the following disclaimer in the | |
16 | * documentation and/or other materials provided with the distribution. | |
17 | * | |
18 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
19 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
20 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
21 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
22 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
28 | * POSSIBILITY OF SUCH DAMAGE. | |
29 | */ | |
30 | ||
d9cd4901 MP |
31 | /* $FreeBSD: head/sys/dev/usb/controller/ehci_pci.c 276717 2015-01-05 20:22:18Z hselasky $ */ |
32 | ||
12bd3c8b SW |
33 | /* |
34 | * USB Enhanced Host Controller Driver, a.k.a. USB 2.0 controller. | |
35 | * | |
36 | * The EHCI 1.0 spec can be found at | |
37 | * http://developer.intel.com/technology/usb/download/ehci-r10.pdf | |
38 | * and the USB 2.0 spec at | |
39 | * http://www.usb.org/developers/docs/usb_20.zip | |
40 | */ | |
41 | ||
42 | /* The low level controller code for EHCI has been split into | |
43 | * PCI probes and EHCI specific code. This was done to facilitate the | |
44 | * sharing of code between *BSD's | |
45 | */ | |
46 | ||
47 | #include <sys/stdint.h> | |
12bd3c8b SW |
48 | #include <sys/param.h> |
49 | #include <sys/queue.h> | |
50 | #include <sys/types.h> | |
51 | #include <sys/systm.h> | |
52 | #include <sys/kernel.h> | |
53 | #include <sys/bus.h> | |
54 | #include <sys/module.h> | |
55 | #include <sys/lock.h> | |
12bd3c8b SW |
56 | #include <sys/condvar.h> |
57 | #include <sys/sysctl.h> | |
12bd3c8b SW |
58 | #include <sys/unistd.h> |
59 | #include <sys/callout.h> | |
60 | #include <sys/malloc.h> | |
2b3f93ea | 61 | #include <sys/caps.h> |
12bd3c8b | 62 | |
722d05c3 SW |
63 | #include <bus/u4b/usb.h> |
64 | #include <bus/u4b/usbdi.h> | |
12bd3c8b | 65 | |
722d05c3 SW |
66 | #include <bus/u4b/usb_core.h> |
67 | #include <bus/u4b/usb_busdma.h> | |
68 | #include <bus/u4b/usb_process.h> | |
69 | #include <bus/u4b/usb_util.h> | |
12bd3c8b | 70 | |
722d05c3 SW |
71 | #include <bus/u4b/usb_controller.h> |
72 | #include <bus/u4b/usb_bus.h> | |
73 | #include <bus/u4b/usb_pci.h> | |
74 | #include <bus/u4b/controller/ehci.h> | |
75 | #include <bus/u4b/controller/ehcireg.h> | |
12bd3c8b SW |
76 | #include "usb_if.h" |
77 | ||
78 | #define PCI_EHCI_VENDORID_ACERLABS 0x10b9 | |
79 | #define PCI_EHCI_VENDORID_AMD 0x1022 | |
80 | #define PCI_EHCI_VENDORID_APPLE 0x106b | |
81 | #define PCI_EHCI_VENDORID_ATI 0x1002 | |
82 | #define PCI_EHCI_VENDORID_CMDTECH 0x1095 | |
83 | #define PCI_EHCI_VENDORID_INTEL 0x8086 | |
84 | #define PCI_EHCI_VENDORID_NEC 0x1033 | |
85 | #define PCI_EHCI_VENDORID_OPTI 0x1045 | |
86 | #define PCI_EHCI_VENDORID_PHILIPS 0x1131 | |
87 | #define PCI_EHCI_VENDORID_SIS 0x1039 | |
88 | #define PCI_EHCI_VENDORID_NVIDIA 0x12D2 | |
89 | #define PCI_EHCI_VENDORID_NVIDIA2 0x10DE | |
90 | #define PCI_EHCI_VENDORID_VIA 0x1106 | |
91 | ||
92 | static device_probe_t ehci_pci_probe; | |
93 | static device_attach_t ehci_pci_attach; | |
94 | static device_detach_t ehci_pci_detach; | |
95 | static usb_take_controller_t ehci_pci_take_controller; | |
96 | ||
97 | static const char * | |
98 | ehci_pci_match(device_t self) | |
99 | { | |
100 | uint32_t device_id = pci_get_devid(self); | |
101 | ||
102 | switch (device_id) { | |
12bd3c8b SW |
103 | case 0x523910b9: |
104 | return "ALi M5239 USB 2.0 controller"; | |
105 | ||
106 | case 0x10227463: | |
107 | return "AMD 8111 USB 2.0 controller"; | |
108 | ||
109 | case 0x20951022: | |
f48b6402 | 110 | return ("AMD CS5536 (Geode) USB 2.0 controller"); |
12bd3c8b SW |
111 | |
112 | case 0x43451002: | |
113 | return "ATI SB200 USB 2.0 controller"; | |
114 | case 0x43731002: | |
115 | return "ATI SB400 USB 2.0 controller"; | |
57bed822 | 116 | case 0x43961002: |
f48b6402 | 117 | return ("AMD SB7x0/SB8x0/SB9x0 USB 2.0 controller"); |
12bd3c8b | 118 | |
d9cd4901 MP |
119 | case 0x0f348086: |
120 | return ("Intel BayTrail USB 2.0 controller"); | |
121 | case 0x1d268086: | |
122 | return ("Intel Patsburg USB 2.0 controller"); | |
123 | case 0x1d2d8086: | |
124 | return ("Intel Patsburg USB 2.0 controller"); | |
57bed822 | 125 | case 0x1e268086: |
f48b6402 | 126 | return ("Intel Panther Point USB 2.0 controller"); |
57bed822 | 127 | case 0x1e2d8086: |
f48b6402 MP |
128 | return ("Intel Panther Point USB 2.0 controller"); |
129 | case 0x1f2c8086: | |
130 | return ("Intel Avoton USB 2.0 controller"); | |
12bd3c8b SW |
131 | case 0x25ad8086: |
132 | return "Intel 6300ESB USB 2.0 controller"; | |
133 | case 0x24cd8086: | |
134 | return "Intel 82801DB/L/M (ICH4) USB 2.0 controller"; | |
135 | case 0x24dd8086: | |
136 | return "Intel 82801EB/R (ICH5) USB 2.0 controller"; | |
137 | case 0x265c8086: | |
138 | return "Intel 82801FB (ICH6) USB 2.0 controller"; | |
57bed822 | 139 | case 0x268c8086: |
f48b6402 | 140 | return ("Intel 63XXESB USB 2.0 controller"); |
12bd3c8b SW |
141 | case 0x27cc8086: |
142 | return "Intel 82801GB/R (ICH7) USB 2.0 controller"; | |
12bd3c8b SW |
143 | case 0x28368086: |
144 | return "Intel 82801H (ICH8) USB 2.0 controller USB2-A"; | |
145 | case 0x283a8086: | |
146 | return "Intel 82801H (ICH8) USB 2.0 controller USB2-B"; | |
147 | case 0x293a8086: | |
148 | return "Intel 82801I (ICH9) USB 2.0 controller"; | |
149 | case 0x293c8086: | |
150 | return "Intel 82801I (ICH9) USB 2.0 controller"; | |
151 | case 0x3a3a8086: | |
152 | return "Intel 82801JI (ICH10) USB 2.0 controller USB-A"; | |
153 | case 0x3a3c8086: | |
154 | return "Intel 82801JI (ICH10) USB 2.0 controller USB-B"; | |
155 | case 0x3b348086: | |
156 | return ("Intel PCH USB 2.0 controller USB-A"); | |
157 | case 0x3b3c8086: | |
158 | return ("Intel PCH USB 2.0 controller USB-B"); | |
f48b6402 MP |
159 | case 0x8c268086: |
160 | return ("Intel Lynx Point USB 2.0 controller USB-A"); | |
161 | case 0x8c2d8086: | |
162 | return ("Intel Lynx Point USB 2.0 controller USB-B"); | |
d9cd4901 MP |
163 | case 0x8ca68086: |
164 | return ("Intel Wildcat Point USB 2.0 controller USB-A"); | |
165 | case 0x8cad8086: | |
166 | return ("Intel Wildcat Point USB 2.0 controller USB-B"); | |
d9bd48f4 | 167 | case 0x8d268086: |
168 | return ("Intel Wellsburg USB 2.0 controller"); | |
169 | case 0x8d2d8086: | |
170 | return ("Intel Wellsburg USB 2.0 controller"); | |
d9cd4901 MP |
171 | case 0x9c268086: |
172 | return ("Intel Lynx Point LP USB 2.0 controller USB"); | |
12bd3c8b SW |
173 | |
174 | case 0x00e01033: | |
d9bd48f4 | 175 | return ("NEC uPD 72010x USB 2.0 controller"); |
12bd3c8b SW |
176 | |
177 | case 0x006810de: | |
178 | return "NVIDIA nForce2 USB 2.0 controller"; | |
179 | case 0x008810de: | |
180 | return "NVIDIA nForce2 Ultra 400 USB 2.0 controller"; | |
181 | case 0x00d810de: | |
182 | return "NVIDIA nForce3 USB 2.0 controller"; | |
183 | case 0x00e810de: | |
184 | return "NVIDIA nForce3 250 USB 2.0 controller"; | |
185 | case 0x005b10de: | |
f48b6402 | 186 | return "NVIDIA nForce CK804 USB 2.0 controller"; |
12bd3c8b SW |
187 | case 0x036d10de: |
188 | return "NVIDIA nForce MCP55 USB 2.0 controller"; | |
189 | case 0x03f210de: | |
190 | return "NVIDIA nForce MCP61 USB 2.0 controller"; | |
191 | case 0x0aa610de: | |
192 | return "NVIDIA nForce MCP79 USB 2.0 controller"; | |
193 | case 0x0aa910de: | |
194 | return "NVIDIA nForce MCP79 USB 2.0 controller"; | |
195 | case 0x0aaa10de: | |
196 | return "NVIDIA nForce MCP79 USB 2.0 controller"; | |
197 | ||
198 | case 0x15621131: | |
199 | return "Philips ISP156x USB 2.0 controller"; | |
200 | ||
201 | case 0x31041106: | |
202 | return ("VIA VT6202 USB 2.0 controller"); | |
203 | ||
204 | default: | |
205 | break; | |
206 | } | |
207 | ||
208 | if ((pci_get_class(self) == PCIC_SERIALBUS) | |
209 | && (pci_get_subclass(self) == PCIS_SERIALBUS_USB) | |
210 | && (pci_get_progif(self) == PCI_INTERFACE_EHCI)) { | |
211 | return ("EHCI (generic) USB 2.0 controller"); | |
212 | } | |
213 | return (NULL); /* dunno */ | |
214 | } | |
215 | ||
216 | static int | |
217 | ehci_pci_probe(device_t self) | |
218 | { | |
219 | const char *desc = ehci_pci_match(self); | |
220 | ||
221 | if (desc) { | |
222 | device_set_desc(self, desc); | |
223 | return (0); | |
224 | } else { | |
225 | return (ENXIO); | |
226 | } | |
227 | } | |
228 | ||
229 | static void | |
230 | ehci_pci_ati_quirk(device_t self, uint8_t is_sb700) | |
231 | { | |
232 | device_t smbdev; | |
233 | uint32_t val; | |
234 | ||
235 | if (is_sb700) { | |
236 | /* Lookup SMBUS PCI device */ | |
237 | smbdev = pci_find_device(PCI_EHCI_VENDORID_ATI, 0x4385); | |
238 | if (smbdev == NULL) | |
239 | return; | |
240 | val = pci_get_revid(smbdev); | |
241 | if (val != 0x3a && val != 0x3b) | |
242 | return; | |
243 | } | |
244 | ||
245 | /* | |
246 | * Note: this bit is described as reserved in SB700 | |
247 | * Register Reference Guide. | |
248 | */ | |
249 | val = pci_read_config(self, 0x53, 1); | |
250 | if (!(val & 0x8)) { | |
251 | val |= 0x8; | |
252 | pci_write_config(self, 0x53, val, 1); | |
253 | device_printf(self, "AMD SB600/700 quirk applied\n"); | |
254 | } | |
255 | } | |
256 | ||
257 | static void | |
258 | ehci_pci_via_quirk(device_t self) | |
259 | { | |
260 | uint32_t val; | |
261 | ||
262 | if ((pci_get_device(self) == 0x3104) && | |
263 | ((pci_get_revid(self) & 0xf0) == 0x60)) { | |
264 | /* Correct schedule sleep time to 10us */ | |
265 | val = pci_read_config(self, 0x4b, 1); | |
266 | if (val & 0x20) | |
267 | return; | |
57bed822 | 268 | val |= 0x20; |
12bd3c8b SW |
269 | pci_write_config(self, 0x4b, val, 1); |
270 | device_printf(self, "VIA-quirk applied\n"); | |
271 | } | |
272 | } | |
273 | ||
274 | static int | |
275 | ehci_pci_attach(device_t self) | |
276 | { | |
277 | ehci_softc_t *sc = device_get_softc(self); | |
278 | int err; | |
279 | int rid; | |
280 | ||
281 | /* initialise some bus fields */ | |
282 | sc->sc_bus.parent = self; | |
283 | sc->sc_bus.devices = sc->sc_devices; | |
284 | sc->sc_bus.devices_max = EHCI_MAX_DEVICES; | |
d9cd4901 | 285 | sc->sc_bus.dma_bits = 32; |
12bd3c8b SW |
286 | |
287 | /* get all DMA memory */ | |
288 | if (usb_bus_mem_alloc_all(&sc->sc_bus, | |
289 | USB_GET_DMA_TAG(self), &ehci_iterate_hw_softc)) { | |
290 | return (ENOMEM); | |
291 | } | |
292 | ||
293 | pci_enable_busmaster(self); | |
294 | ||
295 | switch (pci_read_config(self, PCI_USBREV, 1) & PCI_USB_REV_MASK) { | |
296 | case PCI_USB_REV_PRE_1_0: | |
297 | case PCI_USB_REV_1_0: | |
298 | case PCI_USB_REV_1_1: | |
299 | /* | |
300 | * NOTE: some EHCI USB controllers have the wrong USB | |
301 | * revision number. It appears those controllers are | |
302 | * fully compliant so we just ignore this value in | |
303 | * some common cases. | |
304 | */ | |
305 | device_printf(self, "pre-2.0 USB revision (ignored)\n"); | |
306 | /* fallthrough */ | |
307 | case PCI_USB_REV_2_0: | |
308 | break; | |
309 | default: | |
310 | /* Quirk for Parallels Desktop 4.0 */ | |
311 | device_printf(self, "USB revision is unknown. Assuming v2.0.\n"); | |
312 | break; | |
313 | } | |
314 | ||
315 | rid = PCI_CBMEM; | |
316 | sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, | |
317 | RF_ACTIVE); | |
318 | if (!sc->sc_io_res) { | |
319 | device_printf(self, "Could not map memory\n"); | |
320 | goto error; | |
321 | } | |
322 | sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); | |
323 | sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); | |
324 | sc->sc_io_size = rman_get_size(sc->sc_io_res); | |
325 | ||
326 | rid = 0; | |
327 | sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, | |
328 | RF_SHAREABLE | RF_ACTIVE); | |
329 | if (sc->sc_irq_res == NULL) { | |
330 | device_printf(self, "Could not allocate irq\n"); | |
331 | goto error; | |
332 | } | |
333 | sc->sc_bus.bdev = device_add_child(self, "usbus", -1); | |
334 | if (!sc->sc_bus.bdev) { | |
335 | device_printf(self, "Could not add USB device\n"); | |
336 | goto error; | |
337 | } | |
338 | device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); | |
339 | ||
340 | /* | |
341 | * ehci_pci_match will never return NULL if ehci_pci_probe | |
342 | * succeeded | |
343 | */ | |
344 | device_set_desc(sc->sc_bus.bdev, ehci_pci_match(self)); | |
345 | switch (pci_get_vendor(self)) { | |
346 | case PCI_EHCI_VENDORID_ACERLABS: | |
722d05c3 | 347 | ksprintf(sc->sc_vendor, "AcerLabs"); |
12bd3c8b SW |
348 | break; |
349 | case PCI_EHCI_VENDORID_AMD: | |
722d05c3 | 350 | ksprintf(sc->sc_vendor, "AMD"); |
12bd3c8b SW |
351 | break; |
352 | case PCI_EHCI_VENDORID_APPLE: | |
722d05c3 | 353 | ksprintf(sc->sc_vendor, "Apple"); |
12bd3c8b SW |
354 | break; |
355 | case PCI_EHCI_VENDORID_ATI: | |
722d05c3 | 356 | ksprintf(sc->sc_vendor, "ATI"); |
12bd3c8b SW |
357 | break; |
358 | case PCI_EHCI_VENDORID_CMDTECH: | |
722d05c3 | 359 | ksprintf(sc->sc_vendor, "CMDTECH"); |
12bd3c8b SW |
360 | break; |
361 | case PCI_EHCI_VENDORID_INTEL: | |
722d05c3 | 362 | ksprintf(sc->sc_vendor, "Intel"); |
12bd3c8b SW |
363 | break; |
364 | case PCI_EHCI_VENDORID_NEC: | |
722d05c3 | 365 | ksprintf(sc->sc_vendor, "NEC"); |
12bd3c8b SW |
366 | break; |
367 | case PCI_EHCI_VENDORID_OPTI: | |
722d05c3 | 368 | ksprintf(sc->sc_vendor, "OPTi"); |
12bd3c8b SW |
369 | break; |
370 | case PCI_EHCI_VENDORID_PHILIPS: | |
722d05c3 | 371 | ksprintf(sc->sc_vendor, "Philips"); |
12bd3c8b SW |
372 | break; |
373 | case PCI_EHCI_VENDORID_SIS: | |
722d05c3 | 374 | ksprintf(sc->sc_vendor, "SiS"); |
12bd3c8b SW |
375 | break; |
376 | case PCI_EHCI_VENDORID_NVIDIA: | |
377 | case PCI_EHCI_VENDORID_NVIDIA2: | |
722d05c3 | 378 | ksprintf(sc->sc_vendor, "nVidia"); |
12bd3c8b SW |
379 | break; |
380 | case PCI_EHCI_VENDORID_VIA: | |
722d05c3 | 381 | ksprintf(sc->sc_vendor, "VIA"); |
12bd3c8b SW |
382 | break; |
383 | default: | |
384 | if (bootverbose) | |
385 | device_printf(self, "(New EHCI DeviceId=0x%08x)\n", | |
386 | pci_get_devid(self)); | |
722d05c3 | 387 | ksprintf(sc->sc_vendor, "(0x%04x)", pci_get_vendor(self)); |
12bd3c8b SW |
388 | } |
389 | ||
722d05c3 SW |
390 | err = bus_setup_intr(self, sc->sc_irq_res, INTR_MPSAFE, |
391 | (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl, NULL); | |
392 | ||
12bd3c8b SW |
393 | if (err) { |
394 | device_printf(self, "Could not setup irq, %d\n", err); | |
395 | sc->sc_intr_hdl = NULL; | |
396 | goto error; | |
397 | } | |
398 | ehci_pci_take_controller(self); | |
399 | ||
400 | /* Undocumented quirks taken from Linux */ | |
401 | ||
402 | switch (pci_get_vendor(self)) { | |
403 | case PCI_EHCI_VENDORID_ATI: | |
404 | /* SB600 and SB700 EHCI quirk */ | |
405 | switch (pci_get_device(self)) { | |
406 | case 0x4386: | |
407 | ehci_pci_ati_quirk(self, 0); | |
408 | break; | |
409 | case 0x4396: | |
410 | ehci_pci_ati_quirk(self, 1); | |
411 | break; | |
412 | default: | |
413 | break; | |
414 | } | |
415 | break; | |
416 | ||
417 | case PCI_EHCI_VENDORID_VIA: | |
418 | ehci_pci_via_quirk(self); | |
419 | break; | |
420 | ||
421 | default: | |
422 | break; | |
423 | } | |
424 | ||
425 | /* Dropped interrupts workaround */ | |
426 | switch (pci_get_vendor(self)) { | |
427 | case PCI_EHCI_VENDORID_ATI: | |
428 | case PCI_EHCI_VENDORID_VIA: | |
429 | sc->sc_flags |= EHCI_SCFLG_LOSTINTRBUG; | |
430 | if (bootverbose) | |
431 | device_printf(self, | |
432 | "Dropped interrupts workaround enabled\n"); | |
433 | break; | |
434 | default: | |
435 | break; | |
436 | } | |
437 | ||
438 | /* Doorbell feature workaround */ | |
439 | switch (pci_get_vendor(self)) { | |
440 | case PCI_EHCI_VENDORID_NVIDIA: | |
441 | case PCI_EHCI_VENDORID_NVIDIA2: | |
442 | sc->sc_flags |= EHCI_SCFLG_IAADBUG; | |
443 | if (bootverbose) | |
444 | device_printf(self, | |
445 | "Doorbell workaround enabled\n"); | |
446 | break; | |
447 | default: | |
448 | break; | |
449 | } | |
450 | ||
451 | err = ehci_init(sc); | |
452 | if (!err) { | |
453 | err = device_probe_and_attach(sc->sc_bus.bdev); | |
454 | } | |
455 | if (err) { | |
456 | device_printf(self, "USB init failed err=%d\n", err); | |
457 | goto error; | |
458 | } | |
459 | return (0); | |
460 | ||
461 | error: | |
462 | ehci_pci_detach(self); | |
463 | return (ENXIO); | |
464 | } | |
465 | ||
466 | static int | |
467 | ehci_pci_detach(device_t self) | |
468 | { | |
469 | ehci_softc_t *sc = device_get_softc(self); | |
470 | device_t bdev; | |
471 | ||
472 | if (sc->sc_bus.bdev) { | |
473 | bdev = sc->sc_bus.bdev; | |
474 | device_detach(bdev); | |
475 | device_delete_child(self, bdev); | |
476 | } | |
477 | /* during module unload there are lots of children leftover */ | |
478 | device_delete_children(self); | |
479 | ||
480 | pci_disable_busmaster(self); | |
481 | ||
482 | if (sc->sc_irq_res && sc->sc_intr_hdl) { | |
483 | /* | |
484 | * only call ehci_detach() after ehci_init() | |
485 | */ | |
486 | ehci_detach(sc); | |
487 | ||
488 | int err = bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl); | |
489 | ||
490 | if (err) | |
491 | /* XXX or should we panic? */ | |
492 | device_printf(self, "Could not tear down irq, %d\n", | |
493 | err); | |
494 | sc->sc_intr_hdl = NULL; | |
495 | } | |
496 | if (sc->sc_irq_res) { | |
497 | bus_release_resource(self, SYS_RES_IRQ, 0, sc->sc_irq_res); | |
498 | sc->sc_irq_res = NULL; | |
499 | } | |
500 | if (sc->sc_io_res) { | |
501 | bus_release_resource(self, SYS_RES_MEMORY, PCI_CBMEM, | |
502 | sc->sc_io_res); | |
503 | sc->sc_io_res = NULL; | |
504 | } | |
505 | usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc); | |
506 | ||
507 | return (0); | |
508 | } | |
509 | ||
510 | static int | |
511 | ehci_pci_take_controller(device_t self) | |
512 | { | |
513 | ehci_softc_t *sc = device_get_softc(self); | |
514 | uint32_t cparams; | |
515 | uint32_t eec; | |
516 | uint16_t to; | |
517 | uint8_t eecp; | |
518 | uint8_t bios_sem; | |
519 | ||
520 | cparams = EREAD4(sc, EHCI_HCCPARAMS); | |
521 | ||
522 | /* Synchronise with the BIOS if it owns the controller. */ | |
523 | for (eecp = EHCI_HCC_EECP(cparams); eecp != 0; | |
524 | eecp = EHCI_EECP_NEXT(eec)) { | |
525 | eec = pci_read_config(self, eecp, 4); | |
526 | if (EHCI_EECP_ID(eec) != EHCI_EC_LEGSUP) { | |
527 | continue; | |
528 | } | |
529 | bios_sem = pci_read_config(self, eecp + | |
530 | EHCI_LEGSUP_BIOS_SEM, 1); | |
531 | if (bios_sem == 0) { | |
532 | continue; | |
533 | } | |
534 | device_printf(sc->sc_bus.bdev, "waiting for BIOS " | |
535 | "to give up control\n"); | |
536 | pci_write_config(self, eecp + | |
537 | EHCI_LEGSUP_OS_SEM, 1, 1); | |
538 | to = 500; | |
539 | while (1) { | |
540 | bios_sem = pci_read_config(self, eecp + | |
541 | EHCI_LEGSUP_BIOS_SEM, 1); | |
542 | if (bios_sem == 0) | |
543 | break; | |
544 | ||
545 | if (--to == 0) { | |
546 | device_printf(sc->sc_bus.bdev, | |
547 | "timed out waiting for BIOS\n"); | |
548 | break; | |
549 | } | |
550 | usb_pause_mtx(NULL, hz / 100); /* wait 10ms */ | |
551 | } | |
552 | } | |
553 | return (0); | |
554 | } | |
555 | ||
556 | static device_method_t ehci_pci_methods[] = { | |
557 | /* Device interface */ | |
558 | DEVMETHOD(device_probe, ehci_pci_probe), | |
559 | DEVMETHOD(device_attach, ehci_pci_attach), | |
560 | DEVMETHOD(device_detach, ehci_pci_detach), | |
561 | DEVMETHOD(device_suspend, bus_generic_suspend), | |
562 | DEVMETHOD(device_resume, bus_generic_resume), | |
563 | DEVMETHOD(device_shutdown, bus_generic_shutdown), | |
564 | DEVMETHOD(usb_take_controller, ehci_pci_take_controller), | |
565 | ||
d3c9c58e | 566 | DEVMETHOD_END |
12bd3c8b SW |
567 | }; |
568 | ||
569 | static driver_t ehci_driver = { | |
570 | .name = "ehci", | |
571 | .methods = ehci_pci_methods, | |
572 | .size = sizeof(struct ehci_softc), | |
573 | }; | |
574 | ||
575 | static devclass_t ehci_devclass; | |
576 | ||
15f415f6 | 577 | DRIVER_MODULE(ehci, pci, ehci_driver, ehci_devclass, NULL, NULL); |
12bd3c8b | 578 | MODULE_DEPEND(ehci, usb, 1, 1, 1); |