<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">Index: sys/arch/x86/include/pci_machdep_common.h
===================================================================
RCS file: /cvsroot/src/sys/arch/x86/include/pci_machdep_common.h,v
retrieving revision 1.3
diff -u -r1.3 pci_machdep_common.h
--- sys/arch/x86/include/pci_machdep_common.h	28 Apr 2010 21:27:14 -0000	1.3
+++ sys/arch/x86/include/pci_machdep_common.h	27 Oct 2010 14:56:51 -0000
@@ -135,4 +135,6 @@
 void pci_mmio_range_infer(pci_chipset_tag_t, int, int, bus_addr_t *,
     bus_size_t *);
 
+void pci_usb_fixup(pci_chipset_tag_t);
+
 #endif /* _X86_PCI_MACHDEP_COMMON_H_ */
Index: sys/arch/i386/i386/machdep.c
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/i386/machdep.c,v
retrieving revision 1.696
diff -u -r1.696 machdep.c
--- sys/arch/i386/i386/machdep.c	24 Oct 2010 07:53:04 -0000	1.696
+++ sys/arch/i386/i386/machdep.c	27 Oct 2010 14:56:51 -0000
@@ -1414,6 +1414,10 @@
 	 */
 	initgdt(NULL);
 #endif /* XEN */
+
+#if NPCI &gt; 0
+	pci_usb_fixup(NULL);
+#endif
 	consinit();	/* XXX SHOULD NOT BE DONE HERE */
 
 #ifdef DEBUG_MEMLOAD
Index: sys/arch/amd64/amd64/machdep.c
===================================================================
RCS file: /cvsroot/src/sys/arch/amd64/amd64/machdep.c,v
retrieving revision 1.154
diff -u -r1.154 machdep.c
--- sys/arch/amd64/amd64/machdep.c	24 Oct 2010 07:53:05 -0000	1.154
+++ sys/arch/amd64/amd64/machdep.c	27 Oct 2010 14:56:51 -0000
@@ -1280,6 +1280,9 @@
 	x86_bus_space_init();
 #endif
 
+#if NPCI &gt; 0
+	pci_usb_fixup(NULL);
+#endif
 	consinit();	/* XXX SHOULD NOT BE DONE HERE */
 
 	/*
Index: sys/arch/x86/pci/pci_usb.c
===================================================================
RCS file: sys/arch/x86/pci/pci_usb.c
diff -N sys/arch/x86/pci/pci_usb.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ sys/arch/x86/pci/pci_usb.c	27 Oct 2010 14:56:51 -0000
@@ -0,0 +1,242 @@
+/* $NetBSD$ */
+
+/*-
+ * Copyright (c) 2010 Jared D. McNeill &lt;jmcneill@invisible.ca&gt;
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include &lt;sys/cdefs.h&gt;
+__KERNEL_RCSID(0, "$NetBSD: platform.c,v 1.9 2010/09/06 15:54:27 jmcneill Exp $");
+
+#include &lt;sys/types.h&gt;
+#include &lt;sys/param.h&gt;
+#include &lt;sys/kernel.h&gt;
+
+#include &lt;dev/pci/pcireg.h&gt;
+#include &lt;dev/pci/pcivar.h&gt;
+
+#include &lt;dev/usb/usb.h&gt;
+#include &lt;dev/usb/ehcireg.h&gt;
+#include &lt;dev/usb/uhcireg.h&gt;
+#include &lt;dev/usb/ohcireg.h&gt;
+
+static void
+pci_usb_attach_args(pci_chipset_tag_t pc, pcitag_t tag,
+    struct pci_attach_args *pa)
+{
+	int bus, device, function;
+	pcireg_t csr;
+
+	pci_decompose_tag(pc, tag, &amp;bus, &amp;device, &amp;function);
+	csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
+
+	pa-&gt;pa_iot = x86_bus_space_io;
+	pa-&gt;pa_memt = x86_bus_space_mem;
+	pa-&gt;pa_dmat = &amp;pci_bus_dma_tag;
+#ifdef _LP64
+	pa-&gt;pa_dmat64 = &amp;pci_bus_dma64_tag;
+#else
+	pa-&gt;pa_dmat64 = NULL;
+#endif
+	pa-&gt;pa_pc = pc;
+	pa-&gt;pa_bus = bus;
+	pa-&gt;pa_device = device;
+	pa-&gt;pa_function = function;
+	pa-&gt;pa_tag = tag;
+	pa-&gt;pa_id = pci_conf_read(pc, tag, PCI_ID_REG);
+	pa-&gt;pa_class = pci_conf_read(pc, tag, PCI_CLASS_REG);
+	pa-&gt;pa_flags = 0;
+	if (csr &amp; PCI_COMMAND_IO_ENABLE)
+		pa-&gt;pa_flags |= PCI_FLAGS_IO_ENABLED;
+	if (csr &amp; PCI_COMMAND_MEM_ENABLE)
+		pa-&gt;pa_flags |= PCI_FLAGS_MEM_ENABLED;
+}
+
+static void
+pci_usb_fixup_ehci(pci_chipset_tag_t pc, pcitag_t tag)
+{
+	struct pci_attach_args pa;
+	bus_space_tag_t iot;
+	bus_space_handle_t ioh;
+	bus_size_t size;
+	uint32_t cparams, addr, cap;
+	pcireg_t legsup;
+	int maxcap = 10;
+	int ms;
+
+	pci_usb_attach_args(pc, tag, &amp;pa);
+
+	if (pci_mapreg_map(&amp;pa, PCI_CBMEM, PCI_MAPREG_TYPE_MEM, 0,
+	    &amp;iot, &amp;ioh, NULL, &amp;size))
+		return;
+
+	cparams = bus_space_read_4(iot, ioh, 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)
+			goto next;
+		legsup = pci_conf_read(pc, tag, addr + PCI_EHCI_USBLEGSUP);
+		/* Ask BIOS to give up ownership */
+		pci_conf_write(pc, tag, addr + PCI_EHCI_USBLEGSUP,
+		    legsup | EHCI_LEG_HC_OS_OWNED);
+		if (legsup &amp; EHCI_LEG_HC_BIOS_OWNED) {
+			for (ms = 0; ms &lt; 1000; ms++) {
+				legsup = pci_conf_read(pc, tag,
+				    addr + PCI_EHCI_USBLEGSUP);
+				if (!(legsup &amp; EHCI_LEG_HC_BIOS_OWNED))
+					break;
+				delay(1000);
+			}
+			if (ms == 1000)
+				pci_conf_write(pc, tag,
+				    addr + PCI_EHCI_USBLEGSUP, 0);
+		}
+
+		/* Disable SMI */
+		pci_conf_write(pc, tag, addr + PCI_EHCI_USBLEGCTLSTS,
+		    EHCI_LEG_EXT_SMI_BAR | EHCI_LEG_EXT_SMI_PCICMD |
+		    EHCI_LEG_EXT_SMI_OS_CHANGE);
+
+next:
+		if (--maxcap &lt; 0)
+			break;
+		addr = EHCI_CAP_GET_NEXT(cap);
+	}
+
+	bus_space_unmap(iot, ioh, size);
+}
+
+static void
+pci_usb_fixup_uhci(pci_chipset_tag_t pc, pcitag_t tag)
+{
+	struct pci_attach_args pa;
+	bus_space_tag_t iot;
+	bus_space_handle_t ioh;
+	bus_size_t size;
+
+	pci_usb_attach_args(pc, tag, &amp;pa);
+
+	if (pci_mapreg_map(&amp;pa, PCI_CBMEM, PCI_MAPREG_TYPE_MEM, 0,
+	    &amp;iot, &amp;ioh, NULL, &amp;size))
+		return;
+
+	pci_conf_write(pc, tag, PCI_LEGSUP, PCI_LEGSUP_USBPIRQDEN);
+	bus_space_write_2(iot, ioh, UHCI_INTR, 0);
+	bus_space_write_2(iot, ioh, UHCI_STS,
+	    bus_space_read_2(iot, ioh, UHCI_STS));
+
+	bus_space_unmap(iot, ioh, size);
+}
+
+static void
+pci_usb_fixup_ohci(pci_chipset_tag_t pc, pcitag_t tag)
+{
+	struct pci_attach_args pa;
+	bus_space_tag_t iot;
+	bus_space_handle_t ioh;
+	bus_size_t size;
+	uint32_t ctl, rwc, s;
+	int i;
+
+	pci_usb_attach_args(pc, tag, &amp;pa);
+
+	if (pci_mapreg_map(&amp;pa, PCI_CBMEM, PCI_MAPREG_TYPE_MEM, 0,
+	    &amp;iot, &amp;ioh, NULL, &amp;size))
+		return;
+
+	ctl = bus_space_read_4(iot, ioh, OHCI_CONTROL);
+	if (ctl &amp; OHCI_IR) {
+		rwc = ctl &amp; OHCI_RWC;
+
+		s = bus_space_read_4(iot, ioh, OHCI_COMMAND_STATUS);
+		bus_space_write_4(iot, ioh, OHCI_COMMAND_STATUS,
+		    s | OHCI_OCR);
+		for (i = 0; i &lt; 100 &amp;&amp; (ctl &amp; OHCI_IR); i++) {
+			delay(2000);
+			ctl = bus_space_read_4(iot, ioh, OHCI_CONTROL);
+		}
+		bus_space_write_4(iot, ioh, OHCI_INTERRUPT_DISABLE,
+		    OHCI_MIE);
+		if ((ctl &amp; OHCI_IR) == 0) {
+			bus_space_write_4(iot, ioh, OHCI_CONTROL,
+			    OHCI_HCFS_RESET | rwc);
+			delay(100000);
+		}
+	}
+
+	bus_space_unmap(iot, ioh, size);
+}
+
+static void
+pci_usb_fixup_cb(pci_chipset_tag_t pc, pcitag_t tag, void *priv)
+{
+	void (*fixup)(pci_chipset_tag_t, pcitag_t) = NULL;
+	int bus, device, function;
+	pcireg_t class, id;
+	const char *type;
+
+	class = pci_conf_read(pc, tag, PCI_CLASS_REG);
+	id = pci_conf_read(pc, tag, PCI_ID_REG);
+
+	if (PCI_CLASS(class) != PCI_CLASS_SERIALBUS ||
+	    PCI_SUBCLASS(class) != PCI_SUBCLASS_SERIALBUS_USB)
+		return;
+
+	switch (PCI_INTERFACE(class)) {
+	case PCI_INTERFACE_EHCI:
+		type = "EHCI";
+		fixup = pci_usb_fixup_ehci;
+		break;
+	case PCI_INTERFACE_UHCI:
+		type = "UHCI";
+		fixup = pci_usb_fixup_uhci;
+		break;
+	case PCI_INTERFACE_OHCI:
+		type = "OHCI";
+		fixup = pci_usb_fixup_ohci;
+		break;
+	}
+
+	if (fixup) {
+		pci_decompose_tag(pc, tag, &amp;bus, &amp;device, &amp;function);
+		aprint_debug("PCI%03d:%02d:%d %04x:%04x %s fixup\n",
+		    bus, device, function,
+		    PCI_VENDOR(id), PCI_PRODUCT(id), type);
+		fixup(pc, tag);
+	} else {
+		aprint_debug("PCI%03d:%02d:%d %04x:%04x "
+		    "unknown USB interface 0x%x\n",
+		    bus, device, function,
+		    PCI_VENDOR(id), PCI_PRODUCT(id), PCI_INTERFACE(class));
+	}
+}
+
+void
+pci_usb_fixup(pci_chipset_tag_t pc)
+{
+	int maxbus = 0;	/* XXX USB controller is likely on bus 0 */
+
+	pci_device_foreach(pc, maxbus, pci_usb_fixup_cb, NULL);
+}
</pre></body></html>