summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/ehci_pci.c
diff options
context:
space:
mode:
authoriedowse <iedowse@FreeBSD.org>2004-08-02 12:56:01 +0000
committeriedowse <iedowse@FreeBSD.org>2004-08-02 12:56:01 +0000
commit5b775a536b482d5822d14e4db6ddf2cbe5ede2fc (patch)
tree6e4b279e12c7342cc1fd53861faeb103ffb62151 /sys/dev/usb/ehci_pci.c
parent2e77b96f4a11ad8896311a302e633a96d6acc5d3 (diff)
downloadFreeBSD-src-5b775a536b482d5822d14e4db6ddf2cbe5ede2fc.zip
FreeBSD-src-5b775a536b482d5822d14e4db6ddf2cbe5ede2fc.tar.gz
Attempt to follow the correct procedure for synchronising with the
system BIOS to disable legacy device emulation as per the "EHCI Extended Capability: Pre-OS to OS Handoff Synchronisation" section of the EHCI spec. BIOSes that implement legacy emulation using SMIs are supposed to disable the emulation when this procedure is performed.
Diffstat (limited to 'sys/dev/usb/ehci_pci.c')
-rw-r--r--sys/dev/usb/ehci_pci.c72
1 files changed, 71 insertions, 1 deletions
diff --git a/sys/dev/usb/ehci_pci.c b/sys/dev/usb/ehci_pci.c
index a367932..482f187 100644
--- a/sys/dev/usb/ehci_pci.c
+++ b/sys/dev/usb/ehci_pci.c
@@ -101,6 +101,24 @@ static const char *ehci_device_generic = "EHCI (generic) USB 2.0 controller";
static int ehci_pci_attach(device_t self);
static int ehci_pci_detach(device_t self);
+static int ehci_pci_shutdown(device_t self);
+static void ehci_pci_givecontroller(device_t self);
+static void ehci_pci_takecontroller(device_t self);
+
+static int
+ehci_pci_shutdown(device_t self)
+{
+ ehci_softc_t *sc = device_get_softc(self);
+ int err;
+
+ err = bus_generic_shutdown(self);
+ if (err)
+ return (err);
+ ehci_shutdown(sc);
+ ehci_pci_givecontroller(self);
+
+ return 0;
+}
static const char *
ehci_pci_match(device_t self)
@@ -276,6 +294,7 @@ ehci_pci_attach(device_t self)
}
sc->sc_ncomp = ncomp;
+ ehci_pci_takecontroller(self);
err = ehci_init(sc);
if (!err)
err = device_probe_and_attach(sc->sc_bus.bdev);
@@ -332,11 +351,62 @@ ehci_pci_detach(device_t self)
return 0;
}
+static void
+ehci_pci_takecontroller(device_t self)
+{
+ ehci_softc_t *sc = device_get_softc(self);
+ u_int32_t cparams, eec, legsup;
+ int eecp, i;
+
+ cparams = EREAD4(sc, EHCI_HCCPARAMS);
+
+ /* Synchronise with the BIOS if it owns the controller. */
+ for (eecp = EHCI_HCC_EECP(cparams); eecp != 0;
+ eecp = EHCI_EECP_NEXT(eec)) {
+ eec = pci_read_config(self, eecp, 4);
+ if (EHCI_EECP_ID(eec) != EHCI_EC_LEGSUP)
+ continue;
+ legsup = eec;
+ pci_write_config(self, eecp, legsup | EHCI_LEGSUP_OSOWNED, 4);
+ if (legsup & EHCI_LEGSUP_BIOSOWNED) {
+ printf("%s: waiting for BIOS to give up control\n",
+ USBDEVNAME(sc->sc_bus.bdev));
+ for (i = 0; i < 5000; i++) {
+ legsup = pci_read_config(self, eecp, 4);
+ if ((legsup & EHCI_LEGSUP_BIOSOWNED) == 0)
+ break;
+ DELAY(1000);
+ }
+ if (legsup & EHCI_LEGSUP_BIOSOWNED)
+ printf("%s: timed out waiting for BIOS\n",
+ USBDEVNAME(sc->sc_bus.bdev));
+ }
+ }
+}
+
+static void
+ehci_pci_givecontroller(device_t self)
+{
+ ehci_softc_t *sc = device_get_softc(self);
+ u_int32_t cparams, eec, legsup;
+ int eecp;
+
+ cparams = EREAD4(sc, EHCI_HCCPARAMS);
+ for (eecp = EHCI_HCC_EECP(cparams); eecp != 0;
+ eecp = EHCI_EECP_NEXT(eec)) {
+ eec = pci_read_config(self, eecp, 4);
+ if (EHCI_EECP_ID(eec) != EHCI_EC_LEGSUP)
+ continue;
+ legsup = eec;
+ pci_write_config(self, eecp, legsup & ~EHCI_LEGSUP_OSOWNED, 4);
+ }
+}
+
static device_method_t ehci_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, ehci_pci_probe),
DEVMETHOD(device_attach, ehci_pci_attach),
- DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_shutdown, ehci_pci_shutdown),
/* Bus interface */
DEVMETHOD(bus_print_child, bus_generic_print_child),
OpenPOWER on IntegriCloud