blob: 692ccc69345e4a9998246a53b6af817a56a5d435 [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>
Eric Lescouet27729aa2010-04-24 23:21:52 +020052#include <linux/usb/hcd.h>
Tony Olechd774efe2006-09-13 11:27:35 +010053#include <linux/workqueue.h>
54#include <linux/platform_device.h>
Matthias Kaehlcked2066eb2007-07-13 21:26:59 +020055#include <linux/mutex.h>
Tony Olechd774efe2006-09-13 11:27:35 +010056#include <asm/io.h>
57#include <asm/irq.h>
Tony Olechd774efe2006-09-13 11:27:35 +010058#include <asm/byteorder.h>
David Brownell47f84682007-04-29 10:21:14 -070059
60 /* FIXME ohci.h is ONLY for internal use by the OHCI driver.
61 * If you're going to try stuff like this, you need to split
62 * out shareable stuff (register declarations?) into its own
63 * file, maybe name <linux/usb/ohci.h>
64 */
65
Tony Olechd774efe2006-09-13 11:27:35 +010066#include "ohci.h"
67#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR
68#define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \
Daniel Walkerb40f8d32008-03-23 00:00:01 -070069 OHCI_INTR_WDH)
Tony Olechd774efe2006-09-13 11:27:35 +010070MODULE_AUTHOR("Tony Olech - Elan Digital Systems Limited");
71MODULE_DESCRIPTION("U132 USB Host Controller Driver");
72MODULE_LICENSE("GPL");
73#define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444)
74INT_MODULE_PARM(testing, 0);
75/* Some boards misreport power switching/overcurrent*/
Rusty Russell90ab5ee2012-01-13 09:32:20 +103076static bool distrust_firmware = 1;
Tony Olechd774efe2006-09-13 11:27:35 +010077module_param(distrust_firmware, bool, 0);
78MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurren"
Daniel Walkerb40f8d32008-03-23 00:00:01 -070079 "t setup");
Adrian Bunk27a3de42006-11-20 03:23:54 +010080static DECLARE_WAIT_QUEUE_HEAD(u132_hcd_wait);
Tony Olechd774efe2006-09-13 11:27:35 +010081/*
82* u132_module_lock exists to protect access to global variables
83*
84*/
Matthias Kaehlcked2066eb2007-07-13 21:26:59 +020085static struct mutex u132_module_lock;
Daniel Walkerb40f8d32008-03-23 00:00:01 -070086static int u132_exiting;
87static int u132_instances;
Tony Olechd774efe2006-09-13 11:27:35 +010088static struct list_head u132_static_list;
89/*
90* end of the global variables protected by u132_module_lock
91*/
92static struct workqueue_struct *workqueue;
93#define MAX_U132_PORTS 7
94#define MAX_U132_ADDRS 128
95#define MAX_U132_UDEVS 4
96#define MAX_U132_ENDPS 100
97#define MAX_U132_RINGS 4
98static const char *cc_to_text[16] = {
Daniel Walkerb40f8d32008-03-23 00:00:01 -070099 "No Error ",
100 "CRC Error ",
101 "Bit Stuff ",
102 "Data Togg ",
103 "Stall ",
104 "DevNotResp ",
105 "PIDCheck ",
106 "UnExpPID ",
107 "DataOver ",
108 "DataUnder ",
109 "(for hw) ",
110 "(for hw) ",
111 "BufferOver ",
112 "BuffUnder ",
113 "(for HCD) ",
114 "(for HCD) "
Tony Olechd774efe2006-09-13 11:27:35 +0100115};
116struct u132_port {
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700117 struct u132 *u132;
118 int reset;
119 int enable;
120 int power;
121 int Status;
Tony Olechd774efe2006-09-13 11:27:35 +0100122};
123struct u132_addr {
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700124 u8 address;
Tony Olechd774efe2006-09-13 11:27:35 +0100125};
126struct u132_udev {
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700127 struct kref kref;
128 struct usb_device *usb_device;
129 u8 enumeration;
130 u8 udev_number;
131 u8 usb_addr;
132 u8 portnumber;
133 u8 endp_number_in[16];
134 u8 endp_number_out[16];
Tony Olechd774efe2006-09-13 11:27:35 +0100135};
136#define ENDP_QUEUE_SHIFT 3
137#define ENDP_QUEUE_SIZE (1<<ENDP_QUEUE_SHIFT)
138#define ENDP_QUEUE_MASK (ENDP_QUEUE_SIZE-1)
139struct u132_urbq {
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700140 struct list_head urb_more;
141 struct urb *urb;
Tony Olechd774efe2006-09-13 11:27:35 +0100142};
143struct u132_spin {
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700144 spinlock_t slock;
Tony Olechd774efe2006-09-13 11:27:35 +0100145};
146struct u132_endp {
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700147 struct kref kref;
148 u8 udev_number;
149 u8 endp_number;
150 u8 usb_addr;
151 u8 usb_endp;
152 struct u132 *u132;
153 struct list_head endp_ring;
154 struct u132_ring *ring;
155 unsigned toggle_bits:2;
156 unsigned active:1;
157 unsigned delayed:1;
158 unsigned input:1;
159 unsigned output:1;
160 unsigned pipetype:2;
161 unsigned dequeueing:1;
162 unsigned edset_flush:1;
163 unsigned spare_bits:14;
164 unsigned long jiffies;
165 struct usb_host_endpoint *hep;
166 struct u132_spin queue_lock;
167 u16 queue_size;
168 u16 queue_last;
169 u16 queue_next;
170 struct urb *urb_list[ENDP_QUEUE_SIZE];
171 struct list_head urb_more;
172 struct delayed_work scheduler;
Tony Olechd774efe2006-09-13 11:27:35 +0100173};
174struct u132_ring {
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700175 unsigned in_use:1;
176 unsigned length:7;
177 u8 number;
178 struct u132 *u132;
179 struct u132_endp *curr_endp;
180 struct delayed_work scheduler;
Tony Olechd774efe2006-09-13 11:27:35 +0100181};
Tony Olechd774efe2006-09-13 11:27:35 +0100182struct u132 {
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700183 struct kref kref;
184 struct list_head u132_list;
185 struct mutex sw_lock;
Daniel Walker50d8ca92008-03-23 00:00:02 -0700186 struct mutex scheduler_lock;
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700187 struct u132_platform_data *board;
188 struct platform_device *platform_dev;
189 struct u132_ring ring[MAX_U132_RINGS];
190 int sequence_num;
191 int going;
192 int power;
193 int reset;
194 int num_ports;
195 u32 hc_control;
196 u32 hc_fminterval;
197 u32 hc_roothub_status;
198 u32 hc_roothub_a;
199 u32 hc_roothub_portstatus[MAX_ROOT_PORTS];
200 int flags;
201 unsigned long next_statechange;
202 struct delayed_work monitor;
203 int num_endpoints;
204 struct u132_addr addr[MAX_U132_ADDRS];
205 struct u132_udev udev[MAX_U132_UDEVS];
206 struct u132_port port[MAX_U132_PORTS];
207 struct u132_endp *endp[MAX_U132_ENDPS];
Tony Olechd774efe2006-09-13 11:27:35 +0100208};
Adrian Bunk9ce85402006-11-20 03:24:44 +0100209
Tony Olechd774efe2006-09-13 11:27:35 +0100210/*
Matt LaPlante0779bf22006-11-30 05:24:39 +0100211* these cannot be inlines because we need the structure offset!!
Tony Olechd774efe2006-09-13 11:27:35 +0100212* Does anyone have a better way?????
213*/
Tony Olech4b873612006-12-06 13:16:22 +0000214#define ftdi_read_pcimem(pdev, member, data) usb_ftdi_elan_read_pcimem(pdev, \
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700215 offsetof(struct ohci_regs, member), 0, data);
Tony Olech4b873612006-12-06 13:16:22 +0000216#define ftdi_write_pcimem(pdev, member, data) usb_ftdi_elan_write_pcimem(pdev, \
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700217 offsetof(struct ohci_regs, member), 0, data);
Tony Olechd774efe2006-09-13 11:27:35 +0100218#define u132_read_pcimem(u132, member, data) \
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700219 usb_ftdi_elan_read_pcimem(u132->platform_dev, offsetof(struct \
220 ohci_regs, member), 0, data);
Tony Olechd774efe2006-09-13 11:27:35 +0100221#define u132_write_pcimem(u132, member, data) \
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700222 usb_ftdi_elan_write_pcimem(u132->platform_dev, offsetof(struct \
223 ohci_regs, member), 0, data);
Tony Olechd774efe2006-09-13 11:27:35 +0100224static inline struct u132 *udev_to_u132(struct u132_udev *udev)
225{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700226 u8 udev_number = udev->udev_number;
227 return container_of(udev, struct u132, udev[udev_number]);
Tony Olechd774efe2006-09-13 11:27:35 +0100228}
229
230static inline struct u132 *hcd_to_u132(struct usb_hcd *hcd)
231{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700232 return (struct u132 *)(hcd->hcd_priv);
Tony Olechd774efe2006-09-13 11:27:35 +0100233}
234
235static inline struct usb_hcd *u132_to_hcd(struct u132 *u132)
236{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700237 return container_of((void *)u132, struct usb_hcd, hcd_priv);
Tony Olechd774efe2006-09-13 11:27:35 +0100238}
239
240static inline void u132_disable(struct u132 *u132)
241{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700242 u132_to_hcd(u132)->state = HC_STATE_HALT;
Tony Olechd774efe2006-09-13 11:27:35 +0100243}
244
245
246#define kref_to_u132(d) container_of(d, struct u132, kref)
247#define kref_to_u132_endp(d) container_of(d, struct u132_endp, kref)
248#define kref_to_u132_udev(d) container_of(d, struct u132_udev, kref)
249#include "../misc/usb_u132.h"
250static const char hcd_name[] = "u132_hcd";
251#define PORT_C_MASK ((USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | \
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700252 USB_PORT_STAT_C_SUSPEND | USB_PORT_STAT_C_OVERCURRENT | \
253 USB_PORT_STAT_C_RESET) << 16)
Tony Olechd774efe2006-09-13 11:27:35 +0100254static void u132_hcd_delete(struct kref *kref)
255{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700256 struct u132 *u132 = kref_to_u132(kref);
257 struct platform_device *pdev = u132->platform_dev;
258 struct usb_hcd *hcd = u132_to_hcd(u132);
259 u132->going += 1;
260 mutex_lock(&u132_module_lock);
261 list_del_init(&u132->u132_list);
262 u132_instances -= 1;
263 mutex_unlock(&u132_module_lock);
264 dev_warn(&u132->platform_dev->dev, "FREEING the hcd=%p and thus the u13"
265 "2=%p going=%d pdev=%p\n", hcd, u132, u132->going, pdev);
266 usb_put_hcd(hcd);
Tony Olechd774efe2006-09-13 11:27:35 +0100267}
268
269static inline void u132_u132_put_kref(struct u132 *u132)
270{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700271 kref_put(&u132->kref, u132_hcd_delete);
Tony Olechd774efe2006-09-13 11:27:35 +0100272}
273
274static inline void u132_u132_init_kref(struct u132 *u132)
275{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700276 kref_init(&u132->kref);
Tony Olechd774efe2006-09-13 11:27:35 +0100277}
278
279static void u132_udev_delete(struct kref *kref)
280{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700281 struct u132_udev *udev = kref_to_u132_udev(kref);
282 udev->udev_number = 0;
283 udev->usb_device = NULL;
284 udev->usb_addr = 0;
285 udev->enumeration = 0;
Tony Olechd774efe2006-09-13 11:27:35 +0100286}
287
288static inline void u132_udev_put_kref(struct u132 *u132, struct u132_udev *udev)
289{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700290 kref_put(&udev->kref, u132_udev_delete);
Tony Olechd774efe2006-09-13 11:27:35 +0100291}
292
293static inline void u132_udev_get_kref(struct u132 *u132, struct u132_udev *udev)
294{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700295 kref_get(&udev->kref);
Tony Olechd774efe2006-09-13 11:27:35 +0100296}
297
298static inline void u132_udev_init_kref(struct u132 *u132,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700299 struct u132_udev *udev)
Tony Olechd774efe2006-09-13 11:27:35 +0100300{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700301 kref_init(&udev->kref);
Tony Olechd774efe2006-09-13 11:27:35 +0100302}
303
304static inline void u132_ring_put_kref(struct u132 *u132, struct u132_ring *ring)
305{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700306 kref_put(&u132->kref, u132_hcd_delete);
Tony Olechd774efe2006-09-13 11:27:35 +0100307}
308
309static void u132_ring_requeue_work(struct u132 *u132, struct u132_ring *ring,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700310 unsigned int delta)
Tony Olechd774efe2006-09-13 11:27:35 +0100311{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700312 if (delta > 0) {
313 if (queue_delayed_work(workqueue, &ring->scheduler, delta))
314 return;
315 } else if (queue_delayed_work(workqueue, &ring->scheduler, 0))
316 return;
317 kref_put(&u132->kref, u132_hcd_delete);
Tony Olechd774efe2006-09-13 11:27:35 +0100318}
319
320static void u132_ring_queue_work(struct u132 *u132, struct u132_ring *ring,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700321 unsigned int delta)
Tony Olechd774efe2006-09-13 11:27:35 +0100322{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700323 kref_get(&u132->kref);
324 u132_ring_requeue_work(u132, ring, delta);
Tony Olechd774efe2006-09-13 11:27:35 +0100325}
326
327static void u132_ring_cancel_work(struct u132 *u132, struct u132_ring *ring)
328{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700329 if (cancel_delayed_work(&ring->scheduler))
330 kref_put(&u132->kref, u132_hcd_delete);
Tony Olechd774efe2006-09-13 11:27:35 +0100331}
332
333static void u132_endp_delete(struct kref *kref)
334{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700335 struct u132_endp *endp = kref_to_u132_endp(kref);
336 struct u132 *u132 = endp->u132;
337 u8 usb_addr = endp->usb_addr;
338 u8 usb_endp = endp->usb_endp;
339 u8 address = u132->addr[usb_addr].address;
340 struct u132_udev *udev = &u132->udev[address];
341 u8 endp_number = endp->endp_number;
342 struct usb_host_endpoint *hep = endp->hep;
343 struct u132_ring *ring = endp->ring;
344 struct list_head *head = &endp->endp_ring;
345 ring->length -= 1;
346 if (endp == ring->curr_endp) {
347 if (list_empty(head)) {
348 ring->curr_endp = NULL;
349 list_del(head);
350 } else {
351 struct u132_endp *next_endp = list_entry(head->next,
352 struct u132_endp, endp_ring);
353 ring->curr_endp = next_endp;
354 list_del(head);
355 }
356 } else
357 list_del(head);
358 if (endp->input) {
359 udev->endp_number_in[usb_endp] = 0;
360 u132_udev_put_kref(u132, udev);
361 }
362 if (endp->output) {
363 udev->endp_number_out[usb_endp] = 0;
364 u132_udev_put_kref(u132, udev);
365 }
366 u132->endp[endp_number - 1] = NULL;
367 hep->hcpriv = NULL;
368 kfree(endp);
369 u132_u132_put_kref(u132);
Tony Olechd774efe2006-09-13 11:27:35 +0100370}
371
372static inline void u132_endp_put_kref(struct u132 *u132, struct u132_endp *endp)
373{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700374 kref_put(&endp->kref, u132_endp_delete);
Tony Olechd774efe2006-09-13 11:27:35 +0100375}
376
377static inline void u132_endp_get_kref(struct u132 *u132, struct u132_endp *endp)
378{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700379 kref_get(&endp->kref);
Tony Olechd774efe2006-09-13 11:27:35 +0100380}
381
382static inline void u132_endp_init_kref(struct u132 *u132,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700383 struct u132_endp *endp)
Tony Olechd774efe2006-09-13 11:27:35 +0100384{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700385 kref_init(&endp->kref);
386 kref_get(&u132->kref);
Tony Olechd774efe2006-09-13 11:27:35 +0100387}
388
389static void u132_endp_queue_work(struct u132 *u132, struct u132_endp *endp,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700390 unsigned int delta)
Tony Olechd774efe2006-09-13 11:27:35 +0100391{
David Howellsc4028952006-11-22 14:57:56 +0000392 if (queue_delayed_work(workqueue, &endp->scheduler, delta))
393 kref_get(&endp->kref);
Tony Olechd774efe2006-09-13 11:27:35 +0100394}
395
396static void u132_endp_cancel_work(struct u132 *u132, struct u132_endp *endp)
397{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700398 if (cancel_delayed_work(&endp->scheduler))
399 kref_put(&endp->kref, u132_endp_delete);
Tony Olechd774efe2006-09-13 11:27:35 +0100400}
401
402static inline void u132_monitor_put_kref(struct u132 *u132)
403{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700404 kref_put(&u132->kref, u132_hcd_delete);
Tony Olechd774efe2006-09-13 11:27:35 +0100405}
406
407static void u132_monitor_queue_work(struct u132 *u132, unsigned int delta)
408{
David Howellsc4028952006-11-22 14:57:56 +0000409 if (queue_delayed_work(workqueue, &u132->monitor, delta))
410 kref_get(&u132->kref);
Tony Olechd774efe2006-09-13 11:27:35 +0100411}
412
413static void u132_monitor_requeue_work(struct u132 *u132, unsigned int delta)
414{
David Howellsc4028952006-11-22 14:57:56 +0000415 if (!queue_delayed_work(workqueue, &u132->monitor, delta))
416 kref_put(&u132->kref, u132_hcd_delete);
Tony Olechd774efe2006-09-13 11:27:35 +0100417}
418
419static void u132_monitor_cancel_work(struct u132 *u132)
420{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700421 if (cancel_delayed_work(&u132->monitor))
422 kref_put(&u132->kref, u132_hcd_delete);
Tony Olechd774efe2006-09-13 11:27:35 +0100423}
424
425static int read_roothub_info(struct u132 *u132)
426{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700427 u32 revision;
428 int retval;
429 retval = u132_read_pcimem(u132, revision, &revision);
430 if (retval) {
431 dev_err(&u132->platform_dev->dev, "error %d accessing device co"
432 "ntrol\n", retval);
433 return retval;
434 } else if ((revision & 0xFF) == 0x10) {
435 } else if ((revision & 0xFF) == 0x11) {
436 } else {
437 dev_err(&u132->platform_dev->dev, "device revision is not valid"
438 " %08X\n", revision);
439 return -ENODEV;
440 }
441 retval = u132_read_pcimem(u132, control, &u132->hc_control);
442 if (retval) {
443 dev_err(&u132->platform_dev->dev, "error %d accessing device co"
444 "ntrol\n", retval);
445 return retval;
446 }
447 retval = u132_read_pcimem(u132, roothub.status,
448 &u132->hc_roothub_status);
449 if (retval) {
450 dev_err(&u132->platform_dev->dev, "error %d accessing device re"
451 "g roothub.status\n", retval);
452 return retval;
453 }
454 retval = u132_read_pcimem(u132, roothub.a, &u132->hc_roothub_a);
455 if (retval) {
456 dev_err(&u132->platform_dev->dev, "error %d accessing device re"
457 "g roothub.a\n", retval);
458 return retval;
459 }
460 {
461 int I = u132->num_ports;
462 int i = 0;
463 while (I-- > 0) {
464 retval = u132_read_pcimem(u132, roothub.portstatus[i],
465 &u132->hc_roothub_portstatus[i]);
466 if (retval) {
467 dev_err(&u132->platform_dev->dev, "error %d acc"
468 "essing device roothub.portstatus[%d]\n"
469 , retval, i);
470 return retval;
471 } else
472 i += 1;
473 }
474 }
475 return 0;
Tony Olechd774efe2006-09-13 11:27:35 +0100476}
477
David Howellsc4028952006-11-22 14:57:56 +0000478static void u132_hcd_monitor_work(struct work_struct *work)
Tony Olechd774efe2006-09-13 11:27:35 +0100479{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700480 struct u132 *u132 = container_of(work, struct u132, monitor.work);
481 if (u132->going > 1) {
482 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
483 , u132->going);
484 u132_monitor_put_kref(u132);
485 return;
486 } else if (u132->going > 0) {
487 dev_err(&u132->platform_dev->dev, "device is being removed\n");
488 u132_monitor_put_kref(u132);
489 return;
490 } else {
491 int retval;
492 mutex_lock(&u132->sw_lock);
493 retval = read_roothub_info(u132);
494 if (retval) {
495 struct usb_hcd *hcd = u132_to_hcd(u132);
496 u132_disable(u132);
497 u132->going = 1;
498 mutex_unlock(&u132->sw_lock);
499 usb_hc_died(hcd);
500 ftdi_elan_gone_away(u132->platform_dev);
501 u132_monitor_put_kref(u132);
502 return;
503 } else {
504 u132_monitor_requeue_work(u132, 500);
505 mutex_unlock(&u132->sw_lock);
506 return;
507 }
508 }
Tony Olechd774efe2006-09-13 11:27:35 +0100509}
510
511static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700512 struct urb *urb, int status)
Tony Olechd774efe2006-09-13 11:27:35 +0100513{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700514 struct u132_ring *ring;
515 unsigned long irqs;
516 struct usb_hcd *hcd = u132_to_hcd(u132);
517 urb->error_count = 0;
518 spin_lock_irqsave(&endp->queue_lock.slock, irqs);
Alan Sterne9df41c2007-08-08 11:48:02 -0400519 usb_hcd_unlink_urb_from_ep(hcd, urb);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700520 endp->queue_next += 1;
521 if (ENDP_QUEUE_SIZE > --endp->queue_size) {
522 endp->active = 0;
523 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
524 } else {
525 struct list_head *next = endp->urb_more.next;
526 struct u132_urbq *urbq = list_entry(next, struct u132_urbq,
527 urb_more);
528 list_del(next);
529 endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] =
530 urbq->urb;
531 endp->active = 0;
532 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
533 kfree(urbq);
534 }
Daniel Walker50d8ca92008-03-23 00:00:02 -0700535 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700536 ring = endp->ring;
537 ring->in_use = 0;
538 u132_ring_cancel_work(u132, ring);
539 u132_ring_queue_work(u132, ring, 0);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700540 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700541 u132_endp_put_kref(u132, endp);
Alan Stern4a000272007-08-24 15:42:24 -0400542 usb_hcd_giveback_urb(hcd, urb, status);
Tony Olechd774efe2006-09-13 11:27:35 +0100543}
544
545static void u132_hcd_forget_urb(struct u132 *u132, struct u132_endp *endp,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700546 struct urb *urb, int status)
Tony Olechd774efe2006-09-13 11:27:35 +0100547{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700548 u132_endp_put_kref(u132, endp);
Tony Olechd774efe2006-09-13 11:27:35 +0100549}
550
551static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700552 struct urb *urb, int status)
Tony Olechd774efe2006-09-13 11:27:35 +0100553{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700554 unsigned long irqs;
555 struct usb_hcd *hcd = u132_to_hcd(u132);
556 urb->error_count = 0;
557 spin_lock_irqsave(&endp->queue_lock.slock, irqs);
Alan Sterne9df41c2007-08-08 11:48:02 -0400558 usb_hcd_unlink_urb_from_ep(hcd, urb);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700559 endp->queue_next += 1;
560 if (ENDP_QUEUE_SIZE > --endp->queue_size) {
561 endp->active = 0;
562 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
563 } else {
564 struct list_head *next = endp->urb_more.next;
565 struct u132_urbq *urbq = list_entry(next, struct u132_urbq,
566 urb_more);
567 list_del(next);
568 endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] =
569 urbq->urb;
570 endp->active = 0;
571 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
572 kfree(urbq);
Joe Perches7f26b3a2010-08-04 10:40:08 -0700573 }
574 usb_hcd_giveback_urb(hcd, urb, status);
Tony Olechd774efe2006-09-13 11:27:35 +0100575}
576
577static inline int edset_input(struct u132 *u132, struct u132_ring *ring,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700578 struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
579 void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
580 int toggle_bits, int error_count, int condition_code, int repeat_number,
581 int halted, int skipped, int actual, int non_null))
Tony Olechd774efe2006-09-13 11:27:35 +0100582{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700583 return usb_ftdi_elan_edset_input(u132->platform_dev, ring->number, endp,
584 urb, address, endp->usb_endp, toggle_bits, callback);
Tony Olechd774efe2006-09-13 11:27:35 +0100585}
586
587static inline int edset_setup(struct u132 *u132, struct u132_ring *ring,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700588 struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
589 void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
590 int toggle_bits, int error_count, int condition_code, int repeat_number,
591 int halted, int skipped, int actual, int non_null))
Tony Olechd774efe2006-09-13 11:27:35 +0100592{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700593 return usb_ftdi_elan_edset_setup(u132->platform_dev, ring->number, endp,
594 urb, address, endp->usb_endp, toggle_bits, callback);
Tony Olechd774efe2006-09-13 11:27:35 +0100595}
596
597static inline int edset_single(struct u132 *u132, struct u132_ring *ring,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700598 struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
599 void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
600 int toggle_bits, int error_count, int condition_code, int repeat_number,
601 int halted, int skipped, int actual, int non_null))
Tony Olechd774efe2006-09-13 11:27:35 +0100602{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700603 return usb_ftdi_elan_edset_single(u132->platform_dev, ring->number,
604 endp, urb, address, endp->usb_endp, toggle_bits, callback);
Tony Olechd774efe2006-09-13 11:27:35 +0100605}
606
607static inline int edset_output(struct u132 *u132, struct u132_ring *ring,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700608 struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
609 void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
610 int toggle_bits, int error_count, int condition_code, int repeat_number,
611 int halted, int skipped, int actual, int non_null))
Tony Olechd774efe2006-09-13 11:27:35 +0100612{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700613 return usb_ftdi_elan_edset_output(u132->platform_dev, ring->number,
614 endp, urb, address, endp->usb_endp, toggle_bits, callback);
Tony Olechd774efe2006-09-13 11:27:35 +0100615}
616
617
618/*
619* must not LOCK sw_lock
620*
621*/
622static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700623 int len, int toggle_bits, int error_count, int condition_code,
624 int repeat_number, int halted, int skipped, int actual, int non_null)
Tony Olechd774efe2006-09-13 11:27:35 +0100625{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700626 struct u132_endp *endp = data;
627 struct u132 *u132 = endp->u132;
628 u8 address = u132->addr[endp->usb_addr].address;
629 struct u132_udev *udev = &u132->udev[address];
Daniel Walker50d8ca92008-03-23 00:00:02 -0700630 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700631 if (u132->going > 1) {
632 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
633 , u132->going);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700634 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700635 u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
636 return;
637 } else if (endp->dequeueing) {
638 endp->dequeueing = 0;
Daniel Walker50d8ca92008-03-23 00:00:02 -0700639 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700640 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
641 return;
642 } else if (u132->going > 0) {
Alan Sterneb231052007-08-21 15:40:36 -0400643 dev_err(&u132->platform_dev->dev, "device is being removed "
644 "urb=%p\n", urb);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700645 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700646 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
647 return;
Alan Sterneb231052007-08-21 15:40:36 -0400648 } else if (!urb->unlinked) {
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700649 struct u132_ring *ring = endp->ring;
650 u8 *u = urb->transfer_buffer + urb->actual_length;
651 u8 *b = buf;
652 int L = len;
653
654 while (L-- > 0)
655 *u++ = *b++;
656
657 urb->actual_length += len;
658 if ((condition_code == TD_CC_NOERROR) &&
659 (urb->transfer_buffer_length > urb->actual_length)) {
660 endp->toggle_bits = toggle_bits;
661 usb_settoggle(udev->usb_device, endp->usb_endp, 0,
662 1 & toggle_bits);
663 if (urb->actual_length > 0) {
664 int retval;
Daniel Walker50d8ca92008-03-23 00:00:02 -0700665 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700666 retval = edset_single(u132, ring, endp, urb,
667 address, endp->toggle_bits,
668 u132_hcd_interrupt_recv);
669 if (retval != 0)
670 u132_hcd_giveback_urb(u132, endp, urb,
671 retval);
672 } else {
673 ring->in_use = 0;
674 endp->active = 0;
675 endp->jiffies = jiffies +
676 msecs_to_jiffies(urb->interval);
677 u132_ring_cancel_work(u132, ring);
678 u132_ring_queue_work(u132, ring, 0);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700679 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700680 u132_endp_put_kref(u132, endp);
681 }
682 return;
683 } else if ((condition_code == TD_DATAUNDERRUN) &&
684 ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) {
685 endp->toggle_bits = toggle_bits;
686 usb_settoggle(udev->usb_device, endp->usb_endp, 0,
687 1 & toggle_bits);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700688 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700689 u132_hcd_giveback_urb(u132, endp, urb, 0);
690 return;
691 } else {
692 if (condition_code == TD_CC_NOERROR) {
693 endp->toggle_bits = toggle_bits;
694 usb_settoggle(udev->usb_device, endp->usb_endp,
695 0, 1 & toggle_bits);
696 } else if (condition_code == TD_CC_STALL) {
697 endp->toggle_bits = 0x2;
698 usb_settoggle(udev->usb_device, endp->usb_endp,
699 0, 0);
700 } else {
701 endp->toggle_bits = 0x2;
702 usb_settoggle(udev->usb_device, endp->usb_endp,
703 0, 0);
704 dev_err(&u132->platform_dev->dev, "urb=%p givin"
705 "g back INTERRUPT %s\n", urb,
706 cc_to_text[condition_code]);
707 }
Daniel Walker50d8ca92008-03-23 00:00:02 -0700708 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700709 u132_hcd_giveback_urb(u132, endp, urb,
710 cc_to_error[condition_code]);
711 return;
712 }
713 } else {
Alan Sterneb231052007-08-21 15:40:36 -0400714 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
715 "unlinked=%d\n", urb, urb->unlinked);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700716 mutex_unlock(&u132->scheduler_lock);
Alan Stern4a000272007-08-24 15:42:24 -0400717 u132_hcd_giveback_urb(u132, endp, urb, 0);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700718 return;
719 }
Tony Olechd774efe2006-09-13 11:27:35 +0100720}
721
722static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700723 int len, int toggle_bits, int error_count, int condition_code,
724 int repeat_number, int halted, int skipped, int actual, int non_null)
Tony Olechd774efe2006-09-13 11:27:35 +0100725{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700726 struct u132_endp *endp = data;
727 struct u132 *u132 = endp->u132;
728 u8 address = u132->addr[endp->usb_addr].address;
Daniel Walker50d8ca92008-03-23 00:00:02 -0700729 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700730 if (u132->going > 1) {
731 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
732 , u132->going);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700733 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700734 u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
735 return;
736 } else if (endp->dequeueing) {
737 endp->dequeueing = 0;
Daniel Walker50d8ca92008-03-23 00:00:02 -0700738 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700739 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
740 return;
741 } else if (u132->going > 0) {
Alan Sterneb231052007-08-21 15:40:36 -0400742 dev_err(&u132->platform_dev->dev, "device is being removed "
743 "urb=%p\n", urb);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700744 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700745 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
746 return;
Alan Sterneb231052007-08-21 15:40:36 -0400747 } else if (!urb->unlinked) {
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700748 struct u132_ring *ring = endp->ring;
749 urb->actual_length += len;
750 endp->toggle_bits = toggle_bits;
751 if (urb->transfer_buffer_length > urb->actual_length) {
752 int retval;
Daniel Walker50d8ca92008-03-23 00:00:02 -0700753 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700754 retval = edset_output(u132, ring, endp, urb, address,
755 endp->toggle_bits, u132_hcd_bulk_output_sent);
756 if (retval != 0)
757 u132_hcd_giveback_urb(u132, endp, urb, retval);
758 return;
759 } else {
Daniel Walker50d8ca92008-03-23 00:00:02 -0700760 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700761 u132_hcd_giveback_urb(u132, endp, urb, 0);
762 return;
763 }
764 } else {
Alan Sterneb231052007-08-21 15:40:36 -0400765 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
766 "unlinked=%d\n", urb, urb->unlinked);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700767 mutex_unlock(&u132->scheduler_lock);
Alan Stern4a000272007-08-24 15:42:24 -0400768 u132_hcd_giveback_urb(u132, endp, urb, 0);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700769 return;
770 }
Tony Olechd774efe2006-09-13 11:27:35 +0100771}
772
773static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700774 int len, int toggle_bits, int error_count, int condition_code,
775 int repeat_number, int halted, int skipped, int actual, int non_null)
Tony Olechd774efe2006-09-13 11:27:35 +0100776{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700777 struct u132_endp *endp = data;
778 struct u132 *u132 = endp->u132;
779 u8 address = u132->addr[endp->usb_addr].address;
780 struct u132_udev *udev = &u132->udev[address];
Daniel Walker50d8ca92008-03-23 00:00:02 -0700781 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700782 if (u132->going > 1) {
783 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
784 , u132->going);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700785 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700786 u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
787 return;
788 } else if (endp->dequeueing) {
789 endp->dequeueing = 0;
Daniel Walker50d8ca92008-03-23 00:00:02 -0700790 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700791 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
792 return;
793 } else if (u132->going > 0) {
Alan Sterneb231052007-08-21 15:40:36 -0400794 dev_err(&u132->platform_dev->dev, "device is being removed "
795 "urb=%p\n", urb);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700796 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700797 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
798 return;
Alan Sterneb231052007-08-21 15:40:36 -0400799 } else if (!urb->unlinked) {
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700800 struct u132_ring *ring = endp->ring;
801 u8 *u = urb->transfer_buffer + urb->actual_length;
802 u8 *b = buf;
803 int L = len;
804
805 while (L-- > 0)
806 *u++ = *b++;
807
808 urb->actual_length += len;
809 if ((condition_code == TD_CC_NOERROR) &&
810 (urb->transfer_buffer_length > urb->actual_length)) {
811 int retval;
812 endp->toggle_bits = toggle_bits;
813 usb_settoggle(udev->usb_device, endp->usb_endp, 0,
814 1 & toggle_bits);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700815 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700816 retval = usb_ftdi_elan_edset_input(u132->platform_dev,
817 ring->number, endp, urb, address,
818 endp->usb_endp, endp->toggle_bits,
819 u132_hcd_bulk_input_recv);
820 if (retval != 0)
821 u132_hcd_giveback_urb(u132, endp, urb, retval);
822 return;
823 } else if (condition_code == TD_CC_NOERROR) {
824 endp->toggle_bits = toggle_bits;
825 usb_settoggle(udev->usb_device, endp->usb_endp, 0,
826 1 & toggle_bits);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700827 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700828 u132_hcd_giveback_urb(u132, endp, urb,
829 cc_to_error[condition_code]);
830 return;
831 } else if ((condition_code == TD_DATAUNDERRUN) &&
832 ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) {
833 endp->toggle_bits = toggle_bits;
834 usb_settoggle(udev->usb_device, endp->usb_endp, 0,
835 1 & toggle_bits);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700836 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700837 u132_hcd_giveback_urb(u132, endp, urb, 0);
838 return;
839 } else if (condition_code == TD_DATAUNDERRUN) {
840 endp->toggle_bits = toggle_bits;
841 usb_settoggle(udev->usb_device, endp->usb_endp, 0,
842 1 & toggle_bits);
843 dev_warn(&u132->platform_dev->dev, "urb=%p(SHORT NOT OK"
844 ") giving back BULK IN %s\n", urb,
845 cc_to_text[condition_code]);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700846 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700847 u132_hcd_giveback_urb(u132, endp, urb, 0);
848 return;
849 } else if (condition_code == TD_CC_STALL) {
850 endp->toggle_bits = 0x2;
851 usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700852 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700853 u132_hcd_giveback_urb(u132, endp, urb,
854 cc_to_error[condition_code]);
855 return;
856 } else {
857 endp->toggle_bits = 0x2;
858 usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0);
859 dev_err(&u132->platform_dev->dev, "urb=%p giving back B"
860 "ULK IN code=%d %s\n", urb, condition_code,
861 cc_to_text[condition_code]);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700862 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700863 u132_hcd_giveback_urb(u132, endp, urb,
864 cc_to_error[condition_code]);
865 return;
866 }
867 } else {
Alan Sterneb231052007-08-21 15:40:36 -0400868 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
869 "unlinked=%d\n", urb, urb->unlinked);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700870 mutex_unlock(&u132->scheduler_lock);
Alan Stern4a000272007-08-24 15:42:24 -0400871 u132_hcd_giveback_urb(u132, endp, urb, 0);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700872 return;
873 }
Tony Olechd774efe2006-09-13 11:27:35 +0100874}
875
876static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700877 int len, int toggle_bits, int error_count, int condition_code,
878 int repeat_number, int halted, int skipped, int actual, int non_null)
Tony Olechd774efe2006-09-13 11:27:35 +0100879{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700880 struct u132_endp *endp = data;
881 struct u132 *u132 = endp->u132;
Daniel Walker50d8ca92008-03-23 00:00:02 -0700882 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700883 if (u132->going > 1) {
884 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
885 , u132->going);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700886 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700887 u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
888 return;
889 } else if (endp->dequeueing) {
890 endp->dequeueing = 0;
Daniel Walker50d8ca92008-03-23 00:00:02 -0700891 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700892 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
893 return;
894 } else if (u132->going > 0) {
Alan Sterneb231052007-08-21 15:40:36 -0400895 dev_err(&u132->platform_dev->dev, "device is being removed "
896 "urb=%p\n", urb);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700897 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700898 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
899 return;
Alan Sterneb231052007-08-21 15:40:36 -0400900 } else if (!urb->unlinked) {
Daniel Walker50d8ca92008-03-23 00:00:02 -0700901 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700902 u132_hcd_giveback_urb(u132, endp, urb, 0);
903 return;
904 } else {
Alan Sterneb231052007-08-21 15:40:36 -0400905 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
906 "unlinked=%d\n", urb, urb->unlinked);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700907 mutex_unlock(&u132->scheduler_lock);
Alan Stern4a000272007-08-24 15:42:24 -0400908 u132_hcd_giveback_urb(u132, endp, urb, 0);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700909 return;
910 }
Tony Olechd774efe2006-09-13 11:27:35 +0100911}
912
913static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700914 int len, int toggle_bits, int error_count, int condition_code,
915 int repeat_number, int halted, int skipped, int actual, int non_null)
Tony Olechd774efe2006-09-13 11:27:35 +0100916{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700917 struct u132_endp *endp = data;
918 struct u132 *u132 = endp->u132;
919 u8 address = u132->addr[endp->usb_addr].address;
Daniel Walker50d8ca92008-03-23 00:00:02 -0700920 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700921 if (u132->going > 1) {
922 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
923 , u132->going);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700924 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700925 u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
926 return;
927 } else if (endp->dequeueing) {
928 endp->dequeueing = 0;
Daniel Walker50d8ca92008-03-23 00:00:02 -0700929 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700930 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
931 return;
932 } else if (u132->going > 0) {
Alan Sterneb231052007-08-21 15:40:36 -0400933 dev_err(&u132->platform_dev->dev, "device is being removed "
934 "urb=%p\n", urb);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700935 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700936 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
937 return;
Alan Sterneb231052007-08-21 15:40:36 -0400938 } else if (!urb->unlinked) {
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700939 struct u132_ring *ring = endp->ring;
940 u8 *u = urb->transfer_buffer;
941 u8 *b = buf;
942 int L = len;
943
944 while (L-- > 0)
945 *u++ = *b++;
946
947 urb->actual_length = len;
948 if ((condition_code == TD_CC_NOERROR) || ((condition_code ==
949 TD_DATAUNDERRUN) && ((urb->transfer_flags &
950 URB_SHORT_NOT_OK) == 0))) {
951 int retval;
Daniel Walker50d8ca92008-03-23 00:00:02 -0700952 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700953 retval = usb_ftdi_elan_edset_empty(u132->platform_dev,
954 ring->number, endp, urb, address,
955 endp->usb_endp, 0x3,
956 u132_hcd_configure_empty_sent);
957 if (retval != 0)
958 u132_hcd_giveback_urb(u132, endp, urb, retval);
959 return;
960 } else if (condition_code == TD_CC_STALL) {
Daniel Walker50d8ca92008-03-23 00:00:02 -0700961 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700962 dev_warn(&u132->platform_dev->dev, "giving back SETUP I"
963 "NPUT STALL urb %p\n", urb);
964 u132_hcd_giveback_urb(u132, endp, urb,
965 cc_to_error[condition_code]);
966 return;
967 } else {
Daniel Walker50d8ca92008-03-23 00:00:02 -0700968 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700969 dev_err(&u132->platform_dev->dev, "giving back SETUP IN"
970 "PUT %s urb %p\n", cc_to_text[condition_code],
971 urb);
972 u132_hcd_giveback_urb(u132, endp, urb,
973 cc_to_error[condition_code]);
974 return;
975 }
976 } else {
Alan Sterneb231052007-08-21 15:40:36 -0400977 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
978 "unlinked=%d\n", urb, urb->unlinked);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700979 mutex_unlock(&u132->scheduler_lock);
Alan Stern4a000272007-08-24 15:42:24 -0400980 u132_hcd_giveback_urb(u132, endp, urb, 0);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700981 return;
982 }
Tony Olechd774efe2006-09-13 11:27:35 +0100983}
984
985static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700986 int len, int toggle_bits, int error_count, int condition_code,
987 int repeat_number, int halted, int skipped, int actual, int non_null)
Tony Olechd774efe2006-09-13 11:27:35 +0100988{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700989 struct u132_endp *endp = data;
990 struct u132 *u132 = endp->u132;
Daniel Walker50d8ca92008-03-23 00:00:02 -0700991 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700992 if (u132->going > 1) {
993 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
994 , u132->going);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700995 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700996 u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
997 return;
998 } else if (endp->dequeueing) {
999 endp->dequeueing = 0;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001000 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001001 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
1002 return;
1003 } else if (u132->going > 0) {
Alan Sterneb231052007-08-21 15:40:36 -04001004 dev_err(&u132->platform_dev->dev, "device is being removed "
1005 "urb=%p\n", urb);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001006 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001007 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
1008 return;
Alan Sterneb231052007-08-21 15:40:36 -04001009 } else if (!urb->unlinked) {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001010 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001011 u132_hcd_giveback_urb(u132, endp, urb, 0);
1012 return;
1013 } else {
Alan Sterneb231052007-08-21 15:40:36 -04001014 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
1015 "unlinked=%d\n", urb, urb->unlinked);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001016 mutex_unlock(&u132->scheduler_lock);
Alan Stern4a000272007-08-24 15:42:24 -04001017 u132_hcd_giveback_urb(u132, endp, urb, 0);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001018 return;
1019 }
Tony Olechd774efe2006-09-13 11:27:35 +01001020}
1021
1022static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001023 int len, int toggle_bits, int error_count, int condition_code,
1024 int repeat_number, int halted, int skipped, int actual, int non_null)
Tony Olechd774efe2006-09-13 11:27:35 +01001025{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001026 struct u132_endp *endp = data;
1027 struct u132 *u132 = endp->u132;
1028 u8 address = u132->addr[endp->usb_addr].address;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001029 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001030 if (u132->going > 1) {
1031 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
1032 , u132->going);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001033 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001034 u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
1035 return;
1036 } else if (endp->dequeueing) {
1037 endp->dequeueing = 0;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001038 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001039 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
1040 return;
1041 } else if (u132->going > 0) {
Alan Sterneb231052007-08-21 15:40:36 -04001042 dev_err(&u132->platform_dev->dev, "device is being removed "
1043 "urb=%p\n", urb);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001044 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001045 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
1046 return;
Alan Sterneb231052007-08-21 15:40:36 -04001047 } else if (!urb->unlinked) {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001048 if (usb_pipein(urb->pipe)) {
1049 int retval;
1050 struct u132_ring *ring = endp->ring;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001051 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001052 retval = usb_ftdi_elan_edset_input(u132->platform_dev,
1053 ring->number, endp, urb, address,
1054 endp->usb_endp, 0,
1055 u132_hcd_configure_input_recv);
1056 if (retval != 0)
1057 u132_hcd_giveback_urb(u132, endp, urb, retval);
1058 return;
1059 } else {
1060 int retval;
1061 struct u132_ring *ring = endp->ring;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001062 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001063 retval = usb_ftdi_elan_edset_input(u132->platform_dev,
1064 ring->number, endp, urb, address,
1065 endp->usb_endp, 0,
1066 u132_hcd_configure_empty_recv);
1067 if (retval != 0)
1068 u132_hcd_giveback_urb(u132, endp, urb, retval);
1069 return;
1070 }
1071 } else {
Alan Sterneb231052007-08-21 15:40:36 -04001072 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
1073 "unlinked=%d\n", urb, urb->unlinked);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001074 mutex_unlock(&u132->scheduler_lock);
Alan Stern4a000272007-08-24 15:42:24 -04001075 u132_hcd_giveback_urb(u132, endp, urb, 0);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001076 return;
1077 }
Tony Olechd774efe2006-09-13 11:27:35 +01001078}
1079
1080static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001081 u8 *buf, int len, int toggle_bits, int error_count, int condition_code,
1082 int repeat_number, int halted, int skipped, int actual, int non_null)
Tony Olechd774efe2006-09-13 11:27:35 +01001083{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001084 struct u132_endp *endp = data;
1085 struct u132 *u132 = endp->u132;
1086 u8 address = u132->addr[endp->usb_addr].address;
1087 struct u132_udev *udev = &u132->udev[address];
Daniel Walker50d8ca92008-03-23 00:00:02 -07001088 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001089 if (u132->going > 1) {
1090 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
1091 , u132->going);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001092 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001093 u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
1094 return;
1095 } else if (endp->dequeueing) {
1096 endp->dequeueing = 0;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001097 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001098 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
1099 return;
1100 } else if (u132->going > 0) {
Alan Sterneb231052007-08-21 15:40:36 -04001101 dev_err(&u132->platform_dev->dev, "device is being removed "
1102 "urb=%p\n", urb);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001103 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001104 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
1105 return;
Alan Sterneb231052007-08-21 15:40:36 -04001106 } else if (!urb->unlinked) {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001107 u132->addr[0].address = 0;
1108 endp->usb_addr = udev->usb_addr;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001109 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001110 u132_hcd_giveback_urb(u132, endp, urb, 0);
1111 return;
1112 } else {
Alan Sterneb231052007-08-21 15:40:36 -04001113 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
1114 "unlinked=%d\n", urb, urb->unlinked);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001115 mutex_unlock(&u132->scheduler_lock);
Alan Stern4a000272007-08-24 15:42:24 -04001116 u132_hcd_giveback_urb(u132, endp, urb, 0);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001117 return;
1118 }
Tony Olechd774efe2006-09-13 11:27:35 +01001119}
1120
1121static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001122 u8 *buf, int len, int toggle_bits, int error_count, int condition_code,
1123 int repeat_number, int halted, int skipped, int actual, int non_null)
Tony Olechd774efe2006-09-13 11:27:35 +01001124{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001125 struct u132_endp *endp = data;
1126 struct u132 *u132 = endp->u132;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001127 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001128 if (u132->going > 1) {
1129 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
1130 , u132->going);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001131 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001132 u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
1133 return;
1134 } else if (endp->dequeueing) {
1135 endp->dequeueing = 0;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001136 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001137 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
1138 return;
1139 } else if (u132->going > 0) {
Alan Sterneb231052007-08-21 15:40:36 -04001140 dev_err(&u132->platform_dev->dev, "device is being removed "
1141 "urb=%p\n", urb);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001142 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001143 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
1144 return;
Alan Sterneb231052007-08-21 15:40:36 -04001145 } else if (!urb->unlinked) {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001146 int retval;
1147 struct u132_ring *ring = endp->ring;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001148 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001149 retval = usb_ftdi_elan_edset_input(u132->platform_dev,
1150 ring->number, endp, urb, 0, endp->usb_endp, 0,
1151 u132_hcd_enumeration_empty_recv);
1152 if (retval != 0)
1153 u132_hcd_giveback_urb(u132, endp, urb, retval);
1154 return;
1155 } else {
Alan Sterneb231052007-08-21 15:40:36 -04001156 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
1157 "unlinked=%d\n", urb, urb->unlinked);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001158 mutex_unlock(&u132->scheduler_lock);
Alan Stern4a000272007-08-24 15:42:24 -04001159 u132_hcd_giveback_urb(u132, endp, urb, 0);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001160 return;
1161 }
Tony Olechd774efe2006-09-13 11:27:35 +01001162}
1163
1164static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001165 int len, int toggle_bits, int error_count, int condition_code,
1166 int repeat_number, int halted, int skipped, int actual, int non_null)
Tony Olechd774efe2006-09-13 11:27:35 +01001167{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001168 struct u132_endp *endp = data;
1169 struct u132 *u132 = endp->u132;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001170 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001171 if (u132->going > 1) {
1172 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
1173 , u132->going);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001174 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001175 u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
1176 return;
1177 } else if (endp->dequeueing) {
1178 endp->dequeueing = 0;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001179 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001180 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
1181 return;
1182 } else if (u132->going > 0) {
Alan Sterneb231052007-08-21 15:40:36 -04001183 dev_err(&u132->platform_dev->dev, "device is being removed "
1184 "urb=%p\n", urb);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001185 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001186 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
1187 return;
Alan Sterneb231052007-08-21 15:40:36 -04001188 } else if (!urb->unlinked) {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001189 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001190 u132_hcd_giveback_urb(u132, endp, urb, 0);
1191 return;
1192 } else {
Alan Sterneb231052007-08-21 15:40:36 -04001193 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
1194 "unlinked=%d\n", urb, urb->unlinked);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001195 mutex_unlock(&u132->scheduler_lock);
Alan Stern4a000272007-08-24 15:42:24 -04001196 u132_hcd_giveback_urb(u132, endp, urb, 0);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001197 return;
1198 }
Tony Olechd774efe2006-09-13 11:27:35 +01001199}
1200
1201static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001202 int len, int toggle_bits, int error_count, int condition_code,
1203 int repeat_number, int halted, int skipped, int actual, int non_null)
Tony Olechd774efe2006-09-13 11:27:35 +01001204{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001205 struct u132_endp *endp = data;
1206 struct u132 *u132 = endp->u132;
1207 u8 address = u132->addr[endp->usb_addr].address;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001208 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001209 if (u132->going > 1) {
1210 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
1211 , u132->going);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001212 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001213 u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
1214 return;
1215 } else if (endp->dequeueing) {
1216 endp->dequeueing = 0;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001217 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001218 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
1219 return;
1220 } else if (u132->going > 0) {
Alan Sterneb231052007-08-21 15:40:36 -04001221 dev_err(&u132->platform_dev->dev, "device is being removed "
1222 "urb=%p\n", urb);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001223 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001224 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
1225 return;
Alan Sterneb231052007-08-21 15:40:36 -04001226 } else if (!urb->unlinked) {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001227 int retval;
1228 struct u132_ring *ring = endp->ring;
1229 u8 *u = urb->transfer_buffer;
1230 u8 *b = buf;
1231 int L = len;
1232
1233 while (L-- > 0)
1234 *u++ = *b++;
1235
1236 urb->actual_length = len;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001237 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001238 retval = usb_ftdi_elan_edset_empty(u132->platform_dev,
1239 ring->number, endp, urb, address, endp->usb_endp, 0x3,
1240 u132_hcd_initial_empty_sent);
1241 if (retval != 0)
1242 u132_hcd_giveback_urb(u132, endp, urb, retval);
1243 return;
1244 } else {
Alan Sterneb231052007-08-21 15:40:36 -04001245 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
1246 "unlinked=%d\n", urb, urb->unlinked);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001247 mutex_unlock(&u132->scheduler_lock);
Alan Stern4a000272007-08-24 15:42:24 -04001248 u132_hcd_giveback_urb(u132, endp, urb, 0);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001249 return;
1250 }
Tony Olechd774efe2006-09-13 11:27:35 +01001251}
1252
1253static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001254 int len, int toggle_bits, int error_count, int condition_code,
1255 int repeat_number, int halted, int skipped, int actual, int non_null)
Tony Olechd774efe2006-09-13 11:27:35 +01001256{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001257 struct u132_endp *endp = data;
1258 struct u132 *u132 = endp->u132;
1259 u8 address = u132->addr[endp->usb_addr].address;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001260 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001261 if (u132->going > 1) {
1262 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
1263 , u132->going);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001264 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001265 u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
1266 return;
1267 } else if (endp->dequeueing) {
1268 endp->dequeueing = 0;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001269 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001270 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
1271 return;
1272 } else if (u132->going > 0) {
Alan Sterneb231052007-08-21 15:40:36 -04001273 dev_err(&u132->platform_dev->dev, "device is being removed "
1274 "urb=%p\n", urb);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001275 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001276 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
1277 return;
Alan Sterneb231052007-08-21 15:40:36 -04001278 } else if (!urb->unlinked) {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001279 int retval;
1280 struct u132_ring *ring = endp->ring;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001281 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001282 retval = usb_ftdi_elan_edset_input(u132->platform_dev,
1283 ring->number, endp, urb, address, endp->usb_endp, 0,
1284 u132_hcd_initial_input_recv);
1285 if (retval != 0)
1286 u132_hcd_giveback_urb(u132, endp, urb, retval);
1287 return;
1288 } else {
Alan Sterneb231052007-08-21 15:40:36 -04001289 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
1290 "unlinked=%d\n", urb, urb->unlinked);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001291 mutex_unlock(&u132->scheduler_lock);
Alan Stern4a000272007-08-24 15:42:24 -04001292 u132_hcd_giveback_urb(u132, endp, urb, 0);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001293 return;
1294 }
Tony Olechd774efe2006-09-13 11:27:35 +01001295}
1296
Tony Olechd774efe2006-09-13 11:27:35 +01001297/*
1298* this work function is only executed from the work queue
1299*
1300*/
David Howellsc4028952006-11-22 14:57:56 +00001301static void u132_hcd_ring_work_scheduler(struct work_struct *work)
Tony Olechd774efe2006-09-13 11:27:35 +01001302{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001303 struct u132_ring *ring =
David Howellsc4028952006-11-22 14:57:56 +00001304 container_of(work, struct u132_ring, scheduler.work);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001305 struct u132 *u132 = ring->u132;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001306 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001307 if (ring->in_use) {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001308 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001309 u132_ring_put_kref(u132, ring);
1310 return;
1311 } else if (ring->curr_endp) {
1312 struct u132_endp *last_endp = ring->curr_endp;
1313 struct list_head *scan;
1314 struct list_head *head = &last_endp->endp_ring;
1315 unsigned long wakeup = 0;
1316 list_for_each(scan, head) {
1317 struct u132_endp *endp = list_entry(scan,
1318 struct u132_endp, endp_ring);
1319 if (endp->queue_next == endp->queue_last) {
1320 } else if ((endp->delayed == 0)
1321 || time_after_eq(jiffies, endp->jiffies)) {
1322 ring->curr_endp = endp;
1323 u132_endp_cancel_work(u132, last_endp);
1324 u132_endp_queue_work(u132, last_endp, 0);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001325 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001326 u132_ring_put_kref(u132, ring);
1327 return;
1328 } else {
1329 unsigned long delta = endp->jiffies - jiffies;
1330 if (delta > wakeup)
1331 wakeup = delta;
1332 }
1333 }
1334 if (last_endp->queue_next == last_endp->queue_last) {
1335 } else if ((last_endp->delayed == 0) || time_after_eq(jiffies,
1336 last_endp->jiffies)) {
1337 u132_endp_cancel_work(u132, last_endp);
1338 u132_endp_queue_work(u132, last_endp, 0);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001339 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001340 u132_ring_put_kref(u132, ring);
1341 return;
1342 } else {
1343 unsigned long delta = last_endp->jiffies - jiffies;
1344 if (delta > wakeup)
1345 wakeup = delta;
1346 }
1347 if (wakeup > 0) {
1348 u132_ring_requeue_work(u132, ring, wakeup);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001349 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001350 return;
1351 } else {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001352 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001353 u132_ring_put_kref(u132, ring);
1354 return;
1355 }
1356 } else {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001357 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001358 u132_ring_put_kref(u132, ring);
1359 return;
1360 }
Tony Olechd774efe2006-09-13 11:27:35 +01001361}
1362
David Howellsc4028952006-11-22 14:57:56 +00001363static void u132_hcd_endp_work_scheduler(struct work_struct *work)
Tony Olechd774efe2006-09-13 11:27:35 +01001364{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001365 struct u132_ring *ring;
1366 struct u132_endp *endp =
David Howellsc4028952006-11-22 14:57:56 +00001367 container_of(work, struct u132_endp, scheduler.work);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001368 struct u132 *u132 = endp->u132;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001369 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001370 ring = endp->ring;
1371 if (endp->edset_flush) {
1372 endp->edset_flush = 0;
1373 if (endp->dequeueing)
1374 usb_ftdi_elan_edset_flush(u132->platform_dev,
1375 ring->number, endp);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001376 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001377 u132_endp_put_kref(u132, endp);
1378 return;
1379 } else if (endp->active) {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001380 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001381 u132_endp_put_kref(u132, endp);
1382 return;
1383 } else if (ring->in_use) {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001384 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001385 u132_endp_put_kref(u132, endp);
1386 return;
1387 } else if (endp->queue_next == endp->queue_last) {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001388 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001389 u132_endp_put_kref(u132, endp);
1390 return;
1391 } else if (endp->pipetype == PIPE_INTERRUPT) {
1392 u8 address = u132->addr[endp->usb_addr].address;
1393 if (ring->in_use) {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001394 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001395 u132_endp_put_kref(u132, endp);
1396 return;
1397 } else {
1398 int retval;
1399 struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
1400 endp->queue_next];
1401 endp->active = 1;
1402 ring->curr_endp = endp;
1403 ring->in_use = 1;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001404 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001405 retval = edset_single(u132, ring, endp, urb, address,
1406 endp->toggle_bits, u132_hcd_interrupt_recv);
1407 if (retval != 0)
1408 u132_hcd_giveback_urb(u132, endp, urb, retval);
1409 return;
1410 }
1411 } else if (endp->pipetype == PIPE_CONTROL) {
1412 u8 address = u132->addr[endp->usb_addr].address;
1413 if (ring->in_use) {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001414 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001415 u132_endp_put_kref(u132, endp);
1416 return;
1417 } else if (address == 0) {
1418 int retval;
1419 struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
1420 endp->queue_next];
1421 endp->active = 1;
1422 ring->curr_endp = endp;
1423 ring->in_use = 1;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001424 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001425 retval = edset_setup(u132, ring, endp, urb, address,
1426 0x2, u132_hcd_initial_setup_sent);
1427 if (retval != 0)
1428 u132_hcd_giveback_urb(u132, endp, urb, retval);
1429 return;
1430 } else if (endp->usb_addr == 0) {
1431 int retval;
1432 struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
1433 endp->queue_next];
1434 endp->active = 1;
1435 ring->curr_endp = endp;
1436 ring->in_use = 1;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001437 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001438 retval = edset_setup(u132, ring, endp, urb, 0, 0x2,
1439 u132_hcd_enumeration_address_sent);
1440 if (retval != 0)
1441 u132_hcd_giveback_urb(u132, endp, urb, retval);
1442 return;
1443 } else {
1444 int retval;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001445 struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
1446 endp->queue_next];
Randy Dunlap1d6ec812010-05-06 16:46:03 -07001447 address = u132->addr[endp->usb_addr].address;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001448 endp->active = 1;
1449 ring->curr_endp = endp;
1450 ring->in_use = 1;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001451 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001452 retval = edset_setup(u132, ring, endp, urb, address,
1453 0x2, u132_hcd_configure_setup_sent);
1454 if (retval != 0)
1455 u132_hcd_giveback_urb(u132, endp, urb, retval);
1456 return;
1457 }
1458 } else {
1459 if (endp->input) {
1460 u8 address = u132->addr[endp->usb_addr].address;
1461 if (ring->in_use) {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001462 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001463 u132_endp_put_kref(u132, endp);
1464 return;
1465 } else {
1466 int retval;
1467 struct urb *urb = endp->urb_list[
1468 ENDP_QUEUE_MASK & endp->queue_next];
1469 endp->active = 1;
1470 ring->curr_endp = endp;
1471 ring->in_use = 1;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001472 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001473 retval = edset_input(u132, ring, endp, urb,
1474 address, endp->toggle_bits,
1475 u132_hcd_bulk_input_recv);
1476 if (retval == 0) {
1477 } else
1478 u132_hcd_giveback_urb(u132, endp, urb,
1479 retval);
1480 return;
1481 }
1482 } else { /* output pipe */
1483 u8 address = u132->addr[endp->usb_addr].address;
1484 if (ring->in_use) {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001485 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001486 u132_endp_put_kref(u132, endp);
1487 return;
1488 } else {
1489 int retval;
1490 struct urb *urb = endp->urb_list[
1491 ENDP_QUEUE_MASK & endp->queue_next];
1492 endp->active = 1;
1493 ring->curr_endp = endp;
1494 ring->in_use = 1;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001495 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001496 retval = edset_output(u132, ring, endp, urb,
1497 address, endp->toggle_bits,
1498 u132_hcd_bulk_output_sent);
1499 if (retval == 0) {
1500 } else
1501 u132_hcd_giveback_urb(u132, endp, urb,
1502 retval);
1503 return;
1504 }
1505 }
1506 }
Tony Olechd774efe2006-09-13 11:27:35 +01001507}
Gabriel C5b570d42007-07-30 12:57:03 +02001508#ifdef CONFIG_PM
Tony Olechd774efe2006-09-13 11:27:35 +01001509
1510static void port_power(struct u132 *u132, int pn, int is_on)
1511{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001512 u132->port[pn].power = is_on;
Tony Olechd774efe2006-09-13 11:27:35 +01001513}
1514
Gabriel C5b570d42007-07-30 12:57:03 +02001515#endif
1516
Tony Olechd774efe2006-09-13 11:27:35 +01001517static void u132_power(struct u132 *u132, int is_on)
1518{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001519 struct usb_hcd *hcd = u132_to_hcd(u132)
1520 ; /* hub is inactive unless the port is powered */
1521 if (is_on) {
1522 if (u132->power)
1523 return;
1524 u132->power = 1;
1525 } else {
1526 u132->power = 0;
1527 hcd->state = HC_STATE_HALT;
1528 }
Tony Olechd774efe2006-09-13 11:27:35 +01001529}
1530
1531static int u132_periodic_reinit(struct u132 *u132)
1532{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001533 int retval;
1534 u32 fi = u132->hc_fminterval & 0x03fff;
1535 u32 fit;
1536 u32 fminterval;
1537 retval = u132_read_pcimem(u132, fminterval, &fminterval);
1538 if (retval)
1539 return retval;
1540 fit = fminterval & FIT;
1541 retval = u132_write_pcimem(u132, fminterval,
1542 (fit ^ FIT) | u132->hc_fminterval);
1543 if (retval)
1544 return retval;
Saurabh Karajgaonkar8602b082015-08-04 14:03:45 +00001545 return u132_write_pcimem(u132, periodicstart,
1546 ((9 * fi) / 10) & 0x3fff);
Tony Olechd774efe2006-09-13 11:27:35 +01001547}
1548
1549static char *hcfs2string(int state)
1550{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001551 switch (state) {
1552 case OHCI_USB_RESET:
1553 return "reset";
1554 case OHCI_USB_RESUME:
1555 return "resume";
1556 case OHCI_USB_OPER:
1557 return "operational";
1558 case OHCI_USB_SUSPEND:
1559 return "suspend";
1560 }
1561 return "?";
Tony Olechd774efe2006-09-13 11:27:35 +01001562}
1563
Tony Olechd774efe2006-09-13 11:27:35 +01001564static int u132_init(struct u132 *u132)
1565{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001566 int retval;
1567 u32 control;
1568 u132_disable(u132);
1569 u132->next_statechange = jiffies;
1570 retval = u132_write_pcimem(u132, intrdisable, OHCI_INTR_MIE);
1571 if (retval)
1572 return retval;
1573 retval = u132_read_pcimem(u132, control, &control);
1574 if (retval)
1575 return retval;
1576 if (u132->num_ports == 0) {
1577 u32 rh_a = -1;
1578 retval = u132_read_pcimem(u132, roothub.a, &rh_a);
1579 if (retval)
1580 return retval;
1581 u132->num_ports = rh_a & RH_A_NDP;
1582 retval = read_roothub_info(u132);
1583 if (retval)
1584 return retval;
1585 }
1586 if (u132->num_ports > MAX_U132_PORTS)
1587 return -EINVAL;
1588
1589 return 0;
Tony Olechd774efe2006-09-13 11:27:35 +01001590}
1591
1592
1593/* Start an OHCI controller, set the BUS operational
1594* resets USB and controller
1595* enable interrupts
1596*/
1597static int u132_run(struct u132 *u132)
1598{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001599 int retval;
1600 u32 control;
1601 u32 status;
1602 u32 fminterval;
1603 u32 periodicstart;
1604 u32 cmdstatus;
1605 u32 roothub_a;
1606 int mask = OHCI_INTR_INIT;
1607 int first = u132->hc_fminterval == 0;
1608 int sleep_time = 0;
1609 int reset_timeout = 30; /* ... allow extra time */
1610 u132_disable(u132);
1611 if (first) {
1612 u32 temp;
1613 retval = u132_read_pcimem(u132, fminterval, &temp);
1614 if (retval)
1615 return retval;
1616 u132->hc_fminterval = temp & 0x3fff;
1617 u132->hc_fminterval |= FSMP(u132->hc_fminterval) << 16;
1618 }
1619 retval = u132_read_pcimem(u132, control, &u132->hc_control);
1620 if (retval)
1621 return retval;
1622 dev_info(&u132->platform_dev->dev, "resetting from state '%s', control "
1623 "= %08X\n", hcfs2string(u132->hc_control & OHCI_CTRL_HCFS),
1624 u132->hc_control);
1625 switch (u132->hc_control & OHCI_CTRL_HCFS) {
1626 case OHCI_USB_OPER:
1627 sleep_time = 0;
1628 break;
1629 case OHCI_USB_SUSPEND:
1630 case OHCI_USB_RESUME:
1631 u132->hc_control &= OHCI_CTRL_RWC;
1632 u132->hc_control |= OHCI_USB_RESUME;
1633 sleep_time = 10;
1634 break;
1635 default:
1636 u132->hc_control &= OHCI_CTRL_RWC;
1637 u132->hc_control |= OHCI_USB_RESET;
1638 sleep_time = 50;
1639 break;
1640 }
1641 retval = u132_write_pcimem(u132, control, u132->hc_control);
1642 if (retval)
1643 return retval;
1644 retval = u132_read_pcimem(u132, control, &control);
1645 if (retval)
1646 return retval;
1647 msleep(sleep_time);
1648 retval = u132_read_pcimem(u132, roothub.a, &roothub_a);
1649 if (retval)
1650 return retval;
1651 if (!(roothub_a & RH_A_NPS)) {
1652 int temp; /* power down each port */
1653 for (temp = 0; temp < u132->num_ports; temp++) {
1654 retval = u132_write_pcimem(u132,
1655 roothub.portstatus[temp], RH_PS_LSDA);
1656 if (retval)
1657 return retval;
1658 }
1659 }
1660 retval = u132_read_pcimem(u132, control, &control);
1661 if (retval)
1662 return retval;
1663retry:
1664 retval = u132_read_pcimem(u132, cmdstatus, &status);
1665 if (retval)
1666 return retval;
1667 retval = u132_write_pcimem(u132, cmdstatus, OHCI_HCR);
1668 if (retval)
1669 return retval;
1670extra: {
1671 retval = u132_read_pcimem(u132, cmdstatus, &status);
1672 if (retval)
1673 return retval;
1674 if (0 != (status & OHCI_HCR)) {
1675 if (--reset_timeout == 0) {
1676 dev_err(&u132->platform_dev->dev, "USB HC reset"
1677 " timed out!\n");
1678 return -ENODEV;
1679 } else {
1680 msleep(5);
1681 goto extra;
1682 }
1683 }
1684 }
1685 if (u132->flags & OHCI_QUIRK_INITRESET) {
1686 retval = u132_write_pcimem(u132, control, u132->hc_control);
1687 if (retval)
1688 return retval;
1689 retval = u132_read_pcimem(u132, control, &control);
1690 if (retval)
1691 return retval;
1692 }
1693 retval = u132_write_pcimem(u132, ed_controlhead, 0x00000000);
1694 if (retval)
1695 return retval;
1696 retval = u132_write_pcimem(u132, ed_bulkhead, 0x11000000);
1697 if (retval)
1698 return retval;
1699 retval = u132_write_pcimem(u132, hcca, 0x00000000);
1700 if (retval)
1701 return retval;
1702 retval = u132_periodic_reinit(u132);
1703 if (retval)
1704 return retval;
1705 retval = u132_read_pcimem(u132, fminterval, &fminterval);
1706 if (retval)
1707 return retval;
1708 retval = u132_read_pcimem(u132, periodicstart, &periodicstart);
1709 if (retval)
1710 return retval;
1711 if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) {
1712 if (!(u132->flags & OHCI_QUIRK_INITRESET)) {
1713 u132->flags |= OHCI_QUIRK_INITRESET;
1714 goto retry;
1715 } else
1716 dev_err(&u132->platform_dev->dev, "init err(%08x %04x)"
1717 "\n", fminterval, periodicstart);
1718 } /* start controller operations */
1719 u132->hc_control &= OHCI_CTRL_RWC;
1720 u132->hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER;
1721 retval = u132_write_pcimem(u132, control, u132->hc_control);
1722 if (retval)
1723 return retval;
1724 retval = u132_write_pcimem(u132, cmdstatus, OHCI_BLF);
1725 if (retval)
1726 return retval;
1727 retval = u132_read_pcimem(u132, cmdstatus, &cmdstatus);
1728 if (retval)
1729 return retval;
1730 retval = u132_read_pcimem(u132, control, &control);
1731 if (retval)
1732 return retval;
1733 u132_to_hcd(u132)->state = HC_STATE_RUNNING;
1734 retval = u132_write_pcimem(u132, roothub.status, RH_HS_DRWE);
1735 if (retval)
1736 return retval;
1737 retval = u132_write_pcimem(u132, intrstatus, mask);
1738 if (retval)
1739 return retval;
1740 retval = u132_write_pcimem(u132, intrdisable,
1741 OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO |
1742 OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH |
1743 OHCI_INTR_SO);
1744 if (retval)
1745 return retval; /* handle root hub init quirks ... */
1746 retval = u132_read_pcimem(u132, roothub.a, &roothub_a);
1747 if (retval)
1748 return retval;
1749 roothub_a &= ~(RH_A_PSM | RH_A_OCPM);
1750 if (u132->flags & OHCI_QUIRK_SUPERIO) {
1751 roothub_a |= RH_A_NOCP;
1752 roothub_a &= ~(RH_A_POTPGT | RH_A_NPS);
1753 retval = u132_write_pcimem(u132, roothub.a, roothub_a);
1754 if (retval)
1755 return retval;
1756 } else if ((u132->flags & OHCI_QUIRK_AMD756) || distrust_firmware) {
1757 roothub_a |= RH_A_NPS;
1758 retval = u132_write_pcimem(u132, roothub.a, roothub_a);
1759 if (retval)
1760 return retval;
1761 }
1762 retval = u132_write_pcimem(u132, roothub.status, RH_HS_LPSC);
1763 if (retval)
1764 return retval;
1765 retval = u132_write_pcimem(u132, roothub.b,
1766 (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM);
1767 if (retval)
1768 return retval;
1769 retval = u132_read_pcimem(u132, control, &control);
1770 if (retval)
1771 return retval;
1772 mdelay((roothub_a >> 23) & 0x1fe);
1773 u132_to_hcd(u132)->state = HC_STATE_RUNNING;
1774 return 0;
Tony Olechd774efe2006-09-13 11:27:35 +01001775}
1776
1777static void u132_hcd_stop(struct usb_hcd *hcd)
1778{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001779 struct u132 *u132 = hcd_to_u132(hcd);
1780 if (u132->going > 1) {
1781 dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p) has b"
1782 "een removed %d\n", u132, hcd, u132->going);
1783 } else if (u132->going > 0) {
1784 dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
1785 "ed\n", hcd);
1786 } else {
1787 mutex_lock(&u132->sw_lock);
1788 msleep(100);
1789 u132_power(u132, 0);
1790 mutex_unlock(&u132->sw_lock);
1791 }
Tony Olechd774efe2006-09-13 11:27:35 +01001792}
1793
1794static int u132_hcd_start(struct usb_hcd *hcd)
1795{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001796 struct u132 *u132 = hcd_to_u132(hcd);
1797 if (u132->going > 1) {
1798 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
1799 , u132->going);
1800 return -ENODEV;
1801 } else if (u132->going > 0) {
1802 dev_err(&u132->platform_dev->dev, "device is being removed\n");
1803 return -ESHUTDOWN;
1804 } else if (hcd->self.controller) {
1805 int retval;
1806 struct platform_device *pdev =
1807 to_platform_device(hcd->self.controller);
1808 u16 vendor = ((struct u132_platform_data *)
Jingoo Hand4f09e22013-07-30 19:59:40 +09001809 dev_get_platdata(&pdev->dev))->vendor;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001810 u16 device = ((struct u132_platform_data *)
Jingoo Hand4f09e22013-07-30 19:59:40 +09001811 dev_get_platdata(&pdev->dev))->device;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001812 mutex_lock(&u132->sw_lock);
1813 msleep(10);
1814 if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) {
1815 u132->flags = OHCI_QUIRK_AMD756;
1816 } else if (vendor == PCI_VENDOR_ID_OPTI && device == 0xc861) {
1817 dev_err(&u132->platform_dev->dev, "WARNING: OPTi workar"
1818 "ounds unavailable\n");
1819 } else if (vendor == PCI_VENDOR_ID_COMPAQ && device == 0xa0f8)
1820 u132->flags |= OHCI_QUIRK_ZFMICRO;
1821 retval = u132_run(u132);
1822 if (retval) {
1823 u132_disable(u132);
1824 u132->going = 1;
1825 }
1826 msleep(100);
1827 mutex_unlock(&u132->sw_lock);
1828 return retval;
1829 } else {
1830 dev_err(&u132->platform_dev->dev, "platform_device missing\n");
1831 return -ENODEV;
1832 }
Tony Olechd774efe2006-09-13 11:27:35 +01001833}
1834
1835static int u132_hcd_reset(struct usb_hcd *hcd)
1836{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001837 struct u132 *u132 = hcd_to_u132(hcd);
1838 if (u132->going > 1) {
1839 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
1840 , u132->going);
1841 return -ENODEV;
1842 } else if (u132->going > 0) {
1843 dev_err(&u132->platform_dev->dev, "device is being removed\n");
1844 return -ESHUTDOWN;
1845 } else {
1846 int retval;
1847 mutex_lock(&u132->sw_lock);
1848 retval = u132_init(u132);
1849 if (retval) {
1850 u132_disable(u132);
1851 u132->going = 1;
1852 }
1853 mutex_unlock(&u132->sw_lock);
1854 return retval;
1855 }
Tony Olechd774efe2006-09-13 11:27:35 +01001856}
1857
1858static int create_endpoint_and_queue_int(struct u132 *u132,
Alan Sterne9df41c2007-08-08 11:48:02 -04001859 struct u132_udev *udev, struct urb *urb,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001860 struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
1861 gfp_t mem_flags)
Tony Olechd774efe2006-09-13 11:27:35 +01001862{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001863 struct u132_ring *ring;
Alan Sterne9df41c2007-08-08 11:48:02 -04001864 unsigned long irqs;
1865 int rc;
1866 u8 endp_number;
1867 struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
1868
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001869 if (!endp)
1870 return -ENOMEM;
Alan Sterne9df41c2007-08-08 11:48:02 -04001871
1872 spin_lock_init(&endp->queue_lock.slock);
1873 spin_lock_irqsave(&endp->queue_lock.slock, irqs);
1874 rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
1875 if (rc) {
1876 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
1877 kfree(endp);
1878 return rc;
1879 }
1880
1881 endp_number = ++u132->num_endpoints;
1882 urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001883 INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
1884 INIT_LIST_HEAD(&endp->urb_more);
1885 ring = endp->ring = &u132->ring[0];
1886 if (ring->curr_endp) {
1887 list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring);
1888 } else {
1889 INIT_LIST_HEAD(&endp->endp_ring);
1890 ring->curr_endp = endp;
1891 }
1892 ring->length += 1;
1893 endp->dequeueing = 0;
1894 endp->edset_flush = 0;
1895 endp->active = 0;
1896 endp->delayed = 0;
1897 endp->endp_number = endp_number;
1898 endp->u132 = u132;
Alan Sterne9df41c2007-08-08 11:48:02 -04001899 endp->hep = urb->ep;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001900 endp->pipetype = usb_pipetype(urb->pipe);
1901 u132_endp_init_kref(u132, endp);
1902 if (usb_pipein(urb->pipe)) {
1903 endp->toggle_bits = 0x2;
1904 usb_settoggle(udev->usb_device, usb_endp, 0, 0);
1905 endp->input = 1;
1906 endp->output = 0;
1907 udev->endp_number_in[usb_endp] = endp_number;
1908 u132_udev_get_kref(u132, udev);
1909 } else {
1910 endp->toggle_bits = 0x2;
1911 usb_settoggle(udev->usb_device, usb_endp, 1, 0);
1912 endp->input = 0;
1913 endp->output = 1;
1914 udev->endp_number_out[usb_endp] = endp_number;
1915 u132_udev_get_kref(u132, udev);
1916 }
1917 urb->hcpriv = u132;
1918 endp->delayed = 1;
1919 endp->jiffies = jiffies + msecs_to_jiffies(urb->interval);
1920 endp->udev_number = address;
1921 endp->usb_addr = usb_addr;
1922 endp->usb_endp = usb_endp;
1923 endp->queue_size = 1;
1924 endp->queue_last = 0;
1925 endp->queue_next = 0;
1926 endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
1927 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
1928 u132_endp_queue_work(u132, endp, msecs_to_jiffies(urb->interval));
1929 return 0;
1930}
1931
1932static int queue_int_on_old_endpoint(struct u132 *u132,
1933 struct u132_udev *udev, struct urb *urb,
1934 struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
1935 u8 usb_endp, u8 address)
1936{
1937 urb->hcpriv = u132;
1938 endp->delayed = 1;
1939 endp->jiffies = jiffies + msecs_to_jiffies(urb->interval);
1940 if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
1941 endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
1942 } else {
1943 struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq),
1944 GFP_ATOMIC);
1945 if (urbq == NULL) {
1946 endp->queue_size -= 1;
1947 return -ENOMEM;
1948 } else {
1949 list_add_tail(&urbq->urb_more, &endp->urb_more);
1950 urbq->urb = urb;
1951 }
1952 }
1953 return 0;
1954}
1955
1956static int create_endpoint_and_queue_bulk(struct u132 *u132,
1957 struct u132_udev *udev, struct urb *urb,
1958 struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
1959 gfp_t mem_flags)
1960{
1961 int ring_number;
1962 struct u132_ring *ring;
1963 unsigned long irqs;
1964 int rc;
1965 u8 endp_number;
1966 struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
1967
1968 if (!endp)
1969 return -ENOMEM;
1970
1971 spin_lock_init(&endp->queue_lock.slock);
1972 spin_lock_irqsave(&endp->queue_lock.slock, irqs);
1973 rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
1974 if (rc) {
1975 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
1976 kfree(endp);
1977 return rc;
1978 }
1979
1980 endp_number = ++u132->num_endpoints;
1981 urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
1982 INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
1983 INIT_LIST_HEAD(&endp->urb_more);
1984 endp->dequeueing = 0;
1985 endp->edset_flush = 0;
1986 endp->active = 0;
1987 endp->delayed = 0;
1988 endp->endp_number = endp_number;
1989 endp->u132 = u132;
1990 endp->hep = urb->ep;
1991 endp->pipetype = usb_pipetype(urb->pipe);
1992 u132_endp_init_kref(u132, endp);
1993 if (usb_pipein(urb->pipe)) {
1994 endp->toggle_bits = 0x2;
1995 usb_settoggle(udev->usb_device, usb_endp, 0, 0);
1996 ring_number = 3;
1997 endp->input = 1;
1998 endp->output = 0;
1999 udev->endp_number_in[usb_endp] = endp_number;
2000 u132_udev_get_kref(u132, udev);
2001 } else {
2002 endp->toggle_bits = 0x2;
2003 usb_settoggle(udev->usb_device, usb_endp, 1, 0);
2004 ring_number = 2;
2005 endp->input = 0;
2006 endp->output = 1;
2007 udev->endp_number_out[usb_endp] = endp_number;
2008 u132_udev_get_kref(u132, udev);
2009 }
2010 ring = endp->ring = &u132->ring[ring_number - 1];
2011 if (ring->curr_endp) {
2012 list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring);
2013 } else {
2014 INIT_LIST_HEAD(&endp->endp_ring);
2015 ring->curr_endp = endp;
2016 }
2017 ring->length += 1;
2018 urb->hcpriv = u132;
2019 endp->udev_number = address;
2020 endp->usb_addr = usb_addr;
2021 endp->usb_endp = usb_endp;
2022 endp->queue_size = 1;
2023 endp->queue_last = 0;
2024 endp->queue_next = 0;
2025 endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
2026 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
2027 u132_endp_queue_work(u132, endp, 0);
2028 return 0;
2029}
2030
2031static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
2032 struct urb *urb,
2033 struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
2034 u8 usb_endp, u8 address)
2035{
2036 urb->hcpriv = u132;
2037 if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
2038 endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
2039 } else {
2040 struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq),
2041 GFP_ATOMIC);
2042 if (urbq == NULL) {
2043 endp->queue_size -= 1;
2044 return -ENOMEM;
2045 } else {
2046 list_add_tail(&urbq->urb_more, &endp->urb_more);
2047 urbq->urb = urb;
2048 }
2049 }
2050 return 0;
2051}
2052
2053static int create_endpoint_and_queue_control(struct u132 *u132,
2054 struct urb *urb,
2055 struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp,
2056 gfp_t mem_flags)
2057{
2058 struct u132_ring *ring;
2059 unsigned long irqs;
2060 int rc;
2061 u8 endp_number;
2062 struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
2063
2064 if (!endp)
2065 return -ENOMEM;
2066
2067 spin_lock_init(&endp->queue_lock.slock);
2068 spin_lock_irqsave(&endp->queue_lock.slock, irqs);
2069 rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
2070 if (rc) {
2071 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
2072 kfree(endp);
2073 return rc;
2074 }
2075
2076 endp_number = ++u132->num_endpoints;
2077 urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
2078 INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
2079 INIT_LIST_HEAD(&endp->urb_more);
2080 ring = endp->ring = &u132->ring[0];
2081 if (ring->curr_endp) {
2082 list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring);
2083 } else {
2084 INIT_LIST_HEAD(&endp->endp_ring);
2085 ring->curr_endp = endp;
2086 }
2087 ring->length += 1;
2088 endp->dequeueing = 0;
2089 endp->edset_flush = 0;
2090 endp->active = 0;
2091 endp->delayed = 0;
2092 endp->endp_number = endp_number;
2093 endp->u132 = u132;
2094 endp->hep = urb->ep;
2095 u132_endp_init_kref(u132, endp);
2096 u132_endp_get_kref(u132, endp);
2097 if (usb_addr == 0) {
2098 u8 address = u132->addr[usb_addr].address;
2099 struct u132_udev *udev = &u132->udev[address];
2100 endp->udev_number = address;
2101 endp->usb_addr = usb_addr;
2102 endp->usb_endp = usb_endp;
2103 endp->input = 1;
2104 endp->output = 1;
2105 endp->pipetype = usb_pipetype(urb->pipe);
2106 u132_udev_init_kref(u132, udev);
2107 u132_udev_get_kref(u132, udev);
2108 udev->endp_number_in[usb_endp] = endp_number;
2109 udev->endp_number_out[usb_endp] = endp_number;
2110 urb->hcpriv = u132;
2111 endp->queue_size = 1;
2112 endp->queue_last = 0;
2113 endp->queue_next = 0;
2114 endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
2115 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
2116 u132_endp_queue_work(u132, endp, 0);
2117 return 0;
2118 } else { /*(usb_addr > 0) */
2119 u8 address = u132->addr[usb_addr].address;
2120 struct u132_udev *udev = &u132->udev[address];
2121 endp->udev_number = address;
2122 endp->usb_addr = usb_addr;
2123 endp->usb_endp = usb_endp;
2124 endp->input = 1;
2125 endp->output = 1;
2126 endp->pipetype = usb_pipetype(urb->pipe);
2127 u132_udev_get_kref(u132, udev);
2128 udev->enumeration = 2;
2129 udev->endp_number_in[usb_endp] = endp_number;
2130 udev->endp_number_out[usb_endp] = endp_number;
2131 urb->hcpriv = u132;
2132 endp->queue_size = 1;
2133 endp->queue_last = 0;
2134 endp->queue_next = 0;
2135 endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
2136 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
2137 u132_endp_queue_work(u132, endp, 0);
2138 return 0;
2139 }
Tony Olechd774efe2006-09-13 11:27:35 +01002140}
2141
2142static int queue_control_on_old_endpoint(struct u132 *u132,
Alan Sterne9df41c2007-08-08 11:48:02 -04002143 struct urb *urb,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002144 struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
2145 u8 usb_endp)
Tony Olechd774efe2006-09-13 11:27:35 +01002146{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002147 if (usb_addr == 0) {
2148 if (usb_pipein(urb->pipe)) {
2149 urb->hcpriv = u132;
2150 if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
2151 endp->urb_list[ENDP_QUEUE_MASK &
2152 endp->queue_last++] = urb;
2153 } else {
2154 struct u132_urbq *urbq =
2155 kmalloc(sizeof(struct u132_urbq),
2156 GFP_ATOMIC);
2157 if (urbq == NULL) {
2158 endp->queue_size -= 1;
2159 return -ENOMEM;
2160 } else {
2161 list_add_tail(&urbq->urb_more,
2162 &endp->urb_more);
2163 urbq->urb = urb;
2164 }
2165 }
2166 return 0;
2167 } else { /* usb_pipeout(urb->pipe) */
2168 struct u132_addr *addr = &u132->addr[usb_dev->devnum];
2169 int I = MAX_U132_UDEVS;
2170 int i = 0;
2171 while (--I > 0) {
2172 struct u132_udev *udev = &u132->udev[++i];
2173 if (udev->usb_device) {
2174 continue;
2175 } else {
2176 udev->enumeration = 1;
2177 u132->addr[0].address = i;
2178 endp->udev_number = i;
2179 udev->udev_number = i;
2180 udev->usb_addr = usb_dev->devnum;
2181 u132_udev_init_kref(u132, udev);
2182 udev->endp_number_in[usb_endp] =
2183 endp->endp_number;
2184 u132_udev_get_kref(u132, udev);
2185 udev->endp_number_out[usb_endp] =
2186 endp->endp_number;
2187 udev->usb_device = usb_dev;
2188 ((u8 *) (urb->setup_packet))[2] =
2189 addr->address = i;
2190 u132_udev_get_kref(u132, udev);
2191 break;
2192 }
2193 }
2194 if (I == 0) {
2195 dev_err(&u132->platform_dev->dev, "run out of d"
2196 "evice space\n");
2197 return -EINVAL;
2198 }
2199 urb->hcpriv = u132;
2200 if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
2201 endp->urb_list[ENDP_QUEUE_MASK &
2202 endp->queue_last++] = urb;
2203 } else {
2204 struct u132_urbq *urbq =
2205 kmalloc(sizeof(struct u132_urbq),
2206 GFP_ATOMIC);
2207 if (urbq == NULL) {
2208 endp->queue_size -= 1;
2209 return -ENOMEM;
2210 } else {
2211 list_add_tail(&urbq->urb_more,
2212 &endp->urb_more);
2213 urbq->urb = urb;
2214 }
2215 }
2216 return 0;
2217 }
2218 } else { /*(usb_addr > 0) */
2219 u8 address = u132->addr[usb_addr].address;
2220 struct u132_udev *udev = &u132->udev[address];
2221 urb->hcpriv = u132;
2222 if (udev->enumeration != 2)
2223 udev->enumeration = 2;
2224 if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
2225 endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] =
2226 urb;
2227 } else {
2228 struct u132_urbq *urbq =
2229 kmalloc(sizeof(struct u132_urbq), GFP_ATOMIC);
2230 if (urbq == NULL) {
2231 endp->queue_size -= 1;
2232 return -ENOMEM;
2233 } else {
2234 list_add_tail(&urbq->urb_more, &endp->urb_more);
2235 urbq->urb = urb;
2236 }
2237 }
2238 return 0;
2239 }
Tony Olechd774efe2006-09-13 11:27:35 +01002240}
2241
Alan Sterne9df41c2007-08-08 11:48:02 -04002242static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
2243 gfp_t mem_flags)
Tony Olechd774efe2006-09-13 11:27:35 +01002244{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002245 struct u132 *u132 = hcd_to_u132(hcd);
2246 if (irqs_disabled()) {
Mel Gormand0164ad2015-11-06 16:28:21 -08002247 if (gfpflags_allow_blocking(mem_flags)) {
Masanari Iidad5f9e732015-09-30 12:51:51 +09002248 printk(KERN_ERR "invalid context for function that might sleep\n");
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002249 return -EINVAL;
2250 }
2251 }
2252 if (u132->going > 1) {
2253 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
2254 , u132->going);
2255 return -ENODEV;
2256 } else if (u132->going > 0) {
Alan Sterneb231052007-08-21 15:40:36 -04002257 dev_err(&u132->platform_dev->dev, "device is being removed "
2258 "urb=%p\n", urb);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002259 return -ESHUTDOWN;
2260 } else {
2261 u8 usb_addr = usb_pipedevice(urb->pipe);
2262 u8 usb_endp = usb_pipeendpoint(urb->pipe);
2263 struct usb_device *usb_dev = urb->dev;
2264 if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
2265 u8 address = u132->addr[usb_addr].address;
2266 struct u132_udev *udev = &u132->udev[address];
2267 struct u132_endp *endp = urb->ep->hcpriv;
2268 urb->actual_length = 0;
2269 if (endp) {
2270 unsigned long irqs;
2271 int retval;
2272 spin_lock_irqsave(&endp->queue_lock.slock,
2273 irqs);
Alan Sterne9df41c2007-08-08 11:48:02 -04002274 retval = usb_hcd_link_urb_to_ep(hcd, urb);
2275 if (retval == 0) {
2276 retval = queue_int_on_old_endpoint(
2277 u132, udev, urb,
2278 usb_dev, endp,
2279 usb_addr, usb_endp,
2280 address);
2281 if (retval)
2282 usb_hcd_unlink_urb_from_ep(
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002283 hcd, urb);
Alan Sterne9df41c2007-08-08 11:48:02 -04002284 }
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002285 spin_unlock_irqrestore(&endp->queue_lock.slock,
2286 irqs);
2287 if (retval) {
2288 return retval;
2289 } else {
2290 u132_endp_queue_work(u132, endp,
2291 msecs_to_jiffies(urb->interval))
2292 ;
2293 return 0;
2294 }
2295 } else if (u132->num_endpoints == MAX_U132_ENDPS) {
2296 return -EINVAL;
2297 } else { /*(endp == NULL) */
2298 return create_endpoint_and_queue_int(u132, udev,
Alan Sterne9df41c2007-08-08 11:48:02 -04002299 urb, usb_dev, usb_addr,
2300 usb_endp, address, mem_flags);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002301 }
2302 } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
2303 dev_err(&u132->platform_dev->dev, "the hardware does no"
2304 "t support PIPE_ISOCHRONOUS\n");
2305 return -EINVAL;
2306 } else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
2307 u8 address = u132->addr[usb_addr].address;
2308 struct u132_udev *udev = &u132->udev[address];
2309 struct u132_endp *endp = urb->ep->hcpriv;
2310 urb->actual_length = 0;
2311 if (endp) {
2312 unsigned long irqs;
2313 int retval;
2314 spin_lock_irqsave(&endp->queue_lock.slock,
2315 irqs);
Alan Sterne9df41c2007-08-08 11:48:02 -04002316 retval = usb_hcd_link_urb_to_ep(hcd, urb);
2317 if (retval == 0) {
2318 retval = queue_bulk_on_old_endpoint(
2319 u132, udev, urb,
2320 usb_dev, endp,
2321 usb_addr, usb_endp,
2322 address);
2323 if (retval)
2324 usb_hcd_unlink_urb_from_ep(
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002325 hcd, urb);
Alan Sterne9df41c2007-08-08 11:48:02 -04002326 }
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002327 spin_unlock_irqrestore(&endp->queue_lock.slock,
2328 irqs);
2329 if (retval) {
2330 return retval;
2331 } else {
2332 u132_endp_queue_work(u132, endp, 0);
2333 return 0;
2334 }
2335 } else if (u132->num_endpoints == MAX_U132_ENDPS) {
2336 return -EINVAL;
2337 } else
2338 return create_endpoint_and_queue_bulk(u132,
Alan Sterne9df41c2007-08-08 11:48:02 -04002339 udev, urb, usb_dev, usb_addr,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002340 usb_endp, address, mem_flags);
2341 } else {
2342 struct u132_endp *endp = urb->ep->hcpriv;
2343 u16 urb_size = 8;
2344 u8 *b = urb->setup_packet;
2345 int i = 0;
2346 char data[30 * 3 + 4];
2347 char *d = data;
2348 int m = (sizeof(data) - 1) / 3;
2349 int l = 0;
2350 data[0] = 0;
2351 while (urb_size-- > 0) {
2352 if (i > m) {
2353 } else if (i++ < m) {
2354 int w = sprintf(d, " %02X", *b++);
2355 d += w;
2356 l += w;
2357 } else
2358 d += sprintf(d, " ..");
2359 }
2360 if (endp) {
2361 unsigned long irqs;
2362 int retval;
2363 spin_lock_irqsave(&endp->queue_lock.slock,
2364 irqs);
Alan Sterne9df41c2007-08-08 11:48:02 -04002365 retval = usb_hcd_link_urb_to_ep(hcd, urb);
2366 if (retval == 0) {
2367 retval = queue_control_on_old_endpoint(
2368 u132, urb, usb_dev,
2369 endp, usb_addr,
2370 usb_endp);
2371 if (retval)
2372 usb_hcd_unlink_urb_from_ep(
2373 hcd, urb);
2374 }
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002375 spin_unlock_irqrestore(&endp->queue_lock.slock,
2376 irqs);
2377 if (retval) {
2378 return retval;
2379 } else {
2380 u132_endp_queue_work(u132, endp, 0);
2381 return 0;
2382 }
2383 } else if (u132->num_endpoints == MAX_U132_ENDPS) {
2384 return -EINVAL;
2385 } else
2386 return create_endpoint_and_queue_control(u132,
Alan Sterne9df41c2007-08-08 11:48:02 -04002387 urb, usb_dev, usb_addr, usb_endp,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002388 mem_flags);
2389 }
2390 }
Tony Olechd774efe2006-09-13 11:27:35 +01002391}
2392
2393static int dequeue_from_overflow_chain(struct u132 *u132,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002394 struct u132_endp *endp, struct urb *urb)
Tony Olechd774efe2006-09-13 11:27:35 +01002395{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002396 struct list_head *scan;
2397 struct list_head *head = &endp->urb_more;
2398 list_for_each(scan, head) {
2399 struct u132_urbq *urbq = list_entry(scan, struct u132_urbq,
2400 urb_more);
2401 if (urbq->urb == urb) {
2402 struct usb_hcd *hcd = u132_to_hcd(u132);
2403 list_del(scan);
2404 endp->queue_size -= 1;
2405 urb->error_count = 0;
Alan Stern4a000272007-08-24 15:42:24 -04002406 usb_hcd_giveback_urb(hcd, urb, 0);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002407 return 0;
2408 } else
2409 continue;
2410 }
2411 dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]=%p ring"
2412 "[%d] %c%c usb_endp=%d usb_addr=%d size=%d next=%04X last=%04X"
2413 "\n", urb, endp->endp_number, endp, endp->ring->number,
2414 endp->input ? 'I' : ' ', endp->output ? 'O' : ' ',
2415 endp->usb_endp, endp->usb_addr, endp->queue_size,
2416 endp->queue_next, endp->queue_last);
2417 return -EINVAL;
Tony Olechd774efe2006-09-13 11:27:35 +01002418}
2419
2420static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
Alan Sterne9df41c2007-08-08 11:48:02 -04002421 struct urb *urb, int status)
Tony Olechd774efe2006-09-13 11:27:35 +01002422{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002423 unsigned long irqs;
Alan Sterne9df41c2007-08-08 11:48:02 -04002424 int rc;
2425
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002426 spin_lock_irqsave(&endp->queue_lock.slock, irqs);
Alan Sterne9df41c2007-08-08 11:48:02 -04002427 rc = usb_hcd_check_unlink_urb(u132_to_hcd(u132), urb, status);
2428 if (rc) {
2429 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
2430 return rc;
2431 }
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002432 if (endp->queue_size == 0) {
2433 dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]"
2434 "=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", urb,
2435 endp->endp_number, endp, endp->ring->number,
2436 endp->input ? 'I' : ' ', endp->output ? 'O' : ' ',
2437 endp->usb_endp, endp->usb_addr);
2438 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
2439 return -EINVAL;
2440 }
2441 if (urb == endp->urb_list[ENDP_QUEUE_MASK & endp->queue_next]) {
2442 if (endp->active) {
2443 endp->dequeueing = 1;
2444 endp->edset_flush = 1;
2445 u132_endp_queue_work(u132, endp, 0);
2446 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
2447 return 0;
2448 } else {
2449 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
Alan Stern4a000272007-08-24 15:42:24 -04002450 u132_hcd_abandon_urb(u132, endp, urb, status);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002451 return 0;
2452 }
2453 } else {
2454 u16 queue_list = 0;
2455 u16 queue_size = endp->queue_size;
2456 u16 queue_scan = endp->queue_next;
2457 struct urb **urb_slot = NULL;
2458 while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) {
2459 if (urb == endp->urb_list[ENDP_QUEUE_MASK &
2460 ++queue_scan]) {
2461 urb_slot = &endp->urb_list[ENDP_QUEUE_MASK &
2462 queue_scan];
2463 break;
2464 } else
2465 continue;
2466 }
2467 while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) {
2468 *urb_slot = endp->urb_list[ENDP_QUEUE_MASK &
2469 ++queue_scan];
2470 urb_slot = &endp->urb_list[ENDP_QUEUE_MASK &
2471 queue_scan];
2472 }
2473 if (urb_slot) {
2474 struct usb_hcd *hcd = u132_to_hcd(u132);
Alan Sterne9df41c2007-08-08 11:48:02 -04002475
2476 usb_hcd_unlink_urb_from_ep(hcd, urb);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002477 endp->queue_size -= 1;
2478 if (list_empty(&endp->urb_more)) {
2479 spin_unlock_irqrestore(&endp->queue_lock.slock,
2480 irqs);
2481 } else {
2482 struct list_head *next = endp->urb_more.next;
2483 struct u132_urbq *urbq = list_entry(next,
2484 struct u132_urbq, urb_more);
2485 list_del(next);
2486 *urb_slot = urbq->urb;
2487 spin_unlock_irqrestore(&endp->queue_lock.slock,
2488 irqs);
2489 kfree(urbq);
2490 } urb->error_count = 0;
Alan Stern4a000272007-08-24 15:42:24 -04002491 usb_hcd_giveback_urb(hcd, urb, status);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002492 return 0;
2493 } else if (list_empty(&endp->urb_more)) {
2494 dev_err(&u132->platform_dev->dev, "urb=%p not found in "
2495 "endp[%d]=%p ring[%d] %c%c usb_endp=%d usb_addr"
2496 "=%d size=%d next=%04X last=%04X\n", urb,
2497 endp->endp_number, endp, endp->ring->number,
2498 endp->input ? 'I' : ' ',
2499 endp->output ? 'O' : ' ', endp->usb_endp,
2500 endp->usb_addr, endp->queue_size,
2501 endp->queue_next, endp->queue_last);
2502 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
2503 return -EINVAL;
2504 } else {
Alan Sterne9df41c2007-08-08 11:48:02 -04002505 int retval;
2506
2507 usb_hcd_unlink_urb_from_ep(u132_to_hcd(u132), urb);
2508 retval = dequeue_from_overflow_chain(u132, endp,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002509 urb);
2510 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
2511 return retval;
2512 }
2513 }
Tony Olechd774efe2006-09-13 11:27:35 +01002514}
2515
Alan Sterne9df41c2007-08-08 11:48:02 -04002516static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
Tony Olechd774efe2006-09-13 11:27:35 +01002517{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002518 struct u132 *u132 = hcd_to_u132(hcd);
2519 if (u132->going > 2) {
2520 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
2521 , u132->going);
2522 return -ENODEV;
2523 } else {
2524 u8 usb_addr = usb_pipedevice(urb->pipe);
2525 u8 usb_endp = usb_pipeendpoint(urb->pipe);
2526 u8 address = u132->addr[usb_addr].address;
2527 struct u132_udev *udev = &u132->udev[address];
2528 if (usb_pipein(urb->pipe)) {
2529 u8 endp_number = udev->endp_number_in[usb_endp];
2530 struct u132_endp *endp = u132->endp[endp_number - 1];
2531 return u132_endp_urb_dequeue(u132, endp, urb, status);
2532 } else {
2533 u8 endp_number = udev->endp_number_out[usb_endp];
2534 struct u132_endp *endp = u132->endp[endp_number - 1];
2535 return u132_endp_urb_dequeue(u132, endp, urb, status);
2536 }
2537 }
Tony Olechd774efe2006-09-13 11:27:35 +01002538}
2539
2540static void u132_endpoint_disable(struct usb_hcd *hcd,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002541 struct usb_host_endpoint *hep)
Tony Olechd774efe2006-09-13 11:27:35 +01002542{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002543 struct u132 *u132 = hcd_to_u132(hcd);
2544 if (u132->going > 2) {
2545 dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p hep=%p"
2546 ") has been removed %d\n", u132, hcd, hep,
2547 u132->going);
2548 } else {
2549 struct u132_endp *endp = hep->hcpriv;
2550 if (endp)
2551 u132_endp_put_kref(u132, endp);
2552 }
Tony Olechd774efe2006-09-13 11:27:35 +01002553}
2554
2555static int u132_get_frame(struct usb_hcd *hcd)
2556{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002557 struct u132 *u132 = hcd_to_u132(hcd);
2558 if (u132->going > 1) {
2559 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
2560 , u132->going);
2561 return -ENODEV;
2562 } else if (u132->going > 0) {
2563 dev_err(&u132->platform_dev->dev, "device is being removed\n");
2564 return -ESHUTDOWN;
2565 } else {
2566 int frame = 0;
2567 dev_err(&u132->platform_dev->dev, "TODO: u132_get_frame\n");
2568 msleep(100);
2569 return frame;
2570 }
Tony Olechd774efe2006-09-13 11:27:35 +01002571}
2572
2573static int u132_roothub_descriptor(struct u132 *u132,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002574 struct usb_hub_descriptor *desc)
Tony Olechd774efe2006-09-13 11:27:35 +01002575{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002576 int retval;
2577 u16 temp;
2578 u32 rh_a = -1;
2579 u32 rh_b = -1;
2580 retval = u132_read_pcimem(u132, roothub.a, &rh_a);
2581 if (retval)
2582 return retval;
Sergei Shtylyov0ce6fe92015-03-29 01:28:15 +03002583 desc->bDescriptorType = USB_DT_HUB;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002584 desc->bPwrOn2PwrGood = (rh_a & RH_A_POTPGT) >> 24;
2585 desc->bHubContrCurrent = 0;
2586 desc->bNbrPorts = u132->num_ports;
2587 temp = 1 + (u132->num_ports / 8);
2588 desc->bDescLength = 7 + 2 * temp;
Sergei Shtylyova7cf6972015-01-19 01:49:59 +03002589 temp = HUB_CHAR_COMMON_LPSM | HUB_CHAR_COMMON_OCPM;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002590 if (rh_a & RH_A_NPS)
Sergei Shtylyova7cf6972015-01-19 01:49:59 +03002591 temp |= HUB_CHAR_NO_LPSM;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002592 if (rh_a & RH_A_PSM)
Sergei Shtylyova7cf6972015-01-19 01:49:59 +03002593 temp |= HUB_CHAR_INDV_PORT_LPSM;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002594 if (rh_a & RH_A_NOCP)
Sergei Shtylyova7cf6972015-01-19 01:49:59 +03002595 temp |= HUB_CHAR_NO_OCPM;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002596 else if (rh_a & RH_A_OCPM)
Sergei Shtylyova7cf6972015-01-19 01:49:59 +03002597 temp |= HUB_CHAR_INDV_PORT_OCPM;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002598 desc->wHubCharacteristics = cpu_to_le16(temp);
2599 retval = u132_read_pcimem(u132, roothub.b, &rh_b);
2600 if (retval)
2601 return retval;
John Youndbe79bb2001-09-17 00:00:00 -07002602 memset(desc->u.hs.DeviceRemovable, 0xff,
2603 sizeof(desc->u.hs.DeviceRemovable));
2604 desc->u.hs.DeviceRemovable[0] = rh_b & RH_B_DR;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002605 if (u132->num_ports > 7) {
John Youndbe79bb2001-09-17 00:00:00 -07002606 desc->u.hs.DeviceRemovable[1] = (rh_b & RH_B_DR) >> 8;
2607 desc->u.hs.DeviceRemovable[2] = 0xff;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002608 } else
John Youndbe79bb2001-09-17 00:00:00 -07002609 desc->u.hs.DeviceRemovable[1] = 0xff;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002610 return 0;
Tony Olechd774efe2006-09-13 11:27:35 +01002611}
2612
2613static int u132_roothub_status(struct u132 *u132, __le32 *desc)
2614{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002615 u32 rh_status = -1;
2616 int ret_status = u132_read_pcimem(u132, roothub.status, &rh_status);
2617 *desc = cpu_to_le32(rh_status);
2618 return ret_status;
Tony Olechd774efe2006-09-13 11:27:35 +01002619}
2620
2621static int u132_roothub_portstatus(struct u132 *u132, __le32 *desc, u16 wIndex)
2622{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002623 if (wIndex == 0 || wIndex > u132->num_ports) {
2624 return -EINVAL;
2625 } else {
2626 int port = wIndex - 1;
2627 u32 rh_portstatus = -1;
2628 int ret_portstatus = u132_read_pcimem(u132,
2629 roothub.portstatus[port], &rh_portstatus);
2630 *desc = cpu_to_le32(rh_portstatus);
2631 if (*(u16 *) (desc + 2)) {
2632 dev_info(&u132->platform_dev->dev, "Port %d Status Chan"
2633 "ge = %08X\n", port, *desc);
2634 }
2635 return ret_portstatus;
2636 }
Tony Olechd774efe2006-09-13 11:27:35 +01002637}
2638
2639
2640/* this timer value might be vendor-specific ... */
2641#define PORT_RESET_HW_MSEC 10
2642#define PORT_RESET_MSEC 10
2643/* wrap-aware logic morphed from <linux/jiffies.h> */
2644#define tick_before(t1, t2) ((s16)(((s16)(t1))-((s16)(t2))) < 0)
2645static int u132_roothub_portreset(struct u132 *u132, int port_index)
2646{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002647 int retval;
2648 u32 fmnumber;
2649 u16 now;
2650 u16 reset_done;
2651 retval = u132_read_pcimem(u132, fmnumber, &fmnumber);
2652 if (retval)
2653 return retval;
2654 now = fmnumber;
2655 reset_done = now + PORT_RESET_MSEC;
2656 do {
2657 u32 portstat;
2658 do {
2659 retval = u132_read_pcimem(u132,
2660 roothub.portstatus[port_index], &portstat);
2661 if (retval)
2662 return retval;
2663 if (RH_PS_PRS & portstat)
2664 continue;
2665 else
2666 break;
2667 } while (tick_before(now, reset_done));
2668 if (RH_PS_PRS & portstat)
2669 return -ENODEV;
2670 if (RH_PS_CCS & portstat) {
2671 if (RH_PS_PRSC & portstat) {
2672 retval = u132_write_pcimem(u132,
2673 roothub.portstatus[port_index],
2674 RH_PS_PRSC);
2675 if (retval)
2676 return retval;
2677 }
2678 } else
2679 break; /* start the next reset,
2680 sleep till it's probably done */
2681 retval = u132_write_pcimem(u132, roothub.portstatus[port_index],
2682 RH_PS_PRS);
2683 if (retval)
2684 return retval;
2685 msleep(PORT_RESET_HW_MSEC);
2686 retval = u132_read_pcimem(u132, fmnumber, &fmnumber);
2687 if (retval)
2688 return retval;
2689 now = fmnumber;
2690 } while (tick_before(now, reset_done));
2691 return 0;
Tony Olechd774efe2006-09-13 11:27:35 +01002692}
2693
2694static int u132_roothub_setportfeature(struct u132 *u132, u16 wValue,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002695 u16 wIndex)
Tony Olechd774efe2006-09-13 11:27:35 +01002696{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002697 if (wIndex == 0 || wIndex > u132->num_ports) {
2698 return -EINVAL;
2699 } else {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002700 int port_index = wIndex - 1;
2701 struct u132_port *port = &u132->port[port_index];
2702 port->Status &= ~(1 << wValue);
2703 switch (wValue) {
2704 case USB_PORT_FEAT_SUSPEND:
Saurabh Karajgaonkar8602b082015-08-04 14:03:45 +00002705 return u132_write_pcimem(u132,
2706 roothub.portstatus[port_index], RH_PS_PSS);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002707 case USB_PORT_FEAT_POWER:
Saurabh Karajgaonkar8602b082015-08-04 14:03:45 +00002708 return u132_write_pcimem(u132,
2709 roothub.portstatus[port_index], RH_PS_PPS);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002710 case USB_PORT_FEAT_RESET:
Saurabh Karajgaonkar8602b082015-08-04 14:03:45 +00002711 return u132_roothub_portreset(u132, port_index);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002712 default:
2713 return -EPIPE;
2714 }
2715 }
Tony Olechd774efe2006-09-13 11:27:35 +01002716}
2717
2718static int u132_roothub_clearportfeature(struct u132 *u132, u16 wValue,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002719 u16 wIndex)
Tony Olechd774efe2006-09-13 11:27:35 +01002720{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002721 if (wIndex == 0 || wIndex > u132->num_ports) {
2722 return -EINVAL;
2723 } else {
2724 int port_index = wIndex - 1;
2725 u32 temp;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002726 struct u132_port *port = &u132->port[port_index];
2727 port->Status &= ~(1 << wValue);
2728 switch (wValue) {
2729 case USB_PORT_FEAT_ENABLE:
2730 temp = RH_PS_CCS;
2731 break;
2732 case USB_PORT_FEAT_C_ENABLE:
2733 temp = RH_PS_PESC;
2734 break;
2735 case USB_PORT_FEAT_SUSPEND:
2736 temp = RH_PS_POCI;
2737 if ((u132->hc_control & OHCI_CTRL_HCFS)
2738 != OHCI_USB_OPER) {
2739 dev_err(&u132->platform_dev->dev, "TODO resume_"
2740 "root_hub\n");
2741 }
2742 break;
2743 case USB_PORT_FEAT_C_SUSPEND:
2744 temp = RH_PS_PSSC;
2745 break;
2746 case USB_PORT_FEAT_POWER:
2747 temp = RH_PS_LSDA;
2748 break;
2749 case USB_PORT_FEAT_C_CONNECTION:
2750 temp = RH_PS_CSC;
2751 break;
2752 case USB_PORT_FEAT_C_OVER_CURRENT:
2753 temp = RH_PS_OCIC;
2754 break;
2755 case USB_PORT_FEAT_C_RESET:
2756 temp = RH_PS_PRSC;
2757 break;
2758 default:
2759 return -EPIPE;
2760 }
Saurabh Karajgaonkar8602b082015-08-04 14:03:45 +00002761 return u132_write_pcimem(u132, roothub.portstatus[port_index],
2762 temp);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002763 }
Tony Olechd774efe2006-09-13 11:27:35 +01002764}
2765
2766
2767/* the virtual root hub timer IRQ checks for hub status*/
2768static int u132_hub_status_data(struct usb_hcd *hcd, char *buf)
2769{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002770 struct u132 *u132 = hcd_to_u132(hcd);
2771 if (u132->going > 1) {
2772 dev_err(&u132->platform_dev->dev, "device hcd=%p has been remov"
2773 "ed %d\n", hcd, u132->going);
2774 return -ENODEV;
2775 } else if (u132->going > 0) {
2776 dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
2777 "ed\n", hcd);
2778 return -ESHUTDOWN;
2779 } else {
2780 int i, changed = 0, length = 1;
2781 if (u132->flags & OHCI_QUIRK_AMD756) {
2782 if ((u132->hc_roothub_a & RH_A_NDP) > MAX_ROOT_PORTS) {
2783 dev_err(&u132->platform_dev->dev, "bogus NDP, r"
2784 "ereads as NDP=%d\n",
2785 u132->hc_roothub_a & RH_A_NDP);
2786 goto done;
2787 }
2788 }
2789 if (u132->hc_roothub_status & (RH_HS_LPSC | RH_HS_OCIC))
2790 buf[0] = changed = 1;
2791 else
2792 buf[0] = 0;
2793 if (u132->num_ports > 7) {
2794 buf[1] = 0;
2795 length++;
2796 }
2797 for (i = 0; i < u132->num_ports; i++) {
2798 if (u132->hc_roothub_portstatus[i] & (RH_PS_CSC |
2799 RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC |
2800 RH_PS_PRSC)) {
2801 changed = 1;
2802 if (i < 7)
2803 buf[0] |= 1 << (i + 1);
2804 else
2805 buf[1] |= 1 << (i - 7);
2806 continue;
2807 }
2808 if (!(u132->hc_roothub_portstatus[i] & RH_PS_CCS))
2809 continue;
2810
2811 if ((u132->hc_roothub_portstatus[i] & RH_PS_PSS))
2812 continue;
2813 }
2814done:
2815 return changed ? length : 0;
2816 }
Tony Olechd774efe2006-09-13 11:27:35 +01002817}
2818
2819static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002820 u16 wIndex, char *buf, u16 wLength)
Tony Olechd774efe2006-09-13 11:27:35 +01002821{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002822 struct u132 *u132 = hcd_to_u132(hcd);
2823 if (u132->going > 1) {
2824 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
2825 , u132->going);
2826 return -ENODEV;
2827 } else if (u132->going > 0) {
2828 dev_err(&u132->platform_dev->dev, "device is being removed\n");
2829 return -ESHUTDOWN;
2830 } else {
2831 int retval = 0;
2832 mutex_lock(&u132->sw_lock);
2833 switch (typeReq) {
2834 case ClearHubFeature:
2835 switch (wValue) {
2836 case C_HUB_OVER_CURRENT:
2837 case C_HUB_LOCAL_POWER:
2838 break;
2839 default:
2840 goto stall;
2841 }
2842 break;
2843 case SetHubFeature:
2844 switch (wValue) {
2845 case C_HUB_OVER_CURRENT:
2846 case C_HUB_LOCAL_POWER:
2847 break;
2848 default:
2849 goto stall;
2850 }
2851 break;
2852 case ClearPortFeature:{
2853 retval = u132_roothub_clearportfeature(u132,
2854 wValue, wIndex);
2855 if (retval)
2856 goto error;
2857 break;
2858 }
2859 case GetHubDescriptor:{
2860 retval = u132_roothub_descriptor(u132,
2861 (struct usb_hub_descriptor *)buf);
2862 if (retval)
2863 goto error;
2864 break;
2865 }
2866 case GetHubStatus:{
2867 retval = u132_roothub_status(u132,
2868 (__le32 *) buf);
2869 if (retval)
2870 goto error;
2871 break;
2872 }
2873 case GetPortStatus:{
2874 retval = u132_roothub_portstatus(u132,
2875 (__le32 *) buf, wIndex);
2876 if (retval)
2877 goto error;
2878 break;
2879 }
2880 case SetPortFeature:{
2881 retval = u132_roothub_setportfeature(u132,
2882 wValue, wIndex);
2883 if (retval)
2884 goto error;
2885 break;
2886 }
2887 default:
2888 goto stall;
2889 error:
2890 u132_disable(u132);
2891 u132->going = 1;
2892 break;
2893 stall:
2894 retval = -EPIPE;
2895 break;
2896 }
2897 mutex_unlock(&u132->sw_lock);
2898 return retval;
2899 }
Tony Olechd774efe2006-09-13 11:27:35 +01002900}
2901
2902static int u132_start_port_reset(struct usb_hcd *hcd, unsigned port_num)
2903{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002904 struct u132 *u132 = hcd_to_u132(hcd);
2905 if (u132->going > 1) {
2906 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
2907 , u132->going);
2908 return -ENODEV;
2909 } else if (u132->going > 0) {
2910 dev_err(&u132->platform_dev->dev, "device is being removed\n");
2911 return -ESHUTDOWN;
2912 } else
2913 return 0;
Tony Olechd774efe2006-09-13 11:27:35 +01002914}
2915
Tony Olechd774efe2006-09-13 11:27:35 +01002916
2917#ifdef CONFIG_PM
Tony Olechd774efe2006-09-13 11:27:35 +01002918static int u132_bus_suspend(struct usb_hcd *hcd)
2919{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002920 struct u132 *u132 = hcd_to_u132(hcd);
2921 if (u132->going > 1) {
2922 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
2923 , u132->going);
2924 return -ENODEV;
2925 } else if (u132->going > 0) {
2926 dev_err(&u132->platform_dev->dev, "device is being removed\n");
2927 return -ESHUTDOWN;
2928 } else
2929 return 0;
Tony Olechd774efe2006-09-13 11:27:35 +01002930}
2931
2932static int u132_bus_resume(struct usb_hcd *hcd)
2933{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002934 struct u132 *u132 = hcd_to_u132(hcd);
2935 if (u132->going > 1) {
2936 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
2937 , u132->going);
2938 return -ENODEV;
2939 } else if (u132->going > 0) {
2940 dev_err(&u132->platform_dev->dev, "device is being removed\n");
2941 return -ESHUTDOWN;
2942 } else
2943 return 0;
Tony Olechd774efe2006-09-13 11:27:35 +01002944}
2945
2946#else
Tony Olechd774efe2006-09-13 11:27:35 +01002947#define u132_bus_suspend NULL
2948#define u132_bus_resume NULL
2949#endif
2950static struct hc_driver u132_hc_driver = {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002951 .description = hcd_name,
2952 .hcd_priv_size = sizeof(struct u132),
2953 .irq = NULL,
2954 .flags = HCD_USB11 | HCD_MEMORY,
2955 .reset = u132_hcd_reset,
2956 .start = u132_hcd_start,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002957 .stop = u132_hcd_stop,
2958 .urb_enqueue = u132_urb_enqueue,
2959 .urb_dequeue = u132_urb_dequeue,
2960 .endpoint_disable = u132_endpoint_disable,
2961 .get_frame_number = u132_get_frame,
2962 .hub_status_data = u132_hub_status_data,
2963 .hub_control = u132_hub_control,
2964 .bus_suspend = u132_bus_suspend,
2965 .bus_resume = u132_bus_resume,
2966 .start_port_reset = u132_start_port_reset,
Tony Olechd774efe2006-09-13 11:27:35 +01002967};
2968
2969/*
2970* This function may be called by the USB core whilst the "usb_all_devices_rwsem"
2971* is held for writing, thus this module must not call usb_remove_hcd()
2972* synchronously - but instead should immediately stop activity to the
Matt LaPlante0779bf22006-11-30 05:24:39 +01002973* device and asynchronously call usb_remove_hcd()
Tony Olechd774efe2006-09-13 11:27:35 +01002974*/
Bill Pembertonfb4e98a2012-11-19 13:26:20 -05002975static int u132_remove(struct platform_device *pdev)
Tony Olechd774efe2006-09-13 11:27:35 +01002976{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002977 struct usb_hcd *hcd = platform_get_drvdata(pdev);
2978 if (hcd) {
2979 struct u132 *u132 = hcd_to_u132(hcd);
2980 if (u132->going++ > 1) {
2981 dev_err(&u132->platform_dev->dev, "already being remove"
Tony Olech4b873612006-12-06 13:16:22 +00002982 "d\n");
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002983 return -ENODEV;
2984 } else {
2985 int rings = MAX_U132_RINGS;
2986 int endps = MAX_U132_ENDPS;
2987 dev_err(&u132->platform_dev->dev, "removing device u132"
Tony Olech4b873612006-12-06 13:16:22 +00002988 ".%d\n", u132->sequence_num);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002989 msleep(100);
2990 mutex_lock(&u132->sw_lock);
2991 u132_monitor_cancel_work(u132);
2992 while (rings-- > 0) {
2993 struct u132_ring *ring = &u132->ring[rings];
2994 u132_ring_cancel_work(u132, ring);
2995 } while (endps-- > 0) {
2996 struct u132_endp *endp = u132->endp[endps];
2997 if (endp)
2998 u132_endp_cancel_work(u132, endp);
2999 }
3000 u132->going += 1;
3001 printk(KERN_INFO "removing device u132.%d\n",
3002 u132->sequence_num);
3003 mutex_unlock(&u132->sw_lock);
3004 usb_remove_hcd(hcd);
3005 u132_u132_put_kref(u132);
3006 return 0;
3007 }
3008 } else
3009 return 0;
Tony Olechd774efe2006-09-13 11:27:35 +01003010}
3011
3012static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
3013{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003014 int rings = MAX_U132_RINGS;
3015 int ports = MAX_U132_PORTS;
3016 int addrs = MAX_U132_ADDRS;
3017 int udevs = MAX_U132_UDEVS;
3018 int endps = MAX_U132_ENDPS;
Jingoo Hand4f09e22013-07-30 19:59:40 +09003019 u132->board = dev_get_platdata(&pdev->dev);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003020 u132->platform_dev = pdev;
3021 u132->power = 0;
3022 u132->reset = 0;
3023 mutex_init(&u132->sw_lock);
Daniel Walker50d8ca92008-03-23 00:00:02 -07003024 mutex_init(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003025 while (rings-- > 0) {
3026 struct u132_ring *ring = &u132->ring[rings];
3027 ring->u132 = u132;
3028 ring->number = rings + 1;
3029 ring->length = 0;
3030 ring->curr_endp = NULL;
3031 INIT_DELAYED_WORK(&ring->scheduler,
David Howellsc4028952006-11-22 14:57:56 +00003032 u132_hcd_ring_work_scheduler);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003033 }
3034 mutex_lock(&u132->sw_lock);
3035 INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work);
3036 while (ports-- > 0) {
3037 struct u132_port *port = &u132->port[ports];
3038 port->u132 = u132;
3039 port->reset = 0;
3040 port->enable = 0;
3041 port->power = 0;
3042 port->Status = 0;
3043 }
3044 while (addrs-- > 0) {
3045 struct u132_addr *addr = &u132->addr[addrs];
3046 addr->address = 0;
3047 }
3048 while (udevs-- > 0) {
3049 struct u132_udev *udev = &u132->udev[udevs];
3050 int i = ARRAY_SIZE(udev->endp_number_in);
3051 int o = ARRAY_SIZE(udev->endp_number_out);
3052 udev->usb_device = NULL;
3053 udev->udev_number = 0;
3054 udev->usb_addr = 0;
3055 udev->portnumber = 0;
3056 while (i-- > 0)
3057 udev->endp_number_in[i] = 0;
3058
3059 while (o-- > 0)
3060 udev->endp_number_out[o] = 0;
3061
3062 }
3063 while (endps-- > 0)
3064 u132->endp[endps] = NULL;
3065
3066 mutex_unlock(&u132->sw_lock);
Tony Olechd774efe2006-09-13 11:27:35 +01003067}
3068
Bill Pemberton41ac7b32012-11-19 13:21:48 -05003069static int u132_probe(struct platform_device *pdev)
Tony Olechd774efe2006-09-13 11:27:35 +01003070{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003071 struct usb_hcd *hcd;
3072 int retval;
3073 u32 control;
3074 u32 rh_a = -1;
3075 u32 num_ports;
3076
3077 msleep(100);
3078 if (u132_exiting > 0)
3079 return -ENODEV;
3080
3081 retval = ftdi_write_pcimem(pdev, intrdisable, OHCI_INTR_MIE);
3082 if (retval)
3083 return retval;
3084 retval = ftdi_read_pcimem(pdev, control, &control);
3085 if (retval)
3086 return retval;
3087 retval = ftdi_read_pcimem(pdev, roothub.a, &rh_a);
3088 if (retval)
3089 return retval;
3090 num_ports = rh_a & RH_A_NDP; /* refuse to confuse usbcore */
3091 if (pdev->dev.dma_mask)
3092 return -EINVAL;
3093
Kay Sievers7071a3c2008-05-02 06:02:41 +02003094 hcd = usb_create_hcd(&u132_hc_driver, &pdev->dev, dev_name(&pdev->dev));
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003095 if (!hcd) {
3096 printk(KERN_ERR "failed to create the usb hcd struct for U132\n"
3097 );
3098 ftdi_elan_gone_away(pdev);
3099 return -ENOMEM;
3100 } else {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003101 struct u132 *u132 = hcd_to_u132(hcd);
Bill Pemberton66414452010-04-29 10:04:56 -04003102 retval = 0;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003103 hcd->rsrc_start = 0;
3104 mutex_lock(&u132_module_lock);
3105 list_add_tail(&u132->u132_list, &u132_static_list);
3106 u132->sequence_num = ++u132_instances;
3107 mutex_unlock(&u132_module_lock);
3108 u132_u132_init_kref(u132);
3109 u132_initialise(u132, pdev);
3110 hcd->product_desc = "ELAN U132 Host Controller";
3111 retval = usb_add_hcd(hcd, 0, 0);
3112 if (retval != 0) {
3113 dev_err(&u132->platform_dev->dev, "init error %d\n",
3114 retval);
3115 u132_u132_put_kref(u132);
3116 return retval;
3117 } else {
Peter Chen3c9740a2013-11-05 10:46:02 +08003118 device_wakeup_enable(hcd->self.controller);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003119 u132_monitor_queue_work(u132, 100);
3120 return 0;
3121 }
3122 }
Tony Olechd774efe2006-09-13 11:27:35 +01003123}
3124
3125
3126#ifdef CONFIG_PM
Alan Stern84ebc102013-03-27 16:14:46 -04003127/*
3128 * for this device there's no useful distinction between the controller
Rafael J. Wysockiceb6c9c2014-11-29 23:47:05 +01003129 * and its root hub.
Alan Stern84ebc102013-03-27 16:14:46 -04003130 */
Tony Olechd774efe2006-09-13 11:27:35 +01003131static int u132_suspend(struct platform_device *pdev, pm_message_t state)
3132{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003133 struct usb_hcd *hcd = platform_get_drvdata(pdev);
3134 struct u132 *u132 = hcd_to_u132(hcd);
3135 if (u132->going > 1) {
3136 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
3137 , u132->going);
3138 return -ENODEV;
3139 } else if (u132->going > 0) {
3140 dev_err(&u132->platform_dev->dev, "device is being removed\n");
3141 return -ESHUTDOWN;
3142 } else {
Mirco Tischler038eb0e2008-02-24 05:16:39 +01003143 int retval = 0, ports;
Rafael J. Wysocki3a2d5b72008-02-23 19:13:25 +01003144
3145 switch (state.event) {
3146 case PM_EVENT_FREEZE:
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003147 retval = u132_bus_suspend(hcd);
Rafael J. Wysocki3a2d5b72008-02-23 19:13:25 +01003148 break;
3149 case PM_EVENT_SUSPEND:
3150 case PM_EVENT_HIBERNATE:
Mirco Tischler038eb0e2008-02-24 05:16:39 +01003151 ports = MAX_U132_PORTS;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003152 while (ports-- > 0) {
3153 port_power(u132, ports, 0);
3154 }
Rafael J. Wysocki3a2d5b72008-02-23 19:13:25 +01003155 break;
3156 }
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003157 return retval;
3158 }
Tony Olechd774efe2006-09-13 11:27:35 +01003159}
3160
3161static int u132_resume(struct platform_device *pdev)
3162{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003163 struct usb_hcd *hcd = platform_get_drvdata(pdev);
3164 struct u132 *u132 = hcd_to_u132(hcd);
3165 if (u132->going > 1) {
3166 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
3167 , u132->going);
3168 return -ENODEV;
3169 } else if (u132->going > 0) {
3170 dev_err(&u132->platform_dev->dev, "device is being removed\n");
3171 return -ESHUTDOWN;
3172 } else {
3173 int retval = 0;
Alan Stern70a1c9e2008-03-06 17:00:58 -05003174 if (!u132->port[0].power) {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003175 int ports = MAX_U132_PORTS;
3176 while (ports-- > 0) {
3177 port_power(u132, ports, 1);
3178 }
3179 retval = 0;
3180 } else {
3181 retval = u132_bus_resume(hcd);
3182 }
3183 return retval;
3184 }
Tony Olechd774efe2006-09-13 11:27:35 +01003185}
3186
3187#else
3188#define u132_suspend NULL
3189#define u132_resume NULL
3190#endif
3191/*
Matt LaPlante0779bf22006-11-30 05:24:39 +01003192* this driver is loaded explicitly by ftdi_u132
Tony Olechd774efe2006-09-13 11:27:35 +01003193*
3194* the platform_driver struct is static because it is per type of module
3195*/
3196static struct platform_driver u132_platform_driver = {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003197 .probe = u132_probe,
Bill Pemberton76904172012-11-19 13:21:08 -05003198 .remove = u132_remove,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003199 .suspend = u132_suspend,
3200 .resume = u132_resume,
3201 .driver = {
Geert Uytterhoevena4586772013-11-12 20:07:25 +01003202 .name = hcd_name,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003203 },
Tony Olechd774efe2006-09-13 11:27:35 +01003204};
3205static int __init u132_hcd_init(void)
3206{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003207 int retval;
3208 INIT_LIST_HEAD(&u132_static_list);
3209 u132_instances = 0;
3210 u132_exiting = 0;
3211 mutex_init(&u132_module_lock);
3212 if (usb_disabled())
3213 return -ENODEV;
Michal Marek654d1212011-04-05 16:59:11 +02003214 printk(KERN_INFO "driver %s\n", hcd_name);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003215 workqueue = create_singlethread_workqueue("u132");
3216 retval = platform_driver_register(&u132_platform_driver);
3217 return retval;
Tony Olechd774efe2006-09-13 11:27:35 +01003218}
3219
3220
3221module_init(u132_hcd_init);
3222static void __exit u132_hcd_exit(void)
3223{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003224 struct u132 *u132;
3225 struct u132 *temp;
3226 mutex_lock(&u132_module_lock);
3227 u132_exiting += 1;
3228 mutex_unlock(&u132_module_lock);
3229 list_for_each_entry_safe(u132, temp, &u132_static_list, u132_list) {
3230 platform_device_unregister(u132->platform_dev);
3231 }
3232 platform_driver_unregister(&u132_platform_driver);
3233 printk(KERN_INFO "u132-hcd driver deregistered\n");
3234 wait_event(u132_hcd_wait, u132_instances == 0);
3235 flush_workqueue(workqueue);
3236 destroy_workqueue(workqueue);
Tony Olechd774efe2006-09-13 11:27:35 +01003237}
3238
3239
3240module_exit(u132_hcd_exit);
3241MODULE_LICENSE("GPL");
Kay Sieversf4fce612008-04-10 21:29:22 -07003242MODULE_ALIAS("platform:u132_hcd");