📄 ti_usb_3410_5052.c
字号:
/* vi: ts=8 sw=8 * * TI 3410/5052 USB Serial Driver * * Copyright (C) 2004 Texas Instruments * * This driver is based on the Linux io_ti driver, which is * Copyright (C) 2000-2002 Inside Out Networks * Copyright (C) 2001-2002 Greg Kroah-Hartman * * 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; either version 2 of the License, or * (at your option) any later version. * * For questions or problems with this driver, contact Texas Instruments * technical support, or Al Borchers <alborchers@steinerpoint.com>, or * Peter Berger <pberger@brimson.com>. * * This driver needs this hotplug script in /etc/hotplug/usb/ti_usb_3410_5052 * or in /etc/hotplug.d/usb/ti_usb_3410_5052.hotplug to set the device * configuration. * * #!/bin/bash * * BOOT_CONFIG=1 * ACTIVE_CONFIG=2 * * if [[ "$ACTION" != "add" ]] * then * exit * fi * * CONFIG_PATH=/sys${DEVPATH%/?*}/bConfigurationValue * * if [[ 0`cat $CONFIG_PATH` -ne $BOOT_CONFIG ]] * then * exit * fi * * PRODUCT=${PRODUCT%/?*} # delete version * VENDOR_ID=`printf "%d" 0x${PRODUCT%/?*}` * PRODUCT_ID=`printf "%d" 0x${PRODUCT#*?/}` * * PARAM_PATH=/sys/module/ti_usb_3410_5052/parameters * * function scan() { * s=$1 * shift * for i * do * if [[ $s -eq $i ]] * then * return 0 * fi * done * return 1 * } * * IFS=$IFS, * * if (scan $VENDOR_ID 1105 `cat $PARAM_PATH/vendor_3410` && * scan $PRODUCT_ID 13328 `cat $PARAM_PATH/product_3410`) || * (scan $VENDOR_ID 1105 `cat $PARAM_PATH/vendor_5052` && * scan $PRODUCT_ID 20562 20818 20570 20575 `cat $PARAM_PATH/product_5052`) * then * echo $ACTIVE_CONFIG > $CONFIG_PATH * fi */#include <linux/config.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/tty.h>#include <linux/tty_driver.h>#include <linux/tty_flip.h>#include <linux/module.h>#include <linux/spinlock.h>#include <linux/ioctl.h>#include <linux/serial.h>#include <linux/circ_buf.h>#include <asm/uaccess.h>#include <asm/semaphore.h>#include <linux/usb.h>#include "usb-serial.h"#include "ti_usb_3410_5052.h"#include "ti_fw_3410.h" /* firmware image for 3410 */#include "ti_fw_5052.h" /* firmware image for 5052 *//* Defines */#define TI_DRIVER_VERSION "v0.9"#define TI_DRIVER_AUTHOR "Al Borchers <alborchers@steinerpoint.com>"#define TI_DRIVER_DESC "TI USB 3410/5052 Serial Driver"#define TI_FIRMWARE_BUF_SIZE 16284#define TI_WRITE_BUF_SIZE 1024#define TI_TRANSFER_TIMEOUT 2#define TI_DEFAULT_LOW_LATENCY 0#define TI_DEFAULT_CLOSING_WAIT 4000 /* in .01 secs *//* supported setserial flags */#define TI_SET_SERIAL_FLAGS (ASYNC_LOW_LATENCY)/* read urb states */#define TI_READ_URB_RUNNING 0#define TI_READ_URB_STOPPING 1#define TI_READ_URB_STOPPED 2#define TI_EXTRA_VID_PID_COUNT 5/* Structures */struct ti_port { int tp_is_open; __u8 tp_msr; __u8 tp_lsr; __u8 tp_shadow_mcr; __u8 tp_uart_mode; /* 232 or 485 modes */ unsigned int tp_uart_base_addr; int tp_flags; int tp_closing_wait;/* in .01 secs */ struct async_icount tp_icount; wait_queue_head_t tp_msr_wait; /* wait for msr change */ wait_queue_head_t tp_write_wait; struct ti_device *tp_tdev; struct usb_serial_port *tp_port; spinlock_t tp_lock; int tp_read_urb_state; int tp_write_urb_in_use; struct circ_buf *tp_write_buf;};struct ti_device { struct semaphore td_open_close_sem; int td_open_port_count; struct usb_serial *td_serial; int td_is_3410; int td_urb_error;};/* Function Declarations */static int ti_startup(struct usb_serial *serial);static void ti_shutdown(struct usb_serial *serial);static int ti_open(struct usb_serial_port *port, struct file *file);static void ti_close(struct usb_serial_port *port, struct file *file);static int ti_write(struct usb_serial_port *port, const unsigned char *data, int count);static int ti_write_room(struct usb_serial_port *port);static int ti_chars_in_buffer(struct usb_serial_port *port);static void ti_throttle(struct usb_serial_port *port);static void ti_unthrottle(struct usb_serial_port *port);static int ti_ioctl(struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg);static void ti_set_termios(struct usb_serial_port *port, struct termios *old_termios);static int ti_tiocmget(struct usb_serial_port *port, struct file *file);static int ti_tiocmset(struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear);static void ti_break(struct usb_serial_port *port, int break_state);static void ti_interrupt_callback(struct urb *urb, struct pt_regs *regs);static void ti_bulk_in_callback(struct urb *urb, struct pt_regs *regs);static void ti_bulk_out_callback(struct urb *urb, struct pt_regs *regs);static void ti_recv(struct device *dev, struct tty_struct *tty, unsigned char *data, int length);static void ti_send(struct ti_port *tport);static int ti_set_mcr(struct ti_port *tport, unsigned int mcr);static int ti_get_lsr(struct ti_port *tport);static int ti_get_serial_info(struct ti_port *tport, struct serial_struct __user *ret_arg);static int ti_set_serial_info(struct ti_port *tport, struct serial_struct __user *new_arg);static void ti_handle_new_msr(struct ti_port *tport, __u8 msr);static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush);static void ti_stop_read(struct ti_port *tport, struct tty_struct *tty);static int ti_restart_read(struct ti_port *tport, struct tty_struct *tty);static int ti_command_out_sync(struct ti_device *tdev, __u8 command, __u16 moduleid, __u16 value, __u8 *data, int size);static int ti_command_in_sync(struct ti_device *tdev, __u8 command, __u16 moduleid, __u16 value, __u8 *data, int size);static int ti_write_byte(struct ti_device *tdev, unsigned long addr, __u8 mask, __u8 byte);static int ti_download_firmware(struct ti_device *tdev, unsigned char *firmware, unsigned int firmware_size);/* circular buffer */static struct circ_buf *ti_buf_alloc(void);static void ti_buf_free(struct circ_buf *cb);static void ti_buf_clear(struct circ_buf *cb);static int ti_buf_data_avail(struct circ_buf *cb);static int ti_buf_space_avail(struct circ_buf *cb);static int ti_buf_put(struct circ_buf *cb, const char *buf, int count);static int ti_buf_get(struct circ_buf *cb, char *buf, int count);/* Data *//* module parameters */static int debug;static int low_latency = TI_DEFAULT_LOW_LATENCY;static int closing_wait = TI_DEFAULT_CLOSING_WAIT;static ushort vendor_3410[TI_EXTRA_VID_PID_COUNT];static int vendor_3410_count;static ushort product_3410[TI_EXTRA_VID_PID_COUNT];static int product_3410_count;static ushort vendor_5052[TI_EXTRA_VID_PID_COUNT];static int vendor_5052_count;static ushort product_5052[TI_EXTRA_VID_PID_COUNT];static int product_5052_count;/* supported devices *//* the array dimension is the number of default entries plus *//* TI_EXTRA_VID_PID_COUNT user defined entries plus 1 terminating *//* null entry */static struct usb_device_id ti_id_table_3410[1+TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },};static struct usb_device_id ti_id_table_5052[4+TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(TI_VENDOR_ID, TI_5052_BOOT_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_5152_BOOT_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_5052_EEPROM_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) },};static struct usb_device_id ti_id_table_combined[] = { { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_5052_BOOT_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_5152_BOOT_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_5052_EEPROM_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) }, { }};static struct usb_driver ti_usb_driver = { .owner = THIS_MODULE, .name = "ti_usb_3410_5052", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .id_table = ti_id_table_combined,};static struct usb_serial_driver ti_1port_device = { .driver = { .owner = THIS_MODULE, .name = "ti_usb_3410_5052_1", }, .description = "TI USB 3410 1 port adapter", .id_table = ti_id_table_3410, .num_interrupt_in = 1, .num_bulk_in = 1, .num_bulk_out = 1, .num_ports = 1, .attach = ti_startup, .shutdown = ti_shutdown, .open = ti_open, .close = ti_close, .write = ti_write, .write_room = ti_write_room, .chars_in_buffer = ti_chars_in_buffer, .throttle = ti_throttle, .unthrottle = ti_unthrottle, .ioctl = ti_ioctl, .set_termios = ti_set_termios, .tiocmget = ti_tiocmget, .tiocmset = ti_tiocmset, .break_ctl = ti_break, .read_int_callback = ti_interrupt_callback, .read_bulk_callback = ti_bulk_in_callback, .write_bulk_callback = ti_bulk_out_callback,};static struct usb_serial_driver ti_2port_device = { .driver = { .owner = THIS_MODULE, .name = "ti_usb_3410_5052_2", }, .description = "TI USB 5052 2 port adapter", .id_table = ti_id_table_5052, .num_interrupt_in = 1, .num_bulk_in = 2, .num_bulk_out = 2, .num_ports = 2, .attach = ti_startup, .shutdown = ti_shutdown, .open = ti_open, .close = ti_close, .write = ti_write, .write_room = ti_write_room, .chars_in_buffer = ti_chars_in_buffer, .throttle = ti_throttle, .unthrottle = ti_unthrottle, .ioctl = ti_ioctl, .set_termios = ti_set_termios, .tiocmget = ti_tiocmget, .tiocmset = ti_tiocmset, .break_ctl = ti_break, .read_int_callback = ti_interrupt_callback, .read_bulk_callback = ti_bulk_in_callback, .write_bulk_callback = ti_bulk_out_callback,};/* Module */MODULE_AUTHOR(TI_DRIVER_AUTHOR);MODULE_DESCRIPTION(TI_DRIVER_DESC);MODULE_VERSION(TI_DRIVER_VERSION);MODULE_LICENSE("GPL");module_param(debug, bool, S_IRUGO | S_IWUSR);MODULE_PARM_DESC(debug, "Enable debugging, 0=no, 1=yes");module_param(low_latency, bool, S_IRUGO | S_IWUSR);MODULE_PARM_DESC(low_latency, "TTY low_latency flag, 0=off, 1=on, default is off");module_param(closing_wait, int, S_IRUGO | S_IWUSR);MODULE_PARM_DESC(closing_wait, "Maximum wait for data to drain in close, in .01 secs, default is 4000");module_param_array(vendor_3410, ushort, &vendor_3410_count, S_IRUGO);MODULE_PARM_DESC(vendor_3410, "Vendor ids for 3410 based devices, 1-5 short integers");module_param_array(product_3410, ushort, &product_3410_count, S_IRUGO);MODULE_PARM_DESC(product_3410, "Product ids for 3410 based devices, 1-5 short integers");module_param_array(vendor_5052, ushort, &vendor_5052_count, S_IRUGO);MODULE_PARM_DESC(vendor_5052, "Vendor ids for 5052 based devices, 1-5 short integers");module_param_array(product_5052, ushort, &product_5052_count, S_IRUGO);MODULE_PARM_DESC(product_5052, "Product ids for 5052 based devices, 1-5 short integers");MODULE_DEVICE_TABLE(usb, ti_id_table_combined);/* Functions */static int __init ti_init(void){ int i,j; int ret; /* insert extra vendor and product ids */ j = sizeof(ti_id_table_3410)/sizeof(struct usb_device_id) - TI_EXTRA_VID_PID_COUNT - 1; for (i=0; i<min(vendor_3410_count,product_3410_count); i++,j++) { ti_id_table_3410[j].idVendor = vendor_3410[i]; ti_id_table_3410[j].idProduct = product_3410[i]; ti_id_table_3410[j].match_flags = USB_DEVICE_ID_MATCH_DEVICE; } j = sizeof(ti_id_table_5052)/sizeof(struct usb_device_id) - TI_EXTRA_VID_PID_COUNT - 1; for (i=0; i<min(vendor_5052_count,product_5052_count); i++,j++) { ti_id_table_5052[j].idVendor = vendor_5052[i]; ti_id_table_5052[j].idProduct = product_5052[i]; ti_id_table_5052[j].match_flags = USB_DEVICE_ID_MATCH_DEVICE; } ret = usb_serial_register(&ti_1port_device); if (ret) goto failed_1port; ret = usb_serial_register(&ti_2port_device); if (ret) goto failed_2port; ret = usb_register(&ti_usb_driver); if (ret) goto failed_usb; info(TI_DRIVER_DESC " " TI_DRIVER_VERSION); return 0;failed_usb: usb_serial_deregister(&ti_2port_device);failed_2port: usb_serial_deregister(&ti_1port_device);failed_1port: return ret;}static void __exit ti_exit(void){ usb_serial_deregister(&ti_1port_device); usb_serial_deregister(&ti_2port_device); usb_deregister(&ti_usb_driver);}module_init(ti_init);module_exit(ti_exit);static int ti_startup(struct usb_serial *serial){ struct ti_device *tdev; struct ti_port *tport; struct usb_device *dev = serial->dev; int status; int i; dbg("%s - product 0x%4X, num configurations %d, configuration value %d", __FUNCTION__, le16_to_cpu(dev->descriptor.idProduct), dev->descriptor.bNumConfigurations, dev->actconfig->desc.bConfigurationValue); /* create device structure */ tdev = kmalloc(sizeof(struct ti_device), GFP_KERNEL); if (tdev == NULL) { dev_err(&dev->dev, "%s - out of memory\n", __FUNCTION__); return -ENOMEM; } memset(tdev, 0, sizeof(struct ti_device)); sema_init(&tdev->td_open_close_sem, 1); tdev->td_serial = serial; usb_set_serial_data(serial, tdev); /* determine device type */ if (usb_match_id(serial->interface, ti_id_table_3410)) tdev->td_is_3410 = 1; dbg("%s - device type is %s", __FUNCTION__, tdev->td_is_3410 ? "3410" : "5052"); /* if we have only 1 configuration, download firmware */ if (dev->descriptor.bNumConfigurations == 1) { if (tdev->td_is_3410) status = ti_download_firmware(tdev, ti_fw_3410, sizeof(ti_fw_3410)); else status = ti_download_firmware(tdev, ti_fw_5052, sizeof(ti_fw_5052)); if (status) goto free_tdev; /* 3410 must be reset, 5052 resets itself */ if (tdev->td_is_3410) { msleep_interruptible(100); usb_reset_device(dev); } status = -ENODEV; goto free_tdev; } /* the second configuration must be set (in sysfs by hotplug script) */ if (dev->actconfig->desc.bConfigurationValue == TI_BOOT_CONFIG) { status = -ENODEV; goto free_tdev;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -