diff options
Diffstat (limited to 'drivers/usb/misc')
-rw-r--r-- | drivers/usb/misc/Kconfig | 51 | ||||
-rw-r--r-- | drivers/usb/misc/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/misc/ftdi-elan.c | 2780 | ||||
-rw-r--r-- | drivers/usb/misc/sisusbvga/sisusbvga.c | 14 | ||||
-rw-r--r-- | drivers/usb/misc/usb251xb.c | 43 | ||||
-rw-r--r-- | drivers/usb/misc/usb3503.c | 64 |
6 files changed, 98 insertions, 2855 deletions
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index a5f7652db7da..99b15b77dfd5 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -4,6 +4,35 @@ # comment "USB Miscellaneous drivers" +config USB_USS720 + tristate "USS720 parport driver" + depends on PARPORT + select PARPORT_NOT_PC + help + This driver is for USB parallel port adapters that use the Lucent + Technologies USS-720 chip. These cables are plugged into your USB + port and provide USB compatibility to peripherals designed with + parallel port interfaces. + + The chip has two modes: automatic mode and manual mode. In automatic + mode, it looks to the computer like a standard USB printer. Only + printers may be connected to the USS-720 in this mode. The generic + USB printer driver ("USB Printer support", above) may be used in + that mode, and you can say N here if you want to use the chip only + in this mode. + + Manual mode is not limited to printers, any parallel port + device should work. This driver utilizes manual mode. + Note however that some operations are three orders of magnitude + slower than on a PCI/ISA Parallel Port, so timing critical + applications might not work. + + Say Y here if you own an USS-720 USB->Parport cable and intend to + connect anything other than a printer to it. + + To compile this driver as a module, choose M here: the + module will be called uss720. + config USB_EMI62 tristate "EMI 6|2m USB Audio interface support" help @@ -108,28 +137,6 @@ config USB_IDMOUSE See also <https://www.fs.tum.de/~echtler/idmouse/>. -config USB_FTDI_ELAN - tristate "Elan PCMCIA CardBus Adapter USB Client" - help - ELAN's Uxxx series of adapters are USB to PCMCIA CardBus adapters. - Currently only the U132 adapter is available. - - The U132 is specifically designed for CardBus PC cards that contain - an OHCI host controller. Typical PC cards are the Orange Mobile 3G - Option GlobeTrotter Fusion card. The U132 adapter will *NOT* work - with PC cards that do not contain an OHCI controller. To use a U132 - adapter you will need this "ftdi-elan" module as well as the "u132-hcd" - module which is a USB host controller driver that talks to the OHCI - controller within CardBus card that are inserted in the U132 adapter. - - This driver has been tested with a CardBus OHCI USB adapter, and - worked with a USB PEN Drive inserted into the first USB port of - the PCCARD. A rather pointless thing to do, but useful for testing. - - See also the USB_U132_HCD entry "Elan U132 Adapter Host Controller" - - It is safe to say M here. - config USB_APPLEDISPLAY tristate "Apple Cinema Display support" select BACKLIGHT_CLASS_DEVICE diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 93581baec3a8..1992cc284d8a 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -10,7 +10,6 @@ obj-$(CONFIG_USB_CYTHERM) += cytherm.o obj-$(CONFIG_USB_EMI26) += emi26.o obj-$(CONFIG_USB_EMI62) += emi62.o obj-$(CONFIG_USB_EZUSB_FX2) += ezusb.o -obj-$(CONFIG_USB_FTDI_ELAN) += ftdi-elan.o obj-$(CONFIG_APPLE_MFI_FASTCHARGE) += apple-mfi-fastcharge.o obj-$(CONFIG_USB_IDMOUSE) += idmouse.o obj-$(CONFIG_USB_IOWARRIOR) += iowarrior.o diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c deleted file mode 100644 index 8ce191e3a4c0..000000000000 --- a/drivers/usb/misc/ftdi-elan.c +++ /dev/null @@ -1,2780 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * USB FTDI client driver for Elan Digital Systems's Uxxx adapters - * - * Copyright(C) 2006 Elan Digital Systems Limited - * http://www.elandigitalsystems.com - * - * Author and Maintainer - Tony Olech - Elan Digital Systems - * tony.olech@elandigitalsystems.com - * - * This driver was written by Tony Olech(tony.olech@elandigitalsystems.com) - * based on various USB client drivers in the 2.6.15 linux kernel - * with constant reference to the 3rd Edition of Linux Device Drivers - * published by O'Reilly - * - * The U132 adapter is a USB to CardBus adapter specifically designed - * for PC cards that contain an OHCI host controller. Typical PC cards - * are the Orange Mobile 3G Option GlobeTrotter Fusion card. - * - * The U132 adapter will *NOT *work with PC cards that do not contain - * an OHCI controller. A simple way to test whether a PC card has an - * OHCI controller as an interface is to insert the PC card directly - * into a laptop(or desktop) with a CardBus slot and if "lspci" shows - * a new USB controller and "lsusb -v" shows a new OHCI Host Controller - * then there is a good chance that the U132 adapter will support the - * PC card.(you also need the specific client driver for the PC card) - * - * Please inform the Author and Maintainer about any PC cards that - * contain OHCI Host Controller and work when directly connected to - * an embedded CardBus slot but do not work when they are connected - * via an ELAN U132 adapter. - * - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/list.h> -#include <linux/ioctl.h> -#include <linux/pci_ids.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/kref.h> -#include <linux/mutex.h> -#include <linux/uaccess.h> -#include <linux/usb.h> -#include <linux/workqueue.h> -#include <linux/platform_device.h> -MODULE_AUTHOR("Tony Olech"); -MODULE_DESCRIPTION("FTDI ELAN driver"); -MODULE_LICENSE("GPL"); -#define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444) -static bool distrust_firmware = 1; -module_param(distrust_firmware, bool, 0); -MODULE_PARM_DESC(distrust_firmware, - "true to distrust firmware power/overcurrent setup"); -extern struct platform_driver u132_platform_driver; -/* - * ftdi_module_lock exists to protect access to global variables - * - */ -static struct mutex ftdi_module_lock; -static int ftdi_instances = 0; -static struct list_head ftdi_static_list; -/* - * end of the global variables protected by ftdi_module_lock - */ -#include "usb_u132.h" -#include <asm/io.h> -#include <linux/usb/hcd.h> - -/* FIXME ohci.h is ONLY for internal use by the OHCI driver. - * If you're going to try stuff like this, you need to split - * out shareable stuff (register declarations?) into its own - * file, maybe name <linux/usb/ohci.h> - */ - -#include "../host/ohci.h" -/* Define these values to match your devices*/ -#define USB_FTDI_ELAN_VENDOR_ID 0x0403 -#define USB_FTDI_ELAN_PRODUCT_ID 0xd6ea -/* table of devices that work with this driver*/ -static const struct usb_device_id ftdi_elan_table[] = { - {USB_DEVICE(USB_FTDI_ELAN_VENDOR_ID, USB_FTDI_ELAN_PRODUCT_ID)}, - { /* Terminating entry */ } -}; - -MODULE_DEVICE_TABLE(usb, ftdi_elan_table); -/* only the jtag(firmware upgrade device) interface requires - * a device file and corresponding minor number, but the - * interface is created unconditionally - I suppose it could - * be configured or not according to a module parameter. - * But since we(now) require one interface per device, - * and since it unlikely that a normal installation would - * require more than a couple of elan-ftdi devices, 8 seems - * like a reasonable limit to have here, and if someone - * really requires more than 8 devices, then they can frig the - * code and recompile - */ -#define USB_FTDI_ELAN_MINOR_BASE 192 -#define COMMAND_BITS 5 -#define COMMAND_SIZE (1<<COMMAND_BITS) -#define COMMAND_MASK (COMMAND_SIZE-1) -struct u132_command { - u8 header; - u16 length; - u8 address; - u8 width; - u32 value; - int follows; - void *buffer; -}; -#define RESPOND_BITS 5 -#define RESPOND_SIZE (1<<RESPOND_BITS) -#define RESPOND_MASK (RESPOND_SIZE-1) -struct u132_respond { - u8 header; - u8 address; - u32 *value; - int *result; - struct completion wait_completion; -}; -struct u132_target { - void *endp; - struct urb *urb; - int toggle_bits; - int error_count; - int condition_code; - int repeat_number; - int halted; - int skipped; - int actual; - int non_null; - int active; - int abandoning; - void (*callback)(void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, - int non_null); -}; -/* Structure to hold all of our device specific stuff*/ -struct usb_ftdi { - struct list_head ftdi_list; - struct mutex u132_lock; - int command_next; - int command_head; - struct u132_command command[COMMAND_SIZE]; - int respond_next; - int respond_head; - struct u132_respond respond[RESPOND_SIZE]; - struct u132_target target[4]; - char device_name[16]; - unsigned synchronized:1; - unsigned enumerated:1; - unsigned registered:1; - unsigned initialized:1; - unsigned card_ejected:1; - int function; - int sequence_num; - int disconnected; - int gone_away; - int stuck_status; - int status_queue_delay; - struct semaphore sw_lock; - struct usb_device *udev; - struct usb_interface *interface; - struct usb_class_driver *class; - struct delayed_work status_work; - struct delayed_work command_work; - struct delayed_work respond_work; - struct u132_platform_data platform_data; - struct resource resources[0]; - struct platform_device platform_dev; - unsigned char *bulk_in_buffer; - size_t bulk_in_size; - size_t bulk_in_last; - size_t bulk_in_left; - __u8 bulk_in_endpointAddr; - __u8 bulk_out_endpointAddr; - struct kref kref; - u32 controlreg; - u8 response[4 + 1024]; - int expected; - int received; - int ed_found; -}; -#define kref_to_usb_ftdi(d) container_of(d, struct usb_ftdi, kref) -#define platform_device_to_usb_ftdi(d) container_of(d, struct usb_ftdi, \ - platform_dev) -static struct usb_driver ftdi_elan_driver; -static void ftdi_elan_delete(struct kref *kref) -{ - struct usb_ftdi *ftdi = kref_to_usb_ftdi(kref); - dev_warn(&ftdi->udev->dev, "FREEING ftdi=%p\n", ftdi); - usb_put_dev(ftdi->udev); - ftdi->disconnected += 1; - mutex_lock(&ftdi_module_lock); - list_del_init(&ftdi->ftdi_list); - ftdi_instances -= 1; - mutex_unlock(&ftdi_module_lock); - kfree(ftdi->bulk_in_buffer); - ftdi->bulk_in_buffer = NULL; - kfree(ftdi); -} - -static void ftdi_elan_put_kref(struct usb_ftdi *ftdi) -{ - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_elan_get_kref(struct usb_ftdi *ftdi) -{ - kref_get(&ftdi->kref); -} - -static void ftdi_elan_init_kref(struct usb_ftdi *ftdi) -{ - kref_init(&ftdi->kref); -} - -static void ftdi_status_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) -{ - if (!schedule_delayed_work(&ftdi->status_work, delta)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_status_queue_work(struct usb_ftdi *ftdi, unsigned int delta) -{ - if (schedule_delayed_work(&ftdi->status_work, delta)) - kref_get(&ftdi->kref); -} - -static void ftdi_status_cancel_work(struct usb_ftdi *ftdi) -{ - if (cancel_delayed_work_sync(&ftdi->status_work)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_command_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) -{ - if (!schedule_delayed_work(&ftdi->command_work, delta)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_command_queue_work(struct usb_ftdi *ftdi, unsigned int delta) -{ - if (schedule_delayed_work(&ftdi->command_work, delta)) - kref_get(&ftdi->kref); -} - -static void ftdi_command_cancel_work(struct usb_ftdi *ftdi) -{ - if (cancel_delayed_work_sync(&ftdi->command_work)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_response_requeue_work(struct usb_ftdi *ftdi, - unsigned int delta) -{ - if (!schedule_delayed_work(&ftdi->respond_work, delta)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_respond_queue_work(struct usb_ftdi *ftdi, unsigned int delta) -{ - if (schedule_delayed_work(&ftdi->respond_work, delta)) - kref_get(&ftdi->kref); -} - -static void ftdi_response_cancel_work(struct usb_ftdi *ftdi) -{ - if (cancel_delayed_work_sync(&ftdi->respond_work)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -void ftdi_elan_gone_away(struct platform_device *pdev) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - ftdi->gone_away += 1; - ftdi_elan_put_kref(ftdi); -} - - -EXPORT_SYMBOL_GPL(ftdi_elan_gone_away); -static void ftdi_release_platform_dev(struct device *dev) -{ - dev->parent = NULL; -} - -static void ftdi_elan_do_callback(struct usb_ftdi *ftdi, - struct u132_target *target, u8 *buffer, int length); -static void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi); -static void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi); -static int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi); -static int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi); -static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi); -static int ftdi_elan_synchronize(struct usb_ftdi *ftdi); -static int ftdi_elan_stuck_waiting(struct usb_ftdi *ftdi); -static int ftdi_elan_command_engine(struct usb_ftdi *ftdi); -static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi); -static int ftdi_elan_hcd_init(struct usb_ftdi *ftdi) -{ - if (ftdi->platform_dev.dev.parent) - return -EBUSY; - - ftdi_elan_get_kref(ftdi); - ftdi->platform_data.potpg = 100; - ftdi->platform_data.reset = NULL; - ftdi->platform_dev.id = ftdi->sequence_num; - ftdi->platform_dev.resource = ftdi->resources; - ftdi->platform_dev.num_resources = ARRAY_SIZE(ftdi->resources); - ftdi->platform_dev.dev.platform_data = &ftdi->platform_data; - ftdi->platform_dev.dev.parent = NULL; - ftdi->platform_dev.dev.release = ftdi_release_platform_dev; - ftdi->platform_dev.dev.dma_mask = NULL; - snprintf(ftdi->device_name, sizeof(ftdi->device_name), "u132_hcd"); - ftdi->platform_dev.name = ftdi->device_name; - dev_info(&ftdi->udev->dev, "requesting module '%s'\n", "u132_hcd"); - request_module("u132_hcd"); - dev_info(&ftdi->udev->dev, "registering '%s'\n", - ftdi->platform_dev.name); - - return platform_device_register(&ftdi->platform_dev); -} - -static void ftdi_elan_abandon_completions(struct usb_ftdi *ftdi) -{ - mutex_lock(&ftdi->u132_lock); - while (ftdi->respond_next > ftdi->respond_head) { - struct u132_respond *respond = &ftdi->respond[RESPOND_MASK & - ftdi->respond_head++]; - *respond->result = -ESHUTDOWN; - *respond->value = 0; - complete(&respond->wait_completion); - } - mutex_unlock(&ftdi->u132_lock); -} - -static void ftdi_elan_abandon_targets(struct usb_ftdi *ftdi) -{ - int ed_number = 4; - mutex_lock(&ftdi->u132_lock); - while (ed_number-- > 0) { - struct u132_target *target = &ftdi->target[ed_number]; - if (target->active == 1) { - target->condition_code = TD_DEVNOTRESP; - mutex_unlock(&ftdi->u132_lock); - ftdi_elan_do_callback(ftdi, target, NULL, 0); - mutex_lock(&ftdi->u132_lock); - } - } - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - mutex_unlock(&ftdi->u132_lock); -} - -static void ftdi_elan_flush_targets(struct usb_ftdi *ftdi) -{ - int ed_number = 4; - mutex_lock(&ftdi->u132_lock); - while (ed_number-- > 0) { - struct u132_target *target = &ftdi->target[ed_number]; - target->abandoning = 1; - wait_1:if (target->active == 1) { - int command_size = ftdi->command_next - - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x80 | (ed_number << 5) | 0x4; - command->length = 0x00; - command->address = 0x00; - command->width = 0x00; - command->follows = 0; - command->value = 0; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - mutex_lock(&ftdi->u132_lock); - goto wait_1; - } - } - wait_2:if (target->active == 1) { - int command_size = ftdi->command_next - - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x90 | (ed_number << 5); - command->length = 0x00; - command->address = 0x00; - command->width = 0x00; - command->follows = 0; - command->value = 0; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - mutex_lock(&ftdi->u132_lock); - goto wait_2; - } - } - } - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - mutex_unlock(&ftdi->u132_lock); -} - -static void ftdi_elan_cancel_targets(struct usb_ftdi *ftdi) -{ - int ed_number = 4; - mutex_lock(&ftdi->u132_lock); - while (ed_number-- > 0) { - struct u132_target *target = &ftdi->target[ed_number]; - target->abandoning = 1; - wait:if (target->active == 1) { - int command_size = ftdi->command_next - - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x80 | (ed_number << 5) | 0x4; - command->length = 0x00; - command->address = 0x00; - command->width = 0x00; - command->follows = 0; - command->value = 0; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - mutex_lock(&ftdi->u132_lock); - goto wait; - } - } - } - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - mutex_unlock(&ftdi->u132_lock); -} - -static void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi) -{ - ftdi_command_queue_work(ftdi, 0); -} - -static void ftdi_elan_command_work(struct work_struct *work) -{ - struct usb_ftdi *ftdi = - container_of(work, struct usb_ftdi, command_work.work); - - if (ftdi->disconnected > 0) { - ftdi_elan_put_kref(ftdi); - return; - } else { - int retval = ftdi_elan_command_engine(ftdi); - if (retval == -ESHUTDOWN) { - ftdi->disconnected += 1; - } else if (retval == -ENODEV) { - ftdi->disconnected += 1; - } else if (retval) - dev_err(&ftdi->udev->dev, "command error %d\n", retval); - ftdi_command_requeue_work(ftdi, msecs_to_jiffies(10)); - return; - } -} - -static void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi) -{ - ftdi_respond_queue_work(ftdi, 0); -} - -static void ftdi_elan_respond_work(struct work_struct *work) -{ - struct usb_ftdi *ftdi = - container_of(work, struct usb_ftdi, respond_work.work); - if (ftdi->disconnected > 0) { - ftdi_elan_put_kref(ftdi); - return; - } else { - int retval = ftdi_elan_respond_engine(ftdi); - if (retval == 0) { - } else if (retval == -ESHUTDOWN) { - ftdi->disconnected += 1; - } else if (retval == -ENODEV) { - ftdi->disconnected += 1; - } else if (retval == -EILSEQ) { - ftdi->disconnected += 1; - } else { - ftdi->disconnected += 1; - dev_err(&ftdi->udev->dev, "respond error %d\n", retval); - } - if (ftdi->disconnected > 0) { - ftdi_elan_abandon_completions(ftdi); - ftdi_elan_abandon_targets(ftdi); - } - ftdi_response_requeue_work(ftdi, msecs_to_jiffies(10)); - return; - } -} - - -/* - * the sw_lock is initially held and will be freed - * after the FTDI has been synchronized - * - */ -static void ftdi_elan_status_work(struct work_struct *work) -{ - struct usb_ftdi *ftdi = - container_of(work, struct usb_ftdi, status_work.work); - int work_delay_in_msec = 0; - if (ftdi->disconnected > 0) { - ftdi_elan_put_kref(ftdi); - return; - } else if (ftdi->synchronized == 0) { - down(&ftdi->sw_lock); - if (ftdi_elan_synchronize(ftdi) == 0) { - ftdi->synchronized = 1; - ftdi_command_queue_work(ftdi, 1); - ftdi_respond_queue_work(ftdi, 1); - up(&ftdi->sw_lock); - work_delay_in_msec = 100; - } else { - dev_err(&ftdi->udev->dev, "synchronize failed\n"); - up(&ftdi->sw_lock); - work_delay_in_msec = 10 *1000; - } - } else if (ftdi->stuck_status > 0) { - if (ftdi_elan_stuck_waiting(ftdi) == 0) { - ftdi->stuck_status = 0; - ftdi->synchronized = 0; - } else if ((ftdi->stuck_status++ % 60) == 1) { - dev_err(&ftdi->udev->dev, "WRONG type of card inserted - please remove\n"); - } else - dev_err(&ftdi->udev->dev, "WRONG type of card inserted - checked %d times\n", - ftdi->stuck_status); - work_delay_in_msec = 100; - } else if (ftdi->enumerated == 0) { - if (ftdi_elan_enumeratePCI(ftdi) == 0) { - ftdi->enumerated = 1; - work_delay_in_msec = 250; - } else - work_delay_in_msec = 1000; - } else if (ftdi->initialized == 0) { - if (ftdi_elan_setupOHCI(ftdi) == 0) { - ftdi->initialized = 1; - work_delay_in_msec = 500; - } else { - dev_err(&ftdi->udev->dev, "initialized failed - trying again in 10 seconds\n"); - work_delay_in_msec = 1 *1000; - } - } else if (ftdi->registered == 0) { - work_delay_in_msec = 10; - if (ftdi_elan_hcd_init(ftdi) == 0) { - ftdi->registered = 1; - } else - dev_err(&ftdi->udev->dev, "register failed\n"); - work_delay_in_msec = 250; - } else { - if (ftdi_elan_checkingPCI(ftdi) == 0) { - work_delay_in_msec = 250; - } else if (ftdi->controlreg & 0x00400000) { - if (ftdi->gone_away > 0) { - dev_err(&ftdi->udev->dev, "PCI device eject confirmed platform_dev.dev.parent=%p platform_dev.dev=%p\n", - ftdi->platform_dev.dev.parent, - &ftdi->platform_dev.dev); - platform_device_unregister(&ftdi->platform_dev); - ftdi->platform_dev.dev.parent = NULL; - ftdi->registered = 0; - ftdi->enumerated = 0; - ftdi->card_ejected = 0; - ftdi->initialized = 0; - ftdi->gone_away = 0; - } else - ftdi_elan_flush_targets(ftdi); - work_delay_in_msec = 250; - } else { - dev_err(&ftdi->udev->dev, "PCI device has disappeared\n"); - ftdi_elan_cancel_targets(ftdi); - work_delay_in_msec = 500; - ftdi->enumerated = 0; - ftdi->initialized = 0; - } - } - if (ftdi->disconnected > 0) { - ftdi_elan_put_kref(ftdi); - return; - } else { - ftdi_status_requeue_work(ftdi, - msecs_to_jiffies(work_delay_in_msec)); - return; - } -} - - -/* - * file_operations for the jtag interface - * - * the usage count for the device is incremented on open() - * and decremented on release() - */ -static int ftdi_elan_open(struct inode *inode, struct file *file) -{ - int subminor; - struct usb_interface *interface; - - subminor = iminor(inode); - interface = usb_find_interface(&ftdi_elan_driver, subminor); - - if (!interface) { - pr_err("can't find device for minor %d\n", subminor); - return -ENODEV; - } else { - struct usb_ftdi *ftdi = usb_get_intfdata(interface); - if (!ftdi) { - return -ENODEV; - } else { - if (down_interruptible(&ftdi->sw_lock)) { - return -EINTR; - } else { - ftdi_elan_get_kref(ftdi); - file->private_data = ftdi; - return 0; - } - } - } -} - -static int ftdi_elan_release(struct inode *inode, struct file *file) -{ - struct usb_ftdi *ftdi = file->private_data; - if (ftdi == NULL) - return -ENODEV; - up(&ftdi->sw_lock); /* decrement the count on our device */ - ftdi_elan_put_kref(ftdi); - return 0; -} - - -/* - * - * blocking bulk reads are used to get data from the device - * - */ -static ssize_t ftdi_elan_read(struct file *file, char __user *buffer, - size_t count, loff_t *ppos) -{ - char data[30 *3 + 4]; - char *d = data; - int m = (sizeof(data) - 1) / 3 - 1; - int bytes_read = 0; - int retry_on_empty = 10; - int retry_on_timeout = 5; - struct usb_ftdi *ftdi = file->private_data; - if (ftdi->disconnected > 0) { - return -ENODEV; - } - data[0] = 0; -have:if (ftdi->bulk_in_left > 0) { - if (count-- > 0) { - char *p = ++ftdi->bulk_in_last + ftdi->bulk_in_buffer; - ftdi->bulk_in_left -= 1; - if (bytes_read < m) { - d += sprintf(d, " %02X", 0x000000FF & *p); - } else if (bytes_read > m) { - } else - d += sprintf(d, " .."); - if (copy_to_user(buffer++, p, 1)) { - return -EFAULT; - } else { - bytes_read += 1; - goto have; - } - } else - return bytes_read; - } -more:if (count > 0) { - int packet_bytes = 0; - int retval = usb_bulk_msg(ftdi->udev, - usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), - ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, 50); - if (packet_bytes > 2) { - ftdi->bulk_in_left = packet_bytes - 2; - ftdi->bulk_in_last = 1; - goto have; - } else if (retval == -ETIMEDOUT) { - if (retry_on_timeout-- > 0) { - goto more; - } else if (bytes_read > 0) { - return bytes_read; - } else - return retval; - } else if (retval == 0) { - if (retry_on_empty-- > 0) { - goto more; - } else - return bytes_read; - } else - return retval; - } else - return bytes_read; -} - -static void ftdi_elan_write_bulk_callback(struct urb *urb) -{ - struct usb_ftdi *ftdi = urb->context; - int status = urb->status; - - if (status && !(status == -ENOENT || status == -ECONNRESET || - status == -ESHUTDOWN)) { - dev_err(&ftdi->udev->dev, - "urb=%p write bulk status received: %d\n", urb, status); - } - usb_free_coherent(urb->dev, urb->transfer_buffer_length, - urb->transfer_buffer, urb->transfer_dma); -} - -static int fill_buffer_with_all_queued_commands(struct usb_ftdi *ftdi, - char *buf, int command_size, int total_size) -{ - int ed_commands = 0; - int b = 0; - int I = command_size; - int i = ftdi->command_head; - while (I-- > 0) { - struct u132_command *command = &ftdi->command[COMMAND_MASK & - i++]; - int F = command->follows; - u8 *f = command->buffer; - if (command->header & 0x80) { - ed_commands |= 1 << (0x3 & (command->header >> 5)); - } - buf[b++] = command->header; - buf[b++] = (command->length >> 0) & 0x00FF; - buf[b++] = (command->length >> 8) & 0x00FF; - buf[b++] = command->address; - buf[b++] = command->width; - while (F-- > 0) { - buf[b++] = *f++; - } - } - return ed_commands; -} - -static int ftdi_elan_total_command_size(struct usb_ftdi *ftdi, int command_size) -{ - int total_size = 0; - int I = command_size; - int i = ftdi->command_head; - while (I-- > 0) { - struct u132_command *command = &ftdi->command[COMMAND_MASK & - i++]; - total_size += 5 + command->follows; - } - return total_size; -} - -static int ftdi_elan_command_engine(struct usb_ftdi *ftdi) -{ - int retval; - char *buf; - int ed_commands; - int total_size; - struct urb *urb; - int command_size = ftdi->command_next - ftdi->command_head; - if (command_size == 0) - return 0; - total_size = ftdi_elan_total_command_size(ftdi, command_size); - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - return -ENOMEM; - buf = usb_alloc_coherent(ftdi->udev, total_size, GFP_KERNEL, - &urb->transfer_dma); - if (!buf) { - dev_err(&ftdi->udev->dev, "could not get a buffer to write %d commands totaling %d bytes to the Uxxx\n", - command_size, total_size); - usb_free_urb(urb); - return -ENOMEM; - } - ed_commands = fill_buffer_with_all_queued_commands(ftdi, buf, - command_size, total_size); - usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, - ftdi->bulk_out_endpointAddr), buf, total_size, - ftdi_elan_write_bulk_callback, ftdi); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - if (ed_commands) { - char diag[40 *3 + 4]; - char *d = diag; - int m = total_size; - u8 *c = buf; - int s = (sizeof(diag) - 1) / 3; - diag[0] = 0; - while (s-- > 0 && m-- > 0) { - if (s > 0 || m == 0) { - d += sprintf(d, " %02X", *c++); - } else - d += sprintf(d, " .."); - } - } - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval) { - dev_err(&ftdi->udev->dev, "failed %d to submit urb %p to write %d commands totaling %d bytes to the Uxxx\n", - retval, urb, command_size, total_size); - usb_free_coherent(ftdi->udev, total_size, buf, urb->transfer_dma); - usb_free_urb(urb); - return retval; - } - usb_free_urb(urb); /* release our reference to this urb, - the USB core will eventually free it entirely */ - ftdi->command_head += command_size; - ftdi_elan_kick_respond_queue(ftdi); - return 0; -} - -static void ftdi_elan_do_callback(struct usb_ftdi *ftdi, - struct u132_target *target, u8 *buffer, int length) -{ - struct urb *urb = target->urb; - int halted = target->halted; - int skipped = target->skipped; - int actual = target->actual; - int non_null = target->non_null; - int toggle_bits = target->toggle_bits; - int error_count = target->error_count; - int condition_code = target->condition_code; - int repeat_number = target->repeat_number; - void (*callback) (void *, struct urb *, u8 *, int, int, int, int, int, - int, int, int, int) = target->callback; - target->active -= 1; - target->callback = NULL; - (*callback) (target->endp, urb, buffer, length, toggle_bits, - error_count, condition_code, repeat_number, halted, skipped, - actual, non_null); -} - -static char *have_ed_set_response(struct usb_ftdi *ftdi, - struct u132_target *target, u16 ed_length, int ed_number, int ed_type, - char *b) -{ - int payload = (ed_length >> 0) & 0x07FF; - mutex_lock(&ftdi->u132_lock); - target->actual = 0; - target->non_null = (ed_length >> 15) & 0x0001; - target->repeat_number = (ed_length >> 11) & 0x000F; - if (ed_type == 0x02 || ed_type == 0x03) { - if (payload == 0 || target->abandoning > 0) { - target->abandoning = 0; - mutex_unlock(&ftdi->u132_lock); - ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, - payload); - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - return ftdi->response; - } else { - ftdi->expected = 4 + payload; - ftdi->ed_found = 1; - mutex_unlock(&ftdi->u132_lock); - return b; - } - } else { - target->abandoning = 0; - mutex_unlock(&ftdi->u132_lock); - ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, - payload); - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - return ftdi->response; - } -} - -static char *have_ed_get_response(struct usb_ftdi *ftdi, - struct u132_target *target, u16 ed_length, int ed_number, int ed_type, - char *b) -{ - mutex_lock(&ftdi->u132_lock); - target->condition_code = TD_DEVNOTRESP; - target->actual = (ed_length >> 0) & 0x01FF; - target->non_null = (ed_length >> 15) & 0x0001; - target->repeat_number = (ed_length >> 11) & 0x000F; - mutex_unlock(&ftdi->u132_lock); - if (target->active) - ftdi_elan_do_callback(ftdi, target, NULL, 0); - target->abandoning = 0; - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - return ftdi->response; -} - - -/* - * The engine tries to empty the FTDI fifo - * - * all responses found in the fifo data are dispatched thus - * the response buffer can only ever hold a maximum sized - * response from the Uxxx. - * - */ -static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi) -{ - u8 *b = ftdi->response + ftdi->received; - int bytes_read = 0; - int retry_on_empty = 1; - int retry_on_timeout = 3; -read:{ - int packet_bytes = 0; - int retval = usb_bulk_msg(ftdi->udev, - usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), - ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, 500); - char diag[30 *3 + 4]; - char *d = diag; - int m = packet_bytes; - u8 *c = ftdi->bulk_in_buffer; - int s = (sizeof(diag) - 1) / 3; - diag[0] = 0; - while (s-- > 0 && m-- > 0) { - if (s > 0 || m == 0) { - d += sprintf(d, " %02X", *c++); - } else - d += sprintf(d, " .."); - } - if (packet_bytes > 2) { - ftdi->bulk_in_left = packet_bytes - 2; - ftdi->bulk_in_last = 1; - goto have; - } else if (retval == -ETIMEDOUT) { - if (retry_on_timeout-- > 0) { - dev_err(&ftdi->udev->dev, "TIMED OUT with packet_bytes = %d with total %d bytes%s\n", - packet_bytes, bytes_read, diag); |