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
- Lines: 317
- Date:
2003-11-28 10:26:20.000000000 -0800
- Orig file:
linux-2.4.22/drivers/usb/serial/pl2303.c
- Orig date:
2003-08-25 04:44:42.000000000 -0700
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)