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

📄 gserial.c

📁 LINUX2.4.18内核下的usb GADGET驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * g_serial.c -- USB gadget serial driver * * $Id: gserial.c,v 1.17 2003/10/01 06:31:57 borchers Exp $ * * 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. * */#ifndef __KERNEL__#define __KERNEL__#endif#ifndef MODULE#define MODULE#endif/* Includes */#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/uts.h>#include <linux/version.h>#include <linux/wait.h>#include <linux/list.h>#include <linux/proc_fs.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;								\})/* Defines */#define GS_VERSION_STR			"v1.0"#define GS_VERSION_NUM			0x0100#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		2#define GS_NUM_INTERFACES		1#define GS_INTERFACE_ID			0#define GS_ALT_INTERFACE_ID		0#define GS_NUM_ENDPOINTS		2#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/* debug macro */#if G_SERIAL_DEBUGstatic int debug = G_SERIAL_DEBUG;#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 /* G_SERIAL_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 *//* 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;};/* 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_in_ep;	/* address of in endpoint */	struct usb_ep		*dev_out_ep;	/* address of out endpoint */	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, int from_user,	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_read_proc( char *page, char **start, off_t off, int count,	int *eof, void *data );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 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_desc( u8 *buf, enum usb_device_speed speed,		u8 type, unsigned int index );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 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 char gs_tmp_buf[GS_TMP_BUF_SIZE];static struct semaphore	gs_tmp_buf_sem;/* tty variables */static int gs_refcount;static struct tty_struct *gs_tty[GS_NUM_PORTS];static struct termios *gs_termios[GS_NUM_PORTS];static struct termios *gs_termios_locked[GS_NUM_PORTS];/* tty driver struct */static struct tty_driver gs_tty_driver = {	.magic =		TTY_DRIVER_MAGIC,	.driver_name =		GS_SHORT_NAME,	.name =			"ttygs",	.major =		GS_MAJOR,	.minor_start =		GS_MINOR_START,	.num =			GS_NUM_PORTS,	.type =			TTY_DRIVER_TYPE_SERIAL,	.subtype =		SERIAL_TYPE_NORMAL,	.flags =		TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,	.refcount =		&gs_refcount,	.table =		gs_tty,	.termios =		gs_termios,	.termios_locked =	gs_termios_locked,	.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,	.read_proc =		gs_read_proc,};/* 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	.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_CONFIG_STR_ID	4/* static strings, in iso 8859/1 */static char manufacturer[40];static struct usb_string gs_strings[] = {	{ GS_MANUFACTURER_STR_ID, manufacturer },	{ GS_PRODUCT_STR_ID, GS_LONG_NAME },	{ GS_SERIAL_STR_ID, "0" },	{ GS_CONFIG_STR_ID, "Bulk" },	{  } /* 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),	.bDeviceClass =		USB_CLASS_VENDOR_SPEC,	.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 const struct usb_config_descriptor gs_config_desc = {	.bLength =		USB_DT_CONFIG_SIZE,	.bDescriptorType =	USB_DT_CONFIG,	/* .wTotalLength set by gs_build_config_desc */	.bNumInterfaces =	GS_NUM_INTERFACES,	.bConfigurationValue =	GS_BULK_CONFIG_ID,	.iConfiguration =	GS_CONFIG_STR_ID,	.bmAttributes =		USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,	.bMaxPower =		1,};static const struct usb_interface_descriptor gs_interface_desc = {	.bLength =		USB_DT_INTERFACE_SIZE,	.bDescriptorType =	USB_DT_INTERFACE,	.bNumEndpoints =	GS_NUM_ENDPOINTS,	.bInterfaceClass =	USB_CLASS_VENDOR_SPEC,	.iInterface =		GS_CONFIG_STR_ID,};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 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),};#ifdef CONFIG_USB_GADGET_DUALSPEEDstatic struct usb_qualifier_descriptor gs_qualifier_desc = {	.bLength =		sizeof(struct usb_qualifier_descriptor),	.bDescriptorType =	USB_DT_DEVICE_QUALIFIER,	.bcdUSB =		__constant_cpu_to_le16 (0x0200),	.bDeviceClass =		USB_CLASS_VENDOR_SPEC,	/* assumes ep0 uses the same value for both speeds ... */	.bNumConfigurations =	GS_NUM_CONFIGS,};#endif/* Module */MODULE_DESCRIPTION( GS_LONG_NAME );MODULE_AUTHOR( "Al Borchers" );MODULE_LICENSE( "GPL" );#if G_SERIAL_DEBUGMODULE_PARM( debug, "i" );MODULE_PARM_DESC( debug, "Enable debugging, 0=off, 1=on" );#endifMODULE_PARM( read_q_size, "i" );MODULE_PARM_DESC( read_q_size, "Read request queue size, default=32" );MODULE_PARM( write_q_size, "i" );MODULE_PARM_DESC( write_q_size, "Write request queue size, default=32" );MODULE_PARM( write_buf_size, "i" );MODULE_PARM_DESC( write_buf_size, "Write buffer size, default=8192" );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,ret;	if( (ret=usb_gadget_register_driver( &gs_gadget_driver )) ) {		printk( KERN_ERR		"gs_module_init: cannot register gadget driver, ret=%d\n",			ret );		return( ret );	}	/* initial stty settings */	gs_tty_driver.init_termios = tty_std_termios;	gs_tty_driver.init_termios.c_cflag		= B9600 | CS8 | CREAD | HUPCL | CLOCAL;	for( i=0; i<GS_NUM_PORTS; i++ )		sema_init( &gs_open_close_sem[i], 1 );	sema_init( &gs_tmp_buf_sem, 1 );	if( (ret=tty_register_driver( &gs_tty_driver )) ) {		usb_gadget_unregister_driver( &gs_gadget_driver );		printk( KERN_ERR			"gs_module_init: cannot register tty driver, ret=%d\n",			ret );		return( ret );	} 	printk( KERN_INFO "gs_module_init: %s %s loaded\n", GS_LONG_NAME,		GS_VERSION_STR );	return( 0 );        }/** gs_module_exit** Unregister as a tty driver and a USB gadget driver.*/static void __exit gs_module_exit( void ){	tty_unregister_driver( &gs_tty_driver );	usb_gadget_unregister_driver( &gs_gadget_driver );	printk( KERN_INFO "gs_module_exit: %s %s unloaded\n",		GS_LONG_NAME, GS_VERSION_STR );}/* TTY Driver *//* * gs_open */static int gs_open( struct tty_struct *tty, struct file *file ){

⌨️ 快捷键说明

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