patch-2.4.23 linux-2.4.23/drivers/usb/serial/pl2303.c

Next file: linux-2.4.23/drivers/usb/serial/pl2303.h
Previous file: linux-2.4.23/drivers/usb/serial/keyspan_usa90msg.h
Back to the patch index
Back to the overall index

diff -urN linux-2.4.22/drivers/usb/serial/pl2303.c linux-2.4.23/drivers/usb/serial/pl2303.c
@@ -59,7 +59,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.9"
+#define DRIVER_VERSION "v0.10"
 #define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"
 
 
@@ -76,6 +76,7 @@
 	{ USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
 	{ USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
 	{ USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
+	{ USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
 	{ }					/* Terminating entry */
 };
 
@@ -153,7 +154,8 @@
 	.shutdown =		pl2303_shutdown,
 };
 
-struct pl2303_private { 
+struct pl2303_private {
+	spinlock_t lock;
 	u8 line_control;
 	u8 line_status;
 	u8 termios_initialized;
@@ -170,7 +172,8 @@
 		if (!priv)
 			return -ENOMEM;
 		memset (priv, 0x00, sizeof (struct pl2303_private));
-		serial->port[i].private = priv;
+		spin_lock_init(&priv->lock);
+		usb_set_serial_port_data(&serial->port[i], priv);
 	}
 	return 0;
 }
@@ -223,25 +226,30 @@
 static void pl2303_set_termios (struct usb_serial_port *port, struct termios *old_termios)
 {
 	struct usb_serial *serial = port->serial;
-	struct pl2303_private *priv;
+	struct pl2303_private *priv = usb_get_serial_port_data(port);
+	unsigned long flags;
 	unsigned int cflag;
 	unsigned char *buf;
 	int baud;
 	int i;
+	u8 control;
 
 	dbg("%s -  port %d, initialized = %d", __FUNCTION__, port->number, 
-	     ((struct pl2303_private *) port->private)->termios_initialized);
+	     priv->termios_initialized);
 
 	if ((!port->tty) || (!port->tty->termios)) {
 		dbg("%s - no tty structures", __FUNCTION__);
 		return;
 	}
 
-	if (!(((struct pl2303_private *) port->private)->termios_initialized)) {
+	spin_lock_irqsave(&priv->lock, flags);
+	if (!priv->termios_initialized) {
 		*(port->tty->termios) = tty_std_termios;
 		port->tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-		((struct pl2303_private *) port->private)->termios_initialized = 1;
+		priv->termios_initialized = 1;
 	}
+	spin_unlock_irqrestore(&priv->lock, flags);
+
 	cflag = port->tty->termios->c_cflag;
 	/* check that they really want us to change something */
 	if (old_termios) {
@@ -266,12 +274,6 @@
 	     buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
 
 
-	i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
-			     VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
-			     0, 1, NULL, 0, 100);
-
-	dbg ("0x40:1:0:1  %d", i);
-
 	if (cflag & CSIZE) {
 		switch (cflag & CSIZE) {
 			case CS5:	buf[6] = 5;	break;
@@ -347,13 +349,19 @@
 			     0, 0, buf, 7, 100);
 	dbg ("0x21:0x20:0:0  %d", i);
 
-	if (cflag && CBAUD) {
-		priv = port->private;
-		if ((cflag && CBAUD) == B0)
-			priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
-		else
-			priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
-		set_control_lines (serial->dev, priv->line_control);
+	/* change control lines if we are switching to or from B0 */
+	spin_lock_irqsave(&priv->lock, flags);
+	control = priv->line_control;
+	if ((cflag & CBAUD) == B0)
+		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
+	else
+		priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
+	if (control != priv->line_control) {
+		control = priv->line_control;
+		spin_unlock_irqrestore(&priv->lock, flags);
+		set_control_lines(serial->dev, control);
+	} else {
+		spin_unlock_irqrestore(&priv->lock, flags);
 	}
 	
 	buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
@@ -387,6 +395,9 @@
 		
 	dbg("%s -  port %d", __FUNCTION__, port->number);
 
+	usb_clear_halt(serial->dev, port->write_urb->pipe);
+	usb_clear_halt(serial->dev, port->read_urb->pipe);
+
 #define FISH(a,b,c,d)								\
 	result=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0),	\
 			       b, a, c, d, buf, 1, 100);			\
@@ -405,9 +416,6 @@
 	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 1);
 	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
 	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
-	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0, 1);
-	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 1, 0xc0);
-	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 4);
 
 	/* Setup termios */
 	if (port->tty) {
@@ -441,6 +449,7 @@
 {
 	struct usb_serial *serial;
 	struct pl2303_private *priv;
+	unsigned long flags;
 	unsigned int c_cflag;
 	int result;
 
@@ -457,10 +466,11 @@
 			c_cflag = port->tty->termios->c_cflag;
 			if (c_cflag & HUPCL) {
 				/* drop DTR and RTS */
-				priv = port->private;
+				priv = usb_get_serial_port_data(port);
+				spin_lock_irqsave(&priv->lock, flags);
 				priv->line_control = 0;
-				set_control_lines (port->serial->dev,
-						   priv->line_control);
+				spin_unlock_irqrestore (&priv->lock, flags);
+				set_control_lines (port->serial->dev, 0);
 			}
 		}
 
@@ -488,12 +498,15 @@
 
 static int set_modem_info (struct usb_serial_port *port, unsigned int cmd, unsigned int *value)
 {
-	struct pl2303_private *priv = port->private;
+	struct pl2303_private *priv = usb_get_serial_port_data(port);
+	unsigned long flags;
 	unsigned int arg;
+	u8 control;
 
 	if (copy_from_user(&arg, value, sizeof(int)))
 		return -EFAULT;
 
+	spin_lock_irqsave (&priv->lock, flags);
 	switch (cmd) {
 		case TIOCMBIS:
 			if (arg & TIOCM_RTS)
@@ -517,21 +530,31 @@
 			priv->line_control |= ((arg & TIOCM_DTR) ? CONTROL_DTR : 0);
 			break;
 	}
+	control = priv->line_control;
+	spin_unlock_irqrestore (&priv->lock, flags);
 
-	return set_control_lines (port->serial->dev, priv->line_control);
+	return set_control_lines (port->serial->dev, control);
 }
 
 static int get_modem_info (struct usb_serial_port *port, unsigned int *value)
 {
-	struct pl2303_private *priv = port->private;
-	unsigned int mcr = priv->line_control;
-	unsigned int status = priv->line_status;
+	struct pl2303_private *priv = usb_get_serial_port_data(port);
+	unsigned long flags;
+	unsigned int mcr;
+	unsigned int status;
 	unsigned int result;
 
+	spin_lock_irqsave (&priv->lock, flags);
+	mcr = priv->line_control;
+	status = priv->line_status;
+	spin_unlock_irqrestore (&priv->lock, flags);
+
 	result = ((mcr & CONTROL_DTR)		? TIOCM_DTR : 0)
 		  | ((mcr & CONTROL_RTS)	? TIOCM_RTS : 0)
 		  | ((status & UART_CTS)	? TIOCM_CTS : 0)
-		  | ((status & UART_DSR)	? TIOCM_DSR : 0);
+		  | ((status & UART_DSR)	? TIOCM_DSR : 0)
+		  | ((status & UART_RING)	? TIOCM_RI  : 0)
+		  | ((status & UART_DCD)	? TIOCM_CD  : 0);
 
 	dbg("%s - result = %x", __FUNCTION__, result);
 
@@ -564,7 +587,6 @@
 	return -ENOIOCTLCMD;
 }
 
-
 static void pl2303_break_ctl (struct usb_serial_port *port, int break_state)
 {
 	struct usb_serial *serial = port->serial;
@@ -593,8 +615,10 @@
 
 	dbg("%s", __FUNCTION__);
 
-	for (i = 0; i < serial->num_ports; ++i)
-		kfree (serial->port[i].private);
+	for (i = 0; i < serial->num_ports; ++i) {
+		kfree (usb_get_serial_port_data(&serial->port[i]));
+		usb_set_serial_port_data(&serial->port[i], NULL);
+	}		
 }
 
 
@@ -602,27 +626,42 @@
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
 	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
-	struct pl2303_private *priv = port->private;
+	struct pl2303_private *priv = usb_get_serial_port_data(port);
 	unsigned char *data = urb->transfer_buffer;
+	unsigned long flags;
+
+	dbg("%s (%d)", __FUNCTION__, port->number);
 
 	/* ints auto restart... */
 
-	if (!serial) {
+	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);
 		return;
 	}
 
-	if (urb->status) {
-		urb->status = 0;
+	if (!serial) {
 		return;
 	}
 
 	usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
 
-	if (urb->actual_length > UART_STATE)
+	if (urb->actual_length < UART_STATE)
 		return;
 
 	/* Save off the uart status for others to look at */
+	spin_lock_irqsave(&priv->lock, flags);
 	priv->line_status = data[UART_STATE];
+	spin_unlock_irqrestore(&priv->lock, flags);
 
 	return;
 }
@@ -632,9 +671,10 @@
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
 	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
-	struct pl2303_private *priv = port->private;
+	struct pl2303_private *priv = usb_get_serial_port_data(port);
 	struct tty_struct *tty;
 	unsigned char *data = urb->transfer_buffer;
+	unsigned long flags;
 	int i;
 	int result;
 	u8 status;
@@ -674,7 +714,10 @@
 
 	/* get tty_flag from status */
 	tty_flag = TTY_NORMAL;
+
+	spin_lock_irqsave(&priv->lock, flags);
 	status = priv->line_status;
+	spin_unlock_irqrestore(&priv->lock, flags);
 
 	/* break takes precedence over parity, */
 	/* which takes precedence over framing errors */
@@ -749,9 +792,14 @@
 
 static int __init pl2303_init (void)
 {
-	usb_serial_register (&pl2303_device);
+	int retval;
+	retval = usb_serial_register(&pl2303_device);
+	if (retval)
+		goto failed_usb_serial_register;
 	info(DRIVER_DESC " " DRIVER_VERSION);
 	return 0;
+failed_usb_serial_register:
+	return retval;
 }
 
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)