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

📄 serial.c

📁 优龙2410linux2.6.8内核源代码
💻 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/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/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>/* 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			"v0.1"#define GS_VERSION_NUM			0x0001#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 settings */#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 *//* USB Controllers *//* * NetChip 2280, PCI based. * * This has half a dozen configurable endpoints, four with dedicated * DMA channels to manage their FIFOs.  It supports high speed. * Those endpoints can be arranged in any desired configuration. */#ifdef	CONFIG_USB_GADGET_NET2280#define CHIP				"net2280"#define EP0_MAXPACKET			64static const char EP_OUT_NAME[] =	"ep-a";#define EP_OUT_NUM			2static const char EP_IN_NAME[] =	"ep-b";#define EP_IN_NUM			2#define HIGHSPEED#define SELFPOWER			USB_CONFIG_ATT_SELFPOWERextern int net2280_set_fifo_mode(struct usb_gadget *gadget, int mode);static inline void hw_optimize(struct usb_gadget *gadget){	/* we can have bigger ep-a/ep-b fifos (2KB each, 4 packets	 * for highspeed bulk) because we're not using ep-c/ep-d.	 */	net2280_set_fifo_mode (gadget, 1);}#endif/* * Dummy_hcd, software-based loopback controller. * * This imitates the abilities of the NetChip 2280, so we will use * the same configuration. */#ifdef	CONFIG_USB_GADGET_DUMMY_HCD#define CHIP				"dummy"#define EP0_MAXPACKET			64static const char EP_OUT_NAME[] =	"ep-a";#define EP_OUT_NUM			2static const char EP_IN_NAME[] =	"ep-b";#define EP_IN_NUM			2#define HIGHSPEED#define SELFPOWER			USB_CONFIG_ATT_SELFPOWER/* no hw optimizations to apply */#define hw_optimize(g)			do {} while (0)#endif/* * PXA-2xx UDC:  widely used in second gen Linux-capable PDAs. * * This has fifteen fixed-function full speed endpoints, and it * can support all USB transfer types. * * These supports three or four configurations, with fixed numbers. * The hardware interprets SET_INTERFACE, net effect is that you * can't use altsettings or reset the interfaces independently. * So stick to a single interface. */#ifdef	CONFIG_USB_GADGET_PXA2XX#define CHIP				"pxa2xx"#define EP0_MAXPACKET			16static const char EP_OUT_NAME[] =	"ep2out-bulk";#define EP_OUT_NUM			2static const char EP_IN_NAME[] =	"ep1in-bulk";#define EP_IN_NUM			1#define SELFPOWER 			USB_CONFIG_ATT_SELFPOWER/* no hw optimizations to apply */#define hw_optimize(g)			do {} while (0)#endif/* * SA-1100 UDC:  widely used in first gen Linux-capable PDAs. * * This has only two fixed function endpoints, which can only * be used for bulk (or interrupt) transfers.  (Plus control.) * * Since it can't flush its TX fifos without disabling the UDC, * the current configuration or altsettings can't change except * in special situations.  So this is a case of "choose it right * during enumeration" ... */#ifdef	CONFIG_USB_GADGET_SA1100#define CHIP				"sa1100"#define EP0_MAXPACKET			8static const char EP_OUT_NAME[] =	"ep1out-bulk";#define EP_OUT_NUM			1static const char EP_IN_NAME [] =	"ep2in-bulk";#define EP_IN_NUM			2#define SELFPOWER			USB_CONFIG_ATT_SELFPOWER/* no hw optimizations to apply */#define hw_optimize(g)			do {} while (0)#endif/* * Toshiba TC86C001 ("Goku-S") UDC * * This has three semi-configurable full speed bulk/interrupt endpoints. */#ifdef	CONFIG_USB_GADGET_GOKU#define CHIP				"goku"#define DRIVER_VERSION_NUM		0x0116#define EP0_MAXPACKET			8static const char EP_OUT_NAME [] =	"ep1-bulk";#define EP_OUT_NUM			1static const char EP_IN_NAME [] =	"ep2-bulk";#define EP_IN_NUM			2#define SELFPOWER			USB_CONFIG_ATT_SELFPOWER/* no hw optimizations to apply */#define hw_optimize(g)			do {} while (0)#endif/* * USB Controller Defaults */#ifndef EP0_MAXPACKET#error Configure some USB peripheral controller for g_serial!#endif#ifndef SELFPOWER/* default: say we rely on bus power */#define SELFPOWER   			0/* else value must be USB_CONFIG_ATT_SELFPOWER */#endif#ifndef	MAX_USB_POWER/* any hub supports this steady state bus power consumption */#define MAX_USB_POWER			100	/* mA */#endif#ifndef	WAKEUP/* default: this driver won't do remote wakeup */#define WAKEUP				0/* else value must be USB_CONFIG_ATT_WAKEUP */#endif/* 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_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);/* Globals */static struct gs_dev *gs_device;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 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 HIGHSPEED	.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 struct usb_string gs_strings[] = {	{ GS_MANUFACTURER_STR_ID, UTS_SYSNAME " " UTS_RELEASE " with " CHIP },	{ 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 const 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,	.bMaxPacketSize0 =	EP0_MAXPACKET,	.idVendor =		__constant_cpu_to_le16(GS_VENDOR_ID),	.idProduct =		__constant_cpu_to_le16(GS_PRODUCT_ID),	.bcdDevice =		__constant_cpu_to_le16(GS_VERSION_NUM),	.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 | SELFPOWER | WAKEUP,	.bMaxPower =		(MAX_USB_POWER + 1) / 2,};

⌨️ 快捷键说明

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