Re: [PATCH] More USB fixes for 2.5.68

From: Greg KH (greg@kroah.com)
Date: Thu Apr 24 2003 - 18:47:34 EST


ChangeSet 1.1165.2.19, 2003/04/24 14:54:09-07:00, greg@kroah.com

[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/



This archive was generated by hypermail 2b29 : Wed Apr 30 2003 - 22:00:19 EST