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