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 + -
显示快捷键?