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

📄 serial.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * 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 + -