📄 kl5kusb105.c
字号:
if (urb->transfer_buffer == NULL) { err("%s - no more kernel memory...", __FUNCTION__); goto exit; } } size = min (count, port->bulk_out_size - KLSI_105_DATA_OFFSET); size = min (size, URB_TRANSFER_BUFFER_SIZE - KLSI_105_DATA_OFFSET); memcpy (urb->transfer_buffer + KLSI_105_DATA_OFFSET, buf, size); /* write payload size into transfer buffer */ ((__u8 *)urb->transfer_buffer)[0] = (__u8) (size & 0xFF); ((__u8 *)urb->transfer_buffer)[1] = (__u8) ((size & 0xFF00)>>8); /* set up our urb */ usb_fill_bulk_urb(urb, port->serial->dev, usb_sndbulkpipe(port->serial->dev, port->bulk_out_endpointAddress), urb->transfer_buffer, URB_TRANSFER_BUFFER_SIZE, klsi_105_write_bulk_callback, port); /* send the data out the bulk port */ result = usb_submit_urb(urb, GFP_ATOMIC); if (result) { err("%s - failed submitting write urb, error %d", __FUNCTION__, result); goto exit; } buf += size; bytes_sent += size; count -= size; }exit: /* lockless, but it's for debug info only... */ priv->bytes_out+=bytes_sent; return bytes_sent; /* that's how much we wrote */} /* klsi_105_write */static void klsi_105_write_bulk_callback ( struct urb *urb, struct pt_regs *regs){ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; dbg("%s - port %d", __FUNCTION__, port->number); if (urb->status) { dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); return; } /* from generic_write_bulk_callback */ schedule_work(&port->work);} /* klsi_105_write_bulk_completion_callback *//* return number of characters currently in the writing process */static int klsi_105_chars_in_buffer (struct usb_serial_port *port){ int chars = 0; int i; unsigned long flags; struct klsi_105_private *priv = usb_get_serial_port_data(port); spin_lock_irqsave (&priv->lock, flags); for (i = 0; i < NUM_URBS; ++i) { if (priv->write_urb_pool[i]->status == -EINPROGRESS) { chars += URB_TRANSFER_BUFFER_SIZE; } } spin_unlock_irqrestore (&priv->lock, flags); dbg("%s - returns %d", __FUNCTION__, chars); return (chars);}static int klsi_105_write_room (struct usb_serial_port *port){ unsigned long flags; int i; int room = 0; struct klsi_105_private *priv = usb_get_serial_port_data(port); spin_lock_irqsave (&priv->lock, flags); for (i = 0; i < NUM_URBS; ++i) { if (priv->write_urb_pool[i]->status != -EINPROGRESS) { room += URB_TRANSFER_BUFFER_SIZE; } } spin_unlock_irqrestore (&priv->lock, flags); dbg("%s - returns %d", __FUNCTION__, room); return (room);}static void klsi_105_read_bulk_callback (struct urb *urb, struct pt_regs *regs){ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct klsi_105_private *priv = usb_get_serial_port_data(port); struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; int rc; dbg("%s - port %d", __FUNCTION__, port->number); /* The urb might have been killed. */ if (urb->status) { dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); return; } /* The data received is again preceded by a length double-byte in LSB- * first order (see klsi_105_write() ) */ if (urb->actual_length == 0) { /* empty urbs seem to happen, we ignore them */ /* dbg("%s - emtpy URB", __FUNCTION__); */ ; } else if (urb->actual_length <= 2) { dbg("%s - size %d URB not understood", __FUNCTION__, urb->actual_length); usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); } else { int i; int bytes_sent = ((__u8 *) data)[0] + ((unsigned int) ((__u8 *) data)[1] << 8); tty = port->tty; /* we should immediately resubmit the URB, before attempting * to pass the data on to the tty layer. But that needs locking * against re-entry an then mixed-up data because of * intermixed tty_flip_buffer_push()s * FIXME */ usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); if (bytes_sent + 2 > urb->actual_length) { dbg("%s - trying to read more data than available" " (%d vs. %d)", __FUNCTION__, bytes_sent+2, urb->actual_length); /* cap at implied limit */ bytes_sent = urb->actual_length - 2; } for (i = 2; i < 2+bytes_sent; i++) { /* if we insert more than TTY_FLIPBUF_SIZE characters, * we drop them. */ if(tty->flip.count >= TTY_FLIPBUF_SIZE) { tty_flip_buffer_push(tty); } /* this doesn't actually push the data through unless * tty->low_latency is set */ tty_insert_flip_char(tty, ((__u8*) data)[i], 0); } tty_flip_buffer_push(tty); /* again lockless, but debug info only */ priv->bytes_in += bytes_sent; } /* Continue trying to always read */ usb_fill_bulk_urb(port->read_urb, port->serial->dev, usb_rcvbulkpipe(port->serial->dev, port->bulk_in_endpointAddress), port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, klsi_105_read_bulk_callback, port); rc = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (rc) err("%s - failed resubmitting read urb, error %d", __FUNCTION__, rc);} /* klsi_105_read_bulk_callback */static void klsi_105_set_termios (struct usb_serial_port *port, struct termios *old_termios){ struct klsi_105_private *priv = usb_get_serial_port_data(port); unsigned int iflag = port->tty->termios->c_iflag; unsigned int old_iflag = old_termios->c_iflag; unsigned int cflag = port->tty->termios->c_cflag; unsigned int old_cflag = old_termios->c_cflag; struct klsi_105_port_settings cfg; unsigned long flags; /* lock while we are modifying the settings */ spin_lock_irqsave (&priv->lock, flags); /* * Update baud rate */ if( (cflag & CBAUD) != (old_cflag & CBAUD) ) { /* reassert DTR and (maybe) RTS on transition from B0 */ if( (old_cflag & CBAUD) == B0 ) { dbg("%s: baud was B0", __FUNCTION__);#if 0 priv->control_state |= TIOCM_DTR; /* don't set RTS if using hardware flow control */ if (!(old_cflag & CRTSCTS)) { priv->control_state |= TIOCM_RTS; } mct_u232_set_modem_ctrl(serial, priv->control_state);#endif } switch(cflag & CBAUD) { case B0: /* handled below */ break; case B1200: priv->cfg.baudrate = kl5kusb105a_sio_b1200; break; case B2400: priv->cfg.baudrate = kl5kusb105a_sio_b2400; break; case B4800: priv->cfg.baudrate = kl5kusb105a_sio_b4800; break; case B9600: priv->cfg.baudrate = kl5kusb105a_sio_b9600; break; case B19200: priv->cfg.baudrate = kl5kusb105a_sio_b19200; break; case B38400: priv->cfg.baudrate = kl5kusb105a_sio_b38400; break; case B57600: priv->cfg.baudrate = kl5kusb105a_sio_b57600; break; case B115200: priv->cfg.baudrate = kl5kusb105a_sio_b115200; break; default: err("KLSI USB->Serial converter:" " unsupported baudrate request, using default" " of 9600"); priv->cfg.baudrate = kl5kusb105a_sio_b9600; break; } if ((cflag & CBAUD) == B0 ) { dbg("%s: baud is B0", __FUNCTION__); /* Drop RTS and DTR */ /* maybe this should be simulated by sending read * disable and read enable messages? */ ;#if 0 priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS); mct_u232_set_modem_ctrl(serial, priv->control_state);#endif } } if ((cflag & CSIZE) != (old_cflag & CSIZE)) { /* set the number of data bits */ switch (cflag & CSIZE) { case CS5: dbg("%s - 5 bits/byte not supported", __FUNCTION__); spin_unlock_irqrestore (&priv->lock, flags); return ; case CS6: dbg("%s - 6 bits/byte not supported", __FUNCTION__); spin_unlock_irqrestore (&priv->lock, flags); return ; case CS7: priv->cfg.databits = kl5kusb105a_dtb_7; break; case CS8: priv->cfg.databits = kl5kusb105a_dtb_8; break; default: err("CSIZE was not CS5-CS8, using default of 8"); priv->cfg.databits = kl5kusb105a_dtb_8; break; } } /* * Update line control register (LCR) */ if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD)) || (cflag & CSTOPB) != (old_cflag & CSTOPB) ) { #if 0 priv->last_lcr = 0; /* set the parity */ if (cflag & PARENB) priv->last_lcr |= (cflag & PARODD) ? MCT_U232_PARITY_ODD : MCT_U232_PARITY_EVEN; else priv->last_lcr |= MCT_U232_PARITY_NONE; /* set the number of stop bits */ priv->last_lcr |= (cflag & CSTOPB) ? MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1; mct_u232_set_line_ctrl(serial, priv->last_lcr);#endif ; } /* * Set flow control: well, I do not really now how to handle DTR/RTS. * Just do what we have seen with SniffUSB on Win98. */ if( (iflag & IXOFF) != (old_iflag & IXOFF) || (iflag & IXON) != (old_iflag & IXON) || (cflag & CRTSCTS) != (old_cflag & CRTSCTS) ) { /* Drop DTR/RTS if no flow control otherwise assert */#if 0 if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS) ) priv->control_state |= TIOCM_DTR | TIOCM_RTS; else priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS); mct_u232_set_modem_ctrl(serial, priv->control_state);#endif ; } memcpy (&cfg, &priv->cfg, sizeof(cfg)); spin_unlock_irqrestore (&priv->lock, flags); /* now commit changes to device */ klsi_105_chg_port_settings(port, &cfg);} /* klsi_105_set_termios */#if 0static void mct_u232_break_ctl( struct usb_serial_port *port, int break_state ){ struct usb_serial *serial = port->serial; struct mct_u232_private *priv = (struct mct_u232_private *)port->private; unsigned char lcr = priv->last_lcr; dbg("%sstate=%d", __FUNCTION__, break_state); if (break_state) lcr |= MCT_U232_SET_BREAK; mct_u232_set_line_ctrl(serial, lcr);} /* mct_u232_break_ctl */#endifstatic int klsi_105_tiocmget (struct usb_serial_port *port, struct file *file){ struct klsi_105_private *priv = usb_get_serial_port_data(port); unsigned long flags; int rc; unsigned long line_state; dbg("%s - request, just guessing", __FUNCTION__); rc = klsi_105_get_line_state(port, &line_state); if (rc < 0) { err("Reading line control failed (error = %d)", rc); /* better return value? EAGAIN? */ return rc; } spin_lock_irqsave (&priv->lock, flags); priv->line_state = line_state; spin_unlock_irqrestore (&priv->lock, flags); dbg("%s - read line state 0x%lx", __FUNCTION__, line_state); return (int)line_state;}static int klsi_105_tiocmset (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear){ int retval = -EINVAL; dbg("%s", __FUNCTION__);/* if this ever gets implemented, it should be done something like this: struct usb_serial *serial = port->serial; struct klsi_105_private *priv = usb_get_serial_port_data(port); unsigned long flags; int control; spin_lock_irqsave (&priv->lock, flags); if (set & TIOCM_RTS) priv->control_state |= TIOCM_RTS; if (set & TIOCM_DTR) priv->control_state |= TIOCM_DTR; if (clear & TIOCM_RTS) priv->control_state &= ~TIOCM_RTS; if (clear & TIOCM_DTR) priv->control_state &= ~TIOCM_DTR; control = priv->control_state; spin_unlock_irqrestore (&priv->lock, flags); retval = mct_u232_set_modem_ctrl(serial, control);*/ return retval;} static int klsi_105_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg){ struct klsi_105_private *priv = usb_get_serial_port_data(port); void __user *user_arg = (void __user *)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 */ dbg("%s - TIOCMIWAIT not handled", __FUNCTION__); return -ENOIOCTLCMD; case TIOCGICOUNT: /* return count of modemline transitions */ /* TODO */ dbg("%s - TIOCGICOUNT not handled", __FUNCTION__); return -ENOIOCTLCMD; case TCGETS: /* return current info to caller */ dbg("%s - TCGETS data faked/incomplete", __FUNCTION__); if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct termios))) return -EFAULT; if (kernel_termios_to_user_termios((struct termios __user *)arg, &priv->termios)) return -EFAULT; return 0; case TCSETS: /* set port termios to the one given by the user */ dbg("%s - TCSETS not handled", __FUNCTION__); if (!access_ok(VERIFY_READ, user_arg, sizeof(struct termios))) return -EFAULT; if (user_termios_to_kernel_termios(&priv->termios, (struct termios __user *)arg)) return -EFAULT; klsi_105_set_termios(port, &priv->termios); return 0; case TCSETSW: { /* set port termios and try to wait for completion of last * write operation */ /* We guess here. If there are not too many write urbs * outstanding, we lie. */ /* what is the right way to wait here? schedule() ? */ /* while (klsi_105_chars_in_buffer(port) > (NUM_URBS / 4 ) * URB_TRANSFER_BUFFER_SIZE) schedule(); */ return -ENOIOCTLCMD; } default: dbg("%s: arg not supported - 0x%04x", __FUNCTION__,cmd); return(-ENOIOCTLCMD); break; } return 0;} /* klsi_105_ioctl */static void klsi_105_throttle (struct usb_serial_port *port){ dbg("%s - port %d", __FUNCTION__, port->number); usb_kill_urb(port->read_urb);}static void klsi_105_unthrottle (struct usb_serial_port *port){ int result; dbg("%s - port %d", __FUNCTION__, port->number); port->read_urb->dev = port->serial->dev; result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) err("%s - failed submitting read urb, error %d", __FUNCTION__, result);}static int __init klsi_105_init (void){ int retval; retval = usb_serial_register(&kl5kusb105d_device); if (retval) goto failed_usb_serial_register; retval = usb_register(&kl5kusb105d_driver); if (retval) goto failed_usb_register; info(DRIVER_DESC " " DRIVER_VERSION); return 0;failed_usb_register: usb_serial_deregister(&kl5kusb105d_device);failed_usb_serial_register: return retval;}static void __exit klsi_105_exit (void){ usb_deregister (&kl5kusb105d_driver); usb_serial_deregister (&kl5kusb105d_device);}module_init (klsi_105_init);module_exit (klsi_105_exit);MODULE_AUTHOR( DRIVER_AUTHOR );MODULE_DESCRIPTION( DRIVER_DESC );MODULE_LICENSE("GPL"); module_param(debug, bool, S_IRUGO | S_IWUSR);MODULE_PARM_DESC(debug, "enable extensive debugging messages");/* vim: set sts=8 ts=8 sw=8: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -