Commit 9e033bb9 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

[PATCH] USB: add error reporting functionality to the pl2303 driver.

parent 5fa6d320
/* /*
* Prolific PL2303 USB to serial adaptor driver * 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 * Original driver for 2.2.x by anonymous
* *
...@@ -111,6 +112,16 @@ static struct usb_driver pl2303_driver = { ...@@ -111,6 +112,16 @@ static struct usb_driver pl2303_driver = {
#define VENDOR_READ_REQUEST_TYPE 0xc0 #define VENDOR_READ_REQUEST_TYPE 0xc0
#define VENDOR_READ_REQUEST 0x01 #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 */ /* function prototypes for a PL2303 serial converter */
static int pl2303_open (struct usb_serial_port *port, struct file *filp); static int pl2303_open (struct usb_serial_port *port, struct file *filp);
static void pl2303_close (struct usb_serial_port *port, struct file *filp); static void pl2303_close (struct usb_serial_port *port, struct file *filp);
...@@ -158,6 +169,7 @@ static struct usb_serial_device_type pl2303_device = { ...@@ -158,6 +169,7 @@ static struct usb_serial_device_type pl2303_device = {
struct pl2303_private { struct pl2303_private {
spinlock_t lock; spinlock_t lock;
u8 line_control; u8 line_control;
u8 line_status;
u8 termios_initialized; u8 termios_initialized;
}; };
...@@ -227,6 +239,7 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol ...@@ -227,6 +239,7 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol
{ {
struct usb_serial *serial = port->serial; struct usb_serial *serial = port->serial;
struct pl2303_private *priv = usb_get_serial_port_data(port); struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
unsigned int cflag; unsigned int cflag;
unsigned char *buf; unsigned char *buf;
int baud; int baud;
...@@ -239,13 +252,13 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol ...@@ -239,13 +252,13 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol
return; return;
} }
spin_lock(&priv->lock); spin_lock_irqsave(&priv->lock, flags);
if (!priv->termios_initialized) { if (!priv->termios_initialized) {
*(port->tty->termios) = tty_std_termios; *(port->tty->termios) = tty_std_termios;
port->tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; port->tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
priv->termios_initialized = 1; priv->termios_initialized = 1;
} }
spin_unlock(&priv->lock); spin_unlock_irqrestore(&priv->lock, flags);
cflag = port->tty->termios->c_cflag; cflag = port->tty->termios->c_cflag;
/* check that they really want us to change something */ /* check that they really want us to change something */
...@@ -355,13 +368,13 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol ...@@ -355,13 +368,13 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol
if (cflag && CBAUD) { if (cflag && CBAUD) {
u8 control; u8 control;
spin_lock (&priv->lock); spin_lock_irqsave(&priv->lock, flags);
if ((cflag && CBAUD) == B0) if ((cflag && CBAUD) == B0)
priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
else else
priv->line_control |= (CONTROL_DTR | CONTROL_RTS); priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
control = priv->line_control; control = priv->line_control;
spin_unlock (&priv->lock); spin_unlock_irqrestore(&priv->lock, flags);
set_control_lines (serial->dev, control); set_control_lines (serial->dev, control);
} }
...@@ -450,6 +463,7 @@ static void pl2303_close (struct usb_serial_port *port, struct file *filp) ...@@ -450,6 +463,7 @@ static void pl2303_close (struct usb_serial_port *port, struct file *filp)
{ {
struct usb_serial *serial; struct usb_serial *serial;
struct pl2303_private *priv; struct pl2303_private *priv;
unsigned long flags;
unsigned int c_cflag; unsigned int c_cflag;
int result; int result;
...@@ -486,9 +500,9 @@ static void pl2303_close (struct usb_serial_port *port, struct file *filp) ...@@ -486,9 +500,9 @@ static void pl2303_close (struct usb_serial_port *port, struct file *filp)
if (c_cflag & HUPCL) { if (c_cflag & HUPCL) {
/* drop DTR and RTS */ /* drop DTR and RTS */
priv = usb_get_serial_port_data(port); priv = usb_get_serial_port_data(port);
spin_lock (&priv->lock); spin_lock_irqsave(&priv->lock, flags);
priv->line_control = 0; priv->line_control = 0;
spin_unlock (&priv->lock); spin_unlock_irqrestore (&priv->lock, flags);
set_control_lines (port->serial->dev, 0); set_control_lines (port->serial->dev, 0);
} }
} }
...@@ -499,9 +513,10 @@ static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file, ...@@ -499,9 +513,10 @@ static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file,
unsigned int set, unsigned int clear) unsigned int set, unsigned int clear)
{ {
struct pl2303_private *priv = usb_get_serial_port_data(port); struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
u8 control; u8 control;
spin_lock (&priv->lock); spin_lock_irqsave (&priv->lock, flags);
if (set & TIOCM_RTS) if (set & TIOCM_RTS)
priv->line_control |= CONTROL_RTS; priv->line_control |= CONTROL_RTS;
if (set & TIOCM_DTR) if (set & TIOCM_DTR)
...@@ -511,7 +526,7 @@ static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file, ...@@ -511,7 +526,7 @@ static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file,
if (clear & TIOCM_DTR) if (clear & TIOCM_DTR)
priv->line_control &= ~CONTROL_DTR; priv->line_control &= ~CONTROL_DTR;
control = priv->line_control; control = priv->line_control;
spin_unlock (&priv->lock); spin_unlock_irqrestore (&priv->lock, flags);
return set_control_lines (port->serial->dev, control); return set_control_lines (port->serial->dev, control);
} }
...@@ -519,14 +534,15 @@ static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file, ...@@ -519,14 +534,15 @@ static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file,
static int pl2303_tiocmget (struct usb_serial_port *port, struct file *file) static int pl2303_tiocmget (struct usb_serial_port *port, struct file *file)
{ {
struct pl2303_private *priv = usb_get_serial_port_data(port); struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
unsigned int mcr; unsigned int mcr;
unsigned int result; unsigned int result;
dbg("%s (%d)", __FUNCTION__, port->number); dbg("%s (%d)", __FUNCTION__, port->number);
spin_lock (&priv->lock); spin_lock_irqsave (&priv->lock, flags);
mcr = priv->line_control; mcr = priv->line_control;
spin_unlock (&priv->lock); spin_unlock_irqrestore (&priv->lock, flags);
result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0) result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0)
| ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0); | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0);
...@@ -588,9 +604,13 @@ static void pl2303_read_int_callback (struct urb *urb, struct pt_regs *regs) ...@@ -588,9 +604,13 @@ static void pl2303_read_int_callback (struct urb *urb, struct pt_regs *regs)
{ {
struct usb_serial_port *port = (struct usb_serial_port *) urb->context; struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); 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; int status;
dbg("%s (%d)", __FUNCTION__, port->number);
switch (urb->status) { switch (urb->status) {
case 0: case 0:
/* success */ /* success */
...@@ -612,8 +632,14 @@ static void pl2303_read_int_callback (struct urb *urb, struct pt_regs *regs) ...@@ -612,8 +632,14 @@ static void pl2303_read_int_callback (struct urb *urb, struct pt_regs *regs)
usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, urb->transfer_buffer); 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: exit:
status = usb_submit_urb (urb, GFP_ATOMIC); status = usb_submit_urb (urb, GFP_ATOMIC);
if (status) if (status)
...@@ -626,10 +652,14 @@ static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs) ...@@ -626,10 +652,14 @@ static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
{ {
struct usb_serial_port *port = (struct usb_serial_port *) urb->context; struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
struct pl2303_private *priv = usb_get_serial_port_data(port);
struct tty_struct *tty; struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer; unsigned char *data = urb->transfer_buffer;
unsigned long flags;
int i; int i;
int result; int result;
u8 status;
char tty_flag;
if (port_paranoia_check (port, __FUNCTION__)) if (port_paranoia_check (port, __FUNCTION__))
return; return;
...@@ -663,13 +693,34 @@ static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs) ...@@ -663,13 +693,34 @@ static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); 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; tty = port->tty;
if (tty && urb->actual_length) { 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) { for (i = 0; i < urb->actual_length; ++i) {
if (tty->flip.count >= TTY_FLIPBUF_SIZE) { if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
tty_flip_buffer_push(tty); 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); tty_flip_buffer_push (tty);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment