📄 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/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/ioport.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/smp_lock.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/timer.h>#include <linux/list.h>#include <linux/interrupt.h>#include <linux/utsname.h>#include <linux/wait.h>#include <linux/proc_fs.h>#include <linux/device.h>#include <linux/tty.h>#include <linux/tty_flip.h>#include <asm/byteorder.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/unaligned.h>#include <asm/uaccess.h>#include <linux/usb_ch9.h>#include <linux/usb_gadget.h>#include "gadget_chips.h"/* Wait Cond */#define __wait_cond_interruptible(wq, condition, lock, flags, ret) \do { \ wait_queue_t __wait; \ init_waitqueue_entry(&__wait, current); \ \ add_wait_queue(&wq, &__wait); \ for (;;) { \ set_current_state(TASK_INTERRUPTIBLE); \ if (condition) \ break; \ if (!signal_pending(current)) { \ spin_unlock_irqrestore(lock, flags); \ schedule(); \ spin_lock_irqsave(lock, flags); \ continue; \ } \ ret = -ERESTARTSYS; \ break; \ } \ current->state = TASK_RUNNING; \ remove_wait_queue(&wq, &__wait); \} while (0) #define wait_cond_interruptible(wq, condition, lock, flags) \({ \ int __ret = 0; \ if (!(condition)) \ __wait_cond_interruptible(wq, condition, lock, flags, \ __ret); \ __ret; \})#define __wait_cond_interruptible_timeout(wq, condition, lock, flags, \ timeout, ret) \do { \ signed long __timeout = timeout; \ wait_queue_t __wait; \ init_waitqueue_entry(&__wait, current); \ \ add_wait_queue(&wq, &__wait); \ for (;;) { \ set_current_state(TASK_INTERRUPTIBLE); \ if (__timeout == 0) \ break; \ if (condition) \ break; \ if (!signal_pending(current)) { \ spin_unlock_irqrestore(lock, flags); \ __timeout = schedule_timeout(__timeout); \ spin_lock_irqsave(lock, flags); \ continue; \ } \ ret = -ERESTARTSYS; \ break; \ } \ current->state = TASK_RUNNING; \ remove_wait_queue(&wq, &__wait); \} while (0) #define wait_cond_interruptible_timeout(wq, condition, lock, flags, \ timeout) \({ \ int __ret = 0; \ if (!(condition)) \ __wait_cond_interruptible_timeout(wq, condition, lock, \ flags, timeout, __ret); \ __ret; \})/* CDC-ACM Defines and Structures */#define USB_CDC_SUBCLASS_ACM 2#define USB_CDC_CTRL_PROTO_NONE 0#define USB_CDC_CTRL_PROTO_AT 1#define USB_CDC_CTRL_PROTO_VENDOR 0xff#define USB_CDC_SUBTYPE_HEADER 0#define USB_CDC_SUBTYPE_CALL_MGMT 1#define USB_CDC_SUBTYPE_ACM 2#define USB_CDC_SUBTYPE_UNION 6#define USB_CDC_CALL_MGMT_CAP_CALL_MGMT 0x01#define USB_CDC_CALL_MGMT_CAP_DATA_INTF 0x02#define USB_CDC_REQ_SET_LINE_CODING 0x20#define USB_CDC_REQ_GET_LINE_CODING 0x21#define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22#define USB_CDC_1_STOP_BITS 0#define USB_CDC_1_5_STOP_BITS 1#define USB_CDC_2_STOP_BITS 2#define USB_CDC_NO_PARITY 0#define USB_CDC_ODD_PARITY 1#define USB_CDC_EVEN_PARITY 2#define USB_CDC_MARK_PARITY 3#define USB_CDC_SPACE_PARITY 4/* Header Functional Descriptor from CDC spec 5.2.3.1 */struct usb_cdc_header_desc { u8 bLength; u8 bDescriptorType; u8 bDescriptorSubType; u16 bcdCDC;} __attribute__ ((packed));/* Call Management Descriptor from CDC spec 5.2.3.3 */struct usb_cdc_call_mgmt_desc { u8 bLength; u8 bDescriptorType; u8 bDescriptorSubType; u8 bmCapabilities; u8 bDataInterface;} __attribute__ ((packed));/* Abstract Control Management Descriptor from CDC spec 5.2.3.4 */struct usb_cdc_acm_desc { u8 bLength; u8 bDescriptorType; u8 bDescriptorSubType; u8 bmCapabilities;} __attribute__ ((packed));/* Union Functional Descriptor from CDC spec 5.2.3.8 */struct usb_cdc_union_desc { u8 bLength; u8 bDescriptorType; u8 bDescriptorSubType; u8 bMasterInterface0; u8 bSlaveInterface0; /* ... and there could be other slave interfaces */} __attribute__ ((packed));/* Line Coding Structure from CDC spec 6.2.13 */struct usb_cdc_line_coding { u32 dwDTERate; u8 bCharFormat; u8 bParityType; u8 bDataBits;} __attribute__ ((packed));/* Defines */#define GS_VERSION_STR "v2.0"#define GS_VERSION_NUM 0x0200#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/* select highspeed/fullspeed, hiding highspeed if not configured */#ifdef CONFIG_USB_GADGET_DUALSPEED#define GS_SPEED_SELECT(is_hs,hs,fs) ((is_hs) ? (hs) : (fs))#else#define GS_SPEED_SELECT(is_hs,hs,fs) (fs)#endif /* CONFIG_USB_GADGET_DUALSPEED *//* debug settings */#ifdef GS_DEBUGstatic int debug = 1;#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)#else#define gs_debug(format, arg...) \ do { } while(0)#define gs_debug_level(level, format, arg...) \ do { } while(0)#endif /* GS_DEBUG *//* 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 /* desciptor 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 termios *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, enum usb_device_speed speed, u8 type, unsigned int index, int is_otg);static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len, int 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, int 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, int kmalloc_flags);static void gs_free_ports(struct gs_dev *dev);/* circular buffer */static struct gs_buf *gs_buf_alloc(unsigned int size, int 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 semaphore gs_open_close_sem[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 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, /* .shutdown = ... */ /* .suspend = ... */ /* .resume = ... */ },};/* 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 = {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -