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