From 3fe79ce029757bb9302423c0df6bc14f5c1dfd6b Mon Sep 17 00:00:00 2001 From: augustss Date: Sun, 20 Nov 2005 14:46:23 +0000 Subject: [PATCH] Go through the prescribed process to get ownership of the controller from BIOS before we start using it. This seems to fix the problems some people have been experiencing with keyboards not working. --- sys/dev/pci/ehci_pci.c | 83 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 2 deletions(-) diff --git a/sys/dev/pci/ehci_pci.c b/sys/dev/pci/ehci_pci.c index d23039b9e497..83f4c8d7a321 100644 --- a/sys/dev/pci/ehci_pci.c +++ b/sys/dev/pci/ehci_pci.c @@ -1,4 +1,4 @@ -/* $NetBSD: ehci_pci.c,v 1.18 2005/06/28 00:28:42 thorpej Exp $ */ +/* $NetBSD: ehci_pci.c,v 1.19 2005/11/20 14:46:23 augustss Exp $ */ /* * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc. @@ -37,7 +37,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: ehci_pci.c,v 1.18 2005/06/28 00:28:42 thorpej Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ehci_pci.c,v 1.19 2005/11/20 14:46:23 augustss Exp $"); #include #include @@ -66,6 +66,9 @@ extern int ehcidebug; #define DPRINTF(x) #endif +static void ehci_get_ownership(ehci_softc_t *sc, pci_chipset_tag_t pc, + pcitag_t tag); + struct ehci_pci_softc { ehci_softc_t sc; pci_chipset_tag_t sc_pc; @@ -73,6 +76,8 @@ struct ehci_pci_softc { void *sc_ih; /* interrupt vectoring */ }; +#define EHCI_MAX_BIOS_WAIT 1000 /* ms */ + static int ehci_pci_match(struct device *parent, struct cfdata *match, void *aux) { @@ -186,6 +191,8 @@ ehci_pci_attach(struct device *parent, struct device *self, void *aux) } sc->sc.sc_ncomp = ncomp; + ehci_get_ownership(&sc->sc, pc, tag); + r = ehci_init(&sc->sc); if (r != USBD_NORMAL_COMPLETION) { aprint_error("%s: init failed, error=%d\n", devname, r); @@ -219,3 +226,75 @@ ehci_pci_detach(device_ptr_t self, int flags) CFATTACH_DECL(ehci_pci, sizeof(struct ehci_pci_softc), ehci_pci_match, ehci_pci_attach, ehci_pci_detach, ehci_activate); + +#ifdef EHCI_DEBUG +static void +ehci_dump_caps(ehci_softc_t *sc, pci_chipset_tag_t pc, pcitag_t tag) +{ + u_int32_t cparams, legctlsts, addr, cap, id; + int maxdump = 10; + + cparams = EREAD4(sc, EHCI_HCCPARAMS); + addr = EHCI_HCC_EECP(cparams); + while (addr != 0) { + cap = pci_conf_read(pc, tag, addr); + id = EHCI_CAP_GET_ID(cap); + switch (id) { + case EHCI_CAP_ID_LEGACY: + legctlsts = pci_conf_read(pc, tag, + addr + PCI_EHCI_USBLEGCTLSTS); + printf("ehci_dump_caps: 0x%08x 0x%08x\n", + cap, legctlsts); + break; + default: + printf("ehci_dump_caps: 0x%08x\n", cap); + break; + } + if (--maxdump < 0) + break; + addr = EHCI_CAP_GET_NEXT(cap); + } +} +#endif + +static void +ehci_get_ownership(ehci_softc_t *sc, pci_chipset_tag_t pc, pcitag_t tag) +{ + const char *devname = sc->sc_bus.bdev.dv_xname; + u_int32_t cparams, addr, cap, legsup; + int maxcap = 10; + int ms; + +#ifdef EHCI_DEBUG + ehci_dump_caps(sc, pc, tag); +#endif + cparams = EREAD4(sc, EHCI_HCCPARAMS); + addr = EHCI_HCC_EECP(cparams); + while (addr != 0) { + cap = pci_conf_read(pc, tag, addr); + if (EHCI_CAP_GET_ID(cap) == EHCI_CAP_ID_LEGACY) + break; + if (--maxcap < 0) + return; + addr = EHCI_CAP_GET_NEXT(cap); + } + + legsup = pci_conf_read(pc, tag, addr + PCI_EHCI_USBLEGSUP); + /* Ask BIOS to give up ownership */ + legsup |= EHCI_LEG_HC_OS_OWNED; + pci_conf_write(pc, tag, addr + PCI_EHCI_USBLEGSUP, legsup); + for (ms = 0; ms < EHCI_MAX_BIOS_WAIT; ms++) { + legsup = pci_conf_read(pc, tag, addr + PCI_EHCI_USBLEGSUP); + if (!(legsup & EHCI_LEG_HC_BIOS_OWNED)) + break; + delay(1000); + } + if (ms == EHCI_MAX_BIOS_WAIT) { + aprint_normal("%s: BIOS refuses to give up ownership, " + "using force\n", devname); + pci_conf_write(pc, tag, addr + PCI_EHCI_USBLEGSUP, 0); + pci_conf_write(pc, tag, addr + PCI_EHCI_USBLEGCTLSTS, 0); + } else { + aprint_normal("%s: BIOS has given up ownership\n", devname); + } +}