diff options
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/host/Kconfig | 28 | ||||
-rw-r--r-- | drivers/usb/host/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/host/u132-hcd.c | 3295 |
4 files changed, 3325 insertions, 0 deletions
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index e33647057095..97d57cfc343b 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile | |||
@@ -14,6 +14,7 @@ obj-$(CONFIG_USB_ISP116X_HCD) += host/ | |||
14 | obj-$(CONFIG_USB_OHCI_HCD) += host/ | 14 | obj-$(CONFIG_USB_OHCI_HCD) += host/ |
15 | obj-$(CONFIG_USB_UHCI_HCD) += host/ | 15 | obj-$(CONFIG_USB_UHCI_HCD) += host/ |
16 | obj-$(CONFIG_USB_SL811_HCD) += host/ | 16 | obj-$(CONFIG_USB_SL811_HCD) += host/ |
17 | obj-$(CONFIG_USB_U132_HCD) += host/ | ||
17 | obj-$(CONFIG_ETRAX_USB_HOST) += host/ | 18 | obj-$(CONFIG_ETRAX_USB_HOST) += host/ |
18 | obj-$(CONFIG_USB_OHCI_AT91) += host/ | 19 | obj-$(CONFIG_USB_OHCI_AT91) += host/ |
19 | 20 | ||
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 4bd5cddae8a5..cf10cbc98f80 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig | |||
@@ -142,6 +142,34 @@ config USB_UHCI_HCD | |||
142 | To compile this driver as a module, choose M here: the | 142 | To compile this driver as a module, choose M here: the |
143 | module will be called uhci-hcd. | 143 | module will be called uhci-hcd. |
144 | 144 | ||
145 | config USB_U132_HCD | ||
146 | tristate "Elan U132 Adapter Host Controller" | ||
147 | depends on USB && USB_FTDI_ELAN | ||
148 | default M | ||
149 | help | ||
150 | The U132 adapter is a USB to CardBus adapter specifically designed | ||
151 | for PC cards that contain an OHCI host controller. Typical PC cards | ||
152 | are the Orange Mobile 3G Option GlobeTrotter Fusion card. The U132 | ||
153 | adapter will *NOT* work with PC cards that do not contain an OHCI | ||
154 | controller. | ||
155 | |||
156 | For those PC cards that contain multiple OHCI controllers only ther | ||
157 | first one is used. | ||
158 | |||
159 | The driver consists of two modules, the "ftdi-elan" module is a | ||
160 | USB client driver that interfaces to the FTDI chip within ELAN's | ||
161 | USB-to-PCMCIA adapter, and this "u132-hcd" module is a USB host | ||
162 | controller driver that talks to the OHCI controller within the | ||
163 | CardBus cards that are inserted in the U132 adapter. | ||
164 | |||
165 | This driver has been tested with a CardBus OHCI USB adapter, and | ||
166 | worked with a USB PEN Drive inserted into the first USB port of | ||
167 | the PCCARD. A rather pointless thing to do, but useful for testing. | ||
168 | |||
169 | It is safe to say M here. | ||
170 | |||
171 | See also <http://www.elandigitalsystems.com/support/ufaq/u132linux.php> | ||
172 | |||
145 | config USB_SL811_HCD | 173 | config USB_SL811_HCD |
146 | tristate "SL811HS HCD support" | 174 | tristate "SL811HS HCD support" |
147 | depends on USB | 175 | depends on USB |
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index e3020f4b17be..a2e58c86849f 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile | |||
@@ -14,4 +14,5 @@ obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o | |||
14 | obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o | 14 | obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o |
15 | obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o | 15 | obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o |
16 | obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o | 16 | obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o |
17 | obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o | ||
17 | obj-$(CONFIG_ETRAX_ARCH_V10) += hc_crisv10.o | 18 | obj-$(CONFIG_ETRAX_ARCH_V10) += hc_crisv10.o |
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c new file mode 100644 index 000000000000..cb2e2a604d1b --- /dev/null +++ b/drivers/usb/host/u132-hcd.c | |||
@@ -0,0 +1,3295 @@ | |||
1 | /* | ||
2 | * Host Controller Driver for the Elan Digital Systems U132 adapter | ||
3 | * | ||
4 | * Copyright(C) 2006 Elan Digital Systems Limited | ||
5 | * http://www.elandigitalsystems.com | ||
6 | * | ||
7 | * Author and Maintainer - Tony Olech - Elan Digital Systems | ||
8 | * tony.olech@elandigitalsystems.com | ||
9 | * | ||
10 | * This program is free software;you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License as | ||
12 | * published by the Free Software Foundation, version 2. | ||
13 | * | ||
14 | * | ||
15 | * This driver was written by Tony Olech(tony.olech@elandigitalsystems.com) | ||
16 | * based on various USB host drivers in the 2.6.15 linux kernel | ||
17 | * with constant reference to the 3rd Edition of Linux Device Drivers | ||
18 | * published by O'Reilly | ||
19 | * | ||
20 | * The U132 adapter is a USB to CardBus adapter specifically designed | ||
21 | * for PC cards that contain an OHCI host controller. Typical PC cards | ||
22 | * are the Orange Mobile 3G Option GlobeTrotter Fusion card. | ||
23 | * | ||
24 | * The U132 adapter will *NOT *work with PC cards that do not contain | ||
25 | * an OHCI controller. A simple way to test whether a PC card has an | ||
26 | * OHCI controller as an interface is to insert the PC card directly | ||
27 | * into a laptop(or desktop) with a CardBus slot and if "lspci" shows | ||
28 | * a new USB controller and "lsusb -v" shows a new OHCI Host Controller | ||
29 | * then there is a good chance that the U132 adapter will support the | ||
30 | * PC card.(you also need the specific client driver for the PC card) | ||
31 | * | ||
32 | * Please inform the Author and Maintainer about any PC cards that | ||
33 | * contain OHCI Host Controller and work when directly connected to | ||
34 | * an embedded CardBus slot but do not work when they are connected | ||
35 | * via an ELAN U132 adapter. | ||
36 | * | ||
37 | */ | ||
38 | #include <linux/config.h> | ||
39 | #include <linux/kernel.h> | ||
40 | #include <linux/module.h> | ||
41 | #include <linux/moduleparam.h> | ||
42 | #include <linux/delay.h> | ||
43 | #include <linux/ioport.h> | ||
44 | #include <linux/sched.h> | ||
45 | #include <linux/slab.h> | ||
46 | #include <linux/smp_lock.h> | ||
47 | #include <linux/errno.h> | ||
48 | #include <linux/init.h> | ||
49 | #include <linux/timer.h> | ||
50 | #include <linux/list.h> | ||
51 | #include <linux/interrupt.h> | ||
52 | #include <linux/usb.h> | ||
53 | #include <linux/workqueue.h> | ||
54 | #include <linux/platform_device.h> | ||
55 | #include <linux/pci_ids.h> | ||
56 | #include <asm/io.h> | ||
57 | #include <asm/irq.h> | ||
58 | #include <asm/system.h> | ||
59 | #include <asm/byteorder.h> | ||
60 | #include "../core/hcd.h" | ||
61 | #include "ohci.h" | ||
62 | #define OHCI_CONTROL_INIT OHCI_CTRL_CBSR | ||
63 | #define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \ | ||
64 | OHCI_INTR_WDH) | ||
65 | MODULE_AUTHOR("Tony Olech - Elan Digital Systems Limited"); | ||
66 | MODULE_DESCRIPTION("U132 USB Host Controller Driver"); | ||
67 | MODULE_LICENSE("GPL"); | ||
68 | #define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444) | ||
69 | INT_MODULE_PARM(testing, 0); | ||
70 | /* Some boards misreport power switching/overcurrent*/ | ||
71 | static int distrust_firmware = 1; | ||
72 | module_param(distrust_firmware, bool, 0); | ||
73 | MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurren" | ||
74 | "t setup"); | ||
75 | DECLARE_WAIT_QUEUE_HEAD(u132_hcd_wait); | ||
76 | /* | ||
77 | * u132_module_lock exists to protect access to global variables | ||
78 | * | ||
79 | */ | ||
80 | static struct semaphore u132_module_lock; | ||
81 | static int u132_exiting = 0; | ||
82 | static int u132_instances = 0; | ||
83 | static struct list_head u132_static_list; | ||
84 | /* | ||
85 | * end of the global variables protected by u132_module_lock | ||
86 | */ | ||
87 | static struct workqueue_struct *workqueue; | ||
88 | #define MAX_U132_PORTS 7 | ||
89 | #define MAX_U132_ADDRS 128 | ||
90 | #define MAX_U132_UDEVS 4 | ||
91 | #define MAX_U132_ENDPS 100 | ||
92 | #define MAX_U132_RINGS 4 | ||
93 | static const char *cc_to_text[16] = { | ||
94 | "No Error ", | ||
95 | "CRC Error ", | ||
96 | "Bit Stuff ", | ||
97 | "Data Togg ", | ||
98 | "Stall ", | ||
99 | "DevNotResp ", | ||
100 | "PIDCheck ", | ||
101 | "UnExpPID ", | ||
102 | "DataOver ", | ||
103 | "DataUnder ", | ||
104 | "(for hw) ", | ||
105 | "(for hw) ", | ||
106 | "BufferOver ", | ||
107 | "BuffUnder ", | ||
108 | "(for HCD) ", | ||
109 | "(for HCD) " | ||
110 | }; | ||
111 | struct u132_port { | ||
112 | struct u132 *u132; | ||
113 | int reset; | ||
114 | int enable; | ||
115 | int power; | ||
116 | int Status; | ||
117 | }; | ||
118 | struct u132_addr { | ||
119 | u8 address; | ||
120 | }; | ||
121 | struct u132_udev { | ||
122 | struct kref kref; | ||
123 | struct usb_device *usb_device; | ||
124 | u8 enumeration; | ||
125 | u8 udev_number; | ||
126 | u8 usb_addr; | ||
127 | u8 portnumber; | ||
128 | u8 endp_number_in[16]; | ||
129 | u8 endp_number_out[16]; | ||
130 | }; | ||
131 | #define ENDP_QUEUE_SHIFT 3 | ||
132 | #define ENDP_QUEUE_SIZE (1<<ENDP_QUEUE_SHIFT) | ||
133 | #define ENDP_QUEUE_MASK (ENDP_QUEUE_SIZE-1) | ||
134 | struct u132_urbq { | ||
135 | struct list_head urb_more; | ||
136 | struct urb *urb; | ||
137 | }; | ||
138 | struct u132_spin { | ||
139 | spinlock_t slock; | ||
140 | }; | ||
141 | struct u132_endp { | ||
142 | struct kref kref; | ||
143 | u8 udev_number; | ||
144 | u8 endp_number; | ||
145 | u8 usb_addr; | ||
146 | u8 usb_endp; | ||
147 | struct u132 *u132; | ||
148 | struct list_head endp_ring; | ||
149 | struct u132_ring *ring; | ||
150 | unsigned toggle_bits:2; | ||
151 | unsigned active:1; | ||
152 | unsigned delayed:1; | ||
153 | unsigned input:1; | ||
154 | unsigned output:1; | ||
155 | unsigned pipetype:2; | ||
156 | unsigned dequeueing:1; | ||
157 | unsigned edset_flush:1; | ||
158 | unsigned spare_bits:14; | ||
159 | unsigned long jiffies; | ||
160 | struct usb_host_endpoint *hep; | ||
161 | struct u132_spin queue_lock; | ||
162 | u16 queue_size; | ||
163 | u16 queue_last; | ||
164 | u16 queue_next; | ||
165 | struct urb *urb_list[ENDP_QUEUE_SIZE]; | ||
166 | struct list_head urb_more; | ||
167 | struct work_struct scheduler; | ||
168 | }; | ||
169 | struct u132_ring { | ||
170 | unsigned in_use:1; | ||
171 | unsigned length:7; | ||
172 | u8 number; | ||
173 | struct u132 *u132; | ||
174 | struct u132_endp *curr_endp; | ||
175 | struct work_struct scheduler; | ||
176 | }; | ||
177 | #define OHCI_QUIRK_AMD756 0x01 | ||
178 | #define OHCI_QUIRK_SUPERIO 0x02 | ||
179 | #define OHCI_QUIRK_INITRESET 0x04 | ||
180 | #define OHCI_BIG_ENDIAN 0x08 | ||
181 | #define OHCI_QUIRK_ZFMICRO 0x10 | ||
182 | struct u132 { | ||
183 | struct kref kref; | ||
184 | struct list_head u132_list; | ||
185 | struct semaphore sw_lock; | ||
186 | struct semaphore scheduler_lock; | ||
187 | struct u132_platform_data *board; | ||
188 | struct platform_device *platform_dev; | ||
189 | struct u132_ring ring[MAX_U132_RINGS]; | ||
190 | int sequence_num; | ||
191 | int going; | ||
192 | int power; | ||
193 | int reset; | ||
194 | int num_ports; | ||
195 | u32 hc_control; | ||
196 | u32 hc_fminterval; | ||
197 | u32 hc_roothub_status; | ||
198 | u32 hc_roothub_a; | ||
199 | u32 hc_roothub_portstatus[MAX_ROOT_PORTS]; | ||
200 | int flags; | ||
201 | unsigned long next_statechange; | ||
202 | struct work_struct monitor; | ||
203 | int num_endpoints; | ||
204 | struct u132_addr addr[MAX_U132_ADDRS]; | ||
205 | struct u132_udev udev[MAX_U132_UDEVS]; | ||
206 | struct u132_port port[MAX_U132_PORTS]; | ||
207 | struct u132_endp *endp[MAX_U132_ENDPS]; | ||
208 | }; | ||
209 | int usb_ftdi_elan_read_reg(struct platform_device *pdev, u32 *data); | ||
210 | int usb_ftdi_elan_read_pcimem(struct platform_device *pdev, u8 addressofs, | ||
211 | u8 width, u32 *data); | ||
212 | int usb_ftdi_elan_write_pcimem(struct platform_device *pdev, u8 addressofs, | ||
213 | u8 width, u32 data); | ||
214 | /* | ||
215 | * these can not be inlines because we need the structure offset!! | ||
216 | * Does anyone have a better way????? | ||
217 | */ | ||
218 | #define u132_read_pcimem(u132, member, data) \ | ||
219 | usb_ftdi_elan_read_pcimem(u132->platform_dev, offsetof(struct \ | ||
220 | ohci_regs, member), 0, data); | ||
221 | #define u132_write_pcimem(u132, member, data) \ | ||
222 | usb_ftdi_elan_write_pcimem(u132->platform_dev, offsetof(struct \ | ||
223 | ohci_regs, member), 0, data); | ||
224 | #define u132_write_pcimem_byte(u132, member, data) \ | ||
225 | usb_ftdi_elan_write_pcimem(u132->platform_dev, offsetof(struct \ | ||
226 | ohci_regs, member), 0x0e, data); | ||
227 | static inline struct u132 *udev_to_u132(struct u132_udev *udev) | ||
228 | { | ||
229 | u8 udev_number = udev->udev_number; | ||
230 | return container_of(udev, struct u132, udev[udev_number]); | ||
231 | } | ||
232 | |||
233 | static inline struct u132 *hcd_to_u132(struct usb_hcd *hcd) | ||
234 | { | ||
235 | return (struct u132 *)(hcd->hcd_priv); | ||
236 | } | ||
237 | |||
238 | static inline struct usb_hcd *u132_to_hcd(struct u132 *u132) | ||
239 | { | ||
240 | return container_of((void *)u132, struct usb_hcd, hcd_priv); | ||
241 | } | ||
242 | |||
243 | static inline void u132_disable(struct u132 *u132) | ||
244 | { | ||
245 | u132_to_hcd(u132)->state = HC_STATE_HALT; | ||
246 | } | ||
247 | |||
248 | |||
249 | #define kref_to_u132(d) container_of(d, struct u132, kref) | ||
250 | #define kref_to_u132_endp(d) container_of(d, struct u132_endp, kref) | ||
251 | #define kref_to_u132_udev(d) container_of(d, struct u132_udev, kref) | ||
252 | #include "../misc/usb_u132.h" | ||
253 | static const char hcd_name[] = "u132_hcd"; | ||
254 | #define PORT_C_MASK ((USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | \ | ||
255 | USB_PORT_STAT_C_SUSPEND | USB_PORT_STAT_C_OVERCURRENT | \ | ||
256 | USB_PORT_STAT_C_RESET) << 16) | ||
257 | static void u132_hcd_delete(struct kref *kref) | ||
258 | { | ||
259 | struct u132 *u132 = kref_to_u132(kref); | ||
260 | struct platform_device *pdev = u132->platform_dev; | ||
261 | struct usb_hcd *hcd = u132_to_hcd(u132); | ||
262 | u132->going += 1; | ||
263 | down(&u132_module_lock); | ||
264 | list_del_init(&u132->u132_list); | ||
265 | u132_instances -= 1; | ||
266 | up(&u132_module_lock); | ||
267 | dev_warn(&u132->platform_dev->dev, "FREEING the hcd=%p and thus the u13" | ||
268 | "2=%p going=%d pdev=%p\n", hcd, u132, u132->going, pdev); | ||
269 | usb_put_hcd(hcd); | ||
270 | } | ||
271 | |||
272 | static inline void u132_u132_put_kref(struct u132 *u132) | ||
273 | { | ||
274 | kref_put(&u132->kref, u132_hcd_delete); | ||
275 | } | ||
276 | |||
277 | static inline void u132_u132_init_kref(struct u132 *u132) | ||
278 | { | ||
279 | kref_init(&u132->kref); | ||
280 | } | ||
281 | |||
282 | static void u132_udev_delete(struct kref *kref) | ||
283 | { | ||
284 | struct u132_udev *udev = kref_to_u132_udev(kref); | ||
285 | udev->udev_number = 0; | ||
286 | udev->usb_device = NULL; | ||
287 | udev->usb_addr = 0; | ||
288 | udev->enumeration = 0; | ||
289 | } | ||
290 | |||
291 | static inline void u132_udev_put_kref(struct u132 *u132, struct u132_udev *udev) | ||
292 | { | ||
293 | kref_put(&udev->kref, u132_udev_delete); | ||
294 | } | ||
295 | |||
296 | static inline void u132_udev_get_kref(struct u132 *u132, struct u132_udev *udev) | ||
297 | { | ||
298 | kref_get(&udev->kref); | ||
299 | } | ||
300 | |||
301 | static inline void u132_udev_init_kref(struct u132 *u132, | ||
302 | struct u132_udev *udev) | ||
303 | { | ||
304 | kref_init(&udev->kref); | ||
305 | } | ||
306 | |||
307 | static inline void u132_ring_put_kref(struct u132 *u132, struct u132_ring *ring) | ||
308 | { | ||
309 | kref_put(&u132->kref, u132_hcd_delete); | ||
310 | } | ||
311 | |||
312 | static void u132_ring_requeue_work(struct u132 *u132, struct u132_ring *ring, | ||
313 | unsigned int delta) | ||
314 | { | ||
315 | if (delta > 0) { | ||
316 | if (queue_delayed_work(workqueue, &ring->scheduler, delta)) | ||
317 | return; | ||
318 | } else if (queue_work(workqueue, &ring->scheduler)) | ||
319 | return; | ||
320 | kref_put(&u132->kref, u132_hcd_delete); | ||
321 | return; | ||
322 | } | ||
323 | |||
324 | static void u132_ring_queue_work(struct u132 *u132, struct u132_ring *ring, | ||
325 | unsigned int delta) | ||
326 | { | ||
327 | kref_get(&u132->kref); | ||
328 | u132_ring_requeue_work(u132, ring, delta); | ||
329 | return; | ||
330 | } | ||
331 | |||
332 | static void u132_ring_cancel_work(struct u132 *u132, struct u132_ring *ring) | ||
333 | { | ||
334 | if (cancel_delayed_work(&ring->scheduler)) { | ||
335 | kref_put(&u132->kref, u132_hcd_delete); | ||
336 | } | ||
337 | } | ||
338 | |||
339 | static void u132_endp_delete(struct kref *kref) | ||
340 | { | ||
341 | struct u132_endp *endp = kref_to_u132_endp(kref); | ||
342 | struct u132 *u132 = endp->u132; | ||
343 | u8 usb_addr = endp->usb_addr; | ||
344 | u8 usb_endp = endp->usb_endp; | ||
345 | u8 address = u132->addr[usb_addr].address; | ||
346 | struct u132_udev *udev = &u132->udev[address]; | ||
347 | u8 endp_number = endp->endp_number; | ||
348 | struct usb_host_endpoint *hep = endp->hep; | ||
349 | struct u132_ring *ring = endp->ring; | ||
350 | struct list_head *head = &endp->endp_ring; | ||
351 | ring->length -= 1; | ||
352 | if (endp == ring->curr_endp) { | ||
353 | if (list_empty(head)) { | ||
354 | ring->curr_endp = NULL; | ||
355 | list_del(head); | ||
356 | } else { | ||
357 | struct u132_endp *next_endp = list_entry(head->next, | ||
358 | struct u132_endp, endp_ring); | ||
359 | ring->curr_endp = next_endp; | ||
360 | list_del(head); | ||
361 | }} else | ||
362 | list_del(head); | ||
363 | if (endp->input) { | ||
364 | udev->endp_number_in[usb_endp] = 0; | ||
365 | u132_udev_put_kref(u132, udev); | ||
366 | } | ||
367 | if (endp->output) { | ||
368 | udev->endp_number_out[usb_endp] = 0; | ||
369 | u132_udev_put_kref(u132, udev); | ||
370 | } | ||
371 | u132->endp[endp_number - 1] = NULL; | ||
372 | hep->hcpriv = NULL; | ||
373 | kfree(endp); | ||
374 | u132_u132_put_kref(u132); | ||
375 | } | ||
376 | |||
377 | static inline void u132_endp_put_kref(struct u132 *u132, struct u132_endp *endp) | ||
378 | { | ||
379 | kref_put(&endp->kref, u132_endp_delete); | ||
380 | } | ||
381 | |||
382 | static inline void u132_endp_get_kref(struct u132 *u132, struct u132_endp *endp) | ||
383 | { | ||
384 | kref_get(&endp->kref); | ||
385 | } | ||
386 | |||
387 | static inline void u132_endp_init_kref(struct u132 *u132, | ||
388 | struct u132_endp *endp) | ||
389 | { | ||
390 | kref_init(&endp->kref); | ||
391 | kref_get(&u132->kref); | ||
392 | } | ||
393 | |||
394 | static void u132_endp_queue_work(struct u132 *u132, struct u132_endp *endp, | ||
395 | unsigned int delta) | ||
396 | { | ||
397 | if (delta > 0) { | ||
398 | if (queue_delayed_work(workqueue, &endp->scheduler, delta)) | ||
399 | kref_get(&endp->kref); | ||
400 | } else if (queue_work(workqueue, &endp->scheduler)) | ||
401 | kref_get(&endp->kref); | ||
402 | return; | ||
403 | } | ||
404 | |||
405 | static void u132_endp_cancel_work(struct u132 *u132, struct u132_endp *endp) | ||
406 | { | ||
407 | if (cancel_delayed_work(&endp->scheduler)) | ||
408 | kref_put(&endp->kref, u132_endp_delete); | ||
409 | } | ||
410 | |||
411 | static inline void u132_monitor_put_kref(struct u132 *u132) | ||
412 | { | ||
413 | kref_put(&u132->kref, u132_hcd_delete); | ||
414 | } | ||
415 | |||
416 | static void u132_monitor_queue_work(struct u132 *u132, unsigned int delta) | ||
417 | { | ||
418 | if (delta > 0) { | ||
419 | if (queue_delayed_work(workqueue, &u132->monitor, delta)) { | ||
420 | kref_get(&u132->kref); | ||
421 | } | ||
422 | } else if (queue_work(workqueue, &u132->monitor)) | ||
423 | kref_get(&u132->kref); | ||
424 | return; | ||
425 | } | ||
426 | |||
427 | static void u132_monitor_requeue_work(struct u132 *u132, unsigned int delta) | ||
428 | { | ||
429 | if (delta > 0) { | ||
430 | if (queue_delayed_work(workqueue, &u132->monitor, delta)) | ||
431 | return; | ||
432 | } else if (queue_work(workqueue, &u132->monitor)) | ||
433 | return; | ||
434 | kref_put(&u132->kref, u132_hcd_delete); | ||
435 | return; | ||
436 | } | ||
437 | |||
438 | static void u132_monitor_cancel_work(struct u132 *u132) | ||
439 | { | ||
440 | if (cancel_delayed_work(&u132->monitor)) | ||
441 | kref_put(&u132->kref, u132_hcd_delete); | ||
442 | } | ||
443 | |||
444 | static int read_roothub_info(struct u132 *u132) | ||
445 | { | ||
446 | u32 revision; | ||
447 | int retval; | ||
448 | retval = u132_read_pcimem(u132, revision, &revision); | ||
449 | if (retval) { | ||
450 | dev_err(&u132->platform_dev->dev, "error %d accessing device co" | ||
451 | "ntrol\n", retval); | ||
452 | return retval; | ||
453 | } else if ((revision & 0xFF) == 0x10) { | ||
454 | } else if ((revision & 0xFF) == 0x11) { | ||
455 | } else { | ||
456 | dev_err(&u132->platform_dev->dev, "device revision is not valid" | ||
457 | " %08X\n", revision); | ||
458 | return -ENODEV; | ||
459 | } | ||
460 | retval = u132_read_pcimem(u132, control, &u132->hc_control); | ||
461 | if (retval) { | ||
462 | dev_err(&u132->platform_dev->dev, "error %d accessing device co" | ||
463 | "ntrol\n", retval); | ||
464 | return retval; | ||
465 | } | ||
466 | retval = u132_read_pcimem(u132, roothub.status, | ||
467 | &u132->hc_roothub_status); | ||
468 | if (retval) { | ||
469 | dev_err(&u132->platform_dev->dev, "error %d accessing device re" | ||
470 | "g roothub.status\n", retval); | ||
471 | return retval; | ||
472 | } | ||
473 | retval = u132_read_pcimem(u132, roothub.a, &u132->hc_roothub_a); | ||
474 | if (retval) { | ||
475 | dev_err(&u132->platform_dev->dev, "error %d accessing device re" | ||
476 | "g roothub.a\n", retval); | ||
477 | return retval; | ||
478 | } | ||
479 | { | ||
480 | int I = u132->num_ports; | ||
481 | int i = 0; | ||
482 | while (I-- > 0) { | ||
483 | retval = u132_read_pcimem(u132, roothub.portstatus[i], | ||
484 | &u132->hc_roothub_portstatus[i]); | ||
485 | if (retval) { | ||
486 | dev_err(&u132->platform_dev->dev, "error %d acc" | ||
487 | "essing device roothub.portstatus[%d]\n" | ||
488 | , retval, i); | ||
489 | return retval; | ||
490 | } else | ||
491 | i += 1; | ||
492 | } | ||
493 | } | ||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | static void u132_hcd_monitor_work(void *data) | ||
498 | { | ||
499 | struct u132 *u132 = data; | ||
500 | if (u132->going > 1) { | ||
501 | dev_err(&u132->platform_dev->dev, "device has been removed %d\n" | ||
502 | , u132->going); | ||
503 | u132_monitor_put_kref(u132); | ||
504 | return; | ||
505 | } else if (u132->going > 0) { | ||
506 | dev_err(&u132->platform_dev->dev, "device is being removed\n"); | ||
507 | u132_monitor_put_kref(u132); | ||
508 | return; | ||
509 | } else { | ||
510 | int retval; | ||
511 | down(&u132->sw_lock); | ||
512 | retval = read_roothub_info(u132); | ||
513 | if (retval) { | ||
514 | struct usb_hcd *hcd = u132_to_hcd(u132); | ||
515 | u132_disable(u132); | ||
516 | u132->going = 1; | ||
517 | up(&u132->sw_lock); | ||
518 | usb_hc_died(hcd); | ||
519 | ftdi_elan_gone_away(u132->platform_dev); | ||
520 | u132_monitor_put_kref(u132); | ||
521 | return; | ||
522 | } else { | ||
523 | u132_monitor_requeue_work(u132, 500); | ||
524 | up(&u132->sw_lock); | ||
525 | return; | ||
526 | } | ||
527 | } | ||
528 | } | ||
529 | |||
530 | static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp, | ||
531 | struct urb *urb, int status) | ||
532 | { | ||
533 | struct u132_ring *ring; | ||
534 | unsigned long irqs; | ||
535 | struct usb_hcd *hcd = u132_to_hcd(u132); | ||
536 | urb->error_count = 0; | ||
537 | urb->status = status; | ||
538 | urb->hcpriv = NULL; | ||
539 | spin_lock_irqsave(&endp->queue_lock.slock, irqs); | ||
540 | endp->queue_next += 1; | ||
541 | if (ENDP_QUEUE_SIZE > --endp->queue_size) { | ||
542 | endp->active = 0; | ||
543 | spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); | ||
544 | } else { | ||
545 | struct list_head *next = endp->urb_more.next; | ||
546 | struct u132_urbq *urbq = list_entry(next, struct u132_urbq, | ||
547 | urb_more); | ||
548 | list_del(next); | ||
549 | endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = | ||
550 | urbq->urb; | ||
551 | endp->active = 0; | ||
552 | spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); | ||
553 | kfree(urbq); | ||
554 | } down(&u132->scheduler_lock); | ||
555 | ring = endp->ring; | ||
556 | ring->in_use = 0; | ||
557 | u132_ring_cancel_work(u132, ring); | ||
558 | u132_ring_queue_work(u132, ring, 0); | ||
559 | up(&u132->scheduler_lock); | ||
560 | u132_endp_put_kref(u132, endp); | ||
561 | usb_hcd_giveback_urb(hcd, urb, NULL); | ||
562 | return; | ||
563 | } | ||
564 | |||
565 | static void u132_hcd_forget_urb(struct u132 *u132, struct u132_endp *endp, | ||
566 | struct urb *urb, int status) | ||
567 | { | ||
568 | u132_endp_put_kref(u132, endp); | ||
569 | } | ||
570 | |||
571 | static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp, | ||
572 | struct urb *urb, int status) | ||
573 | { | ||
574 | unsigned long irqs; | ||
575 | struct usb_hcd *hcd = u132_to_hcd(u132); | ||
576 | urb->error_count = 0; | ||
577 | urb->status = status; | ||
578 | urb->hcpriv = NULL; | ||
579 | spin_lock_irqsave(&endp->queue_lock.slock, irqs); | ||
580 | endp->queue_next += 1; | ||
581 | if (ENDP_QUEUE_SIZE > --endp->queue_size) { | ||
582 | endp->active = 0; | ||
583 | spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); | ||
584 | } else { | ||
585 | struct list_head *next = endp->urb_more.next; | ||
586 | struct u132_urbq *urbq = list_entry(next, struct u132_urbq, | ||
587 | urb_more); | ||
588 | list_del(next); | ||
589 | endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = | ||
590 | urbq->urb; | ||
591 | endp->active = 0; | ||
592 | spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); | ||
593 | kfree(urbq); | ||
594 | } usb_hcd_giveback_urb(hcd, urb, NULL); | ||
595 | return; | ||
596 | } | ||
597 | |||
598 | static inline int edset_input(struct u132 *u132, struct u132_ring *ring, | ||
599 | struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits, | ||
600 | void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, | ||
601 | int toggle_bits, int error_count, int condition_code, int repeat_number, | ||
602 | int halted, int skipped, int actual, int non_null)) | ||
603 | { | ||
604 | return usb_ftdi_elan_edset_input(u132->platform_dev, ring->number, endp, | ||
605 | urb, address, endp->usb_endp, toggle_bits, callback); | ||
606 | } | ||
607 | |||
608 | static inline int edset_setup(struct u132 *u132, struct u132_ring *ring, | ||
609 | struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits, | ||
610 | void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, | ||
611 | int toggle_bits, int error_count, int condition_code, int repeat_number, | ||
612 | int halted, int skipped, int actual, int non_null)) | ||
613 | { | ||
614 | return usb_ftdi_elan_edset_setup(u132->platform_dev, ring->number, endp, | ||
615 | urb, address, endp->usb_endp, toggle_bits, callback); | ||
616 | } | ||
617 | |||
618 | static inline int edset_single(struct u132 *u132, struct u132_ring *ring, | ||
619 | struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits, | ||
620 | void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, | ||
621 | int toggle_bits, int error_count, int condition_code, int repeat_number, | ||
622 | int halted, int skipped, int actual, int non_null)) | ||
623 | { | ||
624 | return usb_ftdi_elan_edset_single(u132->platform_dev, ring->number, | ||
625 | endp, urb, address, endp->usb_endp, toggle_bits, callback); | ||
626 | } | ||
627 | |||
628 | static inline int edset_output(struct u132 *u132, struct u132_ring *ring, | ||
629 | struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits, | ||
630 | void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, | ||
631 | int toggle_bits, int error_count, int condition_code, int repeat_number, | ||
632 | int halted, int skipped, int actual, int non_null)) | ||
633 | { | ||
634 | return usb_ftdi_elan_edset_output(u132->platform_dev, ring->number, | ||
635 | endp, urb, address, endp->usb_endp, toggle_bits, callback); | ||
636 | } | ||
637 | |||
638 | |||
639 | /* | ||
640 | * must not LOCK sw_lock | ||
641 | * | ||
642 | */ | ||
643 | static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf, | ||
644 | int len, int toggle_bits, int error_count, int condition_code, | ||
645 | int repeat_number, int halted, int skipped, int actual, int non_null) | ||
646 | { | ||
647 | struct u132_endp *endp = data; | ||
648 | struct u132 *u132 = endp->u132; | ||
649 | u8 address = u132->addr[endp->usb_addr].address; | ||
650 | struct u132_udev *udev = &u132->udev[address]; | ||
651 | down(&u132->scheduler_lock); | ||
652 | if (u132->going > 1) { | ||
653 | dev_err(&u132->platform_dev->dev, "device has been removed %d\n" | ||
654 | , u132->going); | ||
655 | up(&u132->scheduler_lock); | ||
656 | u132_hcd_forget_urb(u132, endp, urb, -ENODEV); | ||
657 | return; | ||
658 | } else if (endp->dequeueing) { | ||
659 | endp->dequeueing = 0; | ||
660 | up(&u132->scheduler_lock); | ||
661 | u132_hcd_giveback_urb(u132, endp, urb, -EINTR); | ||
662 | return; | ||
663 | } else if (u132->going > 0) { | ||
664 | dev_err(&u132->platform_dev->dev, "device is being removed urb=" | ||
665 | "%p status=%d\n", urb, urb->status); | ||
666 | up(&u132->scheduler_lock); | ||
667 | u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); | ||
668 | return; | ||
669 | } else if (urb->status == -EINPROGRESS) { | ||
670 | struct u132_ring *ring = endp->ring; | ||
671 | u8 *u = urb->transfer_buffer + urb->actual_length; | ||
672 | u8 *b = buf; | ||
673 | int L = len; | ||
674 | while (L-- > 0) { | ||
675 | *u++ = *b++; | ||
676 | } | ||
677 | urb->actual_length += len; | ||
678 | if ((condition_code == TD_CC_NOERROR) && | ||
679 | (urb->transfer_buffer_length > urb->actual_length)) { | ||
680 | endp->toggle_bits = toggle_bits; | ||
681 | usb_settoggle(udev->usb_device, endp->usb_endp, 0, | ||
682 | 1 & toggle_bits); | ||
683 | if (urb->actual_length > 0) { | ||
684 | int retval; | ||
685 | up(&u132->scheduler_lock); | ||
686 | retval = edset_single(u132, ring, endp, urb, | ||
687 | address, endp->toggle_bits, | ||
688 | u132_hcd_interrupt_recv); | ||
689 | if (retval == 0) { | ||
690 | } else | ||
691 | u132_hcd_giveback_urb(u132, endp, urb, | ||
692 | retval); | ||
693 | } else { | ||
694 | ring->in_use = 0; | ||
695 | endp->active = 0; | ||
696 | endp->jiffies = jiffies + | ||
697 | msecs_to_jiffies(urb->interval); | ||
698 | u132_ring_cancel_work(u132, ring); | ||
699 | u132_ring_queue_work(u132, ring, 0); | ||
700 | up(&u132->scheduler_lock); | ||
701 | u132_endp_put_kref(u132, endp); | ||
702 | } | ||
703 | return; | ||
704 | } else if ((condition_code == TD_DATAUNDERRUN) && | ||
705 | ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) { | ||
706 | endp->toggle_bits = toggle_bits; | ||
707 | usb_settoggle(udev->usb_device, endp->usb_endp, 0, | ||
708 | 1 & toggle_bits); | ||
709 | up(&u132->scheduler_lock); | ||
710 | u132_hcd_giveback_urb(u132, endp, urb, 0); | ||
711 | return; | ||
712 | } else { | ||
713 | if (condition_code == TD_CC_NOERROR) { | ||
714 | endp->toggle_bits = toggle_bits; | ||
715 | usb_settoggle(udev->usb_device, endp->usb_endp, | ||
716 | 0, 1 & toggle_bits); | ||
717 | } else if (condition_code == TD_CC_STALL) { | ||
718 | endp->toggle_bits = 0x2; | ||
719 | usb_settoggle(udev->usb_device, endp->usb_endp, | ||
720 | 0, 0); | ||
721 | } else { | ||
722 | endp->toggle_bits = 0x2; | ||
723 | usb_settoggle(udev->usb_device, endp->usb_endp, | ||
724 | 0, 0); | ||
725 | dev_err(&u132->platform_dev->dev, "urb=%p givin" | ||
726 | "g back INTERRUPT %s\n", urb, | ||
727 | cc_to_text[condition_code]); | ||
728 | } | ||
729 | up(&u132->scheduler_lock); | ||
730 | u132_hcd_giveback_urb(u132, endp, urb, | ||
731 | cc_to_error[condition_code]); | ||
732 | return; | ||
733 | } | ||
734 | } else { | ||
735 | dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" | ||
736 | "s=%d\n", urb, urb->status); | ||
737 | up(&u132->scheduler_lock); | ||
738 | u132_hcd_giveback_urb(u132, endp, urb, urb->status); | ||
739 | return; | ||
740 | } | ||
741 | } | ||
742 | |||
743 | static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf, | ||
744 | int len, int toggle_bits, int error_count, int condition_code, | ||
745 | int repeat_number, int halted, int skipped, int actual, int non_null) | ||
746 | { | ||
747 | struct u132_endp *endp = data; | ||
748 | struct u132 *u132 = endp->u132; | ||
749 | u8 address = u132->addr[endp->usb_addr].address; | ||
750 | down(&u132->scheduler_lock); | ||
751 | if (u132->going > 1) { | ||
752 | dev_err(&u132->platform_dev->dev, "device has been removed %d\n" | ||
753 | , u132->going); | ||
754 | up(&u132->scheduler_lock); | ||
755 | u132_hcd_forget_urb(u132, endp, urb, -ENODEV); | ||
756 | return; | ||
757 | } else if (endp->dequeueing) { | ||
758 | endp->dequeueing = 0; | ||
759 | up(&u132->scheduler_lock); | ||
760 | u132_hcd_giveback_urb(u132, endp, urb, -EINTR); | ||
761 | return; | ||
762 | } else if (u132->going > 0) { | ||
763 | dev_err(&u132->platform_dev->dev, "device is being removed urb=" | ||
764 | "%p status=%d\n", urb, urb->status); | ||
765 | up(&u132->scheduler_lock); | ||
766 | u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); | ||
767 | return; | ||
768 | } else if (urb->status == -EINPROGRESS) { | ||
769 | struct u132_ring *ring = endp->ring; | ||
770 | urb->actual_length += len; | ||
771 | endp->toggle_bits = toggle_bits; | ||
772 | if (urb->transfer_buffer_length > urb->actual_length) { | ||
773 | int retval; | ||
774 | up(&u132->scheduler_lock); | ||
775 | retval = edset_output(u132, ring, endp, urb, address, | ||
776 | endp->toggle_bits, u132_hcd_bulk_output_sent); | ||
777 | if (retval == 0) { | ||
778 | } else | ||
779 | u132_hcd_giveback_urb(u132, endp, urb, retval); | ||
780 | return; | ||
781 | } else { | ||
782 | up(&u132->scheduler_lock); | ||
783 | u132_hcd_giveback_urb(u132, endp, urb, 0); | ||
784 | return; | ||
785 | } | ||
786 | } else { | ||
787 | dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" | ||
788 | "s=%d\n", urb, urb->status); | ||
789 | up(&u132->scheduler_lock); | ||
790 | u132_hcd_giveback_urb(u132, endp, urb, urb->status); | ||
791 | return; | ||
792 | } | ||
793 | } | ||
794 | |||
795 | static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf, | ||
796 | int len, int toggle_bits, int error_count, int condition_code, | ||
797 | int repeat_number, int halted, int skipped, int actual, int non_null) | ||
798 | { | ||
799 | struct u132_endp *endp = data; | ||
800 | struct u132 *u132 = endp->u132; | ||
801 | u8 address = u132->addr[endp->usb_addr].address; | ||
802 | struct u132_udev *udev = &u132->udev[address]; | ||
803 | down(&u132->scheduler_lock); | ||
804 | if (u132->going > 1) { | ||
805 | dev_err(&u132->platform_dev->dev, "device has been removed %d\n" | ||
806 | , u132->going); | ||
807 | up(&u132->scheduler_lock); | ||
808 | u132_hcd_forget_urb(u132, endp, urb, -ENODEV); | ||
809 | return; | ||
810 | } else if (endp->dequeueing) { | ||
811 | endp->dequeueing = 0; | ||
812 | up(&u132->scheduler_lock); | ||
813 | u132_hcd_giveback_urb(u132, endp, urb, -EINTR); | ||
814 | return; | ||
815 | } else if (u132->going > 0) { | ||
816 | dev_err(&u132->platform_dev->dev, "device is being removed urb=" | ||
817 | "%p status=%d\n", urb, urb->status); | ||
818 | up(&u132->scheduler_lock); | ||
819 | u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); | ||
820 | return; | ||
821 | } else if (urb->status == -EINPROGRESS) { | ||
822 | struct u132_ring *ring = endp->ring; | ||
823 | u8 *u = urb->transfer_buffer + urb->actual_length; | ||
824 | u8 *b = buf; | ||
825 | int L = len; | ||
826 | while (L-- > 0) { | ||
827 | *u++ = *b++; | ||
828 | } | ||
829 | urb->actual_length += len; | ||
830 | if ((condition_code == TD_CC_NOERROR) && | ||
831 | (urb->transfer_buffer_length > urb->actual_length)) { | ||
832 | int retval; | ||
833 | endp->toggle_bits = toggle_bits; | ||
834 | usb_settoggle(udev->usb_device, endp->usb_endp, 0, | ||
835 | 1 & toggle_bits); | ||
836 | up(&u132->scheduler_lock); | ||
837 | retval = usb_ftdi_elan_edset_input(u132->platform_dev, | ||
838 | ring->number, endp, urb, address, | ||
839 | endp->usb_endp, endp->toggle_bits, | ||
840 | u132_hcd_bulk_input_recv); | ||
841 | if (retval == 0) { | ||
842 | } else | ||
843 | u132_hcd_giveback_urb(u132, endp, urb, retval); | ||
844 | return; | ||
845 | } else if (condition_code == TD_CC_NOERROR) { | ||
846 | endp->toggle_bits = toggle_bits; | ||
847 | usb_settoggle(udev->usb_device, endp->usb_endp, 0, | ||
848 | 1 & toggle_bits); | ||
849 | up(&u132->scheduler_lock); | ||
850 | u132_hcd_giveback_urb(u132, endp, urb, | ||
851 | cc_to_error[condition_code]); | ||
852 | return; | ||
853 | } else if ((condition_code == TD_DATAUNDERRUN) && | ||
854 | ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) { | ||
855 | endp->toggle_bits = toggle_bits; | ||
856 | usb_settoggle(udev->usb_device, endp->usb_endp, 0, | ||
857 | 1 & toggle_bits); | ||
858 | up(&u132->scheduler_lock); | ||
859 | u132_hcd_giveback_urb(u132, endp, urb, 0); | ||
860 | return; | ||
861 | } else if (condition_code == TD_DATAUNDERRUN) { | ||
862 | endp->toggle_bits = toggle_bits; | ||
863 | usb_settoggle(udev->usb_device, endp->usb_endp, 0, | ||
864 | 1 & toggle_bits); | ||
865 | dev_warn(&u132->platform_dev->dev, "urb=%p(SHORT NOT OK" | ||
866 | ") giving back BULK IN %s\n", urb, | ||
867 | cc_to_text[condition_code]); | ||
868 | up(&u132->scheduler_lock); | ||
869 | u132_hcd_giveback_urb(u132, endp, urb, 0); | ||
870 | return; | ||
871 | } else if (condition_code == TD_CC_STALL) { | ||
872 | endp->toggle_bits = 0x2; | ||
873 | usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0); | ||
874 | up(&u132->scheduler_lock); | ||
875 | u132_hcd_giveback_urb(u132, endp, urb, | ||
876 | cc_to_error[condition_code]); | ||
877 | return; | ||
878 | } else { | ||
879 | endp->toggle_bits = 0x2; | ||
880 | usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0); | ||
881 | dev_err(&u132->platform_dev->dev, "urb=%p giving back B" | ||
882 | "ULK IN code=%d %s\n", urb, condition_code, | ||
883 | cc_to_text[condition_code]); | ||
884 | up(&u132->scheduler_lock); | ||
885 | u132_hcd_giveback_urb(u132, endp, urb, | ||
886 | cc_to_error[condition_code]); | ||
887 | return; | ||
888 | } | ||
889 | } else { | ||
890 | dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" | ||
891 | "s=%d\n", urb, urb->status); | ||
892 | up(&u132->scheduler_lock); | ||
893 | u132_hcd_giveback_urb(u132, endp, urb, urb->status); | ||
894 | return; | ||
895 | } | ||
896 | } | ||
897 | |||
898 | static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf, | ||
899 | int len, int toggle_bits, int error_count, int condition_code, | ||
900 | int repeat_number, int halted, int skipped, int actual, int non_null) | ||
901 | { | ||
902 | struct u132_endp *endp = data; | ||
903 | struct u132 *u132 = endp->u132; | ||
904 | down(&u132->scheduler_lock); | ||
905 | if (u132->going > 1) { | ||
906 | dev_err(&u132->platform_dev->dev, "device has been removed %d\n" | ||
907 | , u132->going); | ||
908 | up(&u132->scheduler_lock); | ||
909 | u132_hcd_forget_urb(u132, endp, urb, -ENODEV); | ||
910 | return; | ||
911 | } else if (endp->dequeueing) { | ||
912 | endp->dequeueing = 0; | ||
913 | up(&u132->scheduler_lock); | ||
914 | u132_hcd_giveback_urb(u132, endp, urb, -EINTR); | ||
915 | return; | ||
916 | } else if (u132->going > 0) { | ||
917 | dev_err(&u132->platform_dev->dev, "device is being removed urb=" | ||
918 | "%p status=%d\n", urb, urb->status); | ||
919 | up(&u132->scheduler_lock); | ||
920 | u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); | ||
921 | return; | ||
922 | } else if (urb->status == -EINPROGRESS) { | ||
923 | up(&u132->scheduler_lock); | ||
924 | u132_hcd_giveback_urb(u132, endp, urb, 0); | ||
925 | return; | ||
926 | } else { | ||
927 | dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" | ||
928 | "s=%d\n", urb, urb->status); | ||
929 | up(&u132->scheduler_lock); | ||
930 | u132_hcd_giveback_urb(u132, endp, urb, urb->status); | ||
931 | return; | ||
932 | } | ||
933 | } | ||
934 | |||
935 | static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf, | ||
936 | int len, int toggle_bits, int error_count, int condition_code, | ||
937 | int repeat_number, int halted, int skipped, int actual, int non_null) | ||
938 | { | ||
939 | struct u132_endp *endp = data; | ||
940 | struct u132 *u132 = endp->u132; | ||
941 | u8 address = u132->addr[endp->usb_addr].address; | ||
942 | down(&u132->scheduler_lock); | ||
943 | if (u132->going > 1) { | ||
944 | dev_err(&u132->platform_dev->dev, "device has been removed %d\n" | ||
945 | , u132->going); | ||
946 | up(&u132->scheduler_lock); | ||
947 | u132_hcd_forget_urb(u132, endp, urb, -ENODEV); | ||
948 | return; | ||
949 | } else if (endp->dequeueing) { | ||
950 | endp->dequeueing = 0; | ||
951 | up(&u132->scheduler_lock); | ||
952 | u132_hcd_giveback_urb(u132, endp, urb, -EINTR); | ||
953 | return; | ||
954 | } else if (u132->going > 0) { | ||
955 | dev_err(&u132->platform_dev->dev, "device is being removed urb=" | ||
956 | "%p status=%d\n", urb, urb->status); | ||
957 | up(&u132->scheduler_lock); | ||
958 | u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); | ||
959 | return; | ||
960 | } else if (urb->status == -EINPROGRESS) { | ||
961 | struct u132_ring *ring = endp->ring; | ||
962 | u8 *u = urb->transfer_buffer; | ||
963 | u8 *b = buf; | ||
964 | int L = len; | ||
965 | while (L-- > 0) { | ||
966 | *u++ = *b++; | ||
967 | } | ||
968 | urb->actual_length = len; | ||
969 | if ((condition_code == TD_CC_NOERROR) || ((condition_code == | ||
970 | TD_DATAUNDERRUN) && ((urb->transfer_flags & | ||
971 | URB_SHORT_NOT_OK) == 0))) { | ||
972 | int retval; | ||
973 | up(&u132->scheduler_lock); | ||
974 | retval = usb_ftdi_elan_edset_empty(u132->platform_dev, | ||
975 | ring->number, endp, urb, address, | ||
976 | endp->usb_endp, 0x3, | ||
977 | u132_hcd_configure_empty_sent); | ||
978 | if (retval == 0) { | ||
979 | } else | ||
980 | u132_hcd_giveback_urb(u132, endp, urb, retval); | ||
981 | return; | ||
982 | } else if (condition_code == TD_CC_STALL) { | ||
983 | up(&u132->scheduler_lock); | ||
984 | dev_warn(&u132->platform_dev->dev, "giving back SETUP I" | ||
985 | "NPUT STALL urb %p\n", urb); | ||
986 | u132_hcd_giveback_urb(u132, endp, urb, | ||
987 | cc_to_error[condition_code]); | ||
988 | return; | ||
989 | } else { | ||
990 | up(&u132->scheduler_lock); | ||
991 | dev_err(&u132->platform_dev->dev, "giving back SETUP IN" | ||
992 | "PUT %s urb %p\n", cc_to_text[condition_code], | ||
993 | urb); | ||
994 | u132_hcd_giveback_urb(u132, endp, urb, | ||
995 | cc_to_error[condition_code]); | ||
996 | return; | ||
997 | } | ||
998 | } else { | ||
999 | dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" | ||
1000 | "s=%d\n", urb, urb->status); | ||
1001 | up(&u132->scheduler_lock); | ||
1002 | u132_hcd_giveback_urb(u132, endp, urb, urb->status); | ||
1003 | return; | ||
1004 | } | ||
1005 | } | ||
1006 | |||
1007 | static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf, | ||
1008 | int len, int toggle_bits, int error_count, int condition_code, | ||
1009 | int repeat_number, int halted, int skipped, int actual, int non_null) | ||
1010 | { | ||
1011 | struct u132_endp *endp = data; | ||
1012 | struct u132 *u132 = endp->u132; | ||
1013 | down(&u132->scheduler_lock); | ||
1014 | if (u132->going > 1) { | ||
1015 | dev_err(&u132->platform_dev->dev, "device has been removed %d\n" | ||
1016 | , u132->going); | ||
1017 | up(&u132->scheduler_lock); | ||
1018 | u132_hcd_forget_urb(u132, endp, urb, -ENODEV); | ||
1019 | return; | ||
1020 | } else if (endp->dequeueing) { | ||
1021 | endp->dequeueing = 0; | ||
1022 | up(&u132->scheduler_lock); | ||
1023 | u132_hcd_giveback_urb(u132, endp, urb, -EINTR); | ||
1024 | return; | ||
1025 | } else if (u132->going > 0) { | ||
1026 | dev_err(&u132->platform_dev->dev, "device is being removed urb=" | ||
1027 | "%p status=%d\n", urb, urb->status); | ||
1028 | up(&u132->scheduler_lock); | ||
1029 | u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); | ||
1030 | return; | ||
1031 | } else if (urb->status == -EINPROGRESS) { | ||
1032 | up(&u132->scheduler_lock); | ||
1033 | u132_hcd_giveback_urb(u132, endp, urb, 0); | ||
1034 | return; | ||
1035 | } else { | ||
1036 | dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" | ||
1037 | "s=%d\n", urb, urb->status); | ||
1038 | up(&u132->scheduler_lock); | ||
1039 | u132_hcd_giveback_urb(u132, endp, urb, urb->status); | ||
1040 | return; | ||
1041 | } | ||
1042 | } | ||
1043 | |||
1044 | static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf, | ||
1045 | int len, int toggle_bits, int error_count, int condition_code, | ||
1046 | int repeat_number, int halted, int skipped, int actual, int non_null) | ||
1047 | { | ||
1048 | struct u132_endp *endp = data; | ||
1049 | struct u132 *u132 = endp->u132; | ||
1050 | u8 address = u132->addr[endp->usb_addr].address; | ||
1051 | down(&u132->scheduler_lock); | ||
1052 | if (u132->going > 1) { | ||
1053 | dev_err(&u132->platform_dev->dev, "device has been removed %d\n" | ||
1054 | , u132->going); | ||
1055 | up(&u132->scheduler_lock); | ||
1056 | u132_hcd_forget_urb(u132, endp, urb, -ENODEV); | ||
1057 | return; | ||
1058 | } else if (endp->dequeueing) { | ||
1059 | endp->dequeueing = 0; | ||
1060 | up(&u132->scheduler_lock); | ||
1061 | u132_hcd_giveback_urb(u132, endp, urb, -EINTR); | ||
1062 | return; | ||
1063 | } else if (u132->going > 0) { | ||
1064 | dev_err(&u132->platform_dev->dev, "device is being removed urb=" | ||
1065 | "%p status=%d\n", urb, urb->status); | ||
1066 | up(&u132->scheduler_lock); | ||
1067 | u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); | ||
1068 | return; | ||
1069 | } else if (urb->status == -EINPROGRESS) { | ||
1070 | if (usb_pipein(urb->pipe)) { | ||
1071 | int retval; | ||
1072 | struct u132_ring *ring = endp->ring; | ||
1073 | up(&u132->scheduler_lock); | ||
1074 | retval = usb_ftdi_elan_edset_input(u132->platform_dev, | ||
1075 | ring->number, endp, urb, address, | ||
1076 | endp->usb_endp, 0, | ||
1077 | u132_hcd_configure_input_recv); | ||
1078 | if (retval == 0) { | ||
1079 | } else | ||
1080 | u132_hcd_giveback_urb(u132, endp, urb, retval); | ||
1081 | return; | ||
1082 | } else { | ||
1083 | int retval; | ||
1084 | struct u132_ring *ring = endp->ring; | ||
1085 | up(&u132->scheduler_lock); | ||
1086 | retval = usb_ftdi_elan_edset_input(u132->platform_dev, | ||
1087 | ring->number, endp, urb, address, | ||
1088 | endp->usb_endp, 0, | ||
1089 | u132_hcd_configure_empty_recv); | ||
1090 | if (retval == 0) { | ||
1091 | } else | ||
1092 | u132_hcd_giveback_urb(u132, endp, urb, retval); | ||
1093 | return; | ||
1094 | } | ||
1095 | } else { | ||
1096 | dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" | ||
1097 | "s=%d\n", urb, urb->status); | ||
1098 | up(&u132->scheduler_lock); | ||
1099 | u132_hcd_giveback_urb(u132, endp, urb, urb->status); | ||
1100 | return; | ||
1101 | } | ||
1102 | } | ||
1103 | |||
1104 | static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb, | ||
1105 | u8 *buf, int len, int toggle_bits, int error_count, int condition_code, | ||
1106 | int repeat_number, int halted, int skipped, int actual, int non_null) | ||
1107 | { | ||
1108 | struct u132_endp *endp = data; | ||
1109 | struct u132 *u132 = endp->u132; | ||
1110 | u8 address = u132->addr[endp->usb_addr].address; | ||
1111 | struct u132_udev *udev = &u132->udev[address]; | ||
1112 | down(&u132->scheduler_lock); | ||
1113 | if (u132->going > 1) { | ||
1114 | dev_err(&u132->platform_dev->dev, "device has been removed %d\n" | ||
1115 | , u132->going); | ||
1116 | up(&u132->scheduler_lock); | ||
1117 | u132_hcd_forget_urb(u132, endp, urb, -ENODEV); | ||
1118 | return; | ||
1119 | } else if (endp->dequeueing) { | ||
1120 | endp->dequeueing = 0; | ||
1121 | up(&u132->scheduler_lock); | ||
1122 | u132_hcd_giveback_urb(u132, endp, urb, -EINTR); | ||
1123 | return; | ||
1124 | } else if (u132->going > 0) { | ||
1125 | dev_err(&u132->platform_dev->dev, "device is being removed urb=" | ||
1126 | "%p status=%d\n", urb, urb->status); | ||
1127 | up(&u132->scheduler_lock); | ||
1128 | u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); | ||
1129 | return; | ||
1130 | } else if (urb->status == -EINPROGRESS) { | ||
1131 | u132->addr[0].address = 0; | ||
1132 | endp->usb_addr = udev->usb_addr; | ||
1133 | up(&u132->scheduler_lock); | ||
1134 | u132_hcd_giveback_urb(u132, endp, urb, 0); | ||
1135 | return; | ||
1136 | } else { | ||
1137 | dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" | ||
1138 | "s=%d\n", urb, urb->status); | ||
1139 | up(&u132->scheduler_lock); | ||
1140 | u132_hcd_giveback_urb(u132, endp, urb, urb->status); | ||
1141 | return; | ||
1142 | } | ||
1143 | } | ||
1144 | |||
1145 | static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb, | ||
1146 | u8 *buf, int len, int toggle_bits, int error_count, int condition_code, | ||
1147 | int repeat_number, int halted, int skipped, int actual, int non_null) | ||
1148 | { | ||
1149 | struct u132_endp *endp = data; | ||
1150 | struct u132 *u132 = endp->u132; | ||
1151 | down(&u132->scheduler_lock); | ||
1152 | if (u132->going > 1) { | ||
1153 | dev_err(&u132->platform_dev->dev, "device has been removed %d\n" | ||
1154 | , u132->going); | ||
1155 | up(&u132->scheduler_lock); | ||
1156 | u132_hcd_forget_urb(u132, endp, urb, -ENODEV); | ||
1157 | return; | ||
1158 | } else if (endp->dequeueing) { | ||
1159 | endp->dequeueing = 0; | ||
1160 | up(&u132->scheduler_lock); | ||
1161 | u132_hcd_giveback_urb(u132, endp, urb, -EINTR); | ||
1162 | return; | ||
1163 | } else if (u132->going > 0) { | ||
1164 | dev_err(&u132->platform_dev->dev, "device is being removed urb=" | ||
1165 | "%p status=%d\n", urb, urb->status); | ||
1166 | up(&u132->scheduler_lock); | ||
1167 | u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); | ||
1168 | return; | ||
1169 | } else if (urb->status == -EINPROGRESS) { | ||
1170 | int retval; | ||
1171 | struct u132_ring *ring = endp->ring; | ||
1172 | up(&u132->scheduler_lock); | ||
1173 | retval = usb_ftdi_elan_edset_input(u132->platform_dev, | ||
1174 | ring->number, endp, urb, 0, endp->usb_endp, 0, | ||
1175 | u132_hcd_enumeration_empty_recv); | ||
1176 | if (retval == 0) { | ||
1177 | } else | ||
1178 | u132_hcd_giveback_urb(u132, endp, urb, retval); | ||
1179 | return; | ||
1180 | } else { | ||
1181 | dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" | ||
1182 | "s=%d\n", urb, urb->status); | ||
1183 | up(&u132->scheduler_lock); | ||
1184 | u132_hcd_giveback_urb(u132, endp, urb, urb->status); | ||
1185 | return; | ||
1186 | } | ||
1187 | } | ||
1188 | |||
1189 | static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf, | ||
1190 | int len, int toggle_bits, int error_count, int condition_code, | ||
1191 | int repeat_number, int halted, int skipped, int actual, int non_null) | ||
1192 | { | ||
1193 | struct u132_endp *endp = data; | ||
1194 | struct u132 *u132 = endp->u132; | ||
1195 | down(&u132->scheduler_lock); | ||
1196 | if (u132->going > 1) { | ||
1197 | dev_err(&u132->platform_dev->dev, "device has been removed %d\n" | ||
1198 | , u132->going); | ||
1199 | up(&u132->scheduler_lock); | ||
1200 | u132_hcd_forget_urb(u132, endp, urb, -ENODEV); | ||
1201 | return; | ||
1202 | } else if (endp->dequeueing) { | ||
1203 | endp->dequeueing = 0; | ||
1204 | up(&u132->scheduler_lock); | ||
1205 | u132_hcd_giveback_urb(u132, endp, urb, -EINTR); | ||
1206 | return; | ||
1207 | } else if (u132->going > 0) { | ||
1208 | dev_err(&u132->platform_dev->dev, "device is being removed urb=" | ||
1209 | "%p status=%d\n", urb, urb->status); | ||
1210 | up(&u132->scheduler_lock); | ||
1211 | u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); | ||
1212 | return; | ||
1213 | } else if (urb->status == -EINPROGRESS) { | ||
1214 | up(&u132->scheduler_lock); | ||
1215 | u132_hcd_giveback_urb(u132, endp, urb, 0); | ||
1216 | return; | ||
1217 | } else { | ||
1218 | dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" | ||
1219 | "s=%d\n", urb, urb->status); | ||
1220 | up(&u132->scheduler_lock); | ||
1221 | u132_hcd_giveback_urb(u132, endp, urb, urb->status); | ||
1222 | return; | ||
1223 | } | ||
1224 | } | ||
1225 | |||
1226 | static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf, | ||
1227 | int len, int toggle_bits, int error_count, int condition_code, | ||
1228 | int repeat_number, int halted, int skipped, int actual, int non_null) | ||
1229 | { | ||
1230 | struct u132_endp *endp = data; | ||
1231 | struct u132 *u132 = endp->u132; | ||
1232 | u8 address = u132->addr[endp->usb_addr].address; | ||
1233 | down(&u132->scheduler_lock); | ||
1234 | if (u132->going > 1) { | ||
1235 | dev_err(&u132->platform_dev->dev, "device has been removed %d\n" | ||
1236 | , u132->going); | ||
1237 | up(&u132->scheduler_lock); | ||
1238 | u132_hcd_forget_urb(u132, endp, urb, -ENODEV); | ||
1239 | return; | ||
1240 | } else if (endp->dequeueing) { | ||
1241 | endp->dequeueing = 0; | ||
1242 | up(&u132->scheduler_lock); | ||
1243 | u132_hcd_giveback_urb(u132, endp, urb, -EINTR); | ||
1244 | return; | ||
1245 | } else if (u132->going > 0) { | ||
1246 | dev_err(&u132->platform_dev->dev, "device is being removed urb=" | ||
1247 | "%p status=%d\n", urb, urb->status); | ||
1248 | up(&u132->scheduler_lock); | ||
1249 | u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); | ||
1250 | return; | ||
1251 | } else if (urb->status == -EINPROGRESS) { | ||
1252 | int retval; | ||
1253 | struct u132_ring *ring = endp->ring; | ||
1254 | u8 *u = urb->transfer_buffer; | ||
1255 | u8 *b = buf; | ||
1256 | int L = len; | ||
1257 | while (L-- > 0) { | ||
1258 | *u++ = *b++; | ||
1259 | } | ||
1260 | urb->actual_length = len; | ||
1261 | up(&u132->scheduler_lock); | ||
1262 | retval = usb_ftdi_elan_edset_empty(u132->platform_dev, | ||
1263 | ring->number, endp, urb, address, endp->usb_endp, 0x3, | ||
1264 | u132_hcd_initial_empty_sent); | ||
1265 | if (retval == 0) { | ||
1266 | } else | ||
1267 | u132_hcd_giveback_urb(u132, endp, urb, retval); | ||
1268 | return; | ||
1269 | } else { | ||
1270 | dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" | ||
1271 | "s=%d\n", urb, urb->status); | ||
1272 | up(&u132->scheduler_lock); | ||
1273 | u132_hcd_giveback_urb(u132, endp, urb, urb->status); | ||
1274 | return; | ||
1275 | } | ||
1276 | } | ||
1277 | |||
1278 | static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf, | ||
1279 | int len, int toggle_bits, int error_count, int condition_code, | ||
1280 | int repeat_number, int halted, int skipped, int actual, int non_null) | ||
1281 | { | ||
1282 | struct u132_endp *endp = data; | ||
1283 | struct u132 *u132 = endp->u132; | ||
1284 | u8 address = u132->addr[endp->usb_addr].address; | ||
1285 | down(&u132->scheduler_lock); | ||
1286 | if (u132->going > 1) { | ||
1287 | dev_err(&u132->platform_dev->dev, "device has been removed %d\n" | ||
1288 | , u132->going); | ||
1289 | up(&u132->scheduler_lock); | ||
1290 | u132_hcd_forget_urb(u132, endp, urb, -ENODEV); | ||
1291 | return; | ||
1292 | } else if (endp->dequeueing) { | ||
1293 | endp->dequeueing = 0; | ||
1294 | up(&u132->scheduler_lock); | ||
1295 | u132_hcd_giveback_urb(u132, endp, urb, -EINTR); | ||
1296 | return; | ||
1297 | } else if (u132->going > 0) { | ||
1298 | dev_err(&u132->platform_dev->dev, "device is being removed urb=" | ||
1299 | "%p status=%d\n", urb, urb->status); | ||
1300 | up(&u132->scheduler_lock); | ||
1301 | u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); | ||
1302 | return; | ||
1303 | } else if (urb->status == -EINPROGRESS) { | ||
1304 | int retval; | ||
1305 | struct u132_ring *ring = endp->ring; | ||
1306 | up(&u132->scheduler_lock); | ||
1307 | retval = usb_ftdi_elan_edset_input(u132->platform_dev, | ||
1308 | ring->number, endp, urb, address, endp->usb_endp, 0, | ||
1309 | u132_hcd_initial_input_recv); | ||
1310 | if (retval == 0) { | ||
1311 | } else | ||
1312 | u132_hcd_giveback_urb(u132, endp, urb, retval); | ||
1313 | return; | ||
1314 | } else { | ||
1315 | dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu" | ||
1316 | "s=%d\n", urb, urb->status); | ||
1317 | up(&u132->scheduler_lock); | ||
1318 | u132_hcd_giveback_urb(u132, endp, urb, urb->status); | ||
1319 | return; | ||
1320 | } | ||
1321 | } | ||
1322 | |||
1323 | static void u132_hcd_ring_work_scheduler(void *data); | ||
1324 | static void u132_hcd_endp_work_scheduler(void *data); | ||
1325 | /* | ||
1326 | * this work function is only executed from the work queue | ||
1327 | * | ||
1328 | */ | ||
1329 | static void u132_hcd_ring_work_scheduler(void *data) | ||
1330 | { | ||
1331 | struct u132_ring *ring = data; | ||
1332 | struct u132 *u132 = ring->u132; | ||
1333 | down(&u132->scheduler_lock); | ||
1334 | if (ring->in_use) { | ||
1335 | up(&u132->scheduler_lock); | ||
1336 | u132_ring_put_kref(u132, ring); | ||
1337 | return; | ||
1338 | } else if (ring->curr_endp) { | ||
1339 | struct u132_endp *last_endp = ring->curr_endp; | ||
1340 | struct list_head *scan; | ||
1341 | struct list_head *head = &last_endp->endp_ring; | ||
1342 | unsigned long wakeup = 0; | ||
1343 | list_for_each(scan, head) { | ||
1344 | struct u132_endp *endp = list_entry(scan, | ||
1345 | struct u132_endp, endp_ring); | ||
1346 | if (endp->queue_next == endp->queue_last) { | ||
1347 | } else if ((endp->delayed == 0) | ||
1348 | || time_after_eq(jiffies, endp->jiffies)) { | ||
1349 | ring->curr_endp = endp; | ||
1350 | u132_endp_cancel_work(u132, last_endp); | ||
1351 | u132_endp_queue_work(u132, last_endp, 0); | ||
1352 | up(&u132->scheduler_lock); | ||
1353 | u132_ring_put_kref(u132, ring); | ||
1354 | return; | ||
1355 | } else { | ||
1356 | unsigned long delta = endp->jiffies - jiffies; | ||
1357 | if (delta > wakeup) | ||
1358 | wakeup = delta; | ||
1359 | } | ||
1360 | } | ||
1361 | if (last_endp->queue_next == last_endp->queue_last) { | ||
1362 | } else if ((last_endp->delayed == 0) || time_after_eq(jiffies, | ||
1363 | last_endp->jiffies)) { | ||
1364 | u132_endp_cancel_work(u132, last_endp); | ||
1365 | u132_endp_queue_work(u132, last_endp, 0); | ||
1366 | up(&u132->scheduler_lock); | ||
1367 | u132_ring_put_kref(u132, ring); | ||
1368 | return; | ||
1369 | } else { | ||
1370 | unsigned long delta = last_endp->jiffies - jiffies; | ||
1371 | if (delta > wakeup) | ||
1372 | wakeup = delta; | ||
1373 | } | ||
1374 | if (wakeup > 0) { | ||
1375 | u132_ring_requeue_work(u132, ring, wakeup); | ||
1376 | up(&u132->scheduler_lock); | ||
1377 | return; | ||
1378 | } else { | ||
1379 | up(&u132->scheduler_lock); | ||
1380 | u132_ring_put_kref(u132, ring); | ||
1381 | return; | ||
1382 | } | ||
1383 | } else { | ||
1384 | up(&u132->scheduler_lock); | ||
1385 | u132_ring_put_kref(u132, ring); | ||
1386 | return; | ||
1387 | } | ||
1388 | } | ||
1389 | |||
1390 | static void u132_hcd_endp_work_scheduler(void *data) | ||
1391 | { | ||
1392 | struct u132_ring *ring; | ||
1393 | struct u132_endp *endp = data; | ||
1394 | struct u132 *u132 = endp->u132; | ||
1395 | down(&u132->scheduler_lock); | ||
1396 | ring = endp->ring; | ||
1397 | if (endp->edset_flush) { | ||
1398 | endp->edset_flush = 0; | ||
1399 | if (endp->dequeueing) | ||
1400 | usb_ftdi_elan_edset_flush(u132->platform_dev, | ||
1401 | ring->number, endp); | ||
1402 | up(&u132->scheduler_lock); | ||
1403 | u132_endp_put_kref(u132, endp); | ||
1404 | return; | ||
1405 | } else if (endp->active) { | ||
1406 | up(&u132->scheduler_lock); | ||
1407 | u132_endp_put_kref(u132, endp); | ||
1408 | return; | ||
1409 | } else if (ring->in_use) { | ||
1410 | up(&u132->scheduler_lock); | ||
1411 | u132_endp_put_kref(u132, endp); | ||
1412 | return; | ||
1413 | } else if (endp->queue_next == endp->queue_last) { | ||
1414 | up(&u132->scheduler_lock); | ||
1415 | u132_endp_put_kref(u132, endp); | ||
1416 | return; | ||
1417 | } else if (endp->pipetype == PIPE_INTERRUPT) { | ||
1418 | u8 address = u132->addr[endp->usb_addr].address; | ||
1419 | if (ring->in_use) { | ||
1420 | up(&u132->scheduler_lock); | ||
1421 | u132_endp_put_kref(u132, endp); | ||
1422 | return; | ||
1423 | } else { | ||
1424 | int retval; | ||
1425 | struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK & | ||
1426 | endp->queue_next]; | ||
1427 | endp->active = 1; | ||
1428 | ring->curr_endp = endp; | ||
1429 | ring->in_use = 1; | ||
1430 | up(&u132->scheduler_lock); | ||
1431 | retval = edset_single(u132, ring, endp, urb, address, | ||
1432 | endp->toggle_bits, u132_hcd_interrupt_recv); | ||
1433 | if (retval == 0) { | ||
1434 | } else | ||
1435 | u132_hcd_giveback_urb(u132, endp, urb, retval); | ||
1436 | return; | ||
1437 | } | ||
1438 | } else if (endp->pipetype == PIPE_CONTROL) { | ||
1439 | u8 address = u132->addr[endp->usb_addr].address; | ||
1440 | if (ring->in_use) { | ||
1441 | up(&u132->scheduler_lock); | ||
1442 | u132_endp_put_kref(u132, endp); | ||
1443 | return; | ||
1444 | } else if (address == 0) { | ||
1445 | int retval; | ||
1446 | struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK & | ||
1447 | endp->queue_next]; | ||
1448 | endp->active = 1; | ||
1449 | ring->curr_endp = endp; | ||
1450 | ring->in_use = 1; | ||
1451 | up(&u132->scheduler_lock); | ||
1452 | retval = edset_setup(u132, ring, endp, urb, address, | ||
1453 | 0x2, u132_hcd_initial_setup_sent); | ||
1454 | if (retval == 0) { | ||
1455 | } else | ||
1456 | u132_hcd_giveback_urb(u132, endp, urb, retval); | ||
1457 | return; | ||
1458 | } else if (endp->usb_addr == 0) { | ||
1459 | int retval; | ||
1460 | struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK & | ||
1461 | endp->queue_next]; | ||
1462 | endp->active = 1; | ||
1463 | ring->curr_endp = endp; | ||
1464 | ring->in_use = 1; | ||
1465 | up(&u132->scheduler_lock); | ||
1466 | retval = edset_setup(u132, ring, endp, urb, 0, 0x2, | ||
1467 | u132_hcd_enumeration_address_sent); | ||
1468 | if (retval == 0) { | ||
1469 | } else | ||
1470 | u132_hcd_giveback_urb(u132, endp, urb, retval); | ||
1471 | return; | ||
1472 | } else { | ||
1473 | int retval; | ||
1474 | u8 address = u132->addr[endp->usb_addr].address; | ||
1475 | struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK & | ||
1476 | endp->queue_next]; | ||
1477 | endp->active = 1; | ||
1478 | ring->curr_endp = endp; | ||
1479 | ring->in_use = 1; | ||
1480 | up(&u132->scheduler_lock); | ||
1481 | retval = edset_setup(u132, ring, endp, urb, address, | ||
1482 | 0x2, u132_hcd_configure_setup_sent); | ||
1483 | if (retval == 0) { | ||
1484 | } else | ||
1485 | u132_hcd_giveback_urb(u132, endp, urb, retval); | ||
1486 | return; | ||
1487 | } | ||
1488 | } else { | ||
1489 | if (endp->input) { | ||
1490 | u8 address = u132->addr[endp->usb_addr].address; | ||
1491 | if (ring->in_use) { | ||
1492 | up(&u132->scheduler_lock); | ||
1493 | u132_endp_put_kref(u132, endp); | ||
1494 | return; | ||
1495 | } else { | ||
1496 | int retval; | ||
1497 | struct urb *urb = endp->urb_list[ | ||
1498 | ENDP_QUEUE_MASK & endp->queue_next]; | ||
1499 | endp->active = 1; | ||
1500 | ring->curr_endp = endp; | ||
1501 | ring->in_use = 1; | ||
1502 | up(&u132->scheduler_lock); | ||
1503 | retval = edset_input(u132, ring, endp, urb, | ||
1504 | address, endp->toggle_bits, | ||
1505 | u132_hcd_bulk_input_recv); | ||
1506 | if (retval == 0) { | ||
1507 | } else | ||
1508 | u132_hcd_giveback_urb(u132, endp, urb, | ||
1509 | retval); | ||
1510 | return; | ||
1511 | } | ||
1512 | } else { /* output pipe */ | ||
1513 | u8 address = u132->addr[endp->usb_addr].address; | ||
1514 | if (ring->in_use) { | ||
1515 | up(&u132->scheduler_lock); | ||
1516 | u132_endp_put_kref(u132, endp); | ||
1517 | return; | ||
1518 | } else { | ||
1519 | int retval; | ||
1520 | struct urb *urb = endp->urb_list[ | ||
1521 | ENDP_QUEUE_MASK & endp->queue_next]; | ||
1522 | endp->active = 1; | ||
1523 | ring->curr_endp = endp; | ||
1524 | ring->in_use = 1; | ||
1525 | up(&u132->scheduler_lock); | ||
1526 | retval = edset_output(u132, ring, endp, urb, | ||
1527 | address, endp->toggle_bits, | ||
1528 | u132_hcd_bulk_output_sent); | ||
1529 | if (retval == 0) { | ||
1530 | } else | ||
1531 | u132_hcd_giveback_urb(u132, endp, urb, | ||
1532 | retval); | ||
1533 | return; | ||
1534 | } | ||
1535 | } | ||
1536 | } | ||
1537 | } | ||
1538 | |||
1539 | static void port_power(struct u132 *u132, int pn, int is_on) | ||
1540 | { | ||
1541 | u132->port[pn].power = is_on; | ||
1542 | } | ||
1543 | |||
1544 | static void u132_power(struct u132 *u132, int is_on) | ||
1545 | { | ||
1546 | struct usb_hcd *hcd = u132_to_hcd(u132) | ||
1547 | ; /* hub is inactive unless the port is powered */ | ||
1548 | if (is_on) { | ||
1549 | if (u132->power) | ||
1550 | return; | ||
1551 | u132->power = 1; | ||
1552 | hcd->self.controller->power.power_state = PMSG_ON; | ||
1553 | } else { | ||
1554 | u132->power = 0; | ||
1555 | hcd->state = HC_STATE_HALT; | ||
1556 | hcd->self.controller->power.power_state = PMSG_SUSPEND; | ||
1557 | } | ||
1558 | } | ||
1559 | |||
1560 | static int u132_periodic_reinit(struct u132 *u132) | ||
1561 | { | ||
1562 | int retval; | ||
1563 | u32 fi = u132->hc_fminterval & 0x03fff; | ||
1564 | u32 fit; | ||
1565 | u32 fminterval; | ||
1566 | retval = u132_read_pcimem(u132, fminterval, &fminterval); | ||
1567 | if (retval) | ||
1568 | return retval; | ||
1569 | fit = fminterval & FIT; | ||
1570 | retval = u132_write_pcimem(u132, fminterval, | ||
1571 | (fit ^ FIT) | u132->hc_fminterval); | ||
1572 | if (retval) | ||
1573 | return retval; | ||
1574 | retval = u132_write_pcimem(u132, periodicstart, | ||
1575 | ((9 *fi) / 10) & 0x3fff); | ||
1576 | if (retval) | ||
1577 | return retval; | ||
1578 | return 0; | ||
1579 | } | ||
1580 | |||
1581 | static char *hcfs2string(int state) | ||
1582 | { | ||
1583 | switch (state) { | ||
1584 | case OHCI_USB_RESET: | ||
1585 | return "reset"; | ||
1586 | case OHCI_USB_RESUME: | ||
1587 | return "resume"; | ||
1588 | case OHCI_USB_OPER: | ||
1589 | return "operational"; | ||
1590 | case OHCI_USB_SUSPEND: | ||
1591 | return "suspend"; | ||
1592 | } | ||
1593 | return "?"; | ||
1594 | } | ||
1595 | |||
1596 | static int u132_usb_reset(struct u132 *u132) | ||
1597 | { | ||
1598 | int retval; | ||
1599 | retval = u132_read_pcimem(u132, control, &u132->hc_control); | ||
1600 | if (retval) | ||
1601 | return retval; | ||
1602 | u132->hc_control &= OHCI_CTRL_RWC; | ||
1603 | retval = u132_write_pcimem(u132, control, u132->hc_control); | ||
1604 | if (retval) | ||
1605 | return retval; | ||
1606 | return 0; | ||
1607 | } | ||
1608 | |||
1609 | static int u132_init(struct u132 *u132) | ||
1610 | { | ||
1611 | int retval; | ||
1612 | u32 control; | ||
1613 | u132_disable(u132); | ||
1614 | u132->next_statechange = | ||
1615 | jiffies; /* SMM owns the HC? not for long! */ { | ||
1616 | u32 control; | ||
1617 | retval = u132_read_pcimem(u132, control, &control); | ||
1618 | if (retval) | ||
1619 | return retval; | ||
1620 | if (control & OHCI_CTRL_IR) { | ||
1621 | u32 temp = 50; | ||
1622 | retval = u132_write_pcimem(u132, intrenable, | ||
1623 | OHCI_INTR_OC); | ||
1624 | if (retval) | ||
1625 | return retval; | ||
1626 | retval = u132_write_pcimem_byte(u132, cmdstatus, | ||
1627 | OHCI_OCR); | ||
1628 | if (retval) | ||
1629 | return retval; | ||
1630 | check:{ | ||
1631 | retval = u132_read_pcimem(u132, control, | ||
1632 | &control); | ||
1633 | if (retval) | ||
1634 | return retval; | ||
1635 | } | ||
1636 | if (control & OHCI_CTRL_IR) { | ||
1637 | msleep(10); | ||
1638 | if (--temp == 0) { | ||
1639 | dev_err(&u132->platform_dev->dev, "USB " | ||
1640 | "HC takeover failed!(BIOS/SMM b" | ||
1641 | "ug) control=%08X\n", control); | ||
1642 | return -EBUSY; | ||
1643 | } | ||
1644 | goto check; | ||
1645 | } | ||
1646 | u132_usb_reset(u132); | ||
1647 | } | ||
1648 | } | ||
1649 | retval = u132_write_pcimem(u132, intrdisable, OHCI_INTR_MIE); | ||
1650 | if (retval) | ||
1651 | return retval; | ||
1652 | retval = u132_read_pcimem(u132, control, &control); | ||
1653 | if (retval) | ||
1654 | return retval; | ||
1655 | if (u132->num_ports == 0) { | ||
1656 | u32 rh_a = -1; | ||
1657 | retval = u132_read_pcimem(u132, roothub.a, &rh_a); | ||
1658 | if (retval) | ||
1659 | return retval; | ||
1660 | u132->num_ports = rh_a & RH_A_NDP; | ||
1661 | retval = read_roothub_info(u132); | ||
1662 | if (retval) | ||
1663 | return retval; | ||
1664 | } | ||
1665 | if (u132->num_ports > MAX_U132_PORTS) { | ||
1666 | return -EINVAL; | ||
1667 | } | ||
1668 | return 0; | ||
1669 | } | ||
1670 | |||
1671 | |||
1672 | /* Start an OHCI controller, set the BUS operational | ||
1673 | * resets USB and controller | ||
1674 | * enable interrupts | ||
1675 | */ | ||
1676 | static int u132_run(struct u132 *u132) | ||
1677 | { | ||
1678 | int retval; | ||
1679 | u32 control; | ||
1680 | u32 status; | ||
1681 | u32 fminterval; | ||
1682 | u32 periodicstart; | ||
1683 | u32 cmdstatus; | ||
1684 | u32 roothub_a; | ||
1685 | int mask = OHCI_INTR_INIT; | ||
1686 | int first = u132->hc_fminterval == 0; | ||
1687 | int sleep_time = 0; | ||
1688 | int reset_timeout = 30; /* ... allow extra time */ | ||
1689 | u132_disable(u132); | ||
1690 | if (first) { | ||
1691 | u32 temp; | ||
1692 | retval = u132_read_pcimem(u132, fminterval, &temp); | ||
1693 | if (retval) | ||
1694 | return retval; | ||
1695 | u132->hc_fminterval = temp & 0x3fff; | ||
1696 | if (u132->hc_fminterval != FI) { | ||
1697 | } | ||
1698 | u132->hc_fminterval |= FSMP(u132->hc_fminterval) << 16; | ||
1699 | } | ||
1700 | retval = u132_read_pcimem(u132, control, &u132->hc_control); | ||
1701 | if (retval) | ||
1702 | return retval; | ||
1703 | dev_info(&u132->platform_dev->dev, "resetting from state '%s', control " | ||
1704 | "= %08X\n", hcfs2string(u132->hc_control & OHCI_CTRL_HCFS), | ||
1705 | u132->hc_control); | ||
1706 | switch (u132->hc_control & OHCI_CTRL_HCFS) { | ||
1707 | case OHCI_USB_OPER: | ||
1708 | sleep_time = 0; | ||
1709 | break; | ||
1710 | case OHCI_USB_SUSPEND: | ||
1711 | case OHCI_USB_RESUME: | ||
1712 | u132->hc_control &= OHCI_CTRL_RWC; | ||
1713 | u132->hc_control |= OHCI_USB_RESUME; | ||
1714 | sleep_time = 10; | ||
1715 | break; | ||
1716 | default: | ||
1717 | u132->hc_control &= OHCI_CTRL_RWC; | ||
1718 | u132->hc_control |= OHCI_USB_RESET; | ||
1719 | sleep_time = 50; | ||
1720 | break; | ||
1721 | } | ||
1722 | retval = u132_write_pcimem(u132, control, u132->hc_control); | ||
1723 | if (retval) | ||
1724 | return retval; | ||
1725 | retval = u132_read_pcimem(u132, control, &control); | ||
1726 | if (retval) | ||
1727 | return retval; | ||
1728 | msleep(sleep_time); | ||
1729 | retval = u132_read_pcimem(u132, roothub.a, &roothub_a); | ||
1730 | if (retval) | ||
1731 | return retval; | ||
1732 | if (!(roothub_a & RH_A_NPS)) { | ||
1733 | int temp; /* power down each port */ | ||
1734 | for (temp = 0; temp < u132->num_ports; temp++) { | ||
1735 | retval = u132_write_pcimem(u132, | ||
1736 | roothub.portstatus[temp], RH_PS_LSDA); | ||
1737 | if (retval) | ||
1738 | return retval; | ||
1739 | } | ||
1740 | } | ||
1741 | retval = u132_read_pcimem(u132, control, &control); | ||
1742 | if (retval) | ||
1743 | return retval; | ||
1744 | retry:retval = u132_read_pcimem(u132, cmdstatus, &status); | ||
1745 | if (retval) | ||
1746 | return retval; | ||
1747 | retval = u132_write_pcimem_byte(u132, cmdstatus, OHCI_HCR); | ||
1748 | if (retval) | ||
1749 | return retval; | ||
1750 | extra:{ | ||
1751 | retval = u132_read_pcimem(u132, cmdstatus, &status); | ||
1752 | if (retval) | ||
1753 | return retval; | ||
1754 | if (0 != (status & OHCI_HCR)) { | ||
1755 | if (--reset_timeout == 0) { | ||
1756 | dev_err(&u132->platform_dev->dev, "USB HC reset" | ||
1757 | " timed out!\n"); | ||
1758 | return -ENODEV; | ||
1759 | } else { | ||
1760 | msleep(5); | ||
1761 | goto extra; | ||
1762 | } | ||
1763 | } | ||
1764 | } | ||
1765 | if (u132->flags & OHCI_QUIRK_INITRESET) { | ||
1766 | retval = u132_write_pcimem(u132, control, u132->hc_control); | ||
1767 | if (retval) | ||
1768 | return retval; | ||
1769 | retval = u132_read_pcimem(u132, control, &control); | ||
1770 | if (retval) | ||
1771 | return retval; | ||
1772 | } | ||
1773 | retval = u132_write_pcimem(u132, ed_controlhead, 0x00000000); | ||
1774 | if (retval) | ||
1775 | return retval; | ||
1776 | retval = u132_write_pcimem(u132, ed_bulkhead, 0x11000000); | ||
1777 | if (retval) | ||
1778 | return retval; | ||
1779 | retval = u132_write_pcimem(u132, hcca, 0x00000000); | ||
1780 | if (retval) | ||
1781 | return retval; | ||
1782 | retval = u132_periodic_reinit(u132); | ||
1783 | if (retval) | ||
1784 | return retval; | ||
1785 | retval = u132_read_pcimem(u132, fminterval, &fminterval); | ||
1786 | if (retval) | ||
1787 | return retval; | ||
1788 | retval = u132_read_pcimem(u132, periodicstart, &periodicstart); | ||
1789 | if (retval) | ||
1790 | return retval; | ||
1791 | if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) { | ||
1792 | if (!(u132->flags & OHCI_QUIRK_INITRESET)) { | ||
1793 | u132->flags |= OHCI_QUIRK_INITRESET; | ||
1794 | goto retry; | ||
1795 | } else | ||
1796 | dev_err(&u132->platform_dev->dev, "init err(%08x %04x)" | ||
1797 | "\n", fminterval, periodicstart); | ||
1798 | } /* start controller operations */ | ||
1799 | u132->hc_control &= OHCI_CTRL_RWC; | ||
1800 | u132->hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER; | ||
1801 | retval = u132_write_pcimem(u132, control, u132->hc_control); | ||
1802 | if (retval) | ||
1803 | return retval; | ||
1804 | retval = u132_write_pcimem_byte(u132, cmdstatus, OHCI_BLF); | ||
1805 | if (retval) | ||
1806 | return retval; | ||
1807 | retval = u132_read_pcimem(u132, cmdstatus, &cmdstatus); | ||
1808 | if (retval) | ||
1809 | return retval; | ||
1810 | retval = u132_read_pcimem(u132, control, &control); | ||
1811 | if (retval) | ||
1812 | return retval; | ||
1813 | u132_to_hcd(u132)->state = HC_STATE_RUNNING; | ||
1814 | retval = u132_write_pcimem(u132, roothub.status, RH_HS_DRWE); | ||
1815 | if (retval) | ||
1816 | return retval; | ||
1817 | retval = u132_write_pcimem(u132, intrstatus, mask); | ||
1818 | if (retval) | ||
1819 | return retval; | ||
1820 | retval = u132_write_pcimem(u132, intrdisable, | ||
1821 | OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO | | ||
1822 | OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH | | ||
1823 | OHCI_INTR_SO); | ||
1824 | if (retval) | ||
1825 | return retval; /* handle root hub init quirks ... */ | ||
1826 | retval = u132_read_pcimem(u132, roothub.a, &roothub_a); | ||
1827 | if (retval) | ||
1828 | return retval; | ||
1829 | roothub_a &= ~(RH_A_PSM | RH_A_OCPM); | ||
1830 | if (u132->flags & OHCI_QUIRK_SUPERIO) { | ||
1831 | roothub_a |= RH_A_NOCP; | ||
1832 | roothub_a &= ~(RH_A_POTPGT | RH_A_NPS); | ||
1833 | retval = u132_write_pcimem(u132, roothub.a, roothub_a); | ||
1834 | if (retval) | ||
1835 | return retval; | ||
1836 | } else if ((u132->flags & OHCI_QUIRK_AMD756) || distrust_firmware) { | ||
1837 | roothub_a |= RH_A_NPS; | ||
1838 | retval = u132_write_pcimem(u132, roothub.a, roothub_a); | ||
1839 | if (retval) | ||
1840 | return retval; | ||
1841 | } | ||
1842 | retval = u132_write_pcimem(u132, roothub.status, RH_HS_LPSC); | ||
1843 | if (retval) | ||
1844 | return retval; | ||
1845 | retval = u132_write_pcimem(u132, roothub.b, | ||
1846 | (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM); | ||
1847 | if (retval) | ||
1848 | return retval; | ||
1849 | retval = u132_read_pcimem(u132, control, &control); | ||
1850 | if (retval) | ||
1851 | return retval; | ||
1852 | mdelay((roothub_a >> 23) & 0x1fe); | ||
1853 | u132_to_hcd(u132)->state = HC_STATE_RUNNING; | ||
1854 | return 0; | ||
1855 | } | ||
1856 | |||
1857 | static void u132_hcd_stop(struct usb_hcd *hcd) | ||
1858 | { | ||
1859 | struct u132 *u132 = hcd_to_u132(hcd); | ||
1860 | if (u132->going > 1) { | ||
1861 | dev_err(&u132->platform_dev->dev, "device has been removed %d\n" | ||
1862 | , u132->going); | ||
1863 | } else if (u132->going > 0) { | ||
1864 | dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov" | ||
1865 | "ed\n", hcd); | ||
1866 | } else { | ||
1867 | down(&u132->sw_lock); | ||
1868 | msleep(100); | ||
1869 | u132_power(u132, 0); | ||
1870 | up(&u132->sw_lock); | ||
1871 | } | ||
1872 | } | ||
1873 | |||
1874 | static int u132_hcd_start(struct usb_hcd *hcd) | ||
1875 | { | ||
1876 | struct u132 *u132 = hcd_to_u132(hcd); | ||
1877 | if (u132->going > 1) { | ||
1878 | dev_err(&u132->platform_dev->dev, "device has been removed %d\n" | ||
1879 | , u132->going); | ||
1880 | return -ENODEV; | ||
1881 | } else if (u132->going > 0) { | ||
1882 | dev_err(&u132->platform_dev->dev, "device is being removed\n"); | ||
1883 | return -ESHUTDOWN; | ||
1884 | } else if (hcd->self.controller) { | ||
1885 | int retval; | ||
1886 | struct platform_device *pdev = | ||
1887 | to_platform_device(hcd->self.controller); | ||
1888 | u16 vendor = ((struct u132_platform_data *) | ||
1889 | (pdev->dev.platform_data))->vendor; | ||
1890 | u16 device = ((struct u132_platform_data *) | ||
1891 | (pdev->dev.platform_data))->device; | ||
1892 | down(&u132->sw_lock); | ||
1893 | msleep(10); | ||
1894 | if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) { | ||
1895 | u132->flags = OHCI_QUIRK_AMD756; | ||
1896 | } else if (vendor == PCI_VENDOR_ID_OPTI && device == 0xc861) { | ||
1897 | dev_err(&u132->platform_dev->dev, "WARNING: OPTi workar" | ||
1898 | "ounds unavailable\n"); | ||
1899 | } else if (vendor == PCI_VENDOR_ID_COMPAQ && device == 0xa0f8) | ||
1900 | u132->flags |= OHCI_QUIRK_ZFMICRO; | ||
1901 | retval = u132_run(u132); | ||
1902 | if (retval) { | ||
1903 | u132_disable(u132); | ||
1904 | u132->going = 1; | ||
1905 | } | ||
1906 | msleep(100); | ||
1907 | up(&u132->sw_lock); | ||
1908 | return retval; | ||
1909 | } else { | ||
1910 | dev_err(&u132->platform_dev->dev, "platform_device missing\n"); | ||
1911 | return -ENODEV; | ||
1912 | } | ||
1913 | } | ||
1914 | |||
1915 | static int u132_hcd_reset(struct usb_hcd *hcd) | ||
1916 | { | ||
1917 | struct u132 *u132 = hcd_to_u132(hcd); | ||
1918 | if (u132->going > 1) { | ||
1919 | dev_err(&u132->platform_dev->dev, "device has been removed %d\n" | ||
1920 | , u132->going); | ||
1921 | return -ENODEV; | ||
1922 | } else if (u132->going > 0) { | ||
1923 | dev_err(&u132->platform_dev->dev, "device is being removed\n"); | ||
1924 | return -ESHUTDOWN; | ||
1925 | } else { | ||
1926 | int retval; | ||
1927 | down(&u132->sw_lock); | ||
1928 | retval = u132_init(u132); | ||
1929 | if (retval) { | ||
1930 | u132_disable(u132); | ||
1931 | u132->going = 1; | ||
1932 | } | ||
1933 | up(&u132->sw_lock); | ||
1934 | return retval; | ||
1935 | } | ||
1936 | } | ||
1937 | |||
1938 | static int create_endpoint_and_queue_int(struct u132 *u132, | ||
1939 | struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb, | ||
1940 | struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address, | ||
1941 | gfp_t mem_flags) | ||
1942 | { | ||
1943 | struct u132_ring *ring; | ||
1944 | unsigned long irqs; | ||
1945 | u8 endp_number = ++u132->num_endpoints; | ||
1946 | struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] = | ||
1947 | kmalloc(sizeof(struct u132_endp), mem_flags); | ||
1948 | if (!endp) { | ||
1949 | return -ENOMEM; | ||
1950 | } | ||
1951 | INIT_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler, (void *)endp); | ||
1952 | spin_lock_init(&endp->queue_lock.slock); | ||
1953 | INIT_LIST_HEAD(&endp->urb_more); | ||
1954 | ring = endp->ring = &u132->ring[0]; | ||
1955 | if (ring->curr_endp) { | ||
1956 | list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring); | ||
1957 | } else { | ||
1958 | INIT_LIST_HEAD(&endp->endp_ring); | ||
1959 | ring->curr_endp = endp; | ||
1960 | } | ||
1961 | ring->length += 1; | ||
1962 | endp->dequeueing = 0; | ||
1963 | endp->edset_flush = 0; | ||
1964 | endp->active = 0; | ||
1965 | endp->delayed = 0; | ||
1966 | endp->endp_number = endp_number; | ||
1967 | endp->u132 = u132; | ||
1968 | endp->hep = hep; | ||
1969 | endp->pipetype = usb_pipetype(urb->pipe); | ||
1970 | u132_endp_init_kref(u132, endp); | ||
1971 | if (usb_pipein(urb->pipe)) { | ||
1972 | endp->toggle_bits = 0x2; | ||
1973 | usb_settoggle(udev->usb_device, usb_endp, 0, 0); | ||
1974 | endp->input = 1; | ||
1975 | endp->output = 0; | ||
1976 | udev->endp_number_in[usb_endp] = endp_number; | ||
1977 | u132_udev_get_kref(u132, udev); | ||
1978 | } else { | ||
1979 | endp->toggle_bits = 0x2; | ||
1980 | usb_settoggle(udev->usb_device, usb_endp, 1, 0); | ||
1981 | endp->input = 0; | ||
1982 | endp->output = 1; | ||
1983 | udev->endp_number_out[usb_endp] = endp_number; | ||
1984 | u132_udev_get_kref(u132, udev); | ||
1985 | } | ||
1986 | urb->hcpriv = u132; | ||
1987 | spin_lock_irqsave(&endp->queue_lock.slock, irqs); | ||
1988 | endp->delayed = 1; | ||
1989 | endp->jiffies = jiffies + msecs_to_jiffies(urb->interval); | ||
1990 | endp->udev_number = address; | ||
1991 | endp->usb_addr = usb_addr; | ||
1992 | endp->usb_endp = usb_endp; | ||
1993 | endp->queue_size = 1; | ||
1994 | endp->queue_last = 0; | ||
1995 | endp->queue_next = 0; | ||
1996 | endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; | ||
1997 | spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); | ||
1998 | u132_endp_queue_work(u132, endp, msecs_to_jiffies(urb->interval)); | ||
1999 | return 0; | ||
2000 | } | ||
2001 | |||
2002 | static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev, | ||
2003 | struct usb_host_endpoint *hep, struct urb *urb, | ||
2004 | struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, | ||
2005 | u8 usb_endp, u8 address) | ||
2006 | { | ||
2007 | urb->hcpriv = u132; | ||
2008 | endp->delayed = 1; | ||
2009 | endp->jiffies = jiffies + msecs_to_jiffies(urb->interval); | ||
2010 | if (endp->queue_size++ < ENDP_QUEUE_SIZE) { | ||
2011 | endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; | ||
2012 | } else { | ||
2013 | struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq), | ||
2014 | GFP_ATOMIC); | ||
2015 | if (urbq == NULL) { | ||
2016 | endp->queue_size -= 1; | ||
2017 | return -ENOMEM; | ||
2018 | } else { | ||
2019 | list_add_tail(&urbq->urb_more, &endp->urb_more); | ||
2020 | urbq->urb = urb; | ||
2021 | } | ||
2022 | } | ||
2023 | return 0; | ||
2024 | } | ||
2025 | |||
2026 | static int create_endpoint_and_queue_bulk(struct u132 *u132, | ||
2027 | struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb, | ||
2028 | struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address, | ||
2029 | gfp_t mem_flags) | ||
2030 | { | ||
2031 | int ring_number; | ||
2032 | struct u132_ring *ring; | ||
2033 | unsigned long irqs; | ||
2034 | u8 endp_number = ++u132->num_endpoints; | ||
2035 | struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] = | ||
2036 | kmalloc(sizeof(struct u132_endp), mem_flags); | ||
2037 | if (!endp) { | ||
2038 | return -ENOMEM; | ||
2039 | } | ||
2040 | INIT_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler, (void *)endp); | ||
2041 | spin_lock_init(&endp->queue_lock.slock); | ||
2042 | INIT_LIST_HEAD(&endp->urb_more); | ||
2043 | endp->dequeueing = 0; | ||
2044 | endp->edset_flush = 0; | ||
2045 | endp->active = 0; | ||
2046 | endp->delayed = 0; | ||
2047 | endp->endp_number = endp_number; | ||
2048 | endp->u132 = u132; | ||
2049 | endp->hep = hep; | ||
2050 | endp->pipetype = usb_pipetype(urb->pipe); | ||
2051 | u132_endp_init_kref(u132, endp); | ||
2052 | if (usb_pipein(urb->pipe)) { | ||
2053 | endp->toggle_bits = 0x2; | ||
2054 | usb_settoggle(udev->usb_device, usb_endp, 0, 0); | ||
2055 | ring_number = 3; | ||
2056 | endp->input = 1; | ||
2057 | endp->output = 0; | ||
2058 | udev->endp_number_in[usb_endp] = endp_number; | ||
2059 | u132_udev_get_kref(u132, udev); | ||
2060 | } else { | ||
2061 | endp->toggle_bits = 0x2; | ||
2062 | usb_settoggle(udev->usb_device, usb_endp, 1, 0); | ||
2063 | ring_number = 2; | ||
2064 | endp->input = 0; | ||
2065 | endp->output = 1; | ||
2066 | udev->endp_number_out[usb_endp] = endp_number; | ||
2067 | u132_udev_get_kref(u132, udev); | ||
2068 | } | ||
2069 | ring = endp->ring = &u132->ring[ring_number - 1]; | ||
2070 | if (ring->curr_endp) { | ||
2071 | list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring); | ||
2072 | } else { | ||
2073 | INIT_LIST_HEAD(&endp->endp_ring); | ||
2074 | ring->curr_endp = endp; | ||
2075 | } | ||
2076 | ring->length += 1; | ||
2077 | urb->hcpriv = u132; | ||
2078 | spin_lock_irqsave(&endp->queue_lock.slock, irqs); | ||
2079 | endp->udev_number = address; | ||
2080 | endp->usb_addr = usb_addr; | ||
2081 | endp->usb_endp = usb_endp; | ||
2082 | endp->queue_size = 1; | ||
2083 | endp->queue_last = 0; | ||
2084 | endp->queue_next = 0; | ||
2085 | endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; | ||
2086 | spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); | ||
2087 | u132_endp_queue_work(u132, endp, 0); | ||
2088 | return 0; | ||
2089 | } | ||
2090 | |||
2091 | static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev, | ||
2092 | struct usb_host_endpoint *hep, struct urb *urb, | ||
2093 | struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, | ||
2094 | u8 usb_endp, u8 address) | ||
2095 | { | ||
2096 | urb->hcpriv = u132; | ||
2097 | if (endp->queue_size++ < ENDP_QUEUE_SIZE) { | ||
2098 | endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; | ||
2099 | } else { | ||
2100 | struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq), | ||
2101 | GFP_ATOMIC); | ||
2102 | if (urbq == NULL) { | ||
2103 | endp->queue_size -= 1; | ||
2104 | return -ENOMEM; | ||
2105 | } else { | ||
2106 | list_add_tail(&urbq->urb_more, &endp->urb_more); | ||
2107 | urbq->urb = urb; | ||
2108 | } | ||
2109 | } | ||
2110 | return 0; | ||
2111 | } | ||
2112 | |||
2113 | static int create_endpoint_and_queue_control(struct u132 *u132, | ||
2114 | struct usb_host_endpoint *hep, struct urb *urb, | ||
2115 | struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, | ||
2116 | gfp_t mem_flags) | ||
2117 | { | ||
2118 | struct u132_ring *ring; | ||
2119 | u8 endp_number = ++u132->num_endpoints; | ||
2120 | struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] = | ||
2121 | kmalloc(sizeof(struct u132_endp), mem_flags); | ||
2122 | if (!endp) { | ||
2123 | return -ENOMEM; | ||
2124 | } | ||
2125 | INIT_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler, (void *)endp); | ||
2126 | spin_lock_init(&endp->queue_lock.slock); | ||
2127 | INIT_LIST_HEAD(&endp->urb_more); | ||
2128 | ring = endp->ring = &u132->ring[0]; | ||
2129 | if (ring->curr_endp) { | ||
2130 | list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring); | ||
2131 | } else { | ||
2132 | INIT_LIST_HEAD(&endp->endp_ring); | ||
2133 | ring->curr_endp = endp; | ||
2134 | } | ||
2135 | ring->length += 1; | ||
2136 | endp->dequeueing = 0; | ||
2137 | endp->edset_flush = 0; | ||
2138 | endp->active = 0; | ||
2139 | endp->delayed = 0; | ||
2140 | endp->endp_number = endp_number; | ||
2141 | endp->u132 = u132; | ||
2142 | endp->hep = hep; | ||
2143 | u132_endp_init_kref(u132, endp); | ||
2144 | u132_endp_get_kref(u132, endp); | ||
2145 | if (usb_addr == 0) { | ||
2146 | unsigned long irqs; | ||
2147 | u8 address = u132->addr[usb_addr].address; | ||
2148 | struct u132_udev *udev = &u132->udev[address]; | ||
2149 | endp->udev_number = address; | ||
2150 | endp->usb_addr = usb_addr; | ||
2151 | endp->usb_endp = usb_endp; | ||
2152 | endp->input = 1; | ||
2153 | endp->output = 1; | ||
2154 | endp->pipetype = usb_pipetype(urb->pipe); | ||
2155 | u132_udev_init_kref(u132, udev); | ||
2156 | u132_udev_get_kref(u132, udev); | ||
2157 | udev->endp_number_in[usb_endp] = endp_number; | ||
2158 | udev->endp_number_out[usb_endp] = endp_number; | ||
2159 | urb->hcpriv = u132; | ||
2160 | spin_lock_irqsave(&endp->queue_lock.slock, irqs); | ||
2161 | endp->queue_size = 1; | ||
2162 | endp->queue_last = 0; | ||
2163 | endp->queue_next = 0; | ||
2164 | endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; | ||
2165 | spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); | ||
2166 | u132_endp_queue_work(u132, endp, 0); | ||
2167 | return 0; | ||
2168 | } else { /*(usb_addr > 0) */ | ||
2169 | unsigned long irqs; | ||
2170 | u8 address = u132->addr[usb_addr].address; | ||
2171 | struct u132_udev *udev = &u132->udev[address]; | ||
2172 | endp->udev_number = address; | ||
2173 | endp->usb_addr = usb_addr; | ||
2174 | endp->usb_endp = usb_endp; | ||
2175 | endp->input = 1; | ||
2176 | endp->output = 1; | ||
2177 | endp->pipetype = usb_pipetype(urb->pipe); | ||
2178 | u132_udev_get_kref(u132, udev); | ||
2179 | udev->enumeration = 2; | ||
2180 | udev->endp_number_in[usb_endp] = endp_number; | ||
2181 | udev->endp_number_out[usb_endp] = endp_number; | ||
2182 | urb->hcpriv = u132; | ||
2183 | spin_lock_irqsave(&endp->queue_lock.slock, irqs); | ||
2184 | endp->queue_size = 1; | ||
2185 | endp->queue_last = 0; | ||
2186 | endp->queue_next = 0; | ||
2187 | endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; | ||
2188 | spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); | ||
2189 | u132_endp_queue_work(u132, endp, 0); | ||
2190 | return 0; | ||
2191 | } | ||
2192 | } | ||
2193 | |||
2194 | static int queue_control_on_old_endpoint(struct u132 *u132, | ||
2195 | struct usb_host_endpoint *hep, struct urb *urb, | ||
2196 | struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, | ||
2197 | u8 usb_endp) | ||
2198 | { | ||
2199 | if (usb_addr == 0) { | ||
2200 | if (usb_pipein(urb->pipe)) { | ||
2201 | urb->hcpriv = u132; | ||
2202 | if (endp->queue_size++ < ENDP_QUEUE_SIZE) { | ||
2203 | endp->urb_list[ENDP_QUEUE_MASK & | ||
2204 | endp->queue_last++] = urb; | ||
2205 | } else { | ||
2206 | struct u132_urbq *urbq = | ||
2207 | kmalloc(sizeof(struct u132_urbq), | ||
2208 | GFP_ATOMIC); | ||
2209 | if (urbq == NULL) { | ||
2210 | endp->queue_size -= 1; | ||
2211 | return -ENOMEM; | ||
2212 | } else { | ||
2213 | list_add_tail(&urbq->urb_more, | ||
2214 | &endp->urb_more); | ||
2215 | urbq->urb = urb; | ||
2216 | } | ||
2217 | } | ||
2218 | return 0; | ||
2219 | } else { /* usb_pipeout(urb->pipe) */ | ||
2220 | struct u132_addr *addr = &u132->addr[usb_dev->devnum]; | ||
2221 | int I = MAX_U132_UDEVS; | ||
2222 | int i = 0; | ||
2223 | while (--I > 0) { | ||
2224 | struct u132_udev *udev = &u132->udev[++i]; | ||
2225 | if (udev->usb_device) { | ||
2226 | continue; | ||
2227 | } else { | ||
2228 | udev->enumeration = 1; | ||
2229 | u132->addr[0].address = i; | ||
2230 | endp->udev_number = i; | ||
2231 | udev->udev_number = i; | ||
2232 | udev->usb_addr = usb_dev->devnum; | ||
2233 | u132_udev_init_kref(u132, udev); | ||
2234 | udev->endp_number_in[usb_endp] = | ||
2235 | endp->endp_number; | ||
2236 | u132_udev_get_kref(u132, udev); | ||
2237 | udev->endp_number_out[usb_endp] = | ||
2238 | endp->endp_number; | ||
2239 | udev->usb_device = usb_dev; | ||
2240 | ((u8 *) (urb->setup_packet))[2] = | ||
2241 | addr->address = i; | ||
2242 | u132_udev_get_kref(u132, udev); | ||
2243 | break; | ||
2244 | } | ||
2245 | } | ||
2246 | if (I == 0) { | ||
2247 | dev_err(&u132->platform_dev->dev, "run out of d" | ||
2248 | "evice space\n"); | ||
2249 | return -EINVAL; | ||
2250 | } | ||
2251 | urb->hcpriv = u132; | ||
2252 | if (endp->queue_size++ < ENDP_QUEUE_SIZE) { | ||
2253 | endp->urb_list[ENDP_QUEUE_MASK & | ||
2254 | endp->queue_last++] = urb; | ||
2255 | } else { | ||
2256 | struct u132_urbq *urbq = | ||
2257 | kmalloc(sizeof(struct u132_urbq), | ||
2258 | GFP_ATOMIC); | ||
2259 | if (urbq == NULL) { | ||
2260 | endp->queue_size -= 1; | ||
2261 | return -ENOMEM; | ||
2262 | } else { | ||
2263 | list_add_tail(&urbq->urb_more, | ||
2264 | &endp->urb_more); | ||
2265 | urbq->urb = urb; | ||
2266 | } | ||
2267 | } | ||
2268 | return 0; | ||
2269 | } | ||
2270 | } else { /*(usb_addr > 0) */ | ||
2271 | u8 address = u132->addr[usb_addr].address; | ||
2272 | struct u132_udev *udev = &u132->udev[address]; | ||
2273 | urb->hcpriv = u132; | ||
2274 | if (udev->enumeration == 2) { | ||
2275 | } else | ||
2276 | udev->enumeration = 2; | ||
2277 | if (endp->queue_size++ < ENDP_QUEUE_SIZE) { | ||
2278 | endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = | ||
2279 | urb; | ||
2280 | } else { | ||
2281 | struct u132_urbq *urbq = | ||
2282 | kmalloc(sizeof(struct u132_urbq), GFP_ATOMIC); | ||
2283 | if (urbq == NULL) { | ||
2284 | endp->queue_size -= 1; | ||
2285 | return -ENOMEM; | ||
2286 | } else { | ||
2287 | list_add_tail(&urbq->urb_more, &endp->urb_more); | ||
2288 | urbq->urb = urb; | ||
2289 | } | ||
2290 | } | ||
2291 | return 0; | ||
2292 | } | ||
2293 | } | ||
2294 | |||
2295 | static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep, | ||
2296 | struct urb *urb, gfp_t mem_flags) | ||
2297 | { | ||
2298 | struct u132 *u132 = hcd_to_u132(hcd); | ||
2299 | if (irqs_disabled()) { | ||
2300 | if (__GFP_WAIT & mem_flags) { | ||
2301 | printk(KERN_ERR "invalid context for function that migh" | ||
2302 | "t sleep\n"); | ||
2303 | return -EINVAL; | ||
2304 | } | ||
2305 | } | ||
2306 | if (u132->going > 1) { | ||
2307 | dev_err(&u132->platform_dev->dev, "device has been removed %d\n" | ||
2308 | , u132->going); | ||
2309 | return -ENODEV; | ||
2310 | } else if (u132->going > 0) { | ||
2311 | dev_err(&u132->platform_dev->dev, "device is being removed urb=" | ||
2312 | "%p status=%d\n", urb, urb->status); | ||
2313 | return -ESHUTDOWN; | ||
2314 | } else { | ||
2315 | u8 usb_addr = usb_pipedevice(urb->pipe); | ||
2316 | u8 usb_endp = usb_pipeendpoint(urb->pipe); | ||
2317 | struct usb_device *usb_dev = urb->dev; | ||
2318 | if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { | ||
2319 | u8 address = u132->addr[usb_addr].address; | ||
2320 | struct u132_udev *udev = &u132->udev[address]; | ||
2321 | struct u132_endp *endp = hep->hcpriv; | ||
2322 | urb->actual_length = 0; | ||
2323 | if (endp) { | ||
2324 | unsigned long irqs; | ||
2325 | int retval; | ||
2326 | spin_lock_irqsave(&endp->queue_lock.slock, | ||
2327 | irqs); | ||
2328 | retval = queue_int_on_old_endpoint(u132, udev, | ||
2329 | hep, urb, usb_dev, endp, usb_addr, | ||
2330 | usb_endp, address); | ||
2331 | spin_unlock_irqrestore(&endp->queue_lock.slock, | ||
2332 | irqs); | ||
2333 | if (retval) { | ||
2334 | return retval; | ||
2335 | } else { | ||
2336 | u132_endp_queue_work(u132, endp, | ||
2337 | msecs_to_jiffies(urb->interval)) | ||
2338 | ; | ||
2339 | return 0; | ||
2340 | } | ||
2341 | } else if (u132->num_endpoints == MAX_U132_ENDPS) { | ||
2342 | return -EINVAL; | ||
2343 | } else { /*(endp == NULL) */ | ||
2344 | return create_endpoint_and_queue_int(u132, udev, | ||
2345 | hep, urb, usb_dev, usb_addr, usb_endp, | ||
2346 | address, mem_flags); | ||
2347 | } | ||
2348 | } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { | ||
2349 | dev_err(&u132->platform_dev->dev, "the hardware does no" | ||
2350 | "t support PIPE_ISOCHRONOUS\n"); | ||
2351 | return -EINVAL; | ||
2352 | } else if (usb_pipetype(urb->pipe) == PIPE_BULK) { | ||
2353 | u8 address = u132->addr[usb_addr].address; | ||
2354 | struct u132_udev *udev = &u132->udev[address]; | ||
2355 | struct u132_endp *endp = hep->hcpriv; | ||
2356 | urb->actual_length = 0; | ||
2357 | if (endp) { | ||
2358 | unsigned long irqs; | ||
2359 | int retval; | ||
2360 | spin_lock_irqsave(&endp->queue_lock.slock, | ||
2361 | irqs); | ||
2362 | retval = queue_bulk_on_old_endpoint(u132, udev, | ||
2363 | hep, urb, usb_dev, endp, usb_addr, | ||
2364 | usb_endp, address); | ||
2365 | spin_unlock_irqrestore(&endp->queue_lock.slock, | ||
2366 | irqs); | ||
2367 | if (retval) { | ||
2368 | return retval; | ||
2369 | } else { | ||
2370 | u132_endp_queue_work(u132, endp, 0); | ||
2371 | return 0; | ||
2372 | } | ||
2373 | } else if (u132->num_endpoints == MAX_U132_ENDPS) { | ||
2374 | return -EINVAL; | ||
2375 | } else | ||
2376 | return create_endpoint_and_queue_bulk(u132, | ||
2377 | udev, hep, urb, usb_dev, usb_addr, | ||
2378 | usb_endp, address, mem_flags); | ||
2379 | } else { | ||
2380 | struct u132_endp *endp = hep->hcpriv; | ||
2381 | u16 urb_size = 8; | ||
2382 | u8 *b = urb->setup_packet; | ||
2383 | int i = 0; | ||
2384 | char data[30 *3 + 4]; | ||
2385 | char *d = data; | ||
2386 | int m = (sizeof(data) - 1) / 3; | ||
2387 | int l = 0; | ||
2388 | data[0] = 0; | ||
2389 | while (urb_size-- > 0) { | ||
2390 | if (i > m) { | ||
2391 | } else if (i++ < m) { | ||
2392 | int w = sprintf(d, " %02X", *b++); | ||
2393 | d += w; | ||
2394 | l += w; | ||
2395 | } else | ||
2396 | d += sprintf(d, " .."); | ||
2397 | } | ||
2398 | if (endp) { | ||
2399 | unsigned long irqs; | ||
2400 | int retval; | ||
2401 | spin_lock_irqsave(&endp->queue_lock.slock, | ||
2402 | irqs); | ||
2403 | retval = queue_control_on_old_endpoint(u132, | ||
2404 | hep, urb, usb_dev, endp, usb_addr, | ||
2405 | usb_endp); | ||
2406 | spin_unlock_irqrestore(&endp->queue_lock.slock, | ||
2407 | irqs); | ||
2408 | if (retval) { | ||
2409 | return retval; | ||
2410 | } else { | ||
2411 | u132_endp_queue_work(u132, endp, 0); | ||
2412 | return 0; | ||
2413 | } | ||
2414 | } else if (u132->num_endpoints == MAX_U132_ENDPS) { | ||
2415 | return -EINVAL; | ||
2416 | } else | ||
2417 | return create_endpoint_and_queue_control(u132, | ||
2418 | hep, urb, usb_dev, usb_addr, usb_endp, | ||
2419 | mem_flags); | ||
2420 | } | ||
2421 | } | ||
2422 | } | ||
2423 | |||
2424 | static int dequeue_from_overflow_chain(struct u132 *u132, | ||
2425 | struct u132_endp *endp, struct urb *urb) | ||
2426 | { | ||
2427 | struct list_head *scan; | ||
2428 | struct list_head *head = &endp->urb_more; | ||
2429 | list_for_each(scan, head) { | ||
2430 | struct u132_urbq *urbq = list_entry(scan, struct u132_urbq, | ||
2431 | urb_more); | ||
2432 | if (urbq->urb == urb) { | ||
2433 | struct usb_hcd *hcd = u132_to_hcd(u132); | ||
2434 | list_del(scan); | ||
2435 | endp->queue_size -= 1; | ||
2436 | urb->error_count = 0; | ||
2437 | urb->hcpriv = NULL; | ||
2438 | usb_hcd_giveback_urb(hcd, urb, NULL); | ||
2439 | return 0; | ||
2440 | } else | ||
2441 | continue; | ||
2442 | } | ||
2443 | dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]=%p ring" | ||
2444 | "[%d] %c%c usb_endp=%d usb_addr=%d size=%d next=%04X last=%04X" | ||
2445 | "\n", urb, endp->endp_number, endp, endp->ring->number, | ||
2446 | endp->input ? 'I' : ' ', endp->output ? 'O' : ' ', | ||
2447 | endp->usb_endp, endp->usb_addr, endp->queue_size, | ||
2448 | endp->queue_next, endp->queue_last); | ||
2449 | return -EINVAL; | ||
2450 | } | ||
2451 | |||
2452 | static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, | ||
2453 | struct urb *urb) | ||
2454 | { | ||
2455 | unsigned long irqs; | ||
2456 | spin_lock_irqsave(&endp->queue_lock.slock, irqs); | ||
2457 | if (endp->queue_size == 0) { | ||
2458 | dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]" | ||
2459 | "=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", urb, | ||
2460 | endp->endp_number, endp, endp->ring->number, | ||
2461 | endp->input ? 'I' : ' ', endp->output ? 'O' : ' ', | ||
2462 | endp->usb_endp, endp->usb_addr); | ||
2463 | spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); | ||
2464 | return -EINVAL; | ||
2465 | } | ||
2466 | if (urb == endp->urb_list[ENDP_QUEUE_MASK & endp->queue_next]) { | ||
2467 | if (endp->active) { | ||
2468 | endp->dequeueing = 1; | ||
2469 | endp->edset_flush = 1; | ||
2470 | u132_endp_queue_work(u132, endp, 0); | ||
2471 | spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); | ||
2472 | urb->hcpriv = NULL; | ||
2473 | return 0; | ||
2474 | } else { | ||
2475 | spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); | ||
2476 | u132_hcd_abandon_urb(u132, endp, urb, urb->status); | ||
2477 | return 0; | ||
2478 | } | ||
2479 | } else { | ||
2480 | u16 queue_list = 0; | ||
2481 | u16 queue_size = endp->queue_size; | ||
2482 | u16 queue_scan = endp->queue_next; | ||
2483 | struct urb **urb_slot = NULL; | ||
2484 | while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) { | ||
2485 | if (urb == endp->urb_list[ENDP_QUEUE_MASK & | ||
2486 | ++queue_scan]) { | ||
2487 | urb_slot = &endp->urb_list[ENDP_QUEUE_MASK & | ||
2488 | queue_scan]; | ||
2489 | break; | ||
2490 | } else | ||
2491 | continue; | ||
2492 | } | ||
2493 | while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) { | ||
2494 | *urb_slot = endp->urb_list[ENDP_QUEUE_MASK & | ||
2495 | ++queue_scan]; | ||
2496 | urb_slot = &endp->urb_list[ENDP_QUEUE_MASK & | ||
2497 | queue_scan]; | ||
2498 | } | ||
2499 | if (urb_slot) { | ||
2500 | struct usb_hcd *hcd = u132_to_hcd(u132); | ||
2501 | endp->queue_size -= 1; | ||
2502 | if (list_empty(&endp->urb_more)) { | ||
2503 | spin_unlock_irqrestore(&endp->queue_lock.slock, | ||
2504 | irqs); | ||
2505 | } else { | ||
2506 | struct list_head *next = endp->urb_more.next; | ||
2507 | struct u132_urbq *urbq = list_entry(next, | ||
2508 | struct u132_urbq, urb_more); | ||
2509 | list_del(next); | ||
2510 | *urb_slot = urbq->urb; | ||
2511 | spin_unlock_irqrestore(&endp->queue_lock.slock, | ||
2512 | irqs); | ||
2513 | kfree(urbq); | ||
2514 | } urb->error_count = 0; | ||
2515 | urb->hcpriv = NULL; | ||
2516 | usb_hcd_giveback_urb(hcd, urb, NULL); | ||
2517 | return 0; | ||
2518 | } else if (list_empty(&endp->urb_more)) { | ||
2519 | dev_err(&u132->platform_dev->dev, "urb=%p not found in " | ||
2520 | "endp[%d]=%p ring[%d] %c%c usb_endp=%d usb_addr" | ||
2521 | "=%d size=%d next=%04X last=%04X\n", urb, | ||
2522 | endp->endp_number, endp, endp->ring->number, | ||
2523 | endp->input ? 'I' : ' ', | ||
2524 | endp->output ? 'O' : ' ', endp->usb_endp, | ||
2525 | endp->usb_addr, endp->queue_size, | ||
2526 | endp->queue_next, endp->queue_last); | ||
2527 | spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); | ||
2528 | return -EINVAL; | ||
2529 | } else { | ||
2530 | int retval = dequeue_from_overflow_chain(u132, endp, | ||
2531 | urb); | ||
2532 | spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); | ||
2533 | return retval; | ||
2534 | } | ||
2535 | } | ||
2536 | } | ||
2537 | |||
2538 | static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) | ||
2539 | { | ||
2540 | struct u132 *u132 = hcd_to_u132(hcd); | ||
2541 | if (u132->going > 2) { | ||
2542 | dev_err(&u132->platform_dev->dev, "device has been removed %d\n" | ||
2543 | , u132->going); | ||
2544 | return -ENODEV; | ||
2545 | } else { | ||
2546 | u8 usb_addr = usb_pipedevice(urb->pipe); | ||
2547 | u8 usb_endp = usb_pipeendpoint(urb->pipe); | ||
2548 | u8 address = u132->addr[usb_addr].address; | ||
2549 | struct u132_udev *udev = &u132->udev[address]; | ||
2550 | if (usb_pipein(urb->pipe)) { | ||
2551 | u8 endp_number = udev->endp_number_in[usb_endp]; | ||
2552 | struct u132_endp *endp = u132->endp[endp_number - 1]; | ||
2553 | return u132_endp_urb_dequeue(u132, endp, urb); | ||
2554 | } else { | ||
2555 | u8 endp_number = udev->endp_number_out[usb_endp]; | ||
2556 | struct u132_endp *endp = u132->endp[endp_number - 1]; | ||
2557 | return u132_endp_urb_dequeue(u132, endp, urb); | ||
2558 | } | ||
2559 | } | ||
2560 | } | ||
2561 | |||
2562 | static void u132_endpoint_disable(struct usb_hcd *hcd, | ||
2563 | struct usb_host_endpoint *hep) | ||
2564 | { | ||
2565 | struct u132 *u132 = hcd_to_u132(hcd); | ||
2566 | if (u132->going > 2) { | ||
2567 | dev_err(&u132->platform_dev->dev, "device has been removed %d\n" | ||
2568 | , u132->going); | ||
2569 | } else { | ||
2570 | struct u132_endp *endp = hep->hcpriv; | ||
2571 | if (endp) | ||
2572 | u132_endp_put_kref(u132, endp); | ||
2573 | } | ||
2574 | } | ||
2575 | |||
2576 | static int u132_get_frame(struct usb_hcd *hcd) | ||
2577 | { | ||
2578 | struct u132 *u132 = hcd_to_u132(hcd); | ||
2579 | if (u132->going > 1) { | ||
2580 | dev_err(&u132->platform_dev->dev, "device has been removed %d\n" | ||
2581 | , u132->going); | ||
2582 | return -ENODEV; | ||
2583 | } else if (u132->going > 0) { | ||
2584 | dev_err(&u132->platform_dev->dev, "device is being removed\n"); | ||
2585 | return -ESHUTDOWN; | ||
2586 | } else { | ||
2587 | int frame = 0; | ||
2588 | dev_err(&u132->platform_dev->dev, "TODO: u132_get_frame\n"); | ||
2589 | msleep(100); | ||
2590 | return frame; | ||
2591 | } | ||
2592 | } | ||
2593 | |||
2594 | static int u132_roothub_descriptor(struct u132 *u132, | ||
2595 | struct usb_hub_descriptor *desc) | ||
2596 | { | ||
2597 | int retval; | ||
2598 | u16 temp; | ||
2599 | u32 rh_a = -1; | ||
2600 | u32 rh_b = -1; | ||
2601 | retval = u132_read_pcimem(u132, roothub.a, &rh_a); | ||
2602 | if (retval) | ||
2603 | return retval; | ||
2604 | desc->bDescriptorType = 0x29; | ||
2605 | desc->bPwrOn2PwrGood = (rh_a & RH_A_POTPGT) >> 24; | ||
2606 | desc->bHubContrCurrent = 0; | ||
2607 | desc->bNbrPorts = u132->num_ports; | ||
2608 | temp = 1 + (u132->num_ports / 8); | ||
2609 | desc->bDescLength = 7 + 2 *temp; | ||
2610 | temp = 0; | ||
2611 | if (rh_a & RH_A_NPS) | ||
2612 | temp |= 0x0002; | ||
2613 | if (rh_a & RH_A_PSM) | ||
2614 | temp |= 0x0001; | ||
2615 | if (rh_a & RH_A_NOCP) { | ||
2616 | temp |= 0x0010; | ||
2617 | } else if (rh_a & RH_A_OCPM) | ||
2618 | temp |= 0x0008; | ||
2619 | desc->wHubCharacteristics = cpu_to_le16(temp); | ||
2620 | retval = u132_read_pcimem(u132, roothub.b, &rh_b); | ||
2621 | if (retval) | ||
2622 | return retval; | ||
2623 | memset(desc->bitmap, 0xff, sizeof(desc->bitmap)); | ||
2624 | desc->bitmap[0] = rh_b & RH_B_DR; | ||
2625 | if (u132->num_ports > 7) { | ||
2626 | desc->bitmap[1] = (rh_b & RH_B_DR) >> 8; | ||
2627 | desc->bitmap[2] = 0xff; | ||
2628 | } else | ||
2629 | desc->bitmap[1] = 0xff; | ||
2630 | return 0; | ||
2631 | } | ||
2632 | |||
2633 | static int u132_roothub_status(struct u132 *u132, __le32 *desc) | ||
2634 | { | ||
2635 | u32 rh_status = -1; | ||
2636 | int ret_status = u132_read_pcimem(u132, roothub.status, &rh_status); | ||
2637 | *desc = cpu_to_le32(rh_status); | ||
2638 | return ret_status; | ||
2639 | } | ||
2640 | |||
2641 | static int u132_roothub_portstatus(struct u132 *u132, __le32 *desc, u16 wIndex) | ||
2642 | { | ||
2643 | if (wIndex == 0 || wIndex > u132->num_ports) { | ||
2644 | return -EINVAL; | ||
2645 | } else { | ||
2646 | int port = wIndex - 1; | ||
2647 | u32 rh_portstatus = -1; | ||
2648 | int ret_portstatus = u132_read_pcimem(u132, | ||
2649 | roothub.portstatus[port], &rh_portstatus); | ||
2650 | *desc = cpu_to_le32(rh_portstatus); | ||
2651 | if (*(u16 *) (desc + 2)) { | ||
2652 | dev_info(&u132->platform_dev->dev, "Port %d Status Chan" | ||
2653 | "ge = %08X\n", port, *desc); | ||
2654 | } | ||
2655 | return ret_portstatus; | ||
2656 | } | ||
2657 | } | ||
2658 | |||
2659 | |||
2660 | /* this timer value might be vendor-specific ... */ | ||
2661 | #define PORT_RESET_HW_MSEC 10 | ||
2662 | #define PORT_RESET_MSEC 10 | ||
2663 | /* wrap-aware logic morphed from <linux/jiffies.h> */ | ||
2664 | #define tick_before(t1, t2) ((s16)(((s16)(t1))-((s16)(t2))) < 0) | ||
2665 | static int u132_roothub_portreset(struct u132 *u132, int port_index) | ||
2666 | { | ||
2667 | int retval; | ||
2668 | u32 fmnumber; | ||
2669 | u16 now; | ||
2670 | u16 reset_done; | ||
2671 | retval = u132_read_pcimem(u132, fmnumber, &fmnumber); | ||
2672 | if (retval) | ||
2673 | return retval; | ||
2674 | now = fmnumber; | ||
2675 | reset_done = now + PORT_RESET_MSEC; | ||
2676 | do { | ||
2677 | u32 portstat; | ||
2678 | do { | ||
2679 | retval = u132_read_pcimem(u132, | ||
2680 | roothub.portstatus[port_index], &portstat); | ||
2681 | if (retval) | ||
2682 | return retval; | ||
2683 | if (RH_PS_PRS & portstat) { | ||
2684 | continue; | ||
2685 | } else | ||
2686 | break; | ||
2687 | } while (tick_before(now, reset_done)); | ||
2688 | if (RH_PS_PRS & portstat) | ||
2689 | return -ENODEV; | ||
2690 | if (RH_PS_CCS & portstat) { | ||
2691 | if (RH_PS_PRSC & portstat) { | ||
2692 | retval = u132_write_pcimem(u132, | ||
2693 | roothub.portstatus[port_index], | ||
2694 | RH_PS_PRSC); | ||
2695 | if (retval) | ||
2696 | return retval; | ||
2697 | } | ||
2698 | } else | ||
2699 | break; /* start the next reset, | ||
2700 | sleep till it's probably done */ | ||
2701 | retval = u132_write_pcimem(u132, roothub.portstatus[port_index], | ||
2702 | RH_PS_PRS); | ||
2703 | if (retval) | ||
2704 | return retval; | ||
2705 | msleep(PORT_RESET_HW_MSEC); | ||
2706 | retval = u132_read_pcimem(u132, fmnumber, &fmnumber); | ||
2707 | if (retval) | ||
2708 | return retval; | ||
2709 | now = fmnumber; | ||
2710 | } while (tick_before(now, reset_done)); | ||
2711 | return 0; | ||
2712 | } | ||
2713 | |||
2714 | static int u132_roothub_setportfeature(struct u132 *u132, u16 wValue, | ||
2715 | u16 wIndex) | ||
2716 | { | ||
2717 | if (wIndex == 0 || wIndex > u132->num_ports) { | ||
2718 | return -EINVAL; | ||
2719 | } else { | ||
2720 | int retval; | ||
2721 | int port_index = wIndex - 1; | ||
2722 | struct u132_port *port = &u132->port[port_index]; | ||
2723 | port->Status &= ~(1 << wValue); | ||
2724 | switch (wValue) { | ||
2725 | case USB_PORT_FEAT_SUSPEND: | ||
2726 | retval = u132_write_pcimem(u132, | ||
2727 | roothub.portstatus[port_index], RH_PS_PSS); | ||
2728 | if (retval) | ||
2729 | return retval; | ||
2730 | return 0; | ||
2731 | case USB_PORT_FEAT_POWER: | ||
2732 | retval = u132_write_pcimem(u132, | ||
2733 | roothub.portstatus[port_index], RH_PS_PPS); | ||
2734 | if (retval) | ||
2735 | return retval; | ||
2736 | return 0; | ||
2737 | case USB_PORT_FEAT_RESET: | ||
2738 | retval = u132_roothub_portreset(u132, port_index); | ||
2739 | if (retval) | ||
2740 | return retval; | ||
2741 | return 0; | ||
2742 | default: | ||
2743 | return -EPIPE; | ||
2744 | } | ||
2745 | } | ||
2746 | } | ||
2747 | |||
2748 | static int u132_roothub_clearportfeature(struct u132 *u132, u16 wValue, | ||
2749 | u16 wIndex) | ||
2750 | { | ||
2751 | if (wIndex == 0 || wIndex > u132->num_ports) { | ||
2752 | return -EINVAL; | ||
2753 | } else { | ||
2754 | int port_index = wIndex - 1; | ||
2755 | u32 temp; | ||
2756 | int retval; | ||
2757 | struct u132_port *port = &u132->port[port_index]; | ||
2758 | port->Status &= ~(1 << wValue); | ||
2759 | switch (wValue) { | ||
2760 | case USB_PORT_FEAT_ENABLE: | ||
2761 | temp = RH_PS_CCS; | ||
2762 | break; | ||
2763 | case USB_PORT_FEAT_C_ENABLE: | ||
2764 | temp = RH_PS_PESC; | ||
2765 | break; | ||
2766 | case USB_PORT_FEAT_SUSPEND: | ||
2767 | temp = RH_PS_POCI; | ||
2768 | if ((u132->hc_control & OHCI_CTRL_HCFS) | ||
2769 | != OHCI_USB_OPER) { | ||
2770 | dev_err(&u132->platform_dev->dev, "TODO resume_" | ||
2771 | "root_hub\n"); | ||
2772 | } | ||
2773 | break; | ||
2774 | case USB_PORT_FEAT_C_SUSPEND: | ||
2775 | temp = RH_PS_PSSC; | ||
2776 | break; | ||
2777 | case USB_PORT_FEAT_POWER: | ||
2778 | temp = RH_PS_LSDA; | ||
2779 | break; | ||
2780 | case USB_PORT_FEAT_C_CONNECTION: | ||
2781 | temp = RH_PS_CSC; | ||
2782 | break; | ||
2783 | case USB_PORT_FEAT_C_OVER_CURRENT: | ||
2784 | temp = RH_PS_OCIC; | ||
2785 | break; | ||
2786 | case USB_PORT_FEAT_C_RESET: | ||
2787 | temp = RH_PS_PRSC; | ||
2788 | break; | ||
2789 | default: | ||
2790 | return -EPIPE; | ||
2791 | } | ||
2792 | retval = u132_write_pcimem(u132, roothub.portstatus[port_index], | ||
2793 | temp); | ||
2794 | if (retval) | ||
2795 | return retval; | ||
2796 | return 0; | ||
2797 | } | ||
2798 | } | ||
2799 | |||
2800 | |||
2801 | /* the virtual root hub timer IRQ checks for hub status*/ | ||
2802 | static int u132_hub_status_data(struct usb_hcd *hcd, char *buf) | ||
2803 | { | ||
2804 | struct u132 *u132 = hcd_to_u132(hcd); | ||
2805 | if (u132->going > 1) { | ||
2806 | dev_err(&u132->platform_dev->dev, "device hcd=%p has been remov" | ||
2807 | "ed %d\n", hcd, u132->going); | ||
2808 | return -ENODEV; | ||
2809 | } else if (u132->going > 0) { | ||
2810 | dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov" | ||
2811 | "ed\n", hcd); | ||
2812 | dump_stack(); | ||
2813 | return -ESHUTDOWN; | ||
2814 | } else { | ||
2815 | int i, changed = 0, length = 1; | ||
2816 | if (u132->flags & OHCI_QUIRK_AMD756) { | ||
2817 | if ((u132->hc_roothub_a & RH_A_NDP) > MAX_ROOT_PORTS) { | ||
2818 | dev_err(&u132->platform_dev->dev, "bogus NDP, r" | ||
2819 | "ereads as NDP=%d\n", | ||
2820 | u132->hc_roothub_a & RH_A_NDP); | ||
2821 | goto done; | ||
2822 | } | ||
2823 | } | ||
2824 | if (u132->hc_roothub_status & (RH_HS_LPSC | RH_HS_OCIC)) { | ||
2825 | buf[0] = changed = 1; | ||
2826 | } else | ||
2827 | buf[0] = 0; | ||
2828 | if (u132->num_ports > 7) { | ||
2829 | buf[1] = 0; | ||
2830 | length++; | ||
2831 | } | ||
2832 | for (i = 0; i < u132->num_ports; i++) { | ||
2833 | if (u132->hc_roothub_portstatus[i] & (RH_PS_CSC | | ||
2834 | RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC | | ||
2835 | RH_PS_PRSC)) { | ||
2836 | changed = 1; | ||
2837 | if (i < 7) { | ||
2838 | buf[0] |= 1 << (i + 1); | ||
2839 | } else | ||
2840 | buf[1] |= 1 << (i - 7); | ||
2841 | continue; | ||
2842 | } | ||
2843 | if (!(u132->hc_roothub_portstatus[i] & RH_PS_CCS)) { | ||
2844 | continue; | ||
2845 | } | ||
2846 | if ((u132->hc_roothub_portstatus[i] & RH_PS_PSS)) { | ||
2847 | continue; | ||
2848 | } | ||
2849 | } | ||
2850 | done:return changed ? length : 0; | ||
2851 | } | ||
2852 | } | ||
2853 | |||
2854 | static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | ||
2855 | u16 wIndex, char *buf, u16 wLength) | ||
2856 | { | ||
2857 | struct u132 *u132 = hcd_to_u132(hcd); | ||
2858 | if (u132->going > 1) { | ||
2859 | dev_err(&u132->platform_dev->dev, "device has been removed %d\n" | ||
2860 | , u132->going); | ||
2861 | return -ENODEV; | ||
2862 | } else if (u132->going > 0) { | ||
2863 | dev_err(&u132->platform_dev->dev, "device is being removed\n"); | ||
2864 | return -ESHUTDOWN; | ||
2865 | } else { | ||
2866 | int retval = 0; | ||
2867 | down(&u132->sw_lock); | ||
2868 | switch (typeReq) { | ||
2869 | case ClearHubFeature: | ||
2870 | switch (wValue) { | ||
2871 | case C_HUB_OVER_CURRENT: | ||
2872 | case C_HUB_LOCAL_POWER: | ||
2873 | break; | ||
2874 | default: | ||
2875 | goto stall; | ||
2876 | } | ||
2877 | break; | ||
2878 | case SetHubFeature: | ||
2879 | switch (wValue) { | ||
2880 | case C_HUB_OVER_CURRENT: | ||
2881 | case C_HUB_LOCAL_POWER: | ||
2882 | break; | ||
2883 | default: | ||
2884 | goto stall; | ||
2885 | } | ||
2886 | break; | ||
2887 | case ClearPortFeature:{ | ||
2888 | retval = u132_roothub_clearportfeature(u132, | ||
2889 | wValue, wIndex); | ||
2890 | if (retval) | ||
2891 | goto error; | ||
2892 | break; | ||
2893 | } | ||
2894 | case GetHubDescriptor:{ | ||
2895 | retval = u132_roothub_descriptor(u132, | ||
2896 | (struct usb_hub_descriptor *)buf); | ||
2897 | if (retval) | ||
2898 | goto error; | ||
2899 | break; | ||
2900 | } | ||
2901 | case GetHubStatus:{ | ||
2902 | retval = u132_roothub_status(u132, | ||
2903 | (__le32 *) buf); | ||
2904 | if (retval) | ||
2905 | goto error; | ||
2906 | break; | ||
2907 | } | ||
2908 | case GetPortStatus:{ | ||
2909 | retval = u132_roothub_portstatus(u132, | ||
2910 | (__le32 *) buf, wIndex); | ||
2911 | if (retval) | ||
2912 | goto error; | ||
2913 | break; | ||
2914 | } | ||
2915 | case SetPortFeature:{ | ||
2916 | retval = u132_roothub_setportfeature(u132, | ||
2917 | wValue, wIndex); | ||
2918 | if (retval) | ||
2919 | goto error; | ||
2920 | break; | ||
2921 | } | ||
2922 | default: | ||
2923 | goto stall; | ||
2924 | error:u132_disable(u132); | ||
2925 | u132->going = 1; | ||
2926 | break; | ||
2927 | stall:retval = -EPIPE; | ||
2928 | break; | ||
2929 | } | ||
2930 | up(&u132->sw_lock); | ||
2931 | return retval; | ||
2932 | } | ||
2933 | } | ||
2934 | |||
2935 | static int u132_start_port_reset(struct usb_hcd *hcd, unsigned port_num) | ||
2936 | { | ||
2937 | struct u132 *u132 = hcd_to_u132(hcd); | ||
2938 | if (u132->going > 1) { | ||
2939 | dev_err(&u132->platform_dev->dev, "device has been removed %d\n" | ||
2940 | , u132->going); | ||
2941 | return -ENODEV; | ||
2942 | } else if (u132->going > 0) { | ||
2943 | dev_err(&u132->platform_dev->dev, "device is being removed\n"); | ||
2944 | return -ESHUTDOWN; | ||
2945 | } else | ||
2946 | return 0; | ||
2947 | } | ||
2948 | |||
2949 | static void u132_hub_irq_enable(struct usb_hcd *hcd) | ||
2950 | { | ||
2951 | struct u132 *u132 = hcd_to_u132(hcd); | ||
2952 | if (u132->going > 1) { | ||
2953 | dev_err(&u132->platform_dev->dev, "device has been removed %d\n" | ||
2954 | , u132->going); | ||
2955 | } else if (u132->going > 0) | ||
2956 | dev_err(&u132->platform_dev->dev, "device is being removed\n"); | ||
2957 | } | ||
2958 | |||
2959 | |||
2960 | #ifdef CONFIG_PM | ||
2961 | static int u132_hcd_suspend(struct usb_hcd *hcd, pm_message_t message) | ||
2962 | { | ||
2963 | struct u132 *u132 = hcd_to_u132(hcd); | ||
2964 | if (u132->going > 1) { | ||
2965 | dev_err(&u132->platform_dev->dev, "device has been removed %d\n" | ||
2966 | , u132->going); | ||
2967 | return -ENODEV; | ||
2968 | } else if (u132->going > 0) { | ||
2969 | dev_err(&u132->platform_dev->dev, "device is being removed\n"); | ||
2970 | return -ESHUTDOWN; | ||
2971 | } else | ||
2972 | return 0; | ||
2973 | } | ||
2974 | |||
2975 | static int u132_hcd_resume(struct usb_hcd *hcd) | ||
2976 | { | ||
2977 | struct u132 *u132 = hcd_to_u132(hcd); | ||
2978 | if (u132->going > 1) { | ||
2979 | dev_err(&u132->platform_dev->dev, "device has been removed %d\n" | ||
2980 | , u132->going); | ||
2981 | return -ENODEV; | ||
2982 | } else if (u132->going > 0) { | ||
2983 | dev_err(&u132->platform_dev->dev, "device is being removed\n"); | ||
2984 | return -ESHUTDOWN; | ||
2985 | } else | ||
2986 | return 0; | ||
2987 | } | ||
2988 | |||
2989 | static int u132_bus_suspend(struct usb_hcd *hcd) | ||
2990 | { | ||
2991 | struct u132 *u132 = hcd_to_u132(hcd); | ||
2992 | if (u132->going > 1) { | ||
2993 | dev_err(&u132->platform_dev->dev, "device has been removed %d\n" | ||
2994 | , u132->going); | ||
2995 | return -ENODEV; | ||
2996 | } else if (u132->going > 0) { | ||
2997 | dev_err(&u132->platform_dev->dev, "device is being removed\n"); | ||
2998 | return -ESHUTDOWN; | ||
2999 | } else | ||
3000 | return 0; | ||
3001 | } | ||
3002 | |||
3003 | static int u132_bus_resume(struct usb_hcd *hcd) | ||
3004 | { | ||
3005 | struct u132 *u132 = hcd_to_u132(hcd); | ||
3006 | if (u132->going > 1) { | ||
3007 | dev_err(&u132->platform_dev->dev, "device has been removed %d\n" | ||
3008 | , u132->going); | ||
3009 | return -ENODEV; | ||
3010 | } else if (u132->going > 0) { | ||
3011 | dev_err(&u132->platform_dev->dev, "device is being removed\n"); | ||
3012 | return -ESHUTDOWN; | ||
3013 | } else | ||
3014 | return 0; | ||
3015 | } | ||
3016 | |||
3017 | #else | ||
3018 | #define u132_hcd_suspend NULL | ||
3019 | #define u132_hcd_resume NULL | ||
3020 | #define u132_bus_suspend NULL | ||
3021 | #define u132_bus_resume NULL | ||
3022 | #endif | ||
3023 | static struct hc_driver u132_hc_driver = { | ||
3024 | .description = hcd_name, | ||
3025 | .hcd_priv_size = sizeof(struct u132), | ||
3026 | .irq = NULL, | ||
3027 | .flags = HCD_USB11 | HCD_MEMORY, | ||
3028 | .reset = u132_hcd_reset, | ||
3029 | .start = u132_hcd_start, | ||
3030 | .suspend = u132_hcd_suspend, | ||
3031 | .resume = u132_hcd_resume, | ||
3032 | .stop = u132_hcd_stop, | ||
3033 | .urb_enqueue = u132_urb_enqueue, | ||
3034 | .urb_dequeue = u132_urb_dequeue, | ||
3035 | .endpoint_disable = u132_endpoint_disable, | ||
3036 | .get_frame_number = u132_get_frame, | ||
3037 | .hub_status_data = u132_hub_status_data, | ||
3038 | .hub_control = u132_hub_control, | ||
3039 | .bus_suspend = u132_bus_suspend, | ||
3040 | .bus_resume = u132_bus_resume, | ||
3041 | .start_port_reset = u132_start_port_reset, | ||
3042 | .hub_irq_enable = u132_hub_irq_enable, | ||
3043 | }; | ||
3044 | |||
3045 | /* | ||
3046 | * This function may be called by the USB core whilst the "usb_all_devices_rwsem" | ||
3047 | * is held for writing, thus this module must not call usb_remove_hcd() | ||
3048 | * synchronously - but instead should immediately stop activity to the | ||
3049 | * device and ansynchronously call usb_remove_hcd() | ||
3050 | */ | ||
3051 | static int __devexit u132_remove(struct platform_device *pdev) | ||
3052 | { | ||
3053 | struct usb_hcd *hcd = platform_get_drvdata(pdev); | ||
3054 | if (hcd) { | ||
3055 | struct u132 *u132 = hcd_to_u132(hcd); | ||
3056 | dump_stack(); | ||
3057 | if (u132->going++ > 1) { | ||
3058 | return -ENODEV; | ||
3059 | } else { | ||
3060 | int rings = MAX_U132_RINGS; | ||
3061 | int endps = MAX_U132_ENDPS; | ||
3062 | msleep(100); | ||
3063 | down(&u132->sw_lock); | ||
3064 | u132_monitor_cancel_work(u132); | ||
3065 | while (rings-- > 0) { | ||
3066 | struct u132_ring *ring = &u132->ring[rings]; | ||
3067 | u132_ring_cancel_work(u132, ring); | ||
3068 | } while (endps-- > 0) { | ||
3069 | struct u132_endp *endp = u132->endp[endps]; | ||
3070 | if (endp) | ||
3071 | u132_endp_cancel_work(u132, endp); | ||
3072 | } | ||
3073 | u132->going += 1; | ||
3074 | printk(KERN_INFO "removing device u132.%d\n", | ||
3075 | u132->sequence_num); | ||
3076 | up(&u132->sw_lock); | ||
3077 | usb_remove_hcd(hcd); | ||
3078 | u132_u132_put_kref(u132); | ||
3079 | return 0; | ||
3080 | } | ||
3081 | } else | ||
3082 | return 0; | ||
3083 | } | ||
3084 | |||
3085 | static void u132_initialise(struct u132 *u132, struct platform_device *pdev) | ||
3086 | { | ||
3087 | int rings = MAX_U132_RINGS; | ||
3088 | int ports = MAX_U132_PORTS; | ||
3089 | int addrs = MAX_U132_ADDRS; | ||
3090 | int udevs = MAX_U132_UDEVS; | ||
3091 | int endps = MAX_U132_ENDPS; | ||
3092 | u132->board = pdev->dev.platform_data; | ||
3093 | u132->platform_dev = pdev; | ||
3094 | u132->power = 0; | ||
3095 | u132->reset = 0; | ||
3096 | init_MUTEX(&u132->sw_lock); | ||
3097 | init_MUTEX(&u132->scheduler_lock); | ||
3098 | while (rings-- > 0) { | ||
3099 | struct u132_ring *ring = &u132->ring[rings]; | ||
3100 | ring->u132 = u132; | ||
3101 | ring->number = rings + 1; | ||
3102 | ring->length = 0; | ||
3103 | ring->curr_endp = NULL; | ||
3104 | INIT_WORK(&ring->scheduler, u132_hcd_ring_work_scheduler, | ||
3105 | (void *)ring); | ||
3106 | } down(&u132->sw_lock); | ||
3107 | INIT_WORK(&u132->monitor, u132_hcd_monitor_work, (void *)u132); | ||
3108 | while (ports-- > 0) { | ||
3109 | struct u132_port *port = &u132->port[ports]; | ||
3110 | port->u132 = u132; | ||
3111 | port->reset = 0; | ||
3112 | port->enable = 0; | ||
3113 | port->power = 0; | ||
3114 | port->Status = 0; | ||
3115 | } while (addrs-- > 0) { | ||
3116 | struct u132_addr *addr = &u132->addr[addrs]; | ||
3117 | addr->address = 0; | ||
3118 | } while (udevs-- > 0) { | ||
3119 | struct u132_udev *udev = &u132->udev[udevs]; | ||
3120 | int i = ARRAY_SIZE(udev->endp_number_in); | ||
3121 | int o = ARRAY_SIZE(udev->endp_number_out); | ||
3122 | udev->usb_device = NULL; | ||
3123 | udev->udev_number = 0; | ||
3124 | udev->usb_addr = 0; | ||
3125 | udev->portnumber = 0; | ||
3126 | while (i-- > 0) { | ||
3127 | udev->endp_number_in[i] = 0; | ||
3128 | } | ||
3129 | while (o-- > 0) { | ||
3130 | udev->endp_number_out[o] = 0; | ||
3131 | } | ||
3132 | } | ||
3133 | while (endps-- > 0) { | ||
3134 | u132->endp[endps] = NULL; | ||
3135 | } | ||
3136 | up(&u132->sw_lock); | ||
3137 | return; | ||
3138 | } | ||
3139 | |||
3140 | static int __devinit u132_probe(struct platform_device *pdev) | ||
3141 | { | ||
3142 | struct usb_hcd *hcd; | ||
3143 | msleep(100); | ||
3144 | if (u132_exiting > 0) { | ||
3145 | return -ENODEV; | ||
3146 | } /* refuse to confuse usbcore */ | ||
3147 | if (pdev->dev.dma_mask) { | ||
3148 | return -EINVAL; | ||
3149 | } | ||
3150 | hcd = usb_create_hcd(&u132_hc_driver, &pdev->dev, pdev->dev.bus_id); | ||
3151 | if (!hcd) { | ||
3152 | printk(KERN_ERR "failed to create the usb hcd struct for U132\n" | ||
3153 | ); | ||
3154 | ftdi_elan_gone_away(pdev); | ||
3155 | return -ENOMEM; | ||
3156 | } else { | ||
3157 | int retval = 0; | ||
3158 | struct u132 *u132 = hcd_to_u132(hcd); | ||
3159 | hcd->rsrc_start = 0; | ||
3160 | down(&u132_module_lock); | ||
3161 | list_add_tail(&u132->u132_list, &u132_static_list); | ||
3162 | u132->sequence_num = ++u132_instances; | ||
3163 | up(&u132_module_lock); | ||
3164 | u132_u132_init_kref(u132); | ||
3165 | u132_initialise(u132, pdev); | ||
3166 | hcd->product_desc = "ELAN U132 Host Controller"; | ||
3167 | retval = usb_add_hcd(hcd, 0, 0); | ||
3168 | if (retval != 0) { | ||
3169 | dev_err(&u132->platform_dev->dev, "init error %d\n", | ||
3170 | retval); | ||
3171 | u132_u132_put_kref(u132); | ||
3172 | return retval; | ||
3173 | } else { | ||
3174 | u132_monitor_queue_work(u132, 100); | ||
3175 | return 0; | ||
3176 | } | ||
3177 | } | ||
3178 | } | ||
3179 | |||
3180 | |||
3181 | #ifdef CONFIG_PM | ||
3182 | /* for this device there's no useful distinction between the controller | ||
3183 | * and its root hub, except that the root hub only gets direct PM calls | ||
3184 | * when CONFIG_USB_SUSPEND is enabled. | ||
3185 | */ | ||
3186 | static int u132_suspend(struct platform_device *pdev, pm_message_t state) | ||
3187 | { | ||
3188 | struct usb_hcd *hcd = platform_get_drvdata(pdev); | ||
3189 | struct u132 *u132 = hcd_to_u132(hcd); | ||
3190 | if (u132->going > 1) { | ||
3191 | dev_err(&u132->platform_dev->dev, "device has been removed %d\n" | ||
3192 | , u132->going); | ||
3193 | return -ENODEV; | ||
3194 | } else if (u132->going > 0) { | ||
3195 | dev_err(&u132->platform_dev->dev, "device is being removed\n"); | ||
3196 | return -ESHUTDOWN; | ||
3197 | } else { | ||
3198 | int retval = 0; | ||
3199 | if (state.event == PM_EVENT_FREEZE) { | ||
3200 | retval = u132_bus_suspend(hcd); | ||
3201 | } else if (state.event == PM_EVENT_SUSPEND) { | ||
3202 | int ports = MAX_U132_PORTS; | ||
3203 | while (ports-- > 0) { | ||
3204 | port_power(u132, ports, 0); | ||
3205 | } | ||
3206 | } | ||
3207 | if (retval == 0) | ||
3208 | pdev->dev.power.power_state = state; | ||
3209 | return retval; | ||
3210 | } | ||
3211 | } | ||
3212 | |||
3213 | static int u132_resume(struct platform_device *pdev) | ||
3214 | { | ||
3215 | struct usb_hcd *hcd = platform_get_drvdata(pdev); | ||
3216 | struct u132 *u132 = hcd_to_u132(hcd); | ||
3217 | if (u132->going > 1) { | ||
3218 | dev_err(&u132->platform_dev->dev, "device has been removed %d\n" | ||
3219 | , u132->going); | ||
3220 | return -ENODEV; | ||
3221 | } else if (u132->going > 0) { | ||
3222 | dev_err(&u132->platform_dev->dev, "device is being removed\n"); | ||
3223 | return -ESHUTDOWN; | ||
3224 | } else { | ||
3225 | int retval = 0; | ||
3226 | if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { | ||
3227 | int ports = MAX_U132_PORTS; | ||
3228 | while (ports-- > 0) { | ||
3229 | port_power(u132, ports, 1); | ||
3230 | } | ||
3231 | retval = 0; | ||
3232 | } else { | ||
3233 | pdev->dev.power.power_state = PMSG_ON; | ||
3234 | retval = u132_bus_resume(hcd); | ||
3235 | } | ||
3236 | return retval; | ||
3237 | } | ||
3238 | } | ||
3239 | |||
3240 | #else | ||
3241 | #define u132_suspend NULL | ||
3242 | #define u132_resume NULL | ||
3243 | #endif | ||
3244 | /* | ||
3245 | * this driver is loaded explicitely by ftdi_u132 | ||
3246 | * | ||
3247 | * the platform_driver struct is static because it is per type of module | ||
3248 | */ | ||
3249 | static struct platform_driver u132_platform_driver = { | ||
3250 | .probe = u132_probe, | ||
3251 | .remove = __devexit_p(u132_remove), | ||
3252 | .suspend = u132_suspend, | ||
3253 | .resume = u132_resume, | ||
3254 | .driver = { | ||
3255 | .name = (char *)hcd_name, | ||
3256 | .owner = THIS_MODULE, | ||
3257 | }, | ||
3258 | }; | ||
3259 | static int __init u132_hcd_init(void) | ||
3260 | { | ||
3261 | int retval; | ||
3262 | INIT_LIST_HEAD(&u132_static_list); | ||
3263 | u132_instances = 0; | ||
3264 | u132_exiting = 0; | ||
3265 | init_MUTEX(&u132_module_lock); | ||
3266 | if (usb_disabled()) | ||
3267 | return -ENODEV; | ||
3268 | printk(KERN_INFO "driver %s built at %s on %s\n", hcd_name, __TIME__, | ||
3269 | __DATE__); | ||
3270 | workqueue = create_singlethread_workqueue("u132"); | ||
3271 | retval = platform_driver_register(&u132_platform_driver); | ||
3272 | return retval; | ||
3273 | } | ||
3274 | |||
3275 | |||
3276 | module_init(u132_hcd_init); | ||
3277 | static void __exit u132_hcd_exit(void) | ||
3278 | { | ||
3279 | struct u132 *u132; | ||
3280 | struct u132 *temp; | ||
3281 | down(&u132_module_lock); | ||
3282 | u132_exiting += 1; | ||
3283 | up(&u132_module_lock); | ||
3284 | list_for_each_entry_safe(u132, temp, &u132_static_list, u132_list) { | ||
3285 | platform_device_unregister(u132->platform_dev); | ||
3286 | } platform_driver_unregister(&u132_platform_driver); | ||
3287 | printk(KERN_INFO "u132-hcd driver deregistered\n"); | ||
3288 | wait_event(u132_hcd_wait, u132_instances == 0); | ||
3289 | flush_workqueue(workqueue); | ||
3290 | destroy_workqueue(workqueue); | ||
3291 | } | ||
3292 | |||
3293 | |||
3294 | module_exit(u132_hcd_exit); | ||
3295 | MODULE_LICENSE("GPL"); | ||