⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ftdi_sio.c

📁 linux2.4.20下的针对三星公司的s3c2410的usb模块驱动代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		for (i = data_offset ; i < urb->actual_length ; ++i) {			/* have to make sure we don't overflow the buffer			  with tty_insert_flip_char's */			if(tty->flip.count >= TTY_FLIPBUF_SIZE) {				tty_flip_buffer_push(tty);			}			/* Note that the error flag is duplicated for 			   every character received since we don't know			   which character it applied to */			tty_insert_flip_char(tty, data[i], error_flag);		}	  	tty_flip_buffer_push(tty);	} #ifdef NOT_CORRECT_BUT_KEEPING_IT_FOR_NOW	/* if a parity error is detected you get status packets forever	   until a character is sent without a parity error.	   This doesn't work well since the application receives a never	   ending stream of bad data - even though new data hasn't been sent.	   Therefore I (bill) have taken this out.	   However - this might make sense for framing errors and so on 	   so I am leaving the code in for now.	*/      else {		if (error_flag != TTY_NORMAL){			dbg("error_flag is not normal");				/* In this case it is just status - if that is an error send a bad character */				if(tty->flip.count >= TTY_FLIPBUF_SIZE) {					tty_flip_buffer_push(tty);				}				tty_insert_flip_char(tty, 0xff, error_flag);				tty_flip_buffer_push(tty);		}	}#endif	/* Continue trying to always read  */	FILL_BULK_URB(port->read_urb, serial->dev, 		      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),		      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,		      ftdi_read_bulk_callback, port);	result = usb_submit_urb(port->read_urb);	if (result)		err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);	return;} /* ftdi_read_bulk_callback */static void ftdi_break_ctl( struct usb_serial_port *port, int break_state ){	struct usb_serial *serial = port->serial;	struct ftdi_private *priv = (struct ftdi_private *)port->private;	__u16 urb_value = 0; 	char buf[1];		/* break_state = -1 to turn on break, and 0 to turn off break */	/* see drivers/char/tty_io.c to see it used */	/* last_set_data_urb_value NEVER has the break bit set in it */	if (break_state) {		urb_value = priv->last_set_data_urb_value | FTDI_SIO_SET_BREAK;	} else {		urb_value = priv->last_set_data_urb_value; 	}		if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),			    FTDI_SIO_SET_DATA_REQUEST, 			    FTDI_SIO_SET_DATA_REQUEST_TYPE,			    urb_value , 0,			    buf, 0, WDR_TIMEOUT) < 0) {		err("%s FAILED to enable/disable break state (state was %d)", __FUNCTION__,break_state);	}	   	dbg("%s break state is %d - urb is %d", __FUNCTION__,break_state, urb_value);	}/* old_termios contains the original termios settings and tty->termios contains * the new setting to be used * WARNING: set_termios calls this with old_termios in kernel space */static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_termios){ /* ftdi_termios */	struct usb_serial *serial = port->serial;	unsigned int cflag = port->tty->termios->c_cflag;	struct ftdi_private *priv = (struct ftdi_private *)port->private;		__u16 urb_value; /* will hold the new flags */	char buf[1]; /* Perhaps I should dynamically alloc this? */			dbg("%s", __FUNCTION__);	/* FIXME -For this cut I don't care if the line is really changing or 	   not  - so just do the change regardless  - should be able to 	   compare old_termios and tty->termios */	/* NOTE These routines can get interrupted by 	   ftdi_sio_read_bulk_callback  - need to examine what this            means - don't see any problems yet */		/* Set number of data bits, parity, stop bits */		urb_value = 0;	urb_value |= (cflag & CSTOPB ? FTDI_SIO_SET_DATA_STOP_BITS_2 :		      FTDI_SIO_SET_DATA_STOP_BITS_1);	urb_value |= (cflag & PARENB ? 		      (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD : 		       FTDI_SIO_SET_DATA_PARITY_EVEN) :		      FTDI_SIO_SET_DATA_PARITY_NONE);	if (cflag & CSIZE) {		switch (cflag & CSIZE) {		case CS5: urb_value |= 5; dbg("Setting CS5"); break;		case CS6: urb_value |= 6; dbg("Setting CS6"); break;		case CS7: urb_value |= 7; dbg("Setting CS7"); break;		case CS8: urb_value |= 8; dbg("Setting CS8"); break;		default:			err("CSIZE was set but not CS5-CS8");		}	}	/* This is needed by the break command since it uses the same command - but is	 *  or'ed with this value  */	priv->last_set_data_urb_value = urb_value;		if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),			    FTDI_SIO_SET_DATA_REQUEST, 			    FTDI_SIO_SET_DATA_REQUEST_TYPE,			    urb_value , 0,			    buf, 0, 100) < 0) {		err("%s FAILED to set databits/stopbits/parity", __FUNCTION__);	}	   	/* Now do the baudrate */	if ((cflag & CBAUD) == B0 ) {		/* Disable flow control */		if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),				    FTDI_SIO_SET_FLOW_CTRL_REQUEST, 				    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,				    0, 0, 				    buf, 0, WDR_TIMEOUT) < 0) {			err("%s error from disable flowcontrol urb", __FUNCTION__);		}	    		/* Drop RTS and DTR */		if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0){			err("%s Error from DTR LOW urb", __FUNCTION__);		}		if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0){			err("%s Error from RTS LOW urb", __FUNCTION__);		}				} else {		/* set the baudrate determined before */		if (change_speed(port)) {			err("%s urb failed to set baurdrate", __FUNCTION__);		}	}	/* Set flow control */	/* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */	if (cflag & CRTSCTS) {		dbg("%s Setting to CRTSCTS flow control", __FUNCTION__);		if (usb_control_msg(serial->dev, 				    usb_sndctrlpipe(serial->dev, 0),				    FTDI_SIO_SET_FLOW_CTRL_REQUEST, 				    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,				    0 , FTDI_SIO_RTS_CTS_HS,				    buf, 0, WDR_TIMEOUT) < 0) {			err("urb failed to set to rts/cts flow control");		}					} else { 		/* CHECKME Assuming XON/XOFF handled by tty stack - not by device */		dbg("%s Turning off hardware flow control", __FUNCTION__);		if (usb_control_msg(serial->dev, 				    usb_sndctrlpipe(serial->dev, 0),				    FTDI_SIO_SET_FLOW_CTRL_REQUEST, 				    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,				    0, 0, 				    buf, 0, WDR_TIMEOUT) < 0) {			err("urb failed to clear flow control");		}							}	return;} /* ftdi_termios */static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg){	struct usb_serial *serial = port->serial;	struct ftdi_private *priv = (struct ftdi_private *)port->private;	__u16 urb_value=0; /* Will hold the new flags */	char buf[2];	int  ret, mask;		dbg("%s cmd 0x%04x", __FUNCTION__, cmd);	/* Based on code from acm.c and others */	switch (cmd) {	case TIOCMGET:		dbg("%s TIOCMGET", __FUNCTION__);		switch (priv->chip_type) {		case SIO:			/* Request the status from the device */			if ((ret = usb_control_msg(serial->dev, 						   usb_rcvctrlpipe(serial->dev, 0),						   FTDI_SIO_GET_MODEM_STATUS_REQUEST, 						   FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,						   0, 0, 						   buf, 1, WDR_TIMEOUT)) < 0 ) {				err("%s Could not get modem status of device - err: %d", __FUNCTION__,				    ret);				return(ret);			}			break;		case FT8U232AM:			/* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same			   format as the data returned from the in point */			if ((ret = usb_control_msg(serial->dev, 						   usb_rcvctrlpipe(serial->dev, 0),						   FTDI_SIO_GET_MODEM_STATUS_REQUEST, 						   FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,						   0, 0, 						   buf, 2, WDR_TIMEOUT)) < 0 ) {				err("%s Could not get modem status of device - err: %d", __FUNCTION__,				    ret);				return(ret);			}			break;		default:			return -EFAULT;			break;		}		return put_user((buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |				(buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) |				(buf[0]  & FTDI_SIO_RI_MASK  ? TIOCM_RI  : 0) |				(buf[0]  & FTDI_SIO_RLSD_MASK ? TIOCM_CD  : 0),				(unsigned long *) arg);		break;	case TIOCMSET: /* Turns on and off the lines as specified by the mask */		dbg("%s TIOCMSET", __FUNCTION__);		if (get_user(mask, (unsigned long *) arg))			return -EFAULT;		urb_value = ((mask & TIOCM_DTR) ? HIGH : LOW);		if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),urb_value) < 0){			err("Error from DTR set urb (TIOCMSET)");		}		urb_value = ((mask & TIOCM_RTS) ? HIGH : LOW);		if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),urb_value) < 0){			err("Error from RTS set urb (TIOCMSET)");		}			break;						case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */		dbg("%s TIOCMBIS", __FUNCTION__); 	        if (get_user(mask, (unsigned long *) arg))			return -EFAULT;  	        if (mask & TIOCM_DTR){			if ((ret = set_dtr(serial->dev, 					   usb_sndctrlpipe(serial->dev, 0),					   HIGH)) < 0) {				err("Urb to set DTR failed");				return(ret);			}		}		if (mask & TIOCM_RTS) {			if ((ret = set_rts(serial->dev, 					   usb_sndctrlpipe(serial->dev, 0),					   HIGH)) < 0){				err("Urb to set RTS failed");				return(ret);			}		}					break;	case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */		dbg("%s TIOCMBIC", __FUNCTION__); 	        if (get_user(mask, (unsigned long *) arg))			return -EFAULT;  	        if (mask & TIOCM_DTR){			if ((ret = set_dtr(serial->dev, 					   usb_sndctrlpipe(serial->dev, 0),					   LOW)) < 0){				err("Urb to unset DTR failed");				return(ret);			}		}			if (mask & TIOCM_RTS) {			if ((ret = set_rts(serial->dev, 					   usb_sndctrlpipe(serial->dev, 0),					   LOW)) < 0){				err("Urb to unset RTS failed");				return(ret);			}		}		break;		/*		 * I had originally implemented TCSET{A,S}{,F,W} and		 * TCGET{A,S} here separately, however when testing I		 * found that the higher layers actually do the termios		 * conversions themselves and pass the call onto		 * ftdi_sio_set_termios. 		 *		 */	case TIOCGSERIAL: /* gets serial port data */		return get_serial_info(port, (struct serial_struct *) arg);	case TIOCSSERIAL: /* sets serial port data */		return set_serial_info(port, (struct serial_struct *) arg);	/*	 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change	 * - mask passed in arg for lines of interest	 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)	 * Caller should use TIOCGICOUNT to see which one it was.	 *	 * This code is borrowed from linux/drivers/char/serial.c	 */	case TIOCMIWAIT:		while (priv != NULL) {			interruptible_sleep_on(&priv->delta_msr_wait);			/* see if a signal did it */			if (signal_pending(current))				return -ERESTARTSYS;			else {				char diff = priv->diff_status;				if (diff == 0) {					return -EIO; /* no change => error */				}				/* Consume all events */				priv->diff_status = 0;				/* Return 0 if caller wanted to know about these bits */				if ( ((arg & TIOCM_RNG) && (diff & FTDI_RS0_RI)) ||				     ((arg & TIOCM_DSR) && (diff & FTDI_RS0_DSR)) ||				     ((arg & TIOCM_CD)  && (diff & FTDI_RS0_RLSD)) ||				     ((arg & TIOCM_CTS) && (diff & FTDI_RS0_CTS)) ) {					return 0;				}				/*				 * Otherwise caller can't care less about what happened,				 * and so we continue to wait for more events.				 */			}		}		/* NOTREACHED */	default:	  /* This is not an error - turns out the higher layers will do 	   *  some ioctls itself (see comment above) 	   */		dbg("%s arg not supported - it was 0x%04x", __FUNCTION__,cmd);		return(-ENOIOCTLCMD);		break;	}	return 0;} /* ftdi_ioctl */static int __init ftdi_init (void){	dbg("%s", __FUNCTION__);	usb_serial_register (&ftdi_SIO_device);	usb_serial_register (&ftdi_8U232AM_device);	info(DRIVER_VERSION ":" DRIVER_DESC);	return 0;}static void __exit ftdi_exit (void){	dbg("%s", __FUNCTION__);	usb_serial_deregister (&ftdi_SIO_device);	usb_serial_deregister (&ftdi_8U232AM_device);}module_init(ftdi_init);module_exit(ftdi_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 + -