⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ftdi-elan.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/** 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 program is free software;you can redistribute it and/or* modify it under the terms of the GNU General Public License as* published by the Free Software Foundation, version 2.*** 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.**/#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 <asm/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 int distrust_firmware = 1;module_param(distrust_firmware, bool, 0);MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurren"        "t setup");extern struct platform_driver u132_platform_driver;static struct workqueue_struct *status_queue;static struct workqueue_struct *command_queue;static struct workqueue_struct *respond_queue;/** 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 "../core/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 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 recieved;        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;}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 (!queue_delayed_work(status_queue, &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 (queue_delayed_work(status_queue, &ftdi->status_work, delta))		kref_get(&ftdi->kref);}static void ftdi_status_cancel_work(struct usb_ftdi *ftdi){        if (cancel_delayed_work(&ftdi->status_work))                kref_put(&ftdi->kref, ftdi_elan_delete);}static void ftdi_command_requeue_work(struct usb_ftdi *ftdi, unsigned int delta){	if (!queue_delayed_work(command_queue, &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 (queue_delayed_work(command_queue, &ftdi->command_work, delta))		kref_get(&ftdi->kref);}static void ftdi_command_cancel_work(struct usb_ftdi *ftdi){        if (cancel_delayed_work(&ftdi->command_work))                kref_put(&ftdi->kref, ftdi_elan_delete);}static void ftdi_response_requeue_work(struct usb_ftdi *ftdi,        unsigned int delta){	if (!queue_delayed_work(respond_queue, &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 (queue_delayed_work(respond_queue, &ftdi->respond_work, delta))		kref_get(&ftdi->kref);}static void ftdi_response_cancel_work(struct usb_ftdi *ftdi){        if (cancel_delayed_work(&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){        int result;        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);        result = platform_device_register(&ftdi->platform_dev);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -