Commit 6ff58ae1 authored by Johan Hovold's avatar Johan Hovold
Browse files

USB: serial: return errors from break handling



Start propagating errors to user space when setting the break state
fails.

This will be used by follow-on changes to also report when a driver or
device does not support break control.

Tested-by: default avatarCorey Minyard <cminyard@mvista.com>
Signed-off-by: default avatarJohan Hovold <johan@kernel.org>
parent 9561de3a
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -433,10 +433,11 @@ static int ark3116_tiocmset(struct tty_struct *tty,
	return 0;
}

static void ark3116_break_ctl(struct tty_struct *tty, int break_state)
static int ark3116_break_ctl(struct tty_struct *tty, int break_state)
{
	struct usb_serial_port *port = tty->driver_data;
	struct ark3116_private *priv = usb_get_serial_port_data(port);
	int ret;

	/* LCR is also used for other things: protect access */
	mutex_lock(&priv->hw_lock);
@@ -446,9 +447,11 @@ static void ark3116_break_ctl(struct tty_struct *tty, int break_state)
	else
		priv->lcr &= ~UART_LCR_SBC;

	ark3116_write_reg(port->serial, UART_LCR, priv->lcr);
	ret = ark3116_write_reg(port->serial, UART_LCR, priv->lcr);

	mutex_unlock(&priv->hw_lock);

	return ret;
}

static void ark3116_update_msr(struct usb_serial_port *port, __u8 msr)
+9 −3
Original line number Diff line number Diff line
@@ -46,7 +46,7 @@ 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,
				  const struct ktermios *old_termios);
static void belkin_sa_break_ctl(struct tty_struct *tty, int break_state);
static int belkin_sa_break_ctl(struct tty_struct *tty, int break_state);
static int  belkin_sa_tiocmget(struct tty_struct *tty);
static int  belkin_sa_tiocmset(struct tty_struct *tty,
					unsigned int set, unsigned int clear);
@@ -399,13 +399,19 @@ static void belkin_sa_set_termios(struct tty_struct *tty,
	spin_unlock_irqrestore(&priv->lock, flags);
}

static void belkin_sa_break_ctl(struct tty_struct *tty, int break_state)
static int belkin_sa_break_ctl(struct tty_struct *tty, int break_state)
{
	struct usb_serial_port *port = tty->driver_data;
	struct usb_serial *serial = port->serial;
	int ret;

	if (BSA_USB_CMD(BELKIN_SA_SET_BREAK_REQUEST, break_state ? 1 : 0) < 0)
	ret = BSA_USB_CMD(BELKIN_SA_SET_BREAK_REQUEST, break_state ? 1 : 0);
	if (ret < 0) {
		dev_err(&port->dev, "Set break_ctl %d\n", break_state);
		return ret;
	}

	return 0;
}

static int belkin_sa_tiocmget(struct tty_struct *tty)
+23 −14
Original line number Diff line number Diff line
@@ -562,12 +562,12 @@ static void ch341_set_termios(struct tty_struct *tty,
 * TCSBRKP. Due to how the simulation is implemented the duration can't be
 * controlled. The duration is always about (1s / 46bd * 9bit) = 196ms.
 */
static void ch341_simulate_break(struct tty_struct *tty, int break_state)
static int ch341_simulate_break(struct tty_struct *tty, int break_state)
{
	struct usb_serial_port *port = tty->driver_data;
	struct ch341_private *priv = usb_get_serial_port_data(port);
	unsigned long now, delay;
	int r;
	int r, r2;

	if (break_state != 0) {
		dev_dbg(&port->dev, "enter break state requested\n");
@@ -599,7 +599,7 @@ static void ch341_simulate_break(struct tty_struct *tty, int break_state)
		 */
		priv->break_end = jiffies + (11 * HZ / CH341_MIN_BPS);

		return;
		return 0;
	}

	dev_dbg(&port->dev, "leave break state requested\n");
@@ -615,17 +615,22 @@ static void ch341_simulate_break(struct tty_struct *tty, int break_state)
		schedule_timeout_interruptible(delay);
	}

	r = 0;
restore:
	/* Restore original baud rate */
	r = ch341_set_baudrate_lcr(port->serial->dev, priv, priv->baud_rate,
	r2 = ch341_set_baudrate_lcr(port->serial->dev, priv, priv->baud_rate,
			priv->lcr);
	if (r < 0)
	if (r2 < 0) {
		dev_err(&port->dev,
			"restoring original baud rate of %u failed: %d\n",
			priv->baud_rate, r);
			priv->baud_rate, r2);
		return r2;
	}

static void ch341_break_ctl(struct tty_struct *tty, int break_state)
	return r;
}

static int ch341_break_ctl(struct tty_struct *tty, int break_state)
{
	const uint16_t ch341_break_reg =
			((uint16_t) CH341_REG_LCR << 8) | CH341_REG_BREAK;
@@ -635,17 +640,17 @@ static void ch341_break_ctl(struct tty_struct *tty, int break_state)
	uint16_t reg_contents;
	uint8_t break_reg[2];

	if (priv->quirks & CH341_QUIRK_SIMULATE_BREAK) {
		ch341_simulate_break(tty, break_state);
		return;
	}
	if (priv->quirks & CH341_QUIRK_SIMULATE_BREAK)
		return ch341_simulate_break(tty, break_state);

	r = ch341_control_in(port->serial->dev, CH341_REQ_READ_REG,
			ch341_break_reg, 0, break_reg, 2);
	if (r) {
		dev_err(&port->dev, "%s - USB control read error (%d)\n",
				__func__, r);
		return;
		if (r > 0)
			r = -EIO;
		return r;
	}
	dev_dbg(&port->dev, "%s - initial ch341 break register contents - reg1: %x, reg2: %x\n",
		__func__, break_reg[0], break_reg[1]);
@@ -663,9 +668,13 @@ static void ch341_break_ctl(struct tty_struct *tty, int break_state)
	reg_contents = get_unaligned_le16(break_reg);
	r = ch341_control_out(port->serial->dev, CH341_REQ_WRITE_REG,
			ch341_break_reg, reg_contents);
	if (r < 0)
	if (r < 0) {
		dev_err(&port->dev, "%s - USB control write error (%d)\n",
				__func__, r);
		return r;
	}

	return 0;
}

static int ch341_tiocmset(struct tty_struct *tty,
+5 −3
Original line number Diff line number Diff line
@@ -39,7 +39,7 @@ static int cp210x_tiocmget(struct tty_struct *);
static int cp210x_tiocmset(struct tty_struct *, unsigned int, unsigned int);
static int cp210x_tiocmset_port(struct usb_serial_port *port,
		unsigned int, unsigned int);
static void cp210x_break_ctl(struct tty_struct *, int);
static int cp210x_break_ctl(struct tty_struct *, int);
static int cp210x_attach(struct usb_serial *);
static void cp210x_disconnect(struct usb_serial *);
static void cp210x_release(struct usb_serial *);
@@ -1434,7 +1434,7 @@ static int cp210x_tiocmget(struct tty_struct *tty)
	return result;
}

static void cp210x_break_ctl(struct tty_struct *tty, int break_state)
static int cp210x_break_ctl(struct tty_struct *tty, int break_state)
{
	struct usb_serial_port *port = tty->driver_data;
	u16 state;
@@ -1443,9 +1443,11 @@ static void cp210x_break_ctl(struct tty_struct *tty, int break_state)
		state = BREAK_OFF;
	else
		state = BREAK_ON;

	dev_dbg(&port->dev, "%s - turning break %s\n", __func__,
		state == BREAK_OFF ? "off" : "on");
	cp210x_write_u16_reg(port, CP210X_SET_BREAK, state);

	return cp210x_write_u16_reg(port, CP210X_SET_BREAK, state);
}

#ifdef CONFIG_GPIOLIB
+4 −3
Original line number Diff line number Diff line
@@ -217,7 +217,7 @@ static void digi_rx_unthrottle(struct tty_struct *tty);
static void digi_set_termios(struct tty_struct *tty,
			     struct usb_serial_port *port,
			     const struct ktermios *old_termios);
static void digi_break_ctl(struct tty_struct *tty, int break_state);
static int digi_break_ctl(struct tty_struct *tty, int break_state);
static int digi_tiocmget(struct tty_struct *tty);
static int digi_tiocmset(struct tty_struct *tty, unsigned int set,
		unsigned int clear);
@@ -839,7 +839,7 @@ static void digi_set_termios(struct tty_struct *tty,
}


static void digi_break_ctl(struct tty_struct *tty, int break_state)
static int digi_break_ctl(struct tty_struct *tty, int break_state)
{
	struct usb_serial_port *port = tty->driver_data;
	unsigned char buf[4];
@@ -848,7 +848,8 @@ static void digi_break_ctl(struct tty_struct *tty, int break_state)
	buf[1] = 2;				/* length */
	buf[2] = break_state ? 1 : 0;
	buf[3] = 0;				/* pad */
	digi_write_inb_command(port, buf, 4, 0);

	return digi_write_inb_command(port, buf, 4, 0);
}


Loading