📄 mct_u232.c
字号:
{ struct usb_serial *serial = port->serial; struct mct_u232_private *priv = usb_get_serial_port_data(port); int retval = 0; unsigned int control_state; unsigned long flags; unsigned char last_lcr; unsigned char last_msr; dbg("%s port %d", __FUNCTION__, port->number); /* Compensate for a hardware bug: although the Sitecom U232-P25 * device reports a maximum output packet size of 32 bytes, * it seems to be able to accept only 16 bytes (and that's what * SniffUSB says too...) */ if (le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_SITECOM_PID) port->bulk_out_size = 16; /* Do a defined restart: the normal serial device seems to * always turn on DTR and RTS here, so do the same. I'm not * sure if this is really necessary. But it should not harm * either. */ spin_lock_irqsave(&priv->lock, flags); if (port->tty->termios->c_cflag & CBAUD) priv->control_state = TIOCM_DTR | TIOCM_RTS; else priv->control_state = 0; priv->last_lcr = (MCT_U232_DATA_BITS_8 | MCT_U232_PARITY_NONE | MCT_U232_STOP_BITS_1); control_state = priv->control_state; last_lcr = priv->last_lcr; spin_unlock_irqrestore(&priv->lock, flags); mct_u232_set_modem_ctrl(serial, control_state); mct_u232_set_line_ctrl(serial, last_lcr); /* Read modem status and update control state */ mct_u232_get_modem_stat(serial, &last_msr); spin_lock_irqsave(&priv->lock, flags); priv->last_msr = last_msr; mct_u232_msr_to_state(&priv->control_state, priv->last_msr); spin_unlock_irqrestore(&priv->lock, flags); port->read_urb->dev = port->serial->dev; retval = usb_submit_urb(port->read_urb, GFP_KERNEL); if (retval) { err("usb_submit_urb(read bulk) failed pipe 0x%x err %d", port->read_urb->pipe, retval); goto exit; } port->interrupt_in_urb->dev = port->serial->dev; retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (retval) err(" usb_submit_urb(read int) failed pipe 0x%x err %d", port->interrupt_in_urb->pipe, retval);exit: return 0;} /* mct_u232_open */static void mct_u232_close (struct usb_serial_port *port, struct file *filp){ dbg("%s port %d", __FUNCTION__, port->number); if (port->serial->dev) { /* shutdown our urbs */ usb_kill_urb(port->write_urb); usb_kill_urb(port->read_urb); usb_kill_urb(port->interrupt_in_urb); }} /* mct_u232_close */static void mct_u232_read_int_callback (struct urb *urb, struct pt_regs *regs){ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct mct_u232_private *priv = usb_get_serial_port_data(port); struct usb_serial *serial = port->serial; struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; int status; unsigned long flags; switch (urb->status) { case 0: /* success */ break; case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); return; default: dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); goto exit; } if (!serial) { dbg("%s - bad serial pointer, exiting", __FUNCTION__); return; } dbg("%s - port %d", __FUNCTION__, port->number); usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); /* * Work-a-round: handle the 'usual' bulk-in pipe here */ if (urb->transfer_buffer_length > 2) { int i; tty = port->tty; if (urb->actual_length) { for (i = 0; i < urb->actual_length ; ++i) { tty_insert_flip_char(tty, data[i], 0); } tty_flip_buffer_push(tty); } goto exit; } /* * The interrupt-in pipe signals exceptional conditions (modem line * signal changes and errors). data[0] holds MSR, data[1] holds LSR. */ spin_lock_irqsave(&priv->lock, flags); priv->last_msr = data[MCT_U232_MSR_INDEX]; /* Record Control Line states */ mct_u232_msr_to_state(&priv->control_state, priv->last_msr);#if 0 /* Not yet handled. See belin_sa.c for further information */ /* Now to report any errors */ priv->last_lsr = data[MCT_U232_LSR_INDEX]; /* * fill in the flip buffer here, but I do not know the relation * to the current/next receive buffer or characters. I need * to look in to this before committing any code. */ if (priv->last_lsr & MCT_U232_LSR_ERR) { tty = port->tty; /* Overrun Error */ if (priv->last_lsr & MCT_U232_LSR_OE) { } /* Parity Error */ if (priv->last_lsr & MCT_U232_LSR_PE) { } /* Framing Error */ if (priv->last_lsr & MCT_U232_LSR_FE) { } /* Break Indicator */ if (priv->last_lsr & MCT_U232_LSR_BI) { } }#endif spin_unlock_irqrestore(&priv->lock, flags);exit: status = usb_submit_urb (urb, GFP_ATOMIC); if (status) err ("%s - usb_submit_urb failed with result %d", __FUNCTION__, status);} /* mct_u232_read_int_callback */static void mct_u232_set_termios (struct usb_serial_port *port, struct termios *old_termios){ struct usb_serial *serial = port->serial; struct mct_u232_private *priv = usb_get_serial_port_data(port); unsigned int iflag = port->tty->termios->c_iflag; unsigned int cflag = port->tty->termios->c_cflag; unsigned int old_cflag = old_termios->c_cflag; unsigned long flags; unsigned int control_state, new_state; unsigned char last_lcr; /* get a local copy of the current port settings */ spin_lock_irqsave(&priv->lock, flags); control_state = priv->control_state; spin_unlock_irqrestore(&priv->lock, flags); last_lcr = 0; /* * Update baud rate. * Do not attempt to cache old rates and skip settings, * disconnects screw such tricks up completely. * Premature optimization is the root of all evil. */ /* reassert DTR and (maybe) RTS on transition from B0 */ if ((old_cflag & CBAUD) == B0) { dbg("%s: baud was B0", __FUNCTION__); control_state |= TIOCM_DTR; /* don't set RTS if using hardware flow control */ if (!(old_cflag & CRTSCTS)) { control_state |= TIOCM_RTS; } mct_u232_set_modem_ctrl(serial, control_state); } mct_u232_set_baud_rate(serial, cflag & CBAUD); if ((cflag & CBAUD) == B0 ) { dbg("%s: baud is B0", __FUNCTION__); /* Drop RTS and DTR */ control_state &= ~(TIOCM_DTR | TIOCM_RTS); mct_u232_set_modem_ctrl(serial, control_state); } /* * Update line control register (LCR) */ /* set the parity */ if (cflag & PARENB) last_lcr |= (cflag & PARODD) ? MCT_U232_PARITY_ODD : MCT_U232_PARITY_EVEN; else last_lcr |= MCT_U232_PARITY_NONE; /* set the number of data bits */ switch (cflag & CSIZE) { case CS5: last_lcr |= MCT_U232_DATA_BITS_5; break; case CS6: last_lcr |= MCT_U232_DATA_BITS_6; break; case CS7: last_lcr |= MCT_U232_DATA_BITS_7; break; case CS8: last_lcr |= MCT_U232_DATA_BITS_8; break; default: err("CSIZE was not CS5-CS8, using default of 8"); last_lcr |= MCT_U232_DATA_BITS_8; break; } /* set the number of stop bits */ last_lcr |= (cflag & CSTOPB) ? MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1; mct_u232_set_line_ctrl(serial, last_lcr); /* * Set flow control: well, I do not really now how to handle DTR/RTS. * Just do what we have seen with SniffUSB on Win98. */ /* Drop DTR/RTS if no flow control otherwise assert */ new_state = control_state; if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS)) new_state |= TIOCM_DTR | TIOCM_RTS; else new_state &= ~(TIOCM_DTR | TIOCM_RTS); if (new_state != control_state) { mct_u232_set_modem_ctrl(serial, new_state); control_state = new_state; } /* save off the modified port settings */ spin_lock_irqsave(&priv->lock, flags); priv->control_state = control_state; priv->last_lcr = last_lcr; spin_unlock_irqrestore(&priv->lock, flags);} /* mct_u232_set_termios */static void mct_u232_break_ctl( struct usb_serial_port *port, int break_state ){ struct usb_serial *serial = port->serial; struct mct_u232_private *priv = usb_get_serial_port_data(port); unsigned char lcr; unsigned long flags; dbg("%sstate=%d", __FUNCTION__, break_state); spin_lock_irqsave(&priv->lock, flags); lcr = priv->last_lcr; spin_unlock_irqrestore(&priv->lock, flags); if (break_state) lcr |= MCT_U232_SET_BREAK; mct_u232_set_line_ctrl(serial, lcr);} /* mct_u232_break_ctl */static int mct_u232_tiocmget (struct usb_serial_port *port, struct file *file){ struct mct_u232_private *priv = usb_get_serial_port_data(port); unsigned int control_state; unsigned long flags; dbg("%s", __FUNCTION__); spin_lock_irqsave(&priv->lock, flags); control_state = priv->control_state; spin_unlock_irqrestore(&priv->lock, flags); return control_state;}static int mct_u232_tiocmset (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear){ struct usb_serial *serial = port->serial; struct mct_u232_private *priv = usb_get_serial_port_data(port); unsigned int control_state; unsigned long flags; dbg("%s", __FUNCTION__); spin_lock_irqsave(&priv->lock, flags); control_state = priv->control_state; if (set & TIOCM_RTS) control_state |= TIOCM_RTS; if (set & TIOCM_DTR) control_state |= TIOCM_DTR; if (clear & TIOCM_RTS) control_state &= ~TIOCM_RTS; if (clear & TIOCM_DTR) control_state &= ~TIOCM_DTR; priv->control_state = control_state; spin_unlock_irqrestore(&priv->lock, flags); return mct_u232_set_modem_ctrl(serial, control_state);}static int mct_u232_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg){ dbg("%scmd=0x%x", __FUNCTION__, cmd); /* Based on code from acm.c and others */ switch (cmd) { case TIOCMIWAIT: /* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/ /* TODO */ return( 0 ); case TIOCGICOUNT: /* return count of modemline transitions */ /* TODO */ return 0; default: dbg("%s: arg not supported - 0x%04x", __FUNCTION__,cmd); return(-ENOIOCTLCMD); break; } return 0;} /* mct_u232_ioctl */static int __init mct_u232_init (void){ int retval; retval = usb_serial_register(&mct_u232_device); if (retval) goto failed_usb_serial_register; retval = usb_register(&mct_u232_driver); if (retval) goto failed_usb_register; info(DRIVER_DESC " " DRIVER_VERSION); return 0;failed_usb_register: usb_serial_deregister(&mct_u232_device);failed_usb_serial_register: return retval;}static void __exit mct_u232_exit (void){ usb_deregister (&mct_u232_driver); usb_serial_deregister (&mct_u232_device);}module_init (mct_u232_init);module_exit(mct_u232_exit);MODULE_AUTHOR( DRIVER_AUTHOR );MODULE_DESCRIPTION( DRIVER_DESC );MODULE_LICENSE("GPL");module_param(debug, bool, S_IRUGO | S_IWUSR);MODULE_PARM_DESC(debug, "Debug enabled or not");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -