diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index d73618475664..9256588624bb 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -613,7 +613,8 @@ static void gs_write_complete(struct usb_ep *ep, struct usb_request *req) /* FALL THROUGH */ case 0: /* normal completion */ - gs_start_tx(port); + if (port->port_usb) + gs_start_tx(port); break; case -ESHUTDOWN: @@ -1012,6 +1013,78 @@ static int gs_break_ctl(struct tty_struct *tty, int duration) return status; } +static int gs_tiocmget(struct tty_struct *tty) +{ + struct gs_port *port = tty->driver_data; + struct gserial *gser; + unsigned int result = 0; + + spin_lock_irq(&port->port_lock); + gser = port->port_usb; + if (!gser) { + result = -ENODEV; + goto fail; + } + + if (gser->get_dtr) + result |= (gser->get_dtr(gser) ? TIOCM_DTR : 0); + + if (gser->get_rts) + result |= (gser->get_rts(gser) ? TIOCM_RTS : 0); + + if (gser->serial_state & TIOCM_CD) + result |= TIOCM_CD; + + if (gser->serial_state & TIOCM_RI) + result |= TIOCM_RI; +fail: + spin_unlock_irq(&port->port_lock); + return result; +} + +static int gs_tiocmset(struct tty_struct *tty, + unsigned int set, unsigned int clear) +{ + struct gs_port *port = tty->driver_data; + struct gserial *gser; + int status = 0; + + spin_lock_irq(&port->port_lock); + gser = port->port_usb; + if (!gser) { + status = -ENODEV; + goto fail; + } + + if (set & TIOCM_RI) { + if (gser->send_ring_indicator) { + gser->serial_state |= TIOCM_RI; + status = gser->send_ring_indicator(gser, 1); + } + } + if (clear & TIOCM_RI) { + if (gser->send_ring_indicator) { + gser->serial_state &= ~TIOCM_RI; + status = gser->send_ring_indicator(gser, 0); + } + } + if (set & TIOCM_CD) { + if (gser->send_carrier_detect) { + gser->serial_state |= TIOCM_CD; + status = gser->send_carrier_detect(gser, 1); + } + } + if (clear & TIOCM_CD) { + if (gser->send_carrier_detect) { + gser->serial_state &= ~TIOCM_CD; + status = gser->send_carrier_detect(gser, 0); + } + } +fail: + spin_unlock_irq(&port->port_lock); + return status; +} + static const struct tty_operations gs_tty_ops = { .open = gs_open, .close = gs_close, @@ -1022,6 +1095,8 @@ static const struct tty_operations gs_tty_ops = { .chars_in_buffer = gs_chars_in_buffer, .unthrottle = gs_unthrottle, .break_ctl = gs_break_ctl, + .tiocmget = gs_tiocmget, + .tiocmset = gs_tiocmset, }; /*-------------------------------------------------------------------------*/ @@ -1301,7 +1376,8 @@ static int userial_init(void) gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; gs_tty_driver->subtype = SERIAL_TYPE_NORMAL; - gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; + gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV + | TTY_DRIVER_RESET_TERMIOS; gs_tty_driver->init_termios = tty_std_termios; /* 9600-8-N-1 ... matches defaults expected by "usbser.sys" on diff --git a/drivers/usb/gadget/function/u_serial.h b/drivers/usb/gadget/function/u_serial.h index c20210c0babd..a0e100a5e635 100644 --- a/drivers/usb/gadget/function/u_serial.h +++ b/drivers/usb/gadget/function/u_serial.h @@ -45,11 +45,18 @@ struct gserial { /* REVISIT avoid this CDC-ACM support harder ... */ struct usb_cdc_line_coding port_line_coding; /* 9600-8-N-1 etc */ + u16 serial_state; + + /* control signal callbacks*/ + unsigned int (*get_dtr)(struct gserial *p); + unsigned int (*get_rts)(struct gserial *p); /* notification callbacks */ void (*connect)(struct gserial *p); void (*disconnect)(struct gserial *p); int (*send_break)(struct gserial *p, int duration); + unsigned int (*send_carrier_detect)(struct gserial *p, unsigned int); + unsigned int (*send_ring_indicator)(struct gserial *p, unsigned int); }; /* utilities to allocate/free request and buffer */