[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
BIOS to OS handover of ehci ports
- To: tech_(_at_)_openbsd_(_dot_)_org
- Subject: BIOS to OS handover of ehci ports
- From: David Gwynne <loki_(_at_)_animata_(_dot_)_net>
- Date: Tue, 21 Dec 2004 19:04:14 +1000
This patch adds support for the handover of ehci ports between the BIOS and
OS.
This is useful for people with the new breed of legacy free machines. We got
a batch of new computers in at work with no dedicated PS/2 connectors for the
keyboard and mouse and discovered that the usb keyboard wasn't being detected
on boot by OpenBSD. However, if we unplug the keyboard and attach it to a
different port it is attached. Nothing happens if it is moved back to the
original port. Rebooting with the keyboard in a different port results in the
same story, but it shifts to the port the kb was plugged into.
This patch was inspired by a change in freebsd by Ian Dowse.
I need testing wherever possible, and especially on non i386 architectures
such as amd64 and macppc.
DG
Index: cardbus/ehci_cardbus.c
===================================================================
RCS file: /cvs/openbsd/src/sys/dev/cardbus/ehci_cardbus.c,v
retrieving revision 1.1
diff -u -p -r1.1 ehci_cardbus.c
--- cardbus/ehci_cardbus.c 7 Dec 2004 05:42:41 -0000 1.1
+++ cardbus/ehci_cardbus.c 21 Dec 2004 08:43:32 -0000
@@ -228,6 +228,8 @@ XXX (ct->ct_cf->cardbus_mem_open)(cc, 0,
return;
}
+ sc->sc.sc_shutdownhook = shutdownhook_establish(ehci_shutdown, &sc->sc);
+
/* Attach usb device. */
sc->sc.sc_child = config_found((void *)sc, &sc->sc.sc_bus,
usbctlprint);
Index: pci/ehci_pci.c
===================================================================
RCS file: /cvs/openbsd/src/sys/dev/pci/ehci_pci.c,v
retrieving revision 1.3
diff -u -p -r1.3 ehci_pci.c
--- pci/ehci_pci.c 30 May 2004 01:25:17 -0000 1.3
+++ pci/ehci_pci.c 21 Dec 2004 08:43:32 -0000
@@ -69,10 +69,6 @@ extern int ehcidebug;
#define DPRINTF(x)
#endif
-int ehci_pci_match(struct device *, void *, void *);
-void ehci_pci_attach(struct device *, struct device *, void *);
-int ehci_pci_detach(device_ptr_t, int);
-
struct ehci_pci_softc {
ehci_softc_t sc;
pci_chipset_tag_t sc_pc;
@@ -80,6 +76,13 @@ struct ehci_pci_softc {
void *sc_ih; /* interrupt vectoring */
};
+int ehci_pci_match(struct device *, void *, void *);
+void ehci_pci_attach(struct device *, struct device *, void *);
+int ehci_pci_detach(device_ptr_t, int);
+void ehci_pci_givecontroller(struct ehci_pci_softc *);
+void ehci_pci_takecontroller(struct ehci_pci_softc *);
+void ehci_pci_shutdown(void *);
+
struct cfattach ehci_pci_ca = {
sizeof(struct ehci_pci_softc), ehci_pci_match, ehci_pci_attach,
ehci_pci_detach, ehci_activate
@@ -203,6 +206,7 @@ ehci_pci_attach(struct device *parent, s
}
sc->sc.sc_ncomp = ncomp;
+ ehci_pci_takecontroller(sc);
r = ehci_init(&sc->sc);
if (r != USBD_NORMAL_COMPLETION) {
printf("%s: init failed, error=%d\n", devname, r);
@@ -210,6 +214,8 @@ ehci_pci_attach(struct device *parent, s
return;
}
+ sc->sc.sc_shutdownhook = shutdownhook_establish(ehci_pci_shutdown, sc);
+
/* Attach usb device. */
sc->sc.sc_child = config_found((void *)sc, &sc->sc.sc_bus,
usbctlprint);
@@ -233,4 +239,64 @@ ehci_pci_detach(device_ptr_t self, int f
sc->sc.sc_size = 0;
}
return (0);
+}
+
+void
+ehci_pci_givecontroller(struct ehci_pci_softc *sc)
+{
+ u_int32_t cparams, eec, legsup;
+ int eecp;
+
+ cparams = EREAD4(&sc->sc, EHCI_HCCPARAMS);
+ for (eecp = EHCI_HCC_EECP(cparams); eecp != 0;
+ eecp = EHCI_EECP_NEXT(eec)) {
+ eec = pci_conf_read(sc->sc_pc, sc->sc_tag, eecp);
+ if (EHCI_EECP_ID(eec) != EHCI_EC_LEGSUP)
+ continue;
+ legsup = eec;
+ pci_conf_write(sc->sc_pc, sc->sc_tag, eecp,
+ legsup & ~EHCI_LEGSUP_OSOWNED);
+ }
+}
+
+void
+ehci_pci_takecontroller(struct ehci_pci_softc *sc)
+{
+ u_int32_t cparams, eec, legsup;
+ int eecp, i;
+
+ cparams = EREAD4(&sc->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_conf_read(sc->sc_pc, sc->sc_tag, eecp);
+ if (EHCI_EECP_ID(eec) != EHCI_EC_LEGSUP)
+ continue;
+ legsup = eec;
+ pci_conf_write(sc->sc_pc, sc->sc_tag, eecp,
+ legsup | EHCI_LEGSUP_OSOWNED);
+ if (legsup & EHCI_LEGSUP_BIOSOWNED) {
+ DPRINTF(("%s: waiting for BIOS to give up control\n",
+ USBDEVNAME(sc->sc.sc_bus.bdev)));
+ for (i = 0; i < 5000; i++) {
+ legsup = pci_conf_read(sc->sc_pc, sc->sc_tag,
+ eecp);
+ 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.sc_bus.bdev));
+ }
+ }
+}
+
+void
+ehci_pci_shutdown(void *v)
+{
+ struct ehci_pci_softc *sc = (struct ehci_pci_softc *)v;
+
+ ehci_shutdown(&sc->sc);
+ ehci_pci_givecontroller(sc);
}
Index: usb/ehci.c
===================================================================
RCS file: /cvs/openbsd/src/sys/dev/usb/ehci.c,v
retrieving revision 1.32
diff -u -p -r1.32 ehci.c
--- usb/ehci.c 31 Oct 2004 10:29:45 -0000 1.32
+++ usb/ehci.c 21 Dec 2004 08:43:32 -0000
@@ -144,7 +144,6 @@ struct ehci_pipe {
} u;
};
-Static void ehci_shutdown(void *);
Static void ehci_power(int, void *);
Static usbd_status ehci_open(usbd_pipe_handle);
@@ -416,7 +415,6 @@ ehci_init(ehci_softc_t *sc)
sc->sc_bus.pipe_size = sizeof(struct ehci_pipe);
sc->sc_powerhook = powerhook_establish(ehci_power, sc);
- sc->sc_shutdownhook = shutdownhook_establish(ehci_shutdown, sc);
sc->sc_eintrs = EHCI_NORMAL_INTRS;
Index: usb/ehcireg.h
===================================================================
RCS file: /cvs/openbsd/src/sys/dev/usb/ehcireg.h,v
retrieving revision 1.11
diff -u -p -r1.11 ehcireg.h
--- usb/ehcireg.h 25 Oct 2004 22:30:04 -0000 1.11
+++ usb/ehcireg.h 21 Dec 2004 08:43:32 -0000
@@ -64,9 +64,16 @@
#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)
+
+#define EHCI_LEGSUP_LEGSUP 0x01
+#define EHCI_LEGSUP_OSOWNED 0x01000000 /* OS owned semaphore */
+#define EHCI_LEGSUP_BIOSOWNED 0x00010000 /* BIOS owned semaphore */
+#define PCI_LEGSUP_USBLEGCTLSTS 0x04
/*** EHCI capability registers ***/
Index: usb/ehcivar.h
===================================================================
RCS file: /cvs/openbsd/src/sys/dev/usb/ehcivar.h,v
retrieving revision 1.6
diff -u -p -r1.6 ehcivar.h
--- usb/ehcivar.h 20 Oct 2004 12:45:31 -0000 1.6
+++ usb/ehcivar.h 21 Dec 2004 08:43:32 -0000
@@ -154,3 +154,4 @@ usbd_status ehci_init(ehci_softc_t *);
int ehci_intr(void *);
int ehci_detach(ehci_softc_t *, int);
int ehci_activate(device_ptr_t, enum devact);
+void ehci_shutdown(void *);
Visit your host, monkey.org