This patch implement relative MCR/MSR function, such like tiocmget()/tiocmset()/dtr_rts(). The f81232_set_mctrl() replace set_control_lines() to do MCR control so we clean-up the set_control_lines() function. Signed-off-by: Peter Hung <hpeter+linux_kernel@xxxxxxxxx> --- drivers/usb/serial/f81232.c | 98 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 77 insertions(+), 21 deletions(-) diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c index 06d1eb0..e1cdf42 100644 --- a/drivers/usb/serial/f81232.c +++ b/drivers/usb/serial/f81232.c @@ -44,6 +44,7 @@ MODULE_DEVICE_TABLE(usb, id_table); #define INTERRUPT_ENABLE_REGISTER (0x01 + SERIAL_BASE_ADDRESS) #define FIFO_CONTROL_REGISTER (0x02 + SERIAL_BASE_ADDRESS) #define LINE_CONTROL_REGISTER (0x03 + SERIAL_BASE_ADDRESS) +#define MODEM_CONTROL_REGISTER (0x04 + SERIAL_BASE_ADDRESS) #define MODEM_STATUS_REGISTER (0x06 + SERIAL_BASE_ADDRESS) #define CONTROL_DTR 0x01 @@ -156,6 +157,50 @@ static void f81232_read_msr(struct usb_serial_port *port) wake_up_interruptible(&port->port.delta_msr_wait); } +static int f81232_set_mctrl(struct usb_serial_port *port, + unsigned int set, unsigned int clear) +{ + u8 urb_value; + int status; + unsigned long flags; + struct f81232_private *priv = usb_get_serial_port_data(port); + + if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) + return 0; /* no change */ + + /* 'set' takes precedence over 'clear' */ + clear &= ~set; + + /* force enable interrupt with OUT2 */ + urb_value = UART_MCR_OUT2 | priv->line_control; + + if (clear & TIOCM_DTR) + urb_value &= ~UART_MCR_DTR; + + if (clear & TIOCM_RTS) + urb_value &= ~UART_MCR_RTS; + + if (set & TIOCM_DTR) + urb_value |= UART_MCR_DTR; + + if (set & TIOCM_RTS) + urb_value |= UART_MCR_RTS; + + dev_dbg(&port->dev, "%s new:%02x old:%02x\n", __func__, + urb_value, priv->line_control); + + status = f81232_set_register(port, MODEM_CONTROL_REGISTER, urb_value); + if (status < 0) { + dev_err(&port->dev, "%s set MCR status < 0\n", __func__); + } else { + spin_lock_irqsave(&priv->lock, flags); + priv->line_control = urb_value; + spin_unlock_irqrestore(&priv->lock, flags); + } + + return status; +} + static void f81232_update_modem_status(struct usb_serial_port *port, unsigned char *data, unsigned int actual_length) @@ -267,12 +312,6 @@ static void f81232_process_read_urb(struct urb *urb) tty_flip_buffer_push(&port->port); } -static int set_control_lines(struct usb_device *dev, u8 value) -{ - /* FIXME - Stubbed out for now */ - return 0; -} - static void f81232_break_ctl(struct tty_struct *tty, int break_state) { /* FIXME - Stubbed out for now */ @@ -388,15 +427,41 @@ static void f81232_set_termios(struct tty_struct *tty, static int f81232_tiocmget(struct tty_struct *tty) { - /* FIXME - Stubbed out for now */ - return 0; + int r; + struct usb_serial_port *port = tty->driver_data; + struct f81232_private *port_priv = usb_get_serial_port_data(port); + unsigned long flags; + u8 mcr, msr; + + /* force get current MSR changed state */ + f81232_read_msr(port); + + spin_lock_irqsave(&port_priv->lock, flags); + mcr = port_priv->line_control; + msr = port_priv->modem_status; + spin_unlock_irqrestore(&port_priv->lock, flags); + + r = (mcr & UART_MCR_DTR ? TIOCM_DTR : 0) | + (mcr & UART_MCR_RTS ? TIOCM_RTS : 0) | + (msr & UART_MSR_CTS ? TIOCM_CTS : 0) | + (msr & UART_MSR_DCD ? TIOCM_CAR : 0) | + (msr & UART_MSR_RI ? TIOCM_RI : 0) | + (msr & UART_MSR_DSR ? TIOCM_DSR : 0); + + return r; } static int f81232_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { - /* FIXME - Stubbed out for now */ - return 0; + int status; + struct usb_serial_port *port = tty->driver_data; + + status = f81232_set_mctrl(port, set, clear); + if (status < 0) + return usb_translate_errors(status); + else + return 0; } static int f81232_open(struct tty_struct *tty, struct usb_serial_port *port) @@ -437,19 +502,10 @@ static void f81232_close(struct usb_serial_port *port) static void f81232_dtr_rts(struct usb_serial_port *port, int on) { - struct f81232_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - u8 control; - - spin_lock_irqsave(&priv->lock, flags); - /* Change DTR and RTS */ if (on) - priv->line_control |= (CONTROL_DTR | CONTROL_RTS); + f81232_set_mctrl(port, TIOCM_DTR | TIOCM_RTS, 0); else - priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); - control = priv->line_control; - spin_unlock_irqrestore(&priv->lock, flags); - set_control_lines(port->serial->dev, control); + f81232_set_mctrl(port, 0, TIOCM_DTR | TIOCM_RTS); } static int f81232_carrier_raised(struct usb_serial_port *port) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html