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

📄 usb-serial.c

📁 Usb1.1驱动c语言源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * USB Serial Converter driver * *	(C) Copyright (C) 1999, 2000 *	    Greg Kroah-Hartman (greg@kroah.com) * *	This program is free software; you can redistribute it and/or modify *	it under the terms of the GNU General Public License as published by *	the Free Software Foundation; either version 2 of the License, or *	(at your option) any later version. * * This driver was originally based on the ACM driver by Armin Fuerst (which was  * based on a driver by Brad Keryan) * * See Documentation/usb-serial.txt for more information on using this driver. *  * (01/13/2000) gkh *	Fixed the vendor id for the generic driver to the one I meant it to be. * * (01/12/2000) gkh *	Forget the version numbering...that's pretty useless... *	Made the driver able to be compiled so that the user can select which *	converter they want to use. This allows people who only want the Visor *	support to not pay the memory size price of the WhiteHEAT. *	Fixed bug where the generic driver (idVendor=0000 and idProduct=0000) *	grabbed the root hub. Not good. *  * version 0.4.0 (01/10/2000) gkh *	Added whiteheat.h containing the firmware for the ConnectTech WhiteHEAT *	device. Added startup function to allow firmware to be downloaded to *	a device if it needs to be. *	Added firmware download logic to the WhiteHEAT device. *	Started to add #defines to split up the different drivers for potential *	configuration option. *	 * version 0.3.1 (12/30/99) gkh *      Fixed problems with urb for bulk out. *      Added initial support for multiple sets of endpoints. This enables *      the Handspring Visor to be attached successfully. Only the first *      bulk in / bulk out endpoint pair is being used right now. * * version 0.3.0 (12/27/99) gkh *	Added initial support for the Handspring Visor based on a patch from *	Miles Lott (milos@sneety.insync.net) *	Cleaned up the code a bunch and converted over to using urbs only. * * version 0.2.3 (12/21/99) gkh *	Added initial support for the Connect Tech WhiteHEAT converter. *	Incremented the number of ports in expectation of getting the *	WhiteHEAT to work properly (4 ports per connection). *	Added notification on insertion and removal of what port the *	device is/was connected to (and what kind of device it was). * * version 0.2.2 (12/16/99) gkh *	Changed major number to the new allocated number. We're legal now! * * version 0.2.1 (12/14/99) gkh *	Fixed bug that happens when device node is opened when there isn't a *	device attached to it. Thanks to marek@webdesign.no for noticing this. * * version 0.2.0 (11/10/99) gkh *	Split up internals to make it easier to add different types of serial  *	converters to the code. *	Added a "generic" driver that gets it's vendor and product id *	from when the module is loaded. Thanks to David E. Nelson (dnelson@jump.net) *	for the idea and sample code (from the usb scanner driver.) *	Cleared up any licensing questions by releasing it under the GNU GPL. * * version 0.1.2 (10/25/99) gkh * 	Fixed bug in detecting device. * * version 0.1.1 (10/05/99) gkh * 	Changed the major number to not conflict with anything else. * * version 0.1 (09/28/99) gkh * 	Can recognize the two different devices and start up a read from *	device when asked to. Writes also work. No control signals yet, this *	all is vendor specific data (i.e. no spec), also no control for *	different baud rates or other bit settings. *	Currently we are using the same devid as the acm driver. This needs *	to change. *  */#include <linux/kernel.h>#include <linux/sched.h>#include <linux/signal.h>#include <linux/errno.h>#include <linux/poll.h>#include <linux/init.h>#include <linux/malloc.h>#include <linux/fcntl.h>#include <linux/tty_driver.h>#include <linux/tty_flip.h>#include <linux/tty.h>#include <linux/module.h>#include <linux/spinlock.h>#ifdef CONFIG_USB_SERIAL_WHITEHEAT#include "whiteheat.h"		/* firmware for the ConnectTech WhiteHEAT device */#endif#define DEBUG#include "usb.h"/* Module information */MODULE_AUTHOR("Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux-usb/");MODULE_DESCRIPTION("USB Serial Driver");#ifdef CONFIG_USB_SERIAL_GENERICstatic __u16	vendor	= 0x05f9;static __u16	product	= 0xffff;MODULE_PARM(vendor, "i");MODULE_PARM_DESC(vendor, "User specified USB idVendor");MODULE_PARM(product, "i");MODULE_PARM_DESC(product, "User specified USB idProduct");#endif/* USB Serial devices vendor ids and device ids that this driver supports */#define BELKIN_VENDOR_ID		0x056c#define BELKIN_SERIAL_CONVERTER		0x8007#define PERACOM_VENDOR_ID		0x0565#define PERACOM_SERIAL_CONVERTER	0x0001#define CONNECT_TECH_VENDOR_ID		0x0710#define CONNECT_TECH_FAKE_WHITE_HEAT_ID	0x0001#define CONNECT_TECH_WHITE_HEAT_ID	0x8001#define HANDSPRING_VENDOR_ID		0x082d#define HANDSPRING_VISOR_ID		0x0100#define SERIAL_MAJOR	188	/* Nice legal number now */#define NUM_PORTS	16	/* Actually we are allowed 255, but this is good for now */static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum);static void usb_serial_disconnect(struct usb_device *dev, void *ptr);#define MAX_ENDPOINTS	8struct usb_serial_state {	struct usb_device *		dev;	struct usb_serial_device_type *	type;	void *				irq_handle;	unsigned int			irqpipe;	struct tty_struct *		tty;		/* the coresponding tty for this device */	unsigned char			number;	char				present;	char				active;	char			num_interrupt_in;	/* number of interrupt in endpoints we have */	char			interrupt_in_inuse;	/* if the interrupt in endpoint is in use */	__u8			interrupt_in_endpoint[MAX_ENDPOINTS];	__u8			interrupt_in_interval[MAX_ENDPOINTS];	__u16			interrupt_in_size[MAX_ENDPOINTS];	/* the size of the interrupt in endpoint */	unsigned int		interrupt_in_pipe[MAX_ENDPOINTS];	unsigned char *		interrupt_in_buffer[MAX_ENDPOINTS];	void *			interrupt_in_transfer[MAX_ENDPOINTS];	struct urb		control_urb;	char			num_bulk_in;		/* number of bulk in endpoints we have */	__u8			bulk_in_endpoint[MAX_ENDPOINTS];	__u8			bulk_in_interval[MAX_ENDPOINTS];	__u16			bulk_in_size[MAX_ENDPOINTS];		/* the size of the bulk in endpoint */	unsigned int		bulk_in_pipe[MAX_ENDPOINTS];	unsigned char *		bulk_in_buffer[MAX_ENDPOINTS];	void *			bulk_in_transfer[MAX_ENDPOINTS];	struct urb		read_urb;	char			num_bulk_out;		/* number of bulk out endpoints we have */	__u8			bulk_out_endpoint[MAX_ENDPOINTS];	__u8			bulk_out_interval[MAX_ENDPOINTS];	__u16			bulk_out_size[MAX_ENDPOINTS];		/* the size of the bulk out endpoint */	unsigned int		bulk_out_pipe[MAX_ENDPOINTS];	unsigned char *		bulk_out_buffer[MAX_ENDPOINTS];	void *			bulk_out_transfer[MAX_ENDPOINTS];	struct urb		write_urb;};#define MUST_HAVE_NOT	0x01#define MUST_HAVE	0x02#define DONT_CARE	0x03#define	HAS		0x02#define HAS_NOT		0x01#define NUM_DONT_CARE	(-1)/* local function prototypes */static int serial_open (struct tty_struct *tty, struct file * filp);static void serial_close (struct tty_struct *tty, struct file * filp);static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count);static void serial_put_char (struct tty_struct *tty, unsigned char ch);static int serial_write_room (struct tty_struct *tty);static int serial_chars_in_buffer (struct tty_struct *tty);static void serial_throttle (struct tty_struct * tty);static void serial_unthrottle (struct tty_struct * tty);/* This structure defines the individual serial converter. */struct usb_serial_device_type {	char	*name;	__u16	*idVendor;	__u16	*idProduct;	char	needs_interrupt_in;	char	needs_bulk_in;	char	needs_bulk_out;	char	num_interrupt_in;	char	num_bulk_in;	char	num_bulk_out;	/* function call to make before accepting driver */	int (*startup) (struct usb_serial_state *serial);	/* return 0 to continue initialization, anything else to abort */		/* serial function calls */	int  (*open)(struct tty_struct * tty, struct file * filp);	void (*close)(struct tty_struct * tty, struct file * filp);	int  (*write)(struct tty_struct * tty, int from_user,const unsigned char *buf, int count);	void (*put_char)(struct tty_struct *tty, unsigned char ch);	int  (*write_room)(struct tty_struct *tty);	int  (*chars_in_buffer)(struct tty_struct *tty);	void (*throttle)(struct tty_struct * tty);	void (*unthrottle)(struct tty_struct * tty);};/* function prototypes for a "generic" type serial converter (no flow control, not all endpoints needed) *//* need to always compile these in, as some of the other devices use these functions as their own. */static int  generic_serial_open		(struct tty_struct *tty, struct file *filp);static void generic_serial_close	(struct tty_struct *tty, struct file *filp);static int  generic_serial_write	(struct tty_struct *tty, int from_user, const unsigned char *buf, int count);static void generic_serial_put_char	(struct tty_struct *tty, unsigned char ch);static int  generic_write_room		(struct tty_struct *tty);static int  generic_chars_in_buffer	(struct tty_struct *tty);#ifdef CONFIG_USB_SERIAL_GENERIC/* All of the device info needed for the Generic Serial Converter */static struct usb_serial_device_type generic_device = {	name:			"Generic",	idVendor:		&vendor,		/* use the user specified vendor id */	idProduct:		&product,		/* use the user specified product id */	needs_interrupt_in:	DONT_CARE,		/* don't have to have an interrupt in endpoint */	needs_bulk_in:		DONT_CARE,		/* don't have to have a bulk in endpoint */	needs_bulk_out:		DONT_CARE,		/* don't have to have a bulk out endpoint */	num_interrupt_in:	NUM_DONT_CARE,	num_bulk_in:		NUM_DONT_CARE,	num_bulk_out:		NUM_DONT_CARE,	open:			generic_serial_open,	close:			generic_serial_close,	write:			generic_serial_write,	put_char:		generic_serial_put_char,	write_room:		generic_write_room,	chars_in_buffer:	generic_chars_in_buffer,};#endif#if defined(CONFIG_USB_SERIAL_BELKIN) || defined(CONFIG_USB_SERIAL_PERACOM)/* function prototypes for the eTek type converters (this includes Belkin and Peracom) */static int  etek_serial_open		(struct tty_struct *tty, struct file *filp);static void etek_serial_close		(struct tty_struct *tty, struct file *filp);#endif#ifdef CONFIG_USB_SERIAL_BELKIN/* All of the device info needed for the Belkin Serial Converter */static __u16	belkin_vendor_id	= BELKIN_VENDOR_ID;static __u16	belkin_product_id	= BELKIN_SERIAL_CONVERTER;static struct usb_serial_device_type belkin_device = {	name:			"Belkin",	idVendor:		&belkin_vendor_id,	/* the Belkin vendor id */	idProduct:		&belkin_product_id,	/* the Belkin serial converter product id */	needs_interrupt_in:	MUST_HAVE,		/* this device must have an interrupt in endpoint */	needs_bulk_in:		MUST_HAVE,		/* this device must have a bulk in endpoint */	needs_bulk_out:		MUST_HAVE,		/* this device must have a bulk out endpoint */	num_interrupt_in:	1,	num_bulk_in:		1,	num_bulk_out:		1,	open:			etek_serial_open,	close:			etek_serial_close,	write:			generic_serial_write,	put_char:		generic_serial_put_char,	write_room:		generic_write_room,	chars_in_buffer:	generic_chars_in_buffer,};#endif#ifdef CONFIG_USB_SERIAL_PERACOM/* All of the device info needed for the Peracom Serial Converter */static __u16	peracom_vendor_id	= PERACOM_VENDOR_ID;static __u16	peracom_product_id	= PERACOM_SERIAL_CONVERTER;static struct usb_serial_device_type peracom_device = {	name:			"Peracom",	idVendor:		&peracom_vendor_id,	/* the Peracom vendor id */	idProduct:		&peracom_product_id,	/* the Peracom serial converter product id */	needs_interrupt_in:	MUST_HAVE,		/* this device must have an interrupt in endpoint */	needs_bulk_in:		MUST_HAVE,		/* this device must have a bulk in endpoint */	needs_bulk_out:		MUST_HAVE,		/* this device must have a bulk out endpoint */	num_interrupt_in:	1,	num_bulk_in:		1,	num_bulk_out:		1,	open:			etek_serial_open,	close:			etek_serial_close,	write:			generic_serial_write,	put_char:		generic_serial_put_char,	write_room:		generic_write_room,	chars_in_buffer:	generic_chars_in_buffer,};#endif#ifdef CONFIG_USB_SERIAL_WHITEHEAT/* function prototypes for the Connect Tech WhiteHEAT serial converter */static int  whiteheat_serial_open	(struct tty_struct *tty, struct file *filp);static void whiteheat_serial_close	(struct tty_struct *tty, struct file *filp);static void whiteheat_throttle		(struct tty_struct *tty);static void whiteheat_unthrottle	(struct tty_struct *tty);static int  whiteheat_startup		(struct usb_serial_state *serial);/* All of the device info needed for the Connect Tech WhiteHEAT */static __u16	connecttech_vendor_id			= CONNECT_TECH_VENDOR_ID;static __u16	connecttech_whiteheat_fake_product_id	= CONNECT_TECH_FAKE_WHITE_HEAT_ID;static __u16	connecttech_whiteheat_product_id	= CONNECT_TECH_WHITE_HEAT_ID;static struct usb_serial_device_type whiteheat_fake_device = {	name:			"Connect Tech - WhiteHEAT - (prerenumeration)",	idVendor:		&connecttech_vendor_id,			/* the Connect Tech vendor id */	idProduct:		&connecttech_whiteheat_fake_product_id,	/* the White Heat initial product id */	needs_interrupt_in:	DONT_CARE,				/* don't have to have an interrupt in endpoint */	needs_bulk_in:		DONT_CARE,				/* don't have to have a bulk in endpoint */	needs_bulk_out:		DONT_CARE,				/* don't have to have a bulk out endpoint */	num_interrupt_in:	NUM_DONT_CARE,	num_bulk_in:		NUM_DONT_CARE,	num_bulk_out:		NUM_DONT_CARE,	startup:		whiteheat_startup	};static struct usb_serial_device_type whiteheat_device = {	name:			"Connect Tech - WhiteHEAT",	idVendor:		&connecttech_vendor_id,			/* the Connect Tech vendor id */	idProduct:		&connecttech_whiteheat_product_id,	/* the White Heat real product id */	needs_interrupt_in:	DONT_CARE,				/* don't have to have an interrupt in endpoint */	needs_bulk_in:		DONT_CARE,				/* don't have to have a bulk in endpoint */	needs_bulk_out:		DONT_CARE,				/* don't have to have a bulk out endpoint */	num_interrupt_in:	NUM_DONT_CARE,	num_bulk_in:		NUM_DONT_CARE,	num_bulk_out:		NUM_DONT_CARE,	open:			whiteheat_serial_open,	close:			whiteheat_serial_close,	write:			generic_serial_write,	put_char:		generic_serial_put_char,	write_room:		generic_write_room,	chars_in_buffer:	generic_chars_in_buffer,	throttle:		whiteheat_throttle,	unthrottle:		whiteheat_unthrottle};#endif#ifdef CONFIG_USB_SERIAL_VISOR/* function prototypes for a handspring visor */static int  visor_serial_open		(struct tty_struct *tty, struct file *filp);static void visor_serial_close		(struct tty_struct *tty, struct file *filp);static void visor_throttle		(struct tty_struct *tty);static void visor_unthrottle		(struct tty_struct *tty);/* All of the device info needed for the Handspring Visor */static __u16	handspring_vendor_id	= HANDSPRING_VENDOR_ID;static __u16	handspring_product_id	= HANDSPRING_VISOR_ID;static struct usb_serial_device_type handspring_device = {	name:			"Handspring Visor",	idVendor:		&handspring_vendor_id,	/* the Handspring vendor ID */	idProduct:		&handspring_product_id,	/* the Handspring Visor product id */	needs_interrupt_in:	MUST_HAVE_NOT,		/* this device must not have an interrupt in endpoint */	needs_bulk_in:		MUST_HAVE,		/* this device must have a bulk in endpoint */	needs_bulk_out:		MUST_HAVE,		/* this device must have a bulk out endpoint */	num_interrupt_in:	0,	num_bulk_in:		2,	num_bulk_out:		2,	open:			visor_serial_open,	close:			visor_serial_close,	write:			generic_serial_write,	put_char:		generic_serial_put_char,	write_room:		generic_write_room,	chars_in_buffer:	generic_chars_in_buffer,	throttle:		visor_throttle,	unthrottle:		visor_unthrottle};#endif/* To add support for another serial converter, create a usb_serial_device_type   structure for that device, and add it to this list, making sure that the last   entry is NULL. */static struct usb_serial_device_type *usb_serial_devices[] = {#ifdef CONFIG_USB_SERIAL_GENERIC	&generic_device,#endif#ifdef CONFIG_USB_SERIAL_WHITEHEAT	&whiteheat_fake_device,	&whiteheat_device,#endif#ifdef CONFIG_USB_SERIAL_BELKIN	&belkin_device,#endif#ifdef CONFIG_USB_SERIAL_PERACOM	&peracom_device,#endif#ifdef CONFIG_USB_SERIAL_VISOR	&handspring_device,#endif	NULL};static struct usb_driver usb_serial_driver = {	"serial",	usb_serial_probe,	usb_serial_disconnect,	{ NULL, NULL }};static int			serial_refcount;static struct tty_struct *	serial_tty[NUM_PORTS];static struct termios *		serial_termios[NUM_PORTS];static struct termios *		serial_termios_locked[NUM_PORTS];static struct usb_serial_state	serial_state_table[NUM_PORTS];static void serial_read_bulk (struct urb *urb){	struct usb_serial_state *serial = (struct usb_serial_state *)urb->context;       	struct tty_struct *tty = serial->tty;        	unsigned char *data = urb->transfer_buffer;	int i;	dbg("serial_read_irq");	if (urb->status) {		dbg("nonzero read bulk status received: %d", urb->status);		return;	}	if (urb->actual_length)		dbg("%d %s", urb->actual_length, data);	if (urb->actual_length) {		for (i = 0; i < urb->actual_length ; ++i) {			 tty_insert_flip_char(tty, data[i], 0);	  	}	  	tty_flip_buffer_push(tty);	}	/* Continue trying to always read  */	if (usb_submit_urb(urb))		dbg("failed resubmitting read urb");	return;}static void serial_write_bulk (struct urb *urb){	struct usb_serial_state *serial = (struct usb_serial_state *) urb->context;        	struct tty_struct *tty = serial->tty; 	dbg("serial_write_irq");	if (urb->status) {		dbg("nonzero write bulk status received: %d", urb->status);		return;	}	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)		(tty->ldisc.write_wakeup)(tty);	wake_up_interruptible(&tty->write_wait);		return;}/***************************************************************************** * Driver tty interface functions *****************************************************************************/static int serial_open (struct tty_struct *tty, struct file * filp){	struct usb_serial_state *serial;		dbg("serial_open");	/* assign a serial object to the tty pointer */	serial = &serial_state_table [MINOR(tty->device)-tty->driver.minor_start];	/* do some sanity checking that we really have a device present */	if (!serial) {		dbg("serial == NULL!");		return (-ENODEV);

⌨️ 快捷键说明

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