]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * OHCI HCD (Host Controller Driver) for USB. | |
3 | * | |
4 | * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> | |
5 | * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> | |
6 | * | |
7 | * [ Initialisation is based on Linus' ] | |
8 | * [ uhci code and gregs ohci fragments ] | |
9 | * [ (C) Copyright 1999 Linus Torvalds ] | |
10 | * [ (C) Copyright 1999 Gregory P. Smith] | |
11 | * | |
12 | * PCI Bus Glue | |
13 | * | |
14 | * This file is licenced under the GPL. | |
15 | */ | |
16 | ||
8c870933 | 17 | #ifdef CONFIG_PPC_PMAC |
1da177e4 LT |
18 | #include <asm/machdep.h> |
19 | #include <asm/pmac_feature.h> | |
20 | #include <asm/pci-bridge.h> | |
21 | #include <asm/prom.h> | |
1da177e4 LT |
22 | #endif |
23 | ||
24 | #ifndef CONFIG_PCI | |
25 | #error "This file is PCI bus glue. CONFIG_PCI must be defined." | |
26 | #endif | |
27 | ||
28 | /*-------------------------------------------------------------------------*/ | |
29 | ||
30 | static int | |
31 | ohci_pci_reset (struct usb_hcd *hcd) | |
32 | { | |
33 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); | |
34 | ||
35 | ohci_hcd_init (ohci); | |
36 | return ohci_init (ohci); | |
37 | } | |
38 | ||
39 | static int __devinit | |
40 | ohci_pci_start (struct usb_hcd *hcd) | |
41 | { | |
42 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); | |
43 | int ret; | |
44 | ||
45 | if(hcd->self.controller && hcd->self.controller->bus == &pci_bus_type) { | |
46 | struct pci_dev *pdev = to_pci_dev(hcd->self.controller); | |
47 | ||
48 | /* AMD 756, for most chips (early revs), corrupts register | |
49 | * values on read ... so enable the vendor workaround. | |
50 | */ | |
51 | if (pdev->vendor == PCI_VENDOR_ID_AMD | |
52 | && pdev->device == 0x740c) { | |
53 | ohci->flags = OHCI_QUIRK_AMD756; | |
0e498763 | 54 | ohci_dbg (ohci, "AMD756 erratum 4 workaround\n"); |
1da177e4 LT |
55 | // also somewhat erratum 10 (suspend/resume issues) |
56 | } | |
57 | ||
58 | /* FIXME for some of the early AMD 760 southbridges, OHCI | |
59 | * won't work at all. blacklist them. | |
60 | */ | |
61 | ||
62 | /* Apple's OHCI driver has a lot of bizarre workarounds | |
63 | * for this chip. Evidently control and bulk lists | |
64 | * can get confused. (B&W G3 models, and ...) | |
65 | */ | |
66 | else if (pdev->vendor == PCI_VENDOR_ID_OPTI | |
67 | && pdev->device == 0xc861) { | |
0e498763 | 68 | ohci_dbg (ohci, |
1da177e4 LT |
69 | "WARNING: OPTi workarounds unavailable\n"); |
70 | } | |
71 | ||
72 | /* Check for NSC87560. We have to look at the bridge (fn1) to | |
73 | * identify the USB (fn2). This quirk might apply to more or | |
74 | * even all NSC stuff. | |
75 | */ | |
76 | else if (pdev->vendor == PCI_VENDOR_ID_NS) { | |
77 | struct pci_dev *b; | |
78 | ||
79 | b = pci_find_slot (pdev->bus->number, | |
80 | PCI_DEVFN (PCI_SLOT (pdev->devfn), 1)); | |
81 | if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO | |
82 | && b->vendor == PCI_VENDOR_ID_NS) { | |
83 | ohci->flags |= OHCI_QUIRK_SUPERIO; | |
0e498763 | 84 | ohci_dbg (ohci, "Using NSC SuperIO setup\n"); |
1da177e4 LT |
85 | } |
86 | } | |
0e498763 DB |
87 | |
88 | /* Check for Compaq's ZFMicro chipset, which needs short | |
89 | * delays before control or bulk queues get re-activated | |
90 | * in finish_unlinks() | |
91 | */ | |
92 | else if (pdev->vendor == PCI_VENDOR_ID_COMPAQ | |
93 | && pdev->device == 0xa0f8) { | |
94 | ohci->flags |= OHCI_QUIRK_ZFMICRO; | |
95 | ohci_dbg (ohci, | |
96 | "enabled Compaq ZFMicro chipset quirk\n"); | |
97 | } | |
1da177e4 LT |
98 | } |
99 | ||
100 | /* NOTE: there may have already been a first reset, to | |
101 | * keep bios/smm irqs from making trouble | |
102 | */ | |
103 | if ((ret = ohci_run (ohci)) < 0) { | |
104 | ohci_err (ohci, "can't start\n"); | |
105 | ohci_stop (hcd); | |
106 | return ret; | |
107 | } | |
108 | return 0; | |
109 | } | |
110 | ||
111 | #ifdef CONFIG_PM | |
112 | ||
9a5d3e98 | 113 | static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) |
1da177e4 | 114 | { |
f197b2c5 | 115 | /* root hub was already suspended */ |
1da177e4 | 116 | |
f197b2c5 DB |
117 | /* FIXME these PMAC things get called in the wrong places. ASIC |
118 | * clocks should be turned off AFTER entering D3, and on BEFORE | |
119 | * trying to enter D0. Evidently the PCI layer doesn't currently | |
120 | * provide the right sort of platform hooks for this ... | |
121 | */ | |
8c870933 | 122 | #ifdef CONFIG_PPC_PMAC |
1da177e4 LT |
123 | if (_machine == _MACH_Pmac) { |
124 | struct device_node *of_node; | |
125 | ||
126 | /* Disable USB PAD & cell clock */ | |
127 | of_node = pci_device_to_OF_node (to_pci_dev(hcd->self.controller)); | |
128 | if (of_node) | |
129 | pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0); | |
130 | } | |
8c870933 | 131 | #endif /* CONFIG_PPC_PMAC */ |
1da177e4 LT |
132 | return 0; |
133 | } | |
134 | ||
135 | ||
136 | static int ohci_pci_resume (struct usb_hcd *hcd) | |
137 | { | |
8c870933 | 138 | #ifdef CONFIG_PPC_PMAC |
1da177e4 LT |
139 | if (_machine == _MACH_Pmac) { |
140 | struct device_node *of_node; | |
141 | ||
142 | /* Re-enable USB PAD & cell clock */ | |
143 | of_node = pci_device_to_OF_node (to_pci_dev(hcd->self.controller)); | |
144 | if (of_node) | |
145 | pmac_call_feature (PMAC_FTR_USB_ENABLE, of_node, 0, 1); | |
146 | } | |
8c870933 | 147 | #endif /* CONFIG_PPC_PMAC */ |
1da177e4 | 148 | |
f197b2c5 DB |
149 | usb_hcd_resume_root_hub(hcd); |
150 | return 0; | |
1da177e4 LT |
151 | } |
152 | ||
153 | #endif /* CONFIG_PM */ | |
154 | ||
155 | ||
156 | /*-------------------------------------------------------------------------*/ | |
157 | ||
158 | static const struct hc_driver ohci_pci_hc_driver = { | |
159 | .description = hcd_name, | |
160 | .product_desc = "OHCI Host Controller", | |
161 | .hcd_priv_size = sizeof(struct ohci_hcd), | |
162 | ||
163 | /* | |
164 | * generic hardware linkage | |
165 | */ | |
166 | .irq = ohci_irq, | |
167 | .flags = HCD_MEMORY | HCD_USB11, | |
168 | ||
169 | /* | |
170 | * basic lifecycle operations | |
171 | */ | |
172 | .reset = ohci_pci_reset, | |
173 | .start = ohci_pci_start, | |
174 | #ifdef CONFIG_PM | |
175 | .suspend = ohci_pci_suspend, | |
176 | .resume = ohci_pci_resume, | |
177 | #endif | |
178 | .stop = ohci_stop, | |
179 | ||
180 | /* | |
181 | * managing i/o requests and associated device resources | |
182 | */ | |
183 | .urb_enqueue = ohci_urb_enqueue, | |
184 | .urb_dequeue = ohci_urb_dequeue, | |
185 | .endpoint_disable = ohci_endpoint_disable, | |
186 | ||
187 | /* | |
188 | * scheduling support | |
189 | */ | |
190 | .get_frame_number = ohci_get_frame, | |
191 | ||
192 | /* | |
193 | * root hub support | |
194 | */ | |
195 | .hub_status_data = ohci_hub_status_data, | |
196 | .hub_control = ohci_hub_control, | |
8ad7fe16 | 197 | #ifdef CONFIG_PM |
0c0382e3 AS |
198 | .bus_suspend = ohci_bus_suspend, |
199 | .bus_resume = ohci_bus_resume, | |
1da177e4 LT |
200 | #endif |
201 | .start_port_reset = ohci_start_port_reset, | |
202 | }; | |
203 | ||
204 | /*-------------------------------------------------------------------------*/ | |
205 | ||
206 | ||
207 | static const struct pci_device_id pci_ids [] = { { | |
208 | /* handle any USB OHCI controller */ | |
209 | PCI_DEVICE_CLASS((PCI_CLASS_SERIAL_USB << 8) | 0x10, ~0), | |
210 | .driver_data = (unsigned long) &ohci_pci_hc_driver, | |
211 | }, { /* end: all zeroes */ } | |
212 | }; | |
213 | MODULE_DEVICE_TABLE (pci, pci_ids); | |
214 | ||
215 | /* pci driver glue; this is a "new style" PCI driver module */ | |
216 | static struct pci_driver ohci_pci_driver = { | |
217 | .name = (char *) hcd_name, | |
218 | .id_table = pci_ids, | |
efa400db | 219 | .owner = THIS_MODULE, |
1da177e4 LT |
220 | |
221 | .probe = usb_hcd_pci_probe, | |
222 | .remove = usb_hcd_pci_remove, | |
223 | ||
224 | #ifdef CONFIG_PM | |
225 | .suspend = usb_hcd_pci_suspend, | |
226 | .resume = usb_hcd_pci_resume, | |
227 | #endif | |
228 | }; | |
229 | ||
230 | ||
231 | static int __init ohci_hcd_pci_init (void) | |
232 | { | |
233 | printk (KERN_DEBUG "%s: " DRIVER_INFO " (PCI)\n", hcd_name); | |
234 | if (usb_disabled()) | |
235 | return -ENODEV; | |
236 | ||
237 | pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name, | |
238 | sizeof (struct ed), sizeof (struct td)); | |
239 | return pci_register_driver (&ohci_pci_driver); | |
240 | } | |
241 | module_init (ohci_hcd_pci_init); | |
242 | ||
243 | /*-------------------------------------------------------------------------*/ | |
244 | ||
245 | static void __exit ohci_hcd_pci_cleanup (void) | |
246 | { | |
247 | pci_unregister_driver (&ohci_pci_driver); | |
248 | } | |
249 | module_exit (ohci_hcd_pci_cleanup); |