📄 digi_acceleport.c
字号:
for( i=0; i<serial->type->num_ports+1; i++ ) { port = &serial->port[i]; port->write_urb->dev = port->serial->dev; if( (ret=usb_submit_urb(port->read_urb)) != 0 ) { err( __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d", ret, i ); break; } } return( ret );}static int digi_startup( struct usb_serial *serial ){ int i; digi_port_t *priv; digi_serial_t *serial_priv;dbg( "digi_startup: TOP" ); /* allocate the private data structures for all ports */ /* number of regular ports + 1 for the out-of-band port */ for( i=0; i<serial->type->num_ports+1; i++ ) { serial->port[i].active = 0; /* allocate port private structure */ priv = serial->port[i].private = (digi_port_t *)kmalloc( sizeof(digi_port_t), GFP_KERNEL ); if( priv == (digi_port_t *)0 ) { while( --i >= 0 ) kfree( serial->port[i].private ); return( 1 ); /* error */ } /* initialize port private structure */ spin_lock_init( &priv->dp_port_lock ); priv->dp_port_num = i; priv->dp_out_buf_len = 0; priv->dp_in_buf_len = 0; priv->dp_write_urb_in_use = 0; priv->dp_modem_signals = 0; init_waitqueue_head( &priv->dp_modem_change_wait ); priv->dp_open_count = 0; priv->dp_transmit_idle = 0; init_waitqueue_head( &priv->dp_transmit_idle_wait ); priv->dp_throttled = 0; priv->dp_throttle_restart = 0; init_waitqueue_head( &priv->dp_flush_wait ); priv->dp_in_close = 0; init_waitqueue_head( &priv->dp_close_wait ); INIT_LIST_HEAD(&priv->dp_wakeup_task.list); priv->dp_wakeup_task.sync = 0; priv->dp_wakeup_task.routine = (void *)digi_wakeup_write_lock; priv->dp_wakeup_task.data = (void *)(&serial->port[i]); /* initialize write wait queue for this port */ init_waitqueue_head( &serial->port[i].write_wait ); } /* allocate serial private structure */ serial_priv = serial->private = (digi_serial_t *)kmalloc( sizeof(digi_serial_t), GFP_KERNEL ); if( serial_priv == (digi_serial_t *)0 ) { for( i=0; i<serial->type->num_ports+1; i++ ) kfree( serial->port[i].private ); return( 1 ); /* error */ } /* initialize serial private structure */ spin_lock_init( &serial_priv->ds_serial_lock ); serial_priv->ds_oob_port_num = serial->type->num_ports; serial_priv->ds_oob_port = &serial->port[serial_priv->ds_oob_port_num]; serial_priv->ds_device_started = 0; return( 0 );}static void digi_shutdown( struct usb_serial *serial ){ int i; digi_port_t *priv; unsigned long flags;dbg( "digi_shutdown: TOP, in_interrupt()=%d", in_interrupt() ); /* stop reads and writes on all ports */ for( i=0; i<serial->type->num_ports+1; i++ ) { usb_unlink_urb( serial->port[i].read_urb ); usb_unlink_urb( serial->port[i].write_urb ); } /* dec module use count */ for( i=0; i<serial->type->num_ports; i++ ) { priv = serial->port[i].private; spin_lock_irqsave( &priv->dp_port_lock, flags ); while( priv->dp_open_count > 0 ) { MOD_DEC_USE_COUNT; --priv->dp_open_count; } spin_unlock_irqrestore( &priv->dp_port_lock, flags ); } /* free the private data structures for all ports */ /* number of regular ports + 1 for the out-of-band port */ for( i=0; i<serial->type->num_ports+1; i++ ) kfree( serial->port[i].private ); kfree( serial->private );}static void digi_read_bulk_callback( struct urb *urb ){ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; digi_port_t *priv; int ret;dbg( "digi_read_bulk_callback: TOP" ); /* port sanity check, do not resubmit if port is not valid */ if( port == NULL || (priv=(digi_port_t *)(port->private)) == NULL ) { err( __FUNCTION__ ": port or port->private is NULL, status=%d", urb->status ); return; } if( port->serial == NULL || serial_paranoia_check( port->serial, __FUNCTION__ ) || port->serial->private == NULL ) { err( __FUNCTION__ ": serial is bad or serial->private is NULL, status=%d", urb->status ); return; } /* do not resubmit urb if it has any status error */ if( urb->status ) { err( __FUNCTION__ ": nonzero read bulk status: status=%d, port=%d", urb->status, priv->dp_port_num ); return; } /* handle oob or inb callback, do not resubmit if error */ if( priv->dp_port_num == ((digi_serial_t *)(port->serial->private))->ds_oob_port_num ) { if( digi_read_oob_callback( urb ) != 0 ) return; } else { if( digi_read_inb_callback( urb ) != 0 ) return; } /* continue read */ urb->dev = port->serial->dev; if( (ret=usb_submit_urb(urb)) != 0 ) { err( __FUNCTION__ ": failed resubmitting urb, ret=%d, port=%d", ret, priv->dp_port_num ); }}/* * Digi Read INB Callback** Digi Read INB Callback handles reads on the in band ports, sending* the data on to the tty subsystem. When called we know port and* port->private are not NULL and port->serial has been validated.* It returns 0 if successful, 1 if successful but the port is* throttled, and -1 if the sanity checks failed.*/static int digi_read_inb_callback( struct urb *urb ){ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct tty_struct *tty = port->tty; digi_port_t *priv = (digi_port_t *)(port->private); int opcode = ((unsigned char *)urb->transfer_buffer)[0]; int len = ((unsigned char *)urb->transfer_buffer)[1]; int status = ((unsigned char *)urb->transfer_buffer)[2]; unsigned char *data = ((unsigned char *)urb->transfer_buffer)+3; int flag,throttled; /* sanity check */ if( port_paranoia_check( port, __FUNCTION__ ) ) return( -1 ); /* do not process callbacks on closed ports */ /* but do continue the read chain */ if( priv->dp_open_count == 0 ) return( 0 ); /* short/multiple packet check */ if( urb->actual_length != len + 2 ) { err( __FUNCTION__ ": INCOMPLETE OR MULTIPLE PACKET, urb->status=%d, port=%d, opcode=%d, len=%d, actual_length=%d, status=%d", urb->status, priv->dp_port_num, opcode, len, urb->actual_length, status ); return( -1 ); } spin_lock( &priv->dp_port_lock ); /* check for throttle; if set, do not resubmit read urb */ /* indicate the read chain needs to be restarted on unthrottle */ throttled = priv->dp_throttled; if( throttled ) priv->dp_throttle_restart = 1; /* receive data */ if( opcode == DIGI_CMD_RECEIVE_DATA ) { /* get flag from status */ flag = 0; /* overrun is special, not associated with a char */ if( status & DIGI_OVERRUN_ERROR ) { tty_insert_flip_char( tty, 0, TTY_OVERRUN ); } /* break takes precedence over parity, */ /* which takes precedence over framing errors */ if( status & DIGI_BREAK_ERROR ) { flag = TTY_BREAK; } else if( status & DIGI_PARITY_ERROR ) { flag = TTY_PARITY; } else if( status & DIGI_FRAMING_ERROR ) { flag = TTY_FRAME; } /* data length is len-1 (one byte of len is status) */ --len; if( throttled ) { len = min( len, DIGI_IN_BUF_SIZE - priv->dp_in_buf_len ); if( len > 0 ) { memcpy( priv->dp_in_buf + priv->dp_in_buf_len, data, len ); memset( priv->dp_in_flag_buf + priv->dp_in_buf_len, flag, len ); priv->dp_in_buf_len += len; } } else { len = min( len, TTY_FLIPBUF_SIZE - tty->flip.count ); if( len > 0 ) { memcpy( tty->flip.char_buf_ptr, data, len ); memset( tty->flip.flag_buf_ptr, flag, len ); tty->flip.char_buf_ptr += len; tty->flip.flag_buf_ptr += len; tty->flip.count += len; tty_flip_buffer_push( tty ); } } } spin_unlock( &priv->dp_port_lock ); if( opcode == DIGI_CMD_RECEIVE_DISABLE ) { dbg( __FUNCTION__ ": got RECEIVE_DISABLE" ); } else if( opcode != DIGI_CMD_RECEIVE_DATA ) { dbg( __FUNCTION__ ": unknown opcode: %d", opcode ); } return( throttled ? 1 : 0 );}/* * Digi Read OOB Callback** Digi Read OOB Callback handles reads on the out of band port.* When called we know port and port->private are not NULL and* the port->serial is valid. It returns 0 if successful, and* -1 if the sanity checks failed.*/static int digi_read_oob_callback( struct urb *urb ){ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct usb_serial *serial = port->serial; digi_port_t *priv = (digi_port_t *)(port->private); int opcode, line, status, val; int i;dbg( "digi_read_oob_callback: port=%d, len=%d", priv->dp_port_num,urb->actual_length ); /* handle each oob command */ for( i=0; i<urb->actual_length-3; ) { opcode = ((unsigned char *)urb->transfer_buffer)[i++]; line = ((unsigned char *)urb->transfer_buffer)[i++]; status = ((unsigned char *)urb->transfer_buffer)[i++]; val = ((unsigned char *)urb->transfer_buffer)[i++];dbg( "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d",opcode, line, status, val ); if( status != 0 || line >= serial->type->num_ports ) continue; port = &serial->port[line]; if( port_paranoia_check( port, __FUNCTION__ ) || (priv=port->private) == NULL ) return( -1 ); if( opcode == DIGI_CMD_READ_INPUT_SIGNALS ) { spin_lock( &priv->dp_port_lock ); /* convert from digi flags to termiox flags */ if( val & DIGI_READ_INPUT_SIGNALS_CTS ) { priv->dp_modem_signals |= TIOCM_CTS; /* port must be open to use tty struct */ if( priv->dp_open_count && port->tty->termios->c_cflag & CRTSCTS ) { port->tty->hw_stopped = 0; digi_wakeup_write( port ); } } else { priv->dp_modem_signals &= ~TIOCM_CTS; /* port must be open to use tty struct */ if( priv->dp_open_count && port->tty->termios->c_cflag & CRTSCTS ) { port->tty->hw_stopped = 1; } } if( val & DIGI_READ_INPUT_SIGNALS_DSR ) priv->dp_modem_signals |= TIOCM_DSR; else priv->dp_modem_signals &= ~TIOCM_DSR; if( val & DIGI_READ_INPUT_SIGNALS_RI ) priv->dp_modem_signals |= TIOCM_RI; else priv->dp_modem_signals &= ~TIOCM_RI; if( val & DIGI_READ_INPUT_SIGNALS_DCD ) priv->dp_modem_signals |= TIOCM_CD; else priv->dp_modem_signals &= ~TIOCM_CD; wake_up_interruptible( &priv->dp_modem_change_wait ); spin_unlock( &priv->dp_port_lock ); } else if( opcode == DIGI_CMD_TRANSMIT_IDLE ) { spin_lock( &priv->dp_port_lock ); priv->dp_transmit_idle = 1; wake_up_interruptible( &priv->dp_transmit_idle_wait ); spin_unlock( &priv->dp_port_lock ); } else if( opcode == DIGI_CMD_IFLUSH_FIFO ) { wake_up_interruptible( &priv->dp_flush_wait ); } } return( 0 );}static int __init digi_init (void){ usb_serial_register (&digi_acceleport_2_device); usb_serial_register (&digi_acceleport_4_device); info(DRIVER_VERSION ":" DRIVER_DESC); return 0;}static void __exit digi_exit (void){ usb_serial_deregister (&digi_acceleport_2_device); usb_serial_deregister (&digi_acceleport_4_device);}module_init(digi_init);module_exit(digi_exit);MODULE_AUTHOR( DRIVER_AUTHOR );MODULE_DESCRIPTION( DRIVER_DESC );MODULE_LICENSE("GPL");MODULE_PARM(debug, "i");MODULE_PARM_DESC(debug, "Debug enabled or not");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -