[PATCH] USB: add error reporting functionality to the pl2303 driver.
drivers/usb/serial/pl2303.c | 79 ++++++++++++++++++++++++++++++++++++--------
1 files changed, 65 insertions(+), 14 deletions(-)
diff -Nru a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
--- a/drivers/usb/serial/pl2303.c Thu Apr 24 16:19:46 2003
+++ b/drivers/usb/serial/pl2303.c Thu Apr 24 16:19:46 2003
@@ -1,7 +1,8 @@
/*
* Prolific PL2303 USB to serial adaptor driver
*
- * Copyright (C) 2001-2002 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001-2003 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2003 IBM Corp.
*
* Original driver for 2.2.x by anonymous
*
@@ -111,6 +112,16 @@
#define VENDOR_READ_REQUEST_TYPE 0xc0
#define VENDOR_READ_REQUEST 0x01
+#define UART_STATE 0x08
+#define UART_DCD 0x01
+#define UART_DSR 0x02
+#define UART_BREAK_ERROR 0x04
+#define UART_RING 0x08
+#define UART_FRAME_ERROR 0x10
+#define UART_PARITY_ERROR 0x20
+#define UART_OVERRUN_ERROR 0x40
+#define UART_CTS 0x80
+
/* function prototypes for a PL2303 serial converter */
static int pl2303_open (struct usb_serial_port *port, struct file *filp);
static void pl2303_close (struct usb_serial_port *port, struct file *filp);
@@ -158,6 +169,7 @@
struct pl2303_private {
spinlock_t lock;
u8 line_control;
+ u8 line_status;
u8 termios_initialized;
};
@@ -227,6 +239,7 @@
{
struct usb_serial *serial = port->serial;
struct pl2303_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
unsigned int cflag;
unsigned char *buf;
int baud;
@@ -239,13 +252,13 @@
return;
}
- spin_lock(&priv->lock);
+ 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;
priv->termios_initialized = 1;
}
- spin_unlock(&priv->lock);
+ spin_unlock_irqrestore(&priv->lock, flags);
cflag = port->tty->termios->c_cflag;
/* check that they really want us to change something */
@@ -355,13 +368,13 @@
if (cflag && CBAUD) {
u8 control;
- spin_lock (&priv->lock);
+ spin_lock_irqsave(&priv->lock, flags);
if ((cflag && CBAUD) == B0)
priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
else
priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
control = priv->line_control;
- spin_unlock (&priv->lock);
+ spin_unlock_irqrestore(&priv->lock, flags);
set_control_lines (serial->dev, control);
}
@@ -450,6 +463,7 @@
{
struct usb_serial *serial;
struct pl2303_private *priv;
+ unsigned long flags;
unsigned int c_cflag;
int result;
@@ -486,9 +500,9 @@
if (c_cflag & HUPCL) {
/* drop DTR and RTS */
priv = usb_get_serial_port_data(port);
- spin_lock (&priv->lock);
+ spin_lock_irqsave(&priv->lock, flags);
priv->line_control = 0;
- spin_unlock (&priv->lock);
+ spin_unlock_irqrestore (&priv->lock, flags);
set_control_lines (port->serial->dev, 0);
}
}
@@ -499,9 +513,10 @@
unsigned int set, unsigned int clear)
{
struct pl2303_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
u8 control;
- spin_lock (&priv->lock);
+ spin_lock_irqsave (&priv->lock, flags);
if (set & TIOCM_RTS)
priv->line_control |= CONTROL_RTS;
if (set & TIOCM_DTR)
@@ -511,7 +526,7 @@
if (clear & TIOCM_DTR)
priv->line_control &= ~CONTROL_DTR;
control = priv->line_control;
- spin_unlock (&priv->lock);
+ spin_unlock_irqrestore (&priv->lock, flags);
return set_control_lines (port->serial->dev, control);
}
@@ -519,14 +534,15 @@
static int pl2303_tiocmget (struct usb_serial_port *port, struct file *file)
{
struct pl2303_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
unsigned int mcr;
unsigned int result;
dbg("%s (%d)", __FUNCTION__, port->number);
- spin_lock (&priv->lock);
+ spin_lock_irqsave (&priv->lock, flags);
mcr = priv->line_control;
- spin_unlock (&priv->lock);
+ spin_unlock_irqrestore (&priv->lock, flags);
result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0)
| ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0);
@@ -588,9 +604,13 @@
{
struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
- //unsigned char *data = urb->transfer_buffer;
+ struct pl2303_private *priv = usb_get_serial_port_data(port);
+ unsigned char *data = urb->transfer_buffer;
+ unsigned long flags;
int status;
+ dbg("%s (%d)", __FUNCTION__, port->number);
+
switch (urb->status) {
case 0:
/* success */
@@ -612,8 +632,14 @@
usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
- //FIXME need to update state of terminal lines variable
+ if (urb->actual_length > UART_STATE)
+ goto exit;
+ /* 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);
+
exit:
status = usb_submit_urb (urb, GFP_ATOMIC);
if (status)
@@ -626,10 +652,14 @@
{
struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+ 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;
+ char tty_flag;
if (port_paranoia_check (port, __FUNCTION__))
return;
@@ -663,13 +693,34 @@
usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+ /* 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 */
+ if (status & UART_BREAK_ERROR )
+ tty_flag = TTY_BREAK;
+ else if (status & UART_PARITY_ERROR)
+ tty_flag = TTY_PARITY;
+ else if (status & UART_FRAME_ERROR)
+ tty_flag = TTY_FRAME;
+ dbg("%s - tty_flag = %d", __FUNCTION__, tty_flag);
+
tty = port->tty;
if (tty && urb->actual_length) {
+ /* overrun is special, not associated with a char */
+ if (status & UART_OVERRUN_ERROR)
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+
for (i = 0; i < urb->actual_length; ++i) {
if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
tty_flip_buffer_push(tty);
}
- tty_insert_flip_char (tty, data[i], 0);
+ tty_insert_flip_char (tty, data[i], tty_flag);
}
tty_flip_buffer_push (tty);
}
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/