ftdi-elan.c revision 33b9e16243fd69493be3ddda7be73226c8be586a
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*/ 8933b9e16243fd69493be3ddda7be73226c8be586aNémeth Mártonstatic const 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/* 660a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* 661a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* blocking bulk reads are used to get data from the device 662a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* 663a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/ 664a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic ssize_t ftdi_elan_read(struct file *file, char __user *buffer, 665a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech size_t count, loff_t *ppos) 666a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 667a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char data[30 *3 + 4]; 668a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *d = data; 669a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int m = (sizeof(data) - 1) / 3; 670a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int bytes_read = 0; 671a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retry_on_empty = 10; 672a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retry_on_timeout = 5; 673a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = (struct usb_ftdi *)file->private_data; 674a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi->disconnected > 0) { 675a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 676a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 677a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech data[0] = 0; 678a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech have:if (ftdi->bulk_in_left > 0) { 679a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (count-- > 0) { 680a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *p = ++ftdi->bulk_in_last + ftdi->bulk_in_buffer; 681a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_left -= 1; 682a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (bytes_read < m) { 683a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " %02X", 0x000000FF & *p); 684a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (bytes_read > m) { 685a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 686a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " .."); 687a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (copy_to_user(buffer++, p, 1)) { 688a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -EFAULT; 689a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 690a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech bytes_read += 1; 691a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto have; 692a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 693a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 694a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return bytes_read; 695a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 696a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech more:if (count > 0) { 697a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int packet_bytes = 0; 698a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retval = usb_bulk_msg(ftdi->udev, 699a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), 700a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_buffer, ftdi->bulk_in_size, 701c0f082c5367a02e8493d779e16ad336167e14718Sarah Sharp &packet_bytes, 50); 702a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (packet_bytes > 2) { 703a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_left = packet_bytes - 2; 704a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_last = 1; 705a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto have; 706a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retval == -ETIMEDOUT) { 707a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_timeout-- > 0) { 708a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 709a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (bytes_read > 0) { 710a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return bytes_read; 711a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 712a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return retval; 713a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retval == 0) { 714a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_empty-- > 0) { 715a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 716a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 717a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return bytes_read; 718a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 719a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return retval; 720a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 721a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return bytes_read; 722a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 723a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 7247d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void ftdi_elan_write_bulk_callback(struct urb *urb) 725a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 726cdc97792289179974af6dda781c855696358d307Ming Lei struct usb_ftdi *ftdi = urb->context; 72784346269f9a05e66ff2973916776a080d566f9abGreg Kroah-Hartman int status = urb->status; 72884346269f9a05e66ff2973916776a080d566f9abGreg Kroah-Hartman 72984346269f9a05e66ff2973916776a080d566f9abGreg Kroah-Hartman if (status && !(status == -ENOENT || status == -ECONNRESET || 73084346269f9a05e66ff2973916776a080d566f9abGreg Kroah-Hartman status == -ESHUTDOWN)) { 731a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "urb=%p write bulk status received: %" 73284346269f9a05e66ff2973916776a080d566f9abGreg Kroah-Hartman "d\n", urb, status); 733a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 734a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_buffer_free(urb->dev, urb->transfer_buffer_length, 735a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb->transfer_buffer, urb->transfer_dma); 736a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 737a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 738a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int fill_buffer_with_all_queued_commands(struct usb_ftdi *ftdi, 739a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *buf, int command_size, int total_size) 740a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 741a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int ed_commands = 0; 742a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int b = 0; 743a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int I = command_size; 744a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int i = ftdi->command_head; 745a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech while (I-- > 0) { 746a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = &ftdi->command[COMMAND_MASK & 747a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech i++]; 748a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int F = command->follows; 749a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 *f = command->buffer; 750a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command->header & 0x80) { 751a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ed_commands |= 1 << (0x3 & (command->header >> 5)); 752a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 753a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf[b++] = command->header; 754a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf[b++] = (command->length >> 0) & 0x00FF; 755a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf[b++] = (command->length >> 8) & 0x00FF; 756a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf[b++] = command->address; 757a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf[b++] = command->width; 758a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech while (F-- > 0) { 759a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf[b++] = *f++; 760a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 761a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 762a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return ed_commands; 763a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 764a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 765a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_total_command_size(struct usb_ftdi *ftdi, int command_size) 766a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 767a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int total_size = 0; 768a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int I = command_size; 769a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int i = ftdi->command_head; 770a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech while (I-- > 0) { 771a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = &ftdi->command[COMMAND_MASK & 772a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech i++]; 773a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech total_size += 5 + command->follows; 774a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } return total_size; 775a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 776a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 777a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_command_engine(struct usb_ftdi *ftdi) 778a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 779a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retval; 780a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *buf; 781a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int ed_commands; 782a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int total_size; 783a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct urb *urb; 784a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_size = ftdi->command_next - ftdi->command_head; 785a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command_size == 0) 786a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 787a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech total_size = ftdi_elan_total_command_size(ftdi, command_size); 788a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb = usb_alloc_urb(0, GFP_KERNEL); 789a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!urb) { 790a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "could not get a urb to write %d comm" 791a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "ands totaling %d bytes to the Uxxx\n", command_size, 792a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech total_size); 793a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 794a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 795a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf = usb_buffer_alloc(ftdi->udev, total_size, GFP_KERNEL, 796a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech &urb->transfer_dma); 797a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!buf) { 798a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "could not get a buffer to write %d c" 799a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "ommands totaling %d bytes to the Uxxx\n", command_size, 800a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech total_size); 801a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_free_urb(urb); 802a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 803a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 804a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ed_commands = fill_buffer_with_all_queued_commands(ftdi, buf, 805a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_size, total_size); 806a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, 807a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_out_endpointAddr), buf, total_size, 808a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_write_bulk_callback, ftdi); 809a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 810a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ed_commands) { 811a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char diag[40 *3 + 4]; 812a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *d = diag; 813a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int m = total_size; 814a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 *c = buf; 815a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int s = (sizeof(diag) - 1) / 3; 816a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech diag[0] = 0; 817a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech while (s-- > 0 && m-- > 0) { 818a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (s > 0 || m == 0) { 819a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " %02X", *c++); 820a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 821a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " .."); 822a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 823a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 824a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = usb_submit_urb(urb, GFP_KERNEL); 825a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retval) { 826a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "failed %d to submit urb %p to write " 827a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "%d commands totaling %d bytes to the Uxxx\n", retval, 828a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb, command_size, total_size); 829a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_buffer_free(ftdi->udev, total_size, buf, urb->transfer_dma); 830a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_free_urb(urb); 831a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return retval; 832a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 833a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_free_urb(urb); /* release our reference to this urb, 834a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech the USB core will eventually free it entirely */ 835a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_head += command_size; 836a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_kick_respond_queue(ftdi); 837a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 838a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 839a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 840a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_do_callback(struct usb_ftdi *ftdi, 841a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_target *target, u8 *buffer, int length) 842a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 843a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct urb *urb = target->urb; 844a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int halted = target->halted; 845a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int skipped = target->skipped; 846a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int actual = target->actual; 847a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int non_null = target->non_null; 848a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int toggle_bits = target->toggle_bits; 849a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int error_count = target->error_count; 850a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int condition_code = target->condition_code; 851a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int repeat_number = target->repeat_number; 852a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void (*callback) (void *, struct urb *, u8 *, int, int, int, int, int, 853a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int, int, int, int) = target->callback; 854a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->active -= 1; 855a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->callback = NULL; 856a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech (*callback) (target->endp, urb, buffer, length, toggle_bits, 857a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech error_count, condition_code, repeat_number, halted, skipped, 858a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech actual, non_null); 859a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 860a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 861a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic char *have_ed_set_response(struct usb_ftdi *ftdi, 862a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_target *target, u16 ed_length, int ed_number, int ed_type, 863a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *b) 864a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 865a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int payload = (ed_length >> 0) & 0x07FF; 866c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&ftdi->u132_lock); 867a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->actual = 0; 868a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->non_null = (ed_length >> 15) & 0x0001; 869a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->repeat_number = (ed_length >> 11) & 0x000F; 870a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ed_type == 0x02) { 871a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (payload == 0 || target->abandoning > 0) { 872a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->abandoning = 0; 873c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 874a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, 875a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech payload); 876a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->recieved = 0; 877a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->expected = 4; 878a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->ed_found = 0; 879a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return ftdi->response; 880a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 881a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->expected = 4 + payload; 882a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->ed_found = 1; 883c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 884a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return b; 885a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 886a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (ed_type == 0x03) { 887a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (payload == 0 || target->abandoning > 0) { 888a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->abandoning = 0; 889c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 890a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, 891a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech payload); 892a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->recieved = 0; 893a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->expected = 4; 894a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->ed_found = 0; 895a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return ftdi->response; 896a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 897a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->expected = 4 + payload; 898a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->ed_found = 1; 899c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 900a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return b; 901a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 902a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (ed_type == 0x01) { 903a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->abandoning = 0; 904c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 905a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, 906a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech payload); 907a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->recieved = 0; 908a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->expected = 4; 909a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->ed_found = 0; 910a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return ftdi->response; 911a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 912a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->abandoning = 0; 913c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 914a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, 915a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech payload); 916a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->recieved = 0; 917a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->expected = 4; 918a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->ed_found = 0; 919a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return ftdi->response; 920a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 921a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 922a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 923a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic char *have_ed_get_response(struct usb_ftdi *ftdi, 924a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_target *target, u16 ed_length, int ed_number, int ed_type, 925a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *b) 926a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 927c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&ftdi->u132_lock); 928a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->condition_code = TD_DEVNOTRESP; 929a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->actual = (ed_length >> 0) & 0x01FF; 930a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->non_null = (ed_length >> 15) & 0x0001; 931a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->repeat_number = (ed_length >> 11) & 0x000F; 932c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 933a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (target->active) 934a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_do_callback(ftdi, target, NULL, 0); 935a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->abandoning = 0; 936a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->recieved = 0; 937a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->expected = 4; 938a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->ed_found = 0; 939a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return ftdi->response; 940a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 941a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 942a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 943a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/* 944a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* The engine tries to empty the FTDI fifo 945a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* 946a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* all responses found in the fifo data are dispatched thus 947a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* the response buffer can only ever hold a maximum sized 948a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* response from the Uxxx. 949a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* 950a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/ 951a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_respond_engine(struct usb_ftdi *ftdi) 952a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 953a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 *b = ftdi->response + ftdi->recieved; 954a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int bytes_read = 0; 955a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retry_on_empty = 1; 956a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retry_on_timeout = 3; 957a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int empty_packets = 0; 958a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech read:{ 959a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int packet_bytes = 0; 960a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retval = usb_bulk_msg(ftdi->udev, 961a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), 962a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_buffer, ftdi->bulk_in_size, 963c0f082c5367a02e8493d779e16ad336167e14718Sarah Sharp &packet_bytes, 500); 964a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char diag[30 *3 + 4]; 965a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *d = diag; 966a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int m = packet_bytes; 967a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 *c = ftdi->bulk_in_buffer; 968a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int s = (sizeof(diag) - 1) / 3; 969a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech diag[0] = 0; 970a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech while (s-- > 0 && m-- > 0) { 971a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (s > 0 || m == 0) { 972a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " %02X", *c++); 973a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 974a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " .."); 975a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 976a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (packet_bytes > 2) { 977a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_left = packet_bytes - 2; 978a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_last = 1; 979a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto have; 980a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retval == -ETIMEDOUT) { 981a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_timeout-- > 0) { 982a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "TIMED OUT with packe" 983a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "t_bytes = %d with total %d bytes%s\n", 984a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech packet_bytes, bytes_read, diag); 985a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 986a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (bytes_read > 0) { 987a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "ONLY %d bytes%s\n", 988a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech bytes_read, diag); 989a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 990a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 991a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "TIMED OUT with packe" 992a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "t_bytes = %d with total %d bytes%s\n", 993a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech packet_bytes, bytes_read, diag); 994a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 995a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 996a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retval == -EILSEQ) { 997a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "error = %d with packet_bytes" 998a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech " = %d with total %d bytes%s\n", retval, 999a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech packet_bytes, bytes_read, diag); 1000a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return retval; 1001a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retval) { 1002a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "error = %d with packet_bytes" 1003a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech " = %d with total %d bytes%s\n", retval, 1004a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech packet_bytes, bytes_read, diag); 1005a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return retval; 1006a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (packet_bytes == 2) { 1007a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech unsigned char s0 = ftdi->bulk_in_buffer[0]; 1008a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech unsigned char s1 = ftdi->bulk_in_buffer[1]; 1009a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech empty_packets += 1; 1010a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (s0 == 0x31 && s1 == 0x60) { 1011a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_empty-- > 0) { 1012a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 1013a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 1014a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1015a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (s0 == 0x31 && s1 == 0x00) { 1016a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_empty-- > 0) { 1017a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 1018a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 1019a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1020a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1021a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_empty-- > 0) { 1022a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 1023a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 1024a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1025a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1026a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (packet_bytes == 1) { 1027a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_empty-- > 0) { 1028a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 1029a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 1030a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1031a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1032a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_empty-- > 0) { 1033a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 1034a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 1035a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1036a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1037a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1038a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech more:{ 1039a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto read; 1040a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1041a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech have:if (ftdi->bulk_in_left > 0) { 1042a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 c = ftdi->bulk_in_buffer[++ftdi->bulk_in_last]; 1043a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech bytes_read += 1; 1044a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_left -= 1; 1045a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi->recieved == 0 && c == 0xFF) { 1046a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto have; 1047a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 1048a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech *b++ = c; 1049a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (++ftdi->recieved < ftdi->expected) { 1050a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto have; 1051a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (ftdi->ed_found) { 1052a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int ed_number = (ftdi->response[0] >> 5) & 0x03; 1053a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u16 ed_length = (ftdi->response[2] << 8) | 1054a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->response[1]; 1055a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_target *target = &ftdi->target[ed_number]; 1056a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int payload = (ed_length >> 0) & 0x07FF; 1057a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char diag[30 *3 + 4]; 1058a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *d = diag; 1059a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int m = payload; 1060a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 *c = 4 + ftdi->response; 1061a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int s = (sizeof(diag) - 1) / 3; 1062a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech diag[0] = 0; 1063a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech while (s-- > 0 && m-- > 0) { 1064a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (s > 0 || m == 0) { 1065a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " %02X", *c++); 1066a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 1067a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " .."); 1068a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1069a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, 1070a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech payload); 1071a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->recieved = 0; 1072a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->expected = 4; 1073a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->ed_found = 0; 1074a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech b = ftdi->response; 1075a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto have; 1076a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (ftdi->expected == 8) { 1077a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 buscmd; 1078a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int respond_head = ftdi->respond_head++; 1079a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_respond *respond = &ftdi->respond[ 1080a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech RESPOND_MASK & respond_head]; 1081a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u32 data = ftdi->response[7]; 1082a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech data <<= 8; 1083a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech data |= ftdi->response[6]; 1084a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech data <<= 8; 1085a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech data |= ftdi->response[5]; 1086a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech data <<= 8; 1087a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech data |= ftdi->response[4]; 1088a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech *respond->value = data; 1089a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech *respond->result = 0; 1090a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech complete(&respond->wait_completion); 1091a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->recieved = 0; 1092a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->expected = 4; 1093a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->ed_found = 0; 1094a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech b = ftdi->response; 1095a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buscmd = (ftdi->response[0] >> 0) & 0x0F; 1096a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (buscmd == 0x00) { 1097a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (buscmd == 0x02) { 1098a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (buscmd == 0x06) { 1099a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (buscmd == 0x0A) { 1100a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 1101a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "Uxxx unknown(%0X) va" 1102a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "lue = %08X\n", buscmd, data); 1103a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto have; 1104a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1105a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if ((ftdi->response[0] & 0x80) == 0x00) { 1106a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->expected = 8; 1107a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto have; 1108a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1109a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int ed_number = (ftdi->response[0] >> 5) & 0x03; 1110a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int ed_type = (ftdi->response[0] >> 0) & 0x03; 1111a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u16 ed_length = (ftdi->response[2] << 8) | 1112a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->response[1]; 1113a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_target *target = &ftdi->target[ 1114a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ed_number]; 1115a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->halted = (ftdi->response[0] >> 3) & 1116a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 0x01; 1117a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->skipped = (ftdi->response[0] >> 2) & 1118a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 0x01; 1119a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->toggle_bits = (ftdi->response[3] >> 6) 1120a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech & 0x03; 1121a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->error_count = (ftdi->response[3] >> 4) 1122a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech & 0x03; 1123a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->condition_code = (ftdi->response[ 1124a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 3] >> 0) & 0x0F; 1125a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if ((ftdi->response[0] & 0x10) == 0x00) { 1126a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech b = have_ed_set_response(ftdi, target, 1127a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ed_length, ed_number, ed_type, 1128a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech b); 1129a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto have; 1130a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1131a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech b = have_ed_get_response(ftdi, target, 1132a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ed_length, ed_number, ed_type, 1133a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech b); 1134a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto have; 1135a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1136a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1137a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1138a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 1139a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 1140a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1141a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1142a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1143a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/* 1144a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* create a urb, and a buffer for it, and copy the data to the urb 1145a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* 1146a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/ 1147a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic ssize_t ftdi_elan_write(struct file *file, 1148a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech const char __user *user_buffer, size_t count, 1149a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech loff_t *ppos) 1150a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1151a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retval = 0; 1152a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct urb *urb; 1153a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *buf; 115496a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartman struct usb_ftdi *ftdi = file->private_data; 115596a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartman 1156a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi->disconnected > 0) { 1157a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1158a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1159a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (count == 0) { 1160a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto exit; 1161a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1162a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb = usb_alloc_urb(0, GFP_KERNEL); 1163a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!urb) { 1164a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = -ENOMEM; 1165a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto error_1; 1166a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1167a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf = usb_buffer_alloc(ftdi->udev, count, GFP_KERNEL, 1168a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech &urb->transfer_dma); 1169a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!buf) { 1170a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = -ENOMEM; 1171a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto error_2; 1172a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1173a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (copy_from_user(buf, user_buffer, count)) { 1174a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = -EFAULT; 1175a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto error_3; 1176a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1177a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, 1178a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_out_endpointAddr), buf, count, 1179a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_write_bulk_callback, ftdi); 1180a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 1181a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = usb_submit_urb(urb, GFP_KERNEL); 1182a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retval) { 1183a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "failed submitting write urb, error %" 1184a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "d\n", retval); 118596a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartman goto error_3; 1186a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1187a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_free_urb(urb); 118896a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartman 118996a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartmanexit: 1190a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return count; 119196a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartmanerror_3: 119296a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartman usb_buffer_free(ftdi->udev, count, buf, urb->transfer_dma); 119396a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartmanerror_2: 119496a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartman usb_free_urb(urb); 119596a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartmanerror_1: 119696a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartman return retval; 1197a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1198a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 119900977a59b951207d38380c75f03a36829950265cArjan van de Venstatic const struct file_operations ftdi_elan_fops = { 1200a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .owner = THIS_MODULE, 1201a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .llseek = no_llseek, 1202a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .read = ftdi_elan_read, 1203a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .write = ftdi_elan_write, 1204a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .open = ftdi_elan_open, 1205a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .release = ftdi_elan_release, 1206a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}; 1207a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1208a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/* 1209a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* usb class driver info in order to get a minor number from the usb core, 1210a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* and to have the device registered with the driver core 1211a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/ 1212a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic struct usb_class_driver ftdi_elan_jtag_class = { 1213a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .name = "ftdi-%d-jtag", 1214a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .fops = &ftdi_elan_fops, 1215a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .minor_base = USB_FTDI_ELAN_MINOR_BASE, 1216a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}; 1217a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1218a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/* 1219a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* the following definitions are for the 1220a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* ELAN FPGA state machgine processor that 1221a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* lies on the other side of the FTDI chip 1222a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/ 1223a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPCIu132rd 0x0 1224a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPCIu132wr 0x1 1225a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPCIiord 0x2 1226a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPCIiowr 0x3 1227a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPCImemrd 0x6 1228a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPCImemwr 0x7 1229a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPCIcfgrd 0xA 1230a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPCIcfgwr 0xB 1231a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPCInull 0xF 1232a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cU132cmd_status 0x0 1233a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cU132flash 0x1 1234a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPIDsetup 0x0 1235a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPIDout 0x1 1236a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPIDin 0x2 1237a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPIDinonce 0x3 1238a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCnoerror 0x0 1239a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCcrc 0x1 1240a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCbitstuff 0x2 1241a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCtoggle 0x3 1242a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCstall 0x4 1243a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCnoresp 0x5 1244a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCbadpid1 0x6 1245a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCbadpid2 0x7 1246a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCdataoverrun 0x8 1247a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCdataunderrun 0x9 1248a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCbuffoverrun 0xC 1249a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCbuffunderrun 0xD 1250a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCnotaccessed 0xF 1251a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_write_reg(struct usb_ftdi *ftdi, u32 data) 1252a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1253a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait:if (ftdi->disconnected > 0) { 1254a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1255a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1256a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_size; 1257c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&ftdi->u132_lock); 1258a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_size = ftdi->command_next - ftdi->command_head; 1259a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command_size < COMMAND_SIZE) { 1260a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = &ftdi->command[ 1261a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech COMMAND_MASK & ftdi->command_next]; 1262a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->header = 0x00 | cPCIu132wr; 1263a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x04; 1264a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->address = 0x00; 1265a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->width = 0x00; 1266a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->follows = 4; 1267a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->value = data; 1268a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->buffer = &command->value; 1269a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_next += 1; 1270a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_kick_command_queue(ftdi); 1271c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1272a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1273a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1274c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1275a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 1276a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto wait; 1277a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1278a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1279a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1280a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1281a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_write_config(struct usb_ftdi *ftdi, int config_offset, 1282a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 width, u32 data) 1283a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1284a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 addressofs = config_offset / 4; 1285a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait:if (ftdi->disconnected > 0) { 1286a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1287a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1288a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_size; 1289c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&ftdi->u132_lock); 1290a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_size = ftdi->command_next - ftdi->command_head; 1291a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command_size < COMMAND_SIZE) { 1292a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = &ftdi->command[ 1293a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech COMMAND_MASK & ftdi->command_next]; 1294a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->header = 0x00 | (cPCIcfgwr & 0x0F); 1295a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x04; 1296a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->address = addressofs; 1297a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->width = 0x00 | (width & 0x0F); 1298a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->follows = 4; 1299a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->value = data; 1300a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->buffer = &command->value; 1301a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_next += 1; 1302a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_kick_command_queue(ftdi); 1303c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1304a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1305a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1306c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1307a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 1308a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto wait; 1309a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1310a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1311a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1312a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1313a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_write_pcimem(struct usb_ftdi *ftdi, int mem_offset, 1314a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 width, u32 data) 1315a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1316a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 addressofs = mem_offset / 4; 1317a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait:if (ftdi->disconnected > 0) { 1318a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1319a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1320a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_size; 1321c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&ftdi->u132_lock); 1322a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_size = ftdi->command_next - ftdi->command_head; 1323a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command_size < COMMAND_SIZE) { 1324a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = &ftdi->command[ 1325a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech COMMAND_MASK & ftdi->command_next]; 1326a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->header = 0x00 | (cPCImemwr & 0x0F); 1327a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x04; 1328a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->address = addressofs; 1329a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->width = 0x00 | (width & 0x0F); 1330a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->follows = 4; 1331a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->value = data; 1332a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->buffer = &command->value; 1333a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_next += 1; 1334a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_kick_command_queue(ftdi); 1335c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1336a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1337a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1338c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1339a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 1340a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto wait; 1341a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1342a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1343a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1344a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1345a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechint usb_ftdi_elan_write_pcimem(struct platform_device *pdev, int mem_offset, 1346a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 width, u32 data) 1347a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1348a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); 1349a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return ftdi_elan_write_pcimem(ftdi, mem_offset, width, data); 1350a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1351a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1352a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1353a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechEXPORT_SYMBOL_GPL(usb_ftdi_elan_write_pcimem); 1354a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_read_reg(struct usb_ftdi *ftdi, u32 *data) 1355a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1356a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait:if (ftdi->disconnected > 0) { 1357a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1358a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1359a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_size; 1360a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int respond_size; 1361c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&ftdi->u132_lock); 1362a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_size = ftdi->command_next - ftdi->command_head; 1363a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond_size = ftdi->respond_next - ftdi->respond_head; 1364a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) 1365a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech { 1366a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = &ftdi->command[ 1367a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech COMMAND_MASK & ftdi->command_next]; 1368a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_respond *respond = &ftdi->respond[ 1369a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech RESPOND_MASK & ftdi->respond_next]; 1370a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int result = -ENODEV; 1371a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond->result = &result; 1372a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond->header = command->header = 0x00 | cPCIu132rd; 1373a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x04; 1374a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond->address = command->address = cU132cmd_status; 1375a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->width = 0x00; 1376a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->follows = 0; 1377a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->value = 0; 1378a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->buffer = NULL; 1379a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond->value = data; 1380a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech init_completion(&respond->wait_completion); 1381a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_next += 1; 1382a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->respond_next += 1; 1383a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_kick_command_queue(ftdi); 1384c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1385a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait_for_completion(&respond->wait_completion); 1386a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return result; 1387a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1388c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1389a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 1390a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto wait; 1391a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1392a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1393a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1394a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1395a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_read_config(struct usb_ftdi *ftdi, int config_offset, 1396a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 width, u32 *data) 1397a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1398a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 addressofs = config_offset / 4; 1399a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait:if (ftdi->disconnected > 0) { 1400a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1401a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1402a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_size; 1403a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int respond_size; 1404c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&ftdi->u132_lock); 1405a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_size = ftdi->command_next - ftdi->command_head; 1406a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond_size = ftdi->respond_next - ftdi->respond_head; 1407a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) 1408a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech { 1409a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = &ftdi->command[ 1410a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech COMMAND_MASK & ftdi->command_next]; 1411a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_respond *respond = &ftdi->respond[ 1412a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech RESPOND_MASK & ftdi->respond_next]; 1413a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int result = -ENODEV; 1414a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond->result = &result; 1415a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond->header = command->header = 0x00 | (cPCIcfgrd & 1416a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 0x0F); 1417a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x04; 1418a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond->address = command->address = addressofs; 1419a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->width = 0x00 | (width & 0x0F); 1420a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->follows = 0; 1421a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->value = 0; 1422a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->buffer = NULL; 1423a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond->value = data; 1424a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech init_completion(&respond->wait_completion); 1425a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_next += 1; 1426a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->respond_next += 1; 1427a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_kick_command_queue(ftdi); 1428c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1429a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait_for_completion(&respond->wait_completion); 1430a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return result; 1431a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1432c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1433a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 1434a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto wait; 1435a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1436a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1437a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1438a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1439a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_read_pcimem(struct usb_ftdi *ftdi, int mem_offset, 1440a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 width, u32 *data) 1441a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1442a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 addressofs = mem_offset / 4; 1443a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait:if (ftdi->disconnected > 0) { 1444a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1445a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1446a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_size; 1447a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int respond_size; 1448c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&ftdi->u132_lock); 1449a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_size = ftdi->command_next - ftdi->command_head; 1450a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond_size = ftdi->respond_next - ftdi->respond_head; 1451a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) 1452a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech { 1453a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = &ftdi->command[ 1454a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech COMMAND_MASK & ftdi->command_next]; 1455a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_respond *respond = &ftdi->respond[ 1456a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech RESPOND_MASK & ftdi->respond_next]; 1457a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int result = -ENODEV; 1458a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond->result = &result; 1459a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond->header = command->header = 0x00 | (cPCImemrd & 1460a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 0x0F); 1461a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x04; 1462a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond->address = command->address = addressofs; 1463a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->width = 0x00 | (width & 0x0F); 1464a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->follows = 0; 1465a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->value = 0; 1466a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->buffer = NULL; 1467a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond->value = data; 1468a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech init_completion(&respond->wait_completion); 1469a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_next += 1; 1470a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->respond_next += 1; 1471a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_kick_command_queue(ftdi); 1472c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1473a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait_for_completion(&respond->wait_completion); 1474a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return result; 1475a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1476c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1477a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 1478a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto wait; 1479a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1480a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1481a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1482a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1483a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechint usb_ftdi_elan_read_pcimem(struct platform_device *pdev, int mem_offset, 1484a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 width, u32 *data) 1485a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1486a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); 1487a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi->initialized == 0) { 1488a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1489a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 1490a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return ftdi_elan_read_pcimem(ftdi, mem_offset, width, data); 1491a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1492a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1493a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1494a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechEXPORT_SYMBOL_GPL(usb_ftdi_elan_read_pcimem); 1495a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_edset_setup(struct usb_ftdi *ftdi, u8 ed_number, 1496a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, 1497a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, 1498a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int toggle_bits, int error_count, int condition_code, int repeat_number, 1499a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int halted, int skipped, int actual, int non_null)) 1500a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1501a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 ed = ed_number - 1; 1502a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait:if (ftdi->disconnected > 0) { 1503a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1504a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (ftdi->initialized == 0) { 1505a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1506a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1507a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_size; 1508c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&ftdi->u132_lock); 1509a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_size = ftdi->command_next - ftdi->command_head; 1510a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command_size < COMMAND_SIZE) { 1511a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_target *target = &ftdi->target[ed]; 1512a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = &ftdi->command[ 1513a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech COMMAND_MASK & ftdi->command_next]; 1514a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->header = 0x80 | (ed << 5); 1515a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x8007; 1516a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->address = (toggle_bits << 6) | (ep_number << 2) 1517a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech | (address << 0); 1518a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->width = usb_maxpacket(urb->dev, urb->pipe, 1519a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_pipeout(urb->pipe)); 1520a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->follows = 8; 1521a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->value = 0; 1522a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->buffer = urb->setup_packet; 1523a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->callback = callback; 1524a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->endp = endp; 1525a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->urb = urb; 1526a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->active = 1; 1527a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_next += 1; 1528a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_kick_command_queue(ftdi); 1529c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1530a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1531a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1532c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1533a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 1534a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto wait; 1535a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1536a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1537a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1538a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1539a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechint usb_ftdi_elan_edset_setup(struct platform_device *pdev, u8 ed_number, 1540a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, 1541a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, 1542a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int toggle_bits, int error_count, int condition_code, int repeat_number, 1543a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int halted, int skipped, int actual, int non_null)) 1544a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1545a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); 1546a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return ftdi_elan_edset_setup(ftdi, ed_number, endp, urb, address, 1547a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ep_number, toggle_bits, callback); 1548a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1549a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1550a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1551a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechEXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_setup); 1552a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_edset_input(struct usb_ftdi *ftdi, u8 ed_number, 1553a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, 1554a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, 1555a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int toggle_bits, int error_count, int condition_code, int repeat_number, 1556a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int halted, int skipped, int actual, int non_null)) 1557a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1558a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 ed = ed_number - 1; 1559a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait:if (ftdi->disconnected > 0) { 1560a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1561a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (ftdi->initialized == 0) { 1562a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1563a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1564a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_size; 1565c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&ftdi->u132_lock); 1566a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_size = ftdi->command_next - ftdi->command_head; 1567a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command_size < COMMAND_SIZE) { 1568a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_target *target = &ftdi->target[ed]; 1569a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = &ftdi->command[ 1570a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech COMMAND_MASK & ftdi->command_next]; 157116e2e5f634f86ccda18366967c4e592eb61bc9ccGreg Kroah-Hartman u32 remaining_length = urb->transfer_buffer_length - 1572a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb->actual_length; 1573a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->header = 0x82 | (ed << 5); 1574a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (remaining_length == 0) { 1575a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x0000; 1576a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (remaining_length > 1024) { 1577a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x8000 | 1023; 1578a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 1579a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x8000 | (remaining_length - 1580a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1); 1581a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->address = (toggle_bits << 6) | (ep_number << 2) 1582a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech | (address << 0); 1583a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->width = usb_maxpacket(urb->dev, urb->pipe, 1584a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_pipeout(urb->pipe)); 1585a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->follows = 0; 1586a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->value = 0; 1587a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->buffer = NULL; 1588a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->callback = callback; 1589a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->endp = endp; 1590a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->urb = urb; 1591a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->active = 1; 1592a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_next += 1; 1593a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_kick_command_queue(ftdi); 1594c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1595a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1596a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1597c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1598a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 1599a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto wait; 1600a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1601a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1602a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1603a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1604a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechint usb_ftdi_elan_edset_input(struct platform_device *pdev, u8 ed_number, 1605a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, 1606a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, 1607a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int toggle_bits, int error_count, int condition_code, int repeat_number, 1608a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int halted, int skipped, int actual, int non_null)) 1609a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1610a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); 1611a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return ftdi_elan_edset_input(ftdi, ed_number, endp, urb, address, 1612a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ep_number, toggle_bits, callback); 1613a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1614a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1615a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1616a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechEXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_input); 1617a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_edset_empty(struct usb_ftdi *ftdi, u8 ed_number, 1618a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, 1619a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, 1620a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int toggle_bits, int error_count, int condition_code, int repeat_number, 1621a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int halted, int skipped, int actual, int non_null)) 1622a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1623a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 ed = ed_number - 1; 1624a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait:if (ftdi->disconnected > 0) { 1625a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1626a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (ftdi->initialized == 0) { 1627a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1628a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1629a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_size; 1630c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&ftdi->u132_lock); 1631a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_size = ftdi->command_next - ftdi->command_head; 1632a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command_size < COMMAND_SIZE) { 1633a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_target *target = &ftdi->target[ed]; 1634a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = &ftdi->command[ 1635a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech COMMAND_MASK & ftdi->command_next]; 1636a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->header = 0x81 | (ed << 5); 1637a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x0000; 1638a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->address = (toggle_bits << 6) | (ep_number << 2) 1639a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech | (address << 0); 1640a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->width = usb_maxpacket(urb->dev, urb->pipe, 1641a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_pipeout(urb->pipe)); 1642a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->follows = 0; 1643a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->value = 0; 1644a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->buffer = NULL; 1645a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->callback = callback; 1646a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->endp = endp; 1647a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->urb = urb; 1648a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->active = 1; 1649a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_next += 1; 1650a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_kick_command_queue(ftdi); 1651c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1652a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1653a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1654c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1655a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 1656a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto wait; 1657a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1658a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1659a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1660a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1661a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechint usb_ftdi_elan_edset_empty(struct platform_device *pdev, u8 ed_number, 1662a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, 1663a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, 1664a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int toggle_bits, int error_count, int condition_code, int repeat_number, 1665a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int halted, int skipped, int actual, int non_null)) 1666a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1667a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); 1668a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return ftdi_elan_edset_empty(ftdi, ed_number, endp, urb, address, 1669a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ep_number, toggle_bits, callback); 1670a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1671a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1672a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1673a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechEXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_empty); 1674a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_edset_output(struct usb_ftdi *ftdi, u8 ed_number, 1675a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, 1676a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, 1677a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int toggle_bits, int error_count, int condition_code, int repeat_number, 1678a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int halted, int skipped, int actual, int non_null)) 1679a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1680a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 ed = ed_number - 1; 1681a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait:if (ftdi->disconnected > 0) { 1682a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1683a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (ftdi->initialized == 0) { 1684a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1685a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1686a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_size; 1687c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&ftdi->u132_lock); 1688a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_size = ftdi->command_next - ftdi->command_head; 1689a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command_size < COMMAND_SIZE) { 1690a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 *b; 1691a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u16 urb_size; 1692a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int i = 0; 1693a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char data[30 *3 + 4]; 1694a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *d = data; 1695a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int m = (sizeof(data) - 1) / 3; 1696a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int l = 0; 1697a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_target *target = &ftdi->target[ed]; 1698a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = &ftdi->command[ 1699a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech COMMAND_MASK & ftdi->command_next]; 1700a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->header = 0x81 | (ed << 5); 1701a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->address = (toggle_bits << 6) | (ep_number << 2) 1702a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech | (address << 0); 1703a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->width = usb_maxpacket(urb->dev, urb->pipe, 1704a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_pipeout(urb->pipe)); 170516e2e5f634f86ccda18366967c4e592eb61bc9ccGreg Kroah-Hartman command->follows = min_t(u32, 1024, 1706a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb->transfer_buffer_length - 1707a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb->actual_length); 1708a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->value = 0; 1709a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->buffer = urb->transfer_buffer + 1710a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb->actual_length; 1711a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x8000 | (command->follows - 1); 1712a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech b = command->buffer; 1713a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb_size = command->follows; 1714a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech data[0] = 0; 1715a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech while (urb_size-- > 0) { 1716a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (i > m) { 1717a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (i++ < m) { 1718a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int w = sprintf(d, " %02X", *b++); 1719a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += w; 1720a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech l += w; 1721a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 1722a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " .."); 1723a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1724a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->callback = callback; 1725a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->endp = endp; 1726a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->urb = urb; 1727a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->active = 1; 1728a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_next += 1; 1729a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_kick_command_queue(ftdi); 1730c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1731a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1732a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1733c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1734a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 1735a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto wait; 1736a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1737a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1738a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1739a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1740a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechint usb_ftdi_elan_edset_output(struct platform_device *pdev, u8 ed_number, 1741a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, 1742a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, 1743a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int toggle_bits, int error_count, int condition_code, int repeat_number, 1744a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int halted, int skipped, int actual, int non_null)) 1745a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1746a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); 1747a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return ftdi_elan_edset_output(ftdi, ed_number, endp, urb, address, 1748a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ep_number, toggle_bits, callback); 1749a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1750a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1751a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1752a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechEXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_output); 1753a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_edset_single(struct usb_ftdi *ftdi, u8 ed_number, 1754a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, 1755a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, 1756a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int toggle_bits, int error_count, int condition_code, int repeat_number, 1757a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int halted, int skipped, int actual, int non_null)) 1758a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1759a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 ed = ed_number - 1; 1760a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait:if (ftdi->disconnected > 0) { 1761a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1762a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (ftdi->initialized == 0) { 1763a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1764a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1765a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_size; 1766c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&ftdi->u132_lock); 1767a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_size = ftdi->command_next - ftdi->command_head; 1768a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command_size < COMMAND_SIZE) { 176916e2e5f634f86ccda18366967c4e592eb61bc9ccGreg Kroah-Hartman u32 remaining_length = urb->transfer_buffer_length - 1770a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb->actual_length; 1771a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_target *target = &ftdi->target[ed]; 1772a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = &ftdi->command[ 1773a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech COMMAND_MASK & ftdi->command_next]; 1774a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->header = 0x83 | (ed << 5); 1775a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (remaining_length == 0) { 1776a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x0000; 1777a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (remaining_length > 1024) { 1778a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x8000 | 1023; 1779a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 1780a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x8000 | (remaining_length - 1781a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1); 1782a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->address = (toggle_bits << 6) | (ep_number << 2) 1783a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech | (address << 0); 1784a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->width = usb_maxpacket(urb->dev, urb->pipe, 1785a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_pipeout(urb->pipe)); 1786a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->follows = 0; 1787a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->value = 0; 1788a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->buffer = NULL; 1789a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->callback = callback; 1790a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->endp = endp; 1791a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->urb = urb; 1792a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->active = 1; 1793a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_next += 1; 1794a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_kick_command_queue(ftdi); 1795c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1796a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1797a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1798c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1799a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 1800a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto wait; 1801a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1802a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1803a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1804a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1805a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechint usb_ftdi_elan_edset_single(struct platform_device *pdev, u8 ed_number, 1806a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, 1807a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, 1808a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int toggle_bits, int error_count, int condition_code, int repeat_number, 1809a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int halted, int skipped, int actual, int non_null)) 1810a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1811a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); 1812a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return ftdi_elan_edset_single(ftdi, ed_number, endp, urb, address, 1813a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ep_number, toggle_bits, callback); 1814a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1815a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1816a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1817a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechEXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_single); 1818a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_edset_flush(struct usb_ftdi *ftdi, u8 ed_number, 1819a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void *endp) 1820a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1821a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 ed = ed_number - 1; 1822a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi->disconnected > 0) { 1823a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1824a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (ftdi->initialized == 0) { 1825a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1826a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1827a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_target *target = &ftdi->target[ed]; 1828c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&ftdi->u132_lock); 1829a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (target->abandoning > 0) { 1830c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1831a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1832a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1833a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->abandoning = 1; 1834a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait_1:if (target->active == 1) { 1835a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_size = ftdi->command_next - 1836a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_head; 1837a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command_size < COMMAND_SIZE) { 1838a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = 1839a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech &ftdi->command[COMMAND_MASK & 1840a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_next]; 1841a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->header = 0x80 | (ed << 5) | 1842a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 0x4; 1843a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x00; 1844a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->address = 0x00; 1845a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->width = 0x00; 1846a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->follows = 0; 1847a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->value = 0; 1848a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->buffer = &command->value; 1849a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_next += 1; 1850a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_kick_command_queue(ftdi); 1851a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1852c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1853a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 1854c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_lock(&ftdi->u132_lock); 1855a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto wait_1; 1856a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1857a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1858c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_unlock(&ftdi->u132_lock); 1859a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1860a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1861a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1862a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1863a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1864a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechint usb_ftdi_elan_edset_flush(struct platform_device *pdev, u8 ed_number, 1865a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void *endp) 1866a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1867a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); 1868a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return ftdi_elan_edset_flush(ftdi, ed_number, endp); 1869a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1870a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1871a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1872a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechEXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_flush); 1873a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_flush_input_fifo(struct usb_ftdi *ftdi) 1874a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1875a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retry_on_empty = 10; 1876a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retry_on_timeout = 5; 1877a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retry_on_status = 20; 1878a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech more:{ 1879a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int packet_bytes = 0; 1880a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retval = usb_bulk_msg(ftdi->udev, 1881a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), 1882a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_buffer, ftdi->bulk_in_size, 1883c0f082c5367a02e8493d779e16ad336167e14718Sarah Sharp &packet_bytes, 100); 1884a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (packet_bytes > 2) { 1885a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char diag[30 *3 + 4]; 1886a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *d = diag; 1887a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int m = (sizeof(diag) - 1) / 3; 1888a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *b = ftdi->bulk_in_buffer; 1889a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int bytes_read = 0; 1890a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech diag[0] = 0; 1891a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech while (packet_bytes-- > 0) { 1892a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char c = *b++; 1893a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (bytes_read < m) { 1894a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " %02X", 1895a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 0x000000FF & c); 1896a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (bytes_read > m) { 1897a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 1898a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " .."); 1899a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech bytes_read += 1; 1900a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech continue; 1901a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1902a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 1903a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (packet_bytes > 1) { 1904a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char s1 = ftdi->bulk_in_buffer[0]; 1905a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char s2 = ftdi->bulk_in_buffer[1]; 1906a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (s1 == 0x31 && s2 == 0x60) { 1907a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1908a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retry_on_status-- > 0) { 1909a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 1910a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1911a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "STATUS ERROR retry l" 1912a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "imit reached\n"); 1913a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -EFAULT; 1914a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1915a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (packet_bytes > 0) { 1916a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char b1 = ftdi->bulk_in_buffer[0]; 1917a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "only one byte flushed from F" 1918a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "TDI = %02X\n", b1); 1919a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_status-- > 0) { 1920a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 1921a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1922a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "STATUS ERROR retry l" 1923a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "imit reached\n"); 1924a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -EFAULT; 1925a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1926a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retval == -ETIMEDOUT) { 1927a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_timeout-- > 0) { 1928a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 1929a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1930a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "TIMED OUT retry limi" 1931a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "t reached\n"); 1932a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 1933a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1934a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retval == 0) { 1935a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_empty-- > 0) { 1936a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 1937a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1938a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "empty packet retry l" 1939a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "imit reached\n"); 1940a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 1941a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1942a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1943a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "error = %d\n", retval); 1944a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return retval; 1945a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1946a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1947a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -1; 1948a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1949a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1950a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1951a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/* 1952a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* send the long flush sequence 1953a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* 1954a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/ 1955a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_synchronize_flush(struct usb_ftdi *ftdi) 1956a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1957a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retval; 1958a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct urb *urb; 1959a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *buf; 1960a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int I = 257; 1961a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int i = 0; 1962a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb = usb_alloc_urb(0, GFP_KERNEL); 1963a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!urb) { 1964a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "could not alloc a urb for flush sequ" 1965a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "ence\n"); 1966a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 1967a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1968a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf = usb_buffer_alloc(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma); 1969a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!buf) { 1970a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "could not get a buffer for flush seq" 1971a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "uence\n"); 1972a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_free_urb(urb); 1973a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 1974a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1975a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech while (I-- > 0) 1976a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf[i++] = 0x55; 1977a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, 1978a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_out_endpointAddr), buf, i, 1979a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_write_bulk_callback, ftdi); 1980a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 1981a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = usb_submit_urb(urb, GFP_KERNEL); 1982a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retval) { 1983a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "failed to submit urb containing the " 1984a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "flush sequence\n"); 1985a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_buffer_free(ftdi->udev, i, buf, urb->transfer_dma); 1986a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_free_urb(urb); 1987a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 1988a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1989a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_free_urb(urb); 1990a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1991a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1992a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1993a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1994a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/* 1995a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* send the reset sequence 1996a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* 1997a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/ 1998a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_synchronize_reset(struct usb_ftdi *ftdi) 1999a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 2000a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retval; 2001a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct urb *urb; 2002a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *buf; 2003a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int I = 4; 2004a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int i = 0; 2005a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb = usb_alloc_urb(0, GFP_KERNEL); 2006a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!urb) { 2007a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "could not get a urb for the reset se" 2008a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "quence\n"); 2009a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 2010a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2011a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf = usb_buffer_alloc(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma); 2012a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!buf) { 2013a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "could not get a buffer for the reset" 2014a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech " sequence\n"); 2015a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_free_urb(urb); 2016a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 2017a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2018a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf[i++] = 0x55; 2019a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf[i++] = 0xAA; 2020a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf[i++] = 0x5A; 2021a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf[i++] = 0xA5; 2022a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, 2023a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_out_endpointAddr), buf, i, 2024a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_write_bulk_callback, ftdi); 2025a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 2026a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = usb_submit_urb(urb, GFP_KERNEL); 2027a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retval) { 2028a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "failed to submit urb containing the " 2029a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "reset sequence\n"); 2030a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_buffer_free(ftdi->udev, i, buf, urb->transfer_dma); 2031a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_free_urb(urb); 2032a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 2033a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2034a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_free_urb(urb); 2035a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 2036a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 2037a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 2038a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_synchronize(struct usb_ftdi *ftdi) 2039a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 2040a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retval; 2041a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int long_stop = 10; 2042a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retry_on_timeout = 5; 2043a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retry_on_empty = 10; 2044a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int err_count = 0; 2045a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = ftdi_elan_flush_input_fifo(ftdi); 2046a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retval) 2047a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return retval; 2048a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_left = 0; 2049a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_last = -1; 2050a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech while (long_stop-- > 0) { 2051a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int read_stop; 2052a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int read_stuck; 2053a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = ftdi_elan_synchronize_flush(ftdi); 2054a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retval) 2055a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return retval; 2056a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = ftdi_elan_flush_input_fifo(ftdi); 2057a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retval) 2058a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return retval; 2059a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reset:retval = ftdi_elan_synchronize_reset(ftdi); 2060a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retval) 2061a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return retval; 2062a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech read_stop = 100; 2063a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech read_stuck = 10; 2064a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech read:{ 2065a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int packet_bytes = 0; 2066a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = usb_bulk_msg(ftdi->udev, 2067a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_rcvbulkpipe(ftdi->udev, 2068a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_endpointAddr), 2069a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_buffer, ftdi->bulk_in_size, 2070c0f082c5367a02e8493d779e16ad336167e14718Sarah Sharp &packet_bytes, 500); 2071a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (packet_bytes > 2) { 2072a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char diag[30 *3 + 4]; 2073a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *d = diag; 2074a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int m = (sizeof(diag) - 1) / 3; 2075a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *b = ftdi->bulk_in_buffer; 2076a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int bytes_read = 0; 2077a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech unsigned char c = 0; 2078a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech diag[0] = 0; 2079a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech while (packet_bytes-- > 0) { 2080a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech c = *b++; 2081a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (bytes_read < m) { 2082a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " %02X", c); 2083a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (bytes_read > m) { 2084a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 2085a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " .."); 2086a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech bytes_read += 1; 2087a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech continue; 2088a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2089a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (c == 0x7E) { 2090a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 2091a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2092a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (c == 0x55) { 2093a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto read; 2094a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (read_stop-- > 0) { 2095a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto read; 2096a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2097a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "retr" 2098a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "y limit reached\n"); 2099a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech continue; 2100a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2101a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2102a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (packet_bytes > 1) { 2103a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech unsigned char s1 = ftdi->bulk_in_buffer[0]; 2104a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech unsigned char s2 = ftdi->bulk_in_buffer[1]; 2105a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (s1 == 0x31 && s2 == 0x00) { 2106a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (read_stuck-- > 0) { 2107a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto read; 2108a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 2109a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto reset; 2110a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (s1 == 0x31 && s2 == 0x60) { 2111a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (read_stop-- > 0) { 2112a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto read; 2113a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2114a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "retr" 2115a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "y limit reached\n"); 2116a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech continue; 2117a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2118a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2119a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (read_stop-- > 0) { 2120a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto read; 2121a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2122a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "retr" 2123a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "y limit reached\n"); 2124a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech continue; 2125a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2126a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2127a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (packet_bytes > 0) { 2128a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (read_stop-- > 0) { 2129a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto read; 2130a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2131a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "retry limit " 2132a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "reached\n"); 2133a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech continue; 2134a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2135a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retval == -ETIMEDOUT) { 2136a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_timeout-- > 0) { 2137a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto read; 2138a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2139a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "TIMED OUT re" 2140a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "try limit reached\n"); 2141a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech continue; 2142a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2143a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retval == 0) { 2144a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_empty-- > 0) { 2145a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto read; 2146a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2147a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "empty packet" 2148a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech " retry limit reached\n"); 2149a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech continue; 2150a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2151a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2152a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech err_count += 1; 2153a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "error = %d\n", 2154a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval); 2155a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (read_stop-- > 0) { 2156a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto read; 2157a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2158a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "retry limit " 2159a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "reached\n"); 2160a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech continue; 2161a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2162a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2163a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2164a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2165a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "failed to synchronize\n"); 2166a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -EFAULT; 2167a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 2168a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 2169a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_stuck_waiting(struct usb_ftdi *ftdi) 2170a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 2171a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retry_on_empty = 10; 2172a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retry_on_timeout = 5; 2173a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retry_on_status = 50; 2174a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech more:{ 2175a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int packet_bytes = 0; 2176a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retval = usb_bulk_msg(ftdi->udev, 2177a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), 2178a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_buffer, ftdi->bulk_in_size, 2179c0f082c5367a02e8493d779e16ad336167e14718Sarah Sharp &packet_bytes, 1000); 2180a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (packet_bytes > 2) { 2181a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char diag[30 *3 + 4]; 2182a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *d = diag; 2183a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int m = (sizeof(diag) - 1) / 3; 2184a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *b = ftdi->bulk_in_buffer; 2185a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int bytes_read = 0; 2186a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech diag[0] = 0; 2187a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech while (packet_bytes-- > 0) { 2188a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char c = *b++; 2189a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (bytes_read < m) { 2190a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " %02X", 2191a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 0x000000FF & c); 2192a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (bytes_read > m) { 2193a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 2194a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " .."); 2195a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech bytes_read += 1; 2196a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech continue; 2197a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2198a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 2199a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (packet_bytes > 1) { 2200a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char s1 = ftdi->bulk_in_buffer[0]; 2201a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char s2 = ftdi->bulk_in_buffer[1]; 2202a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (s1 == 0x31 && s2 == 0x60) { 2203a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 2204a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retry_on_status-- > 0) { 2205a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(5); 2206a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 2207a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 2208a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -EFAULT; 2209a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (packet_bytes > 0) { 2210a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char b1 = ftdi->bulk_in_buffer[0]; 2211a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "only one byte flushed from F" 2212a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "TDI = %02X\n", b1); 2213a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_status-- > 0) { 2214a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(5); 2215a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 2216a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2217a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "STATUS ERROR retry l" 2218a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "imit reached\n"); 2219a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -EFAULT; 2220a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2221a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retval == -ETIMEDOUT) { 2222a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_timeout-- > 0) { 2223a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 2224a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2225a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "TIMED OUT retry limi" 2226a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "t reached\n"); 2227a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 2228a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2229a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retval == 0) { 2230a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_empty-- > 0) { 2231a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 2232a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2233a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "empty packet retry l" 2234a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "imit reached\n"); 2235a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 2236a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2237a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2238a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "error = %d\n", retval); 2239a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 2240a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2241a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2242a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -1; 2243a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 2244a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 2245a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi) 2246a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 2247a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int UxxxStatus = ftdi_elan_read_reg(ftdi, &ftdi->controlreg); 2248a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2249a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2250a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi->controlreg & 0x00400000) { 2251a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi->card_ejected) { 2252a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2253a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->card_ejected = 1; 2254a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "CARD EJECTED - controlreg = " 2255a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "%08X\n", ftdi->controlreg); 2256a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2257a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 2258a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2259a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 fn = ftdi->function - 1; 2260a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int activePCIfn = fn << 8; 2261a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u32 pcidata; 2262a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u32 pciVID; 2263a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u32 pciPID; 2264a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int reg = 0; 2265a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, 2266a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech &pcidata); 2267a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2268a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2269a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech pciVID = pcidata & 0xFFFF; 2270a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech pciPID = (pcidata >> 16) & 0xFFFF; 2271a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (pciVID == ftdi->platform_data.vendor && pciPID == 2272a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->platform_data.device) { 2273a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 2274a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2275a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "vendor=%04X pciVID=%04X devi" 2276a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "ce=%04X pciPID=%04X\n", 2277a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->platform_data.vendor, pciVID, 2278a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->platform_data.device, pciPID); 2279a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 2280a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2281a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2282a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 2283a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 22844b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech 22854b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech#define ftdi_read_pcimem(ftdi, member, data) ftdi_elan_read_pcimem(ftdi, \ 22864b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech offsetof(struct ohci_regs, member), 0, data); 22874b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech#define ftdi_write_pcimem(ftdi, member, data) ftdi_elan_write_pcimem(ftdi, \ 22884b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech offsetof(struct ohci_regs, member), 0, data); 228947f8468e6008a1d62f7dacbcff4ec3e115a500c8David Brownell 22904b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR 22914b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech#define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \ 22924b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech OHCI_INTR_WDH) 22934b87361d49c04894458f4d4e80f9669abc894ae1Tony Olechstatic int ftdi_elan_check_controller(struct usb_ftdi *ftdi, int quirk) 22944b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech{ 22954b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech int devices = 0; 22964b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech int retval; 22974b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech u32 hc_control; 22984b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech int num_ports; 22994b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech u32 control; 23004b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech u32 rh_a = -1; 23014b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech u32 status; 23024b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech u32 fminterval; 23034b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech u32 hc_fminterval; 23044b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech u32 periodicstart; 23054b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech u32 cmdstatus; 23064b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech u32 roothub_a; 23074b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech int mask = OHCI_INTR_INIT; 23084b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech int sleep_time = 0; 23094b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech int reset_timeout = 30; /* ... allow extra time */ 23104b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech int temp; 23114b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_write_pcimem(ftdi, intrdisable, OHCI_INTR_MIE); 23124b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 23134b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 23144b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_read_pcimem(ftdi, control, &control); 23154b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 23164b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 23174b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_read_pcimem(ftdi, roothub.a, &rh_a); 23184b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 23194b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 23204b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech num_ports = rh_a & RH_A_NDP; 23214b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_read_pcimem(ftdi, fminterval, &hc_fminterval); 23224b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 23234b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 23244b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech hc_fminterval &= 0x3fff; 23254b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (hc_fminterval != FI) { 23264b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech } 23274b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech hc_fminterval |= FSMP(hc_fminterval) << 16; 23284b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_read_pcimem(ftdi, control, &hc_control); 23294b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 23304b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 23314b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech switch (hc_control & OHCI_CTRL_HCFS) { 23324b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech case OHCI_USB_OPER: 23334b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech sleep_time = 0; 23344b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech break; 23354b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech case OHCI_USB_SUSPEND: 23364b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech case OHCI_USB_RESUME: 23374b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech hc_control &= OHCI_CTRL_RWC; 23384b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech hc_control |= OHCI_USB_RESUME; 23394b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech sleep_time = 10; 23404b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech break; 23414b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech default: 23424b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech hc_control &= OHCI_CTRL_RWC; 23434b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech hc_control |= OHCI_USB_RESET; 23444b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech sleep_time = 50; 23454b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech break; 23464b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech } 23474b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_write_pcimem(ftdi, control, hc_control); 23484b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 23494b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 23504b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_read_pcimem(ftdi, control, &control); 23514b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 23524b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 23534b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech msleep(sleep_time); 23544b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a); 23554b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 23564b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 23574b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (!(roothub_a & RH_A_NPS)) { /* power down each port */ 23584b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech for (temp = 0; temp < num_ports; temp++) { 23594b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_write_pcimem(ftdi, 23604b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech roothub.portstatus[temp], RH_PS_LSDA); 23614b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 23624b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 23634b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech } 23644b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech } 23654b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_read_pcimem(ftdi, control, &control); 23664b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 23674b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 23684b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retry:retval = ftdi_read_pcimem(ftdi, cmdstatus, &status); 23694b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 23704b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 23714b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_HCR); 23724b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 23734b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 23744b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech extra:{ 23754b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_read_pcimem(ftdi, cmdstatus, &status); 23764b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 23774b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 23784b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (0 != (status & OHCI_HCR)) { 23794b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (--reset_timeout == 0) { 23804b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech dev_err(&ftdi->udev->dev, "USB HC reset timed o" 23814b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech "ut!\n"); 23824b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return -ENODEV; 23834b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech } else { 23844b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech msleep(5); 23854b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech goto extra; 23864b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech } 23874b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech } 23884b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech } 23894b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (quirk & OHCI_QUIRK_INITRESET) { 23904b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_write_pcimem(ftdi, control, hc_control); 23914b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 23924b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 23934b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_read_pcimem(ftdi, control, &control); 23944b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 23954b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 23964b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech } 23974b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_write_pcimem(ftdi, ed_controlhead, 0x00000000); 23984b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 23994b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 24004b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_write_pcimem(ftdi, ed_bulkhead, 0x11000000); 24014b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 24024b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 24034b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_write_pcimem(ftdi, hcca, 0x00000000); 24044b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 24054b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 24064b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval); 24074b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 24084b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 24094b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_write_pcimem(ftdi, fminterval, 24104b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech ((fminterval & FIT) ^ FIT) | hc_fminterval); 24114b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 24124b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 24134b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_write_pcimem(ftdi, periodicstart, 24144b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech ((9 *hc_fminterval) / 10) & 0x3fff); 24154b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 24164b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 24174b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval); 24184b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 24194b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 24204b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_read_pcimem(ftdi, periodicstart, &periodicstart); 24214b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 24224b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 24234b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) { 24244b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (!(quirk & OHCI_QUIRK_INITRESET)) { 24254b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech quirk |= OHCI_QUIRK_INITRESET; 24264b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech goto retry; 24274b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech } else 24284b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech dev_err(&ftdi->udev->dev, "init err(%08x %04x)\n", 24294b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech fminterval, periodicstart); 24304b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech } /* start controller operations */ 24314b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech hc_control &= OHCI_CTRL_RWC; 24324b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER; 24334b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_write_pcimem(ftdi, control, hc_control); 24344b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 24354b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 24364b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_BLF); 24374b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 24384b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 24394b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_read_pcimem(ftdi, cmdstatus, &cmdstatus); 24404b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 24414b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 24424b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_read_pcimem(ftdi, control, &control); 24434b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 24444b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 24454b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_DRWE); 24464b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 24474b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 24484b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_write_pcimem(ftdi, intrstatus, mask); 24494b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 24504b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 24514b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_write_pcimem(ftdi, intrdisable, 24524b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO | 24534b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH | 24544b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech OHCI_INTR_SO); 24554b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 24564b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; /* handle root hub init quirks ... */ 24574b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a); 24584b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 24594b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 24604b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech roothub_a &= ~(RH_A_PSM | RH_A_OCPM); 24614b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (quirk & OHCI_QUIRK_SUPERIO) { 24624b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech roothub_a |= RH_A_NOCP; 24634b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech roothub_a &= ~(RH_A_POTPGT | RH_A_NPS); 24644b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a); 24654b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 24664b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 24674b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech } else if ((quirk & OHCI_QUIRK_AMD756) || distrust_firmware) { 24684b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech roothub_a |= RH_A_NPS; 24694b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a); 24704b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 24714b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 24724b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech } 24734b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_LPSC); 24744b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 24754b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 24764b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_write_pcimem(ftdi, roothub.b, 24774b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM); 24784b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 24794b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 24804b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_read_pcimem(ftdi, control, &control); 24814b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 24824b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 24834b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech mdelay((roothub_a >> 23) & 0x1fe); 24844b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech for (temp = 0; temp < num_ports; temp++) { 24854b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech u32 portstatus; 24864b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech retval = ftdi_read_pcimem(ftdi, roothub.portstatus[temp], 24874b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech &portstatus); 24884b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (retval) 24894b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return retval; 24904b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (1 & portstatus) 24914b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech devices += 1; 24924b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech } 24934b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return devices; 24944b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech} 24954b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech 24964b87361d49c04894458f4d4e80f9669abc894ae1Tony Olechstatic int ftdi_elan_setup_controller(struct usb_ftdi *ftdi, int fn) 2497a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 2498a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u32 latence_timer; 2499a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int UxxxStatus; 2500a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u32 pcidata; 2501a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int reg = 0; 25024b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech int activePCIfn = fn << 8; 25034b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800); 2504a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2505a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 25064b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech reg = 16; 25074b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, 25084b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech 0xFFFFFFFF); 2509a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2510a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 25114b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, 25124b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech &pcidata); 2513a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2514a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 25154b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, 25164b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech 0xF0000000); 2517a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2518a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 25194b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, 25204b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech &pcidata); 2521a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2522a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 25234b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech reg = 12; 25244b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, 25254b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech &latence_timer); 2526a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2527a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 25284b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech latence_timer &= 0xFFFF00FF; 25294b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech latence_timer |= 0x00001600; 25304b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, 25314b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech latence_timer); 2532a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2533a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 25344b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, 25354b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech &pcidata); 2536a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2537a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 25384b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech reg = 4; 25394b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, 25404b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech 0x06); 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 for (reg = 0; reg <= 0x54; reg += 4) { 25484b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech UxxxStatus = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); 2549a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2550a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2551a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 25524b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return 0; 25534b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech} 25544b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech 25554b87361d49c04894458f4d4e80f9669abc894ae1Tony Olechstatic int ftdi_elan_close_controller(struct usb_ftdi *ftdi, int fn) 25564b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech{ 25574b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech u32 latence_timer; 25584b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech int UxxxStatus; 25594b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech u32 pcidata; 25604b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech int reg = 0; 25614b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech int activePCIfn = fn << 8; 2562a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800); 2563a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2564a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2565a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reg = 16; 2566a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, 2567a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 0xFFFFFFFF); 2568a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2569a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2570a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, 2571a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech &pcidata); 2572a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2573a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2574a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, 25754b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech 0x00000000); 2576a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2577a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2578a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, 2579a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech &pcidata); 2580a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2581a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2582a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reg = 12; 2583a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, 2584a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech &latence_timer); 2585a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2586a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2587a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech latence_timer &= 0xFFFF00FF; 2588a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech latence_timer |= 0x00001600; 2589a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, 2590a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech latence_timer); 2591a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2592a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2593a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, 2594a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech &pcidata); 2595a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2596a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2597a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reg = 4; 2598a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, 25994b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech 0x00); 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 return 0; 2607a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 2608a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 26094b87361d49c04894458f4d4e80f9669abc894ae1Tony Olechstatic int ftdi_elan_found_controller(struct usb_ftdi *ftdi, int fn, int quirk) 26104b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech{ 26114b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech int result; 26124b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech int UxxxStatus; 26134b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech UxxxStatus = ftdi_elan_setup_controller(ftdi, fn); 26144b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (UxxxStatus) 26154b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return UxxxStatus; 26164b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech result = ftdi_elan_check_controller(ftdi, quirk); 26174b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech UxxxStatus = ftdi_elan_close_controller(ftdi, fn); 26184b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (UxxxStatus) 26194b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return UxxxStatus; 26204b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return result; 26214b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech} 26224b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech 26234b87361d49c04894458f4d4e80f9669abc894ae1Tony Olechstatic int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi) 26244b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech{ 26254b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech u32 controlreg; 26264b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech u8 sensebits; 26274b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech int UxxxStatus; 26284b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); 26294b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (UxxxStatus) 26304b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return UxxxStatus; 26314b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000000L); 26324b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (UxxxStatus) 26334b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return UxxxStatus; 26344b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech msleep(750); 26354b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x100); 26364b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (UxxxStatus) 26374b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return UxxxStatus; 26384b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x500); 26394b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (UxxxStatus) 26404b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return UxxxStatus; 26414b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); 26424b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (UxxxStatus) 26434b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return UxxxStatus; 26444b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020CL | 0x000); 26454b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (UxxxStatus) 26464b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return UxxxStatus; 26474b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020DL | 0x000); 26484b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (UxxxStatus) 26494b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return UxxxStatus; 26504b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech msleep(250); 26514b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020FL | 0x000); 26524b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (UxxxStatus) 26534b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return UxxxStatus; 26544b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); 26554b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (UxxxStatus) 26564b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return UxxxStatus; 26574b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x800); 26584b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (UxxxStatus) 26594b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return UxxxStatus; 26604b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); 26614b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (UxxxStatus) 26624b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return UxxxStatus; 26634b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); 26644b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (UxxxStatus) 26654b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return UxxxStatus; 26664b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech msleep(1000); 26674b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech sensebits = (controlreg >> 16) & 0x000F; 26684b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (0x0D == sensebits) 26694b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return 0; 26704b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech else 26714b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return - ENXIO; 26724b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech} 26734b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech 2674a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi) 2675a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 26764b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech int UxxxStatus; 2677a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u32 pcidata; 26784b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech int reg = 0; 26794b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech u8 fn; 26804b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech int activePCIfn = 0; 26814b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech int max_devices = 0; 26824b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech int controllers = 0; 26834b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech int unrecognized = 0; 26844b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech ftdi->function = 0; 26854b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech for (fn = 0; (fn < 4); fn++) { 26864b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech u32 pciVID = 0; 26874b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech u32 pciPID = 0; 26884b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech int devices = 0; 26894b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech activePCIfn = fn << 8; 26904b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, 26914b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech &pcidata); 26924b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (UxxxStatus) 26934b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return UxxxStatus; 26944b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech pciVID = pcidata & 0xFFFF; 26954b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech pciPID = (pcidata >> 16) & 0xFFFF; 26964b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if ((pciVID == PCI_VENDOR_ID_OPTI) && (pciPID == 0xc861)) { 26974b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech devices = ftdi_elan_found_controller(ftdi, fn, 0); 26984b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech controllers += 1; 26994b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech } else if ((pciVID == PCI_VENDOR_ID_NEC) && (pciPID == 0x0035)) 27004b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech { 27014b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech devices = ftdi_elan_found_controller(ftdi, fn, 0); 27024b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech controllers += 1; 27034b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech } else if ((pciVID == PCI_VENDOR_ID_AL) && (pciPID == 0x5237)) { 27044b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech devices = ftdi_elan_found_controller(ftdi, fn, 0); 27054b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech controllers += 1; 27064b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech } else if ((pciVID == PCI_VENDOR_ID_ATT) && (pciPID == 0x5802)) 27074b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech { 27084b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech devices = ftdi_elan_found_controller(ftdi, fn, 0); 27094b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech controllers += 1; 27104b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech } else if (pciVID == PCI_VENDOR_ID_AMD && pciPID == 0x740c) { 27114b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech devices = ftdi_elan_found_controller(ftdi, fn, 27124b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech OHCI_QUIRK_AMD756); 27134b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech controllers += 1; 27144b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech } else if (pciVID == PCI_VENDOR_ID_COMPAQ && pciPID == 0xa0f8) { 27154b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech devices = ftdi_elan_found_controller(ftdi, fn, 27164b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech OHCI_QUIRK_ZFMICRO); 27174b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech controllers += 1; 27184b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech } else if (0 == pcidata) { 27194b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech } else 27204b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech unrecognized += 1; 27214b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (devices > max_devices) { 27224b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech max_devices = devices; 27234b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech ftdi->function = fn + 1; 27244b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech ftdi->platform_data.vendor = pciVID; 27254b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech ftdi->platform_data.device = pciPID; 2726a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2727a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 27284b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (ftdi->function > 0) { 27294b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech UxxxStatus = ftdi_elan_setup_controller(ftdi, 27304b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech ftdi->function - 1); 27314b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech if (UxxxStatus) 27324b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return UxxxStatus; 27334b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return 0; 27344b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech } else if (controllers > 0) { 27354b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return -ENXIO; 27364b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech } else if (unrecognized > 0) { 27374b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return -ENXIO; 27384b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech } else { 27394b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech ftdi->enumerated = 0; 27404b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech return -ENXIO; 2741a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2742a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 2743a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 2744a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 2745a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/* 2746a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* we use only the first bulk-in and bulk-out endpoints 2747a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/ 2748a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_probe(struct usb_interface *interface, 2749a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech const struct usb_device_id *id) 2750a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 2751a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_host_interface *iface_desc; 2752a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_endpoint_descriptor *endpoint; 2753a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech size_t buffer_size; 2754a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int i; 2755a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retval = -ENOMEM; 27565280d6083a77cc06a8c8360a2c461fd12d780fb8Mariusz Kozlowski struct usb_ftdi *ftdi; 27575280d6083a77cc06a8c8360a2c461fd12d780fb8Mariusz Kozlowski 27585280d6083a77cc06a8c8360a2c461fd12d780fb8Mariusz Kozlowski ftdi = kzalloc(sizeof(struct usb_ftdi), GFP_KERNEL); 27595280d6083a77cc06a8c8360a2c461fd12d780fb8Mariusz Kozlowski if (!ftdi) { 2760a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech printk(KERN_ERR "Out of memory\n"); 2761a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 2762a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 27635280d6083a77cc06a8c8360a2c461fd12d780fb8Mariusz Kozlowski 2764eb33caec1ed29fa2b04a2c5f02e3fed2add91db4Matthias Kaehlcke mutex_lock(&ftdi_module_lock); 2765a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech list_add_tail(&ftdi->ftdi_list, &ftdi_static_list); 2766a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->sequence_num = ++ftdi_instances; 2767eb33caec1ed29fa2b04a2c5f02e3fed2add91db4Matthias Kaehlcke mutex_unlock(&ftdi_module_lock); 2768a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_init_kref(ftdi); 2769a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech init_MUTEX(&ftdi->sw_lock); 2770a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->udev = usb_get_dev(interface_to_usbdev(interface)); 2771a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->interface = interface; 2772c93d46509e7aee7d58680c4c8a12cfbe98df98cbMatthias Kaehlcke mutex_init(&ftdi->u132_lock); 2773a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->expected = 4; 2774a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech iface_desc = interface->cur_altsetting; 2775a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { 2776a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech endpoint = &iface_desc->endpoint[i].desc; 2777a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!ftdi->bulk_in_endpointAddr && 27782ae7745beac6de54a47ed19fe441f1d45aa96172Luiz Fernando N. Capitulino usb_endpoint_is_bulk_in(endpoint)) { 2779a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); 2780a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_size = buffer_size; 2781a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_endpointAddr = endpoint->bEndpointAddress; 2782a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); 2783a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!ftdi->bulk_in_buffer) { 2784a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "Could not allocate b" 2785a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "ulk_in_buffer\n"); 2786a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = -ENOMEM; 2787a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto error; 2788a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2789a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2790a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!ftdi->bulk_out_endpointAddr && 27912ae7745beac6de54a47ed19fe441f1d45aa96172Luiz Fernando N. Capitulino usb_endpoint_is_bulk_out(endpoint)) { 2792a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_out_endpointAddr = 2793a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech endpoint->bEndpointAddress; 2794a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2795a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2796a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!(ftdi->bulk_in_endpointAddr && ftdi->bulk_out_endpointAddr)) { 2797a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "Could not find both bulk-in and bulk" 2798a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "-out endpoints\n"); 2799a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = -ENODEV; 2800a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto error; 2801a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2802a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_info(&ftdi->udev->dev, "interface %d has I=%02X O=%02X\n", 2803a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech iface_desc->desc.bInterfaceNumber, ftdi->bulk_in_endpointAddr, 2804a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_out_endpointAddr); 2805a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_set_intfdata(interface, ftdi); 2806a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (iface_desc->desc.bInterfaceNumber == 0 && 2807a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_endpointAddr == 0x81 && 2808a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_out_endpointAddr == 0x02) { 2809a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = usb_register_dev(interface, &ftdi_elan_jtag_class); 2810a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retval) { 2811a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "Not able to get a minor for " 2812a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "this device.\n"); 2813a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_set_intfdata(interface, NULL); 2814a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = -ENOMEM; 2815a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto error; 2816a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2817a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->class = &ftdi_elan_jtag_class; 2818a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_info(&ftdi->udev->dev, "USB FDTI=%p JTAG interface " 2819a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "%d now attached to ftdi%d\n", ftdi, 2820a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech iface_desc->desc.bInterfaceNumber, 2821a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech interface->minor); 2822a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 2823a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2824a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (iface_desc->desc.bInterfaceNumber == 1 && 2825a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_endpointAddr == 0x83 && 2826a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_out_endpointAddr == 0x04) { 2827a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->class = NULL; 2828a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_info(&ftdi->udev->dev, "USB FDTI=%p ELAN interface %d now a" 2829a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "ctivated\n", ftdi, iface_desc->desc.bInterfaceNumber); 2830c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells INIT_DELAYED_WORK(&ftdi->status_work, ftdi_elan_status_work); 2831c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells INIT_DELAYED_WORK(&ftdi->command_work, ftdi_elan_command_work); 2832c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells INIT_DELAYED_WORK(&ftdi->respond_work, ftdi_elan_respond_work); 2833a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_status_queue_work(ftdi, msecs_to_jiffies(3 *1000)); 2834a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 2835a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2836a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, 2837a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "Could not find ELAN's U132 device\n"); 2838a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = -ENODEV; 2839a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto error; 2840a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2841a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech error:if (ftdi) { 2842a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_put_kref(ftdi); 2843a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2844a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return retval; 2845a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 2846a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 2847a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_disconnect(struct usb_interface *interface) 2848a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 2849a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = usb_get_intfdata(interface); 2850a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->disconnected += 1; 2851a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi->class) { 2852a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int minor = interface->minor; 2853a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_class_driver *class = ftdi->class; 2854a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_set_intfdata(interface, NULL); 2855a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_deregister_dev(interface, class); 2856a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_info(&ftdi->udev->dev, "USB FTDI U132 jtag interface on min" 2857a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "or %d now disconnected\n", minor); 2858a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2859a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_status_cancel_work(ftdi); 2860a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_command_cancel_work(ftdi); 2861a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_response_cancel_work(ftdi); 2862a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_abandon_completions(ftdi); 2863a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_abandon_targets(ftdi); 2864a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi->registered) { 2865a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech platform_device_unregister(&ftdi->platform_dev); 2866a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->synchronized = 0; 2867a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->enumerated = 0; 28684b87361d49c04894458f4d4e80f9669abc894ae1Tony Olech ftdi->initialized = 0; 2869a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->registered = 0; 2870a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2871a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech flush_workqueue(status_queue); 2872a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech flush_workqueue(command_queue); 2873a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech flush_workqueue(respond_queue); 2874a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->disconnected += 1; 2875a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_set_intfdata(interface, NULL); 2876a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_info(&ftdi->udev->dev, "USB FTDI U132 host controller inter" 2877a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "face now disconnected\n"); 2878a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2879a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_put_kref(ftdi); 2880a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 2881a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 2882a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic struct usb_driver ftdi_elan_driver = { 2883a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .name = "ftdi-elan", 2884a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .probe = ftdi_elan_probe, 2885a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .disconnect = ftdi_elan_disconnect, 2886a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .id_table = ftdi_elan_table, 2887a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}; 2888a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int __init ftdi_elan_init(void) 2889a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 2890a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int result; 2891a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech printk(KERN_INFO "driver %s built at %s on %s\n", ftdi_elan_driver.name, 2892ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov __TIME__, __DATE__); 2893eb33caec1ed29fa2b04a2c5f02e3fed2add91db4Matthias Kaehlcke mutex_init(&ftdi_module_lock); 2894a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech INIT_LIST_HEAD(&ftdi_static_list); 2895a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech status_queue = create_singlethread_workqueue("ftdi-status-control"); 2896ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov if (!status_queue) 2897893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov goto err_status_queue; 2898a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_queue = create_singlethread_workqueue("ftdi-command-engine"); 2899ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov if (!command_queue) 2900893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov goto err_command_queue; 2901a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond_queue = create_singlethread_workqueue("ftdi-respond-engine"); 2902ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov if (!respond_queue) 2903893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov goto err_respond_queue; 2904a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech result = usb_register(&ftdi_elan_driver); 2905893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov if (result) { 2906893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov destroy_workqueue(status_queue); 2907893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov destroy_workqueue(command_queue); 2908893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov destroy_workqueue(respond_queue); 2909a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech printk(KERN_ERR "usb_register failed. Error number %d\n", 2910ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov result); 2911893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov } 2912a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return result; 2913ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov 2914893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov err_respond_queue: 2915ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov destroy_workqueue(command_queue); 2916893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov err_command_queue: 2917ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov destroy_workqueue(status_queue); 2918893a342a686e6ce36ef24d322f3f52420a041313Cyrill Gorcunov err_status_queue: 2919ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov printk(KERN_ERR "%s couldn't create workqueue\n", ftdi_elan_driver.name); 2920ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20Cyrill Gorcunov return -ENOMEM; 2921a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 2922a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 2923a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void __exit ftdi_elan_exit(void) 2924a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 2925a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi; 2926a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *temp; 2927a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_deregister(&ftdi_elan_driver); 2928a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech printk(KERN_INFO "ftdi_u132 driver deregistered\n"); 2929a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech list_for_each_entry_safe(ftdi, temp, &ftdi_static_list, ftdi_list) { 2930a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_status_cancel_work(ftdi); 2931a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_command_cancel_work(ftdi); 2932a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_response_cancel_work(ftdi); 2933a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } flush_workqueue(status_queue); 2934a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech destroy_workqueue(status_queue); 2935a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech status_queue = NULL; 2936a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech flush_workqueue(command_queue); 2937a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech destroy_workqueue(command_queue); 2938a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_queue = NULL; 2939a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech flush_workqueue(respond_queue); 2940a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech destroy_workqueue(respond_queue); 2941a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond_queue = NULL; 2942a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 2943a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 2944a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 2945a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechmodule_init(ftdi_elan_init); 2946a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechmodule_exit(ftdi_elan_exit); 2947