From 2afd8287c6e2ac6c1affb46d009cfd866dffed77 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Sat, 15 May 2010 17:53:53 +0200 Subject: [PATCH] USB: belkin_sa: implement line status handling Use process_read_urb to implement line status handling. Compile-only tested. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/belkin_sa.c | 77 ++++++++++++++++++++++------------ 1 file changed, 51 insertions(+), 26 deletions(-) diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index c39673608c35..36df35295db2 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -3,6 +3,7 @@ * * Copyright (C) 2000 William Greathouse (wgreathouse@smva.com) * Copyright (C) 2000-2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2010 Johan Hovold (jhovold@gmail.com) * * This program is largely derived from work by the linux-usb group * and associated source files. Please see the usb/serial files for @@ -84,7 +85,7 @@ static int debug; /* * Version Information */ -#define DRIVER_VERSION "v1.2" +#define DRIVER_VERSION "v1.3" #define DRIVER_AUTHOR "William Greathouse " #define DRIVER_DESC "USB Belkin Serial converter driver" @@ -95,6 +96,7 @@ static int belkin_sa_open(struct tty_struct *tty, struct usb_serial_port *port); static void belkin_sa_close(struct usb_serial_port *port); static void belkin_sa_read_int_callback(struct urb *urb); +static void belkin_sa_process_read_urb(struct urb *urb); static void belkin_sa_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios * old); static void belkin_sa_break_ctl(struct tty_struct *tty, int break_state); @@ -135,7 +137,7 @@ static struct usb_serial_driver belkin_device = { .open = belkin_sa_open, .close = belkin_sa_close, .read_int_callback = belkin_sa_read_int_callback, - /* How we get the status info */ + .process_read_urb = belkin_sa_process_read_urb, .set_termios = belkin_sa_set_termios, .break_ctl = belkin_sa_break_ctl, .tiocmget = belkin_sa_tiocmget, @@ -289,31 +291,7 @@ static void belkin_sa_read_int_callback(struct urb *urb) else priv->control_state &= ~TIOCM_CD; - /* Now to report any errors */ priv->last_lsr = data[BELKIN_SA_LSR_INDEX]; -#if 0 - /* - * fill in the flip buffer here, but I do not know the relation - * to the current/next receive buffer or characters. I need - * to look in to this before committing any code. - */ - if (priv->last_lsr & BELKIN_SA_LSR_ERR) { - tty = tty_port_tty_get(&port->port); - /* Overrun Error */ - if (priv->last_lsr & BELKIN_SA_LSR_OE) { - } - /* Parity Error */ - if (priv->last_lsr & BELKIN_SA_LSR_PE) { - } - /* Framing Error */ - if (priv->last_lsr & BELKIN_SA_LSR_FE) { - } - /* Break Indicator */ - if (priv->last_lsr & BELKIN_SA_LSR_BI) { - } - tty_kref_put(tty); - } -#endif spin_unlock_irqrestore(&priv->lock, flags); exit: retval = usb_submit_urb(urb, GFP_ATOMIC); @@ -322,6 +300,53 @@ static void belkin_sa_read_int_callback(struct urb *urb) "result %d\n", __func__, retval); } +static void belkin_sa_process_read_urb(struct urb *urb) +{ + struct usb_serial_port *port = urb->context; + struct belkin_sa_private *priv = usb_get_serial_port_data(port); + struct tty_struct *tty; + unsigned char *data = urb->transfer_buffer; + unsigned long flags; + unsigned char status; + char tty_flag; + + /* Update line status */ + tty_flag = TTY_NORMAL; + + spin_lock_irqsave(&priv->lock, flags); + status = priv->last_lsr; + priv->last_lsr &= ~BELKIN_SA_LSR_ERR; + spin_unlock_irqrestore(&priv->lock, flags); + + if (!urb->actual_length) + return; + + tty = tty_port_tty_get(&port->port); + if (!tty) + return; + + if (status & BELKIN_SA_LSR_ERR) { + /* Break takes precedence over parity, which takes precedence + * over framing errors. */ + if (status & BELKIN_SA_LSR_BI) + tty_flag = TTY_BREAK; + else if (status & BELKIN_SA_LSR_PE) + tty_flag = TTY_PARITY; + else if (status & BELKIN_SA_LSR_FE) + tty_flag = TTY_FRAME; + dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag); + + /* Overrun is special, not associated with a char. */ + if (status & BELKIN_SA_LSR_OE) + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + } + + tty_insert_flip_string_fixed_flag(tty, data, tty_flag, + urb->actual_length); + tty_flip_buffer_push(tty); + tty_kref_put(tty); +} + static void belkin_sa_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) {