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