blob: 43d52931b5bf3509c7ca6255ddb82aa7b7c5cb98 [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*/
Geyslan G. Bem900937c2015-12-02 20:25:23 -030076static bool distrust_firmware = true;
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) {
Geliang Tang4e5d7a82015-12-19 00:34:29 +08001312 struct u132_endp *endp, *last_endp = ring->curr_endp;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001313 unsigned long wakeup = 0;
Geliang Tang4e5d7a82015-12-19 00:34:29 +08001314 list_for_each_entry(endp, &last_endp->endp_ring, endp_ring) {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001315 if (endp->queue_next == endp->queue_last) {
1316 } else if ((endp->delayed == 0)
1317 || time_after_eq(jiffies, endp->jiffies)) {
1318 ring->curr_endp = endp;
1319 u132_endp_cancel_work(u132, last_endp);
1320 u132_endp_queue_work(u132, last_endp, 0);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001321 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001322 u132_ring_put_kref(u132, ring);
1323 return;
1324 } else {
1325 unsigned long delta = endp->jiffies - jiffies;
1326 if (delta > wakeup)
1327 wakeup = delta;
1328 }
1329 }
1330 if (last_endp->queue_next == last_endp->queue_last) {
1331 } else if ((last_endp->delayed == 0) || time_after_eq(jiffies,
1332 last_endp->jiffies)) {
1333 u132_endp_cancel_work(u132, last_endp);
1334 u132_endp_queue_work(u132, last_endp, 0);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001335 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001336 u132_ring_put_kref(u132, ring);
1337 return;
1338 } else {
1339 unsigned long delta = last_endp->jiffies - jiffies;
1340 if (delta > wakeup)
1341 wakeup = delta;
1342 }
1343 if (wakeup > 0) {
1344 u132_ring_requeue_work(u132, ring, wakeup);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001345 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001346 return;
1347 } else {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001348 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001349 u132_ring_put_kref(u132, ring);
1350 return;
1351 }
1352 } else {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001353 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001354 u132_ring_put_kref(u132, ring);
1355 return;
1356 }
Tony Olechd774efe2006-09-13 11:27:35 +01001357}
1358
David Howellsc4028952006-11-22 14:57:56 +00001359static void u132_hcd_endp_work_scheduler(struct work_struct *work)
Tony Olechd774efe2006-09-13 11:27:35 +01001360{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001361 struct u132_ring *ring;
1362 struct u132_endp *endp =
David Howellsc4028952006-11-22 14:57:56 +00001363 container_of(work, struct u132_endp, scheduler.work);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001364 struct u132 *u132 = endp->u132;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001365 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001366 ring = endp->ring;
1367 if (endp->edset_flush) {
1368 endp->edset_flush = 0;
1369 if (endp->dequeueing)
1370 usb_ftdi_elan_edset_flush(u132->platform_dev,
1371 ring->number, endp);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001372 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001373 u132_endp_put_kref(u132, endp);
1374 return;
1375 } else if (endp->active) {
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 (ring->in_use) {
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 (endp->queue_next == endp->queue_last) {
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->pipetype == PIPE_INTERRUPT) {
1388 u8 address = u132->addr[endp->usb_addr].address;
1389 if (ring->in_use) {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001390 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001391 u132_endp_put_kref(u132, endp);
1392 return;
1393 } else {
1394 int retval;
1395 struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
1396 endp->queue_next];
1397 endp->active = 1;
1398 ring->curr_endp = endp;
1399 ring->in_use = 1;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001400 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001401 retval = edset_single(u132, ring, endp, urb, address,
1402 endp->toggle_bits, u132_hcd_interrupt_recv);
1403 if (retval != 0)
1404 u132_hcd_giveback_urb(u132, endp, urb, retval);
1405 return;
1406 }
1407 } else if (endp->pipetype == PIPE_CONTROL) {
1408 u8 address = u132->addr[endp->usb_addr].address;
1409 if (ring->in_use) {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001410 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001411 u132_endp_put_kref(u132, endp);
1412 return;
1413 } else if (address == 0) {
1414 int retval;
1415 struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
1416 endp->queue_next];
1417 endp->active = 1;
1418 ring->curr_endp = endp;
1419 ring->in_use = 1;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001420 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001421 retval = edset_setup(u132, ring, endp, urb, address,
1422 0x2, u132_hcd_initial_setup_sent);
1423 if (retval != 0)
1424 u132_hcd_giveback_urb(u132, endp, urb, retval);
1425 return;
1426 } else if (endp->usb_addr == 0) {
1427 int retval;
1428 struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
1429 endp->queue_next];
1430 endp->active = 1;
1431 ring->curr_endp = endp;
1432 ring->in_use = 1;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001433 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001434 retval = edset_setup(u132, ring, endp, urb, 0, 0x2,
1435 u132_hcd_enumeration_address_sent);
1436 if (retval != 0)
1437 u132_hcd_giveback_urb(u132, endp, urb, retval);
1438 return;
1439 } else {
1440 int retval;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001441 struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
1442 endp->queue_next];
Randy Dunlap1d6ec812010-05-06 16:46:03 -07001443 address = u132->addr[endp->usb_addr].address;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001444 endp->active = 1;
1445 ring->curr_endp = endp;
1446 ring->in_use = 1;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001447 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001448 retval = edset_setup(u132, ring, endp, urb, address,
1449 0x2, u132_hcd_configure_setup_sent);
1450 if (retval != 0)
1451 u132_hcd_giveback_urb(u132, endp, urb, retval);
1452 return;
1453 }
1454 } else {
1455 if (endp->input) {
1456 u8 address = u132->addr[endp->usb_addr].address;
1457 if (ring->in_use) {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001458 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001459 u132_endp_put_kref(u132, endp);
1460 return;
1461 } else {
1462 int retval;
1463 struct urb *urb = endp->urb_list[
1464 ENDP_QUEUE_MASK & endp->queue_next];
1465 endp->active = 1;
1466 ring->curr_endp = endp;
1467 ring->in_use = 1;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001468 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001469 retval = edset_input(u132, ring, endp, urb,
1470 address, endp->toggle_bits,
1471 u132_hcd_bulk_input_recv);
1472 if (retval == 0) {
1473 } else
1474 u132_hcd_giveback_urb(u132, endp, urb,
1475 retval);
1476 return;
1477 }
1478 } else { /* output pipe */
1479 u8 address = u132->addr[endp->usb_addr].address;
1480 if (ring->in_use) {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001481 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001482 u132_endp_put_kref(u132, endp);
1483 return;
1484 } else {
1485 int retval;
1486 struct urb *urb = endp->urb_list[
1487 ENDP_QUEUE_MASK & endp->queue_next];
1488 endp->active = 1;
1489 ring->curr_endp = endp;
1490 ring->in_use = 1;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001491 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001492 retval = edset_output(u132, ring, endp, urb,
1493 address, endp->toggle_bits,
1494 u132_hcd_bulk_output_sent);
1495 if (retval == 0) {
1496 } else
1497 u132_hcd_giveback_urb(u132, endp, urb,
1498 retval);
1499 return;
1500 }
1501 }
1502 }
Tony Olechd774efe2006-09-13 11:27:35 +01001503}
Gabriel C5b570d42007-07-30 12:57:03 +02001504#ifdef CONFIG_PM
Tony Olechd774efe2006-09-13 11:27:35 +01001505
1506static void port_power(struct u132 *u132, int pn, int is_on)
1507{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001508 u132->port[pn].power = is_on;
Tony Olechd774efe2006-09-13 11:27:35 +01001509}
1510
Gabriel C5b570d42007-07-30 12:57:03 +02001511#endif
1512
Tony Olechd774efe2006-09-13 11:27:35 +01001513static void u132_power(struct u132 *u132, int is_on)
1514{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001515 struct usb_hcd *hcd = u132_to_hcd(u132)
1516 ; /* hub is inactive unless the port is powered */
1517 if (is_on) {
1518 if (u132->power)
1519 return;
1520 u132->power = 1;
1521 } else {
1522 u132->power = 0;
1523 hcd->state = HC_STATE_HALT;
1524 }
Tony Olechd774efe2006-09-13 11:27:35 +01001525}
1526
1527static int u132_periodic_reinit(struct u132 *u132)
1528{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001529 int retval;
1530 u32 fi = u132->hc_fminterval & 0x03fff;
1531 u32 fit;
1532 u32 fminterval;
1533 retval = u132_read_pcimem(u132, fminterval, &fminterval);
1534 if (retval)
1535 return retval;
1536 fit = fminterval & FIT;
1537 retval = u132_write_pcimem(u132, fminterval,
1538 (fit ^ FIT) | u132->hc_fminterval);
1539 if (retval)
1540 return retval;
Saurabh Karajgaonkar8602b082015-08-04 14:03:45 +00001541 return u132_write_pcimem(u132, periodicstart,
1542 ((9 * fi) / 10) & 0x3fff);
Tony Olechd774efe2006-09-13 11:27:35 +01001543}
1544
1545static char *hcfs2string(int state)
1546{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001547 switch (state) {
1548 case OHCI_USB_RESET:
1549 return "reset";
1550 case OHCI_USB_RESUME:
1551 return "resume";
1552 case OHCI_USB_OPER:
1553 return "operational";
1554 case OHCI_USB_SUSPEND:
1555 return "suspend";
1556 }
1557 return "?";
Tony Olechd774efe2006-09-13 11:27:35 +01001558}
1559
Tony Olechd774efe2006-09-13 11:27:35 +01001560static int u132_init(struct u132 *u132)
1561{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001562 int retval;
1563 u32 control;
1564 u132_disable(u132);
1565 u132->next_statechange = jiffies;
1566 retval = u132_write_pcimem(u132, intrdisable, OHCI_INTR_MIE);
1567 if (retval)
1568 return retval;
1569 retval = u132_read_pcimem(u132, control, &control);
1570 if (retval)
1571 return retval;
1572 if (u132->num_ports == 0) {
1573 u32 rh_a = -1;
1574 retval = u132_read_pcimem(u132, roothub.a, &rh_a);
1575 if (retval)
1576 return retval;
1577 u132->num_ports = rh_a & RH_A_NDP;
1578 retval = read_roothub_info(u132);
1579 if (retval)
1580 return retval;
1581 }
1582 if (u132->num_ports > MAX_U132_PORTS)
1583 return -EINVAL;
1584
1585 return 0;
Tony Olechd774efe2006-09-13 11:27:35 +01001586}
1587
1588
1589/* Start an OHCI controller, set the BUS operational
1590* resets USB and controller
1591* enable interrupts
1592*/
1593static int u132_run(struct u132 *u132)
1594{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001595 int retval;
1596 u32 control;
1597 u32 status;
1598 u32 fminterval;
1599 u32 periodicstart;
1600 u32 cmdstatus;
1601 u32 roothub_a;
1602 int mask = OHCI_INTR_INIT;
1603 int first = u132->hc_fminterval == 0;
1604 int sleep_time = 0;
1605 int reset_timeout = 30; /* ... allow extra time */
1606 u132_disable(u132);
1607 if (first) {
1608 u32 temp;
1609 retval = u132_read_pcimem(u132, fminterval, &temp);
1610 if (retval)
1611 return retval;
1612 u132->hc_fminterval = temp & 0x3fff;
1613 u132->hc_fminterval |= FSMP(u132->hc_fminterval) << 16;
1614 }
1615 retval = u132_read_pcimem(u132, control, &u132->hc_control);
1616 if (retval)
1617 return retval;
1618 dev_info(&u132->platform_dev->dev, "resetting from state '%s', control "
1619 "= %08X\n", hcfs2string(u132->hc_control & OHCI_CTRL_HCFS),
1620 u132->hc_control);
1621 switch (u132->hc_control & OHCI_CTRL_HCFS) {
1622 case OHCI_USB_OPER:
1623 sleep_time = 0;
1624 break;
1625 case OHCI_USB_SUSPEND:
1626 case OHCI_USB_RESUME:
1627 u132->hc_control &= OHCI_CTRL_RWC;
1628 u132->hc_control |= OHCI_USB_RESUME;
1629 sleep_time = 10;
1630 break;
1631 default:
1632 u132->hc_control &= OHCI_CTRL_RWC;
1633 u132->hc_control |= OHCI_USB_RESET;
1634 sleep_time = 50;
1635 break;
1636 }
1637 retval = u132_write_pcimem(u132, control, u132->hc_control);
1638 if (retval)
1639 return retval;
1640 retval = u132_read_pcimem(u132, control, &control);
1641 if (retval)
1642 return retval;
1643 msleep(sleep_time);
1644 retval = u132_read_pcimem(u132, roothub.a, &roothub_a);
1645 if (retval)
1646 return retval;
1647 if (!(roothub_a & RH_A_NPS)) {
1648 int temp; /* power down each port */
1649 for (temp = 0; temp < u132->num_ports; temp++) {
1650 retval = u132_write_pcimem(u132,
1651 roothub.portstatus[temp], RH_PS_LSDA);
1652 if (retval)
1653 return retval;
1654 }
1655 }
1656 retval = u132_read_pcimem(u132, control, &control);
1657 if (retval)
1658 return retval;
1659retry:
1660 retval = u132_read_pcimem(u132, cmdstatus, &status);
1661 if (retval)
1662 return retval;
1663 retval = u132_write_pcimem(u132, cmdstatus, OHCI_HCR);
1664 if (retval)
1665 return retval;
1666extra: {
1667 retval = u132_read_pcimem(u132, cmdstatus, &status);
1668 if (retval)
1669 return retval;
1670 if (0 != (status & OHCI_HCR)) {
1671 if (--reset_timeout == 0) {
1672 dev_err(&u132->platform_dev->dev, "USB HC reset"
1673 " timed out!\n");
1674 return -ENODEV;
1675 } else {
1676 msleep(5);
1677 goto extra;
1678 }
1679 }
1680 }
1681 if (u132->flags & OHCI_QUIRK_INITRESET) {
1682 retval = u132_write_pcimem(u132, control, u132->hc_control);
1683 if (retval)
1684 return retval;
1685 retval = u132_read_pcimem(u132, control, &control);
1686 if (retval)
1687 return retval;
1688 }
1689 retval = u132_write_pcimem(u132, ed_controlhead, 0x00000000);
1690 if (retval)
1691 return retval;
1692 retval = u132_write_pcimem(u132, ed_bulkhead, 0x11000000);
1693 if (retval)
1694 return retval;
1695 retval = u132_write_pcimem(u132, hcca, 0x00000000);
1696 if (retval)
1697 return retval;
1698 retval = u132_periodic_reinit(u132);
1699 if (retval)
1700 return retval;
1701 retval = u132_read_pcimem(u132, fminterval, &fminterval);
1702 if (retval)
1703 return retval;
1704 retval = u132_read_pcimem(u132, periodicstart, &periodicstart);
1705 if (retval)
1706 return retval;
1707 if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) {
1708 if (!(u132->flags & OHCI_QUIRK_INITRESET)) {
1709 u132->flags |= OHCI_QUIRK_INITRESET;
1710 goto retry;
1711 } else
1712 dev_err(&u132->platform_dev->dev, "init err(%08x %04x)"
1713 "\n", fminterval, periodicstart);
1714 } /* start controller operations */
1715 u132->hc_control &= OHCI_CTRL_RWC;
1716 u132->hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER;
1717 retval = u132_write_pcimem(u132, control, u132->hc_control);
1718 if (retval)
1719 return retval;
1720 retval = u132_write_pcimem(u132, cmdstatus, OHCI_BLF);
1721 if (retval)
1722 return retval;
1723 retval = u132_read_pcimem(u132, cmdstatus, &cmdstatus);
1724 if (retval)
1725 return retval;
1726 retval = u132_read_pcimem(u132, control, &control);
1727 if (retval)
1728 return retval;
1729 u132_to_hcd(u132)->state = HC_STATE_RUNNING;
1730 retval = u132_write_pcimem(u132, roothub.status, RH_HS_DRWE);
1731 if (retval)
1732 return retval;
1733 retval = u132_write_pcimem(u132, intrstatus, mask);
1734 if (retval)
1735 return retval;
1736 retval = u132_write_pcimem(u132, intrdisable,
1737 OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO |
1738 OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH |
1739 OHCI_INTR_SO);
1740 if (retval)
1741 return retval; /* handle root hub init quirks ... */
1742 retval = u132_read_pcimem(u132, roothub.a, &roothub_a);
1743 if (retval)
1744 return retval;
1745 roothub_a &= ~(RH_A_PSM | RH_A_OCPM);
1746 if (u132->flags & OHCI_QUIRK_SUPERIO) {
1747 roothub_a |= RH_A_NOCP;
1748 roothub_a &= ~(RH_A_POTPGT | RH_A_NPS);
1749 retval = u132_write_pcimem(u132, roothub.a, roothub_a);
1750 if (retval)
1751 return retval;
1752 } else if ((u132->flags & OHCI_QUIRK_AMD756) || distrust_firmware) {
1753 roothub_a |= RH_A_NPS;
1754 retval = u132_write_pcimem(u132, roothub.a, roothub_a);
1755 if (retval)
1756 return retval;
1757 }
1758 retval = u132_write_pcimem(u132, roothub.status, RH_HS_LPSC);
1759 if (retval)
1760 return retval;
1761 retval = u132_write_pcimem(u132, roothub.b,
1762 (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM);
1763 if (retval)
1764 return retval;
1765 retval = u132_read_pcimem(u132, control, &control);
1766 if (retval)
1767 return retval;
1768 mdelay((roothub_a >> 23) & 0x1fe);
1769 u132_to_hcd(u132)->state = HC_STATE_RUNNING;
1770 return 0;
Tony Olechd774efe2006-09-13 11:27:35 +01001771}
1772
1773static void u132_hcd_stop(struct usb_hcd *hcd)
1774{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001775 struct u132 *u132 = hcd_to_u132(hcd);
1776 if (u132->going > 1) {
1777 dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p) has b"
1778 "een removed %d\n", u132, hcd, u132->going);
1779 } else if (u132->going > 0) {
1780 dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
1781 "ed\n", hcd);
1782 } else {
1783 mutex_lock(&u132->sw_lock);
1784 msleep(100);
1785 u132_power(u132, 0);
1786 mutex_unlock(&u132->sw_lock);
1787 }
Tony Olechd774efe2006-09-13 11:27:35 +01001788}
1789
1790static int u132_hcd_start(struct usb_hcd *hcd)
1791{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001792 struct u132 *u132 = hcd_to_u132(hcd);
1793 if (u132->going > 1) {
1794 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
1795 , u132->going);
1796 return -ENODEV;
1797 } else if (u132->going > 0) {
1798 dev_err(&u132->platform_dev->dev, "device is being removed\n");
1799 return -ESHUTDOWN;
1800 } else if (hcd->self.controller) {
1801 int retval;
1802 struct platform_device *pdev =
1803 to_platform_device(hcd->self.controller);
1804 u16 vendor = ((struct u132_platform_data *)
Jingoo Hand4f09e22013-07-30 19:59:40 +09001805 dev_get_platdata(&pdev->dev))->vendor;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001806 u16 device = ((struct u132_platform_data *)
Jingoo Hand4f09e22013-07-30 19:59:40 +09001807 dev_get_platdata(&pdev->dev))->device;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001808 mutex_lock(&u132->sw_lock);
1809 msleep(10);
1810 if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) {
1811 u132->flags = OHCI_QUIRK_AMD756;
1812 } else if (vendor == PCI_VENDOR_ID_OPTI && device == 0xc861) {
1813 dev_err(&u132->platform_dev->dev, "WARNING: OPTi workar"
1814 "ounds unavailable\n");
1815 } else if (vendor == PCI_VENDOR_ID_COMPAQ && device == 0xa0f8)
1816 u132->flags |= OHCI_QUIRK_ZFMICRO;
1817 retval = u132_run(u132);
1818 if (retval) {
1819 u132_disable(u132);
1820 u132->going = 1;
1821 }
1822 msleep(100);
1823 mutex_unlock(&u132->sw_lock);
1824 return retval;
1825 } else {
1826 dev_err(&u132->platform_dev->dev, "platform_device missing\n");
1827 return -ENODEV;
1828 }
Tony Olechd774efe2006-09-13 11:27:35 +01001829}
1830
1831static int u132_hcd_reset(struct usb_hcd *hcd)
1832{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001833 struct u132 *u132 = hcd_to_u132(hcd);
1834 if (u132->going > 1) {
1835 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
1836 , u132->going);
1837 return -ENODEV;
1838 } else if (u132->going > 0) {
1839 dev_err(&u132->platform_dev->dev, "device is being removed\n");
1840 return -ESHUTDOWN;
1841 } else {
1842 int retval;
1843 mutex_lock(&u132->sw_lock);
1844 retval = u132_init(u132);
1845 if (retval) {
1846 u132_disable(u132);
1847 u132->going = 1;
1848 }
1849 mutex_unlock(&u132->sw_lock);
1850 return retval;
1851 }
Tony Olechd774efe2006-09-13 11:27:35 +01001852}
1853
1854static int create_endpoint_and_queue_int(struct u132 *u132,
Alan Sterne9df41c2007-08-08 11:48:02 -04001855 struct u132_udev *udev, struct urb *urb,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001856 struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
1857 gfp_t mem_flags)
Tony Olechd774efe2006-09-13 11:27:35 +01001858{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001859 struct u132_ring *ring;
Alan Sterne9df41c2007-08-08 11:48:02 -04001860 unsigned long irqs;
1861 int rc;
1862 u8 endp_number;
1863 struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
1864
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001865 if (!endp)
1866 return -ENOMEM;
Alan Sterne9df41c2007-08-08 11:48:02 -04001867
1868 spin_lock_init(&endp->queue_lock.slock);
1869 spin_lock_irqsave(&endp->queue_lock.slock, irqs);
1870 rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
1871 if (rc) {
1872 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
1873 kfree(endp);
1874 return rc;
1875 }
1876
1877 endp_number = ++u132->num_endpoints;
1878 urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001879 INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
1880 INIT_LIST_HEAD(&endp->urb_more);
1881 ring = endp->ring = &u132->ring[0];
1882 if (ring->curr_endp) {
1883 list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring);
1884 } else {
1885 INIT_LIST_HEAD(&endp->endp_ring);
1886 ring->curr_endp = endp;
1887 }
1888 ring->length += 1;
1889 endp->dequeueing = 0;
1890 endp->edset_flush = 0;
1891 endp->active = 0;
1892 endp->delayed = 0;
1893 endp->endp_number = endp_number;
1894 endp->u132 = u132;
Alan Sterne9df41c2007-08-08 11:48:02 -04001895 endp->hep = urb->ep;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001896 endp->pipetype = usb_pipetype(urb->pipe);
1897 u132_endp_init_kref(u132, endp);
1898 if (usb_pipein(urb->pipe)) {
1899 endp->toggle_bits = 0x2;
1900 usb_settoggle(udev->usb_device, usb_endp, 0, 0);
1901 endp->input = 1;
1902 endp->output = 0;
1903 udev->endp_number_in[usb_endp] = endp_number;
1904 u132_udev_get_kref(u132, udev);
1905 } else {
1906 endp->toggle_bits = 0x2;
1907 usb_settoggle(udev->usb_device, usb_endp, 1, 0);
1908 endp->input = 0;
1909 endp->output = 1;
1910 udev->endp_number_out[usb_endp] = endp_number;
1911 u132_udev_get_kref(u132, udev);
1912 }
1913 urb->hcpriv = u132;
1914 endp->delayed = 1;
1915 endp->jiffies = jiffies + msecs_to_jiffies(urb->interval);
1916 endp->udev_number = address;
1917 endp->usb_addr = usb_addr;
1918 endp->usb_endp = usb_endp;
1919 endp->queue_size = 1;
1920 endp->queue_last = 0;
1921 endp->queue_next = 0;
1922 endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
1923 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
1924 u132_endp_queue_work(u132, endp, msecs_to_jiffies(urb->interval));
1925 return 0;
1926}
1927
1928static int queue_int_on_old_endpoint(struct u132 *u132,
1929 struct u132_udev *udev, struct urb *urb,
1930 struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
1931 u8 usb_endp, u8 address)
1932{
1933 urb->hcpriv = u132;
1934 endp->delayed = 1;
1935 endp->jiffies = jiffies + msecs_to_jiffies(urb->interval);
1936 if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
1937 endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
1938 } else {
1939 struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq),
1940 GFP_ATOMIC);
1941 if (urbq == NULL) {
1942 endp->queue_size -= 1;
1943 return -ENOMEM;
1944 } else {
1945 list_add_tail(&urbq->urb_more, &endp->urb_more);
1946 urbq->urb = urb;
1947 }
1948 }
1949 return 0;
1950}
1951
1952static int create_endpoint_and_queue_bulk(struct u132 *u132,
1953 struct u132_udev *udev, struct urb *urb,
1954 struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
1955 gfp_t mem_flags)
1956{
1957 int ring_number;
1958 struct u132_ring *ring;
1959 unsigned long irqs;
1960 int rc;
1961 u8 endp_number;
1962 struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
1963
1964 if (!endp)
1965 return -ENOMEM;
1966
1967 spin_lock_init(&endp->queue_lock.slock);
1968 spin_lock_irqsave(&endp->queue_lock.slock, irqs);
1969 rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
1970 if (rc) {
1971 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
1972 kfree(endp);
1973 return rc;
1974 }
1975
1976 endp_number = ++u132->num_endpoints;
1977 urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
1978 INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
1979 INIT_LIST_HEAD(&endp->urb_more);
1980 endp->dequeueing = 0;
1981 endp->edset_flush = 0;
1982 endp->active = 0;
1983 endp->delayed = 0;
1984 endp->endp_number = endp_number;
1985 endp->u132 = u132;
1986 endp->hep = urb->ep;
1987 endp->pipetype = usb_pipetype(urb->pipe);
1988 u132_endp_init_kref(u132, endp);
1989 if (usb_pipein(urb->pipe)) {
1990 endp->toggle_bits = 0x2;
1991 usb_settoggle(udev->usb_device, usb_endp, 0, 0);
1992 ring_number = 3;
1993 endp->input = 1;
1994 endp->output = 0;
1995 udev->endp_number_in[usb_endp] = endp_number;
1996 u132_udev_get_kref(u132, udev);
1997 } else {
1998 endp->toggle_bits = 0x2;
1999 usb_settoggle(udev->usb_device, usb_endp, 1, 0);
2000 ring_number = 2;
2001 endp->input = 0;
2002 endp->output = 1;
2003 udev->endp_number_out[usb_endp] = endp_number;
2004 u132_udev_get_kref(u132, udev);
2005 }
2006 ring = endp->ring = &u132->ring[ring_number - 1];
2007 if (ring->curr_endp) {
2008 list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring);
2009 } else {
2010 INIT_LIST_HEAD(&endp->endp_ring);
2011 ring->curr_endp = endp;
2012 }
2013 ring->length += 1;
2014 urb->hcpriv = u132;
2015 endp->udev_number = address;
2016 endp->usb_addr = usb_addr;
2017 endp->usb_endp = usb_endp;
2018 endp->queue_size = 1;
2019 endp->queue_last = 0;
2020 endp->queue_next = 0;
2021 endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
2022 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
2023 u132_endp_queue_work(u132, endp, 0);
2024 return 0;
2025}
2026
2027static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
2028 struct urb *urb,
2029 struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
2030 u8 usb_endp, u8 address)
2031{
2032 urb->hcpriv = u132;
2033 if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
2034 endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
2035 } else {
2036 struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq),
2037 GFP_ATOMIC);
2038 if (urbq == NULL) {
2039 endp->queue_size -= 1;
2040 return -ENOMEM;
2041 } else {
2042 list_add_tail(&urbq->urb_more, &endp->urb_more);
2043 urbq->urb = urb;
2044 }
2045 }
2046 return 0;
2047}
2048
2049static int create_endpoint_and_queue_control(struct u132 *u132,
2050 struct urb *urb,
2051 struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp,
2052 gfp_t mem_flags)
2053{
2054 struct u132_ring *ring;
2055 unsigned long irqs;
2056 int rc;
2057 u8 endp_number;
2058 struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
2059
2060 if (!endp)
2061 return -ENOMEM;
2062
2063 spin_lock_init(&endp->queue_lock.slock);
2064 spin_lock_irqsave(&endp->queue_lock.slock, irqs);
2065 rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
2066 if (rc) {
2067 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
2068 kfree(endp);
2069 return rc;
2070 }
2071
2072 endp_number = ++u132->num_endpoints;
2073 urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
2074 INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
2075 INIT_LIST_HEAD(&endp->urb_more);
2076 ring = endp->ring = &u132->ring[0];
2077 if (ring->curr_endp) {
2078 list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring);
2079 } else {
2080 INIT_LIST_HEAD(&endp->endp_ring);
2081 ring->curr_endp = endp;
2082 }
2083 ring->length += 1;
2084 endp->dequeueing = 0;
2085 endp->edset_flush = 0;
2086 endp->active = 0;
2087 endp->delayed = 0;
2088 endp->endp_number = endp_number;
2089 endp->u132 = u132;
2090 endp->hep = urb->ep;
2091 u132_endp_init_kref(u132, endp);
2092 u132_endp_get_kref(u132, endp);
2093 if (usb_addr == 0) {
2094 u8 address = u132->addr[usb_addr].address;
2095 struct u132_udev *udev = &u132->udev[address];
2096 endp->udev_number = address;
2097 endp->usb_addr = usb_addr;
2098 endp->usb_endp = usb_endp;
2099 endp->input = 1;
2100 endp->output = 1;
2101 endp->pipetype = usb_pipetype(urb->pipe);
2102 u132_udev_init_kref(u132, udev);
2103 u132_udev_get_kref(u132, udev);
2104 udev->endp_number_in[usb_endp] = endp_number;
2105 udev->endp_number_out[usb_endp] = endp_number;
2106 urb->hcpriv = u132;
2107 endp->queue_size = 1;
2108 endp->queue_last = 0;
2109 endp->queue_next = 0;
2110 endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
2111 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
2112 u132_endp_queue_work(u132, endp, 0);
2113 return 0;
2114 } else { /*(usb_addr > 0) */
2115 u8 address = u132->addr[usb_addr].address;
2116 struct u132_udev *udev = &u132->udev[address];
2117 endp->udev_number = address;
2118 endp->usb_addr = usb_addr;
2119 endp->usb_endp = usb_endp;
2120 endp->input = 1;
2121 endp->output = 1;
2122 endp->pipetype = usb_pipetype(urb->pipe);
2123 u132_udev_get_kref(u132, udev);
2124 udev->enumeration = 2;
2125 udev->endp_number_in[usb_endp] = endp_number;
2126 udev->endp_number_out[usb_endp] = endp_number;
2127 urb->hcpriv = u132;
2128 endp->queue_size = 1;
2129 endp->queue_last = 0;
2130 endp->queue_next = 0;
2131 endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
2132 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
2133 u132_endp_queue_work(u132, endp, 0);
2134 return 0;
2135 }
Tony Olechd774efe2006-09-13 11:27:35 +01002136}
2137
2138static int queue_control_on_old_endpoint(struct u132 *u132,
Alan Sterne9df41c2007-08-08 11:48:02 -04002139 struct urb *urb,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002140 struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
2141 u8 usb_endp)
Tony Olechd774efe2006-09-13 11:27:35 +01002142{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002143 if (usb_addr == 0) {
2144 if (usb_pipein(urb->pipe)) {
2145 urb->hcpriv = u132;
2146 if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
2147 endp->urb_list[ENDP_QUEUE_MASK &
2148 endp->queue_last++] = urb;
2149 } else {
2150 struct u132_urbq *urbq =
2151 kmalloc(sizeof(struct u132_urbq),
2152 GFP_ATOMIC);
2153 if (urbq == NULL) {
2154 endp->queue_size -= 1;
2155 return -ENOMEM;
2156 } else {
2157 list_add_tail(&urbq->urb_more,
2158 &endp->urb_more);
2159 urbq->urb = urb;
2160 }
2161 }
2162 return 0;
2163 } else { /* usb_pipeout(urb->pipe) */
2164 struct u132_addr *addr = &u132->addr[usb_dev->devnum];
2165 int I = MAX_U132_UDEVS;
2166 int i = 0;
2167 while (--I > 0) {
2168 struct u132_udev *udev = &u132->udev[++i];
2169 if (udev->usb_device) {
2170 continue;
2171 } else {
2172 udev->enumeration = 1;
2173 u132->addr[0].address = i;
2174 endp->udev_number = i;
2175 udev->udev_number = i;
2176 udev->usb_addr = usb_dev->devnum;
2177 u132_udev_init_kref(u132, udev);
2178 udev->endp_number_in[usb_endp] =
2179 endp->endp_number;
2180 u132_udev_get_kref(u132, udev);
2181 udev->endp_number_out[usb_endp] =
2182 endp->endp_number;
2183 udev->usb_device = usb_dev;
2184 ((u8 *) (urb->setup_packet))[2] =
2185 addr->address = i;
2186 u132_udev_get_kref(u132, udev);
2187 break;
2188 }
2189 }
2190 if (I == 0) {
2191 dev_err(&u132->platform_dev->dev, "run out of d"
2192 "evice space\n");
2193 return -EINVAL;
2194 }
2195 urb->hcpriv = u132;
2196 if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
2197 endp->urb_list[ENDP_QUEUE_MASK &
2198 endp->queue_last++] = urb;
2199 } else {
2200 struct u132_urbq *urbq =
2201 kmalloc(sizeof(struct u132_urbq),
2202 GFP_ATOMIC);
2203 if (urbq == NULL) {
2204 endp->queue_size -= 1;
2205 return -ENOMEM;
2206 } else {
2207 list_add_tail(&urbq->urb_more,
2208 &endp->urb_more);
2209 urbq->urb = urb;
2210 }
2211 }
2212 return 0;
2213 }
2214 } else { /*(usb_addr > 0) */
2215 u8 address = u132->addr[usb_addr].address;
2216 struct u132_udev *udev = &u132->udev[address];
2217 urb->hcpriv = u132;
2218 if (udev->enumeration != 2)
2219 udev->enumeration = 2;
2220 if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
2221 endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] =
2222 urb;
2223 } else {
2224 struct u132_urbq *urbq =
2225 kmalloc(sizeof(struct u132_urbq), GFP_ATOMIC);
2226 if (urbq == NULL) {
2227 endp->queue_size -= 1;
2228 return -ENOMEM;
2229 } else {
2230 list_add_tail(&urbq->urb_more, &endp->urb_more);
2231 urbq->urb = urb;
2232 }
2233 }
2234 return 0;
2235 }
Tony Olechd774efe2006-09-13 11:27:35 +01002236}
2237
Alan Sterne9df41c2007-08-08 11:48:02 -04002238static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
2239 gfp_t mem_flags)
Tony Olechd774efe2006-09-13 11:27:35 +01002240{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002241 struct u132 *u132 = hcd_to_u132(hcd);
2242 if (irqs_disabled()) {
Mel Gormand0164ad2015-11-06 16:28:21 -08002243 if (gfpflags_allow_blocking(mem_flags)) {
Masanari Iidad5f9e732015-09-30 12:51:51 +09002244 printk(KERN_ERR "invalid context for function that might sleep\n");
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002245 return -EINVAL;
2246 }
2247 }
2248 if (u132->going > 1) {
2249 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
2250 , u132->going);
2251 return -ENODEV;
2252 } else if (u132->going > 0) {
Alan Sterneb231052007-08-21 15:40:36 -04002253 dev_err(&u132->platform_dev->dev, "device is being removed "
2254 "urb=%p\n", urb);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002255 return -ESHUTDOWN;
2256 } else {
2257 u8 usb_addr = usb_pipedevice(urb->pipe);
2258 u8 usb_endp = usb_pipeendpoint(urb->pipe);
2259 struct usb_device *usb_dev = urb->dev;
2260 if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
2261 u8 address = u132->addr[usb_addr].address;
2262 struct u132_udev *udev = &u132->udev[address];
2263 struct u132_endp *endp = urb->ep->hcpriv;
2264 urb->actual_length = 0;
2265 if (endp) {
2266 unsigned long irqs;
2267 int retval;
2268 spin_lock_irqsave(&endp->queue_lock.slock,
2269 irqs);
Alan Sterne9df41c2007-08-08 11:48:02 -04002270 retval = usb_hcd_link_urb_to_ep(hcd, urb);
2271 if (retval == 0) {
2272 retval = queue_int_on_old_endpoint(
2273 u132, udev, urb,
2274 usb_dev, endp,
2275 usb_addr, usb_endp,
2276 address);
2277 if (retval)
2278 usb_hcd_unlink_urb_from_ep(
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002279 hcd, urb);
Alan Sterne9df41c2007-08-08 11:48:02 -04002280 }
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002281 spin_unlock_irqrestore(&endp->queue_lock.slock,
2282 irqs);
2283 if (retval) {
2284 return retval;
2285 } else {
2286 u132_endp_queue_work(u132, endp,
2287 msecs_to_jiffies(urb->interval))
2288 ;
2289 return 0;
2290 }
2291 } else if (u132->num_endpoints == MAX_U132_ENDPS) {
2292 return -EINVAL;
2293 } else { /*(endp == NULL) */
2294 return create_endpoint_and_queue_int(u132, udev,
Alan Sterne9df41c2007-08-08 11:48:02 -04002295 urb, usb_dev, usb_addr,
2296 usb_endp, address, mem_flags);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002297 }
2298 } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
2299 dev_err(&u132->platform_dev->dev, "the hardware does no"
2300 "t support PIPE_ISOCHRONOUS\n");
2301 return -EINVAL;
2302 } else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
2303 u8 address = u132->addr[usb_addr].address;
2304 struct u132_udev *udev = &u132->udev[address];
2305 struct u132_endp *endp = urb->ep->hcpriv;
2306 urb->actual_length = 0;
2307 if (endp) {
2308 unsigned long irqs;
2309 int retval;
2310 spin_lock_irqsave(&endp->queue_lock.slock,
2311 irqs);
Alan Sterne9df41c2007-08-08 11:48:02 -04002312 retval = usb_hcd_link_urb_to_ep(hcd, urb);
2313 if (retval == 0) {
2314 retval = queue_bulk_on_old_endpoint(
2315 u132, udev, urb,
2316 usb_dev, endp,
2317 usb_addr, usb_endp,
2318 address);
2319 if (retval)
2320 usb_hcd_unlink_urb_from_ep(
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002321 hcd, urb);
Alan Sterne9df41c2007-08-08 11:48:02 -04002322 }
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002323 spin_unlock_irqrestore(&endp->queue_lock.slock,
2324 irqs);
2325 if (retval) {
2326 return retval;
2327 } else {
2328 u132_endp_queue_work(u132, endp, 0);
2329 return 0;
2330 }
2331 } else if (u132->num_endpoints == MAX_U132_ENDPS) {
2332 return -EINVAL;
2333 } else
2334 return create_endpoint_and_queue_bulk(u132,
Alan Sterne9df41c2007-08-08 11:48:02 -04002335 udev, urb, usb_dev, usb_addr,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002336 usb_endp, address, mem_flags);
2337 } else {
2338 struct u132_endp *endp = urb->ep->hcpriv;
2339 u16 urb_size = 8;
2340 u8 *b = urb->setup_packet;
2341 int i = 0;
2342 char data[30 * 3 + 4];
2343 char *d = data;
2344 int m = (sizeof(data) - 1) / 3;
2345 int l = 0;
2346 data[0] = 0;
2347 while (urb_size-- > 0) {
2348 if (i > m) {
2349 } else if (i++ < m) {
2350 int w = sprintf(d, " %02X", *b++);
2351 d += w;
2352 l += w;
2353 } else
2354 d += sprintf(d, " ..");
2355 }
2356 if (endp) {
2357 unsigned long irqs;
2358 int retval;
2359 spin_lock_irqsave(&endp->queue_lock.slock,
2360 irqs);
Alan Sterne9df41c2007-08-08 11:48:02 -04002361 retval = usb_hcd_link_urb_to_ep(hcd, urb);
2362 if (retval == 0) {
2363 retval = queue_control_on_old_endpoint(
2364 u132, urb, usb_dev,
2365 endp, usb_addr,
2366 usb_endp);
2367 if (retval)
2368 usb_hcd_unlink_urb_from_ep(
2369 hcd, urb);
2370 }
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002371 spin_unlock_irqrestore(&endp->queue_lock.slock,
2372 irqs);
2373 if (retval) {
2374 return retval;
2375 } else {
2376 u132_endp_queue_work(u132, endp, 0);
2377 return 0;
2378 }
2379 } else if (u132->num_endpoints == MAX_U132_ENDPS) {
2380 return -EINVAL;
2381 } else
2382 return create_endpoint_and_queue_control(u132,
Alan Sterne9df41c2007-08-08 11:48:02 -04002383 urb, usb_dev, usb_addr, usb_endp,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002384 mem_flags);
2385 }
2386 }
Tony Olechd774efe2006-09-13 11:27:35 +01002387}
2388
2389static int dequeue_from_overflow_chain(struct u132 *u132,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002390 struct u132_endp *endp, struct urb *urb)
Tony Olechd774efe2006-09-13 11:27:35 +01002391{
Geliang Tang4e5d7a82015-12-19 00:34:29 +08002392 struct u132_urbq *urbq;
2393
2394 list_for_each_entry(urbq, &endp->urb_more, urb_more) {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002395 if (urbq->urb == urb) {
2396 struct usb_hcd *hcd = u132_to_hcd(u132);
Geliang Tang4e5d7a82015-12-19 00:34:29 +08002397 list_del(&urbq->urb_more);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002398 endp->queue_size -= 1;
2399 urb->error_count = 0;
Alan Stern4a000272007-08-24 15:42:24 -04002400 usb_hcd_giveback_urb(hcd, urb, 0);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002401 return 0;
2402 } else
2403 continue;
2404 }
2405 dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]=%p ring"
2406 "[%d] %c%c usb_endp=%d usb_addr=%d size=%d next=%04X last=%04X"
2407 "\n", urb, endp->endp_number, endp, endp->ring->number,
2408 endp->input ? 'I' : ' ', endp->output ? 'O' : ' ',
2409 endp->usb_endp, endp->usb_addr, endp->queue_size,
2410 endp->queue_next, endp->queue_last);
2411 return -EINVAL;
Tony Olechd774efe2006-09-13 11:27:35 +01002412}
2413
2414static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
Alan Sterne9df41c2007-08-08 11:48:02 -04002415 struct urb *urb, int status)
Tony Olechd774efe2006-09-13 11:27:35 +01002416{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002417 unsigned long irqs;
Alan Sterne9df41c2007-08-08 11:48:02 -04002418 int rc;
2419
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002420 spin_lock_irqsave(&endp->queue_lock.slock, irqs);
Alan Sterne9df41c2007-08-08 11:48:02 -04002421 rc = usb_hcd_check_unlink_urb(u132_to_hcd(u132), urb, status);
2422 if (rc) {
2423 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
2424 return rc;
2425 }
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002426 if (endp->queue_size == 0) {
2427 dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]"
2428 "=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", urb,
2429 endp->endp_number, endp, endp->ring->number,
2430 endp->input ? 'I' : ' ', endp->output ? 'O' : ' ',
2431 endp->usb_endp, endp->usb_addr);
2432 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
2433 return -EINVAL;
2434 }
2435 if (urb == endp->urb_list[ENDP_QUEUE_MASK & endp->queue_next]) {
2436 if (endp->active) {
2437 endp->dequeueing = 1;
2438 endp->edset_flush = 1;
2439 u132_endp_queue_work(u132, endp, 0);
2440 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
2441 return 0;
2442 } else {
2443 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
Alan Stern4a000272007-08-24 15:42:24 -04002444 u132_hcd_abandon_urb(u132, endp, urb, status);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002445 return 0;
2446 }
2447 } else {
2448 u16 queue_list = 0;
2449 u16 queue_size = endp->queue_size;
2450 u16 queue_scan = endp->queue_next;
2451 struct urb **urb_slot = NULL;
2452 while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) {
2453 if (urb == endp->urb_list[ENDP_QUEUE_MASK &
2454 ++queue_scan]) {
2455 urb_slot = &endp->urb_list[ENDP_QUEUE_MASK &
2456 queue_scan];
2457 break;
2458 } else
2459 continue;
2460 }
2461 while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) {
2462 *urb_slot = endp->urb_list[ENDP_QUEUE_MASK &
2463 ++queue_scan];
2464 urb_slot = &endp->urb_list[ENDP_QUEUE_MASK &
2465 queue_scan];
2466 }
2467 if (urb_slot) {
2468 struct usb_hcd *hcd = u132_to_hcd(u132);
Alan Sterne9df41c2007-08-08 11:48:02 -04002469
2470 usb_hcd_unlink_urb_from_ep(hcd, urb);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002471 endp->queue_size -= 1;
2472 if (list_empty(&endp->urb_more)) {
2473 spin_unlock_irqrestore(&endp->queue_lock.slock,
2474 irqs);
2475 } else {
2476 struct list_head *next = endp->urb_more.next;
2477 struct u132_urbq *urbq = list_entry(next,
2478 struct u132_urbq, urb_more);
2479 list_del(next);
2480 *urb_slot = urbq->urb;
2481 spin_unlock_irqrestore(&endp->queue_lock.slock,
2482 irqs);
2483 kfree(urbq);
2484 } urb->error_count = 0;
Alan Stern4a000272007-08-24 15:42:24 -04002485 usb_hcd_giveback_urb(hcd, urb, status);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002486 return 0;
2487 } else if (list_empty(&endp->urb_more)) {
2488 dev_err(&u132->platform_dev->dev, "urb=%p not found in "
2489 "endp[%d]=%p ring[%d] %c%c usb_endp=%d usb_addr"
2490 "=%d size=%d next=%04X last=%04X\n", urb,
2491 endp->endp_number, endp, endp->ring->number,
2492 endp->input ? 'I' : ' ',
2493 endp->output ? 'O' : ' ', endp->usb_endp,
2494 endp->usb_addr, endp->queue_size,
2495 endp->queue_next, endp->queue_last);
2496 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
2497 return -EINVAL;
2498 } else {
Alan Sterne9df41c2007-08-08 11:48:02 -04002499 int retval;
2500
2501 usb_hcd_unlink_urb_from_ep(u132_to_hcd(u132), urb);
2502 retval = dequeue_from_overflow_chain(u132, endp,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002503 urb);
2504 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
2505 return retval;
2506 }
2507 }
Tony Olechd774efe2006-09-13 11:27:35 +01002508}
2509
Alan Sterne9df41c2007-08-08 11:48:02 -04002510static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
Tony Olechd774efe2006-09-13 11:27:35 +01002511{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002512 struct u132 *u132 = hcd_to_u132(hcd);
2513 if (u132->going > 2) {
2514 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
2515 , u132->going);
2516 return -ENODEV;
2517 } else {
2518 u8 usb_addr = usb_pipedevice(urb->pipe);
2519 u8 usb_endp = usb_pipeendpoint(urb->pipe);
2520 u8 address = u132->addr[usb_addr].address;
2521 struct u132_udev *udev = &u132->udev[address];
2522 if (usb_pipein(urb->pipe)) {
2523 u8 endp_number = udev->endp_number_in[usb_endp];
2524 struct u132_endp *endp = u132->endp[endp_number - 1];
2525 return u132_endp_urb_dequeue(u132, endp, urb, status);
2526 } else {
2527 u8 endp_number = udev->endp_number_out[usb_endp];
2528 struct u132_endp *endp = u132->endp[endp_number - 1];
2529 return u132_endp_urb_dequeue(u132, endp, urb, status);
2530 }
2531 }
Tony Olechd774efe2006-09-13 11:27:35 +01002532}
2533
2534static void u132_endpoint_disable(struct usb_hcd *hcd,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002535 struct usb_host_endpoint *hep)
Tony Olechd774efe2006-09-13 11:27:35 +01002536{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002537 struct u132 *u132 = hcd_to_u132(hcd);
2538 if (u132->going > 2) {
2539 dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p hep=%p"
2540 ") has been removed %d\n", u132, hcd, hep,
2541 u132->going);
2542 } else {
2543 struct u132_endp *endp = hep->hcpriv;
2544 if (endp)
2545 u132_endp_put_kref(u132, endp);
2546 }
Tony Olechd774efe2006-09-13 11:27:35 +01002547}
2548
2549static int u132_get_frame(struct usb_hcd *hcd)
2550{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002551 struct u132 *u132 = hcd_to_u132(hcd);
2552 if (u132->going > 1) {
2553 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
2554 , u132->going);
2555 return -ENODEV;
2556 } else if (u132->going > 0) {
2557 dev_err(&u132->platform_dev->dev, "device is being removed\n");
2558 return -ESHUTDOWN;
2559 } else {
2560 int frame = 0;
2561 dev_err(&u132->platform_dev->dev, "TODO: u132_get_frame\n");
2562 msleep(100);
2563 return frame;
2564 }
Tony Olechd774efe2006-09-13 11:27:35 +01002565}
2566
2567static int u132_roothub_descriptor(struct u132 *u132,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002568 struct usb_hub_descriptor *desc)
Tony Olechd774efe2006-09-13 11:27:35 +01002569{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002570 int retval;
2571 u16 temp;
2572 u32 rh_a = -1;
2573 u32 rh_b = -1;
2574 retval = u132_read_pcimem(u132, roothub.a, &rh_a);
2575 if (retval)
2576 return retval;
Sergei Shtylyov0ce6fe92015-03-29 01:28:15 +03002577 desc->bDescriptorType = USB_DT_HUB;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002578 desc->bPwrOn2PwrGood = (rh_a & RH_A_POTPGT) >> 24;
2579 desc->bHubContrCurrent = 0;
2580 desc->bNbrPorts = u132->num_ports;
2581 temp = 1 + (u132->num_ports / 8);
2582 desc->bDescLength = 7 + 2 * temp;
Sergei Shtylyova7cf6972015-01-19 01:49:59 +03002583 temp = HUB_CHAR_COMMON_LPSM | HUB_CHAR_COMMON_OCPM;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002584 if (rh_a & RH_A_NPS)
Sergei Shtylyova7cf6972015-01-19 01:49:59 +03002585 temp |= HUB_CHAR_NO_LPSM;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002586 if (rh_a & RH_A_PSM)
Sergei Shtylyova7cf6972015-01-19 01:49:59 +03002587 temp |= HUB_CHAR_INDV_PORT_LPSM;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002588 if (rh_a & RH_A_NOCP)
Sergei Shtylyova7cf6972015-01-19 01:49:59 +03002589 temp |= HUB_CHAR_NO_OCPM;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002590 else if (rh_a & RH_A_OCPM)
Sergei Shtylyova7cf6972015-01-19 01:49:59 +03002591 temp |= HUB_CHAR_INDV_PORT_OCPM;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002592 desc->wHubCharacteristics = cpu_to_le16(temp);
2593 retval = u132_read_pcimem(u132, roothub.b, &rh_b);
2594 if (retval)
2595 return retval;
John Youndbe79bb2001-09-17 00:00:00 -07002596 memset(desc->u.hs.DeviceRemovable, 0xff,
2597 sizeof(desc->u.hs.DeviceRemovable));
2598 desc->u.hs.DeviceRemovable[0] = rh_b & RH_B_DR;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002599 if (u132->num_ports > 7) {
John Youndbe79bb2001-09-17 00:00:00 -07002600 desc->u.hs.DeviceRemovable[1] = (rh_b & RH_B_DR) >> 8;
2601 desc->u.hs.DeviceRemovable[2] = 0xff;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002602 } else
John Youndbe79bb2001-09-17 00:00:00 -07002603 desc->u.hs.DeviceRemovable[1] = 0xff;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002604 return 0;
Tony Olechd774efe2006-09-13 11:27:35 +01002605}
2606
2607static int u132_roothub_status(struct u132 *u132, __le32 *desc)
2608{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002609 u32 rh_status = -1;
2610 int ret_status = u132_read_pcimem(u132, roothub.status, &rh_status);
2611 *desc = cpu_to_le32(rh_status);
2612 return ret_status;
Tony Olechd774efe2006-09-13 11:27:35 +01002613}
2614
2615static int u132_roothub_portstatus(struct u132 *u132, __le32 *desc, u16 wIndex)
2616{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002617 if (wIndex == 0 || wIndex > u132->num_ports) {
2618 return -EINVAL;
2619 } else {
2620 int port = wIndex - 1;
2621 u32 rh_portstatus = -1;
2622 int ret_portstatus = u132_read_pcimem(u132,
2623 roothub.portstatus[port], &rh_portstatus);
2624 *desc = cpu_to_le32(rh_portstatus);
2625 if (*(u16 *) (desc + 2)) {
2626 dev_info(&u132->platform_dev->dev, "Port %d Status Chan"
2627 "ge = %08X\n", port, *desc);
2628 }
2629 return ret_portstatus;
2630 }
Tony Olechd774efe2006-09-13 11:27:35 +01002631}
2632
2633
2634/* this timer value might be vendor-specific ... */
2635#define PORT_RESET_HW_MSEC 10
2636#define PORT_RESET_MSEC 10
2637/* wrap-aware logic morphed from <linux/jiffies.h> */
2638#define tick_before(t1, t2) ((s16)(((s16)(t1))-((s16)(t2))) < 0)
2639static int u132_roothub_portreset(struct u132 *u132, int port_index)
2640{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002641 int retval;
2642 u32 fmnumber;
2643 u16 now;
2644 u16 reset_done;
2645 retval = u132_read_pcimem(u132, fmnumber, &fmnumber);
2646 if (retval)
2647 return retval;
2648 now = fmnumber;
2649 reset_done = now + PORT_RESET_MSEC;
2650 do {
2651 u32 portstat;
2652 do {
2653 retval = u132_read_pcimem(u132,
2654 roothub.portstatus[port_index], &portstat);
2655 if (retval)
2656 return retval;
2657 if (RH_PS_PRS & portstat)
2658 continue;
2659 else
2660 break;
2661 } while (tick_before(now, reset_done));
2662 if (RH_PS_PRS & portstat)
2663 return -ENODEV;
2664 if (RH_PS_CCS & portstat) {
2665 if (RH_PS_PRSC & portstat) {
2666 retval = u132_write_pcimem(u132,
2667 roothub.portstatus[port_index],
2668 RH_PS_PRSC);
2669 if (retval)
2670 return retval;
2671 }
2672 } else
2673 break; /* start the next reset,
2674 sleep till it's probably done */
2675 retval = u132_write_pcimem(u132, roothub.portstatus[port_index],
2676 RH_PS_PRS);
2677 if (retval)
2678 return retval;
2679 msleep(PORT_RESET_HW_MSEC);
2680 retval = u132_read_pcimem(u132, fmnumber, &fmnumber);
2681 if (retval)
2682 return retval;
2683 now = fmnumber;
2684 } while (tick_before(now, reset_done));
2685 return 0;
Tony Olechd774efe2006-09-13 11:27:35 +01002686}
2687
2688static int u132_roothub_setportfeature(struct u132 *u132, u16 wValue,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002689 u16 wIndex)
Tony Olechd774efe2006-09-13 11:27:35 +01002690{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002691 if (wIndex == 0 || wIndex > u132->num_ports) {
2692 return -EINVAL;
2693 } else {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002694 int port_index = wIndex - 1;
2695 struct u132_port *port = &u132->port[port_index];
2696 port->Status &= ~(1 << wValue);
2697 switch (wValue) {
2698 case USB_PORT_FEAT_SUSPEND:
Saurabh Karajgaonkar8602b082015-08-04 14:03:45 +00002699 return u132_write_pcimem(u132,
2700 roothub.portstatus[port_index], RH_PS_PSS);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002701 case USB_PORT_FEAT_POWER:
Saurabh Karajgaonkar8602b082015-08-04 14:03:45 +00002702 return u132_write_pcimem(u132,
2703 roothub.portstatus[port_index], RH_PS_PPS);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002704 case USB_PORT_FEAT_RESET:
Saurabh Karajgaonkar8602b082015-08-04 14:03:45 +00002705 return u132_roothub_portreset(u132, port_index);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002706 default:
2707 return -EPIPE;
2708 }
2709 }
Tony Olechd774efe2006-09-13 11:27:35 +01002710}
2711
2712static int u132_roothub_clearportfeature(struct u132 *u132, u16 wValue,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002713 u16 wIndex)
Tony Olechd774efe2006-09-13 11:27:35 +01002714{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002715 if (wIndex == 0 || wIndex > u132->num_ports) {
2716 return -EINVAL;
2717 } else {
2718 int port_index = wIndex - 1;
2719 u32 temp;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002720 struct u132_port *port = &u132->port[port_index];
2721 port->Status &= ~(1 << wValue);
2722 switch (wValue) {
2723 case USB_PORT_FEAT_ENABLE:
2724 temp = RH_PS_CCS;
2725 break;
2726 case USB_PORT_FEAT_C_ENABLE:
2727 temp = RH_PS_PESC;
2728 break;
2729 case USB_PORT_FEAT_SUSPEND:
2730 temp = RH_PS_POCI;
2731 if ((u132->hc_control & OHCI_CTRL_HCFS)
2732 != OHCI_USB_OPER) {
2733 dev_err(&u132->platform_dev->dev, "TODO resume_"
2734 "root_hub\n");
2735 }
2736 break;
2737 case USB_PORT_FEAT_C_SUSPEND:
2738 temp = RH_PS_PSSC;
2739 break;
2740 case USB_PORT_FEAT_POWER:
2741 temp = RH_PS_LSDA;
2742 break;
2743 case USB_PORT_FEAT_C_CONNECTION:
2744 temp = RH_PS_CSC;
2745 break;
2746 case USB_PORT_FEAT_C_OVER_CURRENT:
2747 temp = RH_PS_OCIC;
2748 break;
2749 case USB_PORT_FEAT_C_RESET:
2750 temp = RH_PS_PRSC;
2751 break;
2752 default:
2753 return -EPIPE;
2754 }
Saurabh Karajgaonkar8602b082015-08-04 14:03:45 +00002755 return u132_write_pcimem(u132, roothub.portstatus[port_index],
2756 temp);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002757 }
Tony Olechd774efe2006-09-13 11:27:35 +01002758}
2759
2760
2761/* the virtual root hub timer IRQ checks for hub status*/
2762static int u132_hub_status_data(struct usb_hcd *hcd, char *buf)
2763{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002764 struct u132 *u132 = hcd_to_u132(hcd);
2765 if (u132->going > 1) {
2766 dev_err(&u132->platform_dev->dev, "device hcd=%p has been remov"
2767 "ed %d\n", hcd, u132->going);
2768 return -ENODEV;
2769 } else if (u132->going > 0) {
2770 dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
2771 "ed\n", hcd);
2772 return -ESHUTDOWN;
2773 } else {
2774 int i, changed = 0, length = 1;
2775 if (u132->flags & OHCI_QUIRK_AMD756) {
2776 if ((u132->hc_roothub_a & RH_A_NDP) > MAX_ROOT_PORTS) {
2777 dev_err(&u132->platform_dev->dev, "bogus NDP, r"
2778 "ereads as NDP=%d\n",
2779 u132->hc_roothub_a & RH_A_NDP);
2780 goto done;
2781 }
2782 }
2783 if (u132->hc_roothub_status & (RH_HS_LPSC | RH_HS_OCIC))
2784 buf[0] = changed = 1;
2785 else
2786 buf[0] = 0;
2787 if (u132->num_ports > 7) {
2788 buf[1] = 0;
2789 length++;
2790 }
2791 for (i = 0; i < u132->num_ports; i++) {
2792 if (u132->hc_roothub_portstatus[i] & (RH_PS_CSC |
2793 RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC |
2794 RH_PS_PRSC)) {
2795 changed = 1;
2796 if (i < 7)
2797 buf[0] |= 1 << (i + 1);
2798 else
2799 buf[1] |= 1 << (i - 7);
2800 continue;
2801 }
2802 if (!(u132->hc_roothub_portstatus[i] & RH_PS_CCS))
2803 continue;
2804
2805 if ((u132->hc_roothub_portstatus[i] & RH_PS_PSS))
2806 continue;
2807 }
2808done:
2809 return changed ? length : 0;
2810 }
Tony Olechd774efe2006-09-13 11:27:35 +01002811}
2812
2813static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002814 u16 wIndex, char *buf, u16 wLength)
Tony Olechd774efe2006-09-13 11:27:35 +01002815{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002816 struct u132 *u132 = hcd_to_u132(hcd);
2817 if (u132->going > 1) {
2818 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
2819 , u132->going);
2820 return -ENODEV;
2821 } else if (u132->going > 0) {
2822 dev_err(&u132->platform_dev->dev, "device is being removed\n");
2823 return -ESHUTDOWN;
2824 } else {
2825 int retval = 0;
2826 mutex_lock(&u132->sw_lock);
2827 switch (typeReq) {
2828 case ClearHubFeature:
2829 switch (wValue) {
2830 case C_HUB_OVER_CURRENT:
2831 case C_HUB_LOCAL_POWER:
2832 break;
2833 default:
2834 goto stall;
2835 }
2836 break;
2837 case SetHubFeature:
2838 switch (wValue) {
2839 case C_HUB_OVER_CURRENT:
2840 case C_HUB_LOCAL_POWER:
2841 break;
2842 default:
2843 goto stall;
2844 }
2845 break;
2846 case ClearPortFeature:{
2847 retval = u132_roothub_clearportfeature(u132,
2848 wValue, wIndex);
2849 if (retval)
2850 goto error;
2851 break;
2852 }
2853 case GetHubDescriptor:{
2854 retval = u132_roothub_descriptor(u132,
2855 (struct usb_hub_descriptor *)buf);
2856 if (retval)
2857 goto error;
2858 break;
2859 }
2860 case GetHubStatus:{
2861 retval = u132_roothub_status(u132,
2862 (__le32 *) buf);
2863 if (retval)
2864 goto error;
2865 break;
2866 }
2867 case GetPortStatus:{
2868 retval = u132_roothub_portstatus(u132,
2869 (__le32 *) buf, wIndex);
2870 if (retval)
2871 goto error;
2872 break;
2873 }
2874 case SetPortFeature:{
2875 retval = u132_roothub_setportfeature(u132,
2876 wValue, wIndex);
2877 if (retval)
2878 goto error;
2879 break;
2880 }
2881 default:
2882 goto stall;
2883 error:
2884 u132_disable(u132);
2885 u132->going = 1;
2886 break;
2887 stall:
2888 retval = -EPIPE;
2889 break;
2890 }
2891 mutex_unlock(&u132->sw_lock);
2892 return retval;
2893 }
Tony Olechd774efe2006-09-13 11:27:35 +01002894}
2895
2896static int u132_start_port_reset(struct usb_hcd *hcd, unsigned port_num)
2897{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002898 struct u132 *u132 = hcd_to_u132(hcd);
2899 if (u132->going > 1) {
2900 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
2901 , u132->going);
2902 return -ENODEV;
2903 } else if (u132->going > 0) {
2904 dev_err(&u132->platform_dev->dev, "device is being removed\n");
2905 return -ESHUTDOWN;
2906 } else
2907 return 0;
Tony Olechd774efe2006-09-13 11:27:35 +01002908}
2909
Tony Olechd774efe2006-09-13 11:27:35 +01002910
2911#ifdef CONFIG_PM
Tony Olechd774efe2006-09-13 11:27:35 +01002912static int u132_bus_suspend(struct usb_hcd *hcd)
2913{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002914 struct u132 *u132 = hcd_to_u132(hcd);
2915 if (u132->going > 1) {
2916 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
2917 , u132->going);
2918 return -ENODEV;
2919 } else if (u132->going > 0) {
2920 dev_err(&u132->platform_dev->dev, "device is being removed\n");
2921 return -ESHUTDOWN;
2922 } else
2923 return 0;
Tony Olechd774efe2006-09-13 11:27:35 +01002924}
2925
2926static int u132_bus_resume(struct usb_hcd *hcd)
2927{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002928 struct u132 *u132 = hcd_to_u132(hcd);
2929 if (u132->going > 1) {
2930 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
2931 , u132->going);
2932 return -ENODEV;
2933 } else if (u132->going > 0) {
2934 dev_err(&u132->platform_dev->dev, "device is being removed\n");
2935 return -ESHUTDOWN;
2936 } else
2937 return 0;
Tony Olechd774efe2006-09-13 11:27:35 +01002938}
2939
2940#else
Tony Olechd774efe2006-09-13 11:27:35 +01002941#define u132_bus_suspend NULL
2942#define u132_bus_resume NULL
2943#endif
2944static struct hc_driver u132_hc_driver = {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002945 .description = hcd_name,
2946 .hcd_priv_size = sizeof(struct u132),
2947 .irq = NULL,
2948 .flags = HCD_USB11 | HCD_MEMORY,
2949 .reset = u132_hcd_reset,
2950 .start = u132_hcd_start,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002951 .stop = u132_hcd_stop,
2952 .urb_enqueue = u132_urb_enqueue,
2953 .urb_dequeue = u132_urb_dequeue,
2954 .endpoint_disable = u132_endpoint_disable,
2955 .get_frame_number = u132_get_frame,
2956 .hub_status_data = u132_hub_status_data,
2957 .hub_control = u132_hub_control,
2958 .bus_suspend = u132_bus_suspend,
2959 .bus_resume = u132_bus_resume,
2960 .start_port_reset = u132_start_port_reset,
Tony Olechd774efe2006-09-13 11:27:35 +01002961};
2962
2963/*
2964* This function may be called by the USB core whilst the "usb_all_devices_rwsem"
2965* is held for writing, thus this module must not call usb_remove_hcd()
2966* synchronously - but instead should immediately stop activity to the
Matt LaPlante0779bf22006-11-30 05:24:39 +01002967* device and asynchronously call usb_remove_hcd()
Tony Olechd774efe2006-09-13 11:27:35 +01002968*/
Bill Pembertonfb4e98a2012-11-19 13:26:20 -05002969static int u132_remove(struct platform_device *pdev)
Tony Olechd774efe2006-09-13 11:27:35 +01002970{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002971 struct usb_hcd *hcd = platform_get_drvdata(pdev);
2972 if (hcd) {
2973 struct u132 *u132 = hcd_to_u132(hcd);
2974 if (u132->going++ > 1) {
2975 dev_err(&u132->platform_dev->dev, "already being remove"
Tony Olech4b873612006-12-06 13:16:22 +00002976 "d\n");
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002977 return -ENODEV;
2978 } else {
2979 int rings = MAX_U132_RINGS;
2980 int endps = MAX_U132_ENDPS;
2981 dev_err(&u132->platform_dev->dev, "removing device u132"
Tony Olech4b873612006-12-06 13:16:22 +00002982 ".%d\n", u132->sequence_num);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002983 msleep(100);
2984 mutex_lock(&u132->sw_lock);
2985 u132_monitor_cancel_work(u132);
2986 while (rings-- > 0) {
2987 struct u132_ring *ring = &u132->ring[rings];
2988 u132_ring_cancel_work(u132, ring);
2989 } while (endps-- > 0) {
2990 struct u132_endp *endp = u132->endp[endps];
2991 if (endp)
2992 u132_endp_cancel_work(u132, endp);
2993 }
2994 u132->going += 1;
2995 printk(KERN_INFO "removing device u132.%d\n",
2996 u132->sequence_num);
2997 mutex_unlock(&u132->sw_lock);
2998 usb_remove_hcd(hcd);
2999 u132_u132_put_kref(u132);
3000 return 0;
3001 }
3002 } else
3003 return 0;
Tony Olechd774efe2006-09-13 11:27:35 +01003004}
3005
3006static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
3007{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003008 int rings = MAX_U132_RINGS;
3009 int ports = MAX_U132_PORTS;
3010 int addrs = MAX_U132_ADDRS;
3011 int udevs = MAX_U132_UDEVS;
3012 int endps = MAX_U132_ENDPS;
Jingoo Hand4f09e22013-07-30 19:59:40 +09003013 u132->board = dev_get_platdata(&pdev->dev);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003014 u132->platform_dev = pdev;
3015 u132->power = 0;
3016 u132->reset = 0;
3017 mutex_init(&u132->sw_lock);
Daniel Walker50d8ca92008-03-23 00:00:02 -07003018 mutex_init(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003019 while (rings-- > 0) {
3020 struct u132_ring *ring = &u132->ring[rings];
3021 ring->u132 = u132;
3022 ring->number = rings + 1;
3023 ring->length = 0;
3024 ring->curr_endp = NULL;
3025 INIT_DELAYED_WORK(&ring->scheduler,
David Howellsc4028952006-11-22 14:57:56 +00003026 u132_hcd_ring_work_scheduler);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003027 }
3028 mutex_lock(&u132->sw_lock);
3029 INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work);
3030 while (ports-- > 0) {
3031 struct u132_port *port = &u132->port[ports];
3032 port->u132 = u132;
3033 port->reset = 0;
3034 port->enable = 0;
3035 port->power = 0;
3036 port->Status = 0;
3037 }
3038 while (addrs-- > 0) {
3039 struct u132_addr *addr = &u132->addr[addrs];
3040 addr->address = 0;
3041 }
3042 while (udevs-- > 0) {
3043 struct u132_udev *udev = &u132->udev[udevs];
3044 int i = ARRAY_SIZE(udev->endp_number_in);
3045 int o = ARRAY_SIZE(udev->endp_number_out);
3046 udev->usb_device = NULL;
3047 udev->udev_number = 0;
3048 udev->usb_addr = 0;
3049 udev->portnumber = 0;
3050 while (i-- > 0)
3051 udev->endp_number_in[i] = 0;
3052
3053 while (o-- > 0)
3054 udev->endp_number_out[o] = 0;
3055
3056 }
3057 while (endps-- > 0)
3058 u132->endp[endps] = NULL;
3059
3060 mutex_unlock(&u132->sw_lock);
Tony Olechd774efe2006-09-13 11:27:35 +01003061}
3062
Bill Pemberton41ac7b32012-11-19 13:21:48 -05003063static int u132_probe(struct platform_device *pdev)
Tony Olechd774efe2006-09-13 11:27:35 +01003064{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003065 struct usb_hcd *hcd;
3066 int retval;
3067 u32 control;
3068 u32 rh_a = -1;
3069 u32 num_ports;
3070
3071 msleep(100);
3072 if (u132_exiting > 0)
3073 return -ENODEV;
3074
3075 retval = ftdi_write_pcimem(pdev, intrdisable, OHCI_INTR_MIE);
3076 if (retval)
3077 return retval;
3078 retval = ftdi_read_pcimem(pdev, control, &control);
3079 if (retval)
3080 return retval;
3081 retval = ftdi_read_pcimem(pdev, roothub.a, &rh_a);
3082 if (retval)
3083 return retval;
3084 num_ports = rh_a & RH_A_NDP; /* refuse to confuse usbcore */
3085 if (pdev->dev.dma_mask)
3086 return -EINVAL;
3087
Kay Sievers7071a3c2008-05-02 06:02:41 +02003088 hcd = usb_create_hcd(&u132_hc_driver, &pdev->dev, dev_name(&pdev->dev));
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003089 if (!hcd) {
3090 printk(KERN_ERR "failed to create the usb hcd struct for U132\n"
3091 );
3092 ftdi_elan_gone_away(pdev);
3093 return -ENOMEM;
3094 } else {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003095 struct u132 *u132 = hcd_to_u132(hcd);
Bill Pemberton66414452010-04-29 10:04:56 -04003096 retval = 0;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003097 hcd->rsrc_start = 0;
3098 mutex_lock(&u132_module_lock);
3099 list_add_tail(&u132->u132_list, &u132_static_list);
3100 u132->sequence_num = ++u132_instances;
3101 mutex_unlock(&u132_module_lock);
3102 u132_u132_init_kref(u132);
3103 u132_initialise(u132, pdev);
3104 hcd->product_desc = "ELAN U132 Host Controller";
3105 retval = usb_add_hcd(hcd, 0, 0);
3106 if (retval != 0) {
3107 dev_err(&u132->platform_dev->dev, "init error %d\n",
3108 retval);
3109 u132_u132_put_kref(u132);
3110 return retval;
3111 } else {
Peter Chen3c9740a2013-11-05 10:46:02 +08003112 device_wakeup_enable(hcd->self.controller);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003113 u132_monitor_queue_work(u132, 100);
3114 return 0;
3115 }
3116 }
Tony Olechd774efe2006-09-13 11:27:35 +01003117}
3118
3119
3120#ifdef CONFIG_PM
Alan Stern84ebc102013-03-27 16:14:46 -04003121/*
3122 * for this device there's no useful distinction between the controller
Rafael J. Wysockiceb6c9c2014-11-29 23:47:05 +01003123 * and its root hub.
Alan Stern84ebc102013-03-27 16:14:46 -04003124 */
Tony Olechd774efe2006-09-13 11:27:35 +01003125static int u132_suspend(struct platform_device *pdev, pm_message_t state)
3126{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003127 struct usb_hcd *hcd = platform_get_drvdata(pdev);
3128 struct u132 *u132 = hcd_to_u132(hcd);
3129 if (u132->going > 1) {
3130 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
3131 , u132->going);
3132 return -ENODEV;
3133 } else if (u132->going > 0) {
3134 dev_err(&u132->platform_dev->dev, "device is being removed\n");
3135 return -ESHUTDOWN;
3136 } else {
Mirco Tischler038eb0e2008-02-24 05:16:39 +01003137 int retval = 0, ports;
Rafael J. Wysocki3a2d5b72008-02-23 19:13:25 +01003138
3139 switch (state.event) {
3140 case PM_EVENT_FREEZE:
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003141 retval = u132_bus_suspend(hcd);
Rafael J. Wysocki3a2d5b72008-02-23 19:13:25 +01003142 break;
3143 case PM_EVENT_SUSPEND:
3144 case PM_EVENT_HIBERNATE:
Mirco Tischler038eb0e2008-02-24 05:16:39 +01003145 ports = MAX_U132_PORTS;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003146 while (ports-- > 0) {
3147 port_power(u132, ports, 0);
3148 }
Rafael J. Wysocki3a2d5b72008-02-23 19:13:25 +01003149 break;
3150 }
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003151 return retval;
3152 }
Tony Olechd774efe2006-09-13 11:27:35 +01003153}
3154
3155static int u132_resume(struct platform_device *pdev)
3156{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003157 struct usb_hcd *hcd = platform_get_drvdata(pdev);
3158 struct u132 *u132 = hcd_to_u132(hcd);
3159 if (u132->going > 1) {
3160 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
3161 , u132->going);
3162 return -ENODEV;
3163 } else if (u132->going > 0) {
3164 dev_err(&u132->platform_dev->dev, "device is being removed\n");
3165 return -ESHUTDOWN;
3166 } else {
3167 int retval = 0;
Alan Stern70a1c9e2008-03-06 17:00:58 -05003168 if (!u132->port[0].power) {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003169 int ports = MAX_U132_PORTS;
3170 while (ports-- > 0) {
3171 port_power(u132, ports, 1);
3172 }
3173 retval = 0;
3174 } else {
3175 retval = u132_bus_resume(hcd);
3176 }
3177 return retval;
3178 }
Tony Olechd774efe2006-09-13 11:27:35 +01003179}
3180
3181#else
3182#define u132_suspend NULL
3183#define u132_resume NULL
3184#endif
3185/*
Matt LaPlante0779bf22006-11-30 05:24:39 +01003186* this driver is loaded explicitly by ftdi_u132
Tony Olechd774efe2006-09-13 11:27:35 +01003187*
3188* the platform_driver struct is static because it is per type of module
3189*/
3190static struct platform_driver u132_platform_driver = {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003191 .probe = u132_probe,
Bill Pemberton76904172012-11-19 13:21:08 -05003192 .remove = u132_remove,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003193 .suspend = u132_suspend,
3194 .resume = u132_resume,
3195 .driver = {
Geert Uytterhoevena4586772013-11-12 20:07:25 +01003196 .name = hcd_name,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003197 },
Tony Olechd774efe2006-09-13 11:27:35 +01003198};
3199static int __init u132_hcd_init(void)
3200{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003201 int retval;
3202 INIT_LIST_HEAD(&u132_static_list);
3203 u132_instances = 0;
3204 u132_exiting = 0;
3205 mutex_init(&u132_module_lock);
3206 if (usb_disabled())
3207 return -ENODEV;
Michal Marek654d1212011-04-05 16:59:11 +02003208 printk(KERN_INFO "driver %s\n", hcd_name);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003209 workqueue = create_singlethread_workqueue("u132");
3210 retval = platform_driver_register(&u132_platform_driver);
3211 return retval;
Tony Olechd774efe2006-09-13 11:27:35 +01003212}
3213
3214
3215module_init(u132_hcd_init);
3216static void __exit u132_hcd_exit(void)
3217{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003218 struct u132 *u132;
3219 struct u132 *temp;
3220 mutex_lock(&u132_module_lock);
3221 u132_exiting += 1;
3222 mutex_unlock(&u132_module_lock);
3223 list_for_each_entry_safe(u132, temp, &u132_static_list, u132_list) {
3224 platform_device_unregister(u132->platform_dev);
3225 }
3226 platform_driver_unregister(&u132_platform_driver);
3227 printk(KERN_INFO "u132-hcd driver deregistered\n");
3228 wait_event(u132_hcd_wait, u132_instances == 0);
3229 flush_workqueue(workqueue);
3230 destroy_workqueue(workqueue);
Tony Olechd774efe2006-09-13 11:27:35 +01003231}
3232
3233
3234module_exit(u132_hcd_exit);
3235MODULE_LICENSE("GPL");
Kay Sieversf4fce612008-04-10 21:29:22 -07003236MODULE_ALIAS("platform:u132_hcd");