mct_u232.c
来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 917 行 · 第 1/2 页
C
917 行
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"); 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");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_unlink_urb (port->write_urb); usb_unlink_urb (port->read_urb); usb_unlink_urb (port->interrupt_in_urb); }} /* mct_u232_close */#ifdef FIX_WRITE_RETURN_CODE_PROBLEM/* The generic routines work fine otherwise */static int mct_u232_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count){ struct usb_serial *serial = port->serial; int result, bytes_sent, size; dbg("%s - port %d", __FUNCTION__, port->number); if (count == 0) { dbg("%s - write request of 0 bytes", __FUNCTION__); return (0); } /* only do something if we have a bulk out endpoint */ if (!serial->num_bulk_out) return(0); /* another write is still pending? */ if (port->write_urb->status == -EINPROGRESS) { dbg("%s - already writing", __FUNCTION__); return (0); } bytes_sent = 0; while (count > 0) { size = (count > port->bulk_out_size) ? port->bulk_out_size : count; usb_serial_debug_data(debug, &port->dev, __FUNCTION__, size, buf); if (from_user) { if (copy_from_user(port->write_urb->transfer_buffer, buf, size)) { return -EFAULT; } } else { memcpy (port->write_urb->transfer_buffer, buf, size); } /* set up our urb */ usb_fill_bulk_urb(port->write_urb, serial->dev, usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress), port->write_urb->transfer_buffer, size, ((serial->type->write_bulk_callback) ? serial->type->write_bulk_callback : mct_u232_write_bulk_callback), port); /* send the data out the bulk port */ result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) { err("%s - failed submitting write urb, error %d", __FUNCTION__, result); return result; } bytes_sent += size; if (write_blocking) interruptible_sleep_on(&port->write_wait); else break; buf += size; count -= size; } return bytes_sent;} /* mct_u232_write */static void mct_u232_write_bulk_callback (struct urb *urb, struct pt_regs *regs){ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct usb_serial *serial = port->serial; struct tty_struct *tty = port->tty; dbg("%s - port %d", __FUNCTION__, port->number); if (!serial) { dbg("%s - bad serial pointer, exiting", __FUNCTION__); return; } if (urb->status) { dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); return; } if (write_blocking) { wake_up_interruptible(&port->write_wait); if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); wake_up_interruptible(&tty->write_wait); } else { /* from generic_write_bulk_callback */ schedule_work(&port->work); } return;} /* mct_u232_write_bulk_callback */#endifstatic 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; dbg("%s - port %d", __FUNCTION__, port->number); 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; } 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, control_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");#ifdef FIX_WRITE_RETURN_CODE_PROBLEMmodule_param(write_blocking, int, 0);MODULE_PARM_DESC(write_blocking, "The write function will block to write out all data");#endifmodule_param(debug, bool, S_IRUGO | S_IWUSR);MODULE_PARM_DESC(debug, "Debug enabled or not");
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?