static void ch341_read_int_callback(struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *) urb->context; unsigned char *data = urb->transfer_buffer; unsigned int actual_length = urb->actual_length; int status; dbg("%s (%d)", __func__, port->number); switch (urb->status) { case 0: /* success */ break; case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ dbg("%s - urb shutting down with status: %d", __func__, urb->status); return; default: dbg("%s - nonzero urb status received: %d", __func__, urb->status); goto exit; } usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, urb->transfer_buffer); if (actual_length >= 4) { struct ch341_private *priv = usb_get_serial_port_data(port); unsigned long flags; u8 prev_line_status = priv->line_status; spin_lock_irqsave(&priv->lock, flags); priv->line_status = (~(data[2])) & CH341_BITS_MODEM_STAT; if ((data[1] & CH341_MULT_STAT)) priv->multi_status_change = 1; spin_unlock_irqrestore(&priv->lock, flags); if ((priv->line_status ^ prev_line_status) & CH341_BIT_DCD) { struct tty_struct *tty = tty_port_tty_get(&port->port); if (tty) usb_serial_handle_dcd_change(port, tty, priv->line_status & CH341_BIT_DCD); tty_kref_put(tty); } wake_up_interruptible(&priv->delta_msr_wait); } exit: status = usb_submit_urb(urb, GFP_ATOMIC); if (status) dev_err(&urb->dev->dev, "%s - usb_submit_urb failed with result %d\n", __func__, status); }
static void spcp8x5_process_read_urb(struct urb *urb) { struct usb_serial_port *port = urb->context; struct spcp8x5_private *priv = usb_get_serial_port_data(port); unsigned char *data = urb->transfer_buffer; unsigned long flags; u8 status; char tty_flag; /* get tty_flag from status */ tty_flag = TTY_NORMAL; spin_lock_irqsave(&priv->lock, flags); status = priv->line_status; priv->line_status &= ~UART_STATE_TRANSIENT_MASK; spin_unlock_irqrestore(&priv->lock, flags); /* wake up the wait for termios */ wake_up_interruptible(&port->delta_msr_wait); if (!urb->actual_length) return; if (status & UART_STATE_TRANSIENT_MASK) { /* 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; dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag); /* overrun is special, not associated with a char */ if (status & UART_OVERRUN_ERROR) tty_insert_flip_char(&port->port, 0, TTY_OVERRUN); if (status & UART_DCD) { struct tty_struct *tty = tty_port_tty_get(&port->port); if (tty) { usb_serial_handle_dcd_change(port, tty, priv->line_status & MSR_STATUS_LINE_DCD); tty_kref_put(tty); } } } tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag, urb->actual_length); tty_flip_buffer_push(&port->port); }
static void pl2303_update_line_status(struct usb_serial_port *port, unsigned char *data, unsigned int actual_length) { struct pl2303_private *priv = usb_get_serial_port_data(port); struct tty_struct *tty; unsigned long flags; u8 status_idx = UART_STATE; u8 length = UART_STATE + 1; u8 prev_line_status; u16 idv, idp; idv = le16_to_cpu(port->serial->dev->descriptor.idVendor); idp = le16_to_cpu(port->serial->dev->descriptor.idProduct); if (idv == SIEMENS_VENDOR_ID) { if (idp == SIEMENS_PRODUCT_ID_X65 || idp == SIEMENS_PRODUCT_ID_SX1 || idp == SIEMENS_PRODUCT_ID_X75) { length = 1; status_idx = 0; } } if (actual_length < length) return; /* Save off the uart status for others to look at */ spin_lock_irqsave(&priv->lock, flags); prev_line_status = priv->line_status; priv->line_status = data[status_idx]; spin_unlock_irqrestore(&priv->lock, flags); if (priv->line_status & UART_BREAK_ERROR) usb_serial_handle_break(port); wake_up_interruptible(&port->port.delta_msr_wait); tty = tty_port_tty_get(&port->port); if (!tty) return; if ((priv->line_status ^ prev_line_status) & UART_DCD) usb_serial_handle_dcd_change(port, tty, priv->line_status & UART_DCD); tty_kref_put(tty); }
static void ch341_update_line_status(struct usb_serial_port *port, unsigned char *data, size_t len) { struct ch341_private *priv = usb_get_serial_port_data(port); struct tty_struct *tty; unsigned long flags; u8 status; u8 delta; if (len < 4) return; status = ~data[2] & CH341_BITS_MODEM_STAT; spin_lock_irqsave(&priv->lock, flags); delta = status ^ priv->line_status; priv->line_status = status; spin_unlock_irqrestore(&priv->lock, flags); if (data[1] & CH341_MULT_STAT) dev_dbg(&port->dev, "%s - multiple status change\n", __func__); if (!delta) return; if (delta & CH341_BIT_CTS) port->icount.cts++; if (delta & CH341_BIT_DSR) port->icount.dsr++; if (delta & CH341_BIT_RI) port->icount.rng++; if (delta & CH341_BIT_DCD) { port->icount.dcd++; tty = tty_port_tty_get(&port->port); if (tty) { usb_serial_handle_dcd_change(port, tty, status & CH341_BIT_DCD); tty_kref_put(tty); } } wake_up_interruptible(&port->port.delta_msr_wait); }
/* bulk read call back function. check the status of the urb. if transfer * failed return. then update the status and the tty send data to tty subsys. * submit urb again. */ static void spcp8x5_read_bulk_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct spcp8x5_private *priv = usb_get_serial_port_data(port); struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; unsigned long flags; int result = urb->status; u8 status; char tty_flag; dev_dbg(&port->dev, "start, result = %d, urb->actual_length = %d\n,", result, urb->actual_length); /* check the urb status */ if (result) { if (result == -EPROTO) { /* spcp8x5 mysteriously fails with -EPROTO */ /* reschedule the read */ urb->dev = port->serial->dev; result = usb_submit_urb(urb , GFP_ATOMIC); if (result) dev_dbg(&port->dev, "failed submitting read urb %d\n", result); return; } dev_dbg(&port->dev, "unable to handle the error, exiting.\n"); return; } /* get tty_flag from status */ tty_flag = TTY_NORMAL; spin_lock_irqsave(&priv->lock, flags); status = priv->line_status; priv->line_status &= ~UART_STATE_TRANSIENT_MASK; spin_unlock_irqrestore(&priv->lock, flags); /* wake up the wait for termios */ wake_up_interruptible(&priv->delta_msr_wait); /* 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; dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag); tty = tty_port_tty_get(&port->port); 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); tty_insert_flip_string_fixed_flag(tty, data, tty_flag, urb->actual_length); tty_flip_buffer_push(tty); } if (status & UART_DCD) usb_serial_handle_dcd_change(port, tty, priv->line_status & MSR_STATUS_LINE_DCD); tty_kref_put(tty); /* Schedule the next read */ urb->dev = port->serial->dev; result = usb_submit_urb(urb , GFP_ATOMIC); if (result) dev_dbg(&port->dev, "failed submitting read urb %d\n", result); }