ChangeSet@1.1831, 2004-04-03 23:30:39+02:00, vojtech@suse.cz input: Disable USB Legacy emulation in PCI quirks. quirks.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 62 insertions(+) diff -Nru a/drivers/pci/quirks.c b/drivers/pci/quirks.c --- a/drivers/pci/quirks.c Sat Apr 3 23:30:49 2004 +++ b/drivers/pci/quirks.c Sat Apr 3 23:30:49 2004 @@ -868,6 +868,66 @@ } #endif /* CONFIG_SCSI_SATA */ + +#define UHCI_USBLEGSUP 0xc0 /* legacy support */ +#define UHCI_USBCMD 0 /* command register */ +#define UHCI_USBINTR 4 /* interrupt register */ +#define UHCI_USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */ +#define UHCI_USBCMD_GRESET 0x0004 /* Global reset */ + +#define OHCI_CONTROL 0x04 +#define OHCI_CMDSTATUS 0x08 +#define OHCI_INTRENABLE 0x10 +#define OHCI_OCR (1 << 3) /* ownership change request */ +#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */ +#define OHCI_INTR_OC (1 << 30) /* ownership change */ + +static void __init quirk_usb_disable_smm_bios(struct pci_dev *pdev) +{ + + if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x00)) { /* UHCI */ + int i; + unsigned long base = 0;; + + for (i = 0; i < PCI_ROM_RESOURCE; i++) + if ((pci_resource_flags(pdev, i) & IORESOURCE_IO)) { + base = pci_resource_start(pdev, i); + break; + } + + if (!base) + return; + + outw(0, base + UHCI_USBINTR); + outw(UHCI_USBCMD_GRESET, base + UHCI_USBCMD); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((HZ*50+999) / 1000); + outw(0, base + UHCI_USBCMD); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((HZ*10+999) / 1000); + + pci_write_config_word(pdev, UHCI_USBLEGSUP, UHCI_USBLEGSUP_DEFAULT); + } + + if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x10)) { /* OHCI */ + char *base = ioremap_nocache(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (base == NULL) return; + + if (readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) { + int temp = 500; /* arbitrary: five seconds */ + writel(OHCI_INTR_OC, base + OHCI_INTRENABLE); + writel(OHCI_OCR, base + OHCI_CMDSTATUS); + while (temp && readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) { + temp--; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout( HZ / 100); + } + } + iounmap(base); + } +} + /* * The main table of quirks. * @@ -983,6 +1043,8 @@ { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_intel_ide_combined }, #endif /* CONFIG_SCSI_SATA */ + + { PCI_FIXUP_FINAL, PCI_ANY_ID, PCI_ANY_ID, quirk_usb_disable_smm_bios }, { 0 } };