blob: 5a783c423d8e7e48298fb384880d36ad264bf480 [file] [log] [blame]
Greg Kroah-Hartman5fd54ac2017-11-03 11:28:30 +01001// SPDX-License-Identifier: GPL-2.0
Tony Olechd774efe2006-09-13 11:27:35 +01002/*
3* Host Controller Driver for the Elan Digital Systems U132 adapter
4*
5* Copyright(C) 2006 Elan Digital Systems Limited
6* http://www.elandigitalsystems.com
7*
8* Author and Maintainer - Tony Olech - Elan Digital Systems
9* tony.olech@elandigitalsystems.com
10*
Tony Olechd774efe2006-09-13 11:27:35 +010011* This driver was written by Tony Olech(tony.olech@elandigitalsystems.com)
12* based on various USB host drivers in the 2.6.15 linux kernel
13* with constant reference to the 3rd Edition of Linux Device Drivers
14* published by O'Reilly
15*
16* The U132 adapter is a USB to CardBus adapter specifically designed
17* for PC cards that contain an OHCI host controller. Typical PC cards
18* are the Orange Mobile 3G Option GlobeTrotter Fusion card.
19*
20* The U132 adapter will *NOT *work with PC cards that do not contain
21* an OHCI controller. A simple way to test whether a PC card has an
22* OHCI controller as an interface is to insert the PC card directly
23* into a laptop(or desktop) with a CardBus slot and if "lspci" shows
24* a new USB controller and "lsusb -v" shows a new OHCI Host Controller
25* then there is a good chance that the U132 adapter will support the
26* PC card.(you also need the specific client driver for the PC card)
27*
28* Please inform the Author and Maintainer about any PC cards that
29* contain OHCI Host Controller and work when directly connected to
30* an embedded CardBus slot but do not work when they are connected
31* via an ELAN U132 adapter.
32*
33*/
Tony Olechd774efe2006-09-13 11:27:35 +010034#include <linux/kernel.h>
35#include <linux/module.h>
36#include <linux/moduleparam.h>
37#include <linux/delay.h>
38#include <linux/ioport.h>
Tony Olech4b873612006-12-06 13:16:22 +000039#include <linux/pci_ids.h>
Tony Olechd774efe2006-09-13 11:27:35 +010040#include <linux/sched.h>
41#include <linux/slab.h>
Tony Olechd774efe2006-09-13 11:27:35 +010042#include <linux/errno.h>
43#include <linux/init.h>
44#include <linux/timer.h>
45#include <linux/list.h>
46#include <linux/interrupt.h>
47#include <linux/usb.h>
Eric Lescouet27729aa2010-04-24 23:21:52 +020048#include <linux/usb/hcd.h>
Tony Olechd774efe2006-09-13 11:27:35 +010049#include <linux/workqueue.h>
50#include <linux/platform_device.h>
Matthias Kaehlcked2066eb2007-07-13 21:26:59 +020051#include <linux/mutex.h>
Tony Olechd774efe2006-09-13 11:27:35 +010052#include <asm/io.h>
53#include <asm/irq.h>
Tony Olechd774efe2006-09-13 11:27:35 +010054#include <asm/byteorder.h>
David Brownell47f84682007-04-29 10:21:14 -070055
56 /* FIXME ohci.h is ONLY for internal use by the OHCI driver.
57 * If you're going to try stuff like this, you need to split
58 * out shareable stuff (register declarations?) into its own
59 * file, maybe name <linux/usb/ohci.h>
60 */
61
Tony Olechd774efe2006-09-13 11:27:35 +010062#include "ohci.h"
63#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR
64#define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \
Daniel Walkerb40f8d32008-03-23 00:00:01 -070065 OHCI_INTR_WDH)
Tony Olechd774efe2006-09-13 11:27:35 +010066MODULE_AUTHOR("Tony Olech - Elan Digital Systems Limited");
67MODULE_DESCRIPTION("U132 USB Host Controller Driver");
68MODULE_LICENSE("GPL");
69#define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444)
70INT_MODULE_PARM(testing, 0);
71/* Some boards misreport power switching/overcurrent*/
Geyslan G. Bem900937c2015-12-02 20:25:23 -030072static bool distrust_firmware = true;
Tony Olechd774efe2006-09-13 11:27:35 +010073module_param(distrust_firmware, bool, 0);
Colin Ian King8f9b6222019-09-11 11:07:45 +010074MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurrent"
Daniel Walkerb40f8d32008-03-23 00:00:01 -070075 "t setup");
Adrian Bunk27a3de42006-11-20 03:23:54 +010076static DECLARE_WAIT_QUEUE_HEAD(u132_hcd_wait);
Tony Olechd774efe2006-09-13 11:27:35 +010077/*
78* u132_module_lock exists to protect access to global variables
79*
80*/
Zheng Yongjun7c536242021-04-05 18:14:34 +080081static DEFINE_MUTEX(u132_module_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -070082static int u132_exiting;
83static int u132_instances;
Tony Olechd774efe2006-09-13 11:27:35 +010084/*
85* end of the global variables protected by u132_module_lock
86*/
87static struct workqueue_struct *workqueue;
88#define MAX_U132_PORTS 7
89#define MAX_U132_ADDRS 128
90#define MAX_U132_UDEVS 4
91#define MAX_U132_ENDPS 100
92#define MAX_U132_RINGS 4
93static const char *cc_to_text[16] = {
Daniel Walkerb40f8d32008-03-23 00:00:01 -070094 "No Error ",
95 "CRC Error ",
96 "Bit Stuff ",
97 "Data Togg ",
98 "Stall ",
99 "DevNotResp ",
100 "PIDCheck ",
101 "UnExpPID ",
102 "DataOver ",
103 "DataUnder ",
104 "(for hw) ",
105 "(for hw) ",
106 "BufferOver ",
107 "BuffUnder ",
108 "(for HCD) ",
109 "(for HCD) "
Tony Olechd774efe2006-09-13 11:27:35 +0100110};
111struct u132_port {
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700112 struct u132 *u132;
113 int reset;
114 int enable;
115 int power;
116 int Status;
Tony Olechd774efe2006-09-13 11:27:35 +0100117};
118struct u132_addr {
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700119 u8 address;
Tony Olechd774efe2006-09-13 11:27:35 +0100120};
121struct u132_udev {
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700122 struct kref kref;
123 struct usb_device *usb_device;
124 u8 enumeration;
125 u8 udev_number;
126 u8 usb_addr;
127 u8 portnumber;
128 u8 endp_number_in[16];
129 u8 endp_number_out[16];
Tony Olechd774efe2006-09-13 11:27:35 +0100130};
131#define ENDP_QUEUE_SHIFT 3
132#define ENDP_QUEUE_SIZE (1<<ENDP_QUEUE_SHIFT)
133#define ENDP_QUEUE_MASK (ENDP_QUEUE_SIZE-1)
134struct u132_urbq {
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700135 struct list_head urb_more;
136 struct urb *urb;
Tony Olechd774efe2006-09-13 11:27:35 +0100137};
138struct u132_spin {
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700139 spinlock_t slock;
Tony Olechd774efe2006-09-13 11:27:35 +0100140};
141struct u132_endp {
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700142 struct kref kref;
143 u8 udev_number;
144 u8 endp_number;
145 u8 usb_addr;
146 u8 usb_endp;
147 struct u132 *u132;
148 struct list_head endp_ring;
149 struct u132_ring *ring;
150 unsigned toggle_bits:2;
151 unsigned active:1;
152 unsigned delayed:1;
153 unsigned input:1;
154 unsigned output:1;
155 unsigned pipetype:2;
156 unsigned dequeueing:1;
157 unsigned edset_flush:1;
158 unsigned spare_bits:14;
159 unsigned long jiffies;
160 struct usb_host_endpoint *hep;
161 struct u132_spin queue_lock;
162 u16 queue_size;
163 u16 queue_last;
164 u16 queue_next;
165 struct urb *urb_list[ENDP_QUEUE_SIZE];
166 struct list_head urb_more;
167 struct delayed_work scheduler;
Tony Olechd774efe2006-09-13 11:27:35 +0100168};
169struct u132_ring {
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700170 unsigned in_use:1;
171 unsigned length:7;
172 u8 number;
173 struct u132 *u132;
174 struct u132_endp *curr_endp;
175 struct delayed_work scheduler;
Tony Olechd774efe2006-09-13 11:27:35 +0100176};
Tony Olechd774efe2006-09-13 11:27:35 +0100177struct u132 {
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700178 struct kref kref;
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700179 struct mutex sw_lock;
Daniel Walker50d8ca92008-03-23 00:00:02 -0700180 struct mutex scheduler_lock;
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700181 struct u132_platform_data *board;
182 struct platform_device *platform_dev;
183 struct u132_ring ring[MAX_U132_RINGS];
184 int sequence_num;
185 int going;
186 int power;
187 int reset;
188 int num_ports;
189 u32 hc_control;
190 u32 hc_fminterval;
191 u32 hc_roothub_status;
192 u32 hc_roothub_a;
193 u32 hc_roothub_portstatus[MAX_ROOT_PORTS];
194 int flags;
195 unsigned long next_statechange;
196 struct delayed_work monitor;
197 int num_endpoints;
198 struct u132_addr addr[MAX_U132_ADDRS];
199 struct u132_udev udev[MAX_U132_UDEVS];
200 struct u132_port port[MAX_U132_PORTS];
201 struct u132_endp *endp[MAX_U132_ENDPS];
Tony Olechd774efe2006-09-13 11:27:35 +0100202};
Adrian Bunk9ce85402006-11-20 03:24:44 +0100203
Tony Olechd774efe2006-09-13 11:27:35 +0100204/*
Matt LaPlante0779bf22006-11-30 05:24:39 +0100205* these cannot be inlines because we need the structure offset!!
Tony Olechd774efe2006-09-13 11:27:35 +0100206* Does anyone have a better way?????
207*/
Tony Olech4b873612006-12-06 13:16:22 +0000208#define ftdi_read_pcimem(pdev, member, data) usb_ftdi_elan_read_pcimem(pdev, \
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700209 offsetof(struct ohci_regs, member), 0, data);
Tony Olech4b873612006-12-06 13:16:22 +0000210#define ftdi_write_pcimem(pdev, member, data) usb_ftdi_elan_write_pcimem(pdev, \
Tom Rix21f5b2f2020-11-27 11:03:36 -0800211 offsetof(struct ohci_regs, member), 0, data)
Tony Olechd774efe2006-09-13 11:27:35 +0100212#define u132_read_pcimem(u132, member, data) \
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700213 usb_ftdi_elan_read_pcimem(u132->platform_dev, offsetof(struct \
Tom Rix21f5b2f2020-11-27 11:03:36 -0800214 ohci_regs, member), 0, data)
Tony Olechd774efe2006-09-13 11:27:35 +0100215#define u132_write_pcimem(u132, member, data) \
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700216 usb_ftdi_elan_write_pcimem(u132->platform_dev, offsetof(struct \
Tom Rix21f5b2f2020-11-27 11:03:36 -0800217 ohci_regs, member), 0, data)
Tony Olechd774efe2006-09-13 11:27:35 +0100218static inline struct u132 *udev_to_u132(struct u132_udev *udev)
219{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700220 u8 udev_number = udev->udev_number;
221 return container_of(udev, struct u132, udev[udev_number]);
Tony Olechd774efe2006-09-13 11:27:35 +0100222}
223
224static inline struct u132 *hcd_to_u132(struct usb_hcd *hcd)
225{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700226 return (struct u132 *)(hcd->hcd_priv);
Tony Olechd774efe2006-09-13 11:27:35 +0100227}
228
229static inline struct usb_hcd *u132_to_hcd(struct u132 *u132)
230{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700231 return container_of((void *)u132, struct usb_hcd, hcd_priv);
Tony Olechd774efe2006-09-13 11:27:35 +0100232}
233
234static inline void u132_disable(struct u132 *u132)
235{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700236 u132_to_hcd(u132)->state = HC_STATE_HALT;
Tony Olechd774efe2006-09-13 11:27:35 +0100237}
238
239
240#define kref_to_u132(d) container_of(d, struct u132, kref)
241#define kref_to_u132_endp(d) container_of(d, struct u132_endp, kref)
242#define kref_to_u132_udev(d) container_of(d, struct u132_udev, kref)
243#include "../misc/usb_u132.h"
244static const char hcd_name[] = "u132_hcd";
245#define PORT_C_MASK ((USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | \
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700246 USB_PORT_STAT_C_SUSPEND | USB_PORT_STAT_C_OVERCURRENT | \
247 USB_PORT_STAT_C_RESET) << 16)
Tony Olechd774efe2006-09-13 11:27:35 +0100248static void u132_hcd_delete(struct kref *kref)
249{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700250 struct u132 *u132 = kref_to_u132(kref);
251 struct platform_device *pdev = u132->platform_dev;
252 struct usb_hcd *hcd = u132_to_hcd(u132);
253 u132->going += 1;
254 mutex_lock(&u132_module_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700255 u132_instances -= 1;
256 mutex_unlock(&u132_module_lock);
257 dev_warn(&u132->platform_dev->dev, "FREEING the hcd=%p and thus the u13"
258 "2=%p going=%d pdev=%p\n", hcd, u132, u132->going, pdev);
259 usb_put_hcd(hcd);
Tony Olechd774efe2006-09-13 11:27:35 +0100260}
261
262static inline void u132_u132_put_kref(struct u132 *u132)
263{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700264 kref_put(&u132->kref, u132_hcd_delete);
Tony Olechd774efe2006-09-13 11:27:35 +0100265}
266
267static inline void u132_u132_init_kref(struct u132 *u132)
268{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700269 kref_init(&u132->kref);
Tony Olechd774efe2006-09-13 11:27:35 +0100270}
271
272static void u132_udev_delete(struct kref *kref)
273{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700274 struct u132_udev *udev = kref_to_u132_udev(kref);
275 udev->udev_number = 0;
276 udev->usb_device = NULL;
277 udev->usb_addr = 0;
278 udev->enumeration = 0;
Tony Olechd774efe2006-09-13 11:27:35 +0100279}
280
281static inline void u132_udev_put_kref(struct u132 *u132, struct u132_udev *udev)
282{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700283 kref_put(&udev->kref, u132_udev_delete);
Tony Olechd774efe2006-09-13 11:27:35 +0100284}
285
286static inline void u132_udev_get_kref(struct u132 *u132, struct u132_udev *udev)
287{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700288 kref_get(&udev->kref);
Tony Olechd774efe2006-09-13 11:27:35 +0100289}
290
291static inline void u132_udev_init_kref(struct u132 *u132,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700292 struct u132_udev *udev)
Tony Olechd774efe2006-09-13 11:27:35 +0100293{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700294 kref_init(&udev->kref);
Tony Olechd774efe2006-09-13 11:27:35 +0100295}
296
297static inline void u132_ring_put_kref(struct u132 *u132, struct u132_ring *ring)
298{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700299 kref_put(&u132->kref, u132_hcd_delete);
Tony Olechd774efe2006-09-13 11:27:35 +0100300}
301
302static void u132_ring_requeue_work(struct u132 *u132, struct u132_ring *ring,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700303 unsigned int delta)
Tony Olechd774efe2006-09-13 11:27:35 +0100304{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700305 if (delta > 0) {
306 if (queue_delayed_work(workqueue, &ring->scheduler, delta))
307 return;
308 } else if (queue_delayed_work(workqueue, &ring->scheduler, 0))
309 return;
310 kref_put(&u132->kref, u132_hcd_delete);
Tony Olechd774efe2006-09-13 11:27:35 +0100311}
312
313static void u132_ring_queue_work(struct u132 *u132, struct u132_ring *ring,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700314 unsigned int delta)
Tony Olechd774efe2006-09-13 11:27:35 +0100315{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700316 kref_get(&u132->kref);
317 u132_ring_requeue_work(u132, ring, delta);
Tony Olechd774efe2006-09-13 11:27:35 +0100318}
319
320static void u132_ring_cancel_work(struct u132 *u132, struct u132_ring *ring)
321{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700322 if (cancel_delayed_work(&ring->scheduler))
323 kref_put(&u132->kref, u132_hcd_delete);
Tony Olechd774efe2006-09-13 11:27:35 +0100324}
325
326static void u132_endp_delete(struct kref *kref)
327{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700328 struct u132_endp *endp = kref_to_u132_endp(kref);
329 struct u132 *u132 = endp->u132;
330 u8 usb_addr = endp->usb_addr;
331 u8 usb_endp = endp->usb_endp;
332 u8 address = u132->addr[usb_addr].address;
333 struct u132_udev *udev = &u132->udev[address];
334 u8 endp_number = endp->endp_number;
335 struct usb_host_endpoint *hep = endp->hep;
336 struct u132_ring *ring = endp->ring;
337 struct list_head *head = &endp->endp_ring;
338 ring->length -= 1;
339 if (endp == ring->curr_endp) {
340 if (list_empty(head)) {
341 ring->curr_endp = NULL;
342 list_del(head);
343 } else {
344 struct u132_endp *next_endp = list_entry(head->next,
345 struct u132_endp, endp_ring);
346 ring->curr_endp = next_endp;
347 list_del(head);
348 }
349 } else
350 list_del(head);
351 if (endp->input) {
352 udev->endp_number_in[usb_endp] = 0;
353 u132_udev_put_kref(u132, udev);
354 }
355 if (endp->output) {
356 udev->endp_number_out[usb_endp] = 0;
357 u132_udev_put_kref(u132, udev);
358 }
359 u132->endp[endp_number - 1] = NULL;
360 hep->hcpriv = NULL;
361 kfree(endp);
362 u132_u132_put_kref(u132);
Tony Olechd774efe2006-09-13 11:27:35 +0100363}
364
365static inline void u132_endp_put_kref(struct u132 *u132, struct u132_endp *endp)
366{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700367 kref_put(&endp->kref, u132_endp_delete);
Tony Olechd774efe2006-09-13 11:27:35 +0100368}
369
370static inline void u132_endp_get_kref(struct u132 *u132, struct u132_endp *endp)
371{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700372 kref_get(&endp->kref);
Tony Olechd774efe2006-09-13 11:27:35 +0100373}
374
375static inline void u132_endp_init_kref(struct u132 *u132,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700376 struct u132_endp *endp)
Tony Olechd774efe2006-09-13 11:27:35 +0100377{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700378 kref_init(&endp->kref);
379 kref_get(&u132->kref);
Tony Olechd774efe2006-09-13 11:27:35 +0100380}
381
382static void u132_endp_queue_work(struct u132 *u132, struct u132_endp *endp,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700383 unsigned int delta)
Tony Olechd774efe2006-09-13 11:27:35 +0100384{
David Howellsc4028952006-11-22 14:57:56 +0000385 if (queue_delayed_work(workqueue, &endp->scheduler, delta))
386 kref_get(&endp->kref);
Tony Olechd774efe2006-09-13 11:27:35 +0100387}
388
389static void u132_endp_cancel_work(struct u132 *u132, struct u132_endp *endp)
390{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700391 if (cancel_delayed_work(&endp->scheduler))
392 kref_put(&endp->kref, u132_endp_delete);
Tony Olechd774efe2006-09-13 11:27:35 +0100393}
394
395static inline void u132_monitor_put_kref(struct u132 *u132)
396{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700397 kref_put(&u132->kref, u132_hcd_delete);
Tony Olechd774efe2006-09-13 11:27:35 +0100398}
399
400static void u132_monitor_queue_work(struct u132 *u132, unsigned int delta)
401{
David Howellsc4028952006-11-22 14:57:56 +0000402 if (queue_delayed_work(workqueue, &u132->monitor, delta))
403 kref_get(&u132->kref);
Tony Olechd774efe2006-09-13 11:27:35 +0100404}
405
406static void u132_monitor_requeue_work(struct u132 *u132, unsigned int delta)
407{
David Howellsc4028952006-11-22 14:57:56 +0000408 if (!queue_delayed_work(workqueue, &u132->monitor, delta))
409 kref_put(&u132->kref, u132_hcd_delete);
Tony Olechd774efe2006-09-13 11:27:35 +0100410}
411
412static void u132_monitor_cancel_work(struct u132 *u132)
413{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700414 if (cancel_delayed_work(&u132->monitor))
415 kref_put(&u132->kref, u132_hcd_delete);
Tony Olechd774efe2006-09-13 11:27:35 +0100416}
417
418static int read_roothub_info(struct u132 *u132)
419{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700420 u32 revision;
421 int retval;
422 retval = u132_read_pcimem(u132, revision, &revision);
423 if (retval) {
424 dev_err(&u132->platform_dev->dev, "error %d accessing device co"
425 "ntrol\n", retval);
426 return retval;
427 } else if ((revision & 0xFF) == 0x10) {
428 } else if ((revision & 0xFF) == 0x11) {
429 } else {
430 dev_err(&u132->platform_dev->dev, "device revision is not valid"
431 " %08X\n", revision);
432 return -ENODEV;
433 }
434 retval = u132_read_pcimem(u132, control, &u132->hc_control);
435 if (retval) {
436 dev_err(&u132->platform_dev->dev, "error %d accessing device co"
437 "ntrol\n", retval);
438 return retval;
439 }
440 retval = u132_read_pcimem(u132, roothub.status,
441 &u132->hc_roothub_status);
442 if (retval) {
443 dev_err(&u132->platform_dev->dev, "error %d accessing device re"
444 "g roothub.status\n", retval);
445 return retval;
446 }
447 retval = u132_read_pcimem(u132, roothub.a, &u132->hc_roothub_a);
448 if (retval) {
449 dev_err(&u132->platform_dev->dev, "error %d accessing device re"
450 "g roothub.a\n", retval);
451 return retval;
452 }
453 {
454 int I = u132->num_ports;
455 int i = 0;
456 while (I-- > 0) {
457 retval = u132_read_pcimem(u132, roothub.portstatus[i],
458 &u132->hc_roothub_portstatus[i]);
459 if (retval) {
460 dev_err(&u132->platform_dev->dev, "error %d acc"
461 "essing device roothub.portstatus[%d]\n"
462 , retval, i);
463 return retval;
464 } else
465 i += 1;
466 }
467 }
468 return 0;
Tony Olechd774efe2006-09-13 11:27:35 +0100469}
470
David Howellsc4028952006-11-22 14:57:56 +0000471static void u132_hcd_monitor_work(struct work_struct *work)
Tony Olechd774efe2006-09-13 11:27:35 +0100472{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700473 struct u132 *u132 = container_of(work, struct u132, monitor.work);
474 if (u132->going > 1) {
475 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
476 , u132->going);
477 u132_monitor_put_kref(u132);
478 return;
479 } else if (u132->going > 0) {
480 dev_err(&u132->platform_dev->dev, "device is being removed\n");
481 u132_monitor_put_kref(u132);
482 return;
483 } else {
484 int retval;
485 mutex_lock(&u132->sw_lock);
486 retval = read_roothub_info(u132);
487 if (retval) {
488 struct usb_hcd *hcd = u132_to_hcd(u132);
489 u132_disable(u132);
490 u132->going = 1;
491 mutex_unlock(&u132->sw_lock);
492 usb_hc_died(hcd);
493 ftdi_elan_gone_away(u132->platform_dev);
494 u132_monitor_put_kref(u132);
495 return;
496 } else {
497 u132_monitor_requeue_work(u132, 500);
498 mutex_unlock(&u132->sw_lock);
499 return;
500 }
501 }
Tony Olechd774efe2006-09-13 11:27:35 +0100502}
503
504static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700505 struct urb *urb, int status)
Tony Olechd774efe2006-09-13 11:27:35 +0100506{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700507 struct u132_ring *ring;
508 unsigned long irqs;
509 struct usb_hcd *hcd = u132_to_hcd(u132);
510 urb->error_count = 0;
511 spin_lock_irqsave(&endp->queue_lock.slock, irqs);
Alan Sterne9df41c2007-08-08 11:48:02 -0400512 usb_hcd_unlink_urb_from_ep(hcd, urb);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700513 endp->queue_next += 1;
514 if (ENDP_QUEUE_SIZE > --endp->queue_size) {
515 endp->active = 0;
516 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
517 } else {
518 struct list_head *next = endp->urb_more.next;
519 struct u132_urbq *urbq = list_entry(next, struct u132_urbq,
520 urb_more);
521 list_del(next);
522 endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] =
523 urbq->urb;
524 endp->active = 0;
525 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
526 kfree(urbq);
527 }
Daniel Walker50d8ca92008-03-23 00:00:02 -0700528 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700529 ring = endp->ring;
530 ring->in_use = 0;
531 u132_ring_cancel_work(u132, ring);
532 u132_ring_queue_work(u132, ring, 0);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700533 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700534 u132_endp_put_kref(u132, endp);
Alan Stern4a000272007-08-24 15:42:24 -0400535 usb_hcd_giveback_urb(hcd, urb, status);
Tony Olechd774efe2006-09-13 11:27:35 +0100536}
537
538static void u132_hcd_forget_urb(struct u132 *u132, struct u132_endp *endp,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700539 struct urb *urb, int status)
Tony Olechd774efe2006-09-13 11:27:35 +0100540{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700541 u132_endp_put_kref(u132, endp);
Tony Olechd774efe2006-09-13 11:27:35 +0100542}
543
544static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700545 struct urb *urb, int status)
Tony Olechd774efe2006-09-13 11:27:35 +0100546{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700547 unsigned long irqs;
548 struct usb_hcd *hcd = u132_to_hcd(u132);
549 urb->error_count = 0;
550 spin_lock_irqsave(&endp->queue_lock.slock, irqs);
Alan Sterne9df41c2007-08-08 11:48:02 -0400551 usb_hcd_unlink_urb_from_ep(hcd, urb);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700552 endp->queue_next += 1;
553 if (ENDP_QUEUE_SIZE > --endp->queue_size) {
554 endp->active = 0;
555 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
556 } else {
557 struct list_head *next = endp->urb_more.next;
558 struct u132_urbq *urbq = list_entry(next, struct u132_urbq,
559 urb_more);
560 list_del(next);
561 endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] =
562 urbq->urb;
563 endp->active = 0;
564 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
565 kfree(urbq);
Joe Perches7f26b3a2010-08-04 10:40:08 -0700566 }
567 usb_hcd_giveback_urb(hcd, urb, status);
Tony Olechd774efe2006-09-13 11:27:35 +0100568}
569
570static inline int edset_input(struct u132 *u132, struct u132_ring *ring,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700571 struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
572 void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
573 int toggle_bits, int error_count, int condition_code, int repeat_number,
574 int halted, int skipped, int actual, int non_null))
Tony Olechd774efe2006-09-13 11:27:35 +0100575{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700576 return usb_ftdi_elan_edset_input(u132->platform_dev, ring->number, endp,
577 urb, address, endp->usb_endp, toggle_bits, callback);
Tony Olechd774efe2006-09-13 11:27:35 +0100578}
579
580static inline int edset_setup(struct u132 *u132, struct u132_ring *ring,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700581 struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
582 void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
583 int toggle_bits, int error_count, int condition_code, int repeat_number,
584 int halted, int skipped, int actual, int non_null))
Tony Olechd774efe2006-09-13 11:27:35 +0100585{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700586 return usb_ftdi_elan_edset_setup(u132->platform_dev, ring->number, endp,
587 urb, address, endp->usb_endp, toggle_bits, callback);
Tony Olechd774efe2006-09-13 11:27:35 +0100588}
589
590static inline int edset_single(struct u132 *u132, struct u132_ring *ring,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700591 struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
592 void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
593 int toggle_bits, int error_count, int condition_code, int repeat_number,
594 int halted, int skipped, int actual, int non_null))
Tony Olechd774efe2006-09-13 11:27:35 +0100595{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700596 return usb_ftdi_elan_edset_single(u132->platform_dev, ring->number,
597 endp, urb, address, endp->usb_endp, toggle_bits, callback);
Tony Olechd774efe2006-09-13 11:27:35 +0100598}
599
600static inline int edset_output(struct u132 *u132, struct u132_ring *ring,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700601 struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
602 void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
603 int toggle_bits, int error_count, int condition_code, int repeat_number,
604 int halted, int skipped, int actual, int non_null))
Tony Olechd774efe2006-09-13 11:27:35 +0100605{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700606 return usb_ftdi_elan_edset_output(u132->platform_dev, ring->number,
607 endp, urb, address, endp->usb_endp, toggle_bits, callback);
Tony Olechd774efe2006-09-13 11:27:35 +0100608}
609
610
611/*
612* must not LOCK sw_lock
613*
614*/
615static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700616 int len, int toggle_bits, int error_count, int condition_code,
617 int repeat_number, int halted, int skipped, int actual, int non_null)
Tony Olechd774efe2006-09-13 11:27:35 +0100618{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700619 struct u132_endp *endp = data;
620 struct u132 *u132 = endp->u132;
621 u8 address = u132->addr[endp->usb_addr].address;
622 struct u132_udev *udev = &u132->udev[address];
Daniel Walker50d8ca92008-03-23 00:00:02 -0700623 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700624 if (u132->going > 1) {
625 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
626 , u132->going);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700627 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700628 u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
629 return;
630 } else if (endp->dequeueing) {
631 endp->dequeueing = 0;
Daniel Walker50d8ca92008-03-23 00:00:02 -0700632 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700633 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
634 return;
635 } else if (u132->going > 0) {
Alan Sterneb231052007-08-21 15:40:36 -0400636 dev_err(&u132->platform_dev->dev, "device is being removed "
637 "urb=%p\n", urb);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700638 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700639 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
640 return;
Alan Sterneb231052007-08-21 15:40:36 -0400641 } else if (!urb->unlinked) {
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700642 struct u132_ring *ring = endp->ring;
643 u8 *u = urb->transfer_buffer + urb->actual_length;
644 u8 *b = buf;
645 int L = len;
646
647 while (L-- > 0)
648 *u++ = *b++;
649
650 urb->actual_length += len;
651 if ((condition_code == TD_CC_NOERROR) &&
652 (urb->transfer_buffer_length > urb->actual_length)) {
653 endp->toggle_bits = toggle_bits;
654 usb_settoggle(udev->usb_device, endp->usb_endp, 0,
655 1 & toggle_bits);
656 if (urb->actual_length > 0) {
657 int retval;
Daniel Walker50d8ca92008-03-23 00:00:02 -0700658 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700659 retval = edset_single(u132, ring, endp, urb,
660 address, endp->toggle_bits,
661 u132_hcd_interrupt_recv);
662 if (retval != 0)
663 u132_hcd_giveback_urb(u132, endp, urb,
664 retval);
665 } else {
666 ring->in_use = 0;
667 endp->active = 0;
668 endp->jiffies = jiffies +
669 msecs_to_jiffies(urb->interval);
670 u132_ring_cancel_work(u132, ring);
671 u132_ring_queue_work(u132, ring, 0);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700672 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700673 u132_endp_put_kref(u132, endp);
674 }
675 return;
676 } else if ((condition_code == TD_DATAUNDERRUN) &&
677 ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) {
678 endp->toggle_bits = toggle_bits;
679 usb_settoggle(udev->usb_device, endp->usb_endp, 0,
680 1 & toggle_bits);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700681 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700682 u132_hcd_giveback_urb(u132, endp, urb, 0);
683 return;
684 } else {
685 if (condition_code == TD_CC_NOERROR) {
686 endp->toggle_bits = toggle_bits;
687 usb_settoggle(udev->usb_device, endp->usb_endp,
688 0, 1 & toggle_bits);
689 } else if (condition_code == TD_CC_STALL) {
690 endp->toggle_bits = 0x2;
691 usb_settoggle(udev->usb_device, endp->usb_endp,
692 0, 0);
693 } else {
694 endp->toggle_bits = 0x2;
695 usb_settoggle(udev->usb_device, endp->usb_endp,
696 0, 0);
697 dev_err(&u132->platform_dev->dev, "urb=%p givin"
698 "g back INTERRUPT %s\n", urb,
699 cc_to_text[condition_code]);
700 }
Daniel Walker50d8ca92008-03-23 00:00:02 -0700701 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700702 u132_hcd_giveback_urb(u132, endp, urb,
703 cc_to_error[condition_code]);
704 return;
705 }
706 } else {
Alan Sterneb231052007-08-21 15:40:36 -0400707 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
708 "unlinked=%d\n", urb, urb->unlinked);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700709 mutex_unlock(&u132->scheduler_lock);
Alan Stern4a000272007-08-24 15:42:24 -0400710 u132_hcd_giveback_urb(u132, endp, urb, 0);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700711 return;
712 }
Tony Olechd774efe2006-09-13 11:27:35 +0100713}
714
715static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700716 int len, int toggle_bits, int error_count, int condition_code,
717 int repeat_number, int halted, int skipped, int actual, int non_null)
Tony Olechd774efe2006-09-13 11:27:35 +0100718{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700719 struct u132_endp *endp = data;
720 struct u132 *u132 = endp->u132;
721 u8 address = u132->addr[endp->usb_addr].address;
Daniel Walker50d8ca92008-03-23 00:00:02 -0700722 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700723 if (u132->going > 1) {
724 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
725 , u132->going);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700726 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700727 u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
728 return;
729 } else if (endp->dequeueing) {
730 endp->dequeueing = 0;
Daniel Walker50d8ca92008-03-23 00:00:02 -0700731 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700732 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
733 return;
734 } else if (u132->going > 0) {
Alan Sterneb231052007-08-21 15:40:36 -0400735 dev_err(&u132->platform_dev->dev, "device is being removed "
736 "urb=%p\n", urb);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700737 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700738 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
739 return;
Alan Sterneb231052007-08-21 15:40:36 -0400740 } else if (!urb->unlinked) {
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700741 struct u132_ring *ring = endp->ring;
742 urb->actual_length += len;
743 endp->toggle_bits = toggle_bits;
744 if (urb->transfer_buffer_length > urb->actual_length) {
745 int retval;
Daniel Walker50d8ca92008-03-23 00:00:02 -0700746 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700747 retval = edset_output(u132, ring, endp, urb, address,
748 endp->toggle_bits, u132_hcd_bulk_output_sent);
749 if (retval != 0)
750 u132_hcd_giveback_urb(u132, endp, urb, retval);
751 return;
752 } else {
Daniel Walker50d8ca92008-03-23 00:00:02 -0700753 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700754 u132_hcd_giveback_urb(u132, endp, urb, 0);
755 return;
756 }
757 } else {
Alan Sterneb231052007-08-21 15:40:36 -0400758 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
759 "unlinked=%d\n", urb, urb->unlinked);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700760 mutex_unlock(&u132->scheduler_lock);
Alan Stern4a000272007-08-24 15:42:24 -0400761 u132_hcd_giveback_urb(u132, endp, urb, 0);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700762 return;
763 }
Tony Olechd774efe2006-09-13 11:27:35 +0100764}
765
766static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700767 int len, int toggle_bits, int error_count, int condition_code,
768 int repeat_number, int halted, int skipped, int actual, int non_null)
Tony Olechd774efe2006-09-13 11:27:35 +0100769{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700770 struct u132_endp *endp = data;
771 struct u132 *u132 = endp->u132;
772 u8 address = u132->addr[endp->usb_addr].address;
773 struct u132_udev *udev = &u132->udev[address];
Daniel Walker50d8ca92008-03-23 00:00:02 -0700774 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700775 if (u132->going > 1) {
776 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
777 , u132->going);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700778 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700779 u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
780 return;
781 } else if (endp->dequeueing) {
782 endp->dequeueing = 0;
Daniel Walker50d8ca92008-03-23 00:00:02 -0700783 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700784 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
785 return;
786 } else if (u132->going > 0) {
Alan Sterneb231052007-08-21 15:40:36 -0400787 dev_err(&u132->platform_dev->dev, "device is being removed "
788 "urb=%p\n", urb);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700789 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700790 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
791 return;
Alan Sterneb231052007-08-21 15:40:36 -0400792 } else if (!urb->unlinked) {
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700793 struct u132_ring *ring = endp->ring;
794 u8 *u = urb->transfer_buffer + urb->actual_length;
795 u8 *b = buf;
796 int L = len;
797
798 while (L-- > 0)
799 *u++ = *b++;
800
801 urb->actual_length += len;
802 if ((condition_code == TD_CC_NOERROR) &&
803 (urb->transfer_buffer_length > urb->actual_length)) {
804 int retval;
805 endp->toggle_bits = toggle_bits;
806 usb_settoggle(udev->usb_device, endp->usb_endp, 0,
807 1 & toggle_bits);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700808 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700809 retval = usb_ftdi_elan_edset_input(u132->platform_dev,
810 ring->number, endp, urb, address,
811 endp->usb_endp, endp->toggle_bits,
812 u132_hcd_bulk_input_recv);
813 if (retval != 0)
814 u132_hcd_giveback_urb(u132, endp, urb, retval);
815 return;
816 } else if (condition_code == TD_CC_NOERROR) {
817 endp->toggle_bits = toggle_bits;
818 usb_settoggle(udev->usb_device, endp->usb_endp, 0,
819 1 & toggle_bits);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700820 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700821 u132_hcd_giveback_urb(u132, endp, urb,
822 cc_to_error[condition_code]);
823 return;
824 } else if ((condition_code == TD_DATAUNDERRUN) &&
825 ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) {
826 endp->toggle_bits = toggle_bits;
827 usb_settoggle(udev->usb_device, endp->usb_endp, 0,
828 1 & toggle_bits);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700829 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700830 u132_hcd_giveback_urb(u132, endp, urb, 0);
831 return;
832 } else if (condition_code == TD_DATAUNDERRUN) {
833 endp->toggle_bits = toggle_bits;
834 usb_settoggle(udev->usb_device, endp->usb_endp, 0,
835 1 & toggle_bits);
836 dev_warn(&u132->platform_dev->dev, "urb=%p(SHORT NOT OK"
837 ") giving back BULK IN %s\n", urb,
838 cc_to_text[condition_code]);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700839 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700840 u132_hcd_giveback_urb(u132, endp, urb, 0);
841 return;
842 } else if (condition_code == TD_CC_STALL) {
843 endp->toggle_bits = 0x2;
844 usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700845 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700846 u132_hcd_giveback_urb(u132, endp, urb,
847 cc_to_error[condition_code]);
848 return;
849 } else {
850 endp->toggle_bits = 0x2;
851 usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0);
852 dev_err(&u132->platform_dev->dev, "urb=%p giving back B"
853 "ULK IN code=%d %s\n", urb, condition_code,
854 cc_to_text[condition_code]);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700855 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700856 u132_hcd_giveback_urb(u132, endp, urb,
857 cc_to_error[condition_code]);
858 return;
859 }
860 } else {
Alan Sterneb231052007-08-21 15:40:36 -0400861 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
862 "unlinked=%d\n", urb, urb->unlinked);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700863 mutex_unlock(&u132->scheduler_lock);
Alan Stern4a000272007-08-24 15:42:24 -0400864 u132_hcd_giveback_urb(u132, endp, urb, 0);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700865 return;
866 }
Tony Olechd774efe2006-09-13 11:27:35 +0100867}
868
869static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700870 int len, int toggle_bits, int error_count, int condition_code,
871 int repeat_number, int halted, int skipped, int actual, int non_null)
Tony Olechd774efe2006-09-13 11:27:35 +0100872{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700873 struct u132_endp *endp = data;
874 struct u132 *u132 = endp->u132;
Daniel Walker50d8ca92008-03-23 00:00:02 -0700875 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700876 if (u132->going > 1) {
877 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
878 , u132->going);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700879 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700880 u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
881 return;
882 } else if (endp->dequeueing) {
883 endp->dequeueing = 0;
Daniel Walker50d8ca92008-03-23 00:00:02 -0700884 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700885 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
886 return;
887 } else if (u132->going > 0) {
Alan Sterneb231052007-08-21 15:40:36 -0400888 dev_err(&u132->platform_dev->dev, "device is being removed "
889 "urb=%p\n", urb);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700890 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700891 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
892 return;
Alan Sterneb231052007-08-21 15:40:36 -0400893 } else if (!urb->unlinked) {
Daniel Walker50d8ca92008-03-23 00:00:02 -0700894 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700895 u132_hcd_giveback_urb(u132, endp, urb, 0);
896 return;
897 } else {
Alan Sterneb231052007-08-21 15:40:36 -0400898 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
899 "unlinked=%d\n", urb, urb->unlinked);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700900 mutex_unlock(&u132->scheduler_lock);
Alan Stern4a000272007-08-24 15:42:24 -0400901 u132_hcd_giveback_urb(u132, endp, urb, 0);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700902 return;
903 }
Tony Olechd774efe2006-09-13 11:27:35 +0100904}
905
906static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700907 int len, int toggle_bits, int error_count, int condition_code,
908 int repeat_number, int halted, int skipped, int actual, int non_null)
Tony Olechd774efe2006-09-13 11:27:35 +0100909{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700910 struct u132_endp *endp = data;
911 struct u132 *u132 = endp->u132;
912 u8 address = u132->addr[endp->usb_addr].address;
Daniel Walker50d8ca92008-03-23 00:00:02 -0700913 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700914 if (u132->going > 1) {
915 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
916 , u132->going);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700917 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700918 u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
919 return;
920 } else if (endp->dequeueing) {
921 endp->dequeueing = 0;
Daniel Walker50d8ca92008-03-23 00:00:02 -0700922 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700923 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
924 return;
925 } else if (u132->going > 0) {
Alan Sterneb231052007-08-21 15:40:36 -0400926 dev_err(&u132->platform_dev->dev, "device is being removed "
927 "urb=%p\n", urb);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700928 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700929 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
930 return;
Alan Sterneb231052007-08-21 15:40:36 -0400931 } else if (!urb->unlinked) {
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700932 struct u132_ring *ring = endp->ring;
933 u8 *u = urb->transfer_buffer;
934 u8 *b = buf;
935 int L = len;
936
937 while (L-- > 0)
938 *u++ = *b++;
939
940 urb->actual_length = len;
941 if ((condition_code == TD_CC_NOERROR) || ((condition_code ==
942 TD_DATAUNDERRUN) && ((urb->transfer_flags &
943 URB_SHORT_NOT_OK) == 0))) {
944 int retval;
Daniel Walker50d8ca92008-03-23 00:00:02 -0700945 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700946 retval = usb_ftdi_elan_edset_empty(u132->platform_dev,
947 ring->number, endp, urb, address,
948 endp->usb_endp, 0x3,
949 u132_hcd_configure_empty_sent);
950 if (retval != 0)
951 u132_hcd_giveback_urb(u132, endp, urb, retval);
952 return;
953 } else if (condition_code == TD_CC_STALL) {
Daniel Walker50d8ca92008-03-23 00:00:02 -0700954 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700955 dev_warn(&u132->platform_dev->dev, "giving back SETUP I"
956 "NPUT STALL urb %p\n", urb);
957 u132_hcd_giveback_urb(u132, endp, urb,
958 cc_to_error[condition_code]);
959 return;
960 } else {
Daniel Walker50d8ca92008-03-23 00:00:02 -0700961 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700962 dev_err(&u132->platform_dev->dev, "giving back SETUP IN"
963 "PUT %s urb %p\n", cc_to_text[condition_code],
964 urb);
965 u132_hcd_giveback_urb(u132, endp, urb,
966 cc_to_error[condition_code]);
967 return;
968 }
969 } else {
Alan Sterneb231052007-08-21 15:40:36 -0400970 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
971 "unlinked=%d\n", urb, urb->unlinked);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700972 mutex_unlock(&u132->scheduler_lock);
Alan Stern4a000272007-08-24 15:42:24 -0400973 u132_hcd_giveback_urb(u132, endp, urb, 0);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700974 return;
975 }
Tony Olechd774efe2006-09-13 11:27:35 +0100976}
977
978static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf,
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700979 int len, int toggle_bits, int error_count, int condition_code,
980 int repeat_number, int halted, int skipped, int actual, int non_null)
Tony Olechd774efe2006-09-13 11:27:35 +0100981{
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700982 struct u132_endp *endp = data;
983 struct u132 *u132 = endp->u132;
Daniel Walker50d8ca92008-03-23 00:00:02 -0700984 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700985 if (u132->going > 1) {
986 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
987 , u132->going);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700988 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700989 u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
990 return;
991 } else if (endp->dequeueing) {
992 endp->dequeueing = 0;
Daniel Walker50d8ca92008-03-23 00:00:02 -0700993 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -0700994 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
995 return;
996 } else if (u132->going > 0) {
Alan Sterneb231052007-08-21 15:40:36 -0400997 dev_err(&u132->platform_dev->dev, "device is being removed "
998 "urb=%p\n", urb);
Daniel Walker50d8ca92008-03-23 00:00:02 -0700999 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001000 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
1001 return;
Alan Sterneb231052007-08-21 15:40:36 -04001002 } else if (!urb->unlinked) {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001003 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001004 u132_hcd_giveback_urb(u132, endp, urb, 0);
1005 return;
1006 } else {
Alan Sterneb231052007-08-21 15:40:36 -04001007 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
1008 "unlinked=%d\n", urb, urb->unlinked);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001009 mutex_unlock(&u132->scheduler_lock);
Alan Stern4a000272007-08-24 15:42:24 -04001010 u132_hcd_giveback_urb(u132, endp, urb, 0);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001011 return;
1012 }
Tony Olechd774efe2006-09-13 11:27:35 +01001013}
1014
1015static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001016 int len, int toggle_bits, int error_count, int condition_code,
1017 int repeat_number, int halted, int skipped, int actual, int non_null)
Tony Olechd774efe2006-09-13 11:27:35 +01001018{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001019 struct u132_endp *endp = data;
1020 struct u132 *u132 = endp->u132;
1021 u8 address = u132->addr[endp->usb_addr].address;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001022 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001023 if (u132->going > 1) {
1024 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
1025 , u132->going);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001026 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001027 u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
1028 return;
1029 } else if (endp->dequeueing) {
1030 endp->dequeueing = 0;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001031 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001032 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
1033 return;
1034 } else if (u132->going > 0) {
Alan Sterneb231052007-08-21 15:40:36 -04001035 dev_err(&u132->platform_dev->dev, "device is being removed "
1036 "urb=%p\n", urb);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001037 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001038 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
1039 return;
Alan Sterneb231052007-08-21 15:40:36 -04001040 } else if (!urb->unlinked) {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001041 if (usb_pipein(urb->pipe)) {
1042 int retval;
1043 struct u132_ring *ring = endp->ring;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001044 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001045 retval = usb_ftdi_elan_edset_input(u132->platform_dev,
1046 ring->number, endp, urb, address,
1047 endp->usb_endp, 0,
1048 u132_hcd_configure_input_recv);
1049 if (retval != 0)
1050 u132_hcd_giveback_urb(u132, endp, urb, retval);
1051 return;
1052 } else {
1053 int retval;
1054 struct u132_ring *ring = endp->ring;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001055 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001056 retval = usb_ftdi_elan_edset_input(u132->platform_dev,
1057 ring->number, endp, urb, address,
1058 endp->usb_endp, 0,
1059 u132_hcd_configure_empty_recv);
1060 if (retval != 0)
1061 u132_hcd_giveback_urb(u132, endp, urb, retval);
1062 return;
1063 }
1064 } else {
Alan Sterneb231052007-08-21 15:40:36 -04001065 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
1066 "unlinked=%d\n", urb, urb->unlinked);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001067 mutex_unlock(&u132->scheduler_lock);
Alan Stern4a000272007-08-24 15:42:24 -04001068 u132_hcd_giveback_urb(u132, endp, urb, 0);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001069 return;
1070 }
Tony Olechd774efe2006-09-13 11:27:35 +01001071}
1072
1073static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001074 u8 *buf, int len, int toggle_bits, int error_count, int condition_code,
1075 int repeat_number, int halted, int skipped, int actual, int non_null)
Tony Olechd774efe2006-09-13 11:27:35 +01001076{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001077 struct u132_endp *endp = data;
1078 struct u132 *u132 = endp->u132;
1079 u8 address = u132->addr[endp->usb_addr].address;
1080 struct u132_udev *udev = &u132->udev[address];
Daniel Walker50d8ca92008-03-23 00:00:02 -07001081 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001082 if (u132->going > 1) {
1083 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
1084 , u132->going);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001085 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001086 u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
1087 return;
1088 } else if (endp->dequeueing) {
1089 endp->dequeueing = 0;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001090 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001091 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
1092 return;
1093 } else if (u132->going > 0) {
Alan Sterneb231052007-08-21 15:40:36 -04001094 dev_err(&u132->platform_dev->dev, "device is being removed "
1095 "urb=%p\n", urb);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001096 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001097 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
1098 return;
Alan Sterneb231052007-08-21 15:40:36 -04001099 } else if (!urb->unlinked) {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001100 u132->addr[0].address = 0;
1101 endp->usb_addr = udev->usb_addr;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001102 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001103 u132_hcd_giveback_urb(u132, endp, urb, 0);
1104 return;
1105 } else {
Alan Sterneb231052007-08-21 15:40:36 -04001106 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
1107 "unlinked=%d\n", urb, urb->unlinked);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001108 mutex_unlock(&u132->scheduler_lock);
Alan Stern4a000272007-08-24 15:42:24 -04001109 u132_hcd_giveback_urb(u132, endp, urb, 0);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001110 return;
1111 }
Tony Olechd774efe2006-09-13 11:27:35 +01001112}
1113
1114static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001115 u8 *buf, int len, int toggle_bits, int error_count, int condition_code,
1116 int repeat_number, int halted, int skipped, int actual, int non_null)
Tony Olechd774efe2006-09-13 11:27:35 +01001117{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001118 struct u132_endp *endp = data;
1119 struct u132 *u132 = endp->u132;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001120 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001121 if (u132->going > 1) {
1122 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
1123 , u132->going);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001124 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001125 u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
1126 return;
1127 } else if (endp->dequeueing) {
1128 endp->dequeueing = 0;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001129 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001130 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
1131 return;
1132 } else if (u132->going > 0) {
Alan Sterneb231052007-08-21 15:40:36 -04001133 dev_err(&u132->platform_dev->dev, "device is being removed "
1134 "urb=%p\n", urb);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001135 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001136 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
1137 return;
Alan Sterneb231052007-08-21 15:40:36 -04001138 } else if (!urb->unlinked) {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001139 int retval;
1140 struct u132_ring *ring = endp->ring;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001141 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001142 retval = usb_ftdi_elan_edset_input(u132->platform_dev,
1143 ring->number, endp, urb, 0, endp->usb_endp, 0,
1144 u132_hcd_enumeration_empty_recv);
1145 if (retval != 0)
1146 u132_hcd_giveback_urb(u132, endp, urb, retval);
1147 return;
1148 } else {
Alan Sterneb231052007-08-21 15:40:36 -04001149 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
1150 "unlinked=%d\n", urb, urb->unlinked);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001151 mutex_unlock(&u132->scheduler_lock);
Alan Stern4a000272007-08-24 15:42:24 -04001152 u132_hcd_giveback_urb(u132, endp, urb, 0);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001153 return;
1154 }
Tony Olechd774efe2006-09-13 11:27:35 +01001155}
1156
1157static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001158 int len, int toggle_bits, int error_count, int condition_code,
1159 int repeat_number, int halted, int skipped, int actual, int non_null)
Tony Olechd774efe2006-09-13 11:27:35 +01001160{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001161 struct u132_endp *endp = data;
1162 struct u132 *u132 = endp->u132;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001163 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001164 if (u132->going > 1) {
1165 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
1166 , u132->going);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001167 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001168 u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
1169 return;
1170 } else if (endp->dequeueing) {
1171 endp->dequeueing = 0;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001172 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001173 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
1174 return;
1175 } else if (u132->going > 0) {
Alan Sterneb231052007-08-21 15:40:36 -04001176 dev_err(&u132->platform_dev->dev, "device is being removed "
1177 "urb=%p\n", urb);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001178 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001179 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
1180 return;
Alan Sterneb231052007-08-21 15:40:36 -04001181 } else if (!urb->unlinked) {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001182 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001183 u132_hcd_giveback_urb(u132, endp, urb, 0);
1184 return;
1185 } else {
Alan Sterneb231052007-08-21 15:40:36 -04001186 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
1187 "unlinked=%d\n", urb, urb->unlinked);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001188 mutex_unlock(&u132->scheduler_lock);
Alan Stern4a000272007-08-24 15:42:24 -04001189 u132_hcd_giveback_urb(u132, endp, urb, 0);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001190 return;
1191 }
Tony Olechd774efe2006-09-13 11:27:35 +01001192}
1193
1194static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001195 int len, int toggle_bits, int error_count, int condition_code,
1196 int repeat_number, int halted, int skipped, int actual, int non_null)
Tony Olechd774efe2006-09-13 11:27:35 +01001197{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001198 struct u132_endp *endp = data;
1199 struct u132 *u132 = endp->u132;
1200 u8 address = u132->addr[endp->usb_addr].address;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001201 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001202 if (u132->going > 1) {
1203 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
1204 , u132->going);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001205 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001206 u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
1207 return;
1208 } else if (endp->dequeueing) {
1209 endp->dequeueing = 0;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001210 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001211 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
1212 return;
1213 } else if (u132->going > 0) {
Alan Sterneb231052007-08-21 15:40:36 -04001214 dev_err(&u132->platform_dev->dev, "device is being removed "
1215 "urb=%p\n", urb);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001216 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001217 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
1218 return;
Alan Sterneb231052007-08-21 15:40:36 -04001219 } else if (!urb->unlinked) {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001220 int retval;
1221 struct u132_ring *ring = endp->ring;
1222 u8 *u = urb->transfer_buffer;
1223 u8 *b = buf;
1224 int L = len;
1225
1226 while (L-- > 0)
1227 *u++ = *b++;
1228
1229 urb->actual_length = len;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001230 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001231 retval = usb_ftdi_elan_edset_empty(u132->platform_dev,
1232 ring->number, endp, urb, address, endp->usb_endp, 0x3,
1233 u132_hcd_initial_empty_sent);
1234 if (retval != 0)
1235 u132_hcd_giveback_urb(u132, endp, urb, retval);
1236 return;
1237 } else {
Alan Sterneb231052007-08-21 15:40:36 -04001238 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
1239 "unlinked=%d\n", urb, urb->unlinked);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001240 mutex_unlock(&u132->scheduler_lock);
Alan Stern4a000272007-08-24 15:42:24 -04001241 u132_hcd_giveback_urb(u132, endp, urb, 0);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001242 return;
1243 }
Tony Olechd774efe2006-09-13 11:27:35 +01001244}
1245
1246static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001247 int len, int toggle_bits, int error_count, int condition_code,
1248 int repeat_number, int halted, int skipped, int actual, int non_null)
Tony Olechd774efe2006-09-13 11:27:35 +01001249{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001250 struct u132_endp *endp = data;
1251 struct u132 *u132 = endp->u132;
1252 u8 address = u132->addr[endp->usb_addr].address;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001253 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001254 if (u132->going > 1) {
1255 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
1256 , u132->going);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001257 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001258 u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
1259 return;
1260 } else if (endp->dequeueing) {
1261 endp->dequeueing = 0;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001262 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001263 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
1264 return;
1265 } else if (u132->going > 0) {
Alan Sterneb231052007-08-21 15:40:36 -04001266 dev_err(&u132->platform_dev->dev, "device is being removed "
1267 "urb=%p\n", urb);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001268 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001269 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
1270 return;
Alan Sterneb231052007-08-21 15:40:36 -04001271 } else if (!urb->unlinked) {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001272 int retval;
1273 struct u132_ring *ring = endp->ring;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001274 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001275 retval = usb_ftdi_elan_edset_input(u132->platform_dev,
1276 ring->number, endp, urb, address, endp->usb_endp, 0,
1277 u132_hcd_initial_input_recv);
1278 if (retval != 0)
1279 u132_hcd_giveback_urb(u132, endp, urb, retval);
1280 return;
1281 } else {
Alan Sterneb231052007-08-21 15:40:36 -04001282 dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
1283 "unlinked=%d\n", urb, urb->unlinked);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001284 mutex_unlock(&u132->scheduler_lock);
Alan Stern4a000272007-08-24 15:42:24 -04001285 u132_hcd_giveback_urb(u132, endp, urb, 0);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001286 return;
1287 }
Tony Olechd774efe2006-09-13 11:27:35 +01001288}
1289
Tony Olechd774efe2006-09-13 11:27:35 +01001290/*
1291* this work function is only executed from the work queue
1292*
1293*/
David Howellsc4028952006-11-22 14:57:56 +00001294static void u132_hcd_ring_work_scheduler(struct work_struct *work)
Tony Olechd774efe2006-09-13 11:27:35 +01001295{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001296 struct u132_ring *ring =
David Howellsc4028952006-11-22 14:57:56 +00001297 container_of(work, struct u132_ring, scheduler.work);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001298 struct u132 *u132 = ring->u132;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001299 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001300 if (ring->in_use) {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001301 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001302 u132_ring_put_kref(u132, ring);
1303 return;
1304 } else if (ring->curr_endp) {
Geliang Tang4e5d7a82015-12-19 00:34:29 +08001305 struct u132_endp *endp, *last_endp = ring->curr_endp;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001306 unsigned long wakeup = 0;
Geliang Tang4e5d7a82015-12-19 00:34:29 +08001307 list_for_each_entry(endp, &last_endp->endp_ring, endp_ring) {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001308 if (endp->queue_next == endp->queue_last) {
1309 } else if ((endp->delayed == 0)
1310 || time_after_eq(jiffies, endp->jiffies)) {
1311 ring->curr_endp = endp;
1312 u132_endp_cancel_work(u132, last_endp);
1313 u132_endp_queue_work(u132, last_endp, 0);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001314 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001315 u132_ring_put_kref(u132, ring);
1316 return;
1317 } else {
1318 unsigned long delta = endp->jiffies - jiffies;
1319 if (delta > wakeup)
1320 wakeup = delta;
1321 }
1322 }
1323 if (last_endp->queue_next == last_endp->queue_last) {
1324 } else if ((last_endp->delayed == 0) || time_after_eq(jiffies,
1325 last_endp->jiffies)) {
1326 u132_endp_cancel_work(u132, last_endp);
1327 u132_endp_queue_work(u132, last_endp, 0);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001328 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001329 u132_ring_put_kref(u132, ring);
1330 return;
1331 } else {
1332 unsigned long delta = last_endp->jiffies - jiffies;
1333 if (delta > wakeup)
1334 wakeup = delta;
1335 }
1336 if (wakeup > 0) {
1337 u132_ring_requeue_work(u132, ring, wakeup);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001338 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001339 return;
1340 } else {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001341 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001342 u132_ring_put_kref(u132, ring);
1343 return;
1344 }
1345 } else {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001346 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001347 u132_ring_put_kref(u132, ring);
1348 return;
1349 }
Tony Olechd774efe2006-09-13 11:27:35 +01001350}
1351
David Howellsc4028952006-11-22 14:57:56 +00001352static void u132_hcd_endp_work_scheduler(struct work_struct *work)
Tony Olechd774efe2006-09-13 11:27:35 +01001353{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001354 struct u132_ring *ring;
1355 struct u132_endp *endp =
David Howellsc4028952006-11-22 14:57:56 +00001356 container_of(work, struct u132_endp, scheduler.work);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001357 struct u132 *u132 = endp->u132;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001358 mutex_lock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001359 ring = endp->ring;
1360 if (endp->edset_flush) {
1361 endp->edset_flush = 0;
1362 if (endp->dequeueing)
1363 usb_ftdi_elan_edset_flush(u132->platform_dev,
1364 ring->number, endp);
Daniel Walker50d8ca92008-03-23 00:00:02 -07001365 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001366 u132_endp_put_kref(u132, endp);
1367 return;
1368 } else if (endp->active) {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001369 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001370 u132_endp_put_kref(u132, endp);
1371 return;
1372 } else if (ring->in_use) {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001373 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001374 u132_endp_put_kref(u132, endp);
1375 return;
1376 } else if (endp->queue_next == endp->queue_last) {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001377 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001378 u132_endp_put_kref(u132, endp);
1379 return;
1380 } else if (endp->pipetype == PIPE_INTERRUPT) {
1381 u8 address = u132->addr[endp->usb_addr].address;
1382 if (ring->in_use) {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001383 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001384 u132_endp_put_kref(u132, endp);
1385 return;
1386 } else {
1387 int retval;
1388 struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
1389 endp->queue_next];
1390 endp->active = 1;
1391 ring->curr_endp = endp;
1392 ring->in_use = 1;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001393 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001394 retval = edset_single(u132, ring, endp, urb, address,
1395 endp->toggle_bits, u132_hcd_interrupt_recv);
1396 if (retval != 0)
1397 u132_hcd_giveback_urb(u132, endp, urb, retval);
1398 return;
1399 }
1400 } else if (endp->pipetype == PIPE_CONTROL) {
1401 u8 address = u132->addr[endp->usb_addr].address;
1402 if (ring->in_use) {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001403 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001404 u132_endp_put_kref(u132, endp);
1405 return;
1406 } else if (address == 0) {
1407 int retval;
1408 struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
1409 endp->queue_next];
1410 endp->active = 1;
1411 ring->curr_endp = endp;
1412 ring->in_use = 1;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001413 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001414 retval = edset_setup(u132, ring, endp, urb, address,
1415 0x2, u132_hcd_initial_setup_sent);
1416 if (retval != 0)
1417 u132_hcd_giveback_urb(u132, endp, urb, retval);
1418 return;
1419 } else if (endp->usb_addr == 0) {
1420 int retval;
1421 struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
1422 endp->queue_next];
1423 endp->active = 1;
1424 ring->curr_endp = endp;
1425 ring->in_use = 1;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001426 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001427 retval = edset_setup(u132, ring, endp, urb, 0, 0x2,
1428 u132_hcd_enumeration_address_sent);
1429 if (retval != 0)
1430 u132_hcd_giveback_urb(u132, endp, urb, retval);
1431 return;
1432 } else {
1433 int retval;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001434 struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
1435 endp->queue_next];
Randy Dunlap1d6ec812010-05-06 16:46:03 -07001436 address = u132->addr[endp->usb_addr].address;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001437 endp->active = 1;
1438 ring->curr_endp = endp;
1439 ring->in_use = 1;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001440 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001441 retval = edset_setup(u132, ring, endp, urb, address,
1442 0x2, u132_hcd_configure_setup_sent);
1443 if (retval != 0)
1444 u132_hcd_giveback_urb(u132, endp, urb, retval);
1445 return;
1446 }
1447 } else {
1448 if (endp->input) {
1449 u8 address = u132->addr[endp->usb_addr].address;
1450 if (ring->in_use) {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001451 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001452 u132_endp_put_kref(u132, endp);
1453 return;
1454 } else {
1455 int retval;
1456 struct urb *urb = endp->urb_list[
1457 ENDP_QUEUE_MASK & endp->queue_next];
1458 endp->active = 1;
1459 ring->curr_endp = endp;
1460 ring->in_use = 1;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001461 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001462 retval = edset_input(u132, ring, endp, urb,
1463 address, endp->toggle_bits,
1464 u132_hcd_bulk_input_recv);
1465 if (retval == 0) {
1466 } else
1467 u132_hcd_giveback_urb(u132, endp, urb,
1468 retval);
1469 return;
1470 }
1471 } else { /* output pipe */
1472 u8 address = u132->addr[endp->usb_addr].address;
1473 if (ring->in_use) {
Daniel Walker50d8ca92008-03-23 00:00:02 -07001474 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001475 u132_endp_put_kref(u132, endp);
1476 return;
1477 } else {
1478 int retval;
1479 struct urb *urb = endp->urb_list[
1480 ENDP_QUEUE_MASK & endp->queue_next];
1481 endp->active = 1;
1482 ring->curr_endp = endp;
1483 ring->in_use = 1;
Daniel Walker50d8ca92008-03-23 00:00:02 -07001484 mutex_unlock(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001485 retval = edset_output(u132, ring, endp, urb,
1486 address, endp->toggle_bits,
1487 u132_hcd_bulk_output_sent);
1488 if (retval == 0) {
1489 } else
1490 u132_hcd_giveback_urb(u132, endp, urb,
1491 retval);
1492 return;
1493 }
1494 }
1495 }
Tony Olechd774efe2006-09-13 11:27:35 +01001496}
Gabriel C5b570d42007-07-30 12:57:03 +02001497#ifdef CONFIG_PM
Tony Olechd774efe2006-09-13 11:27:35 +01001498
1499static void port_power(struct u132 *u132, int pn, int is_on)
1500{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001501 u132->port[pn].power = is_on;
Tony Olechd774efe2006-09-13 11:27:35 +01001502}
1503
Gabriel C5b570d42007-07-30 12:57:03 +02001504#endif
1505
Tony Olechd774efe2006-09-13 11:27:35 +01001506static void u132_power(struct u132 *u132, int is_on)
1507{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001508 struct usb_hcd *hcd = u132_to_hcd(u132)
1509 ; /* hub is inactive unless the port is powered */
1510 if (is_on) {
1511 if (u132->power)
1512 return;
1513 u132->power = 1;
1514 } else {
1515 u132->power = 0;
1516 hcd->state = HC_STATE_HALT;
1517 }
Tony Olechd774efe2006-09-13 11:27:35 +01001518}
1519
1520static int u132_periodic_reinit(struct u132 *u132)
1521{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001522 int retval;
1523 u32 fi = u132->hc_fminterval & 0x03fff;
1524 u32 fit;
1525 u32 fminterval;
1526 retval = u132_read_pcimem(u132, fminterval, &fminterval);
1527 if (retval)
1528 return retval;
1529 fit = fminterval & FIT;
1530 retval = u132_write_pcimem(u132, fminterval,
1531 (fit ^ FIT) | u132->hc_fminterval);
1532 if (retval)
1533 return retval;
Saurabh Karajgaonkar8602b082015-08-04 14:03:45 +00001534 return u132_write_pcimem(u132, periodicstart,
1535 ((9 * fi) / 10) & 0x3fff);
Tony Olechd774efe2006-09-13 11:27:35 +01001536}
1537
1538static char *hcfs2string(int state)
1539{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001540 switch (state) {
1541 case OHCI_USB_RESET:
1542 return "reset";
1543 case OHCI_USB_RESUME:
1544 return "resume";
1545 case OHCI_USB_OPER:
1546 return "operational";
1547 case OHCI_USB_SUSPEND:
1548 return "suspend";
1549 }
1550 return "?";
Tony Olechd774efe2006-09-13 11:27:35 +01001551}
1552
Tony Olechd774efe2006-09-13 11:27:35 +01001553static int u132_init(struct u132 *u132)
1554{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001555 int retval;
1556 u32 control;
1557 u132_disable(u132);
1558 u132->next_statechange = jiffies;
1559 retval = u132_write_pcimem(u132, intrdisable, OHCI_INTR_MIE);
1560 if (retval)
1561 return retval;
1562 retval = u132_read_pcimem(u132, control, &control);
1563 if (retval)
1564 return retval;
1565 if (u132->num_ports == 0) {
1566 u32 rh_a = -1;
1567 retval = u132_read_pcimem(u132, roothub.a, &rh_a);
1568 if (retval)
1569 return retval;
1570 u132->num_ports = rh_a & RH_A_NDP;
1571 retval = read_roothub_info(u132);
1572 if (retval)
1573 return retval;
1574 }
1575 if (u132->num_ports > MAX_U132_PORTS)
1576 return -EINVAL;
1577
1578 return 0;
Tony Olechd774efe2006-09-13 11:27:35 +01001579}
1580
1581
1582/* Start an OHCI controller, set the BUS operational
1583* resets USB and controller
1584* enable interrupts
1585*/
1586static int u132_run(struct u132 *u132)
1587{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001588 int retval;
1589 u32 control;
1590 u32 status;
1591 u32 fminterval;
1592 u32 periodicstart;
1593 u32 cmdstatus;
1594 u32 roothub_a;
1595 int mask = OHCI_INTR_INIT;
1596 int first = u132->hc_fminterval == 0;
1597 int sleep_time = 0;
1598 int reset_timeout = 30; /* ... allow extra time */
1599 u132_disable(u132);
1600 if (first) {
1601 u32 temp;
1602 retval = u132_read_pcimem(u132, fminterval, &temp);
1603 if (retval)
1604 return retval;
1605 u132->hc_fminterval = temp & 0x3fff;
1606 u132->hc_fminterval |= FSMP(u132->hc_fminterval) << 16;
1607 }
1608 retval = u132_read_pcimem(u132, control, &u132->hc_control);
1609 if (retval)
1610 return retval;
1611 dev_info(&u132->platform_dev->dev, "resetting from state '%s', control "
1612 "= %08X\n", hcfs2string(u132->hc_control & OHCI_CTRL_HCFS),
1613 u132->hc_control);
1614 switch (u132->hc_control & OHCI_CTRL_HCFS) {
1615 case OHCI_USB_OPER:
1616 sleep_time = 0;
1617 break;
1618 case OHCI_USB_SUSPEND:
1619 case OHCI_USB_RESUME:
1620 u132->hc_control &= OHCI_CTRL_RWC;
1621 u132->hc_control |= OHCI_USB_RESUME;
1622 sleep_time = 10;
1623 break;
1624 default:
1625 u132->hc_control &= OHCI_CTRL_RWC;
1626 u132->hc_control |= OHCI_USB_RESET;
1627 sleep_time = 50;
1628 break;
1629 }
1630 retval = u132_write_pcimem(u132, control, u132->hc_control);
1631 if (retval)
1632 return retval;
1633 retval = u132_read_pcimem(u132, control, &control);
1634 if (retval)
1635 return retval;
1636 msleep(sleep_time);
1637 retval = u132_read_pcimem(u132, roothub.a, &roothub_a);
1638 if (retval)
1639 return retval;
1640 if (!(roothub_a & RH_A_NPS)) {
1641 int temp; /* power down each port */
1642 for (temp = 0; temp < u132->num_ports; temp++) {
1643 retval = u132_write_pcimem(u132,
1644 roothub.portstatus[temp], RH_PS_LSDA);
1645 if (retval)
1646 return retval;
1647 }
1648 }
1649 retval = u132_read_pcimem(u132, control, &control);
1650 if (retval)
1651 return retval;
1652retry:
1653 retval = u132_read_pcimem(u132, cmdstatus, &status);
1654 if (retval)
1655 return retval;
1656 retval = u132_write_pcimem(u132, cmdstatus, OHCI_HCR);
1657 if (retval)
1658 return retval;
1659extra: {
1660 retval = u132_read_pcimem(u132, cmdstatus, &status);
1661 if (retval)
1662 return retval;
1663 if (0 != (status & OHCI_HCR)) {
1664 if (--reset_timeout == 0) {
1665 dev_err(&u132->platform_dev->dev, "USB HC reset"
1666 " timed out!\n");
1667 return -ENODEV;
1668 } else {
1669 msleep(5);
1670 goto extra;
1671 }
1672 }
1673 }
1674 if (u132->flags & OHCI_QUIRK_INITRESET) {
1675 retval = u132_write_pcimem(u132, control, u132->hc_control);
1676 if (retval)
1677 return retval;
1678 retval = u132_read_pcimem(u132, control, &control);
1679 if (retval)
1680 return retval;
1681 }
1682 retval = u132_write_pcimem(u132, ed_controlhead, 0x00000000);
1683 if (retval)
1684 return retval;
1685 retval = u132_write_pcimem(u132, ed_bulkhead, 0x11000000);
1686 if (retval)
1687 return retval;
1688 retval = u132_write_pcimem(u132, hcca, 0x00000000);
1689 if (retval)
1690 return retval;
1691 retval = u132_periodic_reinit(u132);
1692 if (retval)
1693 return retval;
1694 retval = u132_read_pcimem(u132, fminterval, &fminterval);
1695 if (retval)
1696 return retval;
1697 retval = u132_read_pcimem(u132, periodicstart, &periodicstart);
1698 if (retval)
1699 return retval;
1700 if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) {
1701 if (!(u132->flags & OHCI_QUIRK_INITRESET)) {
1702 u132->flags |= OHCI_QUIRK_INITRESET;
1703 goto retry;
1704 } else
1705 dev_err(&u132->platform_dev->dev, "init err(%08x %04x)"
1706 "\n", fminterval, periodicstart);
1707 } /* start controller operations */
1708 u132->hc_control &= OHCI_CTRL_RWC;
1709 u132->hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER;
1710 retval = u132_write_pcimem(u132, control, u132->hc_control);
1711 if (retval)
1712 return retval;
1713 retval = u132_write_pcimem(u132, cmdstatus, OHCI_BLF);
1714 if (retval)
1715 return retval;
1716 retval = u132_read_pcimem(u132, cmdstatus, &cmdstatus);
1717 if (retval)
1718 return retval;
1719 retval = u132_read_pcimem(u132, control, &control);
1720 if (retval)
1721 return retval;
1722 u132_to_hcd(u132)->state = HC_STATE_RUNNING;
1723 retval = u132_write_pcimem(u132, roothub.status, RH_HS_DRWE);
1724 if (retval)
1725 return retval;
1726 retval = u132_write_pcimem(u132, intrstatus, mask);
1727 if (retval)
1728 return retval;
1729 retval = u132_write_pcimem(u132, intrdisable,
1730 OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO |
1731 OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH |
1732 OHCI_INTR_SO);
1733 if (retval)
1734 return retval; /* handle root hub init quirks ... */
1735 retval = u132_read_pcimem(u132, roothub.a, &roothub_a);
1736 if (retval)
1737 return retval;
1738 roothub_a &= ~(RH_A_PSM | RH_A_OCPM);
1739 if (u132->flags & OHCI_QUIRK_SUPERIO) {
1740 roothub_a |= RH_A_NOCP;
1741 roothub_a &= ~(RH_A_POTPGT | RH_A_NPS);
1742 retval = u132_write_pcimem(u132, roothub.a, roothub_a);
1743 if (retval)
1744 return retval;
1745 } else if ((u132->flags & OHCI_QUIRK_AMD756) || distrust_firmware) {
1746 roothub_a |= RH_A_NPS;
1747 retval = u132_write_pcimem(u132, roothub.a, roothub_a);
1748 if (retval)
1749 return retval;
1750 }
1751 retval = u132_write_pcimem(u132, roothub.status, RH_HS_LPSC);
1752 if (retval)
1753 return retval;
1754 retval = u132_write_pcimem(u132, roothub.b,
1755 (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM);
1756 if (retval)
1757 return retval;
1758 retval = u132_read_pcimem(u132, control, &control);
1759 if (retval)
1760 return retval;
1761 mdelay((roothub_a >> 23) & 0x1fe);
1762 u132_to_hcd(u132)->state = HC_STATE_RUNNING;
1763 return 0;
Tony Olechd774efe2006-09-13 11:27:35 +01001764}
1765
1766static void u132_hcd_stop(struct usb_hcd *hcd)
1767{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001768 struct u132 *u132 = hcd_to_u132(hcd);
1769 if (u132->going > 1) {
1770 dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p) has b"
1771 "een removed %d\n", u132, hcd, u132->going);
1772 } else if (u132->going > 0) {
1773 dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
1774 "ed\n", hcd);
1775 } else {
1776 mutex_lock(&u132->sw_lock);
1777 msleep(100);
1778 u132_power(u132, 0);
1779 mutex_unlock(&u132->sw_lock);
1780 }
Tony Olechd774efe2006-09-13 11:27:35 +01001781}
1782
1783static int u132_hcd_start(struct usb_hcd *hcd)
1784{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001785 struct u132 *u132 = hcd_to_u132(hcd);
1786 if (u132->going > 1) {
1787 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
1788 , u132->going);
1789 return -ENODEV;
1790 } else if (u132->going > 0) {
1791 dev_err(&u132->platform_dev->dev, "device is being removed\n");
1792 return -ESHUTDOWN;
1793 } else if (hcd->self.controller) {
1794 int retval;
1795 struct platform_device *pdev =
1796 to_platform_device(hcd->self.controller);
1797 u16 vendor = ((struct u132_platform_data *)
Jingoo Hand4f09e22013-07-30 19:59:40 +09001798 dev_get_platdata(&pdev->dev))->vendor;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001799 u16 device = ((struct u132_platform_data *)
Jingoo Hand4f09e22013-07-30 19:59:40 +09001800 dev_get_platdata(&pdev->dev))->device;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001801 mutex_lock(&u132->sw_lock);
1802 msleep(10);
1803 if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) {
1804 u132->flags = OHCI_QUIRK_AMD756;
1805 } else if (vendor == PCI_VENDOR_ID_OPTI && device == 0xc861) {
1806 dev_err(&u132->platform_dev->dev, "WARNING: OPTi workar"
1807 "ounds unavailable\n");
1808 } else if (vendor == PCI_VENDOR_ID_COMPAQ && device == 0xa0f8)
1809 u132->flags |= OHCI_QUIRK_ZFMICRO;
1810 retval = u132_run(u132);
1811 if (retval) {
1812 u132_disable(u132);
1813 u132->going = 1;
1814 }
1815 msleep(100);
1816 mutex_unlock(&u132->sw_lock);
1817 return retval;
1818 } else {
1819 dev_err(&u132->platform_dev->dev, "platform_device missing\n");
1820 return -ENODEV;
1821 }
Tony Olechd774efe2006-09-13 11:27:35 +01001822}
1823
1824static int u132_hcd_reset(struct usb_hcd *hcd)
1825{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001826 struct u132 *u132 = hcd_to_u132(hcd);
1827 if (u132->going > 1) {
1828 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
1829 , u132->going);
1830 return -ENODEV;
1831 } else if (u132->going > 0) {
1832 dev_err(&u132->platform_dev->dev, "device is being removed\n");
1833 return -ESHUTDOWN;
1834 } else {
1835 int retval;
1836 mutex_lock(&u132->sw_lock);
1837 retval = u132_init(u132);
1838 if (retval) {
1839 u132_disable(u132);
1840 u132->going = 1;
1841 }
1842 mutex_unlock(&u132->sw_lock);
1843 return retval;
1844 }
Tony Olechd774efe2006-09-13 11:27:35 +01001845}
1846
1847static int create_endpoint_and_queue_int(struct u132 *u132,
Alan Sterne9df41c2007-08-08 11:48:02 -04001848 struct u132_udev *udev, struct urb *urb,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001849 struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
1850 gfp_t mem_flags)
Tony Olechd774efe2006-09-13 11:27:35 +01001851{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001852 struct u132_ring *ring;
Alan Sterne9df41c2007-08-08 11:48:02 -04001853 unsigned long irqs;
1854 int rc;
1855 u8 endp_number;
1856 struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
1857
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001858 if (!endp)
1859 return -ENOMEM;
Alan Sterne9df41c2007-08-08 11:48:02 -04001860
1861 spin_lock_init(&endp->queue_lock.slock);
1862 spin_lock_irqsave(&endp->queue_lock.slock, irqs);
1863 rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
1864 if (rc) {
1865 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
1866 kfree(endp);
1867 return rc;
1868 }
1869
1870 endp_number = ++u132->num_endpoints;
1871 urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001872 INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
1873 INIT_LIST_HEAD(&endp->urb_more);
1874 ring = endp->ring = &u132->ring[0];
1875 if (ring->curr_endp) {
1876 list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring);
1877 } else {
1878 INIT_LIST_HEAD(&endp->endp_ring);
1879 ring->curr_endp = endp;
1880 }
1881 ring->length += 1;
1882 endp->dequeueing = 0;
1883 endp->edset_flush = 0;
1884 endp->active = 0;
1885 endp->delayed = 0;
1886 endp->endp_number = endp_number;
1887 endp->u132 = u132;
Alan Sterne9df41c2007-08-08 11:48:02 -04001888 endp->hep = urb->ep;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07001889 endp->pipetype = usb_pipetype(urb->pipe);
1890 u132_endp_init_kref(u132, endp);
1891 if (usb_pipein(urb->pipe)) {
1892 endp->toggle_bits = 0x2;
1893 usb_settoggle(udev->usb_device, usb_endp, 0, 0);
1894 endp->input = 1;
1895 endp->output = 0;
1896 udev->endp_number_in[usb_endp] = endp_number;
1897 u132_udev_get_kref(u132, udev);
1898 } else {
1899 endp->toggle_bits = 0x2;
1900 usb_settoggle(udev->usb_device, usb_endp, 1, 0);
1901 endp->input = 0;
1902 endp->output = 1;
1903 udev->endp_number_out[usb_endp] = endp_number;
1904 u132_udev_get_kref(u132, udev);
1905 }
1906 urb->hcpriv = u132;
1907 endp->delayed = 1;
1908 endp->jiffies = jiffies + msecs_to_jiffies(urb->interval);
1909 endp->udev_number = address;
1910 endp->usb_addr = usb_addr;
1911 endp->usb_endp = usb_endp;
1912 endp->queue_size = 1;
1913 endp->queue_last = 0;
1914 endp->queue_next = 0;
1915 endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
1916 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
1917 u132_endp_queue_work(u132, endp, msecs_to_jiffies(urb->interval));
1918 return 0;
1919}
1920
1921static int queue_int_on_old_endpoint(struct u132 *u132,
1922 struct u132_udev *udev, struct urb *urb,
1923 struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
1924 u8 usb_endp, u8 address)
1925{
1926 urb->hcpriv = u132;
1927 endp->delayed = 1;
1928 endp->jiffies = jiffies + msecs_to_jiffies(urb->interval);
1929 if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
1930 endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
1931 } else {
1932 struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq),
1933 GFP_ATOMIC);
1934 if (urbq == NULL) {
1935 endp->queue_size -= 1;
1936 return -ENOMEM;
1937 } else {
1938 list_add_tail(&urbq->urb_more, &endp->urb_more);
1939 urbq->urb = urb;
1940 }
1941 }
1942 return 0;
1943}
1944
1945static int create_endpoint_and_queue_bulk(struct u132 *u132,
1946 struct u132_udev *udev, struct urb *urb,
1947 struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
1948 gfp_t mem_flags)
1949{
1950 int ring_number;
1951 struct u132_ring *ring;
1952 unsigned long irqs;
1953 int rc;
1954 u8 endp_number;
1955 struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
1956
1957 if (!endp)
1958 return -ENOMEM;
1959
1960 spin_lock_init(&endp->queue_lock.slock);
1961 spin_lock_irqsave(&endp->queue_lock.slock, irqs);
1962 rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
1963 if (rc) {
1964 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
1965 kfree(endp);
1966 return rc;
1967 }
1968
1969 endp_number = ++u132->num_endpoints;
1970 urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
1971 INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
1972 INIT_LIST_HEAD(&endp->urb_more);
1973 endp->dequeueing = 0;
1974 endp->edset_flush = 0;
1975 endp->active = 0;
1976 endp->delayed = 0;
1977 endp->endp_number = endp_number;
1978 endp->u132 = u132;
1979 endp->hep = urb->ep;
1980 endp->pipetype = usb_pipetype(urb->pipe);
1981 u132_endp_init_kref(u132, endp);
1982 if (usb_pipein(urb->pipe)) {
1983 endp->toggle_bits = 0x2;
1984 usb_settoggle(udev->usb_device, usb_endp, 0, 0);
1985 ring_number = 3;
1986 endp->input = 1;
1987 endp->output = 0;
1988 udev->endp_number_in[usb_endp] = endp_number;
1989 u132_udev_get_kref(u132, udev);
1990 } else {
1991 endp->toggle_bits = 0x2;
1992 usb_settoggle(udev->usb_device, usb_endp, 1, 0);
1993 ring_number = 2;
1994 endp->input = 0;
1995 endp->output = 1;
1996 udev->endp_number_out[usb_endp] = endp_number;
1997 u132_udev_get_kref(u132, udev);
1998 }
1999 ring = endp->ring = &u132->ring[ring_number - 1];
2000 if (ring->curr_endp) {
2001 list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring);
2002 } else {
2003 INIT_LIST_HEAD(&endp->endp_ring);
2004 ring->curr_endp = endp;
2005 }
2006 ring->length += 1;
2007 urb->hcpriv = u132;
2008 endp->udev_number = address;
2009 endp->usb_addr = usb_addr;
2010 endp->usb_endp = usb_endp;
2011 endp->queue_size = 1;
2012 endp->queue_last = 0;
2013 endp->queue_next = 0;
2014 endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
2015 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
2016 u132_endp_queue_work(u132, endp, 0);
2017 return 0;
2018}
2019
2020static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
2021 struct urb *urb,
2022 struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
2023 u8 usb_endp, u8 address)
2024{
2025 urb->hcpriv = u132;
2026 if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
2027 endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
2028 } else {
2029 struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq),
2030 GFP_ATOMIC);
2031 if (urbq == NULL) {
2032 endp->queue_size -= 1;
2033 return -ENOMEM;
2034 } else {
2035 list_add_tail(&urbq->urb_more, &endp->urb_more);
2036 urbq->urb = urb;
2037 }
2038 }
2039 return 0;
2040}
2041
2042static int create_endpoint_and_queue_control(struct u132 *u132,
2043 struct urb *urb,
2044 struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp,
2045 gfp_t mem_flags)
2046{
2047 struct u132_ring *ring;
2048 unsigned long irqs;
2049 int rc;
2050 u8 endp_number;
2051 struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
2052
2053 if (!endp)
2054 return -ENOMEM;
2055
2056 spin_lock_init(&endp->queue_lock.slock);
2057 spin_lock_irqsave(&endp->queue_lock.slock, irqs);
2058 rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
2059 if (rc) {
2060 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
2061 kfree(endp);
2062 return rc;
2063 }
2064
2065 endp_number = ++u132->num_endpoints;
2066 urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
2067 INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
2068 INIT_LIST_HEAD(&endp->urb_more);
2069 ring = endp->ring = &u132->ring[0];
2070 if (ring->curr_endp) {
2071 list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring);
2072 } else {
2073 INIT_LIST_HEAD(&endp->endp_ring);
2074 ring->curr_endp = endp;
2075 }
2076 ring->length += 1;
2077 endp->dequeueing = 0;
2078 endp->edset_flush = 0;
2079 endp->active = 0;
2080 endp->delayed = 0;
2081 endp->endp_number = endp_number;
2082 endp->u132 = u132;
2083 endp->hep = urb->ep;
2084 u132_endp_init_kref(u132, endp);
2085 u132_endp_get_kref(u132, endp);
2086 if (usb_addr == 0) {
2087 u8 address = u132->addr[usb_addr].address;
2088 struct u132_udev *udev = &u132->udev[address];
2089 endp->udev_number = address;
2090 endp->usb_addr = usb_addr;
2091 endp->usb_endp = usb_endp;
2092 endp->input = 1;
2093 endp->output = 1;
2094 endp->pipetype = usb_pipetype(urb->pipe);
2095 u132_udev_init_kref(u132, udev);
2096 u132_udev_get_kref(u132, udev);
2097 udev->endp_number_in[usb_endp] = endp_number;
2098 udev->endp_number_out[usb_endp] = endp_number;
2099 urb->hcpriv = u132;
2100 endp->queue_size = 1;
2101 endp->queue_last = 0;
2102 endp->queue_next = 0;
2103 endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
2104 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
2105 u132_endp_queue_work(u132, endp, 0);
2106 return 0;
2107 } else { /*(usb_addr > 0) */
2108 u8 address = u132->addr[usb_addr].address;
2109 struct u132_udev *udev = &u132->udev[address];
2110 endp->udev_number = address;
2111 endp->usb_addr = usb_addr;
2112 endp->usb_endp = usb_endp;
2113 endp->input = 1;
2114 endp->output = 1;
2115 endp->pipetype = usb_pipetype(urb->pipe);
2116 u132_udev_get_kref(u132, udev);
2117 udev->enumeration = 2;
2118 udev->endp_number_in[usb_endp] = endp_number;
2119 udev->endp_number_out[usb_endp] = endp_number;
2120 urb->hcpriv = u132;
2121 endp->queue_size = 1;
2122 endp->queue_last = 0;
2123 endp->queue_next = 0;
2124 endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
2125 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
2126 u132_endp_queue_work(u132, endp, 0);
2127 return 0;
2128 }
Tony Olechd774efe2006-09-13 11:27:35 +01002129}
2130
2131static int queue_control_on_old_endpoint(struct u132 *u132,
Alan Sterne9df41c2007-08-08 11:48:02 -04002132 struct urb *urb,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002133 struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
2134 u8 usb_endp)
Tony Olechd774efe2006-09-13 11:27:35 +01002135{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002136 if (usb_addr == 0) {
2137 if (usb_pipein(urb->pipe)) {
2138 urb->hcpriv = u132;
2139 if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
2140 endp->urb_list[ENDP_QUEUE_MASK &
2141 endp->queue_last++] = urb;
2142 } else {
2143 struct u132_urbq *urbq =
2144 kmalloc(sizeof(struct u132_urbq),
2145 GFP_ATOMIC);
2146 if (urbq == NULL) {
2147 endp->queue_size -= 1;
2148 return -ENOMEM;
2149 } else {
2150 list_add_tail(&urbq->urb_more,
2151 &endp->urb_more);
2152 urbq->urb = urb;
2153 }
2154 }
2155 return 0;
2156 } else { /* usb_pipeout(urb->pipe) */
2157 struct u132_addr *addr = &u132->addr[usb_dev->devnum];
2158 int I = MAX_U132_UDEVS;
2159 int i = 0;
2160 while (--I > 0) {
2161 struct u132_udev *udev = &u132->udev[++i];
2162 if (udev->usb_device) {
2163 continue;
2164 } else {
2165 udev->enumeration = 1;
2166 u132->addr[0].address = i;
2167 endp->udev_number = i;
2168 udev->udev_number = i;
2169 udev->usb_addr = usb_dev->devnum;
2170 u132_udev_init_kref(u132, udev);
2171 udev->endp_number_in[usb_endp] =
2172 endp->endp_number;
2173 u132_udev_get_kref(u132, udev);
2174 udev->endp_number_out[usb_endp] =
2175 endp->endp_number;
2176 udev->usb_device = usb_dev;
2177 ((u8 *) (urb->setup_packet))[2] =
2178 addr->address = i;
2179 u132_udev_get_kref(u132, udev);
2180 break;
2181 }
2182 }
2183 if (I == 0) {
2184 dev_err(&u132->platform_dev->dev, "run out of d"
2185 "evice space\n");
2186 return -EINVAL;
2187 }
2188 urb->hcpriv = u132;
2189 if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
2190 endp->urb_list[ENDP_QUEUE_MASK &
2191 endp->queue_last++] = urb;
2192 } else {
2193 struct u132_urbq *urbq =
2194 kmalloc(sizeof(struct u132_urbq),
2195 GFP_ATOMIC);
2196 if (urbq == NULL) {
2197 endp->queue_size -= 1;
2198 return -ENOMEM;
2199 } else {
2200 list_add_tail(&urbq->urb_more,
2201 &endp->urb_more);
2202 urbq->urb = urb;
2203 }
2204 }
2205 return 0;
2206 }
2207 } else { /*(usb_addr > 0) */
2208 u8 address = u132->addr[usb_addr].address;
2209 struct u132_udev *udev = &u132->udev[address];
2210 urb->hcpriv = u132;
2211 if (udev->enumeration != 2)
2212 udev->enumeration = 2;
2213 if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
2214 endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] =
2215 urb;
2216 } else {
2217 struct u132_urbq *urbq =
2218 kmalloc(sizeof(struct u132_urbq), GFP_ATOMIC);
2219 if (urbq == NULL) {
2220 endp->queue_size -= 1;
2221 return -ENOMEM;
2222 } else {
2223 list_add_tail(&urbq->urb_more, &endp->urb_more);
2224 urbq->urb = urb;
2225 }
2226 }
2227 return 0;
2228 }
Tony Olechd774efe2006-09-13 11:27:35 +01002229}
2230
Alan Sterne9df41c2007-08-08 11:48:02 -04002231static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
2232 gfp_t mem_flags)
Tony Olechd774efe2006-09-13 11:27:35 +01002233{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002234 struct u132 *u132 = hcd_to_u132(hcd);
2235 if (irqs_disabled()) {
Mel Gormand0164ad2015-11-06 16:28:21 -08002236 if (gfpflags_allow_blocking(mem_flags)) {
Masanari Iidad5f9e732015-09-30 12:51:51 +09002237 printk(KERN_ERR "invalid context for function that might sleep\n");
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002238 return -EINVAL;
2239 }
2240 }
2241 if (u132->going > 1) {
2242 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
2243 , u132->going);
2244 return -ENODEV;
2245 } else if (u132->going > 0) {
Alan Sterneb231052007-08-21 15:40:36 -04002246 dev_err(&u132->platform_dev->dev, "device is being removed "
2247 "urb=%p\n", urb);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002248 return -ESHUTDOWN;
2249 } else {
2250 u8 usb_addr = usb_pipedevice(urb->pipe);
2251 u8 usb_endp = usb_pipeendpoint(urb->pipe);
2252 struct usb_device *usb_dev = urb->dev;
2253 if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
2254 u8 address = u132->addr[usb_addr].address;
2255 struct u132_udev *udev = &u132->udev[address];
2256 struct u132_endp *endp = urb->ep->hcpriv;
2257 urb->actual_length = 0;
2258 if (endp) {
2259 unsigned long irqs;
2260 int retval;
2261 spin_lock_irqsave(&endp->queue_lock.slock,
2262 irqs);
Alan Sterne9df41c2007-08-08 11:48:02 -04002263 retval = usb_hcd_link_urb_to_ep(hcd, urb);
2264 if (retval == 0) {
2265 retval = queue_int_on_old_endpoint(
2266 u132, udev, urb,
2267 usb_dev, endp,
2268 usb_addr, usb_endp,
2269 address);
2270 if (retval)
2271 usb_hcd_unlink_urb_from_ep(
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002272 hcd, urb);
Alan Sterne9df41c2007-08-08 11:48:02 -04002273 }
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002274 spin_unlock_irqrestore(&endp->queue_lock.slock,
2275 irqs);
2276 if (retval) {
2277 return retval;
2278 } else {
2279 u132_endp_queue_work(u132, endp,
2280 msecs_to_jiffies(urb->interval))
2281 ;
2282 return 0;
2283 }
2284 } else if (u132->num_endpoints == MAX_U132_ENDPS) {
2285 return -EINVAL;
2286 } else { /*(endp == NULL) */
2287 return create_endpoint_and_queue_int(u132, udev,
Alan Sterne9df41c2007-08-08 11:48:02 -04002288 urb, usb_dev, usb_addr,
2289 usb_endp, address, mem_flags);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002290 }
2291 } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
2292 dev_err(&u132->platform_dev->dev, "the hardware does no"
2293 "t support PIPE_ISOCHRONOUS\n");
2294 return -EINVAL;
2295 } else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
2296 u8 address = u132->addr[usb_addr].address;
2297 struct u132_udev *udev = &u132->udev[address];
2298 struct u132_endp *endp = urb->ep->hcpriv;
2299 urb->actual_length = 0;
2300 if (endp) {
2301 unsigned long irqs;
2302 int retval;
2303 spin_lock_irqsave(&endp->queue_lock.slock,
2304 irqs);
Alan Sterne9df41c2007-08-08 11:48:02 -04002305 retval = usb_hcd_link_urb_to_ep(hcd, urb);
2306 if (retval == 0) {
2307 retval = queue_bulk_on_old_endpoint(
2308 u132, udev, urb,
2309 usb_dev, endp,
2310 usb_addr, usb_endp,
2311 address);
2312 if (retval)
2313 usb_hcd_unlink_urb_from_ep(
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002314 hcd, urb);
Alan Sterne9df41c2007-08-08 11:48:02 -04002315 }
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002316 spin_unlock_irqrestore(&endp->queue_lock.slock,
2317 irqs);
2318 if (retval) {
2319 return retval;
2320 } else {
2321 u132_endp_queue_work(u132, endp, 0);
2322 return 0;
2323 }
2324 } else if (u132->num_endpoints == MAX_U132_ENDPS) {
2325 return -EINVAL;
2326 } else
2327 return create_endpoint_and_queue_bulk(u132,
Alan Sterne9df41c2007-08-08 11:48:02 -04002328 udev, urb, usb_dev, usb_addr,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002329 usb_endp, address, mem_flags);
2330 } else {
2331 struct u132_endp *endp = urb->ep->hcpriv;
2332 u16 urb_size = 8;
2333 u8 *b = urb->setup_packet;
2334 int i = 0;
2335 char data[30 * 3 + 4];
2336 char *d = data;
2337 int m = (sizeof(data) - 1) / 3;
2338 int l = 0;
2339 data[0] = 0;
2340 while (urb_size-- > 0) {
2341 if (i > m) {
2342 } else if (i++ < m) {
2343 int w = sprintf(d, " %02X", *b++);
2344 d += w;
2345 l += w;
2346 } else
2347 d += sprintf(d, " ..");
2348 }
2349 if (endp) {
2350 unsigned long irqs;
2351 int retval;
2352 spin_lock_irqsave(&endp->queue_lock.slock,
2353 irqs);
Alan Sterne9df41c2007-08-08 11:48:02 -04002354 retval = usb_hcd_link_urb_to_ep(hcd, urb);
2355 if (retval == 0) {
2356 retval = queue_control_on_old_endpoint(
2357 u132, urb, usb_dev,
2358 endp, usb_addr,
2359 usb_endp);
2360 if (retval)
2361 usb_hcd_unlink_urb_from_ep(
2362 hcd, urb);
2363 }
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002364 spin_unlock_irqrestore(&endp->queue_lock.slock,
2365 irqs);
2366 if (retval) {
2367 return retval;
2368 } else {
2369 u132_endp_queue_work(u132, endp, 0);
2370 return 0;
2371 }
2372 } else if (u132->num_endpoints == MAX_U132_ENDPS) {
2373 return -EINVAL;
2374 } else
2375 return create_endpoint_and_queue_control(u132,
Alan Sterne9df41c2007-08-08 11:48:02 -04002376 urb, usb_dev, usb_addr, usb_endp,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002377 mem_flags);
2378 }
2379 }
Tony Olechd774efe2006-09-13 11:27:35 +01002380}
2381
2382static int dequeue_from_overflow_chain(struct u132 *u132,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002383 struct u132_endp *endp, struct urb *urb)
Tony Olechd774efe2006-09-13 11:27:35 +01002384{
Geliang Tang4e5d7a82015-12-19 00:34:29 +08002385 struct u132_urbq *urbq;
2386
2387 list_for_each_entry(urbq, &endp->urb_more, urb_more) {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002388 if (urbq->urb == urb) {
2389 struct usb_hcd *hcd = u132_to_hcd(u132);
Geliang Tang4e5d7a82015-12-19 00:34:29 +08002390 list_del(&urbq->urb_more);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002391 endp->queue_size -= 1;
2392 urb->error_count = 0;
Alan Stern4a000272007-08-24 15:42:24 -04002393 usb_hcd_giveback_urb(hcd, urb, 0);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002394 return 0;
2395 } else
2396 continue;
2397 }
2398 dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]=%p ring"
2399 "[%d] %c%c usb_endp=%d usb_addr=%d size=%d next=%04X last=%04X"
2400 "\n", urb, endp->endp_number, endp, endp->ring->number,
2401 endp->input ? 'I' : ' ', endp->output ? 'O' : ' ',
2402 endp->usb_endp, endp->usb_addr, endp->queue_size,
2403 endp->queue_next, endp->queue_last);
2404 return -EINVAL;
Tony Olechd774efe2006-09-13 11:27:35 +01002405}
2406
2407static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
Alan Sterne9df41c2007-08-08 11:48:02 -04002408 struct urb *urb, int status)
Tony Olechd774efe2006-09-13 11:27:35 +01002409{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002410 unsigned long irqs;
Alan Sterne9df41c2007-08-08 11:48:02 -04002411 int rc;
2412
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002413 spin_lock_irqsave(&endp->queue_lock.slock, irqs);
Alan Sterne9df41c2007-08-08 11:48:02 -04002414 rc = usb_hcd_check_unlink_urb(u132_to_hcd(u132), urb, status);
2415 if (rc) {
2416 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
2417 return rc;
2418 }
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002419 if (endp->queue_size == 0) {
2420 dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]"
2421 "=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", urb,
2422 endp->endp_number, endp, endp->ring->number,
2423 endp->input ? 'I' : ' ', endp->output ? 'O' : ' ',
2424 endp->usb_endp, endp->usb_addr);
2425 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
2426 return -EINVAL;
2427 }
2428 if (urb == endp->urb_list[ENDP_QUEUE_MASK & endp->queue_next]) {
2429 if (endp->active) {
2430 endp->dequeueing = 1;
2431 endp->edset_flush = 1;
2432 u132_endp_queue_work(u132, endp, 0);
2433 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
2434 return 0;
2435 } else {
2436 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
Alan Stern4a000272007-08-24 15:42:24 -04002437 u132_hcd_abandon_urb(u132, endp, urb, status);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002438 return 0;
2439 }
2440 } else {
2441 u16 queue_list = 0;
2442 u16 queue_size = endp->queue_size;
2443 u16 queue_scan = endp->queue_next;
2444 struct urb **urb_slot = NULL;
2445 while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) {
2446 if (urb == endp->urb_list[ENDP_QUEUE_MASK &
2447 ++queue_scan]) {
2448 urb_slot = &endp->urb_list[ENDP_QUEUE_MASK &
2449 queue_scan];
2450 break;
2451 } else
2452 continue;
2453 }
2454 while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) {
2455 *urb_slot = endp->urb_list[ENDP_QUEUE_MASK &
2456 ++queue_scan];
2457 urb_slot = &endp->urb_list[ENDP_QUEUE_MASK &
2458 queue_scan];
2459 }
2460 if (urb_slot) {
2461 struct usb_hcd *hcd = u132_to_hcd(u132);
Alan Sterne9df41c2007-08-08 11:48:02 -04002462
2463 usb_hcd_unlink_urb_from_ep(hcd, urb);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002464 endp->queue_size -= 1;
2465 if (list_empty(&endp->urb_more)) {
2466 spin_unlock_irqrestore(&endp->queue_lock.slock,
2467 irqs);
2468 } else {
2469 struct list_head *next = endp->urb_more.next;
2470 struct u132_urbq *urbq = list_entry(next,
2471 struct u132_urbq, urb_more);
2472 list_del(next);
2473 *urb_slot = urbq->urb;
2474 spin_unlock_irqrestore(&endp->queue_lock.slock,
2475 irqs);
2476 kfree(urbq);
Colin Ian Kingd1ab1b82019-01-04 17:43:49 +00002477 }
2478 urb->error_count = 0;
Alan Stern4a000272007-08-24 15:42:24 -04002479 usb_hcd_giveback_urb(hcd, urb, status);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002480 return 0;
2481 } else if (list_empty(&endp->urb_more)) {
2482 dev_err(&u132->platform_dev->dev, "urb=%p not found in "
2483 "endp[%d]=%p ring[%d] %c%c usb_endp=%d usb_addr"
2484 "=%d size=%d next=%04X last=%04X\n", urb,
2485 endp->endp_number, endp, endp->ring->number,
2486 endp->input ? 'I' : ' ',
2487 endp->output ? 'O' : ' ', endp->usb_endp,
2488 endp->usb_addr, endp->queue_size,
2489 endp->queue_next, endp->queue_last);
2490 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
2491 return -EINVAL;
2492 } else {
Alan Sterne9df41c2007-08-08 11:48:02 -04002493 int retval;
2494
2495 usb_hcd_unlink_urb_from_ep(u132_to_hcd(u132), urb);
2496 retval = dequeue_from_overflow_chain(u132, endp,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002497 urb);
2498 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
2499 return retval;
2500 }
2501 }
Tony Olechd774efe2006-09-13 11:27:35 +01002502}
2503
Alan Sterne9df41c2007-08-08 11:48:02 -04002504static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
Tony Olechd774efe2006-09-13 11:27:35 +01002505{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002506 struct u132 *u132 = hcd_to_u132(hcd);
2507 if (u132->going > 2) {
2508 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
2509 , u132->going);
2510 return -ENODEV;
2511 } else {
2512 u8 usb_addr = usb_pipedevice(urb->pipe);
2513 u8 usb_endp = usb_pipeendpoint(urb->pipe);
2514 u8 address = u132->addr[usb_addr].address;
2515 struct u132_udev *udev = &u132->udev[address];
2516 if (usb_pipein(urb->pipe)) {
2517 u8 endp_number = udev->endp_number_in[usb_endp];
2518 struct u132_endp *endp = u132->endp[endp_number - 1];
2519 return u132_endp_urb_dequeue(u132, endp, urb, status);
2520 } else {
2521 u8 endp_number = udev->endp_number_out[usb_endp];
2522 struct u132_endp *endp = u132->endp[endp_number - 1];
2523 return u132_endp_urb_dequeue(u132, endp, urb, status);
2524 }
2525 }
Tony Olechd774efe2006-09-13 11:27:35 +01002526}
2527
2528static void u132_endpoint_disable(struct usb_hcd *hcd,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002529 struct usb_host_endpoint *hep)
Tony Olechd774efe2006-09-13 11:27:35 +01002530{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002531 struct u132 *u132 = hcd_to_u132(hcd);
2532 if (u132->going > 2) {
2533 dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p hep=%p"
2534 ") has been removed %d\n", u132, hcd, hep,
2535 u132->going);
2536 } else {
2537 struct u132_endp *endp = hep->hcpriv;
2538 if (endp)
2539 u132_endp_put_kref(u132, endp);
2540 }
Tony Olechd774efe2006-09-13 11:27:35 +01002541}
2542
2543static int u132_get_frame(struct usb_hcd *hcd)
2544{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002545 struct u132 *u132 = hcd_to_u132(hcd);
2546 if (u132->going > 1) {
2547 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
2548 , u132->going);
2549 return -ENODEV;
2550 } else if (u132->going > 0) {
2551 dev_err(&u132->platform_dev->dev, "device is being removed\n");
2552 return -ESHUTDOWN;
2553 } else {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002554 dev_err(&u132->platform_dev->dev, "TODO: u132_get_frame\n");
Jia-Ju Bai6d4f2682018-09-01 17:23:47 +08002555 mdelay(100);
Hariprasad Kelam0e016242019-06-05 19:48:42 +05302556 return 0;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002557 }
Tony Olechd774efe2006-09-13 11:27:35 +01002558}
2559
2560static int u132_roothub_descriptor(struct u132 *u132,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002561 struct usb_hub_descriptor *desc)
Tony Olechd774efe2006-09-13 11:27:35 +01002562{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002563 int retval;
2564 u16 temp;
2565 u32 rh_a = -1;
2566 u32 rh_b = -1;
2567 retval = u132_read_pcimem(u132, roothub.a, &rh_a);
2568 if (retval)
2569 return retval;
Sergei Shtylyov0ce6fe92015-03-29 01:28:15 +03002570 desc->bDescriptorType = USB_DT_HUB;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002571 desc->bPwrOn2PwrGood = (rh_a & RH_A_POTPGT) >> 24;
2572 desc->bHubContrCurrent = 0;
2573 desc->bNbrPorts = u132->num_ports;
2574 temp = 1 + (u132->num_ports / 8);
2575 desc->bDescLength = 7 + 2 * temp;
Sergei Shtylyova7cf6972015-01-19 01:49:59 +03002576 temp = HUB_CHAR_COMMON_LPSM | HUB_CHAR_COMMON_OCPM;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002577 if (rh_a & RH_A_NPS)
Sergei Shtylyova7cf6972015-01-19 01:49:59 +03002578 temp |= HUB_CHAR_NO_LPSM;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002579 if (rh_a & RH_A_PSM)
Sergei Shtylyova7cf6972015-01-19 01:49:59 +03002580 temp |= HUB_CHAR_INDV_PORT_LPSM;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002581 if (rh_a & RH_A_NOCP)
Sergei Shtylyova7cf6972015-01-19 01:49:59 +03002582 temp |= HUB_CHAR_NO_OCPM;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002583 else if (rh_a & RH_A_OCPM)
Sergei Shtylyova7cf6972015-01-19 01:49:59 +03002584 temp |= HUB_CHAR_INDV_PORT_OCPM;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002585 desc->wHubCharacteristics = cpu_to_le16(temp);
2586 retval = u132_read_pcimem(u132, roothub.b, &rh_b);
2587 if (retval)
2588 return retval;
John Youndbe79bb2001-09-17 00:00:00 -07002589 memset(desc->u.hs.DeviceRemovable, 0xff,
2590 sizeof(desc->u.hs.DeviceRemovable));
2591 desc->u.hs.DeviceRemovable[0] = rh_b & RH_B_DR;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002592 if (u132->num_ports > 7) {
John Youndbe79bb2001-09-17 00:00:00 -07002593 desc->u.hs.DeviceRemovable[1] = (rh_b & RH_B_DR) >> 8;
2594 desc->u.hs.DeviceRemovable[2] = 0xff;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002595 } else
John Youndbe79bb2001-09-17 00:00:00 -07002596 desc->u.hs.DeviceRemovable[1] = 0xff;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002597 return 0;
Tony Olechd774efe2006-09-13 11:27:35 +01002598}
2599
2600static int u132_roothub_status(struct u132 *u132, __le32 *desc)
2601{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002602 u32 rh_status = -1;
2603 int ret_status = u132_read_pcimem(u132, roothub.status, &rh_status);
2604 *desc = cpu_to_le32(rh_status);
2605 return ret_status;
Tony Olechd774efe2006-09-13 11:27:35 +01002606}
2607
2608static int u132_roothub_portstatus(struct u132 *u132, __le32 *desc, u16 wIndex)
2609{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002610 if (wIndex == 0 || wIndex > u132->num_ports) {
2611 return -EINVAL;
2612 } else {
2613 int port = wIndex - 1;
2614 u32 rh_portstatus = -1;
2615 int ret_portstatus = u132_read_pcimem(u132,
2616 roothub.portstatus[port], &rh_portstatus);
2617 *desc = cpu_to_le32(rh_portstatus);
2618 if (*(u16 *) (desc + 2)) {
2619 dev_info(&u132->platform_dev->dev, "Port %d Status Chan"
2620 "ge = %08X\n", port, *desc);
2621 }
2622 return ret_portstatus;
2623 }
Tony Olechd774efe2006-09-13 11:27:35 +01002624}
2625
2626
2627/* this timer value might be vendor-specific ... */
2628#define PORT_RESET_HW_MSEC 10
2629#define PORT_RESET_MSEC 10
2630/* wrap-aware logic morphed from <linux/jiffies.h> */
2631#define tick_before(t1, t2) ((s16)(((s16)(t1))-((s16)(t2))) < 0)
2632static int u132_roothub_portreset(struct u132 *u132, int port_index)
2633{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002634 int retval;
2635 u32 fmnumber;
2636 u16 now;
2637 u16 reset_done;
2638 retval = u132_read_pcimem(u132, fmnumber, &fmnumber);
2639 if (retval)
2640 return retval;
2641 now = fmnumber;
2642 reset_done = now + PORT_RESET_MSEC;
2643 do {
2644 u32 portstat;
2645 do {
2646 retval = u132_read_pcimem(u132,
2647 roothub.portstatus[port_index], &portstat);
2648 if (retval)
2649 return retval;
2650 if (RH_PS_PRS & portstat)
2651 continue;
2652 else
2653 break;
2654 } while (tick_before(now, reset_done));
2655 if (RH_PS_PRS & portstat)
2656 return -ENODEV;
2657 if (RH_PS_CCS & portstat) {
2658 if (RH_PS_PRSC & portstat) {
2659 retval = u132_write_pcimem(u132,
2660 roothub.portstatus[port_index],
2661 RH_PS_PRSC);
2662 if (retval)
2663 return retval;
2664 }
2665 } else
2666 break; /* start the next reset,
2667 sleep till it's probably done */
2668 retval = u132_write_pcimem(u132, roothub.portstatus[port_index],
2669 RH_PS_PRS);
2670 if (retval)
2671 return retval;
2672 msleep(PORT_RESET_HW_MSEC);
2673 retval = u132_read_pcimem(u132, fmnumber, &fmnumber);
2674 if (retval)
2675 return retval;
2676 now = fmnumber;
2677 } while (tick_before(now, reset_done));
2678 return 0;
Tony Olechd774efe2006-09-13 11:27:35 +01002679}
2680
2681static int u132_roothub_setportfeature(struct u132 *u132, u16 wValue,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002682 u16 wIndex)
Tony Olechd774efe2006-09-13 11:27:35 +01002683{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002684 if (wIndex == 0 || wIndex > u132->num_ports) {
2685 return -EINVAL;
2686 } else {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002687 int port_index = wIndex - 1;
2688 struct u132_port *port = &u132->port[port_index];
2689 port->Status &= ~(1 << wValue);
2690 switch (wValue) {
2691 case USB_PORT_FEAT_SUSPEND:
Saurabh Karajgaonkar8602b082015-08-04 14:03:45 +00002692 return u132_write_pcimem(u132,
2693 roothub.portstatus[port_index], RH_PS_PSS);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002694 case USB_PORT_FEAT_POWER:
Saurabh Karajgaonkar8602b082015-08-04 14:03:45 +00002695 return u132_write_pcimem(u132,
2696 roothub.portstatus[port_index], RH_PS_PPS);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002697 case USB_PORT_FEAT_RESET:
Saurabh Karajgaonkar8602b082015-08-04 14:03:45 +00002698 return u132_roothub_portreset(u132, port_index);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002699 default:
2700 return -EPIPE;
2701 }
2702 }
Tony Olechd774efe2006-09-13 11:27:35 +01002703}
2704
2705static int u132_roothub_clearportfeature(struct u132 *u132, u16 wValue,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002706 u16 wIndex)
Tony Olechd774efe2006-09-13 11:27:35 +01002707{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002708 if (wIndex == 0 || wIndex > u132->num_ports) {
2709 return -EINVAL;
2710 } else {
2711 int port_index = wIndex - 1;
2712 u32 temp;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002713 struct u132_port *port = &u132->port[port_index];
2714 port->Status &= ~(1 << wValue);
2715 switch (wValue) {
2716 case USB_PORT_FEAT_ENABLE:
2717 temp = RH_PS_CCS;
2718 break;
2719 case USB_PORT_FEAT_C_ENABLE:
2720 temp = RH_PS_PESC;
2721 break;
2722 case USB_PORT_FEAT_SUSPEND:
2723 temp = RH_PS_POCI;
2724 if ((u132->hc_control & OHCI_CTRL_HCFS)
2725 != OHCI_USB_OPER) {
2726 dev_err(&u132->platform_dev->dev, "TODO resume_"
2727 "root_hub\n");
2728 }
2729 break;
2730 case USB_PORT_FEAT_C_SUSPEND:
2731 temp = RH_PS_PSSC;
2732 break;
2733 case USB_PORT_FEAT_POWER:
2734 temp = RH_PS_LSDA;
2735 break;
2736 case USB_PORT_FEAT_C_CONNECTION:
2737 temp = RH_PS_CSC;
2738 break;
2739 case USB_PORT_FEAT_C_OVER_CURRENT:
2740 temp = RH_PS_OCIC;
2741 break;
2742 case USB_PORT_FEAT_C_RESET:
2743 temp = RH_PS_PRSC;
2744 break;
2745 default:
2746 return -EPIPE;
2747 }
Saurabh Karajgaonkar8602b082015-08-04 14:03:45 +00002748 return u132_write_pcimem(u132, roothub.portstatus[port_index],
2749 temp);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002750 }
Tony Olechd774efe2006-09-13 11:27:35 +01002751}
2752
2753
2754/* the virtual root hub timer IRQ checks for hub status*/
2755static int u132_hub_status_data(struct usb_hcd *hcd, char *buf)
2756{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002757 struct u132 *u132 = hcd_to_u132(hcd);
2758 if (u132->going > 1) {
2759 dev_err(&u132->platform_dev->dev, "device hcd=%p has been remov"
2760 "ed %d\n", hcd, u132->going);
2761 return -ENODEV;
2762 } else if (u132->going > 0) {
2763 dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
2764 "ed\n", hcd);
2765 return -ESHUTDOWN;
2766 } else {
2767 int i, changed = 0, length = 1;
2768 if (u132->flags & OHCI_QUIRK_AMD756) {
2769 if ((u132->hc_roothub_a & RH_A_NDP) > MAX_ROOT_PORTS) {
2770 dev_err(&u132->platform_dev->dev, "bogus NDP, r"
2771 "ereads as NDP=%d\n",
2772 u132->hc_roothub_a & RH_A_NDP);
2773 goto done;
2774 }
2775 }
2776 if (u132->hc_roothub_status & (RH_HS_LPSC | RH_HS_OCIC))
2777 buf[0] = changed = 1;
2778 else
2779 buf[0] = 0;
2780 if (u132->num_ports > 7) {
2781 buf[1] = 0;
2782 length++;
2783 }
2784 for (i = 0; i < u132->num_ports; i++) {
2785 if (u132->hc_roothub_portstatus[i] & (RH_PS_CSC |
2786 RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC |
2787 RH_PS_PRSC)) {
2788 changed = 1;
2789 if (i < 7)
2790 buf[0] |= 1 << (i + 1);
2791 else
2792 buf[1] |= 1 << (i - 7);
2793 continue;
2794 }
2795 if (!(u132->hc_roothub_portstatus[i] & RH_PS_CCS))
2796 continue;
2797
2798 if ((u132->hc_roothub_portstatus[i] & RH_PS_PSS))
2799 continue;
2800 }
2801done:
2802 return changed ? length : 0;
2803 }
Tony Olechd774efe2006-09-13 11:27:35 +01002804}
2805
2806static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002807 u16 wIndex, char *buf, u16 wLength)
Tony Olechd774efe2006-09-13 11:27:35 +01002808{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002809 struct u132 *u132 = hcd_to_u132(hcd);
2810 if (u132->going > 1) {
2811 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
2812 , u132->going);
2813 return -ENODEV;
2814 } else if (u132->going > 0) {
2815 dev_err(&u132->platform_dev->dev, "device is being removed\n");
2816 return -ESHUTDOWN;
2817 } else {
2818 int retval = 0;
2819 mutex_lock(&u132->sw_lock);
2820 switch (typeReq) {
2821 case ClearHubFeature:
2822 switch (wValue) {
2823 case C_HUB_OVER_CURRENT:
2824 case C_HUB_LOCAL_POWER:
2825 break;
2826 default:
2827 goto stall;
2828 }
2829 break;
2830 case SetHubFeature:
2831 switch (wValue) {
2832 case C_HUB_OVER_CURRENT:
2833 case C_HUB_LOCAL_POWER:
2834 break;
2835 default:
2836 goto stall;
2837 }
2838 break;
2839 case ClearPortFeature:{
2840 retval = u132_roothub_clearportfeature(u132,
2841 wValue, wIndex);
2842 if (retval)
2843 goto error;
2844 break;
2845 }
2846 case GetHubDescriptor:{
2847 retval = u132_roothub_descriptor(u132,
2848 (struct usb_hub_descriptor *)buf);
2849 if (retval)
2850 goto error;
2851 break;
2852 }
2853 case GetHubStatus:{
2854 retval = u132_roothub_status(u132,
2855 (__le32 *) buf);
2856 if (retval)
2857 goto error;
2858 break;
2859 }
2860 case GetPortStatus:{
2861 retval = u132_roothub_portstatus(u132,
2862 (__le32 *) buf, wIndex);
2863 if (retval)
2864 goto error;
2865 break;
2866 }
2867 case SetPortFeature:{
2868 retval = u132_roothub_setportfeature(u132,
2869 wValue, wIndex);
2870 if (retval)
2871 goto error;
2872 break;
2873 }
2874 default:
2875 goto stall;
2876 error:
2877 u132_disable(u132);
2878 u132->going = 1;
2879 break;
2880 stall:
2881 retval = -EPIPE;
2882 break;
2883 }
2884 mutex_unlock(&u132->sw_lock);
2885 return retval;
2886 }
Tony Olechd774efe2006-09-13 11:27:35 +01002887}
2888
2889static int u132_start_port_reset(struct usb_hcd *hcd, unsigned port_num)
2890{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002891 struct u132 *u132 = hcd_to_u132(hcd);
2892 if (u132->going > 1) {
2893 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
2894 , u132->going);
2895 return -ENODEV;
2896 } else if (u132->going > 0) {
2897 dev_err(&u132->platform_dev->dev, "device is being removed\n");
2898 return -ESHUTDOWN;
2899 } else
2900 return 0;
Tony Olechd774efe2006-09-13 11:27:35 +01002901}
2902
Tony Olechd774efe2006-09-13 11:27:35 +01002903
2904#ifdef CONFIG_PM
Tony Olechd774efe2006-09-13 11:27:35 +01002905static int u132_bus_suspend(struct usb_hcd *hcd)
2906{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002907 struct u132 *u132 = hcd_to_u132(hcd);
2908 if (u132->going > 1) {
2909 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
2910 , u132->going);
2911 return -ENODEV;
2912 } else if (u132->going > 0) {
2913 dev_err(&u132->platform_dev->dev, "device is being removed\n");
2914 return -ESHUTDOWN;
2915 } else
2916 return 0;
Tony Olechd774efe2006-09-13 11:27:35 +01002917}
2918
2919static int u132_bus_resume(struct usb_hcd *hcd)
2920{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002921 struct u132 *u132 = hcd_to_u132(hcd);
2922 if (u132->going > 1) {
2923 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
2924 , u132->going);
2925 return -ENODEV;
2926 } else if (u132->going > 0) {
2927 dev_err(&u132->platform_dev->dev, "device is being removed\n");
2928 return -ESHUTDOWN;
2929 } else
2930 return 0;
Tony Olechd774efe2006-09-13 11:27:35 +01002931}
2932
2933#else
Tony Olechd774efe2006-09-13 11:27:35 +01002934#define u132_bus_suspend NULL
2935#define u132_bus_resume NULL
2936#endif
Julia Lawall0b88b1c2017-07-28 22:41:52 +02002937static const struct hc_driver u132_hc_driver = {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002938 .description = hcd_name,
2939 .hcd_priv_size = sizeof(struct u132),
2940 .irq = NULL,
2941 .flags = HCD_USB11 | HCD_MEMORY,
2942 .reset = u132_hcd_reset,
2943 .start = u132_hcd_start,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002944 .stop = u132_hcd_stop,
2945 .urb_enqueue = u132_urb_enqueue,
2946 .urb_dequeue = u132_urb_dequeue,
2947 .endpoint_disable = u132_endpoint_disable,
2948 .get_frame_number = u132_get_frame,
2949 .hub_status_data = u132_hub_status_data,
2950 .hub_control = u132_hub_control,
2951 .bus_suspend = u132_bus_suspend,
2952 .bus_resume = u132_bus_resume,
2953 .start_port_reset = u132_start_port_reset,
Tony Olechd774efe2006-09-13 11:27:35 +01002954};
2955
2956/*
2957* This function may be called by the USB core whilst the "usb_all_devices_rwsem"
2958* is held for writing, thus this module must not call usb_remove_hcd()
2959* synchronously - but instead should immediately stop activity to the
Matt LaPlante0779bf22006-11-30 05:24:39 +01002960* device and asynchronously call usb_remove_hcd()
Tony Olechd774efe2006-09-13 11:27:35 +01002961*/
Bill Pembertonfb4e98a2012-11-19 13:26:20 -05002962static int u132_remove(struct platform_device *pdev)
Tony Olechd774efe2006-09-13 11:27:35 +01002963{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002964 struct usb_hcd *hcd = platform_get_drvdata(pdev);
2965 if (hcd) {
2966 struct u132 *u132 = hcd_to_u132(hcd);
2967 if (u132->going++ > 1) {
2968 dev_err(&u132->platform_dev->dev, "already being remove"
Tony Olech4b873612006-12-06 13:16:22 +00002969 "d\n");
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002970 return -ENODEV;
2971 } else {
2972 int rings = MAX_U132_RINGS;
2973 int endps = MAX_U132_ENDPS;
2974 dev_err(&u132->platform_dev->dev, "removing device u132"
Tony Olech4b873612006-12-06 13:16:22 +00002975 ".%d\n", u132->sequence_num);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002976 msleep(100);
2977 mutex_lock(&u132->sw_lock);
2978 u132_monitor_cancel_work(u132);
2979 while (rings-- > 0) {
2980 struct u132_ring *ring = &u132->ring[rings];
2981 u132_ring_cancel_work(u132, ring);
Colin Ian Kingd1ab1b82019-01-04 17:43:49 +00002982 }
2983 while (endps-- > 0) {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07002984 struct u132_endp *endp = u132->endp[endps];
2985 if (endp)
2986 u132_endp_cancel_work(u132, endp);
2987 }
2988 u132->going += 1;
2989 printk(KERN_INFO "removing device u132.%d\n",
2990 u132->sequence_num);
2991 mutex_unlock(&u132->sw_lock);
2992 usb_remove_hcd(hcd);
2993 u132_u132_put_kref(u132);
2994 return 0;
2995 }
2996 } else
2997 return 0;
Tony Olechd774efe2006-09-13 11:27:35 +01002998}
2999
3000static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
3001{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003002 int rings = MAX_U132_RINGS;
3003 int ports = MAX_U132_PORTS;
3004 int addrs = MAX_U132_ADDRS;
3005 int udevs = MAX_U132_UDEVS;
3006 int endps = MAX_U132_ENDPS;
Jingoo Hand4f09e22013-07-30 19:59:40 +09003007 u132->board = dev_get_platdata(&pdev->dev);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003008 u132->platform_dev = pdev;
3009 u132->power = 0;
3010 u132->reset = 0;
3011 mutex_init(&u132->sw_lock);
Daniel Walker50d8ca92008-03-23 00:00:02 -07003012 mutex_init(&u132->scheduler_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003013 while (rings-- > 0) {
3014 struct u132_ring *ring = &u132->ring[rings];
3015 ring->u132 = u132;
3016 ring->number = rings + 1;
3017 ring->length = 0;
3018 ring->curr_endp = NULL;
3019 INIT_DELAYED_WORK(&ring->scheduler,
David Howellsc4028952006-11-22 14:57:56 +00003020 u132_hcd_ring_work_scheduler);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003021 }
3022 mutex_lock(&u132->sw_lock);
3023 INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work);
3024 while (ports-- > 0) {
3025 struct u132_port *port = &u132->port[ports];
3026 port->u132 = u132;
3027 port->reset = 0;
3028 port->enable = 0;
3029 port->power = 0;
3030 port->Status = 0;
3031 }
3032 while (addrs-- > 0) {
3033 struct u132_addr *addr = &u132->addr[addrs];
3034 addr->address = 0;
3035 }
3036 while (udevs-- > 0) {
3037 struct u132_udev *udev = &u132->udev[udevs];
3038 int i = ARRAY_SIZE(udev->endp_number_in);
3039 int o = ARRAY_SIZE(udev->endp_number_out);
3040 udev->usb_device = NULL;
3041 udev->udev_number = 0;
3042 udev->usb_addr = 0;
3043 udev->portnumber = 0;
3044 while (i-- > 0)
3045 udev->endp_number_in[i] = 0;
3046
3047 while (o-- > 0)
3048 udev->endp_number_out[o] = 0;
3049
3050 }
3051 while (endps-- > 0)
3052 u132->endp[endps] = NULL;
3053
3054 mutex_unlock(&u132->sw_lock);
Tony Olechd774efe2006-09-13 11:27:35 +01003055}
3056
Bill Pemberton41ac7b32012-11-19 13:21:48 -05003057static int u132_probe(struct platform_device *pdev)
Tony Olechd774efe2006-09-13 11:27:35 +01003058{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003059 struct usb_hcd *hcd;
3060 int retval;
3061 u32 control;
3062 u32 rh_a = -1;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003063
3064 msleep(100);
3065 if (u132_exiting > 0)
3066 return -ENODEV;
3067
3068 retval = ftdi_write_pcimem(pdev, intrdisable, OHCI_INTR_MIE);
3069 if (retval)
3070 return retval;
3071 retval = ftdi_read_pcimem(pdev, control, &control);
3072 if (retval)
3073 return retval;
3074 retval = ftdi_read_pcimem(pdev, roothub.a, &rh_a);
3075 if (retval)
3076 return retval;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003077
Kay Sievers7071a3c2008-05-02 06:02:41 +02003078 hcd = usb_create_hcd(&u132_hc_driver, &pdev->dev, dev_name(&pdev->dev));
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003079 if (!hcd) {
3080 printk(KERN_ERR "failed to create the usb hcd struct for U132\n"
3081 );
3082 ftdi_elan_gone_away(pdev);
3083 return -ENOMEM;
3084 } else {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003085 struct u132 *u132 = hcd_to_u132(hcd);
Bill Pemberton66414452010-04-29 10:04:56 -04003086 retval = 0;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003087 hcd->rsrc_start = 0;
3088 mutex_lock(&u132_module_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003089 u132->sequence_num = ++u132_instances;
3090 mutex_unlock(&u132_module_lock);
3091 u132_u132_init_kref(u132);
3092 u132_initialise(u132, pdev);
3093 hcd->product_desc = "ELAN U132 Host Controller";
3094 retval = usb_add_hcd(hcd, 0, 0);
3095 if (retval != 0) {
3096 dev_err(&u132->platform_dev->dev, "init error %d\n",
3097 retval);
3098 u132_u132_put_kref(u132);
3099 return retval;
3100 } else {
Peter Chen3c9740a2013-11-05 10:46:02 +08003101 device_wakeup_enable(hcd->self.controller);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003102 u132_monitor_queue_work(u132, 100);
3103 return 0;
3104 }
3105 }
Tony Olechd774efe2006-09-13 11:27:35 +01003106}
3107
3108
3109#ifdef CONFIG_PM
Alan Stern84ebc102013-03-27 16:14:46 -04003110/*
3111 * for this device there's no useful distinction between the controller
Rafael J. Wysockiceb6c9c2014-11-29 23:47:05 +01003112 * and its root hub.
Alan Stern84ebc102013-03-27 16:14:46 -04003113 */
Tony Olechd774efe2006-09-13 11:27:35 +01003114static int u132_suspend(struct platform_device *pdev, pm_message_t state)
3115{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003116 struct usb_hcd *hcd = platform_get_drvdata(pdev);
3117 struct u132 *u132 = hcd_to_u132(hcd);
3118 if (u132->going > 1) {
3119 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
3120 , u132->going);
3121 return -ENODEV;
3122 } else if (u132->going > 0) {
3123 dev_err(&u132->platform_dev->dev, "device is being removed\n");
3124 return -ESHUTDOWN;
3125 } else {
Mirco Tischler038eb0e2008-02-24 05:16:39 +01003126 int retval = 0, ports;
Rafael J. Wysocki3a2d5b72008-02-23 19:13:25 +01003127
3128 switch (state.event) {
3129 case PM_EVENT_FREEZE:
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003130 retval = u132_bus_suspend(hcd);
Rafael J. Wysocki3a2d5b72008-02-23 19:13:25 +01003131 break;
3132 case PM_EVENT_SUSPEND:
3133 case PM_EVENT_HIBERNATE:
Mirco Tischler038eb0e2008-02-24 05:16:39 +01003134 ports = MAX_U132_PORTS;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003135 while (ports-- > 0) {
3136 port_power(u132, ports, 0);
3137 }
Rafael J. Wysocki3a2d5b72008-02-23 19:13:25 +01003138 break;
3139 }
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003140 return retval;
3141 }
Tony Olechd774efe2006-09-13 11:27:35 +01003142}
3143
3144static int u132_resume(struct platform_device *pdev)
3145{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003146 struct usb_hcd *hcd = platform_get_drvdata(pdev);
3147 struct u132 *u132 = hcd_to_u132(hcd);
3148 if (u132->going > 1) {
3149 dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
3150 , u132->going);
3151 return -ENODEV;
3152 } else if (u132->going > 0) {
3153 dev_err(&u132->platform_dev->dev, "device is being removed\n");
3154 return -ESHUTDOWN;
3155 } else {
3156 int retval = 0;
Alan Stern70a1c9e2008-03-06 17:00:58 -05003157 if (!u132->port[0].power) {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003158 int ports = MAX_U132_PORTS;
3159 while (ports-- > 0) {
3160 port_power(u132, ports, 1);
3161 }
3162 retval = 0;
3163 } else {
3164 retval = u132_bus_resume(hcd);
3165 }
3166 return retval;
3167 }
Tony Olechd774efe2006-09-13 11:27:35 +01003168}
3169
3170#else
3171#define u132_suspend NULL
3172#define u132_resume NULL
3173#endif
3174/*
Matt LaPlante0779bf22006-11-30 05:24:39 +01003175* this driver is loaded explicitly by ftdi_u132
Tony Olechd774efe2006-09-13 11:27:35 +01003176*
3177* the platform_driver struct is static because it is per type of module
3178*/
3179static struct platform_driver u132_platform_driver = {
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003180 .probe = u132_probe,
Bill Pemberton76904172012-11-19 13:21:08 -05003181 .remove = u132_remove,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003182 .suspend = u132_suspend,
3183 .resume = u132_resume,
3184 .driver = {
Geert Uytterhoevena4586772013-11-12 20:07:25 +01003185 .name = hcd_name,
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003186 },
Tony Olechd774efe2006-09-13 11:27:35 +01003187};
3188static int __init u132_hcd_init(void)
3189{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003190 int retval;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003191 u132_instances = 0;
3192 u132_exiting = 0;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003193 if (usb_disabled())
3194 return -ENODEV;
Michal Marek654d1212011-04-05 16:59:11 +02003195 printk(KERN_INFO "driver %s\n", hcd_name);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003196 workqueue = create_singlethread_workqueue("u132");
Kangjie Lu3de3dbe2019-03-19 12:34:06 -05003197 if (!workqueue)
3198 return -ENOMEM;
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003199 retval = platform_driver_register(&u132_platform_driver);
Mukesh Ojhaf276e002019-03-26 13:42:22 +05303200 if (retval)
3201 destroy_workqueue(workqueue);
3202
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003203 return retval;
Tony Olechd774efe2006-09-13 11:27:35 +01003204}
3205
3206
3207module_init(u132_hcd_init);
3208static void __exit u132_hcd_exit(void)
3209{
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003210 mutex_lock(&u132_module_lock);
3211 u132_exiting += 1;
3212 mutex_unlock(&u132_module_lock);
Daniel Walkerb40f8d32008-03-23 00:00:01 -07003213 platform_driver_unregister(&u132_platform_driver);
3214 printk(KERN_INFO "u132-hcd driver deregistered\n");
3215 wait_event(u132_hcd_wait, u132_instances == 0);
3216 flush_workqueue(workqueue);
3217 destroy_workqueue(workqueue);
Tony Olechd774efe2006-09-13 11:27:35 +01003218}
3219
3220
3221module_exit(u132_hcd_exit);
3222MODULE_LICENSE("GPL");
Kay Sieversf4fce612008-04-10 21:29:22 -07003223MODULE_ALIAS("platform:u132_hcd");