From 5b775a536b482d5822d14e4db6ddf2cbe5ede2fc Mon Sep 17 00:00:00 2001 From: iedowse Date: Mon, 2 Aug 2004 12:56:01 +0000 Subject: [PATCH] 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. --- sys/dev/usb/ehci.c | 3 -- sys/dev/usb/ehci_pci.c | 72 +++++++++++++++++++++++++++++++++++++++++- sys/dev/usb/ehcireg.h | 14 ++++++-- sys/dev/usb/ehcivar.h | 1 + 4 files changed, 83 insertions(+), 7 deletions(-) diff --git a/sys/dev/usb/ehci.c b/sys/dev/usb/ehci.c index ae6d111c2d5..ed371c3391e 100644 --- a/sys/dev/usb/ehci.c +++ b/sys/dev/usb/ehci.c @@ -169,7 +169,6 @@ struct ehci_pipe { }; #if defined(__NetBSD__) || defined(__OpenBSD__) -Static void ehci_shutdown(void *); Static void ehci_power(int, void *); #endif @@ -1057,7 +1056,6 @@ OOO /* * Shut down the controller when the system is going down. */ -#if defined(__NetBSD__) || defined(__OpenBSD__) void ehci_shutdown(void *v) { @@ -1067,7 +1065,6 @@ ehci_shutdown(void *v) EOWRITE4(sc, EHCI_USBCMD, 0); /* Halt controller */ EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET); } -#endif usbd_status ehci_allocm(struct usbd_bus *bus, usb_dma_t *dma, u_int32_t size) diff --git a/sys/dev/usb/ehci_pci.c b/sys/dev/usb/ehci_pci.c index a367932cbda..482f187f8fa 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), diff --git a/sys/dev/usb/ehcireg.h b/sys/dev/usb/ehcireg.h index ec5d893b2eb..634fc9e693d 100644 --- a/sys/dev/usb/ehcireg.h +++ b/sys/dev/usb/ehcireg.h @@ -64,9 +64,17 @@ #define PCI_EHCI_PORTWAKECAP 0x62 /* RW Port wake caps (opt) */ -/* Regs ar EECP + offset */ -#define PCI_EHCI_USBLEGSUP 0x00 -#define PCI_EHCI_USBLEGCTLSTS 0x04 +/* EHCI Extended Capabilities */ +#define EHCI_EC_LEGSUP 0x01 + +#define EHCI_EECP_NEXT(x) (((x) >> 8) & 0xff) +#define EHCI_EECP_ID(x) ((x) & 0xff) + +/* Legacy support extended capability */ +#define EHCI_LEGSUP_LEGSUP 0x01 +#define EHCI_LEGSUP_OSOWNED 0x01000000 /* OS owned semaphore */ +#define EHCI_LEGSUP_BIOSOWNED 0x00010000 /* BIOS owned semaphore */ +#define EHCI_LEGSUP_USBLEGCTLSTS 0x04 /*** EHCI capability registers ***/ diff --git a/sys/dev/usb/ehcivar.h b/sys/dev/usb/ehcivar.h index 046c3297abf..318d835a745 100644 --- a/sys/dev/usb/ehcivar.h +++ b/sys/dev/usb/ehcivar.h @@ -165,6 +165,7 @@ int ehci_intr(void *); int ehci_detach(ehci_softc_t *, int); int ehci_activate(device_ptr_t, enum devact); #endif +void ehci_shutdown(void *v); #define MS_TO_TICKS(ms) ((ms) * hz / 1000) -- 2.45.2