ftdi-elan.c revision 2ae7745beac6de54a47ed19fe441f1d45aa96172
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> 43a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#include <linux/slab.h> 44a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#include <linux/module.h> 45a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#include <linux/kref.h> 46a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#include <asm/uaccess.h> 47a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#include <linux/usb.h> 48a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#include <linux/workqueue.h> 49a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#include <linux/platform_device.h> 50a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechMODULE_AUTHOR("Tony Olech"); 51a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechMODULE_DESCRIPTION("FTDI ELAN driver"); 52a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechMODULE_LICENSE("GPL"); 53a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444) 54a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechextern struct platform_driver u132_platform_driver; 55a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic struct workqueue_struct *status_queue; 56a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic struct workqueue_struct *command_queue; 57a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic struct workqueue_struct *respond_queue; 58a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/* 59a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* ftdi_module_lock exists to protect access to global variables 60a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* 61a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/ 62a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic struct semaphore ftdi_module_lock; 63a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_instances = 0; 64a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic struct list_head ftdi_static_list; 65a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/* 66a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* end of the global variables protected by ftdi_module_lock 67a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/ 68a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#include "usb_u132.h" 69a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define TD_DEVNOTRESP 5 70a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/* Define these values to match your devices*/ 71a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define USB_FTDI_ELAN_VENDOR_ID 0x0403 72a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define USB_FTDI_ELAN_PRODUCT_ID 0xd6ea 73a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/* table of devices that work with this driver*/ 74a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic struct usb_device_id ftdi_elan_table[] = { 75a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech {USB_DEVICE(USB_FTDI_ELAN_VENDOR_ID, USB_FTDI_ELAN_PRODUCT_ID)}, 76a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech { /* Terminating entry */ } 77a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}; 78a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 79a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechMODULE_DEVICE_TABLE(usb, ftdi_elan_table); 80a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/* only the jtag(firmware upgrade device) interface requires 81a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* a device file and corresponding minor number, but the 82a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* interface is created unconditionally - I suppose it could 83a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* be configured or not according to a module parameter. 84a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* But since we(now) require one interface per device, 85a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* and since it unlikely that a normal installation would 86a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* require more than a couple of elan-ftdi devices, 8 seems 87a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* like a reasonable limit to have here, and if someone 88a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* really requires more than 8 devices, then they can frig the 89a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* code and recompile 90a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/ 91a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define USB_FTDI_ELAN_MINOR_BASE 192 92a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define COMMAND_BITS 5 93a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define COMMAND_SIZE (1<<COMMAND_BITS) 94a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define COMMAND_MASK (COMMAND_SIZE-1) 95a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstruct u132_command { 96a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 header; 97a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u16 length; 98a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 address; 99a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 width; 100a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u32 value; 101a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int follows; 102a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void *buffer; 103a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}; 104a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define RESPOND_BITS 5 105a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define RESPOND_SIZE (1<<RESPOND_BITS) 106a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define RESPOND_MASK (RESPOND_SIZE-1) 107a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstruct u132_respond { 108a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 header; 109a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 address; 110a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u32 *value; 111a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int *result; 112a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct completion wait_completion; 113a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}; 114a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstruct u132_target { 115a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void *endp; 116a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct urb *urb; 117a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int toggle_bits; 118a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int error_count; 119a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int condition_code; 120a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int repeat_number; 121a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int halted; 122a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int skipped; 123a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int actual; 124a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int non_null; 125a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int active; 126a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int abandoning; 127a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, 128a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int toggle_bits, int error_count, int condition_code, 129a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int repeat_number, int halted, int skipped, int actual, 130a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int non_null); 131a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}; 132a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/* Structure to hold all of our device specific stuff*/ 133a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstruct usb_ftdi { 134a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct list_head ftdi_list; 135a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct semaphore u132_lock; 136a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_next; 137a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_head; 138a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command command[COMMAND_SIZE]; 139a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int respond_next; 140a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int respond_head; 141a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_respond respond[RESPOND_SIZE]; 142a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_target target[4]; 143a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char device_name[16]; 144a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech unsigned synchronized:1; 145a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech unsigned enumerated:1; 146a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech unsigned registered:1; 147a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech unsigned initialized:1; 148a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech unsigned card_ejected:1; 149a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int function; 150a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int sequence_num; 151a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int disconnected; 152a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int gone_away; 153a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int stuck_status; 154a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int status_queue_delay; 155a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct semaphore sw_lock; 156a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_device *udev; 157a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_interface *interface; 158a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_class_driver *class; 159a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct work_struct status_work; 160a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct work_struct command_work; 161a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct work_struct respond_work; 162a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_platform_data platform_data; 163a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct resource resources[0]; 164a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct platform_device platform_dev; 165a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech unsigned char *bulk_in_buffer; 166a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech size_t bulk_in_size; 167a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech size_t bulk_in_last; 168a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech size_t bulk_in_left; 169a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech __u8 bulk_in_endpointAddr; 170a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech __u8 bulk_out_endpointAddr; 171a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct kref kref; 172a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u32 controlreg; 173a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 response[4 + 1024]; 174a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int expected; 175a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int recieved; 176a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int ed_found; 177a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}; 178a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define kref_to_usb_ftdi(d) container_of(d, struct usb_ftdi, kref) 179a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define platform_device_to_usb_ftdi(d) container_of(d, struct usb_ftdi, \ 180a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech platform_dev) 181a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic struct usb_driver ftdi_elan_driver; 182a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_delete(struct kref *kref) 183a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 184a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = kref_to_usb_ftdi(kref); 185a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_warn(&ftdi->udev->dev, "FREEING ftdi=%p\n", ftdi); 186a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_put_dev(ftdi->udev); 187a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->disconnected += 1; 188a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech down(&ftdi_module_lock); 189a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech list_del_init(&ftdi->ftdi_list); 190a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_instances -= 1; 191a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi_module_lock); 192a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech kfree(ftdi->bulk_in_buffer); 193a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_buffer = NULL; 194a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 195a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 196a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_put_kref(struct usb_ftdi *ftdi) 197a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 198a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech kref_put(&ftdi->kref, ftdi_elan_delete); 199a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 200a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 201a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_get_kref(struct usb_ftdi *ftdi) 202a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 203a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech kref_get(&ftdi->kref); 204a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 205a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 206a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_init_kref(struct usb_ftdi *ftdi) 207a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 208a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech kref_init(&ftdi->kref); 209a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 210a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 211a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_status_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) 212a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 213a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (delta > 0) { 214a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (queue_delayed_work(status_queue, &ftdi->status_work, delta)) 215a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return; 216a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (queue_work(status_queue, &ftdi->status_work)) 217a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return; 218a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech kref_put(&ftdi->kref, ftdi_elan_delete); 219a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return; 220a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 221a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 222a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_status_queue_work(struct usb_ftdi *ftdi, unsigned int delta) 223a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 224a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (delta > 0) { 225a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (queue_delayed_work(status_queue, &ftdi->status_work, delta)) 226a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech kref_get(&ftdi->kref); 227a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (queue_work(status_queue, &ftdi->status_work)) 228a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech kref_get(&ftdi->kref); 229a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return; 230a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 231a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 232a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_status_cancel_work(struct usb_ftdi *ftdi) 233a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 234a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (cancel_delayed_work(&ftdi->status_work)) 235a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech kref_put(&ftdi->kref, ftdi_elan_delete); 236a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 237a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 238a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_command_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) 239a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 240a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (delta > 0) { 241a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (queue_delayed_work(command_queue, &ftdi->command_work, 242a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech delta)) 243a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return; 244a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (queue_work(command_queue, &ftdi->command_work)) 245a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return; 246a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech kref_put(&ftdi->kref, ftdi_elan_delete); 247a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return; 248a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 249a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 250a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_command_queue_work(struct usb_ftdi *ftdi, unsigned int delta) 251a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 252a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (delta > 0) { 253a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (queue_delayed_work(command_queue, &ftdi->command_work, 254a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech delta)) 255a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech kref_get(&ftdi->kref); 256a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (queue_work(command_queue, &ftdi->command_work)) 257a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech kref_get(&ftdi->kref); 258a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return; 259a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 260a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 261a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_command_cancel_work(struct usb_ftdi *ftdi) 262a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 263a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (cancel_delayed_work(&ftdi->command_work)) 264a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech kref_put(&ftdi->kref, ftdi_elan_delete); 265a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 266a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 267a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_response_requeue_work(struct usb_ftdi *ftdi, 268a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech unsigned int delta) 269a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 270a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (delta > 0) { 271a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (queue_delayed_work(respond_queue, &ftdi->respond_work, 272a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech delta)) 273a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return; 274a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (queue_work(respond_queue, &ftdi->respond_work)) 275a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return; 276a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech kref_put(&ftdi->kref, ftdi_elan_delete); 277a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return; 278a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 279a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 280a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_respond_queue_work(struct usb_ftdi *ftdi, unsigned int delta) 281a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 282a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (delta > 0) { 283a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (queue_delayed_work(respond_queue, &ftdi->respond_work, 284a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech delta)) 285a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech kref_get(&ftdi->kref); 286a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (queue_work(respond_queue, &ftdi->respond_work)) 287a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech kref_get(&ftdi->kref); 288a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return; 289a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 290a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 291a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_response_cancel_work(struct usb_ftdi *ftdi) 292a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 293a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (cancel_delayed_work(&ftdi->respond_work)) 294a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech kref_put(&ftdi->kref, ftdi_elan_delete); 295a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 296a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 297a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechvoid ftdi_elan_gone_away(struct platform_device *pdev) 298a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 299a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); 300a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->gone_away += 1; 301a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_put_kref(ftdi); 302a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 303a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 304a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 305a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechEXPORT_SYMBOL_GPL(ftdi_elan_gone_away); 306a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechvoid ftdi_release_platform_dev(struct device *dev) 307a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 308a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev->parent = NULL; 309a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 310a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 311a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_do_callback(struct usb_ftdi *ftdi, 312a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_target *target, u8 *buffer, int length); 313a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi); 314a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi); 315a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi); 316a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi); 317a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi); 318a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_synchronize(struct usb_ftdi *ftdi); 319a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_stuck_waiting(struct usb_ftdi *ftdi); 320a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_command_engine(struct usb_ftdi *ftdi); 321a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_respond_engine(struct usb_ftdi *ftdi); 322a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_hcd_init(struct usb_ftdi *ftdi) 323a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 324a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int result; 325a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi->platform_dev.dev.parent) 326a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -EBUSY; 327a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_get_kref(ftdi); 328a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->platform_data.potpg = 100; 329a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->platform_data.reset = NULL; 330a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->platform_dev.id = ftdi->sequence_num; 331a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->platform_dev.resource = ftdi->resources; 332a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->platform_dev.num_resources = ARRAY_SIZE(ftdi->resources); 333a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->platform_dev.dev.platform_data = &ftdi->platform_data; 334a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->platform_dev.dev.parent = NULL; 335a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->platform_dev.dev.release = ftdi_release_platform_dev; 336a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->platform_dev.dev.dma_mask = NULL; 337a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech snprintf(ftdi->device_name, sizeof(ftdi->device_name), "u132_hcd"); 338a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->platform_dev.name = ftdi->device_name; 339a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_info(&ftdi->udev->dev, "requesting module '%s'\n", "u132_hcd"); 340a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech request_module("u132_hcd"); 341a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_info(&ftdi->udev->dev, "registering '%s'\n", 342a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->platform_dev.name); 343a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech result = platform_device_register(&ftdi->platform_dev); 344a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return result; 345a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 346a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 347a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_abandon_completions(struct usb_ftdi *ftdi) 348a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 349a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech down(&ftdi->u132_lock); 350a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech while (ftdi->respond_next > ftdi->respond_head) { 351a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_respond *respond = &ftdi->respond[RESPOND_MASK & 352a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->respond_head++]; 353a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech *respond->result = -ESHUTDOWN; 354a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech *respond->value = 0; 355a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech complete(&respond->wait_completion); 356a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } up(&ftdi->u132_lock); 357a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 358a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 359a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_abandon_targets(struct usb_ftdi *ftdi) 360a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 361a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int ed_number = 4; 362a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech down(&ftdi->u132_lock); 363a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech while (ed_number-- > 0) { 364a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_target *target = &ftdi->target[ed_number]; 365a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (target->active == 1) { 366a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->condition_code = TD_DEVNOTRESP; 367a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 368a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_do_callback(ftdi, target, NULL, 0); 369a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech down(&ftdi->u132_lock); 370a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 371a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 372a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->recieved = 0; 373a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->expected = 4; 374a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->ed_found = 0; 375a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 376a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 377a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 378a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_flush_targets(struct usb_ftdi *ftdi) 379a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 380a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int ed_number = 4; 381a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech down(&ftdi->u132_lock); 382a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech while (ed_number-- > 0) { 383a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_target *target = &ftdi->target[ed_number]; 384a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->abandoning = 1; 385a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait_1:if (target->active == 1) { 386a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_size = ftdi->command_next - 387a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_head; 388a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command_size < COMMAND_SIZE) { 389a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = &ftdi->command[ 390a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech COMMAND_MASK & ftdi->command_next]; 391a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->header = 0x80 | (ed_number << 5) | 0x4; 392a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x00; 393a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->address = 0x00; 394a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->width = 0x00; 395a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->follows = 0; 396a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->value = 0; 397a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->buffer = &command->value; 398a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_next += 1; 399a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_kick_command_queue(ftdi); 400a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 401a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 402a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 403a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech down(&ftdi->u132_lock); 404a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto wait_1; 405a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 406a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 407a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait_2:if (target->active == 1) { 408a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_size = ftdi->command_next - 409a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_head; 410a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command_size < COMMAND_SIZE) { 411a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = &ftdi->command[ 412a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech COMMAND_MASK & ftdi->command_next]; 413a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->header = 0x90 | (ed_number << 5); 414a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x00; 415a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->address = 0x00; 416a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->width = 0x00; 417a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->follows = 0; 418a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->value = 0; 419a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->buffer = &command->value; 420a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_next += 1; 421a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_kick_command_queue(ftdi); 422a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 423a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 424a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 425a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech down(&ftdi->u132_lock); 426a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto wait_2; 427a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 428a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 429a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 430a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->recieved = 0; 431a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->expected = 4; 432a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->ed_found = 0; 433a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 434a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 435a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 436a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_cancel_targets(struct usb_ftdi *ftdi) 437a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 438a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int ed_number = 4; 439a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech down(&ftdi->u132_lock); 440a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech while (ed_number-- > 0) { 441a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_target *target = &ftdi->target[ed_number]; 442a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->abandoning = 1; 443a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait:if (target->active == 1) { 444a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_size = ftdi->command_next - 445a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_head; 446a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command_size < COMMAND_SIZE) { 447a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = &ftdi->command[ 448a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech COMMAND_MASK & ftdi->command_next]; 449a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->header = 0x80 | (ed_number << 5) | 0x4; 450a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x00; 451a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->address = 0x00; 452a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->width = 0x00; 453a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->follows = 0; 454a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->value = 0; 455a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->buffer = &command->value; 456a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_next += 1; 457a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_kick_command_queue(ftdi); 458a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 459a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 460a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 461a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech down(&ftdi->u132_lock); 462a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto wait; 463a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 464a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 465a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 466a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->recieved = 0; 467a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->expected = 4; 468a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->ed_found = 0; 469a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 470a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 471a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 472a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi) 473a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 474a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_command_queue_work(ftdi, 0); 475a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return; 476a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 477a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 478a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_command_work(void *data) 479a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 480a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = data; 481a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi->disconnected > 0) { 482a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_put_kref(ftdi); 483a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return; 484a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 485a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retval = ftdi_elan_command_engine(ftdi); 486a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retval == -ESHUTDOWN) { 487a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->disconnected += 1; 488a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retval == -ENODEV) { 489a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->disconnected += 1; 490a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retval) 491a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "command error %d\n", retval); 492a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_command_requeue_work(ftdi, msecs_to_jiffies(10)); 493a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return; 494a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 495a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 496a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 497a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi) 498a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 499a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_respond_queue_work(ftdi, 0); 500a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return; 501a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 502a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 503a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_respond_work(void *data) 504a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 505a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = data; 506a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi->disconnected > 0) { 507a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_put_kref(ftdi); 508a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return; 509a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 510a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retval = ftdi_elan_respond_engine(ftdi); 511a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retval == 0) { 512a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retval == -ESHUTDOWN) { 513a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->disconnected += 1; 514a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retval == -ENODEV) { 515a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->disconnected += 1; 516a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retval == -EILSEQ) { 517a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->disconnected += 1; 518a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 519a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->disconnected += 1; 520a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "respond error %d\n", retval); 521a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 522a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi->disconnected > 0) { 523a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_abandon_completions(ftdi); 524a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_abandon_targets(ftdi); 525a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 526a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_response_requeue_work(ftdi, msecs_to_jiffies(10)); 527a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return; 528a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 529a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 530a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 531a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 532a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/* 533a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* the sw_lock is initially held and will be freed 534a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* after the FTDI has been synchronized 535a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* 536a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/ 537a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_status_work(void *data) 538a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 539a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = data; 540a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int work_delay_in_msec = 0; 541a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi->disconnected > 0) { 542a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_put_kref(ftdi); 543a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return; 544a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (ftdi->synchronized == 0) { 545a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech down(&ftdi->sw_lock); 546a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi_elan_synchronize(ftdi) == 0) { 547a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->synchronized = 1; 548a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_command_queue_work(ftdi, 1); 549a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_respond_queue_work(ftdi, 1); 550a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->sw_lock); 551a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech work_delay_in_msec = 100; 552a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 553a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "synchronize failed\n"); 554a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->sw_lock); 555a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech work_delay_in_msec = 10 *1000; 556a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 557a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (ftdi->stuck_status > 0) { 558a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi_elan_stuck_waiting(ftdi) == 0) { 559a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->stuck_status = 0; 560a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->synchronized = 0; 561a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if ((ftdi->stuck_status++ % 60) == 1) { 562a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "WRONG type of card inserted " 563a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "- please remove\n"); 564a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 565a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "WRONG type of card inserted " 566a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "- checked %d times\n", ftdi->stuck_status); 567a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech work_delay_in_msec = 100; 568a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (ftdi->enumerated == 0) { 569a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi_elan_enumeratePCI(ftdi) == 0) { 570a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->enumerated = 1; 571a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech work_delay_in_msec = 250; 572a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 573a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech work_delay_in_msec = 1000; 574a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (ftdi->initialized == 0) { 575a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi_elan_setupOHCI(ftdi) == 0) { 576a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->initialized = 1; 577a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech work_delay_in_msec = 500; 578a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 579a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "initialized failed - trying " 580a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "again in 10 seconds\n"); 581a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech work_delay_in_msec = 10 *1000; 582a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 583a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (ftdi->registered == 0) { 584a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech work_delay_in_msec = 10; 585a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi_elan_hcd_init(ftdi) == 0) { 586a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->registered = 1; 587a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 588a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "register failed\n"); 589a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech work_delay_in_msec = 250; 590a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 591a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi_elan_checkingPCI(ftdi) == 0) { 592a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech work_delay_in_msec = 250; 593a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (ftdi->controlreg & 0x00400000) { 594a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi->gone_away > 0) { 595a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "PCI device eject con" 596a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "firmed platform_dev.dev.parent=%p plat" 597a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "form_dev.dev=%p\n", 598a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->platform_dev.dev.parent, 599a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech &ftdi->platform_dev.dev); 600a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech platform_device_unregister(&ftdi->platform_dev); 601a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->platform_dev.dev.parent = NULL; 602a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->registered = 0; 603a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->enumerated = 0; 604a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->card_ejected = 0; 605a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->initialized = 0; 606a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->gone_away = 0; 607a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 608a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_flush_targets(ftdi); 609a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech work_delay_in_msec = 250; 610a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 611a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "PCI device has disappeared\n" 612a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ); 613a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_cancel_targets(ftdi); 614a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech work_delay_in_msec = 500; 615a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->enumerated = 0; 616a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->initialized = 0; 617a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 618a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 619a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi->disconnected > 0) { 620a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_put_kref(ftdi); 621a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return; 622a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 623a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_status_requeue_work(ftdi, 624a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msecs_to_jiffies(work_delay_in_msec)); 625a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return; 626a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 627a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 628a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 629a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 630a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/* 631a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* file_operations for the jtag interface 632a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* 633a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* the usage count for the device is incremented on open() 634a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* and decremented on release() 635a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/ 636a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_open(struct inode *inode, struct file *file) 637a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 638a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int subminor = iminor(inode); 639a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_interface *interface = usb_find_interface(&ftdi_elan_driver, 640a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech subminor); 641a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!interface) { 642a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech printk(KERN_ERR "can't find device for minor %d\n", subminor); 643a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 644a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 645a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = usb_get_intfdata(interface); 646a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!ftdi) { 647a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 648a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 649a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (down_interruptible(&ftdi->sw_lock)) { 650a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -EINTR; 651a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 652a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_get_kref(ftdi); 653a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech file->private_data = ftdi; 654a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 655a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 656a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 657a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 658a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 659a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 660a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_release(struct inode *inode, struct file *file) 661a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 662a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = (struct usb_ftdi *)file->private_data; 663a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi == NULL) 664a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 665a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->sw_lock); /* decrement the count on our device */ 666a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_put_kref(ftdi); 667a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 668a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 669a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 670a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 671a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define FTDI_ELAN_IOC_MAGIC 0xA1 672a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define FTDI_ELAN_IOCDEBUG _IOC(_IOC_WRITE, FTDI_ELAN_IOC_MAGIC, 1, 132) 673a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_ioctl(struct inode *inode, struct file *file, 674a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech unsigned int cmd, unsigned long arg) 675a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 676a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech switch (cmd) { 677a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech case FTDI_ELAN_IOCDEBUG:{ 678a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char line[132]; 679a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int size = strncpy_from_user(line, 680a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech (const char __user *)arg, sizeof(line)); 681a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (size < 0) { 682a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -EINVAL; 683a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 684a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech printk(KERN_ERR "TODO: ioctl %s\n", line); 685a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 686a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 687a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 688a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech default: 689a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -EFAULT; 690a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 691a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 692a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 693a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 694a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/* 695a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* 696a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* blocking bulk reads are used to get data from the device 697a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* 698a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/ 699a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic ssize_t ftdi_elan_read(struct file *file, char __user *buffer, 700a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech size_t count, loff_t *ppos) 701a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 702a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char data[30 *3 + 4]; 703a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *d = data; 704a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int m = (sizeof(data) - 1) / 3; 705a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int bytes_read = 0; 706a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retry_on_empty = 10; 707a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retry_on_timeout = 5; 708a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = (struct usb_ftdi *)file->private_data; 709a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi->disconnected > 0) { 710a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 711a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 712a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech data[0] = 0; 713a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech have:if (ftdi->bulk_in_left > 0) { 714a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (count-- > 0) { 715a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *p = ++ftdi->bulk_in_last + ftdi->bulk_in_buffer; 716a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_left -= 1; 717a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (bytes_read < m) { 718a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " %02X", 0x000000FF & *p); 719a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (bytes_read > m) { 720a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 721a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " .."); 722a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (copy_to_user(buffer++, p, 1)) { 723a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -EFAULT; 724a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 725a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech bytes_read += 1; 726a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto have; 727a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 728a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 729a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return bytes_read; 730a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 731a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech more:if (count > 0) { 732a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int packet_bytes = 0; 733a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retval = usb_bulk_msg(ftdi->udev, 734a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), 735a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_buffer, ftdi->bulk_in_size, 736a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech &packet_bytes, msecs_to_jiffies(50)); 737a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (packet_bytes > 2) { 738a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_left = packet_bytes - 2; 739a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_last = 1; 740a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto have; 741a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retval == -ETIMEDOUT) { 742a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_timeout-- > 0) { 743a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 744a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (bytes_read > 0) { 745a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return bytes_read; 746a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 747a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return retval; 748a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retval == 0) { 749a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_empty-- > 0) { 750a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 751a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 752a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return bytes_read; 753a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 754a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return retval; 755a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 756a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return bytes_read; 757a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 758a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 7597d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void ftdi_elan_write_bulk_callback(struct urb *urb) 760a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 761a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = (struct usb_ftdi *)urb->context; 762a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (urb->status && !(urb->status == -ENOENT || urb->status == 763a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech -ECONNRESET || urb->status == -ESHUTDOWN)) { 764a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "urb=%p write bulk status received: %" 765a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "d\n", urb, urb->status); 766a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 767a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_buffer_free(urb->dev, urb->transfer_buffer_length, 768a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb->transfer_buffer, urb->transfer_dma); 769a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 770a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 771a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int fill_buffer_with_all_queued_commands(struct usb_ftdi *ftdi, 772a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *buf, int command_size, int total_size) 773a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 774a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int ed_commands = 0; 775a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int b = 0; 776a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int I = command_size; 777a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int i = ftdi->command_head; 778a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech while (I-- > 0) { 779a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = &ftdi->command[COMMAND_MASK & 780a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech i++]; 781a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int F = command->follows; 782a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 *f = command->buffer; 783a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command->header & 0x80) { 784a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ed_commands |= 1 << (0x3 & (command->header >> 5)); 785a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 786a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf[b++] = command->header; 787a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf[b++] = (command->length >> 0) & 0x00FF; 788a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf[b++] = (command->length >> 8) & 0x00FF; 789a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf[b++] = command->address; 790a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf[b++] = command->width; 791a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech while (F-- > 0) { 792a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf[b++] = *f++; 793a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 794a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 795a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return ed_commands; 796a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 797a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 798a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_total_command_size(struct usb_ftdi *ftdi, int command_size) 799a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 800a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int total_size = 0; 801a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int I = command_size; 802a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int i = ftdi->command_head; 803a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech while (I-- > 0) { 804a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = &ftdi->command[COMMAND_MASK & 805a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech i++]; 806a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech total_size += 5 + command->follows; 807a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } return total_size; 808a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 809a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 810a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_command_engine(struct usb_ftdi *ftdi) 811a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 812a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retval; 813a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *buf; 814a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int ed_commands; 815a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int total_size; 816a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct urb *urb; 817a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_size = ftdi->command_next - ftdi->command_head; 818a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command_size == 0) 819a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 820a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech total_size = ftdi_elan_total_command_size(ftdi, command_size); 821a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb = usb_alloc_urb(0, GFP_KERNEL); 822a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!urb) { 823a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "could not get a urb to write %d comm" 824a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "ands totaling %d bytes to the Uxxx\n", command_size, 825a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech total_size); 826a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 827a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 828a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf = usb_buffer_alloc(ftdi->udev, total_size, GFP_KERNEL, 829a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech &urb->transfer_dma); 830a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!buf) { 831a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "could not get a buffer to write %d c" 832a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "ommands totaling %d bytes to the Uxxx\n", command_size, 833a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech total_size); 834a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_free_urb(urb); 835a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 836a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 837a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ed_commands = fill_buffer_with_all_queued_commands(ftdi, buf, 838a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_size, total_size); 839a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, 840a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_out_endpointAddr), buf, total_size, 841a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_write_bulk_callback, ftdi); 842a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 843a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ed_commands) { 844a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char diag[40 *3 + 4]; 845a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *d = diag; 846a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int m = total_size; 847a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 *c = buf; 848a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int s = (sizeof(diag) - 1) / 3; 849a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech diag[0] = 0; 850a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech while (s-- > 0 && m-- > 0) { 851a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (s > 0 || m == 0) { 852a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " %02X", *c++); 853a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 854a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " .."); 855a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 856a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 857a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = usb_submit_urb(urb, GFP_KERNEL); 858a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retval) { 859a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "failed %d to submit urb %p to write " 860a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "%d commands totaling %d bytes to the Uxxx\n", retval, 861a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb, command_size, total_size); 862a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_buffer_free(ftdi->udev, total_size, buf, urb->transfer_dma); 863a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_free_urb(urb); 864a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return retval; 865a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 866a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_free_urb(urb); /* release our reference to this urb, 867a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech the USB core will eventually free it entirely */ 868a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_head += command_size; 869a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_kick_respond_queue(ftdi); 870a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 871a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 872a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 873a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_do_callback(struct usb_ftdi *ftdi, 874a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_target *target, u8 *buffer, int length) 875a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 876a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct urb *urb = target->urb; 877a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int halted = target->halted; 878a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int skipped = target->skipped; 879a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int actual = target->actual; 880a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int non_null = target->non_null; 881a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int toggle_bits = target->toggle_bits; 882a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int error_count = target->error_count; 883a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int condition_code = target->condition_code; 884a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int repeat_number = target->repeat_number; 885a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void (*callback) (void *, struct urb *, u8 *, int, int, int, int, int, 886a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int, int, int, int) = target->callback; 887a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->active -= 1; 888a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->callback = NULL; 889a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech (*callback) (target->endp, urb, buffer, length, toggle_bits, 890a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech error_count, condition_code, repeat_number, halted, skipped, 891a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech actual, non_null); 892a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 893a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 894a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic char *have_ed_set_response(struct usb_ftdi *ftdi, 895a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_target *target, u16 ed_length, int ed_number, int ed_type, 896a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *b) 897a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 898a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int payload = (ed_length >> 0) & 0x07FF; 899a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech down(&ftdi->u132_lock); 900a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->actual = 0; 901a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->non_null = (ed_length >> 15) & 0x0001; 902a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->repeat_number = (ed_length >> 11) & 0x000F; 903a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ed_type == 0x02) { 904a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (payload == 0 || target->abandoning > 0) { 905a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->abandoning = 0; 906a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 907a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, 908a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech payload); 909a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->recieved = 0; 910a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->expected = 4; 911a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->ed_found = 0; 912a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return ftdi->response; 913a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 914a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->expected = 4 + payload; 915a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->ed_found = 1; 916a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 917a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return b; 918a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 919a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (ed_type == 0x03) { 920a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (payload == 0 || target->abandoning > 0) { 921a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->abandoning = 0; 922a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 923a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, 924a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech payload); 925a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->recieved = 0; 926a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->expected = 4; 927a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->ed_found = 0; 928a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return ftdi->response; 929a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 930a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->expected = 4 + payload; 931a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->ed_found = 1; 932a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 933a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return b; 934a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 935a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (ed_type == 0x01) { 936a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->abandoning = 0; 937a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 938a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, 939a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech payload); 940a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->recieved = 0; 941a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->expected = 4; 942a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->ed_found = 0; 943a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return ftdi->response; 944a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 945a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->abandoning = 0; 946a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 947a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, 948a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech payload); 949a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->recieved = 0; 950a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->expected = 4; 951a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->ed_found = 0; 952a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return ftdi->response; 953a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 954a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 955a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 956a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic char *have_ed_get_response(struct usb_ftdi *ftdi, 957a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_target *target, u16 ed_length, int ed_number, int ed_type, 958a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *b) 959a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 960a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech down(&ftdi->u132_lock); 961a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->condition_code = TD_DEVNOTRESP; 962a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->actual = (ed_length >> 0) & 0x01FF; 963a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->non_null = (ed_length >> 15) & 0x0001; 964a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->repeat_number = (ed_length >> 11) & 0x000F; 965a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 966a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (target->active) 967a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_do_callback(ftdi, target, NULL, 0); 968a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->abandoning = 0; 969a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->recieved = 0; 970a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->expected = 4; 971a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->ed_found = 0; 972a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return ftdi->response; 973a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 974a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 975a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 976a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/* 977a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* The engine tries to empty the FTDI fifo 978a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* 979a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* all responses found in the fifo data are dispatched thus 980a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* the response buffer can only ever hold a maximum sized 981a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* response from the Uxxx. 982a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* 983a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/ 984a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_respond_engine(struct usb_ftdi *ftdi) 985a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 986a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 *b = ftdi->response + ftdi->recieved; 987a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int bytes_read = 0; 988a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retry_on_empty = 1; 989a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retry_on_timeout = 3; 990a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int empty_packets = 0; 991a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech read:{ 992a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int packet_bytes = 0; 993a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retval = usb_bulk_msg(ftdi->udev, 994a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), 995a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_buffer, ftdi->bulk_in_size, 996a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech &packet_bytes, msecs_to_jiffies(500)); 997a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char diag[30 *3 + 4]; 998a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *d = diag; 999a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int m = packet_bytes; 1000a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 *c = ftdi->bulk_in_buffer; 1001a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int s = (sizeof(diag) - 1) / 3; 1002a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech diag[0] = 0; 1003a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech while (s-- > 0 && m-- > 0) { 1004a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (s > 0 || m == 0) { 1005a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " %02X", *c++); 1006a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 1007a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " .."); 1008a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1009a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (packet_bytes > 2) { 1010a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_left = packet_bytes - 2; 1011a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_last = 1; 1012a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto have; 1013a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retval == -ETIMEDOUT) { 1014a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_timeout-- > 0) { 1015a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "TIMED OUT with packe" 1016a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "t_bytes = %d with total %d bytes%s\n", 1017a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech packet_bytes, bytes_read, diag); 1018a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 1019a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (bytes_read > 0) { 1020a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "ONLY %d bytes%s\n", 1021a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech bytes_read, diag); 1022a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 1023a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1024a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "TIMED OUT with packe" 1025a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "t_bytes = %d with total %d bytes%s\n", 1026a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech packet_bytes, bytes_read, diag); 1027a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 1028a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1029a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retval == -EILSEQ) { 1030a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "error = %d with packet_bytes" 1031a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech " = %d with total %d bytes%s\n", retval, 1032a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech packet_bytes, bytes_read, diag); 1033a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return retval; 1034a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retval) { 1035a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "error = %d with packet_bytes" 1036a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech " = %d with total %d bytes%s\n", retval, 1037a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech packet_bytes, bytes_read, diag); 1038a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return retval; 1039a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (packet_bytes == 2) { 1040a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech unsigned char s0 = ftdi->bulk_in_buffer[0]; 1041a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech unsigned char s1 = ftdi->bulk_in_buffer[1]; 1042a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech empty_packets += 1; 1043a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (s0 == 0x31 && s1 == 0x60) { 1044a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_empty-- > 0) { 1045a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 1046a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 1047a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1048a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (s0 == 0x31 && s1 == 0x00) { 1049a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_empty-- > 0) { 1050a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 1051a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 1052a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1053a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1054a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_empty-- > 0) { 1055a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 1056a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 1057a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1058a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1059a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (packet_bytes == 1) { 1060a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_empty-- > 0) { 1061a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 1062a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 1063a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1064a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1065a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_empty-- > 0) { 1066a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 1067a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 1068a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1069a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1070a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1071a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech more:{ 1072a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto read; 1073a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1074a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech have:if (ftdi->bulk_in_left > 0) { 1075a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 c = ftdi->bulk_in_buffer[++ftdi->bulk_in_last]; 1076a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech bytes_read += 1; 1077a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_left -= 1; 1078a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi->recieved == 0 && c == 0xFF) { 1079a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto have; 1080a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 1081a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech *b++ = c; 1082a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (++ftdi->recieved < ftdi->expected) { 1083a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto have; 1084a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (ftdi->ed_found) { 1085a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int ed_number = (ftdi->response[0] >> 5) & 0x03; 1086a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u16 ed_length = (ftdi->response[2] << 8) | 1087a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->response[1]; 1088a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_target *target = &ftdi->target[ed_number]; 1089a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int payload = (ed_length >> 0) & 0x07FF; 1090a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char diag[30 *3 + 4]; 1091a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *d = diag; 1092a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int m = payload; 1093a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 *c = 4 + ftdi->response; 1094a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int s = (sizeof(diag) - 1) / 3; 1095a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech diag[0] = 0; 1096a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech while (s-- > 0 && m-- > 0) { 1097a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (s > 0 || m == 0) { 1098a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " %02X", *c++); 1099a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 1100a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " .."); 1101a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1102a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, 1103a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech payload); 1104a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->recieved = 0; 1105a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->expected = 4; 1106a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->ed_found = 0; 1107a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech b = ftdi->response; 1108a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto have; 1109a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (ftdi->expected == 8) { 1110a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 buscmd; 1111a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int respond_head = ftdi->respond_head++; 1112a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_respond *respond = &ftdi->respond[ 1113a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech RESPOND_MASK & respond_head]; 1114a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u32 data = ftdi->response[7]; 1115a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech data <<= 8; 1116a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech data |= ftdi->response[6]; 1117a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech data <<= 8; 1118a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech data |= ftdi->response[5]; 1119a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech data <<= 8; 1120a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech data |= ftdi->response[4]; 1121a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech *respond->value = data; 1122a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech *respond->result = 0; 1123a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech complete(&respond->wait_completion); 1124a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->recieved = 0; 1125a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->expected = 4; 1126a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->ed_found = 0; 1127a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech b = ftdi->response; 1128a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buscmd = (ftdi->response[0] >> 0) & 0x0F; 1129a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (buscmd == 0x00) { 1130a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (buscmd == 0x02) { 1131a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (buscmd == 0x06) { 1132a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (buscmd == 0x0A) { 1133a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 1134a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "Uxxx unknown(%0X) va" 1135a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "lue = %08X\n", buscmd, data); 1136a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto have; 1137a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1138a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if ((ftdi->response[0] & 0x80) == 0x00) { 1139a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->expected = 8; 1140a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto have; 1141a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1142a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int ed_number = (ftdi->response[0] >> 5) & 0x03; 1143a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int ed_type = (ftdi->response[0] >> 0) & 0x03; 1144a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u16 ed_length = (ftdi->response[2] << 8) | 1145a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->response[1]; 1146a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_target *target = &ftdi->target[ 1147a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ed_number]; 1148a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->halted = (ftdi->response[0] >> 3) & 1149a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 0x01; 1150a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->skipped = (ftdi->response[0] >> 2) & 1151a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 0x01; 1152a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->toggle_bits = (ftdi->response[3] >> 6) 1153a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech & 0x03; 1154a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->error_count = (ftdi->response[3] >> 4) 1155a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech & 0x03; 1156a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->condition_code = (ftdi->response[ 1157a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 3] >> 0) & 0x0F; 1158a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if ((ftdi->response[0] & 0x10) == 0x00) { 1159a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech b = have_ed_set_response(ftdi, target, 1160a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ed_length, ed_number, ed_type, 1161a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech b); 1162a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto have; 1163a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1164a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech b = have_ed_get_response(ftdi, target, 1165a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ed_length, ed_number, ed_type, 1166a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech b); 1167a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto have; 1168a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1169a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1170a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1171a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 1172a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 1173a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1174a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1175a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1176a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/* 1177a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* create a urb, and a buffer for it, and copy the data to the urb 1178a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* 1179a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/ 1180a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic ssize_t ftdi_elan_write(struct file *file, 1181a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech const char __user *user_buffer, size_t count, 1182a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech loff_t *ppos) 1183a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1184a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retval = 0; 1185a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct urb *urb; 1186a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *buf; 118796a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartman struct usb_ftdi *ftdi = file->private_data; 118896a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartman 1189a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi->disconnected > 0) { 1190a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1191a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1192a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (count == 0) { 1193a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto exit; 1194a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1195a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb = usb_alloc_urb(0, GFP_KERNEL); 1196a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!urb) { 1197a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = -ENOMEM; 1198a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto error_1; 1199a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1200a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf = usb_buffer_alloc(ftdi->udev, count, GFP_KERNEL, 1201a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech &urb->transfer_dma); 1202a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!buf) { 1203a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = -ENOMEM; 1204a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto error_2; 1205a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1206a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (copy_from_user(buf, user_buffer, count)) { 1207a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = -EFAULT; 1208a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto error_3; 1209a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1210a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, 1211a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_out_endpointAddr), buf, count, 1212a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_write_bulk_callback, ftdi); 1213a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 1214a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = usb_submit_urb(urb, GFP_KERNEL); 1215a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retval) { 1216a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "failed submitting write urb, error %" 1217a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "d\n", retval); 121896a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartman goto error_3; 1219a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1220a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_free_urb(urb); 122196a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartman 122296a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartmanexit: 1223a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return count; 122496a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartmanerror_3: 122596a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartman usb_buffer_free(ftdi->udev, count, buf, urb->transfer_dma); 122696a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartmanerror_2: 122796a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartman usb_free_urb(urb); 122896a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartmanerror_1: 122996a518928e1fd00a6d0eb344f420ea82aeec8ab9Greg Kroah-Hartman return retval; 1230a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1231a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1232a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic struct file_operations ftdi_elan_fops = { 1233a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .owner = THIS_MODULE, 1234a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .llseek = no_llseek, 1235a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .ioctl = ftdi_elan_ioctl, 1236a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .read = ftdi_elan_read, 1237a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .write = ftdi_elan_write, 1238a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .open = ftdi_elan_open, 1239a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .release = ftdi_elan_release, 1240a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}; 1241a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1242a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/* 1243a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* usb class driver info in order to get a minor number from the usb core, 1244a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* and to have the device registered with the driver core 1245a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/ 1246a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic struct usb_class_driver ftdi_elan_jtag_class = { 1247a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .name = "ftdi-%d-jtag", 1248a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .fops = &ftdi_elan_fops, 1249a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .minor_base = USB_FTDI_ELAN_MINOR_BASE, 1250a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}; 1251a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1252a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/* 1253a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* the following definitions are for the 1254a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* ELAN FPGA state machgine processor that 1255a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* lies on the other side of the FTDI chip 1256a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/ 1257a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPCIu132rd 0x0 1258a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPCIu132wr 0x1 1259a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPCIiord 0x2 1260a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPCIiowr 0x3 1261a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPCImemrd 0x6 1262a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPCImemwr 0x7 1263a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPCIcfgrd 0xA 1264a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPCIcfgwr 0xB 1265a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPCInull 0xF 1266a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cU132cmd_status 0x0 1267a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cU132flash 0x1 1268a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPIDsetup 0x0 1269a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPIDout 0x1 1270a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPIDin 0x2 1271a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cPIDinonce 0x3 1272a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCnoerror 0x0 1273a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCcrc 0x1 1274a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCbitstuff 0x2 1275a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCtoggle 0x3 1276a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCstall 0x4 1277a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCnoresp 0x5 1278a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCbadpid1 0x6 1279a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCbadpid2 0x7 1280a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCdataoverrun 0x8 1281a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCdataunderrun 0x9 1282a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCbuffoverrun 0xC 1283a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCbuffunderrun 0xD 1284a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech#define cCCnotaccessed 0xF 1285a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_write_reg(struct usb_ftdi *ftdi, u32 data) 1286a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1287a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait:if (ftdi->disconnected > 0) { 1288a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1289a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1290a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_size; 1291a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech down(&ftdi->u132_lock); 1292a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_size = ftdi->command_next - ftdi->command_head; 1293a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command_size < COMMAND_SIZE) { 1294a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = &ftdi->command[ 1295a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech COMMAND_MASK & ftdi->command_next]; 1296a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->header = 0x00 | cPCIu132wr; 1297a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x04; 1298a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->address = 0x00; 1299a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->width = 0x00; 1300a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->follows = 4; 1301a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->value = data; 1302a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->buffer = &command->value; 1303a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_next += 1; 1304a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_kick_command_queue(ftdi); 1305a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 1306a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1307a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1308a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 1309a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 1310a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto wait; 1311a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1312a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1313a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1314a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1315a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_write_config(struct usb_ftdi *ftdi, int config_offset, 1316a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 width, u32 data) 1317a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1318a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 addressofs = config_offset / 4; 1319a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait:if (ftdi->disconnected > 0) { 1320a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1321a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1322a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_size; 1323a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech down(&ftdi->u132_lock); 1324a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_size = ftdi->command_next - ftdi->command_head; 1325a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command_size < COMMAND_SIZE) { 1326a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = &ftdi->command[ 1327a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech COMMAND_MASK & ftdi->command_next]; 1328a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->header = 0x00 | (cPCIcfgwr & 0x0F); 1329a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x04; 1330a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->address = addressofs; 1331a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->width = 0x00 | (width & 0x0F); 1332a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->follows = 4; 1333a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->value = data; 1334a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->buffer = &command->value; 1335a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_next += 1; 1336a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_kick_command_queue(ftdi); 1337a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 1338a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1339a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1340a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 1341a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 1342a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto wait; 1343a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1344a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1345a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1346a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1347a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_write_pcimem(struct usb_ftdi *ftdi, int mem_offset, 1348a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 width, u32 data) 1349a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1350a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 addressofs = mem_offset / 4; 1351a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait:if (ftdi->disconnected > 0) { 1352a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1353a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1354a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_size; 1355a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech down(&ftdi->u132_lock); 1356a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_size = ftdi->command_next - ftdi->command_head; 1357a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command_size < COMMAND_SIZE) { 1358a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = &ftdi->command[ 1359a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech COMMAND_MASK & ftdi->command_next]; 1360a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->header = 0x00 | (cPCImemwr & 0x0F); 1361a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x04; 1362a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->address = addressofs; 1363a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->width = 0x00 | (width & 0x0F); 1364a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->follows = 4; 1365a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->value = data; 1366a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->buffer = &command->value; 1367a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_next += 1; 1368a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_kick_command_queue(ftdi); 1369a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 1370a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1371a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1372a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 1373a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 1374a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto wait; 1375a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1376a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1377a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1378a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1379a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechint usb_ftdi_elan_write_pcimem(struct platform_device *pdev, int mem_offset, 1380a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 width, u32 data) 1381a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1382a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); 1383a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return ftdi_elan_write_pcimem(ftdi, mem_offset, width, data); 1384a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1385a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1386a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1387a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechEXPORT_SYMBOL_GPL(usb_ftdi_elan_write_pcimem); 1388a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_read_reg(struct usb_ftdi *ftdi, u32 *data) 1389a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1390a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait:if (ftdi->disconnected > 0) { 1391a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1392a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1393a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_size; 1394a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int respond_size; 1395a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech down(&ftdi->u132_lock); 1396a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_size = ftdi->command_next - ftdi->command_head; 1397a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond_size = ftdi->respond_next - ftdi->respond_head; 1398a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) 1399a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech { 1400a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = &ftdi->command[ 1401a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech COMMAND_MASK & ftdi->command_next]; 1402a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_respond *respond = &ftdi->respond[ 1403a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech RESPOND_MASK & ftdi->respond_next]; 1404a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int result = -ENODEV; 1405a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond->result = &result; 1406a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond->header = command->header = 0x00 | cPCIu132rd; 1407a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x04; 1408a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond->address = command->address = cU132cmd_status; 1409a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->width = 0x00; 1410a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->follows = 0; 1411a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->value = 0; 1412a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->buffer = NULL; 1413a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond->value = data; 1414a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech init_completion(&respond->wait_completion); 1415a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_next += 1; 1416a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->respond_next += 1; 1417a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_kick_command_queue(ftdi); 1418a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 1419a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait_for_completion(&respond->wait_completion); 1420a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return result; 1421a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1422a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 1423a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 1424a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto wait; 1425a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1426a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1427a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1428a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1429a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechint usb_ftdi_elan_read_reg(struct platform_device *pdev, u32 *data) 1430a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1431a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); 1432a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return ftdi_elan_read_reg(ftdi, data); 1433a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1434a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1435a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1436a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechEXPORT_SYMBOL_GPL(usb_ftdi_elan_read_reg); 1437a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_read_config(struct usb_ftdi *ftdi, int config_offset, 1438a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 width, u32 *data) 1439a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1440a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 addressofs = config_offset / 4; 1441a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait:if (ftdi->disconnected > 0) { 1442a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1443a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1444a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_size; 1445a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int respond_size; 1446a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech down(&ftdi->u132_lock); 1447a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_size = ftdi->command_next - ftdi->command_head; 1448a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond_size = ftdi->respond_next - ftdi->respond_head; 1449a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) 1450a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech { 1451a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = &ftdi->command[ 1452a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech COMMAND_MASK & ftdi->command_next]; 1453a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_respond *respond = &ftdi->respond[ 1454a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech RESPOND_MASK & ftdi->respond_next]; 1455a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int result = -ENODEV; 1456a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond->result = &result; 1457a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond->header = command->header = 0x00 | (cPCIcfgrd & 1458a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 0x0F); 1459a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x04; 1460a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond->address = command->address = addressofs; 1461a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->width = 0x00 | (width & 0x0F); 1462a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->follows = 0; 1463a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->value = 0; 1464a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->buffer = NULL; 1465a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond->value = data; 1466a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech init_completion(&respond->wait_completion); 1467a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_next += 1; 1468a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->respond_next += 1; 1469a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_kick_command_queue(ftdi); 1470a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 1471a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait_for_completion(&respond->wait_completion); 1472a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return result; 1473a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1474a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 1475a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 1476a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto wait; 1477a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1478a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1479a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1480a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1481a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_read_pcimem(struct usb_ftdi *ftdi, int mem_offset, 1482a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 width, u32 *data) 1483a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1484a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 addressofs = mem_offset / 4; 1485a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait:if (ftdi->disconnected > 0) { 1486a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1487a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1488a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_size; 1489a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int respond_size; 1490a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech down(&ftdi->u132_lock); 1491a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_size = ftdi->command_next - ftdi->command_head; 1492a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond_size = ftdi->respond_next - ftdi->respond_head; 1493a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) 1494a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech { 1495a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = &ftdi->command[ 1496a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech COMMAND_MASK & ftdi->command_next]; 1497a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_respond *respond = &ftdi->respond[ 1498a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech RESPOND_MASK & ftdi->respond_next]; 1499a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int result = -ENODEV; 1500a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond->result = &result; 1501a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond->header = command->header = 0x00 | (cPCImemrd & 1502a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 0x0F); 1503a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x04; 1504a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond->address = command->address = addressofs; 1505a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->width = 0x00 | (width & 0x0F); 1506a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->follows = 0; 1507a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->value = 0; 1508a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->buffer = NULL; 1509a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond->value = data; 1510a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech init_completion(&respond->wait_completion); 1511a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_next += 1; 1512a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->respond_next += 1; 1513a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_kick_command_queue(ftdi); 1514a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 1515a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait_for_completion(&respond->wait_completion); 1516a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return result; 1517a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1518a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 1519a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 1520a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto wait; 1521a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1522a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1523a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1524a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1525a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechint usb_ftdi_elan_read_pcimem(struct platform_device *pdev, int mem_offset, 1526a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 width, u32 *data) 1527a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1528a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); 1529a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi->initialized == 0) { 1530a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1531a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 1532a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return ftdi_elan_read_pcimem(ftdi, mem_offset, width, data); 1533a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1534a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1535a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1536a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechEXPORT_SYMBOL_GPL(usb_ftdi_elan_read_pcimem); 1537a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_edset_setup(struct usb_ftdi *ftdi, u8 ed_number, 1538a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, 1539a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, 1540a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int toggle_bits, int error_count, int condition_code, int repeat_number, 1541a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int halted, int skipped, int actual, int non_null)) 1542a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1543a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 ed = ed_number - 1; 1544a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait:if (ftdi->disconnected > 0) { 1545a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1546a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (ftdi->initialized == 0) { 1547a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1548a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1549a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_size; 1550a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech down(&ftdi->u132_lock); 1551a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_size = ftdi->command_next - ftdi->command_head; 1552a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command_size < COMMAND_SIZE) { 1553a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_target *target = &ftdi->target[ed]; 1554a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = &ftdi->command[ 1555a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech COMMAND_MASK & ftdi->command_next]; 1556a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->header = 0x80 | (ed << 5); 1557a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x8007; 1558a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->address = (toggle_bits << 6) | (ep_number << 2) 1559a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech | (address << 0); 1560a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->width = usb_maxpacket(urb->dev, urb->pipe, 1561a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_pipeout(urb->pipe)); 1562a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->follows = 8; 1563a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->value = 0; 1564a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->buffer = urb->setup_packet; 1565a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->callback = callback; 1566a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->endp = endp; 1567a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->urb = urb; 1568a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->active = 1; 1569a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_next += 1; 1570a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_kick_command_queue(ftdi); 1571a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 1572a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1573a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1574a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 1575a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 1576a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto wait; 1577a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1578a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1579a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1580a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1581a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechint usb_ftdi_elan_edset_setup(struct platform_device *pdev, u8 ed_number, 1582a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, 1583a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, 1584a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int toggle_bits, int error_count, int condition_code, int repeat_number, 1585a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int halted, int skipped, int actual, int non_null)) 1586a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1587a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); 1588a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return ftdi_elan_edset_setup(ftdi, ed_number, endp, urb, address, 1589a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ep_number, toggle_bits, callback); 1590a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1591a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1592a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1593a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechEXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_setup); 1594a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_edset_input(struct usb_ftdi *ftdi, u8 ed_number, 1595a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, 1596a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, 1597a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int toggle_bits, int error_count, int condition_code, int repeat_number, 1598a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int halted, int skipped, int actual, int non_null)) 1599a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1600a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 ed = ed_number - 1; 1601a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait:if (ftdi->disconnected > 0) { 1602a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1603a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (ftdi->initialized == 0) { 1604a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1605a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1606a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_size; 1607a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech down(&ftdi->u132_lock); 1608a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_size = ftdi->command_next - ftdi->command_head; 1609a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command_size < COMMAND_SIZE) { 1610a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_target *target = &ftdi->target[ed]; 1611a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = &ftdi->command[ 1612a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech COMMAND_MASK & ftdi->command_next]; 1613a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int remaining_length = urb->transfer_buffer_length - 1614a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb->actual_length; 1615a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->header = 0x82 | (ed << 5); 1616a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (remaining_length == 0) { 1617a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x0000; 1618a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (remaining_length > 1024) { 1619a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x8000 | 1023; 1620a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 1621a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x8000 | (remaining_length - 1622a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1); 1623a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->address = (toggle_bits << 6) | (ep_number << 2) 1624a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech | (address << 0); 1625a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->width = usb_maxpacket(urb->dev, urb->pipe, 1626a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_pipeout(urb->pipe)); 1627a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->follows = 0; 1628a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->value = 0; 1629a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->buffer = NULL; 1630a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->callback = callback; 1631a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->endp = endp; 1632a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->urb = urb; 1633a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->active = 1; 1634a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_next += 1; 1635a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_kick_command_queue(ftdi); 1636a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 1637a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1638a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1639a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 1640a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 1641a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto wait; 1642a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1643a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1644a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1645a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1646a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechint usb_ftdi_elan_edset_input(struct platform_device *pdev, u8 ed_number, 1647a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, 1648a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, 1649a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int toggle_bits, int error_count, int condition_code, int repeat_number, 1650a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int halted, int skipped, int actual, int non_null)) 1651a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1652a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); 1653a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return ftdi_elan_edset_input(ftdi, ed_number, endp, urb, address, 1654a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ep_number, toggle_bits, callback); 1655a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1656a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1657a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1658a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechEXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_input); 1659a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_edset_empty(struct usb_ftdi *ftdi, u8 ed_number, 1660a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, 1661a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, 1662a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int toggle_bits, int error_count, int condition_code, int repeat_number, 1663a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int halted, int skipped, int actual, int non_null)) 1664a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1665a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 ed = ed_number - 1; 1666a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait:if (ftdi->disconnected > 0) { 1667a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1668a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (ftdi->initialized == 0) { 1669a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1670a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1671a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_size; 1672a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech down(&ftdi->u132_lock); 1673a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_size = ftdi->command_next - ftdi->command_head; 1674a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command_size < COMMAND_SIZE) { 1675a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_target *target = &ftdi->target[ed]; 1676a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = &ftdi->command[ 1677a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech COMMAND_MASK & ftdi->command_next]; 1678a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->header = 0x81 | (ed << 5); 1679a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x0000; 1680a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->address = (toggle_bits << 6) | (ep_number << 2) 1681a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech | (address << 0); 1682a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->width = usb_maxpacket(urb->dev, urb->pipe, 1683a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_pipeout(urb->pipe)); 1684a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->follows = 0; 1685a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->value = 0; 1686a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->buffer = NULL; 1687a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->callback = callback; 1688a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->endp = endp; 1689a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->urb = urb; 1690a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->active = 1; 1691a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_next += 1; 1692a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_kick_command_queue(ftdi); 1693a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 1694a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1695a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1696a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 1697a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 1698a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto wait; 1699a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1700a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1701a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1702a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1703a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechint usb_ftdi_elan_edset_empty(struct platform_device *pdev, u8 ed_number, 1704a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, 1705a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, 1706a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int toggle_bits, int error_count, int condition_code, int repeat_number, 1707a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int halted, int skipped, int actual, int non_null)) 1708a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1709a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); 1710a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return ftdi_elan_edset_empty(ftdi, ed_number, endp, urb, address, 1711a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ep_number, toggle_bits, callback); 1712a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1713a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1714a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1715a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechEXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_empty); 1716a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_edset_output(struct usb_ftdi *ftdi, u8 ed_number, 1717a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, 1718a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, 1719a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int toggle_bits, int error_count, int condition_code, int repeat_number, 1720a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int halted, int skipped, int actual, int non_null)) 1721a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1722a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 ed = ed_number - 1; 1723a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait:if (ftdi->disconnected > 0) { 1724a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1725a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (ftdi->initialized == 0) { 1726a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1727a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1728a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_size; 1729a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech down(&ftdi->u132_lock); 1730a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_size = ftdi->command_next - ftdi->command_head; 1731a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command_size < COMMAND_SIZE) { 1732a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 *b; 1733a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u16 urb_size; 1734a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int i = 0; 1735a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char data[30 *3 + 4]; 1736a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *d = data; 1737a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int m = (sizeof(data) - 1) / 3; 1738a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int l = 0; 1739a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_target *target = &ftdi->target[ed]; 1740a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = &ftdi->command[ 1741a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech COMMAND_MASK & ftdi->command_next]; 1742a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->header = 0x81 | (ed << 5); 1743a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->address = (toggle_bits << 6) | (ep_number << 2) 1744a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech | (address << 0); 1745a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->width = usb_maxpacket(urb->dev, urb->pipe, 1746a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_pipeout(urb->pipe)); 1747a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->follows = min(1024, 1748a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb->transfer_buffer_length - 1749a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb->actual_length); 1750a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->value = 0; 1751a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->buffer = urb->transfer_buffer + 1752a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb->actual_length; 1753a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x8000 | (command->follows - 1); 1754a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech b = command->buffer; 1755a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb_size = command->follows; 1756a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech data[0] = 0; 1757a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech while (urb_size-- > 0) { 1758a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (i > m) { 1759a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (i++ < m) { 1760a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int w = sprintf(d, " %02X", *b++); 1761a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += w; 1762a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech l += w; 1763a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 1764a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " .."); 1765a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1766a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->callback = callback; 1767a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->endp = endp; 1768a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->urb = urb; 1769a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->active = 1; 1770a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_next += 1; 1771a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_kick_command_queue(ftdi); 1772a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 1773a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1774a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1775a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 1776a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 1777a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto wait; 1778a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1779a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1780a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1781a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1782a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechint usb_ftdi_elan_edset_output(struct platform_device *pdev, u8 ed_number, 1783a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, 1784a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, 1785a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int toggle_bits, int error_count, int condition_code, int repeat_number, 1786a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int halted, int skipped, int actual, int non_null)) 1787a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1788a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); 1789a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return ftdi_elan_edset_output(ftdi, ed_number, endp, urb, address, 1790a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ep_number, toggle_bits, callback); 1791a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1792a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1793a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1794a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechEXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_output); 1795a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_edset_single(struct usb_ftdi *ftdi, u8 ed_number, 1796a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, 1797a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, 1798a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int toggle_bits, int error_count, int condition_code, int repeat_number, 1799a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int halted, int skipped, int actual, int non_null)) 1800a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1801a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 ed = ed_number - 1; 1802a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait:if (ftdi->disconnected > 0) { 1803a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1804a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (ftdi->initialized == 0) { 1805a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1806a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1807a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_size; 1808a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech down(&ftdi->u132_lock); 1809a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_size = ftdi->command_next - ftdi->command_head; 1810a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command_size < COMMAND_SIZE) { 1811a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int remaining_length = urb->transfer_buffer_length - 1812a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb->actual_length; 1813a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_target *target = &ftdi->target[ed]; 1814a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = &ftdi->command[ 1815a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech COMMAND_MASK & ftdi->command_next]; 1816a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->header = 0x83 | (ed << 5); 1817a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (remaining_length == 0) { 1818a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x0000; 1819a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (remaining_length > 1024) { 1820a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x8000 | 1023; 1821a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 1822a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x8000 | (remaining_length - 1823a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1); 1824a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->address = (toggle_bits << 6) | (ep_number << 2) 1825a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech | (address << 0); 1826a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->width = usb_maxpacket(urb->dev, urb->pipe, 1827a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_pipeout(urb->pipe)); 1828a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->follows = 0; 1829a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->value = 0; 1830a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->buffer = NULL; 1831a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->callback = callback; 1832a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->endp = endp; 1833a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->urb = urb; 1834a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->active = 1; 1835a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_next += 1; 1836a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_kick_command_queue(ftdi); 1837a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 1838a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1839a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1840a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 1841a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 1842a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto wait; 1843a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1844a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1845a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1846a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1847a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechint usb_ftdi_elan_edset_single(struct platform_device *pdev, u8 ed_number, 1848a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, 1849a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, 1850a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int toggle_bits, int error_count, int condition_code, int repeat_number, 1851a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int halted, int skipped, int actual, int non_null)) 1852a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1853a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); 1854a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return ftdi_elan_edset_single(ftdi, ed_number, endp, urb, address, 1855a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ep_number, toggle_bits, callback); 1856a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1857a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1858a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1859a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechEXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_single); 1860a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_edset_flush(struct usb_ftdi *ftdi, u8 ed_number, 1861a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void *endp) 1862a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1863a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 ed = ed_number - 1; 1864a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi->disconnected > 0) { 1865a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1866a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (ftdi->initialized == 0) { 1867a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 1868a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1869a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_target *target = &ftdi->target[ed]; 1870a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech down(&ftdi->u132_lock); 1871a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (target->abandoning > 0) { 1872a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 1873a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1874a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1875a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech target->abandoning = 1; 1876a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech wait_1:if (target->active == 1) { 1877a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int command_size = ftdi->command_next - 1878a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_head; 1879a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (command_size < COMMAND_SIZE) { 1880a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct u132_command *command = 1881a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech &ftdi->command[COMMAND_MASK & 1882a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_next]; 1883a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->header = 0x80 | (ed << 5) | 1884a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 0x4; 1885a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->length = 0x00; 1886a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->address = 0x00; 1887a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->width = 0x00; 1888a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->follows = 0; 1889a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->value = 0; 1890a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command->buffer = &command->value; 1891a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->command_next += 1; 1892a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_kick_command_queue(ftdi); 1893a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1894a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 1895a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 1896a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech down(&ftdi->u132_lock); 1897a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto wait_1; 1898a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1899a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1900a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi->u132_lock); 1901a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1902a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1903a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1904a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1905a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1906a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechint usb_ftdi_elan_edset_flush(struct platform_device *pdev, u8 ed_number, 1907a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech void *endp) 1908a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1909a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); 1910a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return ftdi_elan_edset_flush(ftdi, ed_number, endp); 1911a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1912a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1913a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1914a5c66e4b2418278786a025a5bd9625f485b2087aTony OlechEXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_flush); 1915a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_flush_input_fifo(struct usb_ftdi *ftdi) 1916a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1917a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retry_on_empty = 10; 1918a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retry_on_timeout = 5; 1919a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retry_on_status = 20; 1920a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech more:{ 1921a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int packet_bytes = 0; 1922a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retval = usb_bulk_msg(ftdi->udev, 1923a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), 1924a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_buffer, ftdi->bulk_in_size, 1925a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech &packet_bytes, msecs_to_jiffies(100)); 1926a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (packet_bytes > 2) { 1927a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char diag[30 *3 + 4]; 1928a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *d = diag; 1929a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int m = (sizeof(diag) - 1) / 3; 1930a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *b = ftdi->bulk_in_buffer; 1931a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int bytes_read = 0; 1932a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech diag[0] = 0; 1933a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech while (packet_bytes-- > 0) { 1934a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char c = *b++; 1935a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (bytes_read < m) { 1936a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " %02X", 1937a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 0x000000FF & c); 1938a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (bytes_read > m) { 1939a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 1940a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " .."); 1941a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech bytes_read += 1; 1942a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech continue; 1943a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1944a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 1945a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (packet_bytes > 1) { 1946a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char s1 = ftdi->bulk_in_buffer[0]; 1947a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char s2 = ftdi->bulk_in_buffer[1]; 1948a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (s1 == 0x31 && s2 == 0x60) { 1949a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 1950a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retry_on_status-- > 0) { 1951a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 1952a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1953a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "STATUS ERROR retry l" 1954a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "imit reached\n"); 1955a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -EFAULT; 1956a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1957a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (packet_bytes > 0) { 1958a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char b1 = ftdi->bulk_in_buffer[0]; 1959a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "only one byte flushed from F" 1960a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "TDI = %02X\n", b1); 1961a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_status-- > 0) { 1962a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 1963a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1964a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "STATUS ERROR retry l" 1965a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "imit reached\n"); 1966a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -EFAULT; 1967a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1968a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retval == -ETIMEDOUT) { 1969a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_timeout-- > 0) { 1970a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 1971a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1972a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "TIMED OUT retry limi" 1973a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "t reached\n"); 1974a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 1975a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1976a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retval == 0) { 1977a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_empty-- > 0) { 1978a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 1979a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1980a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "empty packet retry l" 1981a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "imit reached\n"); 1982a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 1983a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1984a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 1985a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "error = %d\n", retval); 1986a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return retval; 1987a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1988a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 1989a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -1; 1990a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 1991a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1992a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 1993a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/* 1994a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* send the long flush sequence 1995a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* 1996a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/ 1997a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_synchronize_flush(struct usb_ftdi *ftdi) 1998a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 1999a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retval; 2000a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct urb *urb; 2001a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *buf; 2002a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int I = 257; 2003a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int i = 0; 2004a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb = usb_alloc_urb(0, GFP_KERNEL); 2005a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!urb) { 2006a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "could not alloc a urb for flush sequ" 2007a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "ence\n"); 2008a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 2009a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2010a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf = usb_buffer_alloc(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma); 2011a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!buf) { 2012a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "could not get a buffer for flush seq" 2013a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "uence\n"); 2014a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_free_urb(urb); 2015a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 2016a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2017a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech while (I-- > 0) 2018a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf[i++] = 0x55; 2019a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, 2020a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_out_endpointAddr), buf, i, 2021a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_write_bulk_callback, ftdi); 2022a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 2023a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = usb_submit_urb(urb, GFP_KERNEL); 2024a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retval) { 2025a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "failed to submit urb containing the " 2026a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "flush sequence\n"); 2027a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_buffer_free(ftdi->udev, i, buf, urb->transfer_dma); 2028a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_free_urb(urb); 2029a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 2030a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2031a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_free_urb(urb); 2032a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 2033a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 2034a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 2035a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 2036a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/* 2037a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* send the reset sequence 2038a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* 2039a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/ 2040a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_synchronize_reset(struct usb_ftdi *ftdi) 2041a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 2042a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retval; 2043a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct urb *urb; 2044a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *buf; 2045a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int I = 4; 2046a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int i = 0; 2047a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb = usb_alloc_urb(0, GFP_KERNEL); 2048a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!urb) { 2049a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "could not get a urb for the reset se" 2050a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "quence\n"); 2051a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 2052a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2053a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf = usb_buffer_alloc(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma); 2054a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!buf) { 2055a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "could not get a buffer for the reset" 2056a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech " sequence\n"); 2057a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_free_urb(urb); 2058a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 2059a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2060a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf[i++] = 0x55; 2061a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf[i++] = 0xAA; 2062a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf[i++] = 0x5A; 2063a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buf[i++] = 0xA5; 2064a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, 2065a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_out_endpointAddr), buf, i, 2066a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_write_bulk_callback, ftdi); 2067a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 2068a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = usb_submit_urb(urb, GFP_KERNEL); 2069a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retval) { 2070a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "failed to submit urb containing the " 2071a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "reset sequence\n"); 2072a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_buffer_free(ftdi->udev, i, buf, urb->transfer_dma); 2073a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_free_urb(urb); 2074a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 2075a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2076a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_free_urb(urb); 2077a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 2078a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 2079a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 2080a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_synchronize(struct usb_ftdi *ftdi) 2081a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 2082a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retval; 2083a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int long_stop = 10; 2084a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retry_on_timeout = 5; 2085a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retry_on_empty = 10; 2086a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int err_count = 0; 2087a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = ftdi_elan_flush_input_fifo(ftdi); 2088a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retval) 2089a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return retval; 2090a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_left = 0; 2091a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_last = -1; 2092a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech while (long_stop-- > 0) { 2093a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int read_stop; 2094a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int read_stuck; 2095a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = ftdi_elan_synchronize_flush(ftdi); 2096a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retval) 2097a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return retval; 2098a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = ftdi_elan_flush_input_fifo(ftdi); 2099a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retval) 2100a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return retval; 2101a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reset:retval = ftdi_elan_synchronize_reset(ftdi); 2102a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retval) 2103a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return retval; 2104a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech read_stop = 100; 2105a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech read_stuck = 10; 2106a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech read:{ 2107a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int packet_bytes = 0; 2108a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = usb_bulk_msg(ftdi->udev, 2109a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_rcvbulkpipe(ftdi->udev, 2110a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_endpointAddr), 2111a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_buffer, ftdi->bulk_in_size, 2112a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech &packet_bytes, msecs_to_jiffies(500)); 2113a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (packet_bytes > 2) { 2114a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char diag[30 *3 + 4]; 2115a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *d = diag; 2116a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int m = (sizeof(diag) - 1) / 3; 2117a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *b = ftdi->bulk_in_buffer; 2118a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int bytes_read = 0; 2119a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech unsigned char c = 0; 2120a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech diag[0] = 0; 2121a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech while (packet_bytes-- > 0) { 2122a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech c = *b++; 2123a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (bytes_read < m) { 2124a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " %02X", c); 2125a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (bytes_read > m) { 2126a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 2127a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " .."); 2128a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech bytes_read += 1; 2129a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech continue; 2130a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2131a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (c == 0x7E) { 2132a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 2133a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2134a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (c == 0x55) { 2135a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto read; 2136a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (read_stop-- > 0) { 2137a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto read; 2138a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2139a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "retr" 2140a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "y limit reached\n"); 2141a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech continue; 2142a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2143a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2144a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (packet_bytes > 1) { 2145a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech unsigned char s1 = ftdi->bulk_in_buffer[0]; 2146a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech unsigned char s2 = ftdi->bulk_in_buffer[1]; 2147a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (s1 == 0x31 && s2 == 0x00) { 2148a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (read_stuck-- > 0) { 2149a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto read; 2150a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 2151a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto reset; 2152a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (s1 == 0x31 && s2 == 0x60) { 2153a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (read_stop-- > 0) { 2154a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto read; 2155a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2156a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "retr" 2157a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "y limit reached\n"); 2158a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech continue; 2159a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2160a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2161a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (read_stop-- > 0) { 2162a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto read; 2163a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2164a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "retr" 2165a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "y limit reached\n"); 2166a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech continue; 2167a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2168a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2169a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (packet_bytes > 0) { 2170a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (read_stop-- > 0) { 2171a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto read; 2172a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2173a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "retry limit " 2174a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "reached\n"); 2175a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech continue; 2176a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2177a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retval == -ETIMEDOUT) { 2178a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_timeout-- > 0) { 2179a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto read; 2180a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2181a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "TIMED OUT re" 2182a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "try limit reached\n"); 2183a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech continue; 2184a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2185a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retval == 0) { 2186a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_empty-- > 0) { 2187a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto read; 2188a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2189a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "empty packet" 2190a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech " retry limit reached\n"); 2191a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech continue; 2192a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2193a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2194a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech err_count += 1; 2195a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "error = %d\n", 2196a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval); 2197a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (read_stop-- > 0) { 2198a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto read; 2199a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2200a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "retry limit " 2201a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "reached\n"); 2202a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech continue; 2203a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2204a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2205a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2206a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2207a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "failed to synchronize\n"); 2208a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -EFAULT; 2209a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 2210a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 2211a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_stuck_waiting(struct usb_ftdi *ftdi) 2212a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 2213a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retry_on_empty = 10; 2214a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retry_on_timeout = 5; 2215a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retry_on_status = 50; 2216a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech more:{ 2217a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int packet_bytes = 0; 2218a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retval = usb_bulk_msg(ftdi->udev, 2219a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), 2220a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_buffer, ftdi->bulk_in_size, 2221a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech &packet_bytes, msecs_to_jiffies(1000)); 2222a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (packet_bytes > 2) { 2223a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char diag[30 *3 + 4]; 2224a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *d = diag; 2225a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int m = (sizeof(diag) - 1) / 3; 2226a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char *b = ftdi->bulk_in_buffer; 2227a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int bytes_read = 0; 2228a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech diag[0] = 0; 2229a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech while (packet_bytes-- > 0) { 2230a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char c = *b++; 2231a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (bytes_read < m) { 2232a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " %02X", 2233a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 0x000000FF & c); 2234a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (bytes_read > m) { 2235a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 2236a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech d += sprintf(d, " .."); 2237a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech bytes_read += 1; 2238a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech continue; 2239a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2240a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 2241a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (packet_bytes > 1) { 2242a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char s1 = ftdi->bulk_in_buffer[0]; 2243a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char s2 = ftdi->bulk_in_buffer[1]; 2244a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (s1 == 0x31 && s2 == 0x60) { 2245a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 2246a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retry_on_status-- > 0) { 2247a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(5); 2248a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 2249a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 2250a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -EFAULT; 2251a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (packet_bytes > 0) { 2252a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech char b1 = ftdi->bulk_in_buffer[0]; 2253a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "only one byte flushed from F" 2254a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "TDI = %02X\n", b1); 2255a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_status-- > 0) { 2256a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(5); 2257a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 2258a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2259a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "STATUS ERROR retry l" 2260a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "imit reached\n"); 2261a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -EFAULT; 2262a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2263a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retval == -ETIMEDOUT) { 2264a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_timeout-- > 0) { 2265a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 2266a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2267a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "TIMED OUT retry limi" 2268a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "t reached\n"); 2269a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 2270a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2271a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (retval == 0) { 2272a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retry_on_empty-- > 0) { 2273a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto more; 2274a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2275a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "empty packet retry l" 2276a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "imit reached\n"); 2277a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 2278a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2279a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2280a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "error = %d\n", retval); 2281a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 2282a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2283a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2284a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -1; 2285a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 2286a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 2287a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi) 2288a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 2289a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int UxxxStatus = ftdi_elan_read_reg(ftdi, &ftdi->controlreg); 2290a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2291a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2292a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi->controlreg & 0x00400000) { 2293a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi->card_ejected) { 2294a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2295a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->card_ejected = 1; 2296a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "CARD EJECTED - controlreg = " 2297a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "%08X\n", ftdi->controlreg); 2298a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2299a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 2300a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2301a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 fn = ftdi->function - 1; 2302a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int activePCIfn = fn << 8; 2303a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u32 pcidata; 2304a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u32 pciVID; 2305a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u32 pciPID; 2306a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int reg = 0; 2307a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, 2308a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech &pcidata); 2309a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2310a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2311a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech pciVID = pcidata & 0xFFFF; 2312a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech pciPID = (pcidata >> 16) & 0xFFFF; 2313a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (pciVID == ftdi->platform_data.vendor && pciPID == 2314a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->platform_data.device) { 2315a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 2316a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2317a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "vendor=%04X pciVID=%04X devi" 2318a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "ce=%04X pciPID=%04X\n", 2319a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->platform_data.vendor, pciVID, 2320a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->platform_data.device, pciPID); 2321a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENODEV; 2322a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2323a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2324a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 2325a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 2326a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi) 2327a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 2328a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u32 latence_timer; 2329a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u32 controlreg; 2330a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int UxxxStatus; 2331a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u32 pcidata; 2332a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int reg = 0; 2333a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int foundOHCI = 0; 2334a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u8 fn; 2335a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int activePCIfn = 0; 2336a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u32 pciVID = 0; 2337a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u32 pciPID = 0; 2338a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); 2339a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2340a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2341a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000000L); 2342a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2343a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2344a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(750); 2345a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x100); 2346a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2347a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2348a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x500); 2349a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2350a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2351a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); 2352a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2353a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2354a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020CL | 0x000); 2355a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2356a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2357a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020DL | 0x000); 2358a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2359a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2360a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(250); 2361a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020FL | 0x000); 2362a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2363a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2364a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); 2365a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2366a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2367a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x800); 2368a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2369a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2370a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); 2371a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2372a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2373a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); 2374a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2375a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2376a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(1000); 2377a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech for (fn = 0; (fn < 4) && (!foundOHCI); fn++) { 2378a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech activePCIfn = fn << 8; 2379a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->function = fn + 1; 2380a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, 2381a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech &pcidata); 2382a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2383a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2384a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech pciVID = pcidata & 0xFFFF; 2385a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech pciPID = (pcidata >> 16) & 0xFFFF; 2386a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if ((pciVID == 0x1045) && (pciPID == 0xc861)) { 2387a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech foundOHCI = 1; 2388a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if ((pciVID == 0x1033) && (pciPID == 0x0035)) { 2389a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech foundOHCI = 1; 2390a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if ((pciVID == 0x10b9) && (pciPID == 0x5237)) { 2391a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech foundOHCI = 1; 2392a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if ((pciVID == 0x11c1) && (pciPID == 0x5802)) { 2393a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech foundOHCI = 1; 2394a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if ((pciVID == 0x11AB) && (pciPID == 0x1FA6)) { 2395a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2396a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2397a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (foundOHCI == 0) { 2398a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENXIO; 2399a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2400a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->platform_data.vendor = pciVID; 2401a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->platform_data.device = pciPID; 2402a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800); 2403a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2404a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2405a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reg = 16; 2406a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, 2407a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 0xFFFFFFFF); 2408a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2409a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2410a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, 2411a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech &pcidata); 2412a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2413a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2414a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, 2415a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 0xF0000000); 2416a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2417a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2418a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, 2419a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech &pcidata); 2420a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2421a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2422a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reg = 12; 2423a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, 2424a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech &latence_timer); 2425a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2426a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2427a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech latence_timer &= 0xFFFF00FF; 2428a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech latence_timer |= 0x00001600; 2429a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, 2430a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech latence_timer); 2431a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2432a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2433a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, 2434a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech &pcidata); 2435a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2436a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2437a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reg = 4; 2438a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, 2439a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 0x06); 2440a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2441a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2442a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, 2443a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech &pcidata); 2444a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (UxxxStatus) 2445a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return UxxxStatus; 2446a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 2447a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 2448a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 2449a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi) 2450a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 2451a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech u32 pcidata; 2452a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int U132Status; 2453a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int reg; 2454a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int reset_repeat = 0; 2455a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech do_reset:reg = 8; 2456a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x0e, 0x01); 2457a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2458a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2459a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reset_check:{ 2460a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); 2461a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2462a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2463a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (pcidata & 1) { 2464a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(500); 2465a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (reset_repeat++ > 100) { 2466a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reset_repeat = 0; 2467a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto do_reset; 2468a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else 2469a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto reset_check; 2470a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2471a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2472a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto dump_regs; 2473a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(500); 2474a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reg = 0x28; 2475a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x11000000); 2476a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2477a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2478a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); 2479a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2480a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2481a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reg = 0x40; 2482a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x2edf); 2483a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2484a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2485a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); 2486a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2487a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2488a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reg = 0x34; 2489a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x2edf2edf); 2490a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2491a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2492a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); 2493a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2494a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2495a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reg = 4; 2496a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0xA0); 2497a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2498a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2499a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); 2500a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2501a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2502a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(250); 2503a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reg = 8; 2504a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x0e, 0x04); 2505a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2506a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2507a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); 2508a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2509a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2510a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reg = 0x28; 2511a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); 2512a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2513a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2514a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reg = 8; 2515a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); 2516a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2517a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2518a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reg = 0x48; 2519a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x00001200); 2520a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2521a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2522a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); 2523a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2524a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2525a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reg = 0x54; 2526a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); 2527a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2528a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2529a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reg = 0x58; 2530a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); 2531a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2532a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2533a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reg = 0x34; 2534a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x28002edf); 2535a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2536a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2537a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); 2538a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2539a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2540a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(100); 2541a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reg = 0x50; 2542a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x10000); 2543a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2544a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2545a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reg = 0x54; 2546a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech power_check:U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); 2547a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2548a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2549a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!(pcidata & 1)) { 2550a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(500); 2551a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto power_check; 2552a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2553a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(3000); 2554a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reg = 0x54; 2555a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); 2556a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2557a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2558a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reg = 0x58; 2559a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); 2560a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2561a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2562a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reg = 0x54; 2563a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x02); 2564a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2565a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2566a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); 2567a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2568a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2569a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reg = 0x54; 2570a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x10); 2571a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2572a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2573a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); 2574a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2575a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2576a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech msleep(750); 2577a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reg = 0x54; 2578a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (0) { 2579a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x02); 2580a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2581a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2582a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2583a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (0) { 2584a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); 2585a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2586a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2587a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2588a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reg = 0x54; 2589a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); 2590a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2591a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2592a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech reg = 0x58; 2593a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); 2594a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2595a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2596a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dump_regs:for (reg = 0; reg <= 0x54; reg += 4) { 2597a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); 2598a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (U132Status) 2599a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return U132Status; 2600a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2601a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 2602a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 2603a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 2604a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 2605a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech/* 2606a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech* we use only the first bulk-in and bulk-out endpoints 2607a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech*/ 2608a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int ftdi_elan_probe(struct usb_interface *interface, 2609a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech const struct usb_device_id *id) 2610a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 2611a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_host_interface *iface_desc; 2612a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_endpoint_descriptor *endpoint; 2613a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech size_t buffer_size; 2614a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int i; 2615a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int retval = -ENOMEM; 2616a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = kmalloc(sizeof(struct usb_ftdi), GFP_KERNEL); 2617a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi == NULL) { 2618a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech printk(KERN_ERR "Out of memory\n"); 2619a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return -ENOMEM; 2620a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2621a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech memset(ftdi, 0x00, sizeof(struct usb_ftdi)); 2622a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech down(&ftdi_module_lock); 2623a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech list_add_tail(&ftdi->ftdi_list, &ftdi_static_list); 2624a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->sequence_num = ++ftdi_instances; 2625a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech up(&ftdi_module_lock); 2626a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_init_kref(ftdi); 2627a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech init_MUTEX(&ftdi->sw_lock); 2628a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->udev = usb_get_dev(interface_to_usbdev(interface)); 2629a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->interface = interface; 2630a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech init_MUTEX(&ftdi->u132_lock); 2631a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->expected = 4; 2632a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech iface_desc = interface->cur_altsetting; 2633a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { 2634a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech endpoint = &iface_desc->endpoint[i].desc; 2635a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!ftdi->bulk_in_endpointAddr && 26362ae7745beac6de54a47ed19fe441f1d45aa96172Luiz Fernando N. Capitulino usb_endpoint_is_bulk_in(endpoint)) { 2637a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); 2638a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_size = buffer_size; 2639a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_endpointAddr = endpoint->bEndpointAddress; 2640a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); 2641a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!ftdi->bulk_in_buffer) { 2642a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "Could not allocate b" 2643a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "ulk_in_buffer\n"); 2644a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = -ENOMEM; 2645a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto error; 2646a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2647a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2648a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!ftdi->bulk_out_endpointAddr && 26492ae7745beac6de54a47ed19fe441f1d45aa96172Luiz Fernando N. Capitulino usb_endpoint_is_bulk_out(endpoint)) { 2650a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_out_endpointAddr = 2651a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech endpoint->bEndpointAddress; 2652a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2653a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2654a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (!(ftdi->bulk_in_endpointAddr && ftdi->bulk_out_endpointAddr)) { 2655a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "Could not find both bulk-in and bulk" 2656a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "-out endpoints\n"); 2657a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = -ENODEV; 2658a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto error; 2659a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2660a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_info(&ftdi->udev->dev, "interface %d has I=%02X O=%02X\n", 2661a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech iface_desc->desc.bInterfaceNumber, ftdi->bulk_in_endpointAddr, 2662a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_out_endpointAddr); 2663a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_set_intfdata(interface, ftdi); 2664a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (iface_desc->desc.bInterfaceNumber == 0 && 2665a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_endpointAddr == 0x81 && 2666a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_out_endpointAddr == 0x02) { 2667a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = usb_register_dev(interface, &ftdi_elan_jtag_class); 2668a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (retval) { 2669a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, "Not able to get a minor for " 2670a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "this device.\n"); 2671a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_set_intfdata(interface, NULL); 2672a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = -ENOMEM; 2673a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto error; 2674a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2675a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->class = &ftdi_elan_jtag_class; 2676a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_info(&ftdi->udev->dev, "USB FDTI=%p JTAG interface " 2677a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "%d now attached to ftdi%d\n", ftdi, 2678a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech iface_desc->desc.bInterfaceNumber, 2679a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech interface->minor); 2680a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 2681a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2682a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else if (iface_desc->desc.bInterfaceNumber == 1 && 2683a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_in_endpointAddr == 0x83 && 2684a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->bulk_out_endpointAddr == 0x04) { 2685a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->class = NULL; 2686a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_info(&ftdi->udev->dev, "USB FDTI=%p ELAN interface %d now a" 2687a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "ctivated\n", ftdi, iface_desc->desc.bInterfaceNumber); 2688a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech INIT_WORK(&ftdi->status_work, ftdi_elan_status_work, 2689a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech (void *)ftdi); 2690a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech INIT_WORK(&ftdi->command_work, ftdi_elan_command_work, 2691a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech (void *)ftdi); 2692a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech INIT_WORK(&ftdi->respond_work, ftdi_elan_respond_work, 2693a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech (void *)ftdi); 2694a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_status_queue_work(ftdi, msecs_to_jiffies(3 *1000)); 2695a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return 0; 2696a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2697a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_err(&ftdi->udev->dev, 2698a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "Could not find ELAN's U132 device\n"); 2699a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech retval = -ENODEV; 2700a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech goto error; 2701a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2702a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech error:if (ftdi) { 2703a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_put_kref(ftdi); 2704a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2705a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return retval; 2706a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 2707a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 2708a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void ftdi_elan_disconnect(struct usb_interface *interface) 2709a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 2710a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi = usb_get_intfdata(interface); 2711a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->disconnected += 1; 2712a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi->class) { 2713a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int minor = interface->minor; 2714a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_class_driver *class = ftdi->class; 2715a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_set_intfdata(interface, NULL); 2716a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_deregister_dev(interface, class); 2717a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_info(&ftdi->udev->dev, "USB FTDI U132 jtag interface on min" 2718a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "or %d now disconnected\n", minor); 2719a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } else { 2720a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_status_cancel_work(ftdi); 2721a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_command_cancel_work(ftdi); 2722a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_response_cancel_work(ftdi); 2723a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_abandon_completions(ftdi); 2724a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_abandon_targets(ftdi); 2725a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (ftdi->registered) { 2726a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech platform_device_unregister(&ftdi->platform_dev); 2727a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->synchronized = 0; 2728a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->enumerated = 0; 2729a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->registered = 0; 2730a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2731a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech flush_workqueue(status_queue); 2732a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech flush_workqueue(command_queue); 2733a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech flush_workqueue(respond_queue); 2734a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi->disconnected += 1; 2735a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_set_intfdata(interface, NULL); 2736a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech dev_info(&ftdi->udev->dev, "USB FTDI U132 host controller inter" 2737a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech "face now disconnected\n"); 2738a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } 2739a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_elan_put_kref(ftdi); 2740a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 2741a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 2742a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic struct usb_driver ftdi_elan_driver = { 2743a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .name = "ftdi-elan", 2744a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .probe = ftdi_elan_probe, 2745a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .disconnect = ftdi_elan_disconnect, 2746a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech .id_table = ftdi_elan_table, 2747a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech}; 2748a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic int __init ftdi_elan_init(void) 2749a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 2750a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech int result; 2751a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech printk(KERN_INFO "driver %s built at %s on %s\n", ftdi_elan_driver.name, 2752a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech __TIME__, __DATE__); 2753a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech init_MUTEX(&ftdi_module_lock); 2754a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech INIT_LIST_HEAD(&ftdi_static_list); 2755a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech status_queue = create_singlethread_workqueue("ftdi-status-control"); 2756a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_queue = create_singlethread_workqueue("ftdi-command-engine"); 2757a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond_queue = create_singlethread_workqueue("ftdi-respond-engine"); 2758a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech result = usb_register(&ftdi_elan_driver); 2759a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech if (result) 2760a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech printk(KERN_ERR "usb_register failed. Error number %d\n", 2761a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech result); 2762a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech return result; 2763a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 2764a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 2765a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechstatic void __exit ftdi_elan_exit(void) 2766a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech{ 2767a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *ftdi; 2768a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech struct usb_ftdi *temp; 2769a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech usb_deregister(&ftdi_elan_driver); 2770a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech printk(KERN_INFO "ftdi_u132 driver deregistered\n"); 2771a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech list_for_each_entry_safe(ftdi, temp, &ftdi_static_list, ftdi_list) { 2772a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_status_cancel_work(ftdi); 2773a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_command_cancel_work(ftdi); 2774a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech ftdi_response_cancel_work(ftdi); 2775a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech } flush_workqueue(status_queue); 2776a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech destroy_workqueue(status_queue); 2777a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech status_queue = NULL; 2778a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech flush_workqueue(command_queue); 2779a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech destroy_workqueue(command_queue); 2780a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech command_queue = NULL; 2781a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech flush_workqueue(respond_queue); 2782a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech destroy_workqueue(respond_queue); 2783a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech respond_queue = NULL; 2784a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech} 2785a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 2786a5c66e4b2418278786a025a5bd9625f485b2087aTony Olech 2787a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechmodule_init(ftdi_elan_init); 2788a5c66e4b2418278786a025a5bd9625f485b2087aTony Olechmodule_exit(ftdi_elan_exit); 2789