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

📄 digi_acceleport.c

📁 基于S3CEB2410平台LINUX操作系统下 USB驱动源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/**  Digi AccelePort USB-4 and USB-2 Serial Converters**  Copyright 2000 by Digi International**  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.**  Shamelessly based on Brian Warner's keyspan_pda.c and Greg Kroah-Hartman's*  usb-serial driver.**  Peter Berger (pberger@brimson.com)*  Al Borchers (borchers@steinerpoint.com)* * (04/08/2001) gb*	Identify version on module load.** (11/01/2000) Adam J. Richter*	usb_device_id table support* * (11/01/2000) pberger and borchers*    -- Turned off the USB_DISABLE_SPD flag for write bulk urbs--it caused*       USB 4 ports to hang on startup.*    -- Serialized access to write urbs by adding the dp_write_urb_in_use*       flag; otherwise, the driver caused SMP system hangs.  Watching the*       urb status is not sufficient.** (10/05/2000) gkh*    -- Fixed bug with urb->dev not being set properly, now that the usb*	core needs it.* *  (8/8/2000) pberger and borchers*    -- Fixed close so that *       - it can timeout while waiting for transmit idle, if needed;*       - it ignores interrupts when flushing the port, turning*         of modem signalling, and so on;*       - it waits for the flush to really complete before returning.*    -- Read_bulk_callback and write_bulk_callback check for a closed*       port before using the tty struct or writing to the port.*    -- The two changes above fix the oops caused by interrupted closes.*    -- Added interruptible args to write_oob_command and set_modem_signals*       and added a timeout arg to transmit_idle; needed for fixes to*       close.*    -- Added code for rx_throttle and rx_unthrottle so that input flow*       control works.*    -- Added code to set overrun, parity, framing, and break errors*       (untested).*    -- Set USB_DISABLE_SPD flag for write bulk urbs, so no 0 length*       bulk writes are done.  These hung the Digi USB device.  The*       0 length bulk writes were a new feature of usb-uhci added in*       the 2.4.0-test6 kernels.*    -- Fixed mod inc race in open; do mod inc before sleeping to wait*       for a close to finish.**  (7/31/2000) pberger*    -- Fixed bugs with hardware handshaking:*       - Added code to set/clear tty->hw_stopped in digi_read_oob_callback()*         and digi_set_termios()*    -- Added code in digi_set_termios() to*       - add conditional in code handling transition from B0 to only*         set RTS if RTS/CTS flow control is either not in use or if*         the port is not currently throttled.*       - handle turning off CRTSCTS.**  (7/30/2000) borchers*    -- Added support for more than one Digi USB device by moving*       globals to a private structure in the pointed to from the*       usb_serial structure.*    -- Moved the modem change and transmit idle wait queues into*       the port private structure, so each port has its own queue*       rather than sharing global queues.*    -- Added support for break signals.**  (7/25/2000) pberger*    -- Added USB-2 support.  Note: the USB-2 supports 3 devices: two*       serial and a parallel port.  The parallel port is implemented*       as a serial-to-parallel converter.  That is, the driver actually*       presents all three USB-2 interfaces as serial ports, but the third*       one physically connects to a parallel device.  Thus, for example,*       one could plug a parallel printer into the USB-2's third port,*       but from the kernel's (and userland's) point of view what's*       actually out there is a serial device.**  (7/15/2000) borchers*    -- Fixed race in open when a close is in progress.*    -- Keep count of opens and dec the module use count for each*       outstanding open when shutdown is called (on disconnect).*    -- Fixed sanity checks in read_bulk_callback and write_bulk_callback*       so pointers are checked before use.*    -- Split read bulk callback into in band and out of band*       callbacks, and no longer restart read chains if there is*       a status error or a sanity error.  This fixed the seg*       faults and other errors we used to get on disconnect.*    -- Port->active is once again a flag as usb-serial intended it*       to be, not a count.  Since it was only a char it would*       have been limited to 256 simultaneous opens.  Now the open*       count is kept in the port private structure in dp_open_count.*    -- Added code for modularization of the digi_acceleport driver.**  (6/27/2000) pberger and borchers*    -- Zeroed out sync field in the wakeup_task before first use;*       otherwise the uninitialized value might prevent the task from*       being scheduled.*    -- Initialized ret value to 0 in write_bulk_callback, otherwise*       the uninitialized value could cause a spurious debugging message.**  (6/22/2000) pberger and borchers*    -- Made cond_wait_... inline--apparently on SPARC the flags arg*       to spin_lock_irqsave cannot be passed to another function*       to call spin_unlock_irqrestore.  Thanks to Pauline Middelink.*    -- In digi_set_modem_signals the inner nested spin locks use just*       spin_lock() rather than spin_lock_irqsave().  The old code*       mistakenly left interrupts off.  Thanks to Pauline Middelink.*    -- copy_from_user (which can sleep) is no longer called while a*       spinlock is held.  We copy to a local buffer before getting*       the spinlock--don't like the extra copy but the code is simpler.*    -- Printk and dbg are no longer called while a spin lock is held.**  (6/4/2000) pberger and borchers*    -- Replaced separate calls to spin_unlock_irqrestore and*       interruptible_sleep_on_timeout with a new function*       cond_wait_interruptible_timeout_irqrestore.  This eliminates*       the race condition where the wake up could happen after*       the unlock and before the sleep.*    -- Close now waits for output to drain.*    -- Open waits until any close in progress is finished.*    -- All out of band responses are now processed, not just the*       first in a USB packet.*    -- Fixed a bug that prevented the driver from working when the*       first Digi port was not the first USB serial port--the driver*       was mistakenly using the external USB serial port number to*       try to index into its internal ports.*    -- Fixed an SMP bug -- write_bulk_callback is called directly from*       an interrupt, so spin_lock_irqsave/spin_unlock_irqrestore are*       needed for locks outside write_bulk_callback that are also*       acquired by write_bulk_callback to prevent deadlocks.*    -- Fixed support for select() by making digi_chars_in_buffer()*       return 256 when -EINPROGRESS is set, as the line discipline*       code in n_tty.c expects.*    -- Fixed an include file ordering problem that prevented debugging*       messages from working.*    -- Fixed an intermittent timeout problem that caused writes to*       sometimes get stuck on some machines on some kernels.  It turns*       out in these circumstances write_chan() (in n_tty.c) was*       asleep waiting for our wakeup call.  Even though we call*       wake_up_interruptible() in digi_write_bulk_callback(), there is*       a race condition that could cause the wakeup to fail: if our*       wake_up_interruptible() call occurs between the time that our*       driver write routine finishes and write_chan() sets current->state*       to TASK_INTERRUPTIBLE, the effect of our wakeup setting the state*       to TASK_RUNNING will be lost and write_chan's subsequent call to*       schedule() will never return (unless it catches a signal).*       This race condition occurs because write_bulk_callback() (and thus*       the wakeup) are called asynchonously from an interrupt, rather than*       from the scheduler.  We can avoid the race by calling the wakeup*       from the scheduler queue and that's our fix:  Now, at the end of*       write_bulk_callback() we queue up a wakeup call on the scheduler*       task queue.  We still also invoke the wakeup directly since that*       squeezes a bit more performance out of the driver, and any lost*       race conditions will get cleaned up at the next scheduler run.**       NOTE:  The problem also goes away if you comment out*       the two code lines in write_chan() where current->state*       is set to TASK_RUNNING just before calling driver.write() and to*       TASK_INTERRUPTIBLE immediately afterwards.  This is why the*       problem did not show up with the 2.2 kernels -- they do not*       include that code.**  (5/16/2000) pberger and borchers*    -- Added timeouts to sleeps, to defend against lost wake ups.*    -- Handle transition to/from B0 baud rate in digi_set_termios.**  (5/13/2000) pberger and borchers*    -- All commands now sent on out of band port, using*       digi_write_oob_command.*    -- Get modem control signals whenever they change, support TIOCMGET/*       SET/BIS/BIC ioctls.*    -- digi_set_termios now supports parity, word size, stop bits, and*       receive enable.*    -- Cleaned up open and close, use digi_set_termios and*       digi_write_oob_command to set port parameters.*    -- Added digi_startup_device to start read chains on all ports.*    -- Write buffer is only used when count==1, to be sure put_char can*       write a char (unless the buffer is full).**  (5/10/2000) pberger and borchers*    -- Added MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT calls on open/close.*    -- Fixed problem where the first incoming character is lost on*       port opens after the first close on that port.  Now we keep*       the read_urb chain open until shutdown.*    -- Added more port conditioning calls in digi_open and digi_close.*    -- Convert port->active to a use count so that we can deal with multiple*       opens and closes properly.*    -- Fixed some problems with the locking code.**  (5/3/2000) pberger and borchers*    -- First alpha version of the driver--many known limitations and bugs.***  Locking and SMP**  - Each port, including the out-of-band port, has a lock used to*    serialize all access to the port's private structure.*  - The port lock is also used to serialize all writes and access to*    the port's URB.*  - The port lock is also used for the port write_wait condition*    variable.  Holding the port lock will prevent a wake up on the*    port's write_wait; this can be used with cond_wait_... to be sure*    the wake up is not lost in a race when dropping the lock and*    sleeping waiting for the wakeup.*  - digi_write() does not sleep, since it is sometimes called on*    interrupt time.*  - digi_write_bulk_callback() and digi_read_bulk_callback() are*    called directly from interrupts.  Hence spin_lock_irqsave()*    and spin_lock_irqrestore() are used in the rest of the code*    for any locks they acquire.*  - digi_write_bulk_callback() gets the port lock before waking up*    processes sleeping on the port write_wait.  It also schedules*    wake ups so they happen from the scheduler, because the tty*    system can miss wake ups from interrupts.*  - All sleeps use a timeout of DIGI_RETRY_TIMEOUT before looping to*    recheck the condition they are sleeping on.  This is defensive,*    in case a wake up is lost.*  - Following Documentation/DocBook/kernel-locking.pdf no spin locks*    are held when calling copy_to/from_user or printk.*    *  $Id: digi_acceleport.c,v 1.80.1.2 2000/11/02 05:45:08 root Exp $*/#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/slab.h>#include <linux/fcntl.h>#include <linux/tty.h>#include <linux/tty_driver.h>#include <linux/tty_flip.h>#include <linux/module.h>#include <linux/spinlock.h>#include <linux/tqueue.h>#include <linux/usb.h>#ifdef CONFIG_USB_SERIAL_DEBUG	static int debug = 1;#else	static int debug;#endif#include "usb-serial.h"/* Defines *//* * Version Information */#define DRIVER_VERSION "v1.80.1.2"#define DRIVER_AUTHOR "Peter Berger <pberger@brimson.com>, Al Borchers <borchers@steinerpoint.com>"#define DRIVER_DESC "Digi AccelePort USB-2/USB-4 Serial Converter driver"/* port output buffer length -- must be <= transfer buffer length - 2 *//* so we can be sure to send the full buffer in one urb */#define DIGI_OUT_BUF_SIZE		8/* port input buffer length -- must be >= transfer buffer length - 3 *//* so we can be sure to hold at least one full buffer from one urb */#define DIGI_IN_BUF_SIZE		64/* retry timeout while sleeping */#define DIGI_RETRY_TIMEOUT		(HZ/10)/* timeout while waiting for tty output to drain in close *//* this delay is used twice in close, so the total delay could *//* be twice this value */#define DIGI_CLOSE_TIMEOUT		(5*HZ)/* AccelePort USB Defines *//* ids */#define DIGI_VENDOR_ID			0x05c5#define DIGI_2_ID			0x0002	/* USB-2 */#define DIGI_4_ID			0x0004	/* USB-4 *//* commands * "INB": can be used on the in-band endpoint * "OOB": can be used on the out-of-band endpoint */#define DIGI_CMD_SET_BAUD_RATE			0	/* INB, OOB */#define DIGI_CMD_SET_WORD_SIZE			1	/* INB, OOB */#define DIGI_CMD_SET_PARITY			2	/* INB, OOB */#define DIGI_CMD_SET_STOP_BITS			3	/* INB, OOB */#define DIGI_CMD_SET_INPUT_FLOW_CONTROL		4	/* INB, OOB */#define DIGI_CMD_SET_OUTPUT_FLOW_CONTROL	5	/* INB, OOB */#define DIGI_CMD_SET_DTR_SIGNAL			6	/* INB, OOB */#define DIGI_CMD_SET_RTS_SIGNAL			7	/* INB, OOB */#define DIGI_CMD_READ_INPUT_SIGNALS		8	/*      OOB */#define DIGI_CMD_IFLUSH_FIFO			9	/*      OOB */#define DIGI_CMD_RECEIVE_ENABLE			10	/* INB, OOB */#define DIGI_CMD_BREAK_CONTROL			11	/* INB, OOB */#define DIGI_CMD_LOCAL_LOOPBACK			12	/* INB, OOB */#define DIGI_CMD_TRANSMIT_IDLE			13	/* INB, OOB */#define DIGI_CMD_READ_UART_REGISTER		14	/*      OOB */#define DIGI_CMD_WRITE_UART_REGISTER		15	/* INB, OOB */#define DIGI_CMD_AND_UART_REGISTER		16	/* INB, OOB */#define DIGI_CMD_OR_UART_REGISTER		17	/* INB, OOB */#define DIGI_CMD_SEND_DATA			18	/* INB      */#define DIGI_CMD_RECEIVE_DATA			19	/* INB      */#define DIGI_CMD_RECEIVE_DISABLE		20	/* INB      */#define DIGI_CMD_GET_PORT_TYPE			21	/*      OOB *//* baud rates */#define DIGI_BAUD_50				0#define DIGI_BAUD_75				1#define DIGI_BAUD_110				2#define DIGI_BAUD_150				3#define DIGI_BAUD_200				4#define DIGI_BAUD_300				5#define DIGI_BAUD_600				6#define DIGI_BAUD_1200				7#define DIGI_BAUD_1800				8#define DIGI_BAUD_2400				9#define DIGI_BAUD_4800				10#define DIGI_BAUD_7200				11#define DIGI_BAUD_9600				12#define DIGI_BAUD_14400				13#define DIGI_BAUD_19200				14#define DIGI_BAUD_28800				15#define DIGI_BAUD_38400				16#define DIGI_BAUD_57600				17#define DIGI_BAUD_76800				18#define DIGI_BAUD_115200			19#define DIGI_BAUD_153600			20#define DIGI_BAUD_230400			21#define DIGI_BAUD_460800			22/* arguments */#define DIGI_WORD_SIZE_5			0#define DIGI_WORD_SIZE_6			1#define DIGI_WORD_SIZE_7			2#define DIGI_WORD_SIZE_8			3#define DIGI_PARITY_NONE			0#define DIGI_PARITY_ODD				1#define DIGI_PARITY_EVEN			2#define DIGI_PARITY_MARK			3#define DIGI_PARITY_SPACE			4#define DIGI_STOP_BITS_1			0#define DIGI_STOP_BITS_2			1#define DIGI_INPUT_FLOW_CONTROL_XON_XOFF	1#define DIGI_INPUT_FLOW_CONTROL_RTS		2#define DIGI_INPUT_FLOW_CONTROL_DTR		4#define DIGI_OUTPUT_FLOW_CONTROL_XON_XOFF	1#define DIGI_OUTPUT_FLOW_CONTROL_CTS		2#define DIGI_OUTPUT_FLOW_CONTROL_DSR		4#define DIGI_DTR_INACTIVE			0#define DIGI_DTR_ACTIVE				1#define DIGI_DTR_INPUT_FLOW_CONTROL		2#define DIGI_RTS_INACTIVE			0#define DIGI_RTS_ACTIVE				1#define DIGI_RTS_INPUT_FLOW_CONTROL		2#define DIGI_RTS_TOGGLE				3#define DIGI_FLUSH_TX				1#define DIGI_FLUSH_RX				2#define DIGI_RESUME_TX				4 /* clears xoff condition */#define DIGI_TRANSMIT_NOT_IDLE			0#define DIGI_TRANSMIT_IDLE			1#define DIGI_DISABLE				0#define DIGI_ENABLE				1#define DIGI_DEASSERT				0#define DIGI_ASSERT				1/* in band status codes */#define DIGI_OVERRUN_ERROR			4#define DIGI_PARITY_ERROR			8#define DIGI_FRAMING_ERROR			16#define DIGI_BREAK_ERROR			32/* out of band status */#define DIGI_NO_ERROR				0#define DIGI_BAD_FIRST_PARAMETER		1#define DIGI_BAD_SECOND_PARAMETER		2#define DIGI_INVALID_LINE			3#define DIGI_INVALID_OPCODE			4/* input signals */#define DIGI_READ_INPUT_SIGNALS_SLOT		1#define DIGI_READ_INPUT_SIGNALS_ERR		2#define DIGI_READ_INPUT_SIGNALS_BUSY		4#define DIGI_READ_INPUT_SIGNALS_PE		8#define DIGI_READ_INPUT_SIGNALS_CTS		16#define DIGI_READ_INPUT_SIGNALS_DSR		32#define DIGI_READ_INPUT_SIGNALS_RI		64#define DIGI_READ_INPUT_SIGNALS_DCD		128/* Structures */typedef struct digi_serial {	spinlock_t ds_serial_lock;	struct usb_serial_port *ds_oob_port;	/* out-of-band port */	int ds_oob_port_num;			/* index of out-of-band port */	int ds_device_started;} digi_serial_t;typedef struct digi_port {

⌨️ 快捷键说明

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