📄 serial.c
字号:
/* * g_serial.c -- USB gadget serial driver * * Copyright 2003 (C) Al Borchers (alborchers@steinerpoint.com) * * This code is based in part on the Gadget Zero driver, which * is Copyright (C) 2003 by David Brownell, all rights reserved. * * This code also borrows from usbserial.c, which is * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2000 Peter Berger (pberger@brimson.com) * Copyright (C) 2000 Al Borchers (alborchers@steinerpoint.com) * * This software is distributed under the terms of the GNU General * Public License ("GPL") as published by the Free Software Foundation, * either version 2 of that License or (at your option) any later version. * */#include <linux/kernel.h>#include <linux/utsname.h>#include <linux/device.h>#include <linux/tty.h>#include <linux/tty_flip.h>#include <linux/usb/ch9.h>#include <linux/usb/cdc.h>#include <linux/usb/gadget.h>#include "gadget_chips.h"/* Defines */#define GS_VERSION_STR "v2.2"#define GS_VERSION_NUM 0x0202#define GS_LONG_NAME "Gadget Serial"#define GS_SHORT_NAME "g_serial"#define GS_MAJOR 127#define GS_MINOR_START 0#define GS_NUM_PORTS 16#define GS_NUM_CONFIGS 1#define GS_NO_CONFIG_ID 0#define GS_BULK_CONFIG_ID 1#define GS_ACM_CONFIG_ID 2#define GS_MAX_NUM_INTERFACES 2#define GS_BULK_INTERFACE_ID 0#define GS_CONTROL_INTERFACE_ID 0#define GS_DATA_INTERFACE_ID 1#define GS_MAX_DESC_LEN 256#define GS_DEFAULT_READ_Q_SIZE 32#define GS_DEFAULT_WRITE_Q_SIZE 32#define GS_DEFAULT_WRITE_BUF_SIZE 8192#define GS_TMP_BUF_SIZE 8192#define GS_CLOSE_TIMEOUT 15#define GS_DEFAULT_USE_ACM 0#define GS_DEFAULT_DTE_RATE 9600#define GS_DEFAULT_DATA_BITS 8#define GS_DEFAULT_PARITY USB_CDC_NO_PARITY#define GS_DEFAULT_CHAR_FORMAT USB_CDC_1_STOP_BITS/* maxpacket and other transfer characteristics vary by speed. */static inline struct usb_endpoint_descriptor *choose_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs, struct usb_endpoint_descriptor *fs){ if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) return hs; return fs;}/* debug settings */#ifdef DEBUGstatic int debug = 1;#else#define debug 0#endif#define gs_debug(format, arg...) \ do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0)#define gs_debug_level(level, format, arg...) \ do { if (debug>=level) printk(KERN_DEBUG format, ## arg); } while(0)/* Thanks to NetChip Technologies for donating this product ID. * * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! * Instead: allocate your own, using normal USB-IF procedures. */#define GS_VENDOR_ID 0x0525 /* NetChip */#define GS_PRODUCT_ID 0xa4a6 /* Linux-USB Serial Gadget */#define GS_CDC_PRODUCT_ID 0xa4a7 /* ... as CDC-ACM */#define GS_LOG2_NOTIFY_INTERVAL 5 /* 1 << 5 == 32 msec */#define GS_NOTIFY_MAXPACKET 8/* Structures */struct gs_dev;/* circular buffer */struct gs_buf { unsigned int buf_size; char *buf_buf; char *buf_get; char *buf_put;};/* list of requests */struct gs_req_entry { struct list_head re_entry; struct usb_request *re_req;};/* the port structure holds info for each port, one for each minor number */struct gs_port { struct gs_dev *port_dev; /* pointer to device struct */ struct tty_struct *port_tty; /* pointer to tty struct */ spinlock_t port_lock; int port_num; int port_open_count; int port_in_use; /* open/close in progress */ wait_queue_head_t port_write_wait;/* waiting to write */ struct gs_buf *port_write_buf; struct usb_cdc_line_coding port_line_coding;};/* the device structure holds info for the USB device */struct gs_dev { struct usb_gadget *dev_gadget; /* gadget device pointer */ spinlock_t dev_lock; /* lock for set/reset config */ int dev_config; /* configuration number */ struct usb_ep *dev_notify_ep; /* address of notify endpoint */ struct usb_ep *dev_in_ep; /* address of in endpoint */ struct usb_ep *dev_out_ep; /* address of out endpoint */ struct usb_endpoint_descriptor /* descriptor of notify ep */ *dev_notify_ep_desc; struct usb_endpoint_descriptor /* descriptor of in endpoint */ *dev_in_ep_desc; struct usb_endpoint_descriptor /* descriptor of out endpoint */ *dev_out_ep_desc; struct usb_request *dev_ctrl_req; /* control request */ struct list_head dev_req_list; /* list of write requests */ int dev_sched_port; /* round robin port scheduled */ struct gs_port *dev_port[GS_NUM_PORTS]; /* the ports */};/* Functions *//* module */static int __init gs_module_init(void);static void __exit gs_module_exit(void);/* tty driver */static int gs_open(struct tty_struct *tty, struct file *file);static void gs_close(struct tty_struct *tty, struct file *file);static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count);static void gs_put_char(struct tty_struct *tty, unsigned char ch);static void gs_flush_chars(struct tty_struct *tty);static int gs_write_room(struct tty_struct *tty);static int gs_chars_in_buffer(struct tty_struct *tty);static void gs_throttle(struct tty_struct * tty);static void gs_unthrottle(struct tty_struct * tty);static void gs_break(struct tty_struct *tty, int break_state);static int gs_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg);static void gs_set_termios(struct tty_struct *tty, struct ktermios *old);static int gs_send(struct gs_dev *dev);static int gs_send_packet(struct gs_dev *dev, char *packet, unsigned int size);static int gs_recv_packet(struct gs_dev *dev, char *packet, unsigned int size);static void gs_read_complete(struct usb_ep *ep, struct usb_request *req);static void gs_write_complete(struct usb_ep *ep, struct usb_request *req);/* gadget driver */static int gs_bind(struct usb_gadget *gadget);static void gs_unbind(struct usb_gadget *gadget);static int gs_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl);static int gs_setup_standard(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl);static int gs_setup_class(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl);static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req);static void gs_disconnect(struct usb_gadget *gadget);static int gs_set_config(struct gs_dev *dev, unsigned config);static void gs_reset_config(struct gs_dev *dev);static int gs_build_config_buf(u8 *buf, struct usb_gadget *g, u8 type, unsigned int index, int is_otg);static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len, gfp_t kmalloc_flags);static void gs_free_req(struct usb_ep *ep, struct usb_request *req);static struct gs_req_entry *gs_alloc_req_entry(struct usb_ep *ep, unsigned len, gfp_t kmalloc_flags);static void gs_free_req_entry(struct usb_ep *ep, struct gs_req_entry *req);static int gs_alloc_ports(struct gs_dev *dev, gfp_t kmalloc_flags);static void gs_free_ports(struct gs_dev *dev);/* circular buffer */static struct gs_buf *gs_buf_alloc(unsigned int size, gfp_t kmalloc_flags);static void gs_buf_free(struct gs_buf *gb);static void gs_buf_clear(struct gs_buf *gb);static unsigned int gs_buf_data_avail(struct gs_buf *gb);static unsigned int gs_buf_space_avail(struct gs_buf *gb);static unsigned int gs_buf_put(struct gs_buf *gb, const char *buf, unsigned int count);static unsigned int gs_buf_get(struct gs_buf *gb, char *buf, unsigned int count);/* external functions */extern int net2280_set_fifo_mode(struct usb_gadget *gadget, int mode);/* Globals */static struct gs_dev *gs_device;static const char *EP_IN_NAME;static const char *EP_OUT_NAME;static const char *EP_NOTIFY_NAME;static struct mutex gs_open_close_lock[GS_NUM_PORTS];static unsigned int read_q_size = GS_DEFAULT_READ_Q_SIZE;static unsigned int write_q_size = GS_DEFAULT_WRITE_Q_SIZE;static unsigned int write_buf_size = GS_DEFAULT_WRITE_BUF_SIZE;static unsigned int use_acm = GS_DEFAULT_USE_ACM;/* tty driver struct */static const struct tty_operations gs_tty_ops = { .open = gs_open, .close = gs_close, .write = gs_write, .put_char = gs_put_char, .flush_chars = gs_flush_chars, .write_room = gs_write_room, .ioctl = gs_ioctl, .set_termios = gs_set_termios, .throttle = gs_throttle, .unthrottle = gs_unthrottle, .break_ctl = gs_break, .chars_in_buffer = gs_chars_in_buffer,};static struct tty_driver *gs_tty_driver;/* gadget driver struct */static struct usb_gadget_driver gs_gadget_driver = {#ifdef CONFIG_USB_GADGET_DUALSPEED .speed = USB_SPEED_HIGH,#else .speed = USB_SPEED_FULL,#endif /* CONFIG_USB_GADGET_DUALSPEED */ .function = GS_LONG_NAME, .bind = gs_bind, .unbind = gs_unbind, .setup = gs_setup, .disconnect = gs_disconnect, .driver = { .name = GS_SHORT_NAME, },};/* USB descriptors */#define GS_MANUFACTURER_STR_ID 1#define GS_PRODUCT_STR_ID 2#define GS_SERIAL_STR_ID 3#define GS_BULK_CONFIG_STR_ID 4#define GS_ACM_CONFIG_STR_ID 5#define GS_CONTROL_STR_ID 6#define GS_DATA_STR_ID 7/* static strings, in UTF-8 */static char manufacturer[50];static struct usb_string gs_strings[] = { { GS_MANUFACTURER_STR_ID, manufacturer }, { GS_PRODUCT_STR_ID, GS_LONG_NAME }, { GS_SERIAL_STR_ID, "0" }, { GS_BULK_CONFIG_STR_ID, "Gadget Serial Bulk" }, { GS_ACM_CONFIG_STR_ID, "Gadget Serial CDC ACM" }, { GS_CONTROL_STR_ID, "Gadget Serial Control" }, { GS_DATA_STR_ID, "Gadget Serial Data" }, { } /* end of list */};static struct usb_gadget_strings gs_string_table = { .language = 0x0409, /* en-us */ .strings = gs_strings,};static struct usb_device_descriptor gs_device_desc = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, .bcdUSB = __constant_cpu_to_le16(0x0200), .bDeviceSubClass = 0, .bDeviceProtocol = 0, .idVendor = __constant_cpu_to_le16(GS_VENDOR_ID), .idProduct = __constant_cpu_to_le16(GS_PRODUCT_ID), .iManufacturer = GS_MANUFACTURER_STR_ID, .iProduct = GS_PRODUCT_STR_ID, .iSerialNumber = GS_SERIAL_STR_ID, .bNumConfigurations = GS_NUM_CONFIGS,};static struct usb_otg_descriptor gs_otg_descriptor = { .bLength = sizeof(gs_otg_descriptor), .bDescriptorType = USB_DT_OTG, .bmAttributes = USB_OTG_SRP,};static struct usb_config_descriptor gs_bulk_config_desc = { .bLength = USB_DT_CONFIG_SIZE, .bDescriptorType = USB_DT_CONFIG, /* .wTotalLength computed dynamically */ .bNumInterfaces = 1, .bConfigurationValue = GS_BULK_CONFIG_ID, .iConfiguration = GS_BULK_CONFIG_STR_ID, .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, .bMaxPower = 1,};static struct usb_config_descriptor gs_acm_config_desc = { .bLength = USB_DT_CONFIG_SIZE, .bDescriptorType = USB_DT_CONFIG, /* .wTotalLength computed dynamically */ .bNumInterfaces = 2, .bConfigurationValue = GS_ACM_CONFIG_ID, .iConfiguration = GS_ACM_CONFIG_STR_ID, .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, .bMaxPower = 1,};static const struct usb_interface_descriptor gs_bulk_interface_desc = { .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = GS_BULK_INTERFACE_ID, .bNumEndpoints = 2, .bInterfaceClass = USB_CLASS_CDC_DATA, .bInterfaceSubClass = 0, .bInterfaceProtocol = 0, .iInterface = GS_DATA_STR_ID,};static const struct usb_interface_descriptor gs_control_interface_desc = { .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = GS_CONTROL_INTERFACE_ID, .bNumEndpoints = 1, .bInterfaceClass = USB_CLASS_COMM, .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, .bInterfaceProtocol = USB_CDC_ACM_PROTO_AT_V25TER, .iInterface = GS_CONTROL_STR_ID,};static const struct usb_interface_descriptor gs_data_interface_desc = { .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = GS_DATA_INTERFACE_ID, .bNumEndpoints = 2, .bInterfaceClass = USB_CLASS_CDC_DATA, .bInterfaceSubClass = 0, .bInterfaceProtocol = 0, .iInterface = GS_DATA_STR_ID,};static const struct usb_cdc_header_desc gs_header_desc = { .bLength = sizeof(gs_header_desc), .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = USB_CDC_HEADER_TYPE, .bcdCDC = __constant_cpu_to_le16(0x0110),};static const struct usb_cdc_call_mgmt_descriptor gs_call_mgmt_descriptor = { .bLength = sizeof(gs_call_mgmt_descriptor), .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE, .bmCapabilities = 0, .bDataInterface = 1, /* index of data interface */};static struct usb_cdc_acm_descriptor gs_acm_descriptor = { .bLength = sizeof(gs_acm_descriptor), .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = USB_CDC_ACM_TYPE, .bmCapabilities = 0,};static const struct usb_cdc_union_desc gs_union_desc = { .bLength = sizeof(gs_union_desc), .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = USB_CDC_UNION_TYPE, .bMasterInterface0 = 0, /* index of control interface */ .bSlaveInterface0 = 1, /* index of data interface */};static struct usb_endpoint_descriptor gs_fullspeed_notify_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = __constant_cpu_to_le16(GS_NOTIFY_MAXPACKET), .bInterval = 1 << GS_LOG2_NOTIFY_INTERVAL,};static struct usb_endpoint_descriptor gs_fullspeed_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK,};static struct usb_endpoint_descriptor gs_fullspeed_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK,};static const struct usb_descriptor_header *gs_bulk_fullspeed_function[] = { (struct usb_descriptor_header *) &gs_otg_descriptor, (struct usb_descriptor_header *) &gs_bulk_interface_desc, (struct usb_descriptor_header *) &gs_fullspeed_in_desc, (struct usb_descriptor_header *) &gs_fullspeed_out_desc, NULL,};static const struct usb_descriptor_header *gs_acm_fullspeed_function[] = { (struct usb_descriptor_header *) &gs_otg_descriptor, (struct usb_descriptor_header *) &gs_control_interface_desc, (struct usb_descriptor_header *) &gs_header_desc, (struct usb_descriptor_header *) &gs_call_mgmt_descriptor, (struct usb_descriptor_header *) &gs_acm_descriptor, (struct usb_descriptor_header *) &gs_union_desc, (struct usb_descriptor_header *) &gs_fullspeed_notify_desc, (struct usb_descriptor_header *) &gs_data_interface_desc, (struct usb_descriptor_header *) &gs_fullspeed_in_desc, (struct usb_descriptor_header *) &gs_fullspeed_out_desc, NULL,};static struct usb_endpoint_descriptor gs_highspeed_notify_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, .wMaxPacketSize = __constant_cpu_to_le16(GS_NOTIFY_MAXPACKET), .bInterval = GS_LOG2_NOTIFY_INTERVAL+4,};static struct usb_endpoint_descriptor gs_highspeed_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = __constant_cpu_to_le16(512),};static struct usb_endpoint_descriptor gs_highspeed_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = __constant_cpu_to_le16(512),};static struct usb_qualifier_descriptor gs_qualifier_desc = { .bLength = sizeof(struct usb_qualifier_descriptor), .bDescriptorType = USB_DT_DEVICE_QUALIFIER, .bcdUSB = __constant_cpu_to_le16 (0x0200), /* assumes ep0 uses the same value for both speeds ... */ .bNumConfigurations = GS_NUM_CONFIGS,};static const struct usb_descriptor_header *gs_bulk_highspeed_function[] = { (struct usb_descriptor_header *) &gs_otg_descriptor, (struct usb_descriptor_header *) &gs_bulk_interface_desc, (struct usb_descriptor_header *) &gs_highspeed_in_desc, (struct usb_descriptor_header *) &gs_highspeed_out_desc, NULL,};static const struct usb_descriptor_header *gs_acm_highspeed_function[] = { (struct usb_descriptor_header *) &gs_otg_descriptor, (struct usb_descriptor_header *) &gs_control_interface_desc, (struct usb_descriptor_header *) &gs_header_desc, (struct usb_descriptor_header *) &gs_call_mgmt_descriptor, (struct usb_descriptor_header *) &gs_acm_descriptor, (struct usb_descriptor_header *) &gs_union_desc, (struct usb_descriptor_header *) &gs_highspeed_notify_desc, (struct usb_descriptor_header *) &gs_data_interface_desc, (struct usb_descriptor_header *) &gs_highspeed_in_desc, (struct usb_descriptor_header *) &gs_highspeed_out_desc, NULL,};/* Module */MODULE_DESCRIPTION(GS_LONG_NAME);MODULE_AUTHOR("Al Borchers");MODULE_LICENSE("GPL");#ifdef DEBUGmodule_param(debug, int, S_IRUGO|S_IWUSR);MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on");#endifmodule_param(read_q_size, uint, S_IRUGO);MODULE_PARM_DESC(read_q_size, "Read request queue size, default=32");module_param(write_q_size, uint, S_IRUGO);MODULE_PARM_DESC(write_q_size, "Write request queue size, default=32");module_param(write_buf_size, uint, S_IRUGO);MODULE_PARM_DESC(write_buf_size, "Write buffer size, default=8192");module_param(use_acm, uint, S_IRUGO);MODULE_PARM_DESC(use_acm, "Use CDC ACM, 0=no, 1=yes, default=no");module_init(gs_module_init);module_exit(gs_module_exit);/** gs_module_init** Register as a USB gadget driver and a tty driver.*/static int __init gs_module_init(void){ int i; int retval; retval = usb_gadget_register_driver(&gs_gadget_driver); if (retval) { printk(KERN_ERR "gs_module_init: cannot register gadget driver, ret=%d\n", retval); return retval; } gs_tty_driver = alloc_tty_driver(GS_NUM_PORTS); if (!gs_tty_driver) return -ENOMEM; gs_tty_driver->owner = THIS_MODULE; gs_tty_driver->driver_name = GS_SHORT_NAME; gs_tty_driver->name = "ttygs"; gs_tty_driver->major = GS_MAJOR; gs_tty_driver->minor_start = GS_MINOR_START; gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; gs_tty_driver->subtype = SERIAL_TYPE_NORMAL; gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; gs_tty_driver->init_termios = tty_std_termios; gs_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; tty_set_operations(gs_tty_driver, &gs_tty_ops); for (i=0; i < GS_NUM_PORTS; i++) mutex_init(&gs_open_close_lock[i]); retval = tty_register_driver(gs_tty_driver); if (retval) { usb_gadget_unregister_driver(&gs_gadget_driver); put_tty_driver(gs_tty_driver); printk(KERN_ERR "gs_module_init: cannot register tty driver, ret=%d\n", retval); return retval; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -