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