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.
This commit is contained in:
parent
8ff42923d7
commit
63868484d5
@ -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)
|
||||
|
@ -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),
|
||||
|
@ -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 ***/
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user