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

📄 ftdi_sio.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * USB FTDI SIO driver * * 	Copyright (C) 1999, 2000 * 	    Greg Kroah-Hartman (greg@kroah.com) *          Bill Ryder (bryder@sgi.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. * * See Documentation/usb/usb-serial.txt for more information on using this driver * * See http://reality.sgi.com/bryder_wellington/ftdi_sio for upto date testing info *     and extra documentation *        * (12/3/2000) Bill Ryder *     Added support for 8U232AM device. *     Moved PID and VIDs into header file only. *     Turned on low-latency for the tty (device will do high baudrates) *     Added shutdown routine to close files when device removed. *     More debug and error message cleanups. *      * * (11/13/2000) Bill Ryder *     Added spinlock protected open code and close code. *     Multiple opens work (sort of - see webpage mentioned above). *     Cleaned up comments. Removed multiple PID/VID definitions. *     Factorised cts/dtr code *     Made use of __FUNCTION__ in dbg's *       * (11/01/2000) Adam J. Richter *	usb_device_id table support *  * (10/05/2000) gkh *	Fixed bug with urb->dev not being set properly, now that the usb *	core needs it. *  * (09/11/2000) gkh *	Removed DEBUG #ifdefs with call to usb_serial_debug_data * * (07/19/2000) gkh *	Added module_init and module_exit functions to handle the fact that this *	driver is a loadable module now. * * (04/04/2000) Bill Ryder  *      Fixed bugs in TCGET/TCSET ioctls (by removing them - they are  *        handled elsewhere in the tty io driver chain). * * (03/30/2000) Bill Ryder  *      Implemented lots of ioctls * 	Fixed a race condition in write * 	Changed some dbg's to errs * * (03/26/2000) gkh * 	Split driver up into device specific pieces. * *//* Bill Ryder - bryder@sgi.com - wrote the FTDI_SIO implementation *//* Thanx to FTDI for so kindly providing details of the protocol required *//*   to talk to the device *//* Thanx to gkh and the rest of the usb dev group for all code I have assimilated :-) */#include <linux/config.h>#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_DEBUG	#define DEBUG#else	#undef DEBUG#endif#include <linux/usb.h>#include "usb-serial.h"#include "ftdi_sio.h"static __devinitdata struct usb_device_id id_table_sio [] = {	{ USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },	{ }						/* Terminating entry */};/* THe 8U232AM has the same API as the sio - but it can support MUCH    higher baudrates (921600 at 48MHz/230400 at 12MHz    so .. it's baudrate setting codes are different */   static __devinitdata struct usb_device_id id_table_8U232AM [] = {	{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },	{ }						/* Terminating entry */};static __devinitdata struct usb_device_id id_table_combined [] = {	{ USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },	{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },	{ }						/* Terminating entry */};MODULE_DEVICE_TABLE (usb, id_table_combined);struct ftdi_private {	ftdi_type_t ftdi_type;	char last_status_byte; /* device sends this every 40ms when open */		};/* function prototypes for a FTDI serial converter */static int  ftdi_sio_startup		(struct usb_serial *serial);static int  ftdi_8U232AM_startup	(struct usb_serial *serial);static void ftdi_sio_shutdown		(struct usb_serial *serial);static int  ftdi_sio_open		(struct usb_serial_port *port, struct file *filp);static void ftdi_sio_close		(struct usb_serial_port *port, struct file *filp);static int  ftdi_sio_write		(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);static void ftdi_sio_write_bulk_callback (struct urb *urb);static void ftdi_sio_read_bulk_callback	(struct urb *urb);static void ftdi_sio_set_termios	(struct usb_serial_port *port, struct termios * old);static int  ftdi_sio_ioctl		(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);/* Should rename most ftdi_sio's to ftdi_ now since there are two devices    which share common code */ struct usb_serial_device_type ftdi_sio_device = {	name:			"FTDI SIO",	id_table:		id_table_sio,	needs_interrupt_in:	MUST_HAVE_NOT,	needs_bulk_in:		MUST_HAVE,	needs_bulk_out:		MUST_HAVE,	num_interrupt_in:	0,	num_bulk_in:		1,	num_bulk_out:		1,	num_ports:		1,	open:			ftdi_sio_open,	close:			ftdi_sio_close,	write:			ftdi_sio_write,	read_bulk_callback:	ftdi_sio_read_bulk_callback,	write_bulk_callback:	ftdi_sio_write_bulk_callback,	ioctl:			ftdi_sio_ioctl,	set_termios:		ftdi_sio_set_termios,	startup:		ftdi_sio_startup,        shutdown:               ftdi_sio_shutdown,};struct usb_serial_device_type ftdi_8U232AM_device = {	name:			"FTDI 8U232AM",	id_table:		id_table_8U232AM,	needs_interrupt_in:	DONT_CARE,	needs_bulk_in:		MUST_HAVE,	needs_bulk_out:		MUST_HAVE,	num_interrupt_in:	0,	num_bulk_in:		1,	num_bulk_out:		1,	num_ports:		1,	open:			ftdi_sio_open,	close:			ftdi_sio_close,	write:			ftdi_sio_write,	read_bulk_callback:	ftdi_sio_read_bulk_callback,	write_bulk_callback:	ftdi_sio_write_bulk_callback,	ioctl:			ftdi_sio_ioctl,	set_termios:		ftdi_sio_set_termios,	startup:		ftdi_8U232AM_startup,        shutdown:               ftdi_sio_shutdown,};/* * *************************************************************************** * FTDI SIO Serial Converter specific driver functions * *************************************************************************** */#define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout *//* utility functions to set and unset dtr and rts */#define HIGH 1#define LOW 0static int set_rts(struct usb_device *dev, 		   unsigned int pipe,		   int high_or_low){	static char buf[1];	unsigned ftdi_high_or_low = (high_or_low? FTDI_SIO_SET_RTS_HIGH : 				FTDI_SIO_SET_RTS_LOW);	return(usb_control_msg(dev, pipe,			       FTDI_SIO_SET_MODEM_CTRL_REQUEST, 			       FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,			       ftdi_high_or_low, 0, 			       buf, 0, WDR_TIMEOUT));}static int set_dtr(struct usb_device *dev, 		   unsigned int pipe,		   int high_or_low){	static char buf[1];	unsigned ftdi_high_or_low = (high_or_low? FTDI_SIO_SET_DTR_HIGH : 				FTDI_SIO_SET_DTR_LOW);	return(usb_control_msg(dev, pipe,			       FTDI_SIO_SET_MODEM_CTRL_REQUEST, 			       FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,			       ftdi_high_or_low, 0, 			       buf, 0, WDR_TIMEOUT));}static int ftdi_sio_startup (struct usb_serial *serial){	struct ftdi_private *priv;		init_waitqueue_head(&serial->port[0].write_wait);		priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL);	if (!priv){		err(__FUNCTION__"- kmalloc(%d) failed.", sizeof(struct ftdi_private));		return -ENOMEM;	}	priv->ftdi_type = sio;		return (0);}static int ftdi_8U232AM_startup (struct usb_serial *serial){	struct ftdi_private *priv; 	init_waitqueue_head(&serial->port[0].write_wait);	priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL);	if (!priv){		err(__FUNCTION__"- kmalloc(%d) failed.", sizeof(struct ftdi_private));		return -ENOMEM;	}	priv->ftdi_type = F8U232AM;		return (0);}static void ftdi_sio_shutdown (struct usb_serial *serial){		dbg (__FUNCTION__);	/* Close ports if they are open */	while (serial->port[0].open_count > 0) {		ftdi_sio_close (&serial->port[0], NULL);	}	if (serial->port->private){		kfree(serial->port->private);		serial->port->private = NULL;	}}static int  ftdi_sio_open (struct usb_serial_port *port, struct file *filp){ /* ftdi_sio_open */	struct termios tmp_termios;	struct usb_serial *serial = port->serial;	unsigned long flags;	/* Used for spinlock */	int result;	char buf[1]; /* Needed for the usb_control_msg I think */	dbg(__FUNCTION__);	spin_lock_irqsave (&port->port_lock, flags);		MOD_INC_USE_COUNT;	++port->open_count;	if (!port->active){		port->active = 1;		spin_unlock_irqrestore (&port->port_lock, flags);		/* do not allow a task to be queued to deliver received data */		port->tty->low_latency = 1;		/* No error checking for this (will get errors later anyway) */		/* See ftdi_sio.h for description of what is reset */		usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),				FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, 				FTDI_SIO_RESET_SIO, 				0, buf, 0, WDR_TIMEOUT);		/* Setup termios defaults. According to tty_io.c the 		   settings are driver specific */		port->tty->termios->c_cflag =			B9600 | CS8 | CREAD | HUPCL | CLOCAL;		/* ftdi_sio_set_termios  will send usb control messages */		ftdi_sio_set_termios(port, &tmp_termios);			/* Turn on RTS and DTR since we are not flow controlling by default */		if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0) {			err(__FUNCTION__ " Error from DTR HIGH urb");		}		if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0){			err(__FUNCTION__ " Error from RTS HIGH urb");		}			/* Start reading from the device */		FILL_BULK_URB(port->read_urb, serial->dev, 			      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),			      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,			      ftdi_sio_read_bulk_callback, port);		result = usb_submit_urb(port->read_urb);		if (result)			err(__FUNCTION__ " - failed submitting read urb, error %d", result);	} else { /* the port was already active - so no initialisation is done */		spin_unlock_irqrestore (&port->port_lock, flags);	}	return (0);} /* ftdi_sio_open */static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp){ /* ftdi_sio_close */	struct usb_serial *serial = port->serial;	unsigned int c_cflag = port->tty->termios->c_cflag;	char buf[1];	unsigned long flags;	dbg( __FUNCTION__);	spin_lock_irqsave (&port->port_lock, flags);	--port->open_count;	if (port->open_count <= 0) {		spin_unlock_irqrestore (&port->port_lock, flags);		if (c_cflag & HUPCL){			/* Disable flow control */			if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),					    FTDI_SIO_SET_FLOW_CTRL_REQUEST, 					    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,					    0, 0, 					    buf, 0, WDR_TIMEOUT) < 0) {				err("error from flowcontrol urb");			}	    			/* drop DTR */			if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0), LOW) < 0){				err("Error from DTR LOW urb");			}			/* drop RTS */			if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0) {				err("Error from RTS LOW urb");			}			} /* Note change no line is hupcl is off */		/* shutdown our bulk reads and writes */		usb_unlink_urb (port->write_urb);		usb_unlink_urb (port->read_urb);		port->active = 0;		port->open_count = 0;	} else {  		spin_unlock_irqrestore (&port->port_lock, flags);		/* Send a HUP if necessary */		if (!(port->tty->termios->c_cflag & CLOCAL)){			tty_hangup(port->tty);		}			}	MOD_DEC_USE_COUNT;} /* ftdi_sio_close */  /* The ftdi_sio requires the first byte to have: *  B0 1 *  B1 0 *  B2..7 length of message excluding byte 0 */static int ftdi_sio_write (struct usb_serial_port *port, int from_user, 			   const unsigned char *buf, int count){ /* ftdi_sio_write */	struct usb_serial *serial = port->serial;	struct ftdi_private *priv = (struct ftdi_private *)port->private;	int data_offset ;	int rc; 	int result;	DECLARE_WAITQUEUE(wait, current);		dbg(__FUNCTION__ " port %d, %d bytes", port->number, count);	if (count == 0) {		err("write request of 0 bytes");		return 0;	}		if (priv->ftdi_type == sio){		data_offset = 1;	} else {		data_offset = 0;	}        dbg("data_offset set to %d",data_offset);	/* only do something if we have a bulk out endpoint */	if (serial->num_bulk_out) {		unsigned char *first_byte = port->write_urb->transfer_buffer;		/* Was seeing a race here, got a read callback, then write callback before		   hitting interuptible_sleep_on  - so wrapping in a wait_queue */		add_wait_queue(&port->write_wait, &wait);		set_current_state (TASK_INTERRUPTIBLE);		while (port->write_urb->status == -EINPROGRESS) {			dbg(__FUNCTION__ " write in progress - retrying");			if (signal_pending(current)) {				current->state = TASK_RUNNING;				remove_wait_queue(&port->write_wait, &wait);				rc = -ERESTARTSYS;				goto err;			}			schedule();		}				remove_wait_queue(&port->write_wait, &wait);		set_current_state(TASK_RUNNING);

⌨️ 快捷键说明

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