aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Brownell <david-b@pacbell.net>2005-09-23 20:14:37 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2005-10-28 19:47:38 -0400
commit7586269c0b52970f60bb69fcb86e765fc1d72309 (patch)
treea0cb04f9527101e8b9331350e4dd9d57e6e019e7
parent38ffdd62b0f466ef9126ac9f060ade5f218b4887 (diff)
[PATCH] USB: move handoff code
This moves the PCI quirk handling for USB host controllers from the PCI directory to the USB directory. Follow-on patches will need to: (a) merge these copies with the originals in the HCD reset methods. they don't wholly agree, despite doing the very same thing; and (b) eventually change it so "usb-handoff" is the default, to help get more robust USB/BIOS/input/... interactions. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> drivers/Makefile | 2 drivers/pci/quirks.c | 253 --------------------------------------- drivers/usb/Makefile | 1 drivers/usb/host/Makefile | 5 drivers/usb/host/pci-quirks.c | 272 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 280 insertions(+), 253 deletions(-)
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/pci/quirks.c253
-rw-r--r--drivers/usb/Makefile1
-rw-r--r--drivers/usb/host/Makefile5
-rw-r--r--drivers/usb/host/pci-quirks.c272
5 files changed, 280 insertions, 253 deletions
diff --git a/drivers/Makefile b/drivers/Makefile
index 1a109a6dd953..65670be6ff1a 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -5,7 +5,7 @@
5# Rewritten to use lists instead of if-statements. 5# Rewritten to use lists instead of if-statements.
6# 6#
7 7
8obj-$(CONFIG_PCI) += pci/ 8obj-$(CONFIG_PCI) += pci/ usb/
9obj-$(CONFIG_PARISC) += parisc/ 9obj-$(CONFIG_PARISC) += parisc/
10obj-y += video/ 10obj-y += video/
11obj-$(CONFIG_ACPI) += acpi/ 11obj-$(CONFIG_ACPI) += acpi/
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index ee1605906a3e..bbd9c2323d8c 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -7,6 +7,9 @@
7 * 7 *
8 * Copyright (c) 1999 Martin Mares <mj@ucw.cz> 8 * Copyright (c) 1999 Martin Mares <mj@ucw.cz>
9 * 9 *
10 * Init/reset quirks for USB host controllers should be in the
11 * USB quirks file, where their drivers can access reuse it.
12 *
10 * The bridge optimization stuff has been removed. If you really 13 * The bridge optimization stuff has been removed. If you really
11 * have a silly BIOS which is unable to set your host bridge right, 14 * have a silly BIOS which is unable to set your host bridge right,
12 * use the PowerTweak utility (see http://powertweak.sourceforge.net). 15 * use the PowerTweak utility (see http://powertweak.sourceforge.net).
@@ -645,28 +648,6 @@ static void quirk_via_irq(struct pci_dev *dev)
645DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_irq); 648DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_irq);
646 649
647/* 650/*
648 * PIIX3 USB: We have to disable USB interrupts that are
649 * hardwired to PIRQD# and may be shared with an
650 * external device.
651 *
652 * Legacy Support Register (LEGSUP):
653 * bit13: USB PIRQ Enable (USBPIRQDEN),
654 * bit4: Trap/SMI On IRQ Enable (USBSMIEN).
655 *
656 * We mask out all r/wc bits, too.
657 */
658static void __devinit quirk_piix3_usb(struct pci_dev *dev)
659{
660 u16 legsup;
661
662 pci_read_config_word(dev, 0xc0, &legsup);
663 legsup &= 0x50ef;
664 pci_write_config_word(dev, 0xc0, legsup);
665}
666DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_2, quirk_piix3_usb );
667DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_2, quirk_piix3_usb );
668
669/*
670 * VIA VT82C598 has its device ID settable and many BIOSes 651 * VIA VT82C598 has its device ID settable and many BIOSes
671 * set it to the ID of VT82C597 for backward compatibility. 652 * set it to the ID of VT82C597 for backward compatibility.
672 * We need to switch it off to be able to recognize the real 653 * We need to switch it off to be able to recognize the real
@@ -1039,234 +1020,6 @@ static void __init quirk_sis_96x_smbus(struct pci_dev *dev)
1039 pci_read_config_byte(dev, 0x77, &val); 1020 pci_read_config_byte(dev, 0x77, &val);
1040} 1021}
1041 1022
1042
1043#define UHCI_USBLEGSUP 0xc0 /* legacy support */
1044#define UHCI_USBCMD 0 /* command register */
1045#define UHCI_USBSTS 2 /* status register */
1046#define UHCI_USBINTR 4 /* interrupt register */
1047#define UHCI_USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */
1048#define UHCI_USBCMD_RUN (1 << 0) /* RUN/STOP bit */
1049#define UHCI_USBCMD_GRESET (1 << 2) /* Global reset */
1050#define UHCI_USBCMD_CONFIGURE (1 << 6) /* config semaphore */
1051#define UHCI_USBSTS_HALTED (1 << 5) /* HCHalted bit */
1052
1053#define OHCI_CONTROL 0x04
1054#define OHCI_CMDSTATUS 0x08
1055#define OHCI_INTRSTATUS 0x0c
1056#define OHCI_INTRENABLE 0x10
1057#define OHCI_INTRDISABLE 0x14
1058#define OHCI_OCR (1 << 3) /* ownership change request */
1059#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */
1060#define OHCI_INTR_OC (1 << 30) /* ownership change */
1061
1062#define EHCI_HCC_PARAMS 0x08 /* extended capabilities */
1063#define EHCI_USBCMD 0 /* command register */
1064#define EHCI_USBCMD_RUN (1 << 0) /* RUN/STOP bit */
1065#define EHCI_USBSTS 4 /* status register */
1066#define EHCI_USBSTS_HALTED (1 << 12) /* HCHalted bit */
1067#define EHCI_USBINTR 8 /* interrupt register */
1068#define EHCI_USBLEGSUP 0 /* legacy support register */
1069#define EHCI_USBLEGSUP_BIOS (1 << 16) /* BIOS semaphore */
1070#define EHCI_USBLEGSUP_OS (1 << 24) /* OS semaphore */
1071#define EHCI_USBLEGCTLSTS 4 /* legacy control/status */
1072#define EHCI_USBLEGCTLSTS_SOOE (1 << 13) /* SMI on ownership change */
1073
1074int usb_early_handoff __devinitdata = 0;
1075static int __init usb_handoff_early(char *str)
1076{
1077 usb_early_handoff = 1;
1078 return 0;
1079}
1080__setup("usb-handoff", usb_handoff_early);
1081
1082static void __devinit quirk_usb_handoff_uhci(struct pci_dev *pdev)
1083{
1084 unsigned long base = 0;
1085 int wait_time, delta;
1086 u16 val, sts;
1087 int i;
1088
1089 for (i = 0; i < PCI_ROM_RESOURCE; i++)
1090 if ((pci_resource_flags(pdev, i) & IORESOURCE_IO)) {
1091 base = pci_resource_start(pdev, i);
1092 break;
1093 }
1094
1095 if (!base)
1096 return;
1097
1098 /*
1099 * stop controller
1100 */
1101 sts = inw(base + UHCI_USBSTS);
1102 val = inw(base + UHCI_USBCMD);
1103 val &= ~(u16)(UHCI_USBCMD_RUN | UHCI_USBCMD_CONFIGURE);
1104 outw(val, base + UHCI_USBCMD);
1105
1106 /*
1107 * wait while it stops if it was running
1108 */
1109 if ((sts & UHCI_USBSTS_HALTED) == 0)
1110 {
1111 wait_time = 1000;
1112 delta = 100;
1113
1114 do {
1115 outw(0x1f, base + UHCI_USBSTS);
1116 udelay(delta);
1117 wait_time -= delta;
1118 val = inw(base + UHCI_USBSTS);
1119 if (val & UHCI_USBSTS_HALTED)
1120 break;
1121 } while (wait_time > 0);
1122 }
1123
1124 /*
1125 * disable interrupts & legacy support
1126 */
1127 outw(0, base + UHCI_USBINTR);
1128 outw(0x1f, base + UHCI_USBSTS);
1129 pci_read_config_word(pdev, UHCI_USBLEGSUP, &val);
1130 if (val & 0xbf)
1131 pci_write_config_word(pdev, UHCI_USBLEGSUP, UHCI_USBLEGSUP_DEFAULT);
1132
1133}
1134
1135static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
1136{
1137 void __iomem *base;
1138 int wait_time;
1139
1140 base = ioremap_nocache(pci_resource_start(pdev, 0),
1141 pci_resource_len(pdev, 0));
1142 if (base == NULL) return;
1143
1144 if (readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) {
1145 wait_time = 500; /* 0.5 seconds */
1146 writel(OHCI_INTR_OC, base + OHCI_INTRENABLE);
1147 writel(OHCI_OCR, base + OHCI_CMDSTATUS);
1148 while (wait_time > 0 &&
1149 readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) {
1150 wait_time -= 10;
1151 msleep(10);
1152 }
1153 }
1154
1155 /*
1156 * disable interrupts
1157 */
1158 writel(~(u32)0, base + OHCI_INTRDISABLE);
1159 writel(~(u32)0, base + OHCI_INTRSTATUS);
1160
1161 iounmap(base);
1162}
1163
1164static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
1165{
1166 int wait_time, delta;
1167 void __iomem *base, *op_reg_base;
1168 u32 hcc_params, val, temp;
1169 u8 cap_length;
1170
1171 base = ioremap_nocache(pci_resource_start(pdev, 0),
1172 pci_resource_len(pdev, 0));
1173 if (base == NULL) return;
1174
1175 cap_length = readb(base);
1176 op_reg_base = base + cap_length;
1177 hcc_params = readl(base + EHCI_HCC_PARAMS);
1178 hcc_params = (hcc_params >> 8) & 0xff;
1179 if (hcc_params) {
1180 pci_read_config_dword(pdev,
1181 hcc_params + EHCI_USBLEGSUP,
1182 &val);
1183 if (((val & 0xff) == 1) && (val & EHCI_USBLEGSUP_BIOS)) {
1184 /*
1185 * Ok, BIOS is in smm mode, try to hand off...
1186 */
1187 pci_read_config_dword(pdev,
1188 hcc_params + EHCI_USBLEGCTLSTS,
1189 &temp);
1190 pci_write_config_dword(pdev,
1191 hcc_params + EHCI_USBLEGCTLSTS,
1192 temp | EHCI_USBLEGCTLSTS_SOOE);
1193 val |= EHCI_USBLEGSUP_OS;
1194 pci_write_config_dword(pdev,
1195 hcc_params + EHCI_USBLEGSUP,
1196 val);
1197
1198 wait_time = 500;
1199 do {
1200 msleep(10);
1201 wait_time -= 10;
1202 pci_read_config_dword(pdev,
1203 hcc_params + EHCI_USBLEGSUP,
1204 &val);
1205 } while (wait_time && (val & EHCI_USBLEGSUP_BIOS));
1206 if (!wait_time) {
1207 /*
1208 * well, possibly buggy BIOS...
1209 */
1210 printk(KERN_WARNING "EHCI early BIOS handoff "
1211 "failed (BIOS bug ?)\n");
1212 pci_write_config_dword(pdev,
1213 hcc_params + EHCI_USBLEGSUP,
1214 EHCI_USBLEGSUP_OS);
1215 pci_write_config_dword(pdev,
1216 hcc_params + EHCI_USBLEGCTLSTS,
1217 0);
1218 }
1219 }
1220 }
1221
1222 /*
1223 * halt EHCI & disable its interrupts in any case
1224 */
1225 val = readl(op_reg_base + EHCI_USBSTS);
1226 if ((val & EHCI_USBSTS_HALTED) == 0) {
1227 val = readl(op_reg_base + EHCI_USBCMD);
1228 val &= ~EHCI_USBCMD_RUN;
1229 writel(val, op_reg_base + EHCI_USBCMD);
1230
1231 wait_time = 2000;
1232 delta = 100;
1233 do {
1234 writel(0x3f, op_reg_base + EHCI_USBSTS);
1235 udelay(delta);
1236 wait_time -= delta;
1237 val = readl(op_reg_base + EHCI_USBSTS);
1238 if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) {
1239 break;
1240 }
1241 } while (wait_time > 0);
1242 }
1243 writel(0, op_reg_base + EHCI_USBINTR);
1244 writel(0x3f, op_reg_base + EHCI_USBSTS);
1245
1246 iounmap(base);
1247
1248 return;
1249}
1250
1251
1252
1253static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
1254{
1255 if (!usb_early_handoff)
1256 return;
1257
1258 if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x00)) { /* UHCI */
1259 quirk_usb_handoff_uhci(pdev);
1260 } else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x10)) { /* OHCI */
1261 quirk_usb_handoff_ohci(pdev);
1262 } else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x20)) { /* EHCI */
1263 quirk_usb_disable_ehci(pdev);
1264 }
1265
1266 return;
1267}
1268DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);
1269
1270/* 1023/*
1271 * ... This is further complicated by the fact that some SiS96x south 1024 * ... This is further complicated by the fact that some SiS96x south
1272 * bridges pretend to be 85C503/5513 instead. In that case see if we 1025 * bridges pretend to be 85C503/5513 instead. In that case see if we
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index df014c2a7c54..aa554f9805ee 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_USB) += core/
8 8
9obj-$(CONFIG_USB_MON) += mon/ 9obj-$(CONFIG_USB_MON) += mon/
10 10
11obj-$(CONFIG_PCI) += host/
11obj-$(CONFIG_USB_EHCI_HCD) += host/ 12obj-$(CONFIG_USB_EHCI_HCD) += host/
12obj-$(CONFIG_USB_ISP116X_HCD) += host/ 13obj-$(CONFIG_USB_ISP116X_HCD) += host/
13obj-$(CONFIG_USB_OHCI_HCD) += host/ 14obj-$(CONFIG_USB_OHCI_HCD) += host/
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 350d14fc1cc9..58321d3f314c 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -1,8 +1,9 @@
1# 1#
2# Makefile for USB Host Controller Driver 2# Makefile for USB Host Controller Drivers
3# framework and drivers
4# 3#
5 4
5obj-$(CONFIG_PCI) += pci-quirks.o
6
6obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o 7obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
7obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o 8obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o
8obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o 9obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
new file mode 100644
index 000000000000..8ee5c3ed4cd6
--- /dev/null
+++ b/drivers/usb/host/pci-quirks.c
@@ -0,0 +1,272 @@
1/*
2 * This file contains code to reset and initialize USB host controllers.
3 * Some of it includes work-arounds for PCI hardware and BIOS quirks.
4 * It may need to run early during booting -- before USB would normally
5 * initialize -- to ensure that Linux doesn't use any legacy modes.
6 *
7 * Copyright (c) 1999 Martin Mares <mj@ucw.cz>
8 * (and others)
9 */
10
11#include <linux/config.h>
12#include <linux/types.h>
13#include <linux/kernel.h>
14#include <linux/pci.h>
15#include <linux/init.h>
16#include <linux/delay.h>
17#include <linux/acpi.h>
18
19
20/*
21 * PIIX3 USB: We have to disable USB interrupts that are
22 * hardwired to PIRQD# and may be shared with an
23 * external device.
24 *
25 * Legacy Support Register (LEGSUP):
26 * bit13: USB PIRQ Enable (USBPIRQDEN),
27 * bit4: Trap/SMI On IRQ Enable (USBSMIEN).
28 *
29 * We mask out all r/wc bits, too.
30 */
31static void __devinit quirk_piix3_usb(struct pci_dev *dev)
32{
33 u16 legsup;
34
35 pci_read_config_word(dev, 0xc0, &legsup);
36 legsup &= 0x50ef;
37 pci_write_config_word(dev, 0xc0, legsup);
38}
39DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_2, quirk_piix3_usb );
40DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_2, quirk_piix3_usb );
41
42
43/* FIXME these should be the guts of hcd->reset() methods; resolve all
44 * the differences between this version and the HCD's version.
45 */
46
47#define UHCI_USBLEGSUP 0xc0 /* legacy support */
48#define UHCI_USBCMD 0 /* command register */
49#define UHCI_USBSTS 2 /* status register */
50#define UHCI_USBINTR 4 /* interrupt register */
51#define UHCI_USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */
52#define UHCI_USBCMD_RUN (1 << 0) /* RUN/STOP bit */
53#define UHCI_USBCMD_GRESET (1 << 2) /* Global reset */
54#define UHCI_USBCMD_CONFIGURE (1 << 6) /* config semaphore */
55#define UHCI_USBSTS_HALTED (1 << 5) /* HCHalted bit */
56
57#define OHCI_CONTROL 0x04
58#define OHCI_CMDSTATUS 0x08
59#define OHCI_INTRSTATUS 0x0c
60#define OHCI_INTRENABLE 0x10
61#define OHCI_INTRDISABLE 0x14
62#define OHCI_OCR (1 << 3) /* ownership change request */
63#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */
64#define OHCI_INTR_OC (1 << 30) /* ownership change */
65
66#define EHCI_HCC_PARAMS 0x08 /* extended capabilities */
67#define EHCI_USBCMD 0 /* command register */
68#define EHCI_USBCMD_RUN (1 << 0) /* RUN/STOP bit */
69#define EHCI_USBSTS 4 /* status register */
70#define EHCI_USBSTS_HALTED (1 << 12) /* HCHalted bit */
71#define EHCI_USBINTR 8 /* interrupt register */
72#define EHCI_USBLEGSUP 0 /* legacy support register */
73#define EHCI_USBLEGSUP_BIOS (1 << 16) /* BIOS semaphore */
74#define EHCI_USBLEGSUP_OS (1 << 24) /* OS semaphore */
75#define EHCI_USBLEGCTLSTS 4 /* legacy control/status */
76#define EHCI_USBLEGCTLSTS_SOOE (1 << 13) /* SMI on ownership change */
77
78int usb_early_handoff __devinitdata = 0;
79static int __init usb_handoff_early(char *str)
80{
81 usb_early_handoff = 1;
82 return 0;
83}
84__setup("usb-handoff", usb_handoff_early);
85
86static void __devinit quirk_usb_handoff_uhci(struct pci_dev *pdev)
87{
88 unsigned long base = 0;
89 int wait_time, delta;
90 u16 val, sts;
91 int i;
92
93 for (i = 0; i < PCI_ROM_RESOURCE; i++)
94 if ((pci_resource_flags(pdev, i) & IORESOURCE_IO)) {
95 base = pci_resource_start(pdev, i);
96 break;
97 }
98
99 if (!base)
100 return;
101
102 /*
103 * stop controller
104 */
105 sts = inw(base + UHCI_USBSTS);
106 val = inw(base + UHCI_USBCMD);
107 val &= ~(u16)(UHCI_USBCMD_RUN | UHCI_USBCMD_CONFIGURE);
108 outw(val, base + UHCI_USBCMD);
109
110 /*
111 * wait while it stops if it was running
112 */
113 if ((sts & UHCI_USBSTS_HALTED) == 0)
114 {
115 wait_time = 1000;
116 delta = 100;
117
118 do {
119 outw(0x1f, base + UHCI_USBSTS);
120 udelay(delta);
121 wait_time -= delta;
122 val = inw(base + UHCI_USBSTS);
123 if (val & UHCI_USBSTS_HALTED)
124 break;
125 } while (wait_time > 0);
126 }
127
128 /*
129 * disable interrupts & legacy support
130 */
131 outw(0, base + UHCI_USBINTR);
132 outw(0x1f, base + UHCI_USBSTS);
133 pci_read_config_word(pdev, UHCI_USBLEGSUP, &val);
134 if (val & 0xbf)
135 pci_write_config_word(pdev, UHCI_USBLEGSUP, UHCI_USBLEGSUP_DEFAULT);
136
137}
138
139static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
140{
141 void __iomem *base;
142 int wait_time;
143
144 base = ioremap_nocache(pci_resource_start(pdev, 0),
145 pci_resource_len(pdev, 0));
146 if (base == NULL) return;
147
148 if (readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) {
149 wait_time = 500; /* 0.5 seconds */
150 writel(OHCI_INTR_OC, base + OHCI_INTRENABLE);
151 writel(OHCI_OCR, base + OHCI_CMDSTATUS);
152 while (wait_time > 0 &&
153 readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) {
154 wait_time -= 10;
155 msleep(10);
156 }
157 }
158
159 /*
160 * disable interrupts
161 */
162 writel(~(u32)0, base + OHCI_INTRDISABLE);
163 writel(~(u32)0, base + OHCI_INTRSTATUS);
164
165 iounmap(base);
166}
167
168static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
169{
170 int wait_time, delta;
171 void __iomem *base, *op_reg_base;
172 u32 hcc_params, val, temp;
173 u8 cap_length;
174
175 base = ioremap_nocache(pci_resource_start(pdev, 0),
176 pci_resource_len(pdev, 0));
177 if (base == NULL) return;
178
179 cap_length = readb(base);
180 op_reg_base = base + cap_length;
181 hcc_params = readl(base + EHCI_HCC_PARAMS);
182 hcc_params = (hcc_params >> 8) & 0xff;
183 if (hcc_params) {
184 pci_read_config_dword(pdev,
185 hcc_params + EHCI_USBLEGSUP,
186 &val);
187 if (((val & 0xff) == 1) && (val & EHCI_USBLEGSUP_BIOS)) {
188 /*
189 * Ok, BIOS is in smm mode, try to hand off...
190 */
191 pci_read_config_dword(pdev,
192 hcc_params + EHCI_USBLEGCTLSTS,
193 &temp);
194 pci_write_config_dword(pdev,
195 hcc_params + EHCI_USBLEGCTLSTS,
196 temp | EHCI_USBLEGCTLSTS_SOOE);
197 val |= EHCI_USBLEGSUP_OS;
198 pci_write_config_dword(pdev,
199 hcc_params + EHCI_USBLEGSUP,
200 val);
201
202 wait_time = 500;
203 do {
204 msleep(10);
205 wait_time -= 10;
206 pci_read_config_dword(pdev,
207 hcc_params + EHCI_USBLEGSUP,
208 &val);
209 } while (wait_time && (val & EHCI_USBLEGSUP_BIOS));
210 if (!wait_time) {
211 /*
212 * well, possibly buggy BIOS...
213 */
214 printk(KERN_WARNING "EHCI early BIOS handoff "
215 "failed (BIOS bug ?)\n");
216 pci_write_config_dword(pdev,
217 hcc_params + EHCI_USBLEGSUP,
218 EHCI_USBLEGSUP_OS);
219 pci_write_config_dword(pdev,
220 hcc_params + EHCI_USBLEGCTLSTS,
221 0);
222 }
223 }
224 }
225
226 /*
227 * halt EHCI & disable its interrupts in any case
228 */
229 val = readl(op_reg_base + EHCI_USBSTS);
230 if ((val & EHCI_USBSTS_HALTED) == 0) {
231 val = readl(op_reg_base + EHCI_USBCMD);
232 val &= ~EHCI_USBCMD_RUN;
233 writel(val, op_reg_base + EHCI_USBCMD);
234
235 wait_time = 2000;
236 delta = 100;
237 do {
238 writel(0x3f, op_reg_base + EHCI_USBSTS);
239 udelay(delta);
240 wait_time -= delta;
241 val = readl(op_reg_base + EHCI_USBSTS);
242 if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) {
243 break;
244 }
245 } while (wait_time > 0);
246 }
247 writel(0, op_reg_base + EHCI_USBINTR);
248 writel(0x3f, op_reg_base + EHCI_USBSTS);
249
250 iounmap(base);
251
252 return;
253}
254
255
256
257static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
258{
259 if (!usb_early_handoff)
260 return;
261
262 if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x00)) { /* UHCI */
263 quirk_usb_handoff_uhci(pdev);
264 } else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x10)) { /* OHCI */
265 quirk_usb_handoff_ohci(pdev);
266 } else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x20)) { /* EHCI */
267 quirk_usb_disable_ehci(pdev);
268 }
269
270 return;
271}
272DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);