📄 digi_acceleport.c
字号:
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 + -