ftdi-elan.c revision c93d46509e7aee7d58680c4c8a12cfbe98df98cb
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; 150c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke struct mutex 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{ 333c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&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); 340c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke } mutex_unlock(&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; 346c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&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; 351c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 352a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_do_callback(ftdi, target, NULL, 0); 353c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&ftdi->u132_lock); 354a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 355a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 356a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->recieved = 0; 357a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->expected = 4; 358a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->ed_found = 0; 359c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&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; 365c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&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 { 385c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 386a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 387c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&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 { 407c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 408a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 409c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&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; 417c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&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; 423c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&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 { 443c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 444a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 445c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&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; 453c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&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; 889c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&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; 896c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&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; 906c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&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; 912c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&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; 922c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 923a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return b; 924a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 925a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (ed_type == 0x01) { 926a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->abandoning = 0; 927c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&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; 936c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&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{ 950c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&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; 955c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&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; 1281c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&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); 1295c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1296a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1297a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1298c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&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; 1313c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&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); 1327c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1328a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1329a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1330c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&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; 1345c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&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); 1359c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1360a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1361a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1362c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&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; 1385c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&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); 1408c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1409a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait_for_completion(&respond->wait_completion); 1410a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return result; 1411a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1412c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&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; 1428c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&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); 1452c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1453a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait_for_completion(&respond->wait_completion); 1454a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return result; 1455a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1456c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&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; 1472c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&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); 1496c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1497a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait_for_completion(&respond->wait_completion); 1498a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return result; 1499a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1500c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&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; 1532c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&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); 1553c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1554a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1555a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1556c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&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; 1589c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&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); 1618c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1619a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1620a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1621c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&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; 1654c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&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); 1675c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1676a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1677a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1678c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&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; 1711c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&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); 1754c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1755a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1756a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1757c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&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; 1790c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&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); 1819c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1820a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1821a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1822c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&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]; 1852c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&ftdi->u132_lock); 1853a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (target->abandoning > 0) { 1854c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&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 { 1876c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1877a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 1878c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&ftdi->u132_lock); 1879a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto wait_1; 1880a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1881a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1882c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&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; 27805280d6083a77cc06a8c8360a2c461fd12d780fb8Mariusz Kozlowski struct usb_ftdi *ftdi; 27815280d6083a77cc06a8c8360a2c461fd12d780fb8Mariusz Kozlowski 27825280d6083a77cc06a8c8360a2c461fd12d780fb8Mariusz Kozlowski ftdi = kzalloc(sizeof(struct usb_ftdi), GFP_KERNEL); 27835280d6083a77cc06a8c8360a2c461fd12d780fb8Mariusz Kozlowski if (!ftdi) { 2784a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech printk(KERN_ERR "Out of memory\n"); 2785a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 2786a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 27875280d6083a77cc06a8c8360a2c461fd12d780fb8Mariusz Kozlowski 2788eb33caec1ed29fa2b04a2c5f02e3fed2add91db4Matthias Kaehlcke mutex_lock(&ftdi_module_lock); 2789a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech list_add_tail(&ftdi->ftdi_list, &ftdi_static_list); 2790a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->sequence_num = ++ftdi_instances; 2791eb33caec1ed29fa2b04a2c5f02e3fed2add91db4Matthias Kaehlcke mutex_unlock(&ftdi_module_lock); 2792a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_init_kref(ftdi); 2793a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech init_MUTEX(&ftdi->sw_lock); 2794a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->udev = usb_get_dev(interface_to_usbdev(interface)); 2795a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->interface = interface; 2796c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_init(&ftdi->u132_lock); 2797a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->expected = 4; 2798a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech iface_desc = interface->cur_altsetting; 2799a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { 2800a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech endpoint = &iface_desc->endpoint[i].desc; 2801a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!ftdi->bulk_in_endpointAddr && 28022ae7745beac6de54a47ed19fe441f1d45aa96172Luiz Fernando N. Capitulino usb_endpoint_is_bulk_in(endpoint)) { 2803a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); 2804a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_size = buffer_size; 2805a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_endpointAddr = endpoint->bEndpointAddress; 2806a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); 2807a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!ftdi->bulk_in_buffer) { 2808a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "Could not allocate b" 2809a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "ulk_in_buffer\n"); 2810a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = -ENOMEM; 2811a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto error; 2812a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2813a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2814a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!ftdi->bulk_out_endpointAddr && 28152ae7745beac6de54a47ed19fe441f1d45aa96172Luiz Fernando N. Capitulino usb_endpoint_is_bulk_out(endpoint)) { 2816a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_out_endpointAddr = 2817a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech endpoint->bEndpointAddress; 2818a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2819a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2820a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!(ftdi->bulk_in_endpointAddr && ftdi->bulk_out_endpointAddr)) { 2821a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "Could not find both bulk-in and bulk" 2822a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "-out endpoints\n"); 2823a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = -ENODEV; 2824a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto error; 2825a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2826a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_info(&ftdi->udev->dev, "interface %d has I=%02X O=%02X\n", 2827a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech iface_desc->desc.bInterfaceNumber, ftdi->bulk_in_endpointAddr, 2828a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_out_endpointAddr); 2829a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_set_intfdata(interface, ftdi); 2830a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (iface_desc->desc.bInterfaceNumber == 0 && 2831a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_endpointAddr == 0x81 && 2832a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_out_endpointAddr == 0x02) { 2833a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = usb_register_dev(interface, &ftdi_elan_jtag_class); 2834a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retval) { 2835a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "Not able to get a minor for " 2836a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "this device.\n"); 2837a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_set_intfdata(interface, NULL); 2838a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = -ENOMEM; 2839a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto error; 2840a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2841a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->class = &ftdi_elan_jtag_class; 2842a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_info(&ftdi->udev->dev, "USB FDTI=%p JTAG interface " 2843a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "%d now attached to ftdi%d\n", ftdi, 2844a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech iface_desc->desc.bInterfaceNumber, 2845a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech interface->minor); 2846a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 2847a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2848a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (iface_desc->desc.bInterfaceNumber == 1 && 2849a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_endpointAddr == 0x83 && 2850a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_out_endpointAddr == 0x04) { 2851a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->class = NULL; 2852a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_info(&ftdi->udev->dev, "USB FDTI=%p ELAN interface %d now a" 2853a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "ctivated\n", ftdi, iface_desc->desc.bInterfaceNumber); 2854c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells INIT_DELAYED_WORK(&ftdi->status_work, ftdi_elan_status_work); 2855c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells INIT_DELAYED_WORK(&ftdi->command_work, ftdi_elan_command_work); 2856c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells INIT_DELAYED_WORK(&ftdi->respond_work, ftdi_elan_respond_work); 2857a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_status_queue_work(ftdi, msecs_to_jiffies(3 *1000)); 2858a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 2859a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2860a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, 2861a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "Could not find ELAN's U132 device\n"); 2862a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = -ENODEV; 2863a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto error; 2864a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2865a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech error:if (ftdi) { 2866a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_put_kref(ftdi); 2867a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2868a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return retval; 2869a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 2870a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 2871a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_disconnect(struct usb_interface *interface) 2872a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 2873a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = usb_get_intfdata(interface); 2874a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->disconnected += 1; 2875a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi->class) { 2876a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int minor = interface->minor; 2877a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_class_driver *class = ftdi->class; 2878a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_set_intfdata(interface, NULL); 2879a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_deregister_dev(interface, class); 2880a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_info(&ftdi->udev->dev, "USB FTDI U132 jtag interface on min" 2881a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "or %d now disconnected\n", minor); 2882a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2883a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_status_cancel_work(ftdi); 2884a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_command_cancel_work(ftdi); 2885a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_response_cancel_work(ftdi); 2886a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_abandon_completions(ftdi); 2887a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_abandon_targets(ftdi); 2888a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi->registered) { 2889a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech platform_device_unregister(&ftdi->platform_dev); 2890a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->synchronized = 0; 2891a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->enumerated = 0; 28924b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech ftdi->initialized = 0; 2893a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->registered = 0; 2894a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2895a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech flush_workqueue(status_queue); 2896a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech flush_workqueue(command_queue); 2897a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech flush_workqueue(respond_queue); 2898a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->disconnected += 1; 2899a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_set_intfdata(interface, NULL); 2900a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_info(&ftdi->udev->dev, "USB FTDI U132 host controller inter" 2901a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "face now disconnected\n"); 2902a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2903a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_put_kref(ftdi); 2904a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 2905a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 2906a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic struct usb_driver ftdi_elan_driver = { 2907a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .name = "ftdi-elan", 2908a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .probe = ftdi_elan_probe, 2909a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .disconnect = ftdi_elan_disconnect, 2910a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .id_table = ftdi_elan_table, 2911a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}; 2912a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int __init ftdi_elan_init(void) 2913a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 2914a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int result; 2915a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech printk(KERN_INFO "driver %s built at %s on %s\n", ftdi_elan_driver.name, 2916ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov __TIME__, __DATE__); 2917eb33caec1ed29fa2b04a2c5f02e3fed2add91db4Matthias Kaehlcke mutex_init(&ftdi_module_lock); 2918a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech INIT_LIST_HEAD(&ftdi_static_list); 2919a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech status_queue = create_singlethread_workqueue("ftdi-status-control"); 2920ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov if (!status_queue) 2921893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov goto err_status_queue; 2922a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_queue = create_singlethread_workqueue("ftdi-command-engine"); 2923ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov if (!command_queue) 2924893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov goto err_command_queue; 2925a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond_queue = create_singlethread_workqueue("ftdi-respond-engine"); 2926ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov if (!respond_queue) 2927893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov goto err_respond_queue; 2928a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech result = usb_register(&ftdi_elan_driver); 2929893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov if (result) { 2930893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov destroy_workqueue(status_queue); 2931893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov destroy_workqueue(command_queue); 2932893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov destroy_workqueue(respond_queue); 2933a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech printk(KERN_ERR "usb_register failed. Error number %d\n", 2934ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov result); 2935893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov } 2936a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return result; 2937ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov 2938893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov err_respond_queue: 2939ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov destroy_workqueue(command_queue); 2940893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov err_command_queue: 2941ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov destroy_workqueue(status_queue); 2942893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov err_status_queue: 2943ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov printk(KERN_ERR "%s couldn't create workqueue\n", ftdi_elan_driver.name); 2944ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov return -ENOMEM; 2945a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 2946a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 2947a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void __exit ftdi_elan_exit(void) 2948a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 2949a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi; 2950a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *temp; 2951a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_deregister(&ftdi_elan_driver); 2952a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech printk(KERN_INFO "ftdi_u132 driver deregistered\n"); 2953a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech list_for_each_entry_safe(ftdi, temp, &ftdi_static_list, ftdi_list) { 2954a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_status_cancel_work(ftdi); 2955a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_command_cancel_work(ftdi); 2956a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_response_cancel_work(ftdi); 2957a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } flush_workqueue(status_queue); 2958a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech destroy_workqueue(status_queue); 2959a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech status_queue = NULL; 2960a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech flush_workqueue(command_queue); 2961a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech destroy_workqueue(command_queue); 2962a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_queue = NULL; 2963a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech flush_workqueue(respond_queue); 2964a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech destroy_workqueue(respond_queue); 2965a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond_queue = NULL; 2966a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 2967a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 2968a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 2969a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechmodule_init(ftdi_elan_init); 2970a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechmodule_exit(ftdi_elan_exit); 2971