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

📄 digi_acceleport.c

📁 基于S3CEB2410平台LINUX操作系统下 USB驱动源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	int ret,data_len,new_len;	digi_port_t *priv = (digi_port_t *)(port->private);	unsigned char *data = port->write_urb->transfer_buffer;	unsigned char user_buf[64];	/* 64 bytes is max USB bulk packet */	unsigned long flags = 0;dbg( "digi_write: TOP: port=%d, count=%d, from_user=%d, in_interrupt=%d",priv->dp_port_num, count, from_user, in_interrupt() );	/* copy user data (which can sleep) before getting spin lock */	count = min( count, port->bulk_out_size-2 );	count = min( 64, count);	if( from_user && copy_from_user( user_buf, buf, count ) ) {		return( -EFAULT );	}	/* be sure only one write proceeds at a time */	/* there are races on the port private buffer */	/* and races to check write_urb->status */	spin_lock_irqsave( &priv->dp_port_lock, flags );	/* wait for urb status clear to submit another urb */	if( port->write_urb->status == -EINPROGRESS	|| priv->dp_write_urb_in_use ) {		/* buffer data if count is 1 (probably put_char) if possible */		if( count == 1 && priv->dp_out_buf_len < DIGI_OUT_BUF_SIZE ) {			priv->dp_out_buf[priv->dp_out_buf_len++]				= *(from_user ? user_buf : buf);			new_len = 1;		} else {			new_len = 0;		}		spin_unlock_irqrestore( &priv->dp_port_lock, flags );		return( new_len );	}	/* allow space for any buffered data and for new data, up to */	/* transfer buffer size - 2 (for command and length bytes) */	new_len = min(count, port->bulk_out_size-2-priv->dp_out_buf_len);	data_len = new_len + priv->dp_out_buf_len;	if( data_len == 0 ) {		spin_unlock_irqrestore( &priv->dp_port_lock, flags );		return( 0 );	}	port->write_urb->transfer_buffer_length = data_len+2;	port->write_urb->dev = port->serial->dev;	*data++ = DIGI_CMD_SEND_DATA;	*data++ = data_len;	/* copy in buffered data first */	memcpy( data, priv->dp_out_buf, priv->dp_out_buf_len );	data += priv->dp_out_buf_len;	/* copy in new data */	memcpy( data, from_user ? user_buf : buf, new_len );	if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {		priv->dp_write_urb_in_use = 1;		ret = new_len;		priv->dp_out_buf_len = 0;	}	/* return length of new data written, or error */	spin_unlock_irqrestore( &priv->dp_port_lock, flags );	if( ret < 0 ) {		err( __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d",			ret, priv->dp_port_num );	}dbg( "digi_write: returning %d", ret );	return( ret );} static void digi_write_bulk_callback( struct urb *urb ){	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;	struct usb_serial *serial;	digi_port_t *priv;	int ret = 0;dbg( "digi_write_bulk_callback: TOP, urb->status=%d", urb->status );	/* port and serial sanity check */	if( port == NULL || (priv=(digi_port_t *)(port->private)) == NULL ) {		err( __FUNCTION__ ": port or port->private is NULL, status=%d",			urb->status );		return;	}	serial = port->serial;	if( serial == NULL || serial->private == NULL ) {		err( __FUNCTION__ ": serial or serial->private is NULL, status=%d", urb->status );		return;	}	/* handle oob callback */	if( priv->dp_port_num	== ((digi_serial_t *)(serial->private))->ds_oob_port_num ) {		dbg( "digi_write_bulk_callback: oob callback" );		spin_lock( &priv->dp_port_lock );		priv->dp_write_urb_in_use = 0;		wake_up_interruptible( &port->write_wait );		spin_unlock( &priv->dp_port_lock );		return;	}	/* further sanity checks */	if( port_paranoia_check( port, __FUNCTION__ )	|| serial_paranoia_check( serial, __FUNCTION__ ) )		return;	/* try to send any buffered data on this port, if it is open */	spin_lock( &priv->dp_port_lock );	priv->dp_write_urb_in_use = 0;	if( priv->dp_open_count && port->write_urb->status != -EINPROGRESS	&& priv->dp_out_buf_len > 0 ) {		*((unsigned char *)(port->write_urb->transfer_buffer))			= (unsigned char)DIGI_CMD_SEND_DATA;		*((unsigned char *)(port->write_urb->transfer_buffer)+1)			= (unsigned char)priv->dp_out_buf_len;		port->write_urb->transfer_buffer_length			= priv->dp_out_buf_len+2;		port->write_urb->dev = serial->dev;		memcpy( port->write_urb->transfer_buffer+2, priv->dp_out_buf,			priv->dp_out_buf_len );		if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {			priv->dp_write_urb_in_use = 1;			priv->dp_out_buf_len = 0;		}	}	/* wake up processes sleeping on writes immediately */	digi_wakeup_write( port );	/* also queue up a wakeup at scheduler time, in case we */	/* lost the race in write_chan(). */	MOD_INC_USE_COUNT;	if (schedule_task(&priv->dp_wakeup_task) == 0)		MOD_DEC_USE_COUNT;	spin_unlock( &priv->dp_port_lock );	if( ret ) {		err( __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d",			ret, priv->dp_port_num );	}}static int digi_write_room( struct usb_serial_port *port ){	int room;	digi_port_t *priv = (digi_port_t *)(port->private);	unsigned long flags = 0;	spin_lock_irqsave( &priv->dp_port_lock, flags );	if( port->write_urb->status == -EINPROGRESS	|| priv->dp_write_urb_in_use )		room = 0;	else		room = port->bulk_out_size - 2 - priv->dp_out_buf_len;	spin_unlock_irqrestore( &priv->dp_port_lock, flags );dbg( "digi_write_room: port=%d, room=%d", priv->dp_port_num, room );	return( room );}static int digi_chars_in_buffer( struct usb_serial_port *port ){	digi_port_t *priv = (digi_port_t *)(port->private);	if( port->write_urb->status == -EINPROGRESS	|| priv->dp_write_urb_in_use ) {dbg( "digi_chars_in_buffer: port=%d, chars=%d", priv->dp_port_num, port->bulk_out_size - 2 );		/* return( port->bulk_out_size - 2 ); */		return( 256 );	} else {dbg( "digi_chars_in_buffer: port=%d, chars=%d", priv->dp_port_num, priv->dp_out_buf_len );		return( priv->dp_out_buf_len );	}}static int digi_open( struct usb_serial_port *port, struct file *filp ){	int ret;	unsigned char buf[32];	digi_port_t *priv = (digi_port_t *)(port->private);	struct termios not_termios;	unsigned long flags = 0;dbg( "digi_open: TOP: port=%d, active=%d, open_count=%d", priv->dp_port_num, port->active, priv->dp_open_count );	/* be sure the device is started up */	if( digi_startup_device( port->serial ) != 0 )		return( -ENXIO );	spin_lock_irqsave( &priv->dp_port_lock, flags );	/* don't wait on a close in progress for non-blocking opens */	if( priv->dp_in_close && (filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0 ) {		spin_unlock_irqrestore( &priv->dp_port_lock, flags );		return( -EAGAIN );	}	/* inc module use count before sleeping to wait for closes */	++priv->dp_open_count;	MOD_INC_USE_COUNT;	/* wait for a close in progress to finish */	while( priv->dp_in_close ) {		cond_wait_interruptible_timeout_irqrestore(			&priv->dp_close_wait, DIGI_RETRY_TIMEOUT,			&priv->dp_port_lock, flags );		if( signal_pending(current) ) {			--priv->dp_open_count;			MOD_DEC_USE_COUNT;			return( -EINTR );		}		spin_lock_irqsave( &priv->dp_port_lock, flags );	}	/* if port is already open, just return */	/* be sure exactly one open proceeds */	if( port->active ) {		spin_unlock_irqrestore( &priv->dp_port_lock, flags );		return( 0 );	}	/* first open, mark port as active */	port->active = 1;	spin_unlock_irqrestore( &priv->dp_port_lock, flags ); 	/* read modem signals automatically whenever they change */	buf[0] = DIGI_CMD_READ_INPUT_SIGNALS;	buf[1] = priv->dp_port_num;	buf[2] = DIGI_ENABLE;	buf[3] = 0;	/* flush fifos */	buf[4] = DIGI_CMD_IFLUSH_FIFO;	buf[5] = priv->dp_port_num;	buf[6] = DIGI_FLUSH_TX | DIGI_FLUSH_RX;	buf[7] = 0;	if( (ret=digi_write_oob_command( port, buf, 8, 1 )) != 0 )		dbg( "digi_open: write oob failed, ret=%d", ret );	/* set termios settings */	not_termios.c_cflag = ~port->tty->termios->c_cflag;	not_termios.c_iflag = ~port->tty->termios->c_iflag;	digi_set_termios( port, &not_termios );	/* set DTR and RTS */	digi_set_modem_signals( port, TIOCM_DTR|TIOCM_RTS, 1 );	return( 0 );}static void digi_close( struct usb_serial_port *port, struct file *filp ){	int ret;	unsigned char buf[32];	struct tty_struct *tty = port->tty;	digi_port_t *priv = (digi_port_t *)port->private;	unsigned long flags = 0;dbg( "digi_close: TOP: port=%d, active=%d, open_count=%d", priv->dp_port_num, port->active, priv->dp_open_count );	/* do cleanup only after final close on this port */	spin_lock_irqsave( &priv->dp_port_lock, flags );	if( priv->dp_open_count > 1 ) {		--priv->dp_open_count;		MOD_DEC_USE_COUNT;		spin_unlock_irqrestore( &priv->dp_port_lock, flags );		return;	} else if( priv->dp_open_count <= 0 ) {		spin_unlock_irqrestore( &priv->dp_port_lock, flags );		return;	}	priv->dp_in_close = 1;	spin_unlock_irqrestore( &priv->dp_port_lock, flags );	/* tell line discipline to process only XON/XOFF */        tty->closing = 1;	/* wait for output to drain */	if( (filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0 ) {		tty_wait_until_sent( tty, DIGI_CLOSE_TIMEOUT );	}	/* flush driver and line discipline buffers */	if( tty->driver.flush_buffer )		tty->driver.flush_buffer( tty );	if( tty->ldisc.flush_buffer )		tty->ldisc.flush_buffer( tty );	if (port->serial->dev) {		/* wait for transmit idle */		if( (filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0 ) {			digi_transmit_idle( port, DIGI_CLOSE_TIMEOUT );		}		/* drop DTR and RTS */		digi_set_modem_signals( port, 0, 0 );		/* disable input flow control */		buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL;		buf[1] = priv->dp_port_num;		buf[2] = DIGI_DISABLE;		buf[3] = 0;		/* disable output flow control */		buf[4] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL;		buf[5] = priv->dp_port_num;		buf[6] = DIGI_DISABLE;		buf[7] = 0;		/* disable reading modem signals automatically */		buf[8] = DIGI_CMD_READ_INPUT_SIGNALS;		buf[9] = priv->dp_port_num;		buf[10] = DIGI_DISABLE;		buf[11] = 0;		/* disable receive */		buf[12] = DIGI_CMD_RECEIVE_ENABLE;		buf[13] = priv->dp_port_num;		buf[14] = DIGI_DISABLE;		buf[15] = 0;		/* flush fifos */		buf[16] = DIGI_CMD_IFLUSH_FIFO;		buf[17] = priv->dp_port_num;		buf[18] = DIGI_FLUSH_TX | DIGI_FLUSH_RX;		buf[19] = 0;		if( (ret=digi_write_oob_command( port, buf, 20, 0 )) != 0 )			dbg( "digi_close: write oob failed, ret=%d", ret );		/* wait for final commands on oob port to complete */		interruptible_sleep_on_timeout( &priv->dp_flush_wait,			DIGI_CLOSE_TIMEOUT );		/* shutdown any outstanding bulk writes */		usb_unlink_urb (port->write_urb);	}	tty->closing = 0;	spin_lock_irqsave( &priv->dp_port_lock, flags );	port->active = 0;	priv->dp_write_urb_in_use = 0;	priv->dp_in_close = 0;	--priv->dp_open_count;	MOD_DEC_USE_COUNT;	wake_up_interruptible( &priv->dp_close_wait );	spin_unlock_irqrestore( &priv->dp_port_lock, flags );dbg( "digi_close: done" );}/**  Digi Startup Device**  Starts reads on all ports.  Must be called AFTER startup, with*  urbs initialized.  Returns 0 if successful, non-zero error otherwise.*/static int digi_startup_device( struct usb_serial *serial ){	int i,ret = 0;	digi_serial_t *serial_priv = (digi_serial_t *)serial->private;	struct usb_serial_port *port;	/* be sure this happens exactly once */	spin_lock( &serial_priv->ds_serial_lock );	if( serial_priv->ds_device_started ) {		spin_unlock( &serial_priv->ds_serial_lock );		return( 0 );	}	serial_priv->ds_device_started = 1;	spin_unlock( &serial_priv->ds_serial_lock );	/* start reading from each bulk in endpoint for the device */	/* set USB_DISABLE_SPD flag for write bulk urbs */

⌨️ 快捷键说明

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