ftdi-elan.c revision 84346269f9a05e66ff2973916776a080d566f9ab
1a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/*
2a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* USB FTDI client driver for Elan Digital Systems's Uxxx adapters
3a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*
4a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* Copyright(C) 2006 Elan Digital Systems Limited
5a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* http://www.elandigitalsystems.com
6a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*
7a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* Author and Maintainer - Tony Olech - Elan Digital Systems
8a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* tony.olech@elandigitalsystems.com
9a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*
10a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* This program is free software;you can redistribute it and/or
11a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* modify it under the terms of the GNU General Public License as
12a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* published by the Free Software Foundation, version 2.
13a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*
14a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*
15a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* This driver was written by Tony Olech(tony.olech@elandigitalsystems.com)
16a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* based on various USB client drivers in the 2.6.15 linux kernel
17a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* with constant reference to the 3rd Edition of Linux Device Drivers
18a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* published by O'Reilly
19a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*
20a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* The U132 adapter is a USB to CardBus adapter specifically designed
21a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* for PC cards that contain an OHCI host controller. Typical PC cards
22a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* are the Orange Mobile 3G Option GlobeTrotter Fusion card.
23a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*
24a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* The U132 adapter will *NOT *work with PC cards that do not contain
25a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* an OHCI controller. A simple way to test whether a PC card has an
26a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* OHCI controller as an interface is to insert the PC card directly
27a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* into a laptop(or desktop) with a CardBus slot and if "lspci" shows
28a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* a new USB controller and "lsusb -v" shows a new OHCI Host Controller
29a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* then there is a good chance that the U132 adapter will support the
30a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* PC card.(you also need the specific client driver for the PC card)
31a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*
32a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* Please inform the Author and Maintainer about any PC cards that
33a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* contain OHCI Host Controller and work when directly connected to
34a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* an embedded CardBus slot but do not work when they are connected
35a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* via an ELAN U132 adapter.
36a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*
37a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/
38a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#include <linux/kernel.h>
39a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#include <linux/errno.h>
40a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#include <linux/init.h>
41a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#include <linux/list.h>
42a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#include <linux/ioctl.h>
434b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech#include <linux/pci_ids.h>
44a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#include <linux/slab.h>
45a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#include <linux/module.h>
46a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#include <linux/kref.h>
47eb33caec1ed29fa2b04a2c5f02e3fed2add91db4Matthias Kaehlcke#include <linux/mutex.h>
48a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#include <asm/uaccess.h>
49a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#include <linux/usb.h>
50a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#include <linux/workqueue.h>
51a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#include <linux/platform_device.h>
52a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechMODULE_AUTHOR("Tony Olech");
53a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechMODULE_DESCRIPTION("FTDI ELAN driver");
54a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechMODULE_LICENSE("GPL");
55a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444)
564b87361d49c04894458f4d4e80f9669abc894ae1Tony Olechstatic int distrust_firmware = 1;
574b87361d49c04894458f4d4e80f9669abc894ae1Tony Olechmodule_param(distrust_firmware, bool, 0);
584b87361d49c04894458f4d4e80f9669abc894ae1Tony OlechMODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurren"
594b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        "t setup");
60a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechextern struct platform_driver u132_platform_driver;
61a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic struct workqueue_struct *status_queue;
62a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic struct workqueue_struct *command_queue;
63a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic struct workqueue_struct *respond_queue;
64a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/*
65a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* ftdi_module_lock exists to protect access to global variables
66a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*
67a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/
68eb33caec1ed29fa2b04a2c5f02e3fed2add91db4Matthias Kaehlckestatic struct mutex ftdi_module_lock;
69a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_instances = 0;
70a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic struct list_head ftdi_static_list;
71a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/*
72a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* end of the global variables protected by ftdi_module_lock
73a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/
74a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#include "usb_u132.h"
754b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech#include <asm/io.h>
764b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech#include "../core/hcd.h"
7747f8468e6008a1d62f7dacbcff4ec3e115a500c8David Brownell
7847f8468e6008a1d62f7dacbcff4ec3e115a500c8David Brownell	/* FIXME ohci.h is ONLY for internal use by the OHCI driver.
7947f8468e6008a1d62f7dacbcff4ec3e115a500c8David Brownell	 * If you're going to try stuff like this, you need to split
8047f8468e6008a1d62f7dacbcff4ec3e115a500c8David Brownell	 * out shareable stuff (register declarations?) into its own
8147f8468e6008a1d62f7dacbcff4ec3e115a500c8David Brownell	 * file, maybe name <linux/usb/ohci.h>
8247f8468e6008a1d62f7dacbcff4ec3e115a500c8David Brownell	 */
8347f8468e6008a1d62f7dacbcff4ec3e115a500c8David Brownell
844b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech#include "../host/ohci.h"
85a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/* Define these values to match your devices*/
86a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define USB_FTDI_ELAN_VENDOR_ID 0x0403
87a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define USB_FTDI_ELAN_PRODUCT_ID 0xd6ea
88a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/* table of devices that work with this driver*/
89a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic struct usb_device_id ftdi_elan_table[] = {
90a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        {USB_DEVICE(USB_FTDI_ELAN_VENDOR_ID, USB_FTDI_ELAN_PRODUCT_ID)},
91a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        { /* Terminating entry */ }
92a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech};
93a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
94a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechMODULE_DEVICE_TABLE(usb, ftdi_elan_table);
95a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/* only the jtag(firmware upgrade device) interface requires
96a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* a device file and corresponding minor number, but the
97a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* interface is created unconditionally - I suppose it could
98a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* be configured or not according to a module parameter.
99a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* But since we(now) require one interface per device,
100a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* and since it unlikely that a normal installation would
101a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* require more than a couple of elan-ftdi devices, 8 seems
102a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* like a reasonable limit to have here, and if someone
103a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* really requires more than 8 devices, then they can frig the
104a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* code and recompile
105a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/
106a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define USB_FTDI_ELAN_MINOR_BASE 192
107a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define COMMAND_BITS 5
108a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define COMMAND_SIZE (1<<COMMAND_BITS)
109a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define COMMAND_MASK (COMMAND_SIZE-1)
110a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstruct u132_command {
111a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u8 header;
112a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u16 length;
113a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u8 address;
114a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u8 width;
115a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u32 value;
116a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int follows;
117a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        void *buffer;
118a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech};
119a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define RESPOND_BITS 5
120a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define RESPOND_SIZE (1<<RESPOND_BITS)
121a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define RESPOND_MASK (RESPOND_SIZE-1)
122a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstruct u132_respond {
123a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u8 header;
124a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u8 address;
125a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u32 *value;
126a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int *result;
127a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct completion wait_completion;
128a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech};
129a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstruct u132_target {
130a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        void *endp;
131a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct urb *urb;
132a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int toggle_bits;
133a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int error_count;
134a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int condition_code;
135a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int repeat_number;
136a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int halted;
137a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int skipped;
138a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int actual;
139a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int non_null;
140a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int active;
141a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int abandoning;
142a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
143a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int toggle_bits, int error_count, int condition_code,
144a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int repeat_number, int halted, int skipped, int actual,
145a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int non_null);
146a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech};
147a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/* Structure to hold all of our device specific stuff*/
148a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstruct usb_ftdi {
149a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct list_head ftdi_list;
150a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct semaphore u132_lock;
151a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int command_next;
152a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int command_head;
153a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct u132_command command[COMMAND_SIZE];
154a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int respond_next;
155a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int respond_head;
156a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct u132_respond respond[RESPOND_SIZE];
157a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct u132_target target[4];
158a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        char device_name[16];
159a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        unsigned synchronized:1;
160a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        unsigned enumerated:1;
161a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        unsigned registered:1;
162a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        unsigned initialized:1;
163a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        unsigned card_ejected:1;
164a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int function;
165a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int sequence_num;
166a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int disconnected;
167a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int gone_away;
168a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int stuck_status;
169a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int status_queue_delay;
170a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct semaphore sw_lock;
171a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct usb_device *udev;
172a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct usb_interface *interface;
173a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct usb_class_driver *class;
174c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells        struct delayed_work status_work;
175c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells        struct delayed_work command_work;
176c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells        struct delayed_work respond_work;
177a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct u132_platform_data platform_data;
178a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct resource resources[0];
179a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct platform_device platform_dev;
180a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        unsigned char *bulk_in_buffer;
181a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        size_t bulk_in_size;
182a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        size_t bulk_in_last;
183a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        size_t bulk_in_left;
184a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        __u8 bulk_in_endpointAddr;
185a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        __u8 bulk_out_endpointAddr;
186a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct kref kref;
187a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u32 controlreg;
188a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u8 response[4 + 1024];
189a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int expected;
190a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int recieved;
191a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int ed_found;
192a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech};
193a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define kref_to_usb_ftdi(d) container_of(d, struct usb_ftdi, kref)
194a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define platform_device_to_usb_ftdi(d) container_of(d, struct usb_ftdi, \
195a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        platform_dev)
196a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic struct usb_driver ftdi_elan_driver;
197a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_delete(struct kref *kref)
198a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
199a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct usb_ftdi *ftdi = kref_to_usb_ftdi(kref);
200a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        dev_warn(&ftdi->udev->dev, "FREEING ftdi=%p\n", ftdi);
201a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        usb_put_dev(ftdi->udev);
202a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->disconnected += 1;
203eb33caec1ed29fa2b04a2c5f02e3fed2add91db4Matthias Kaehlcke        mutex_lock(&ftdi_module_lock);
204a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        list_del_init(&ftdi->ftdi_list);
205a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi_instances -= 1;
206eb33caec1ed29fa2b04a2c5f02e3fed2add91db4Matthias Kaehlcke        mutex_unlock(&ftdi_module_lock);
207a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        kfree(ftdi->bulk_in_buffer);
208a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->bulk_in_buffer = NULL;
209a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
210a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
211a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_put_kref(struct usb_ftdi *ftdi)
212a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
213a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        kref_put(&ftdi->kref, ftdi_elan_delete);
214a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
215a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
216a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_get_kref(struct usb_ftdi *ftdi)
217a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
218a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        kref_get(&ftdi->kref);
219a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
220a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
221a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_init_kref(struct usb_ftdi *ftdi)
222a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
223a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        kref_init(&ftdi->kref);
224a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
225a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
226a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_status_requeue_work(struct usb_ftdi *ftdi, unsigned int delta)
227a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
228c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells	if (!queue_delayed_work(status_queue, &ftdi->status_work, delta))
229c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells		kref_put(&ftdi->kref, ftdi_elan_delete);
230a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
231a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
232a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_status_queue_work(struct usb_ftdi *ftdi, unsigned int delta)
233a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
234c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells	if (queue_delayed_work(status_queue, &ftdi->status_work, delta))
235c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells		kref_get(&ftdi->kref);
236a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
237a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
238a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_status_cancel_work(struct usb_ftdi *ftdi)
239a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
240a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (cancel_delayed_work(&ftdi->status_work))
241a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                kref_put(&ftdi->kref, ftdi_elan_delete);
242a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
243a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
244a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_command_requeue_work(struct usb_ftdi *ftdi, unsigned int delta)
245a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
246c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells	if (!queue_delayed_work(command_queue, &ftdi->command_work, delta))
247c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells		kref_put(&ftdi->kref, ftdi_elan_delete);
248a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
249a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
250a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_command_queue_work(struct usb_ftdi *ftdi, unsigned int delta)
251a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
252c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells	if (queue_delayed_work(command_queue, &ftdi->command_work, delta))
253c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells		kref_get(&ftdi->kref);
254a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
255a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
256a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_command_cancel_work(struct usb_ftdi *ftdi)
257a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
258a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (cancel_delayed_work(&ftdi->command_work))
259a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                kref_put(&ftdi->kref, ftdi_elan_delete);
260a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
261a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
262a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_response_requeue_work(struct usb_ftdi *ftdi,
263a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        unsigned int delta)
264a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
265c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells	if (!queue_delayed_work(respond_queue, &ftdi->respond_work, delta))
266c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells		kref_put(&ftdi->kref, ftdi_elan_delete);
267a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
268a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
269a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_respond_queue_work(struct usb_ftdi *ftdi, unsigned int delta)
270a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
271c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells	if (queue_delayed_work(respond_queue, &ftdi->respond_work, delta))
272c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells		kref_get(&ftdi->kref);
273a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
274a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
275a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_response_cancel_work(struct usb_ftdi *ftdi)
276a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
277a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (cancel_delayed_work(&ftdi->respond_work))
278a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                kref_put(&ftdi->kref, ftdi_elan_delete);
279a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
280a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
281a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechvoid ftdi_elan_gone_away(struct platform_device *pdev)
282a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
283a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
284a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->gone_away += 1;
285a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi_elan_put_kref(ftdi);
286a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
287a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
288a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
289a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechEXPORT_SYMBOL_GPL(ftdi_elan_gone_away);
2909ce8540c884c19c0f5f38c9e85d4bdc192baf321Adrian Bunkstatic void ftdi_release_platform_dev(struct device *dev)
291a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
292a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        dev->parent = NULL;
293a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
294a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
295a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_do_callback(struct usb_ftdi *ftdi,
296a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct u132_target *target, u8 *buffer, int length);
297a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi);
298a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi);
299a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi);
300a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi);
301a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi);
302a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_synchronize(struct usb_ftdi *ftdi);
303a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_stuck_waiting(struct usb_ftdi *ftdi);
304a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_command_engine(struct usb_ftdi *ftdi);
305a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_respond_engine(struct usb_ftdi *ftdi);
306a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_hcd_init(struct usb_ftdi *ftdi)
307a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
308a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int result;
309a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (ftdi->platform_dev.dev.parent)
310a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -EBUSY;
311a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi_elan_get_kref(ftdi);
312a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->platform_data.potpg = 100;
313a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->platform_data.reset = NULL;
314a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->platform_dev.id = ftdi->sequence_num;
315a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->platform_dev.resource = ftdi->resources;
316a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->platform_dev.num_resources = ARRAY_SIZE(ftdi->resources);
317a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->platform_dev.dev.platform_data = &ftdi->platform_data;
318a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->platform_dev.dev.parent = NULL;
319a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->platform_dev.dev.release = ftdi_release_platform_dev;
320a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->platform_dev.dev.dma_mask = NULL;
321a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        snprintf(ftdi->device_name, sizeof(ftdi->device_name), "u132_hcd");
322a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->platform_dev.name = ftdi->device_name;
323a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        dev_info(&ftdi->udev->dev, "requesting module '%s'\n", "u132_hcd");
324a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        request_module("u132_hcd");
325a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        dev_info(&ftdi->udev->dev, "registering '%s'\n",
326a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi->platform_dev.name);
327a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        result = platform_device_register(&ftdi->platform_dev);
328a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        return result;
329a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
330a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
331a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_abandon_completions(struct usb_ftdi *ftdi)
332a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
333a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        down(&ftdi->u132_lock);
334a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        while (ftdi->respond_next > ftdi->respond_head) {
335a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                struct u132_respond *respond = &ftdi->respond[RESPOND_MASK &
336a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->respond_head++];
337a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                *respond->result = -ESHUTDOWN;
338a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                *respond->value = 0;
339a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                complete(&respond->wait_completion);
340a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } up(&ftdi->u132_lock);
341a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
342a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
343a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_abandon_targets(struct usb_ftdi *ftdi)
344a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
345a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int ed_number = 4;
346a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        down(&ftdi->u132_lock);
347a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        while (ed_number-- > 0) {
348a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                struct u132_target *target = &ftdi->target[ed_number];
349a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (target->active == 1) {
350a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        target->condition_code = TD_DEVNOTRESP;
351a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->u132_lock);
352a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi_elan_do_callback(ftdi, target, NULL, 0);
353a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        down(&ftdi->u132_lock);
354a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
355a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
356a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->recieved = 0;
357a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->expected = 4;
358a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->ed_found = 0;
359a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        up(&ftdi->u132_lock);
360a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
361a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
362a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_flush_targets(struct usb_ftdi *ftdi)
363a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
364a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int ed_number = 4;
365a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        down(&ftdi->u132_lock);
366a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        while (ed_number-- > 0) {
367a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                struct u132_target *target = &ftdi->target[ed_number];
368a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                target->abandoning = 1;
369a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech              wait_1:if (target->active == 1) {
370a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        int command_size = ftdi->command_next -
371a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                ftdi->command_head;
372a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if (command_size < COMMAND_SIZE) {
373a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                struct u132_command *command = &ftdi->command[
374a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        COMMAND_MASK & ftdi->command_next];
375a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                command->header = 0x80 | (ed_number << 5) | 0x4;
376a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                command->length = 0x00;
377a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                command->address = 0x00;
378a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                command->width = 0x00;
379a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                command->follows = 0;
380a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                command->value = 0;
381a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                command->buffer = &command->value;
382a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                ftdi->command_next += 1;
383a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                ftdi_elan_kick_command_queue(ftdi);
384a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else {
385a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                up(&ftdi->u132_lock);
386a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                msleep(100);
387a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                down(&ftdi->u132_lock);
388a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                goto wait_1;
389a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        }
390a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
391a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech              wait_2:if (target->active == 1) {
392a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        int command_size = ftdi->command_next -
393a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                ftdi->command_head;
394a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if (command_size < COMMAND_SIZE) {
395a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                struct u132_command *command = &ftdi->command[
396a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        COMMAND_MASK & ftdi->command_next];
397a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                command->header = 0x90 | (ed_number << 5);
398a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                command->length = 0x00;
399a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                command->address = 0x00;
400a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                command->width = 0x00;
401a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                command->follows = 0;
402a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                command->value = 0;
403a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                command->buffer = &command->value;
404a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                ftdi->command_next += 1;
405a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                ftdi_elan_kick_command_queue(ftdi);
406a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else {
407a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                up(&ftdi->u132_lock);
408a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                msleep(100);
409a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                down(&ftdi->u132_lock);
410a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                goto wait_2;
411a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        }
412a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
413a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
414a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->recieved = 0;
415a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->expected = 4;
416a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->ed_found = 0;
417a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        up(&ftdi->u132_lock);
418a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
419a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
420a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_cancel_targets(struct usb_ftdi *ftdi)
421a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
422a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int ed_number = 4;
423a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        down(&ftdi->u132_lock);
424a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        while (ed_number-- > 0) {
425a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                struct u132_target *target = &ftdi->target[ed_number];
426a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                target->abandoning = 1;
427a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech              wait:if (target->active == 1) {
428a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        int command_size = ftdi->command_next -
429a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                ftdi->command_head;
430a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if (command_size < COMMAND_SIZE) {
431a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                struct u132_command *command = &ftdi->command[
432a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        COMMAND_MASK & ftdi->command_next];
433a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                command->header = 0x80 | (ed_number << 5) | 0x4;
434a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                command->length = 0x00;
435a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                command->address = 0x00;
436a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                command->width = 0x00;
437a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                command->follows = 0;
438a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                command->value = 0;
439a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                command->buffer = &command->value;
440a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                ftdi->command_next += 1;
441a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                ftdi_elan_kick_command_queue(ftdi);
442a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else {
443a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                up(&ftdi->u132_lock);
444a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                msleep(100);
445a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                down(&ftdi->u132_lock);
446a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                goto wait;
447a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        }
448a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
449a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
450a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->recieved = 0;
451a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->expected = 4;
452a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->ed_found = 0;
453a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        up(&ftdi->u132_lock);
454a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
455a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
456a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi)
457a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
458a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi_command_queue_work(ftdi, 0);
459a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        return;
460a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
461a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
462c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howellsstatic void ftdi_elan_command_work(struct work_struct *work)
463a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
464c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells        struct usb_ftdi *ftdi =
465c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells		container_of(work, struct usb_ftdi, command_work.work);
466c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells
467a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (ftdi->disconnected > 0) {
468a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi_elan_put_kref(ftdi);
469a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return;
470a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else {
471a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int retval = ftdi_elan_command_engine(ftdi);
472a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (retval == -ESHUTDOWN) {
473a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->disconnected += 1;
474a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else if (retval == -ENODEV) {
475a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->disconnected += 1;
476a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else if (retval)
477a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        dev_err(&ftdi->udev->dev, "command error %d\n", retval);
478a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi_command_requeue_work(ftdi, msecs_to_jiffies(10));
479a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return;
480a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
481a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
482a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
483a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi)
484a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
485a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi_respond_queue_work(ftdi, 0);
486a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        return;
487a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
488a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
489c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howellsstatic void ftdi_elan_respond_work(struct work_struct *work)
490a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
491c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells        struct usb_ftdi *ftdi =
492c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells		container_of(work, struct usb_ftdi, respond_work.work);
493a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (ftdi->disconnected > 0) {
494a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi_elan_put_kref(ftdi);
495a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return;
496a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else {
497a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int retval = ftdi_elan_respond_engine(ftdi);
498a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (retval == 0) {
499a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else if (retval == -ESHUTDOWN) {
500a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->disconnected += 1;
501a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else if (retval == -ENODEV) {
502a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->disconnected += 1;
503a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else if (retval == -EILSEQ) {
504a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->disconnected += 1;
505a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else {
506a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->disconnected += 1;
507a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        dev_err(&ftdi->udev->dev, "respond error %d\n", retval);
508a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
509a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (ftdi->disconnected > 0) {
510a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi_elan_abandon_completions(ftdi);
511a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi_elan_abandon_targets(ftdi);
512a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
513a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi_response_requeue_work(ftdi, msecs_to_jiffies(10));
514a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return;
515a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
516a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
517a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
518a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
519a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/*
520a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* the sw_lock is initially held and will be freed
521a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* after the FTDI has been synchronized
522a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*
523a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/
524c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howellsstatic void ftdi_elan_status_work(struct work_struct *work)
525a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
526c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells        struct usb_ftdi *ftdi =
527c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells		container_of(work, struct usb_ftdi, status_work.work);
528a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int work_delay_in_msec = 0;
529a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (ftdi->disconnected > 0) {
530a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi_elan_put_kref(ftdi);
531a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return;
532a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else if (ftdi->synchronized == 0) {
533a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                down(&ftdi->sw_lock);
534a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (ftdi_elan_synchronize(ftdi) == 0) {
535a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->synchronized = 1;
536a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi_command_queue_work(ftdi, 1);
537a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi_respond_queue_work(ftdi, 1);
538a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->sw_lock);
539a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        work_delay_in_msec = 100;
540a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else {
541a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        dev_err(&ftdi->udev->dev, "synchronize failed\n");
542a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->sw_lock);
543a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        work_delay_in_msec = 10 *1000;
544a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
545a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else if (ftdi->stuck_status > 0) {
546a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (ftdi_elan_stuck_waiting(ftdi) == 0) {
547a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->stuck_status = 0;
548a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->synchronized = 0;
549a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else if ((ftdi->stuck_status++ % 60) == 1) {
550a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        dev_err(&ftdi->udev->dev, "WRONG type of card inserted "
551a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                "- please remove\n");
552a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else
553a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        dev_err(&ftdi->udev->dev, "WRONG type of card inserted "
554a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                "- checked %d times\n", ftdi->stuck_status);
555a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                work_delay_in_msec = 100;
556a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else if (ftdi->enumerated == 0) {
557a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (ftdi_elan_enumeratePCI(ftdi) == 0) {
558a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->enumerated = 1;
559a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        work_delay_in_msec = 250;
560a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else
561a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        work_delay_in_msec = 1000;
562a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else if (ftdi->initialized == 0) {
563a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (ftdi_elan_setupOHCI(ftdi) == 0) {
564a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->initialized = 1;
565a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        work_delay_in_msec = 500;
566a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else {
567a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        dev_err(&ftdi->udev->dev, "initialized failed - trying "
568a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                "again in 10 seconds\n");
5694b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        work_delay_in_msec = 1 *1000;
570a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
571a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else if (ftdi->registered == 0) {
572a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                work_delay_in_msec = 10;
573a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (ftdi_elan_hcd_init(ftdi) == 0) {
574a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->registered = 1;
575a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else
576a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        dev_err(&ftdi->udev->dev, "register failed\n");
577a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                work_delay_in_msec = 250;
578a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else {
579a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (ftdi_elan_checkingPCI(ftdi) == 0) {
580a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        work_delay_in_msec = 250;
581a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else if (ftdi->controlreg & 0x00400000) {
582a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if (ftdi->gone_away > 0) {
583a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                dev_err(&ftdi->udev->dev, "PCI device eject con"
584a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        "firmed platform_dev.dev.parent=%p plat"
585a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        "form_dev.dev=%p\n",
586a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        ftdi->platform_dev.dev.parent,
587a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        &ftdi->platform_dev.dev);
588a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                platform_device_unregister(&ftdi->platform_dev);
589a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                ftdi->platform_dev.dev.parent = NULL;
590a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                ftdi->registered = 0;
591a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                ftdi->enumerated = 0;
592a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                ftdi->card_ejected = 0;
593a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                ftdi->initialized = 0;
594a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                ftdi->gone_away = 0;
595a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else
596a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                ftdi_elan_flush_targets(ftdi);
597a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        work_delay_in_msec = 250;
598a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else {
599a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        dev_err(&ftdi->udev->dev, "PCI device has disappeared\n"
600a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                );
601a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi_elan_cancel_targets(ftdi);
602a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        work_delay_in_msec = 500;
603a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->enumerated = 0;
604a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->initialized = 0;
605a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
606a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
607a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (ftdi->disconnected > 0) {
608a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi_elan_put_kref(ftdi);
609a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return;
610a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else {
611a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi_status_requeue_work(ftdi,
612a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        msecs_to_jiffies(work_delay_in_msec));
613a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return;
614a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
615a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
616a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
617a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
618a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/*
619a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* file_operations for the jtag interface
620a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*
621a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* the usage count for the device is incremented on open()
622a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* and decremented on release()
623a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/
624a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_open(struct inode *inode, struct file *file)
625a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
626a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int subminor = iminor(inode);
627a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct usb_interface *interface = usb_find_interface(&ftdi_elan_driver,
628a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                subminor);
629a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (!interface) {
630a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                printk(KERN_ERR "can't find device for minor %d\n", subminor);
631a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENODEV;
632a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else {
633a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                struct usb_ftdi *ftdi = usb_get_intfdata(interface);
634a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (!ftdi) {
635a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return -ENODEV;
636a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else {
637a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if (down_interruptible(&ftdi->sw_lock)) {
638a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                return -EINTR;
639a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else {
640a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                ftdi_elan_get_kref(ftdi);
641a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                file->private_data = ftdi;
642a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                return 0;
643a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        }
644a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
645a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
646a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
647a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
648a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_release(struct inode *inode, struct file *file)
649a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
650a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct usb_ftdi *ftdi = (struct usb_ftdi *)file->private_data;
651a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (ftdi == NULL)
652a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENODEV;
653a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        up(&ftdi->sw_lock);        /* decrement the count on our device */
654a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi_elan_put_kref(ftdi);
655a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        return 0;
656a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
657a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
658a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
659a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define FTDI_ELAN_IOC_MAGIC 0xA1
660a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define FTDI_ELAN_IOCDEBUG _IOC(_IOC_WRITE, FTDI_ELAN_IOC_MAGIC, 1, 132)
661a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_ioctl(struct inode *inode, struct file *file,
662a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        unsigned int cmd, unsigned long arg)
663a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
664a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        switch (cmd) {
665a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        case FTDI_ELAN_IOCDEBUG:{
666a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        char line[132];
667a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        int size = strncpy_from_user(line,
668a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                (const char __user *)arg, sizeof(line));
669a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if (size < 0) {
670a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                return -EINVAL;
671a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else {
672a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                printk(KERN_ERR "TODO: ioctl %s\n", line);
673a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                return 0;
674a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        }
675a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
676a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        default:
677a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -EFAULT;
678a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
679a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
680a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
681a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
682a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/*
683a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*
684a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* blocking bulk reads are used to get data from the device
685a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*
686a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/
687a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic ssize_t ftdi_elan_read(struct file *file, char __user *buffer,
688a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech			      size_t count, loff_t *ppos)
689a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
690a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        char data[30 *3 + 4];
691a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        char *d = data;
692a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int m = (sizeof(data) - 1) / 3;
693a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int bytes_read = 0;
694a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int retry_on_empty = 10;
695a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int retry_on_timeout = 5;
696a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct usb_ftdi *ftdi = (struct usb_ftdi *)file->private_data;
697a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (ftdi->disconnected > 0) {
698a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENODEV;
699a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
700a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        data[0] = 0;
701a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech      have:if (ftdi->bulk_in_left > 0) {
702a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (count-- > 0) {
703a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        char *p = ++ftdi->bulk_in_last + ftdi->bulk_in_buffer;
704a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->bulk_in_left -= 1;
705a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if (bytes_read < m) {
706a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                d += sprintf(d, " %02X", 0x000000FF & *p);
707a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else if (bytes_read > m) {
708a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else
709a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                d += sprintf(d, " ..");
710a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if (copy_to_user(buffer++, p, 1)) {
711a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                return -EFAULT;
712a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else {
713a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                bytes_read += 1;
714a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                goto have;
715a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        }
716a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else
717a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return bytes_read;
718a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
719a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech      more:if (count > 0) {
720a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int packet_bytes = 0;
721a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int retval = usb_bulk_msg(ftdi->udev,
722a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr),
723a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                         ftdi->bulk_in_buffer, ftdi->bulk_in_size,
724a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        &packet_bytes, msecs_to_jiffies(50));
725a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (packet_bytes > 2) {
726a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->bulk_in_left = packet_bytes - 2;
727a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->bulk_in_last = 1;
728a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        goto have;
729a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else if (retval == -ETIMEDOUT) {
730a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if (retry_on_timeout-- > 0) {
731a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                goto more;
732a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else if (bytes_read > 0) {
733a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                return bytes_read;
734a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else
735a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                return retval;
736a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else if (retval == 0) {
737a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if (retry_on_empty-- > 0) {
738a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                goto more;
739a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else
740a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                return bytes_read;
741a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else
742a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return retval;
743a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else
744a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return bytes_read;
745a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
746a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
7477d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void ftdi_elan_write_bulk_callback(struct urb *urb)
748a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
749a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct usb_ftdi *ftdi = (struct usb_ftdi *)urb->context;
75084346269f9a05e66ff2973916776a080d566f9abGreg Kroah-Hartman	int status = urb->status;
75184346269f9a05e66ff2973916776a080d566f9abGreg Kroah-Hartman
75284346269f9a05e66ff2973916776a080d566f9abGreg Kroah-Hartman	if (status && !(status == -ENOENT || status == -ECONNRESET ||
75384346269f9a05e66ff2973916776a080d566f9abGreg Kroah-Hartman	    status == -ESHUTDOWN)) {
754a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                dev_err(&ftdi->udev->dev, "urb=%p write bulk status received: %"
75584346269f9a05e66ff2973916776a080d566f9abGreg Kroah-Hartman                        "d\n", urb, status);
756a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
757a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        usb_buffer_free(urb->dev, urb->transfer_buffer_length,
758a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                urb->transfer_buffer, urb->transfer_dma);
759a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
760a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
761a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int fill_buffer_with_all_queued_commands(struct usb_ftdi *ftdi,
762a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        char *buf, int command_size, int total_size)
763a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
764a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int ed_commands = 0;
765a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int b = 0;
766a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int I = command_size;
767a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int i = ftdi->command_head;
768a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        while (I-- > 0) {
769a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                struct u132_command *command = &ftdi->command[COMMAND_MASK &
770a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        i++];
771a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int F = command->follows;
772a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                u8 *f = command->buffer;
773a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (command->header & 0x80) {
774a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ed_commands |= 1 << (0x3 & (command->header >> 5));
775a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
776a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                buf[b++] = command->header;
777a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                buf[b++] = (command->length >> 0) & 0x00FF;
778a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                buf[b++] = (command->length >> 8) & 0x00FF;
779a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                buf[b++] = command->address;
780a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                buf[b++] = command->width;
781a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                while (F-- > 0) {
782a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        buf[b++] = *f++;
783a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
784a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
785a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        return ed_commands;
786a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
787a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
788a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_total_command_size(struct usb_ftdi *ftdi, int command_size)
789a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
790a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int total_size = 0;
791a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int I = command_size;
792a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int i = ftdi->command_head;
793a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        while (I-- > 0) {
794a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                struct u132_command *command = &ftdi->command[COMMAND_MASK &
795a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        i++];
796a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                total_size += 5 + command->follows;
797a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } return total_size;
798a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
799a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
800a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_command_engine(struct usb_ftdi *ftdi)
801a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
802a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int retval;
803a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        char *buf;
804a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int ed_commands;
805a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int total_size;
806a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct urb *urb;
807a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int command_size = ftdi->command_next - ftdi->command_head;
808a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (command_size == 0)
809a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return 0;
810a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        total_size = ftdi_elan_total_command_size(ftdi, command_size);
811a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        urb = usb_alloc_urb(0, GFP_KERNEL);
812a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (!urb) {
813a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                dev_err(&ftdi->udev->dev, "could not get a urb to write %d comm"
814a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        "ands totaling %d bytes to the Uxxx\n", command_size,
815a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        total_size);
816a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENOMEM;
817a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
818a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        buf = usb_buffer_alloc(ftdi->udev, total_size, GFP_KERNEL,
819a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                &urb->transfer_dma);
820a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (!buf) {
821a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                dev_err(&ftdi->udev->dev, "could not get a buffer to write %d c"
822a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        "ommands totaling %d bytes to the Uxxx\n", command_size,
823a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                         total_size);
824a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                usb_free_urb(urb);
825a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENOMEM;
826a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
827a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ed_commands = fill_buffer_with_all_queued_commands(ftdi, buf,
828a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                command_size, total_size);
829a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev,
830a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi->bulk_out_endpointAddr), buf, total_size,
831a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi_elan_write_bulk_callback, ftdi);
832a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
833a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (ed_commands) {
834a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                char diag[40 *3 + 4];
835a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                char *d = diag;
836a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int m = total_size;
837a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                u8 *c = buf;
838a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int s = (sizeof(diag) - 1) / 3;
839a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                diag[0] = 0;
840a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                while (s-- > 0 && m-- > 0) {
841a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if (s > 0 || m == 0) {
842a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                d += sprintf(d, " %02X", *c++);
843a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else
844a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                d += sprintf(d, " ..");
845a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
846a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
847a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        retval = usb_submit_urb(urb, GFP_KERNEL);
848a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (retval) {
849a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                dev_err(&ftdi->udev->dev, "failed %d to submit urb %p to write "
850a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        "%d commands totaling %d bytes to the Uxxx\n", retval,
851a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        urb, command_size, total_size);
852a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                usb_buffer_free(ftdi->udev, total_size, buf, urb->transfer_dma);
853a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                usb_free_urb(urb);
854a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return retval;
855a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
856a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        usb_free_urb(urb);        /* release our reference to this urb,
857a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                the USB core will eventually free it entirely */
858a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->command_head += command_size;
859a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi_elan_kick_respond_queue(ftdi);
860a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        return 0;
861a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
862a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
863a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_do_callback(struct usb_ftdi *ftdi,
864a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct u132_target *target, u8 *buffer, int length)
865a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
866a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct urb *urb = target->urb;
867a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int halted = target->halted;
868a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int skipped = target->skipped;
869a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int actual = target->actual;
870a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int non_null = target->non_null;
871a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int toggle_bits = target->toggle_bits;
872a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int error_count = target->error_count;
873a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int condition_code = target->condition_code;
874a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int repeat_number = target->repeat_number;
875a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        void (*callback) (void *, struct urb *, u8 *, int, int, int, int, int,
876a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int, int, int, int) = target->callback;
877a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        target->active -= 1;
878a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        target->callback = NULL;
879a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        (*callback) (target->endp, urb, buffer, length, toggle_bits,
880a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                error_count, condition_code, repeat_number, halted, skipped,
881a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                actual, non_null);
882a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
883a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
884a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic char *have_ed_set_response(struct usb_ftdi *ftdi,
885a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct u132_target *target, u16 ed_length, int ed_number, int ed_type,
886a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        char *b)
887a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
888a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int payload = (ed_length >> 0) & 0x07FF;
889a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        down(&ftdi->u132_lock);
890a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        target->actual = 0;
891a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        target->non_null = (ed_length >> 15) & 0x0001;
892a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        target->repeat_number = (ed_length >> 11) & 0x000F;
893a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (ed_type == 0x02) {
894a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (payload == 0 || target->abandoning > 0) {
895a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        target->abandoning = 0;
896a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->u132_lock);
897a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response,
898a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                payload);
899a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->recieved = 0;
900a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->expected = 4;
901a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->ed_found = 0;
902a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return ftdi->response;
903a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else {
904a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->expected = 4 + payload;
905a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->ed_found = 1;
906a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->u132_lock);
907a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return b;
908a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
909a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else if (ed_type == 0x03) {
910a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (payload == 0 || target->abandoning > 0) {
911a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        target->abandoning = 0;
912a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->u132_lock);
913a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response,
914a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                payload);
915a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->recieved = 0;
916a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->expected = 4;
917a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->ed_found = 0;
918a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return ftdi->response;
919a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else {
920a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->expected = 4 + payload;
921a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->ed_found = 1;
922a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->u132_lock);
923a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return b;
924a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
925a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else if (ed_type == 0x01) {
926a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                target->abandoning = 0;
927a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                up(&ftdi->u132_lock);
928a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response,
929a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        payload);
930a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi->recieved = 0;
931a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi->expected = 4;
932a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi->ed_found = 0;
933a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return ftdi->response;
934a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else {
935a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                target->abandoning = 0;
936a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                up(&ftdi->u132_lock);
937a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response,
938a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        payload);
939a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi->recieved = 0;
940a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi->expected = 4;
941a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi->ed_found = 0;
942a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return ftdi->response;
943a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
944a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
945a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
946a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic char *have_ed_get_response(struct usb_ftdi *ftdi,
947a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct u132_target *target, u16 ed_length, int ed_number, int ed_type,
948a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        char *b)
949a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
950a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        down(&ftdi->u132_lock);
951a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        target->condition_code = TD_DEVNOTRESP;
952a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        target->actual = (ed_length >> 0) & 0x01FF;
953a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        target->non_null = (ed_length >> 15) & 0x0001;
954a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        target->repeat_number = (ed_length >> 11) & 0x000F;
955a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        up(&ftdi->u132_lock);
956a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (target->active)
957a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi_elan_do_callback(ftdi, target, NULL, 0);
958a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        target->abandoning = 0;
959a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->recieved = 0;
960a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->expected = 4;
961a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->ed_found = 0;
962a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        return ftdi->response;
963a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
964a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
965a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
966a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/*
967a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* The engine tries to empty the FTDI fifo
968a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*
969a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* all responses found in the fifo data are dispatched thus
970a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* the response buffer can only ever hold a maximum sized
971a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* response from the Uxxx.
972a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*
973a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/
974a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_respond_engine(struct usb_ftdi *ftdi)
975a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
976a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u8 *b = ftdi->response + ftdi->recieved;
977a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int bytes_read = 0;
978a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int retry_on_empty = 1;
979a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int retry_on_timeout = 3;
980a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int empty_packets = 0;
981a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech      read:{
982a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int packet_bytes = 0;
983a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int retval = usb_bulk_msg(ftdi->udev,
984a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr),
985a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                         ftdi->bulk_in_buffer, ftdi->bulk_in_size,
986a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        &packet_bytes, msecs_to_jiffies(500));
987a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                char diag[30 *3 + 4];
988a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                char *d = diag;
989a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int m = packet_bytes;
990a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                u8 *c = ftdi->bulk_in_buffer;
991a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int s = (sizeof(diag) - 1) / 3;
992a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                diag[0] = 0;
993a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                while (s-- > 0 && m-- > 0) {
994a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if (s > 0 || m == 0) {
995a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                d += sprintf(d, " %02X", *c++);
996a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else
997a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                d += sprintf(d, " ..");
998a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
999a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (packet_bytes > 2) {
1000a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->bulk_in_left = packet_bytes - 2;
1001a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->bulk_in_last = 1;
1002a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        goto have;
1003a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else if (retval == -ETIMEDOUT) {
1004a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if (retry_on_timeout-- > 0) {
1005a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                dev_err(&ftdi->udev->dev, "TIMED OUT with packe"
1006a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        "t_bytes = %d with total %d bytes%s\n",
1007a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        packet_bytes, bytes_read, diag);
1008a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                goto more;
1009a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else if (bytes_read > 0) {
1010a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                dev_err(&ftdi->udev->dev, "ONLY %d bytes%s\n",
1011a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        bytes_read, diag);
1012a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                return -ENOMEM;
1013a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else {
1014a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                dev_err(&ftdi->udev->dev, "TIMED OUT with packe"
1015a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        "t_bytes = %d with total %d bytes%s\n",
1016a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        packet_bytes, bytes_read, diag);
1017a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                return -ENOMEM;
1018a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        }
1019a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else if (retval == -EILSEQ) {
1020a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        dev_err(&ftdi->udev->dev, "error = %d with packet_bytes"
1021a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                " = %d with total %d bytes%s\n", retval,
1022a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                packet_bytes, bytes_read, diag);
1023a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return retval;
1024a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else if (retval) {
1025a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        dev_err(&ftdi->udev->dev, "error = %d with packet_bytes"
1026a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                " = %d with total %d bytes%s\n", retval,
1027a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                packet_bytes, bytes_read, diag);
1028a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return retval;
1029a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else if (packet_bytes == 2) {
1030a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        unsigned char s0 = ftdi->bulk_in_buffer[0];
1031a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        unsigned char s1 = ftdi->bulk_in_buffer[1];
1032a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        empty_packets += 1;
1033a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if (s0 == 0x31 && s1 == 0x60) {
1034a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                if (retry_on_empty-- > 0) {
1035a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        goto more;
1036a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                } else
1037a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        return 0;
1038a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else if (s0 == 0x31 && s1 == 0x00) {
1039a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                if (retry_on_empty-- > 0) {
1040a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        goto more;
1041a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                } else
1042a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        return 0;
1043a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else {
1044a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                if (retry_on_empty-- > 0) {
1045a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        goto more;
1046a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                } else
1047a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        return 0;
1048a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        }
1049a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else if (packet_bytes == 1) {
1050a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if (retry_on_empty-- > 0) {
1051a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                goto more;
1052a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else
1053a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                return 0;
1054a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else {
1055a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if (retry_on_empty-- > 0) {
1056a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                goto more;
1057a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else
1058a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                return 0;
1059a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
1060a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
1061a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech      more:{
1062a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                goto read;
1063a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
1064a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech      have:if (ftdi->bulk_in_left > 0) {
1065a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                u8 c = ftdi->bulk_in_buffer[++ftdi->bulk_in_last];
1066a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                bytes_read += 1;
1067a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi->bulk_in_left -= 1;
1068a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (ftdi->recieved == 0 && c == 0xFF) {
1069a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        goto have;
1070a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else
1071a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        *b++ = c;
1072a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (++ftdi->recieved < ftdi->expected) {
1073a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        goto have;
1074a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else if (ftdi->ed_found) {
1075a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        int ed_number = (ftdi->response[0] >> 5) & 0x03;
1076a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        u16 ed_length = (ftdi->response[2] << 8) |
1077a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                ftdi->response[1];
1078a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        struct u132_target *target = &ftdi->target[ed_number];
1079a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        int payload = (ed_length >> 0) & 0x07FF;
1080a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        char diag[30 *3 + 4];
1081a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        char *d = diag;
1082a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        int m = payload;
1083a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        u8 *c = 4 + ftdi->response;
1084a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        int s = (sizeof(diag) - 1) / 3;
1085a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        diag[0] = 0;
1086a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        while (s-- > 0 && m-- > 0) {
1087a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                if (s > 0 || m == 0) {
1088a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        d += sprintf(d, " %02X", *c++);
1089a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                } else
1090a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        d += sprintf(d, " ..");
1091a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        }
1092a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response,
1093a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                payload);
1094a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->recieved = 0;
1095a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->expected = 4;
1096a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->ed_found = 0;
1097a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        b = ftdi->response;
1098a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        goto have;
1099a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else if (ftdi->expected == 8) {
1100a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        u8 buscmd;
1101a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        int respond_head = ftdi->respond_head++;
1102a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        struct u132_respond *respond = &ftdi->respond[
1103a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                RESPOND_MASK & respond_head];
1104a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        u32 data = ftdi->response[7];
1105a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        data <<= 8;
1106a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        data |= ftdi->response[6];
1107a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        data <<= 8;
1108a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        data |= ftdi->response[5];
1109a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        data <<= 8;
1110a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        data |= ftdi->response[4];
1111a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        *respond->value = data;
1112a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        *respond->result = 0;
1113a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        complete(&respond->wait_completion);
1114a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->recieved = 0;
1115a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->expected = 4;
1116a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->ed_found = 0;
1117a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        b = ftdi->response;
1118a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        buscmd = (ftdi->response[0] >> 0) & 0x0F;
1119a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if (buscmd == 0x00) {
1120a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else if (buscmd == 0x02) {
1121a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else if (buscmd == 0x06) {
1122a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else if (buscmd == 0x0A) {
1123a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else
1124a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                dev_err(&ftdi->udev->dev, "Uxxx unknown(%0X) va"
1125a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        "lue = %08X\n", buscmd, data);
1126a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        goto have;
1127a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else {
1128a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if ((ftdi->response[0] & 0x80) == 0x00) {
1129a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                ftdi->expected = 8;
1130a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                goto have;
1131a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else {
1132a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                int ed_number = (ftdi->response[0] >> 5) & 0x03;
1133a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                int ed_type = (ftdi->response[0] >> 0) & 0x03;
1134a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                u16 ed_length = (ftdi->response[2] << 8) |
1135a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        ftdi->response[1];
1136a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                struct u132_target *target = &ftdi->target[
1137a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        ed_number];
1138a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                target->halted = (ftdi->response[0] >> 3) &
1139a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        0x01;
1140a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                target->skipped = (ftdi->response[0] >> 2) &
1141a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        0x01;
1142a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                target->toggle_bits = (ftdi->response[3] >> 6)
1143a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        & 0x03;
1144a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                target->error_count = (ftdi->response[3] >> 4)
1145a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        & 0x03;
1146a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                target->condition_code = (ftdi->response[
1147a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        3] >> 0) & 0x0F;
1148a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                if ((ftdi->response[0] & 0x10) == 0x00) {
1149a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        b = have_ed_set_response(ftdi, target,
1150a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                ed_length, ed_number, ed_type,
1151a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                b);
1152a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        goto have;
1153a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                } else {
1154a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        b = have_ed_get_response(ftdi, target,
1155a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                ed_length, ed_number, ed_type,
1156a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                b);
1157a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        goto have;
1158a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                }
1159a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        }
1160a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
1161a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else
1162a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                goto more;
1163a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
1164a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1165a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1166a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/*
1167a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* create a urb, and a buffer for it, and copy the data to the urb
1168a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*
1169a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/
1170a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic ssize_t ftdi_elan_write(struct file *file,
1171a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech			       const char __user *user_buffer, size_t count,
1172a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech			       loff_t *ppos)
1173a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
1174a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int retval = 0;
1175a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct urb *urb;
1176a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        char *buf;
117796a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartman        struct usb_ftdi *ftdi = file->private_data;
117896a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartman
1179a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (ftdi->disconnected > 0) {
1180a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENODEV;
1181a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
1182a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (count == 0) {
1183a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                goto exit;
1184a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
1185a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        urb = usb_alloc_urb(0, GFP_KERNEL);
1186a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (!urb) {
1187a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                retval = -ENOMEM;
1188a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                goto error_1;
1189a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
1190a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        buf = usb_buffer_alloc(ftdi->udev, count, GFP_KERNEL,
1191a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                &urb->transfer_dma);
1192a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (!buf) {
1193a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                retval = -ENOMEM;
1194a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                goto error_2;
1195a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
1196a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (copy_from_user(buf, user_buffer, count)) {
1197a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                retval = -EFAULT;
1198a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                goto error_3;
1199a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
1200a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev,
1201a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi->bulk_out_endpointAddr), buf, count,
1202a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi_elan_write_bulk_callback, ftdi);
1203a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1204a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        retval = usb_submit_urb(urb, GFP_KERNEL);
1205a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (retval) {
1206a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                dev_err(&ftdi->udev->dev, "failed submitting write urb, error %"
1207a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        "d\n", retval);
120896a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartman                goto error_3;
1209a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
1210a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        usb_free_urb(urb);
121196a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartman
121296a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartmanexit:
1213a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        return count;
121496a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartmanerror_3:
121596a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartman	usb_buffer_free(ftdi->udev, count, buf, urb->transfer_dma);
121696a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartmanerror_2:
121796a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartman	usb_free_urb(urb);
121896a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartmanerror_1:
121996a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartman	return retval;
1220a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
1221a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
122200977a59b951207d38380c75f03a36829950265cArjan van de Venstatic const struct file_operations ftdi_elan_fops = {
1223a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        .owner = THIS_MODULE,
1224a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        .llseek = no_llseek,
1225a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        .ioctl = ftdi_elan_ioctl,
1226a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        .read = ftdi_elan_read,
1227a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        .write = ftdi_elan_write,
1228a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        .open = ftdi_elan_open,
1229a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        .release = ftdi_elan_release,
1230a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech};
1231a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1232a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/*
1233a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* usb class driver info in order to get a minor number from the usb core,
1234a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* and to have the device registered with the driver core
1235a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/
1236a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic struct usb_class_driver ftdi_elan_jtag_class = {
1237a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        .name = "ftdi-%d-jtag",
1238a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        .fops = &ftdi_elan_fops,
1239a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        .minor_base = USB_FTDI_ELAN_MINOR_BASE,
1240a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech};
1241a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1242a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/*
1243a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* the following definitions are for the
1244a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* ELAN FPGA state machgine processor that
1245a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* lies on the other side of the FTDI chip
1246a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/
1247a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPCIu132rd 0x0
1248a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPCIu132wr 0x1
1249a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPCIiord 0x2
1250a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPCIiowr 0x3
1251a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPCImemrd 0x6
1252a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPCImemwr 0x7
1253a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPCIcfgrd 0xA
1254a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPCIcfgwr 0xB
1255a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPCInull 0xF
1256a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cU132cmd_status 0x0
1257a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cU132flash 0x1
1258a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPIDsetup 0x0
1259a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPIDout 0x1
1260a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPIDin 0x2
1261a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPIDinonce 0x3
1262a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCnoerror 0x0
1263a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCcrc 0x1
1264a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCbitstuff 0x2
1265a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCtoggle 0x3
1266a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCstall 0x4
1267a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCnoresp 0x5
1268a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCbadpid1 0x6
1269a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCbadpid2 0x7
1270a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCdataoverrun 0x8
1271a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCdataunderrun 0x9
1272a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCbuffoverrun 0xC
1273a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCbuffunderrun 0xD
1274a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCnotaccessed 0xF
1275a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_write_reg(struct usb_ftdi *ftdi, u32 data)
1276a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
1277a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech      wait:if (ftdi->disconnected > 0) {
1278a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENODEV;
1279a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else {
1280a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int command_size;
1281a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                down(&ftdi->u132_lock);
1282a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                command_size = ftdi->command_next - ftdi->command_head;
1283a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (command_size < COMMAND_SIZE) {
1284a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        struct u132_command *command = &ftdi->command[
1285a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                COMMAND_MASK & ftdi->command_next];
1286a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->header = 0x00 | cPCIu132wr;
1287a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->length = 0x04;
1288a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->address = 0x00;
1289a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->width = 0x00;
1290a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->follows = 4;
1291a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->value = data;
1292a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->buffer = &command->value;
1293a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->command_next += 1;
1294a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi_elan_kick_command_queue(ftdi);
1295a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->u132_lock);
1296a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return 0;
1297a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else {
1298a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->u132_lock);
1299a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        msleep(100);
1300a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        goto wait;
1301a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
1302a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
1303a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
1304a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1305a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_write_config(struct usb_ftdi *ftdi, int config_offset,
1306a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u8 width, u32 data)
1307a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
1308a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u8 addressofs = config_offset / 4;
1309a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech      wait:if (ftdi->disconnected > 0) {
1310a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENODEV;
1311a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else {
1312a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int command_size;
1313a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                down(&ftdi->u132_lock);
1314a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                command_size = ftdi->command_next - ftdi->command_head;
1315a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (command_size < COMMAND_SIZE) {
1316a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        struct u132_command *command = &ftdi->command[
1317a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                COMMAND_MASK & ftdi->command_next];
1318a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->header = 0x00 | (cPCIcfgwr & 0x0F);
1319a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->length = 0x04;
1320a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->address = addressofs;
1321a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->width = 0x00 | (width & 0x0F);
1322a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->follows = 4;
1323a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->value = data;
1324a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->buffer = &command->value;
1325a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->command_next += 1;
1326a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi_elan_kick_command_queue(ftdi);
1327a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->u132_lock);
1328a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return 0;
1329a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else {
1330a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->u132_lock);
1331a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        msleep(100);
1332a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        goto wait;
1333a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
1334a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
1335a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
1336a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1337a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_write_pcimem(struct usb_ftdi *ftdi, int mem_offset,
1338a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u8 width, u32 data)
1339a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
1340a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u8 addressofs = mem_offset / 4;
1341a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech      wait:if (ftdi->disconnected > 0) {
1342a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENODEV;
1343a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else {
1344a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int command_size;
1345a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                down(&ftdi->u132_lock);
1346a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                command_size = ftdi->command_next - ftdi->command_head;
1347a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (command_size < COMMAND_SIZE) {
1348a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        struct u132_command *command = &ftdi->command[
1349a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                COMMAND_MASK & ftdi->command_next];
1350a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->header = 0x00 | (cPCImemwr & 0x0F);
1351a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->length = 0x04;
1352a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->address = addressofs;
1353a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->width = 0x00 | (width & 0x0F);
1354a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->follows = 4;
1355a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->value = data;
1356a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->buffer = &command->value;
1357a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->command_next += 1;
1358a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi_elan_kick_command_queue(ftdi);
1359a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->u132_lock);
1360a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return 0;
1361a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else {
1362a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->u132_lock);
1363a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        msleep(100);
1364a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        goto wait;
1365a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
1366a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
1367a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
1368a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1369a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechint usb_ftdi_elan_write_pcimem(struct platform_device *pdev, int mem_offset,
1370a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u8 width, u32 data)
1371a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
1372a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
1373a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        return ftdi_elan_write_pcimem(ftdi, mem_offset, width, data);
1374a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
1375a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1376a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1377a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechEXPORT_SYMBOL_GPL(usb_ftdi_elan_write_pcimem);
1378a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_read_reg(struct usb_ftdi *ftdi, u32 *data)
1379a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
1380a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech      wait:if (ftdi->disconnected > 0) {
1381a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENODEV;
1382a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else {
1383a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int command_size;
1384a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int respond_size;
1385a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                down(&ftdi->u132_lock);
1386a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                command_size = ftdi->command_next - ftdi->command_head;
1387a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                respond_size = ftdi->respond_next - ftdi->respond_head;
1388a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE)
1389a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        {
1390a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        struct u132_command *command = &ftdi->command[
1391a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                COMMAND_MASK & ftdi->command_next];
1392a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        struct u132_respond *respond = &ftdi->respond[
1393a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                RESPOND_MASK & ftdi->respond_next];
1394a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        int result = -ENODEV;
1395a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        respond->result = &result;
1396a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        respond->header = command->header = 0x00 | cPCIu132rd;
1397a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->length = 0x04;
1398a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        respond->address = command->address = cU132cmd_status;
1399a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->width = 0x00;
1400a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->follows = 0;
1401a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->value = 0;
1402a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->buffer = NULL;
1403a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        respond->value = data;
1404a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        init_completion(&respond->wait_completion);
1405a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->command_next += 1;
1406a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->respond_next += 1;
1407a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi_elan_kick_command_queue(ftdi);
1408a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->u132_lock);
1409a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        wait_for_completion(&respond->wait_completion);
1410a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return result;
1411a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else {
1412a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->u132_lock);
1413a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        msleep(100);
1414a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        goto wait;
1415a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
1416a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
1417a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
1418a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1419a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_read_config(struct usb_ftdi *ftdi, int config_offset,
1420a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u8 width, u32 *data)
1421a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
1422a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u8 addressofs = config_offset / 4;
1423a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech      wait:if (ftdi->disconnected > 0) {
1424a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENODEV;
1425a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else {
1426a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int command_size;
1427a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int respond_size;
1428a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                down(&ftdi->u132_lock);
1429a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                command_size = ftdi->command_next - ftdi->command_head;
1430a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                respond_size = ftdi->respond_next - ftdi->respond_head;
1431a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE)
1432a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        {
1433a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        struct u132_command *command = &ftdi->command[
1434a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                COMMAND_MASK & ftdi->command_next];
1435a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        struct u132_respond *respond = &ftdi->respond[
1436a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                RESPOND_MASK & ftdi->respond_next];
1437a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        int result = -ENODEV;
1438a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        respond->result = &result;
1439a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        respond->header = command->header = 0x00 | (cPCIcfgrd &
1440a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                0x0F);
1441a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->length = 0x04;
1442a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        respond->address = command->address = addressofs;
1443a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->width = 0x00 | (width & 0x0F);
1444a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->follows = 0;
1445a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->value = 0;
1446a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->buffer = NULL;
1447a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        respond->value = data;
1448a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        init_completion(&respond->wait_completion);
1449a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->command_next += 1;
1450a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->respond_next += 1;
1451a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi_elan_kick_command_queue(ftdi);
1452a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->u132_lock);
1453a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        wait_for_completion(&respond->wait_completion);
1454a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return result;
1455a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else {
1456a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->u132_lock);
1457a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        msleep(100);
1458a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        goto wait;
1459a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
1460a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
1461a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
1462a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1463a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_read_pcimem(struct usb_ftdi *ftdi, int mem_offset,
1464a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u8 width, u32 *data)
1465a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
1466a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u8 addressofs = mem_offset / 4;
1467a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech      wait:if (ftdi->disconnected > 0) {
1468a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENODEV;
1469a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else {
1470a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int command_size;
1471a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int respond_size;
1472a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                down(&ftdi->u132_lock);
1473a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                command_size = ftdi->command_next - ftdi->command_head;
1474a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                respond_size = ftdi->respond_next - ftdi->respond_head;
1475a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE)
1476a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        {
1477a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        struct u132_command *command = &ftdi->command[
1478a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                COMMAND_MASK & ftdi->command_next];
1479a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        struct u132_respond *respond = &ftdi->respond[
1480a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                RESPOND_MASK & ftdi->respond_next];
1481a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        int result = -ENODEV;
1482a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        respond->result = &result;
1483a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        respond->header = command->header = 0x00 | (cPCImemrd &
1484a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                0x0F);
1485a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->length = 0x04;
1486a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        respond->address = command->address = addressofs;
1487a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->width = 0x00 | (width & 0x0F);
1488a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->follows = 0;
1489a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->value = 0;
1490a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->buffer = NULL;
1491a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        respond->value = data;
1492a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        init_completion(&respond->wait_completion);
1493a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->command_next += 1;
1494a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->respond_next += 1;
1495a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi_elan_kick_command_queue(ftdi);
1496a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->u132_lock);
1497a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        wait_for_completion(&respond->wait_completion);
1498a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return result;
1499a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else {
1500a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->u132_lock);
1501a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        msleep(100);
1502a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        goto wait;
1503a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
1504a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
1505a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
1506a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1507a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechint usb_ftdi_elan_read_pcimem(struct platform_device *pdev, int mem_offset,
1508a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u8 width, u32 *data)
1509a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
1510a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
1511a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (ftdi->initialized == 0) {
1512a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENODEV;
1513a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else
1514a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return ftdi_elan_read_pcimem(ftdi, mem_offset, width, data);
1515a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
1516a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1517a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1518a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechEXPORT_SYMBOL_GPL(usb_ftdi_elan_read_pcimem);
1519a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_edset_setup(struct usb_ftdi *ftdi, u8 ed_number,
1520a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
1521a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
1522a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int toggle_bits, int error_count, int condition_code, int repeat_number,
1523a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech         int halted, int skipped, int actual, int non_null))
1524a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
1525a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u8 ed = ed_number - 1;
1526a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech      wait:if (ftdi->disconnected > 0) {
1527a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENODEV;
1528a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else if (ftdi->initialized == 0) {
1529a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENODEV;
1530a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else {
1531a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int command_size;
1532a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                down(&ftdi->u132_lock);
1533a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                command_size = ftdi->command_next - ftdi->command_head;
1534a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (command_size < COMMAND_SIZE) {
1535a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        struct u132_target *target = &ftdi->target[ed];
1536a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        struct u132_command *command = &ftdi->command[
1537a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                COMMAND_MASK & ftdi->command_next];
1538a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->header = 0x80 | (ed << 5);
1539a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->length = 0x8007;
1540a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->address = (toggle_bits << 6) | (ep_number << 2)
1541a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                | (address << 0);
1542a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->width = usb_maxpacket(urb->dev, urb->pipe,
1543a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                usb_pipeout(urb->pipe));
1544a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->follows = 8;
1545a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->value = 0;
1546a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->buffer = urb->setup_packet;
1547a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        target->callback = callback;
1548a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        target->endp = endp;
1549a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        target->urb = urb;
1550a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        target->active = 1;
1551a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->command_next += 1;
1552a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi_elan_kick_command_queue(ftdi);
1553a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->u132_lock);
1554a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return 0;
1555a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else {
1556a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->u132_lock);
1557a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        msleep(100);
1558a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        goto wait;
1559a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
1560a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
1561a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
1562a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1563a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechint usb_ftdi_elan_edset_setup(struct platform_device *pdev, u8 ed_number,
1564a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
1565a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
1566a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int toggle_bits, int error_count, int condition_code, int repeat_number,
1567a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech         int halted, int skipped, int actual, int non_null))
1568a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
1569a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
1570a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        return ftdi_elan_edset_setup(ftdi, ed_number, endp, urb, address,
1571a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ep_number, toggle_bits, callback);
1572a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
1573a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1574a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1575a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechEXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_setup);
1576a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_edset_input(struct usb_ftdi *ftdi, u8 ed_number,
1577a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
1578a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
1579a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int toggle_bits, int error_count, int condition_code, int repeat_number,
1580a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech         int halted, int skipped, int actual, int non_null))
1581a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
1582a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u8 ed = ed_number - 1;
1583a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech      wait:if (ftdi->disconnected > 0) {
1584a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENODEV;
1585a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else if (ftdi->initialized == 0) {
1586a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENODEV;
1587a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else {
1588a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int command_size;
1589a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                down(&ftdi->u132_lock);
1590a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                command_size = ftdi->command_next - ftdi->command_head;
1591a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (command_size < COMMAND_SIZE) {
1592a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        struct u132_target *target = &ftdi->target[ed];
1593a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        struct u132_command *command = &ftdi->command[
1594a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                COMMAND_MASK & ftdi->command_next];
1595a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        int remaining_length = urb->transfer_buffer_length -
1596a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                urb->actual_length;
1597a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->header = 0x82 | (ed << 5);
1598a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if (remaining_length == 0) {
1599a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                command->length = 0x0000;
1600a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else if (remaining_length > 1024) {
1601a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                command->length = 0x8000 | 1023;
1602a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else
1603a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                command->length = 0x8000 | (remaining_length -
1604a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        1);
1605a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->address = (toggle_bits << 6) | (ep_number << 2)
1606a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                | (address << 0);
1607a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->width = usb_maxpacket(urb->dev, urb->pipe,
1608a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                usb_pipeout(urb->pipe));
1609a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->follows = 0;
1610a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->value = 0;
1611a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->buffer = NULL;
1612a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        target->callback = callback;
1613a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        target->endp = endp;
1614a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        target->urb = urb;
1615a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        target->active = 1;
1616a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->command_next += 1;
1617a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi_elan_kick_command_queue(ftdi);
1618a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->u132_lock);
1619a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return 0;
1620a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else {
1621a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->u132_lock);
1622a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        msleep(100);
1623a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        goto wait;
1624a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
1625a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
1626a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
1627a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1628a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechint usb_ftdi_elan_edset_input(struct platform_device *pdev, u8 ed_number,
1629a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
1630a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
1631a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int toggle_bits, int error_count, int condition_code, int repeat_number,
1632a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech         int halted, int skipped, int actual, int non_null))
1633a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
1634a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
1635a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        return ftdi_elan_edset_input(ftdi, ed_number, endp, urb, address,
1636a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ep_number, toggle_bits, callback);
1637a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
1638a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1639a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1640a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechEXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_input);
1641a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_edset_empty(struct usb_ftdi *ftdi, u8 ed_number,
1642a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
1643a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
1644a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int toggle_bits, int error_count, int condition_code, int repeat_number,
1645a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech         int halted, int skipped, int actual, int non_null))
1646a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
1647a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u8 ed = ed_number - 1;
1648a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech      wait:if (ftdi->disconnected > 0) {
1649a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENODEV;
1650a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else if (ftdi->initialized == 0) {
1651a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENODEV;
1652a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else {
1653a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int command_size;
1654a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                down(&ftdi->u132_lock);
1655a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                command_size = ftdi->command_next - ftdi->command_head;
1656a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (command_size < COMMAND_SIZE) {
1657a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        struct u132_target *target = &ftdi->target[ed];
1658a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        struct u132_command *command = &ftdi->command[
1659a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                COMMAND_MASK & ftdi->command_next];
1660a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->header = 0x81 | (ed << 5);
1661a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->length = 0x0000;
1662a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->address = (toggle_bits << 6) | (ep_number << 2)
1663a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                | (address << 0);
1664a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->width = usb_maxpacket(urb->dev, urb->pipe,
1665a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                usb_pipeout(urb->pipe));
1666a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->follows = 0;
1667a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->value = 0;
1668a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->buffer = NULL;
1669a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        target->callback = callback;
1670a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        target->endp = endp;
1671a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        target->urb = urb;
1672a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        target->active = 1;
1673a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->command_next += 1;
1674a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi_elan_kick_command_queue(ftdi);
1675a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->u132_lock);
1676a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return 0;
1677a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else {
1678a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->u132_lock);
1679a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        msleep(100);
1680a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        goto wait;
1681a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
1682a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
1683a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
1684a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1685a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechint usb_ftdi_elan_edset_empty(struct platform_device *pdev, u8 ed_number,
1686a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
1687a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
1688a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int toggle_bits, int error_count, int condition_code, int repeat_number,
1689a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech         int halted, int skipped, int actual, int non_null))
1690a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
1691a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
1692a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        return ftdi_elan_edset_empty(ftdi, ed_number, endp, urb, address,
1693a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ep_number, toggle_bits, callback);
1694a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
1695a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1696a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1697a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechEXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_empty);
1698a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_edset_output(struct usb_ftdi *ftdi, u8 ed_number,
1699a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
1700a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
1701a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int toggle_bits, int error_count, int condition_code, int repeat_number,
1702a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech         int halted, int skipped, int actual, int non_null))
1703a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
1704a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u8 ed = ed_number - 1;
1705a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech      wait:if (ftdi->disconnected > 0) {
1706a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENODEV;
1707a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else if (ftdi->initialized == 0) {
1708a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENODEV;
1709a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else {
1710a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int command_size;
1711a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                down(&ftdi->u132_lock);
1712a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                command_size = ftdi->command_next - ftdi->command_head;
1713a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (command_size < COMMAND_SIZE) {
1714a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        u8 *b;
1715a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        u16 urb_size;
1716a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        int i = 0;
1717a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        char data[30 *3 + 4];
1718a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        char *d = data;
1719a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        int m = (sizeof(data) - 1) / 3;
1720a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        int l = 0;
1721a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        struct u132_target *target = &ftdi->target[ed];
1722a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        struct u132_command *command = &ftdi->command[
1723a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                COMMAND_MASK & ftdi->command_next];
1724a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->header = 0x81 | (ed << 5);
1725a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->address = (toggle_bits << 6) | (ep_number << 2)
1726a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                | (address << 0);
1727a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->width = usb_maxpacket(urb->dev, urb->pipe,
1728a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                usb_pipeout(urb->pipe));
1729a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->follows = min(1024,
1730a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                urb->transfer_buffer_length -
1731a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                urb->actual_length);
1732a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->value = 0;
1733a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->buffer = urb->transfer_buffer +
1734a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                urb->actual_length;
1735a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->length = 0x8000 | (command->follows - 1);
1736a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        b = command->buffer;
1737a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        urb_size = command->follows;
1738a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        data[0] = 0;
1739a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        while (urb_size-- > 0) {
1740a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                if (i > m) {
1741a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                } else if (i++ < m) {
1742a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        int w = sprintf(d, " %02X", *b++);
1743a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        d += w;
1744a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        l += w;
1745a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                } else
1746a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        d += sprintf(d, " ..");
1747a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        }
1748a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        target->callback = callback;
1749a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        target->endp = endp;
1750a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        target->urb = urb;
1751a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        target->active = 1;
1752a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->command_next += 1;
1753a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi_elan_kick_command_queue(ftdi);
1754a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->u132_lock);
1755a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return 0;
1756a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else {
1757a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->u132_lock);
1758a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        msleep(100);
1759a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        goto wait;
1760a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
1761a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
1762a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
1763a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1764a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechint usb_ftdi_elan_edset_output(struct platform_device *pdev, u8 ed_number,
1765a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
1766a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
1767a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int toggle_bits, int error_count, int condition_code, int repeat_number,
1768a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech         int halted, int skipped, int actual, int non_null))
1769a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
1770a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
1771a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        return ftdi_elan_edset_output(ftdi, ed_number, endp, urb, address,
1772a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ep_number, toggle_bits, callback);
1773a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
1774a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1775a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1776a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechEXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_output);
1777a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_edset_single(struct usb_ftdi *ftdi, u8 ed_number,
1778a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
1779a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
1780a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int toggle_bits, int error_count, int condition_code, int repeat_number,
1781a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech         int halted, int skipped, int actual, int non_null))
1782a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
1783a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u8 ed = ed_number - 1;
1784a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech      wait:if (ftdi->disconnected > 0) {
1785a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENODEV;
1786a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else if (ftdi->initialized == 0) {
1787a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENODEV;
1788a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else {
1789a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int command_size;
1790a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                down(&ftdi->u132_lock);
1791a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                command_size = ftdi->command_next - ftdi->command_head;
1792a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (command_size < COMMAND_SIZE) {
1793a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        int remaining_length = urb->transfer_buffer_length -
1794a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                urb->actual_length;
1795a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        struct u132_target *target = &ftdi->target[ed];
1796a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        struct u132_command *command = &ftdi->command[
1797a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                COMMAND_MASK & ftdi->command_next];
1798a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->header = 0x83 | (ed << 5);
1799a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if (remaining_length == 0) {
1800a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                command->length = 0x0000;
1801a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else if (remaining_length > 1024) {
1802a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                command->length = 0x8000 | 1023;
1803a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else
1804a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                command->length = 0x8000 | (remaining_length -
1805a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        1);
1806a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->address = (toggle_bits << 6) | (ep_number << 2)
1807a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                | (address << 0);
1808a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->width = usb_maxpacket(urb->dev, urb->pipe,
1809a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                usb_pipeout(urb->pipe));
1810a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->follows = 0;
1811a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->value = 0;
1812a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        command->buffer = NULL;
1813a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        target->callback = callback;
1814a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        target->endp = endp;
1815a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        target->urb = urb;
1816a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        target->active = 1;
1817a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->command_next += 1;
1818a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi_elan_kick_command_queue(ftdi);
1819a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->u132_lock);
1820a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return 0;
1821a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else {
1822a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->u132_lock);
1823a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        msleep(100);
1824a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        goto wait;
1825a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
1826a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
1827a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
1828a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1829a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechint usb_ftdi_elan_edset_single(struct platform_device *pdev, u8 ed_number,
1830a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
1831a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
1832a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int toggle_bits, int error_count, int condition_code, int repeat_number,
1833a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech         int halted, int skipped, int actual, int non_null))
1834a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
1835a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
1836a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        return ftdi_elan_edset_single(ftdi, ed_number, endp, urb, address,
1837a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ep_number, toggle_bits, callback);
1838a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
1839a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1840a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1841a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechEXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_single);
1842a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_edset_flush(struct usb_ftdi *ftdi, u8 ed_number,
1843a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        void *endp)
1844a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
1845a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u8 ed = ed_number - 1;
1846a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (ftdi->disconnected > 0) {
1847a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENODEV;
1848a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else if (ftdi->initialized == 0) {
1849a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENODEV;
1850a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else {
1851a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                struct u132_target *target = &ftdi->target[ed];
1852a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                down(&ftdi->u132_lock);
1853a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (target->abandoning > 0) {
1854a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->u132_lock);
1855a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return 0;
1856a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else {
1857a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        target->abandoning = 1;
1858a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                      wait_1:if (target->active == 1) {
1859a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                int command_size = ftdi->command_next -
1860a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        ftdi->command_head;
1861a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                if (command_size < COMMAND_SIZE) {
1862a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        struct u132_command *command =
1863a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                &ftdi->command[COMMAND_MASK &
1864a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                ftdi->command_next];
1865a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        command->header = 0x80 | (ed << 5) |
1866a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                0x4;
1867a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        command->length = 0x00;
1868a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        command->address = 0x00;
1869a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        command->width = 0x00;
1870a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        command->follows = 0;
1871a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        command->value = 0;
1872a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        command->buffer = &command->value;
1873a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        ftdi->command_next += 1;
1874a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        ftdi_elan_kick_command_queue(ftdi);
1875a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                } else {
1876a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        up(&ftdi->u132_lock);
1877a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        msleep(100);
1878a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        down(&ftdi->u132_lock);
1879a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        goto wait_1;
1880a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                }
1881a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        }
1882a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        up(&ftdi->u132_lock);
1883a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return 0;
1884a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
1885a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
1886a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
1887a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1888a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechint usb_ftdi_elan_edset_flush(struct platform_device *pdev, u8 ed_number,
1889a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        void *endp)
1890a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
1891a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
1892a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        return ftdi_elan_edset_flush(ftdi, ed_number, endp);
1893a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
1894a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1895a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1896a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechEXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_flush);
1897a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_flush_input_fifo(struct usb_ftdi *ftdi)
1898a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
1899a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int retry_on_empty = 10;
1900a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int retry_on_timeout = 5;
1901a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int retry_on_status = 20;
1902a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech      more:{
1903a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int packet_bytes = 0;
1904a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int retval = usb_bulk_msg(ftdi->udev,
1905a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr),
1906a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                         ftdi->bulk_in_buffer, ftdi->bulk_in_size,
1907a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        &packet_bytes, msecs_to_jiffies(100));
1908a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (packet_bytes > 2) {
1909a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        char diag[30 *3 + 4];
1910a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        char *d = diag;
1911a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        int m = (sizeof(diag) - 1) / 3;
1912a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        char *b = ftdi->bulk_in_buffer;
1913a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        int bytes_read = 0;
1914a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        diag[0] = 0;
1915a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        while (packet_bytes-- > 0) {
1916a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                char c = *b++;
1917a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                if (bytes_read < m) {
1918a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        d += sprintf(d, " %02X",
1919a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                0x000000FF & c);
1920a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                } else if (bytes_read > m) {
1921a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                } else
1922a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        d += sprintf(d, " ..");
1923a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                bytes_read += 1;
1924a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                continue;
1925a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        }
1926a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        goto more;
1927a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else if (packet_bytes > 1) {
1928a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        char s1 = ftdi->bulk_in_buffer[0];
1929a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        char s2 = ftdi->bulk_in_buffer[1];
1930a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if (s1 == 0x31 && s2 == 0x60) {
1931a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                return 0;
1932a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else if (retry_on_status-- > 0) {
1933a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                goto more;
1934a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else {
1935a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                dev_err(&ftdi->udev->dev, "STATUS ERROR retry l"
1936a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        "imit reached\n");
1937a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                return -EFAULT;
1938a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        }
1939a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else if (packet_bytes > 0) {
1940a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        char b1 = ftdi->bulk_in_buffer[0];
1941a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        dev_err(&ftdi->udev->dev, "only one byte flushed from F"
1942a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                "TDI = %02X\n", b1);
1943a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if (retry_on_status-- > 0) {
1944a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                goto more;
1945a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else {
1946a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                dev_err(&ftdi->udev->dev, "STATUS ERROR retry l"
1947a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        "imit reached\n");
1948a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                return -EFAULT;
1949a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        }
1950a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else if (retval == -ETIMEDOUT) {
1951a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if (retry_on_timeout-- > 0) {
1952a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                goto more;
1953a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else {
1954a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                dev_err(&ftdi->udev->dev, "TIMED OUT retry limi"
1955a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        "t reached\n");
1956a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                return -ENOMEM;
1957a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        }
1958a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else if (retval == 0) {
1959a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if (retry_on_empty-- > 0) {
1960a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                goto more;
1961a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else {
1962a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                dev_err(&ftdi->udev->dev, "empty packet retry l"
1963a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        "imit reached\n");
1964a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                return -ENOMEM;
1965a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        }
1966a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else {
1967a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        dev_err(&ftdi->udev->dev, "error = %d\n", retval);
1968a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return retval;
1969a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
1970a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
1971a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        return -1;
1972a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
1973a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1974a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
1975a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/*
1976a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* send the long flush sequence
1977a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*
1978a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/
1979a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_synchronize_flush(struct usb_ftdi *ftdi)
1980a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
1981a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int retval;
1982a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct urb *urb;
1983a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        char *buf;
1984a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int I = 257;
1985a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int i = 0;
1986a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        urb = usb_alloc_urb(0, GFP_KERNEL);
1987a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (!urb) {
1988a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                dev_err(&ftdi->udev->dev, "could not alloc a urb for flush sequ"
1989a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        "ence\n");
1990a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENOMEM;
1991a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
1992a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        buf = usb_buffer_alloc(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma);
1993a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (!buf) {
1994a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                dev_err(&ftdi->udev->dev, "could not get a buffer for flush seq"
1995a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        "uence\n");
1996a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                usb_free_urb(urb);
1997a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENOMEM;
1998a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
1999a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        while (I-- > 0)
2000a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                buf[i++] = 0x55;
2001a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev,
2002a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi->bulk_out_endpointAddr), buf, i,
2003a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi_elan_write_bulk_callback, ftdi);
2004a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
2005a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        retval = usb_submit_urb(urb, GFP_KERNEL);
2006a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (retval) {
2007a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                dev_err(&ftdi->udev->dev, "failed to submit urb containing the "
2008a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        "flush sequence\n");
2009a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                usb_buffer_free(ftdi->udev, i, buf, urb->transfer_dma);
2010a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                usb_free_urb(urb);
2011a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENOMEM;
2012a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
2013a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        usb_free_urb(urb);
2014a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        return 0;
2015a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
2016a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
2017a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
2018a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/*
2019a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* send the reset sequence
2020a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*
2021a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/
2022a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_synchronize_reset(struct usb_ftdi *ftdi)
2023a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
2024a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int retval;
2025a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct urb *urb;
2026a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        char *buf;
2027a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int I = 4;
2028a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int i = 0;
2029a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        urb = usb_alloc_urb(0, GFP_KERNEL);
2030a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (!urb) {
2031a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                dev_err(&ftdi->udev->dev, "could not get a urb for the reset se"
2032a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        "quence\n");
2033a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENOMEM;
2034a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
2035a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        buf = usb_buffer_alloc(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma);
2036a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (!buf) {
2037a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                dev_err(&ftdi->udev->dev, "could not get a buffer for the reset"
2038a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        " sequence\n");
2039a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                usb_free_urb(urb);
2040a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENOMEM;
2041a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
2042a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        buf[i++] = 0x55;
2043a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        buf[i++] = 0xAA;
2044a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        buf[i++] = 0x5A;
2045a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        buf[i++] = 0xA5;
2046a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev,
2047a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi->bulk_out_endpointAddr), buf, i,
2048a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi_elan_write_bulk_callback, ftdi);
2049a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
2050a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        retval = usb_submit_urb(urb, GFP_KERNEL);
2051a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (retval) {
2052a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                dev_err(&ftdi->udev->dev, "failed to submit urb containing the "
2053a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        "reset sequence\n");
2054a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                usb_buffer_free(ftdi->udev, i, buf, urb->transfer_dma);
2055a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                usb_free_urb(urb);
2056a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENOMEM;
2057a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
2058a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        usb_free_urb(urb);
2059a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        return 0;
2060a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
2061a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
2062a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_synchronize(struct usb_ftdi *ftdi)
2063a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
2064a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int retval;
2065a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int long_stop = 10;
2066a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int retry_on_timeout = 5;
2067a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int retry_on_empty = 10;
2068a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int err_count = 0;
2069a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        retval = ftdi_elan_flush_input_fifo(ftdi);
2070a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (retval)
2071a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return retval;
2072a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->bulk_in_left = 0;
2073a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->bulk_in_last = -1;
2074a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        while (long_stop-- > 0) {
2075a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int read_stop;
2076a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int read_stuck;
2077a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                retval = ftdi_elan_synchronize_flush(ftdi);
2078a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (retval)
2079a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return retval;
2080a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                retval = ftdi_elan_flush_input_fifo(ftdi);
2081a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (retval)
2082a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return retval;
2083a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech              reset:retval = ftdi_elan_synchronize_reset(ftdi);
2084a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (retval)
2085a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return retval;
2086a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                read_stop = 100;
2087a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                read_stuck = 10;
2088a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech              read:{
2089a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        int packet_bytes = 0;
2090a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        retval = usb_bulk_msg(ftdi->udev,
2091a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                usb_rcvbulkpipe(ftdi->udev,
2092a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                ftdi->bulk_in_endpointAddr),
2093a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                ftdi->bulk_in_buffer, ftdi->bulk_in_size,
2094a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                &packet_bytes, msecs_to_jiffies(500));
2095a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if (packet_bytes > 2) {
2096a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                char diag[30 *3 + 4];
2097a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                char *d = diag;
2098a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                int m = (sizeof(diag) - 1) / 3;
2099a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                char *b = ftdi->bulk_in_buffer;
2100a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                int bytes_read = 0;
2101a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                unsigned char c = 0;
2102a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                diag[0] = 0;
2103a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                while (packet_bytes-- > 0) {
2104a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        c = *b++;
2105a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        if (bytes_read < m) {
2106a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                d += sprintf(d, " %02X", c);
2107a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        } else if (bytes_read > m) {
2108a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        } else
2109a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                d += sprintf(d, " ..");
2110a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        bytes_read += 1;
2111a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        continue;
2112a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                }
2113a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                if (c == 0x7E) {
2114a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        return 0;
2115a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                } else {
2116a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        if (c == 0x55) {
2117a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                goto read;
2118a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        } else if (read_stop-- > 0) {
2119a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                goto read;
2120a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        } else {
2121a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                dev_err(&ftdi->udev->dev, "retr"
2122a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                        "y limit reached\n");
2123a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                continue;
2124a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        }
2125a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                }
2126a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else if (packet_bytes > 1) {
2127a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                unsigned char s1 = ftdi->bulk_in_buffer[0];
2128a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                unsigned char s2 = ftdi->bulk_in_buffer[1];
2129a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                if (s1 == 0x31 && s2 == 0x00) {
2130a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        if (read_stuck-- > 0) {
2131a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                goto read;
2132a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        } else
2133a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                goto reset;
2134a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                } else if (s1 == 0x31 && s2 == 0x60) {
2135a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        if (read_stop-- > 0) {
2136a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                goto read;
2137a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        } else {
2138a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                dev_err(&ftdi->udev->dev, "retr"
2139a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                        "y limit reached\n");
2140a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                continue;
2141a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        }
2142a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                } else {
2143a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        if (read_stop-- > 0) {
2144a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                goto read;
2145a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        } else {
2146a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                dev_err(&ftdi->udev->dev, "retr"
2147a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                        "y limit reached\n");
2148a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                continue;
2149a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        }
2150a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                }
2151a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else if (packet_bytes > 0) {
2152a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                if (read_stop-- > 0) {
2153a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        goto read;
2154a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                } else {
2155a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        dev_err(&ftdi->udev->dev, "retry limit "
2156a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                "reached\n");
2157a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        continue;
2158a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                }
2159a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else if (retval == -ETIMEDOUT) {
2160a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                if (retry_on_timeout-- > 0) {
2161a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        goto read;
2162a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                } else {
2163a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        dev_err(&ftdi->udev->dev, "TIMED OUT re"
2164a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                "try limit reached\n");
2165a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        continue;
2166a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                }
2167a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else if (retval == 0) {
2168a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                if (retry_on_empty-- > 0) {
2169a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        goto read;
2170a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                } else {
2171a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        dev_err(&ftdi->udev->dev, "empty packet"
2172a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                " retry limit reached\n");
2173a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        continue;
2174a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                }
2175a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else {
2176a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                err_count += 1;
2177a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                dev_err(&ftdi->udev->dev, "error = %d\n",
2178a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        retval);
2179a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                if (read_stop-- > 0) {
2180a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        goto read;
2181a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                } else {
2182a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        dev_err(&ftdi->udev->dev, "retry limit "
2183a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                "reached\n");
2184a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        continue;
2185a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                }
2186a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        }
2187a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
2188a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
2189a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        dev_err(&ftdi->udev->dev, "failed to synchronize\n");
2190a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        return -EFAULT;
2191a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
2192a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
2193a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_stuck_waiting(struct usb_ftdi *ftdi)
2194a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
2195a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int retry_on_empty = 10;
2196a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int retry_on_timeout = 5;
2197a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int retry_on_status = 50;
2198a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech      more:{
2199a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int packet_bytes = 0;
2200a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int retval = usb_bulk_msg(ftdi->udev,
2201a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr),
2202a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                         ftdi->bulk_in_buffer, ftdi->bulk_in_size,
2203a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        &packet_bytes, msecs_to_jiffies(1000));
2204a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (packet_bytes > 2) {
2205a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        char diag[30 *3 + 4];
2206a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        char *d = diag;
2207a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        int m = (sizeof(diag) - 1) / 3;
2208a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        char *b = ftdi->bulk_in_buffer;
2209a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        int bytes_read = 0;
2210a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        diag[0] = 0;
2211a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        while (packet_bytes-- > 0) {
2212a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                char c = *b++;
2213a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                if (bytes_read < m) {
2214a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        d += sprintf(d, " %02X",
2215a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                                0x000000FF & c);
2216a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                } else if (bytes_read > m) {
2217a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                } else
2218a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        d += sprintf(d, " ..");
2219a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                bytes_read += 1;
2220a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                continue;
2221a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        }
2222a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        goto more;
2223a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else if (packet_bytes > 1) {
2224a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        char s1 = ftdi->bulk_in_buffer[0];
2225a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        char s2 = ftdi->bulk_in_buffer[1];
2226a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if (s1 == 0x31 && s2 == 0x60) {
2227a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                return 0;
2228a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else if (retry_on_status-- > 0) {
2229a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                msleep(5);
2230a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                goto more;
2231a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else
2232a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                return -EFAULT;
2233a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else if (packet_bytes > 0) {
2234a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        char b1 = ftdi->bulk_in_buffer[0];
2235a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        dev_err(&ftdi->udev->dev, "only one byte flushed from F"
2236a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                "TDI = %02X\n", b1);
2237a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if (retry_on_status-- > 0) {
2238a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                msleep(5);
2239a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                goto more;
2240a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else {
2241a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                dev_err(&ftdi->udev->dev, "STATUS ERROR retry l"
2242a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        "imit reached\n");
2243a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                return -EFAULT;
2244a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        }
2245a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else if (retval == -ETIMEDOUT) {
2246a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if (retry_on_timeout-- > 0) {
2247a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                goto more;
2248a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else {
2249a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                dev_err(&ftdi->udev->dev, "TIMED OUT retry limi"
2250a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        "t reached\n");
2251a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                return -ENOMEM;
2252a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        }
2253a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else if (retval == 0) {
2254a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if (retry_on_empty-- > 0) {
2255a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                goto more;
2256a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        } else {
2257a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                dev_err(&ftdi->udev->dev, "empty packet retry l"
2258a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        "imit reached\n");
2259a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                return -ENOMEM;
2260a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        }
2261a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else {
2262a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        dev_err(&ftdi->udev->dev, "error = %d\n", retval);
2263a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return -ENOMEM;
2264a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
2265a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
2266a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        return -1;
2267a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
2268a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
2269a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi)
2270a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
2271a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int UxxxStatus = ftdi_elan_read_reg(ftdi, &ftdi->controlreg);
2272a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (UxxxStatus)
2273a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return UxxxStatus;
2274a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (ftdi->controlreg & 0x00400000) {
2275a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (ftdi->card_ejected) {
2276a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else {
2277a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->card_ejected = 1;
2278a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        dev_err(&ftdi->udev->dev, "CARD EJECTED - controlreg = "
2279a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                "%08X\n", ftdi->controlreg);
2280a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
2281a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENODEV;
2282a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else {
2283a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                u8 fn = ftdi->function - 1;
2284a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int activePCIfn = fn << 8;
2285a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                u32 pcidata;
2286a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                u32 pciVID;
2287a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                u32 pciPID;
2288a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int reg = 0;
2289a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
2290a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        &pcidata);
2291a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (UxxxStatus)
2292a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return UxxxStatus;
2293a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                pciVID = pcidata & 0xFFFF;
2294a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                pciPID = (pcidata >> 16) & 0xFFFF;
2295a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (pciVID == ftdi->platform_data.vendor && pciPID ==
2296a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->platform_data.device) {
2297a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return 0;
2298a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else {
2299a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        dev_err(&ftdi->udev->dev, "vendor=%04X pciVID=%04X devi"
2300a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                "ce=%04X pciPID=%04X\n",
2301a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                ftdi->platform_data.vendor, pciVID,
2302a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                ftdi->platform_data.device, pciPID);
2303a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return -ENODEV;
2304a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
2305a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
2306a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
2307a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
23084b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech
23094b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech#define ftdi_read_pcimem(ftdi, member, data) ftdi_elan_read_pcimem(ftdi, \
23104b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        offsetof(struct ohci_regs, member), 0, data);
23114b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech#define ftdi_write_pcimem(ftdi, member, data) ftdi_elan_write_pcimem(ftdi, \
23124b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        offsetof(struct ohci_regs, member), 0, data);
231347f8468e6008a1d62f7dacbcff4ec3e115a500c8David Brownell
23144b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR
23154b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech#define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \
23164b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        OHCI_INTR_WDH)
23174b87361d49c04894458f4d4e80f9669abc894ae1Tony Olechstatic int ftdi_elan_check_controller(struct usb_ftdi *ftdi, int quirk)
23184b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech{
23194b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        int devices = 0;
23204b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        int retval;
23214b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        u32 hc_control;
23224b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        int num_ports;
23234b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        u32 control;
23244b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        u32 rh_a = -1;
23254b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        u32 status;
23264b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        u32 fminterval;
23274b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        u32 hc_fminterval;
23284b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        u32 periodicstart;
23294b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        u32 cmdstatus;
23304b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        u32 roothub_a;
23314b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        int mask = OHCI_INTR_INIT;
23324b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        int sleep_time = 0;
23334b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        int reset_timeout = 30;        /* ... allow extra time */
23344b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        int temp;
23354b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        retval = ftdi_write_pcimem(ftdi, intrdisable, OHCI_INTR_MIE);
23364b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
23374b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;
23384b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        retval = ftdi_read_pcimem(ftdi, control, &control);
23394b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
23404b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;
23414b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        retval = ftdi_read_pcimem(ftdi, roothub.a, &rh_a);
23424b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
23434b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;
23444b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        num_ports = rh_a & RH_A_NDP;
23454b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        retval = ftdi_read_pcimem(ftdi, fminterval, &hc_fminterval);
23464b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
23474b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;
23484b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        hc_fminterval &= 0x3fff;
23494b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (hc_fminterval != FI) {
23504b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        }
23514b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        hc_fminterval |= FSMP(hc_fminterval) << 16;
23524b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        retval = ftdi_read_pcimem(ftdi, control, &hc_control);
23534b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
23544b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;
23554b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        switch (hc_control & OHCI_CTRL_HCFS) {
23564b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        case OHCI_USB_OPER:
23574b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                sleep_time = 0;
23584b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                break;
23594b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        case OHCI_USB_SUSPEND:
23604b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        case OHCI_USB_RESUME:
23614b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                hc_control &= OHCI_CTRL_RWC;
23624b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                hc_control |= OHCI_USB_RESUME;
23634b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                sleep_time = 10;
23644b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                break;
23654b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        default:
23664b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                hc_control &= OHCI_CTRL_RWC;
23674b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                hc_control |= OHCI_USB_RESET;
23684b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                sleep_time = 50;
23694b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                break;
23704b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        }
23714b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        retval = ftdi_write_pcimem(ftdi, control, hc_control);
23724b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
23734b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;
23744b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        retval = ftdi_read_pcimem(ftdi, control, &control);
23754b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
23764b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;
23774b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        msleep(sleep_time);
23784b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a);
23794b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
23804b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;
23814b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (!(roothub_a & RH_A_NPS)) {        /* power down each port */
23824b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                for (temp = 0; temp < num_ports; temp++) {
23834b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        retval = ftdi_write_pcimem(ftdi,
23844b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                                roothub.portstatus[temp], RH_PS_LSDA);
23854b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        if (retval)
23864b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                                return retval;
23874b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                }
23884b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        }
23894b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        retval = ftdi_read_pcimem(ftdi, control, &control);
23904b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
23914b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;
23924b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech      retry:retval = ftdi_read_pcimem(ftdi, cmdstatus, &status);
23934b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
23944b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;
23954b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_HCR);
23964b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
23974b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;
23984b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech      extra:{
23994b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                retval = ftdi_read_pcimem(ftdi, cmdstatus, &status);
24004b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                if (retval)
24014b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        return retval;
24024b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                if (0 != (status & OHCI_HCR)) {
24034b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        if (--reset_timeout == 0) {
24044b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                                dev_err(&ftdi->udev->dev, "USB HC reset timed o"
24054b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                                        "ut!\n");
24064b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                                return -ENODEV;
24074b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        } else {
24084b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                                msleep(5);
24094b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                                goto extra;
24104b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        }
24114b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                }
24124b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        }
24134b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (quirk & OHCI_QUIRK_INITRESET) {
24144b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                retval = ftdi_write_pcimem(ftdi, control, hc_control);
24154b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                if (retval)
24164b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        return retval;
24174b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                retval = ftdi_read_pcimem(ftdi, control, &control);
24184b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                if (retval)
24194b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        return retval;
24204b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        }
24214b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        retval = ftdi_write_pcimem(ftdi, ed_controlhead, 0x00000000);
24224b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
24234b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;
24244b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        retval = ftdi_write_pcimem(ftdi, ed_bulkhead, 0x11000000);
24254b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
24264b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;
24274b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        retval = ftdi_write_pcimem(ftdi, hcca, 0x00000000);
24284b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
24294b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;
24304b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval);
24314b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
24324b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;
24334b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        retval = ftdi_write_pcimem(ftdi, fminterval,
24344b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                ((fminterval & FIT) ^ FIT) | hc_fminterval);
24354b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
24364b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;
24374b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        retval = ftdi_write_pcimem(ftdi, periodicstart,
24384b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                ((9 *hc_fminterval) / 10) & 0x3fff);
24394b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
24404b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;
24414b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval);
24424b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
24434b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;
24444b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        retval = ftdi_read_pcimem(ftdi, periodicstart, &periodicstart);
24454b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
24464b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;
24474b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) {
24484b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                if (!(quirk & OHCI_QUIRK_INITRESET)) {
24494b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        quirk |= OHCI_QUIRK_INITRESET;
24504b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        goto retry;
24514b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                } else
24524b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        dev_err(&ftdi->udev->dev, "init err(%08x %04x)\n",
24534b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                                fminterval, periodicstart);
24544b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        }                        /* start controller operations */
24554b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        hc_control &= OHCI_CTRL_RWC;
24564b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER;
24574b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        retval = ftdi_write_pcimem(ftdi, control, hc_control);
24584b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
24594b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;
24604b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_BLF);
24614b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
24624b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;
24634b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        retval = ftdi_read_pcimem(ftdi, cmdstatus, &cmdstatus);
24644b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
24654b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;
24664b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        retval = ftdi_read_pcimem(ftdi, control, &control);
24674b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
24684b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;
24694b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_DRWE);
24704b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
24714b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;
24724b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        retval = ftdi_write_pcimem(ftdi, intrstatus, mask);
24734b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
24744b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;
24754b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        retval = ftdi_write_pcimem(ftdi, intrdisable,
24764b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO |
24774b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH |
24784b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                OHCI_INTR_SO);
24794b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
24804b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;        /* handle root hub init quirks ... */
24814b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a);
24824b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
24834b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;
24844b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        roothub_a &= ~(RH_A_PSM | RH_A_OCPM);
24854b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (quirk & OHCI_QUIRK_SUPERIO) {
24864b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                roothub_a |= RH_A_NOCP;
24874b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                roothub_a &= ~(RH_A_POTPGT | RH_A_NPS);
24884b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a);
24894b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                if (retval)
24904b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        return retval;
24914b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        } else if ((quirk & OHCI_QUIRK_AMD756) || distrust_firmware) {
24924b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                roothub_a |= RH_A_NPS;
24934b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a);
24944b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                if (retval)
24954b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        return retval;
24964b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        }
24974b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_LPSC);
24984b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
24994b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;
25004b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        retval = ftdi_write_pcimem(ftdi, roothub.b,
25014b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM);
25024b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
25034b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;
25044b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        retval = ftdi_read_pcimem(ftdi, control, &control);
25054b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (retval)
25064b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return retval;
25074b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        mdelay((roothub_a >> 23) & 0x1fe);
25084b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        for (temp = 0; temp < num_ports; temp++) {
25094b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                u32 portstatus;
25104b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                retval = ftdi_read_pcimem(ftdi, roothub.portstatus[temp],
25114b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        &portstatus);
25124b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                if (retval)
25134b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        return retval;
25144b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                if (1 & portstatus)
25154b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        devices += 1;
25164b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        }
25174b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        return devices;
25184b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech}
25194b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech
25204b87361d49c04894458f4d4e80f9669abc894ae1Tony Olechstatic int ftdi_elan_setup_controller(struct usb_ftdi *ftdi, int fn)
2521a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
2522a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u32 latence_timer;
2523a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int UxxxStatus;
2524a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u32 pcidata;
2525a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int reg = 0;
25264b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        int activePCIfn = fn << 8;
25274b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800);
2528a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (UxxxStatus)
2529a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return UxxxStatus;
25304b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        reg = 16;
25314b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0,
25324b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                0xFFFFFFFF);
2533a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (UxxxStatus)
2534a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return UxxxStatus;
25354b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
25364b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                &pcidata);
2537a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (UxxxStatus)
2538a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return UxxxStatus;
25394b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0,
25404b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                0xF0000000);
2541a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (UxxxStatus)
2542a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return UxxxStatus;
25434b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
25444b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                &pcidata);
2545a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (UxxxStatus)
2546a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return UxxxStatus;
25474b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        reg = 12;
25484b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
25494b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                &latence_timer);
2550a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (UxxxStatus)
2551a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return UxxxStatus;
25524b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        latence_timer &= 0xFFFF00FF;
25534b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        latence_timer |= 0x00001600;
25544b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00,
25554b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                latence_timer);
2556a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (UxxxStatus)
2557a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return UxxxStatus;
25584b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
25594b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                &pcidata);
2560a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (UxxxStatus)
2561a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return UxxxStatus;
25624b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        reg = 4;
25634b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00,
25644b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                0x06);
2565a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (UxxxStatus)
2566a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return UxxxStatus;
25674b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
25684b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                &pcidata);
2569a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (UxxxStatus)
2570a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return UxxxStatus;
25714b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        for (reg = 0; reg <= 0x54; reg += 4) {
25724b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                UxxxStatus = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
2573a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (UxxxStatus)
2574a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return UxxxStatus;
2575a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
25764b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        return 0;
25774b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech}
25784b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech
25794b87361d49c04894458f4d4e80f9669abc894ae1Tony Olechstatic int ftdi_elan_close_controller(struct usb_ftdi *ftdi, int fn)
25804b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech{
25814b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        u32 latence_timer;
25824b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        int UxxxStatus;
25834b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        u32 pcidata;
25844b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        int reg = 0;
25854b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        int activePCIfn = fn << 8;
2586a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800);
2587a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (UxxxStatus)
2588a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return UxxxStatus;
2589a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        reg = 16;
2590a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0,
2591a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                0xFFFFFFFF);
2592a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (UxxxStatus)
2593a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return UxxxStatus;
2594a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
2595a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                &pcidata);
2596a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (UxxxStatus)
2597a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return UxxxStatus;
2598a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0,
25994b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                0x00000000);
2600a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (UxxxStatus)
2601a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return UxxxStatus;
2602a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
2603a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                &pcidata);
2604a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (UxxxStatus)
2605a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return UxxxStatus;
2606a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        reg = 12;
2607a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
2608a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                &latence_timer);
2609a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (UxxxStatus)
2610a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return UxxxStatus;
2611a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        latence_timer &= 0xFFFF00FF;
2612a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        latence_timer |= 0x00001600;
2613a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00,
2614a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                latence_timer);
2615a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (UxxxStatus)
2616a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return UxxxStatus;
2617a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
2618a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                &pcidata);
2619a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (UxxxStatus)
2620a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return UxxxStatus;
2621a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        reg = 4;
2622a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00,
26234b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                0x00);
2624a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (UxxxStatus)
2625a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return UxxxStatus;
2626a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
2627a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                &pcidata);
2628a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (UxxxStatus)
2629a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return UxxxStatus;
2630a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        return 0;
2631a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
2632a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
26334b87361d49c04894458f4d4e80f9669abc894ae1Tony Olechstatic int ftdi_elan_found_controller(struct usb_ftdi *ftdi, int fn, int quirk)
26344b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech{
26354b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        int result;
26364b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        int UxxxStatus;
26374b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        UxxxStatus = ftdi_elan_setup_controller(ftdi, fn);
26384b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (UxxxStatus)
26394b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return UxxxStatus;
26404b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        result = ftdi_elan_check_controller(ftdi, quirk);
26414b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        UxxxStatus = ftdi_elan_close_controller(ftdi, fn);
26424b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (UxxxStatus)
26434b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return UxxxStatus;
26444b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        return result;
26454b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech}
26464b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech
26474b87361d49c04894458f4d4e80f9669abc894ae1Tony Olechstatic int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi)
26484b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech{
26494b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        u32 controlreg;
26504b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        u8 sensebits;
26514b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        int UxxxStatus;
26524b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
26534b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (UxxxStatus)
26544b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return UxxxStatus;
26554b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000000L);
26564b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (UxxxStatus)
26574b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return UxxxStatus;
26584b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        msleep(750);
26594b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x100);
26604b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (UxxxStatus)
26614b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return UxxxStatus;
26624b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x500);
26634b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (UxxxStatus)
26644b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return UxxxStatus;
26654b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
26664b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (UxxxStatus)
26674b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return UxxxStatus;
26684b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020CL | 0x000);
26694b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (UxxxStatus)
26704b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return UxxxStatus;
26714b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020DL | 0x000);
26724b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (UxxxStatus)
26734b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return UxxxStatus;
26744b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        msleep(250);
26754b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020FL | 0x000);
26764b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (UxxxStatus)
26774b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return UxxxStatus;
26784b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
26794b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (UxxxStatus)
26804b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return UxxxStatus;
26814b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x800);
26824b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (UxxxStatus)
26834b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return UxxxStatus;
26844b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
26854b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (UxxxStatus)
26864b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return UxxxStatus;
26874b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
26884b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (UxxxStatus)
26894b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return UxxxStatus;
26904b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        msleep(1000);
26914b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        sensebits = (controlreg >> 16) & 0x000F;
26924b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (0x0D == sensebits)
26934b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return 0;
26944b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        else
26954b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech		return - ENXIO;
26964b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech}
26974b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech
2698a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi)
2699a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
27004b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        int UxxxStatus;
2701a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        u32 pcidata;
27024b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        int reg = 0;
27034b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        u8 fn;
27044b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        int activePCIfn = 0;
27054b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        int max_devices = 0;
27064b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        int controllers = 0;
27074b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        int unrecognized = 0;
27084b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        ftdi->function = 0;
27094b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        for (fn = 0; (fn < 4); fn++) {
27104b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                u32 pciVID = 0;
27114b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                u32 pciPID = 0;
27124b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                int devices = 0;
27134b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                activePCIfn = fn << 8;
27144b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
27154b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        &pcidata);
27164b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                if (UxxxStatus)
27174b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        return UxxxStatus;
27184b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                pciVID = pcidata & 0xFFFF;
27194b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                pciPID = (pcidata >> 16) & 0xFFFF;
27204b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                if ((pciVID == PCI_VENDOR_ID_OPTI) && (pciPID == 0xc861)) {
27214b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        devices = ftdi_elan_found_controller(ftdi, fn, 0);
27224b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        controllers += 1;
27234b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                } else if ((pciVID == PCI_VENDOR_ID_NEC) && (pciPID == 0x0035))
27244b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        {
27254b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        devices = ftdi_elan_found_controller(ftdi, fn, 0);
27264b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        controllers += 1;
27274b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                } else if ((pciVID == PCI_VENDOR_ID_AL) && (pciPID == 0x5237)) {
27284b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        devices = ftdi_elan_found_controller(ftdi, fn, 0);
27294b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        controllers += 1;
27304b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                } else if ((pciVID == PCI_VENDOR_ID_ATT) && (pciPID == 0x5802))
27314b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        {
27324b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        devices = ftdi_elan_found_controller(ftdi, fn, 0);
27334b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        controllers += 1;
27344b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                } else if (pciVID == PCI_VENDOR_ID_AMD && pciPID == 0x740c) {
27354b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        devices = ftdi_elan_found_controller(ftdi, fn,
27364b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                                OHCI_QUIRK_AMD756);
27374b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        controllers += 1;
27384b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                } else if (pciVID == PCI_VENDOR_ID_COMPAQ && pciPID == 0xa0f8) {
27394b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        devices = ftdi_elan_found_controller(ftdi, fn,
27404b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                                OHCI_QUIRK_ZFMICRO);
27414b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        controllers += 1;
27424b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                } else if (0 == pcidata) {
27434b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                } else
27444b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        unrecognized += 1;
27454b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                if (devices > max_devices) {
27464b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        max_devices = devices;
27474b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        ftdi->function = fn + 1;
27484b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        ftdi->platform_data.vendor = pciVID;
27494b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        ftdi->platform_data.device = pciPID;
2750a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
2751a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
27524b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        if (ftdi->function > 0) {
27534b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                UxxxStatus = ftdi_elan_setup_controller(ftdi,
27544b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        ftdi->function - 1);
27554b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                if (UxxxStatus)
27564b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        return UxxxStatus;
27574b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return 0;
27584b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        } else if (controllers > 0) {
27594b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return -ENXIO;
27604b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        } else if (unrecognized > 0) {
27614b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return -ENXIO;
27624b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech        } else {
27634b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                ftdi->enumerated = 0;
27644b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                return -ENXIO;
2765a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
2766a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
2767a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
2768a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
2769a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/*
2770a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* we use only the first bulk-in and bulk-out endpoints
2771a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/
2772a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_probe(struct usb_interface *interface,
2773a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        const struct usb_device_id *id)
2774a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
2775a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct usb_host_interface *iface_desc;
2776a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct usb_endpoint_descriptor *endpoint;
2777a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        size_t buffer_size;
2778a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int i;
2779a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int retval = -ENOMEM;
2780a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct usb_ftdi *ftdi = kmalloc(sizeof(struct usb_ftdi), GFP_KERNEL);
2781a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (ftdi == NULL) {
2782a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                printk(KERN_ERR "Out of memory\n");
2783a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return -ENOMEM;
2784a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
2785a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        memset(ftdi, 0x00, sizeof(struct usb_ftdi));
2786eb33caec1ed29fa2b04a2c5f02e3fed2add91db4Matthias Kaehlcke        mutex_lock(&ftdi_module_lock);
2787a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        list_add_tail(&ftdi->ftdi_list, &ftdi_static_list);
2788a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->sequence_num = ++ftdi_instances;
2789eb33caec1ed29fa2b04a2c5f02e3fed2add91db4Matthias Kaehlcke        mutex_unlock(&ftdi_module_lock);
2790a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi_elan_init_kref(ftdi);
2791a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        init_MUTEX(&ftdi->sw_lock);
2792a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->udev = usb_get_dev(interface_to_usbdev(interface));
2793a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->interface = interface;
2794a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        init_MUTEX(&ftdi->u132_lock);
2795a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->expected = 4;
2796a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        iface_desc = interface->cur_altsetting;
2797a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
2798a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                endpoint = &iface_desc->endpoint[i].desc;
2799a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (!ftdi->bulk_in_endpointAddr &&
28002ae7745beac6de54a47ed19fe441f1d45aa96172Luiz Fernando N. Capitulino		    usb_endpoint_is_bulk_in(endpoint)) {
2801a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
2802a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->bulk_in_size = buffer_size;
2803a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->bulk_in_endpointAddr = endpoint->bEndpointAddress;
2804a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
2805a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        if (!ftdi->bulk_in_buffer) {
2806a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                dev_err(&ftdi->udev->dev, "Could not allocate b"
2807a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                        "ulk_in_buffer\n");
2808a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                retval = -ENOMEM;
2809a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                goto error;
2810a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        }
2811a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
2812a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (!ftdi->bulk_out_endpointAddr &&
28132ae7745beac6de54a47ed19fe441f1d45aa96172Luiz Fernando N. Capitulino		    usb_endpoint_is_bulk_out(endpoint)) {
2814a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->bulk_out_endpointAddr =
2815a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                endpoint->bEndpointAddress;
2816a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
2817a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
2818a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (!(ftdi->bulk_in_endpointAddr && ftdi->bulk_out_endpointAddr)) {
2819a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                dev_err(&ftdi->udev->dev, "Could not find both bulk-in and bulk"
2820a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        "-out endpoints\n");
2821a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                retval = -ENODEV;
2822a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                goto error;
2823a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
2824a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        dev_info(&ftdi->udev->dev, "interface %d has I=%02X O=%02X\n",
2825a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                iface_desc->desc.bInterfaceNumber, ftdi->bulk_in_endpointAddr,
2826a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi->bulk_out_endpointAddr);
2827a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        usb_set_intfdata(interface, ftdi);
2828a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (iface_desc->desc.bInterfaceNumber == 0 &&
2829a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi->bulk_in_endpointAddr == 0x81 &&
2830a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi->bulk_out_endpointAddr == 0x02) {
2831a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                retval = usb_register_dev(interface, &ftdi_elan_jtag_class);
2832a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (retval) {
2833a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        dev_err(&ftdi->udev->dev, "Not able to get a minor for "
2834a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                "this device.\n");
2835a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        usb_set_intfdata(interface, NULL);
2836a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        retval = -ENOMEM;
2837a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        goto error;
2838a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                } else {
2839a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->class = &ftdi_elan_jtag_class;
2840a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        dev_info(&ftdi->udev->dev, "USB FDTI=%p JTAG interface "
2841a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                "%d now attached to ftdi%d\n", ftdi,
2842a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                iface_desc->desc.bInterfaceNumber,
2843a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                                interface->minor);
2844a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        return 0;
2845a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
2846a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else if (iface_desc->desc.bInterfaceNumber == 1 &&
2847a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi->bulk_in_endpointAddr == 0x83 &&
2848a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi->bulk_out_endpointAddr == 0x04) {
2849a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi->class = NULL;
2850a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                dev_info(&ftdi->udev->dev, "USB FDTI=%p ELAN interface %d now a"
2851a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        "ctivated\n", ftdi, iface_desc->desc.bInterfaceNumber);
2852c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells                INIT_DELAYED_WORK(&ftdi->status_work, ftdi_elan_status_work);
2853c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells                INIT_DELAYED_WORK(&ftdi->command_work, ftdi_elan_command_work);
2854c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells                INIT_DELAYED_WORK(&ftdi->respond_work, ftdi_elan_respond_work);
2855a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi_status_queue_work(ftdi, msecs_to_jiffies(3 *1000));
2856a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                return 0;
2857a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else {
2858a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                dev_err(&ftdi->udev->dev,
2859a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        "Could not find ELAN's U132 device\n");
2860a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                retval = -ENODEV;
2861a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                goto error;
2862a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
2863a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech      error:if (ftdi) {
2864a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi_elan_put_kref(ftdi);
2865a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
2866a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        return retval;
2867a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
2868a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
2869a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_disconnect(struct usb_interface *interface)
2870a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
2871a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct usb_ftdi *ftdi = usb_get_intfdata(interface);
2872a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi->disconnected += 1;
2873a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        if (ftdi->class) {
2874a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                int minor = interface->minor;
2875a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                struct usb_class_driver *class = ftdi->class;
2876a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                usb_set_intfdata(interface, NULL);
2877a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                usb_deregister_dev(interface, class);
2878a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                dev_info(&ftdi->udev->dev, "USB FTDI U132 jtag interface on min"
2879a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        "or %d now disconnected\n", minor);
2880a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } else {
2881a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi_status_cancel_work(ftdi);
2882a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi_command_cancel_work(ftdi);
2883a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi_response_cancel_work(ftdi);
2884a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi_elan_abandon_completions(ftdi);
2885a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi_elan_abandon_targets(ftdi);
2886a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                if (ftdi->registered) {
2887a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        platform_device_unregister(&ftdi->platform_dev);
2888a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->synchronized = 0;
2889a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->enumerated = 0;
28904b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech                        ftdi->initialized = 0;
2891a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        ftdi->registered = 0;
2892a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                }
2893a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                flush_workqueue(status_queue);
2894a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                flush_workqueue(command_queue);
2895a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                flush_workqueue(respond_queue);
2896a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi->disconnected += 1;
2897a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                usb_set_intfdata(interface, NULL);
2898a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                dev_info(&ftdi->udev->dev, "USB FTDI U132 host controller inter"
2899a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                        "face now disconnected\n");
2900a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        }
2901a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        ftdi_elan_put_kref(ftdi);
2902a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
2903a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
2904a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic struct usb_driver ftdi_elan_driver = {
2905a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        .name = "ftdi-elan",
2906a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        .probe = ftdi_elan_probe,
2907a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        .disconnect = ftdi_elan_disconnect,
2908a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        .id_table = ftdi_elan_table,
2909a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech};
2910a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int __init ftdi_elan_init(void)
2911a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
2912a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        int result;
2913a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        printk(KERN_INFO "driver %s built at %s on %s\n", ftdi_elan_driver.name,
2914ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov	       __TIME__, __DATE__);
2915eb33caec1ed29fa2b04a2c5f02e3fed2add91db4Matthias Kaehlcke        mutex_init(&ftdi_module_lock);
2916a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        INIT_LIST_HEAD(&ftdi_static_list);
2917a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        status_queue = create_singlethread_workqueue("ftdi-status-control");
2918ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov	if (!status_queue)
2919893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov		goto err_status_queue;
2920a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        command_queue = create_singlethread_workqueue("ftdi-command-engine");
2921ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov	if (!command_queue)
2922893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov		goto err_command_queue;
2923a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        respond_queue = create_singlethread_workqueue("ftdi-respond-engine");
2924ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov	if (!respond_queue)
2925893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov		goto err_respond_queue;
2926a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        result = usb_register(&ftdi_elan_driver);
2927893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov        if (result) {
2928893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov		destroy_workqueue(status_queue);
2929893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov		destroy_workqueue(command_queue);
2930893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov		destroy_workqueue(respond_queue);
2931a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                printk(KERN_ERR "usb_register failed. Error number %d\n",
2932ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov		       result);
2933893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov	}
2934a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        return result;
2935ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov
2936893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov err_respond_queue:
2937ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov	destroy_workqueue(command_queue);
2938893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov err_command_queue:
2939ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov	destroy_workqueue(status_queue);
2940893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov err_status_queue:
2941ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov	printk(KERN_ERR "%s couldn't create workqueue\n", ftdi_elan_driver.name);
2942ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov	return -ENOMEM;
2943a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
2944a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
2945a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void __exit ftdi_elan_exit(void)
2946a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{
2947a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct usb_ftdi *ftdi;
2948a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        struct usb_ftdi *temp;
2949a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        usb_deregister(&ftdi_elan_driver);
2950a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        printk(KERN_INFO "ftdi_u132 driver deregistered\n");
2951a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        list_for_each_entry_safe(ftdi, temp, &ftdi_static_list, ftdi_list) {
2952a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi_status_cancel_work(ftdi);
2953a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi_command_cancel_work(ftdi);
2954a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech                ftdi_response_cancel_work(ftdi);
2955a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        } flush_workqueue(status_queue);
2956a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        destroy_workqueue(status_queue);
2957a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        status_queue = NULL;
2958a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        flush_workqueue(command_queue);
2959a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        destroy_workqueue(command_queue);
2960a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        command_queue = NULL;
2961a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        flush_workqueue(respond_queue);
2962a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        destroy_workqueue(respond_queue);
2963a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech        respond_queue = NULL;
2964a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}
2965a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
2966a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech
2967a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechmodule_init(ftdi_elan_init);
2968a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechmodule_exit(ftdi_elan_exit);
2969