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

📄 digi_acceleport.c

📁 基于S3CEB2410平台LINUX操作系统下 USB驱动源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	spinlock_t dp_port_lock;	int dp_port_num;	int dp_out_buf_len;	unsigned char dp_out_buf[DIGI_OUT_BUF_SIZE];	int dp_in_buf_len;	unsigned char dp_in_buf[DIGI_IN_BUF_SIZE];	unsigned char dp_in_flag_buf[DIGI_IN_BUF_SIZE];	int dp_write_urb_in_use;	unsigned int dp_modem_signals;	wait_queue_head_t dp_modem_change_wait;	int dp_open_count;			/* inc on open, dec on close */	int dp_transmit_idle;	wait_queue_head_t dp_transmit_idle_wait;	int dp_throttled;	int dp_throttle_restart;	wait_queue_head_t dp_flush_wait;	int dp_in_close;			/* close in progress */	wait_queue_head_t dp_close_wait;	/* wait queue for close */	struct tq_struct dp_wakeup_task;} digi_port_t;/* Local Function Declarations */static void digi_wakeup_write( struct usb_serial_port *port );static void digi_wakeup_write_lock( struct usb_serial_port *port );static int digi_write_oob_command( struct usb_serial_port *port,	unsigned char *buf, int count, int interruptible );static int digi_write_inb_command( struct usb_serial_port *port,	unsigned char *buf, int count, unsigned long timeout );static int digi_set_modem_signals( struct usb_serial_port *port,	unsigned int modem_signals, int interruptible );static int digi_transmit_idle( struct usb_serial_port *port,	unsigned long timeout );static void digi_rx_throttle (struct usb_serial_port *port);static void digi_rx_unthrottle (struct usb_serial_port *port);static void digi_set_termios( struct usb_serial_port *port, 	struct termios *old_termios );static void digi_break_ctl( struct usb_serial_port *port, int break_state );static int digi_ioctl( struct usb_serial_port *port, struct file *file,	unsigned int cmd, unsigned long arg );static int digi_write( struct usb_serial_port *port, int from_user,	const unsigned char *buf, int count );static void digi_write_bulk_callback( struct urb *urb );static int digi_write_room( struct usb_serial_port *port );static int digi_chars_in_buffer( struct usb_serial_port *port );static int digi_open( struct usb_serial_port *port, struct file *filp );static void digi_close( struct usb_serial_port *port, struct file *filp );static int digi_startup_device( struct usb_serial *serial );static int digi_startup( struct usb_serial *serial );static void digi_shutdown( struct usb_serial *serial );static void digi_read_bulk_callback( struct urb *urb );static int digi_read_inb_callback( struct urb *urb );static int digi_read_oob_callback( struct urb *urb );/* Statics */static __devinitdata struct usb_device_id id_table_combined [] = {	{ USB_DEVICE(DIGI_VENDOR_ID, DIGI_2_ID) },	{ USB_DEVICE(DIGI_VENDOR_ID, DIGI_4_ID) },	{ }						/* Terminating entry */};static __devinitdata struct usb_device_id id_table_2 [] = {	{ USB_DEVICE(DIGI_VENDOR_ID, DIGI_2_ID) },	{ }						/* Terminating entry */};static __devinitdata struct usb_device_id id_table_4 [] = {	{ USB_DEVICE(DIGI_VENDOR_ID, DIGI_4_ID) },	{ }						/* Terminating entry */};MODULE_DEVICE_TABLE (usb, id_table_combined);/* device info needed for the Digi serial converter */static struct usb_serial_device_type digi_acceleport_2_device = {	name:				"Digi USB",	id_table:			id_table_2,	needs_interrupt_in:		DONT_CARE,	needs_bulk_in:			MUST_HAVE,	needs_bulk_out:			MUST_HAVE,	num_interrupt_in:		0,	num_bulk_in:			4,	num_bulk_out:			4,	num_ports:			3,	open:				digi_open,	close:				digi_close,	write:				digi_write,	write_room:			digi_write_room,	write_bulk_callback: 		digi_write_bulk_callback,	read_bulk_callback:		digi_read_bulk_callback,	chars_in_buffer:		digi_chars_in_buffer,	throttle:			digi_rx_throttle,	unthrottle:			digi_rx_unthrottle,	ioctl:				digi_ioctl,	set_termios:			digi_set_termios,	break_ctl:			digi_break_ctl,	startup:			digi_startup,	shutdown:			digi_shutdown,};static struct usb_serial_device_type digi_acceleport_4_device = {	name:				"Digi USB",	id_table:			id_table_4,	needs_interrupt_in:		DONT_CARE,	needs_bulk_in:			MUST_HAVE,	needs_bulk_out:			MUST_HAVE,	num_interrupt_in:		0,	num_bulk_in:			5,	num_bulk_out:			5,	num_ports:			4,	open:				digi_open,	close:				digi_close,	write:				digi_write,	write_room:			digi_write_room,	write_bulk_callback: 		digi_write_bulk_callback,	read_bulk_callback:		digi_read_bulk_callback,	chars_in_buffer:		digi_chars_in_buffer,	throttle:			digi_rx_throttle,	unthrottle:			digi_rx_unthrottle,	ioctl:				digi_ioctl,	set_termios:			digi_set_termios,	break_ctl:			digi_break_ctl,	startup:			digi_startup,	shutdown:			digi_shutdown,};/* Functions *//**  Cond Wait Interruptible Timeout Irqrestore**  Do spin_unlock_irqrestore and interruptible_sleep_on_timeout*  so that wake ups are not lost if they occur between the unlock*  and the sleep.  In other words, spin_lock_irqrestore and*  interruptible_sleep_on_timeout are "atomic" with respect to*  wake ups.  This is used to implement condition variables.*/static inline long cond_wait_interruptible_timeout_irqrestore(	wait_queue_head_t *q, long timeout,	spinlock_t *lock, unsigned long flags ){	wait_queue_t wait;	init_waitqueue_entry( &wait, current );	set_current_state( TASK_INTERRUPTIBLE );	add_wait_queue( q, &wait );	spin_unlock_irqrestore( lock, flags );	timeout = schedule_timeout(timeout);	set_current_state( TASK_RUNNING );	remove_wait_queue( q, &wait );	return( timeout );}/**  Digi Wakeup Write**  Wake up port, line discipline, and tty processes sleeping*  on writes.*/static void digi_wakeup_write_lock( struct usb_serial_port *port ){	unsigned long flags;	digi_port_t *priv = (digi_port_t *)(port->private);	spin_lock_irqsave( &priv->dp_port_lock, flags );	digi_wakeup_write( port );	spin_unlock_irqrestore( &priv->dp_port_lock, flags );	MOD_DEC_USE_COUNT;}static void digi_wakeup_write( struct usb_serial_port *port ){	struct tty_struct *tty = port->tty;	/* wake up port processes */	wake_up_interruptible( &port->write_wait );	/* wake up line discipline */	if( (tty->flags & (1 << TTY_DO_WRITE_WAKEUP))	&& tty->ldisc.write_wakeup )		(tty->ldisc.write_wakeup)(tty);	/* wake up other tty processes */	wake_up_interruptible( &tty->write_wait );	/* For 2.2.16 backport -- wake_up_interruptible( &tty->poll_wait ); */}/**  Digi Write OOB Command**  Write commands on the out of band port.  Commands are 4*  bytes each, multiple commands can be sent at once, and*  no command will be split across USB packets.  Returns 0*  if successful, -EINTR if interrupted while sleeping and*  the interruptible flag is true, or a negative error*  returned by usb_submit_urb.*/static int digi_write_oob_command( struct usb_serial_port *port,	unsigned char *buf, int count, int interruptible ){	int ret = 0;	int len;	struct usb_serial_port *oob_port = (struct usb_serial_port *)((digi_serial_t *)port->serial->private)->ds_oob_port;	digi_port_t *oob_priv = (digi_port_t *)oob_port->private;	unsigned long flags = 0;dbg( "digi_write_oob_command: TOP: port=%d, count=%d", oob_priv->dp_port_num, count );	spin_lock_irqsave( &oob_priv->dp_port_lock, flags );	while( count > 0 ) {		while( oob_port->write_urb->status == -EINPROGRESS		|| oob_priv->dp_write_urb_in_use ) {			cond_wait_interruptible_timeout_irqrestore(				&oob_port->write_wait, DIGI_RETRY_TIMEOUT,				&oob_priv->dp_port_lock, flags );			if( interruptible && signal_pending(current) ) {				return( -EINTR );			}			spin_lock_irqsave( &oob_priv->dp_port_lock, flags );		}		/* len must be a multiple of 4, so commands are not split */		len = min(count, oob_port->bulk_out_size );		if( len > 4 )			len &= ~3;		memcpy( oob_port->write_urb->transfer_buffer, buf, len );		oob_port->write_urb->transfer_buffer_length = len;		oob_port->write_urb->dev = port->serial->dev;		if( (ret=usb_submit_urb(oob_port->write_urb)) == 0 ) {			oob_priv->dp_write_urb_in_use = 1;			count -= len;			buf += len;		}	}	spin_unlock_irqrestore( &oob_priv->dp_port_lock, flags );	if( ret ) {		err( __FUNCTION__ ": usb_submit_urb failed, ret=%d",			ret );	}	return( ret );}/**  Digi Write In Band Command**  Write commands on the given port.  Commands are 4*  bytes each, multiple commands can be sent at once, and*  no command will be split across USB packets.  If timeout*  is non-zero, write in band command will return after*  waiting unsuccessfully for the URB status to clear for*  timeout ticks.  Returns 0 if successful, or a negative*  error returned by digi_write.*/static int digi_write_inb_command( struct usb_serial_port *port,	unsigned char *buf, int count, unsigned long timeout ){	int ret = 0;	int len;	digi_port_t *priv = (digi_port_t *)(port->private);	unsigned char *data = port->write_urb->transfer_buffer;	unsigned long flags = 0;dbg( "digi_write_inb_command: TOP: port=%d, count=%d", priv->dp_port_num,count );	if( timeout )		timeout += jiffies;	else		timeout = ULONG_MAX;	spin_lock_irqsave( &priv->dp_port_lock, flags );	while( count > 0 && ret == 0 ) {		while( (port->write_urb->status == -EINPROGRESS		|| priv->dp_write_urb_in_use) && jiffies < timeout ) {			cond_wait_interruptible_timeout_irqrestore(				&port->write_wait, DIGI_RETRY_TIMEOUT,				&priv->dp_port_lock, flags );			if( signal_pending(current) ) {				return( -EINTR );			}			spin_lock_irqsave( &priv->dp_port_lock, flags );		}		/* len must be a multiple of 4 and small enough to */		/* guarantee the write will send buffered data first, */		/* so commands are in order with data and not split */		len = min(count, port->bulk_out_size-2-priv->dp_out_buf_len );		if( len > 4 )			len &= ~3;		/* write any buffered data first */		if( priv->dp_out_buf_len > 0 ) {			data[0] = DIGI_CMD_SEND_DATA;			data[1] = priv->dp_out_buf_len;			memcpy( data+2, priv->dp_out_buf,				priv->dp_out_buf_len );			memcpy( data+2+priv->dp_out_buf_len, buf, len );			port->write_urb->transfer_buffer_length				= priv->dp_out_buf_len+2+len;		} else {			memcpy( data, buf, len );			port->write_urb->transfer_buffer_length = len;		}		port->write_urb->dev = port->serial->dev;		if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {			priv->dp_write_urb_in_use = 1;			priv->dp_out_buf_len = 0;			count -= len;			buf += len;		}	}	spin_unlock_irqrestore( &priv->dp_port_lock, flags );	if( ret ) {		err( __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d",		ret, priv->dp_port_num );	}	return( ret );}/**  Digi Set Modem Signals**  Sets or clears DTR and RTS on the port, according to the*  modem_signals argument.  Use TIOCM_DTR and TIOCM_RTS flags*  for the modem_signals argument.  Returns 0 if successful,*  -EINTR if interrupted while sleeping, or a non-zero error*  returned by usb_submit_urb.*/static int digi_set_modem_signals( struct usb_serial_port *port,	unsigned int modem_signals, int interruptible ){	int ret;	digi_port_t *port_priv = (digi_port_t *)port->private;	struct usb_serial_port *oob_port = (struct usb_serial_port *)((digi_serial_t *)port->serial->private)->ds_oob_port;	digi_port_t *oob_priv = (digi_port_t *)oob_port->private;	unsigned char *data = oob_port->write_urb->transfer_buffer;	unsigned long flags = 0;dbg( "digi_set_modem_signals: TOP: port=%d, modem_signals=0x%x",port_priv->dp_port_num, modem_signals );	spin_lock_irqsave( &oob_priv->dp_port_lock, flags );	spin_lock( &port_priv->dp_port_lock );	while( oob_port->write_urb->status == -EINPROGRESS	|| oob_priv->dp_write_urb_in_use ) {		spin_unlock( &port_priv->dp_port_lock );		cond_wait_interruptible_timeout_irqrestore(			&oob_port->write_wait, DIGI_RETRY_TIMEOUT,			&oob_priv->dp_port_lock, flags );		if( interruptible && signal_pending(current) ) {			return( -EINTR );		}		spin_lock_irqsave( &oob_priv->dp_port_lock, flags );		spin_lock( &port_priv->dp_port_lock );	}	data[0] = DIGI_CMD_SET_DTR_SIGNAL;	data[1] = port_priv->dp_port_num;	data[2] = (modem_signals&TIOCM_DTR) ?		DIGI_DTR_ACTIVE : DIGI_DTR_INACTIVE;	data[3] = 0;	data[4] = DIGI_CMD_SET_RTS_SIGNAL;	data[5] = port_priv->dp_port_num;	data[6] = (modem_signals&TIOCM_RTS) ?		DIGI_RTS_ACTIVE : DIGI_RTS_INACTIVE;	data[7] = 0;

⌨️ 快捷键说明

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