Commit ed921771 authored by Johan Hovold's avatar Johan Hovold
Browse files

USB: serial: cp210x: refactor flow-control handling



Add a helper function to be used to configure flow control.

The flow-control code was the last caller that relied on the
memset-on-failure behaviour of cp210x_read_reg_block(), which we can now
drop in favour of bailing out on errors when retrieving the flow-control
settings.

This should also simplify adding support for software flow control.

Signed-off-by: default avatarJohan Hovold <johan@kernel.org>
parent b339628e
Loading
Loading
Loading
Loading
+47 −50
Original line number Diff line number Diff line
@@ -555,14 +555,8 @@ static int cp210x_read_reg_block(struct usb_serial_port *port, u8 req,
	int result;

	dmabuf = kmalloc(bufsize, GFP_KERNEL);
	if (!dmabuf) {
		/*
		 * FIXME Some callers don't bother to check for error,
		 * at least give them consistent junk until they are fixed
		 */
		memset(buf, 0, bufsize);
	if (!dmabuf)
		return -ENOMEM;
	}

	result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
			req, REQTYPE_INTERFACE_TO_HOST, 0,
@@ -576,12 +570,6 @@ static int cp210x_read_reg_block(struct usb_serial_port *port, u8 req,
				req, bufsize, result);
		if (result >= 0)
			result = -EIO;

		/*
		 * FIXME Some callers don't bother to check for error,
		 * at least give them consistent junk until they are fixed
		 */
		memset(buf, 0, bufsize);
	}

	kfree(dmabuf);
@@ -1095,11 +1083,55 @@ static bool cp210x_termios_change(const struct ktermios *a, const struct ktermio
	return tty_termios_hw_change(a, b) || iflag_change;
}

static void cp210x_set_flow_control(struct tty_struct *tty,
		struct usb_serial_port *port, struct ktermios *old_termios)
{
	struct cp210x_flow_ctl flow_ctl;
	u32 flow_repl;
	u32 ctl_hs;
	int ret;

	if (old_termios && C_CRTSCTS(tty) == (old_termios->c_cflag & CRTSCTS))
		return;

	ret = cp210x_read_reg_block(port, CP210X_GET_FLOW, &flow_ctl,
			sizeof(flow_ctl));
	if (ret)
		return;

	ctl_hs = le32_to_cpu(flow_ctl.ulControlHandshake);
	flow_repl = le32_to_cpu(flow_ctl.ulFlowReplace);

	ctl_hs &= ~CP210X_SERIAL_DSR_HANDSHAKE;
	ctl_hs &= ~CP210X_SERIAL_DCD_HANDSHAKE;
	ctl_hs &= ~CP210X_SERIAL_DSR_SENSITIVITY;
	ctl_hs &= ~CP210X_SERIAL_DTR_MASK;
	ctl_hs |= CP210X_SERIAL_DTR_SHIFT(CP210X_SERIAL_DTR_ACTIVE);

	if (C_CRTSCTS(tty)) {
		ctl_hs |= CP210X_SERIAL_CTS_HANDSHAKE;
		flow_repl &= ~CP210X_SERIAL_RTS_MASK;
		flow_repl |= CP210X_SERIAL_RTS_SHIFT(CP210X_SERIAL_RTS_FLOW_CTL);
	} else {
		ctl_hs &= ~CP210X_SERIAL_CTS_HANDSHAKE;
		flow_repl &= ~CP210X_SERIAL_RTS_MASK;
		flow_repl |= CP210X_SERIAL_RTS_SHIFT(CP210X_SERIAL_RTS_ACTIVE);
	}

	dev_dbg(&port->dev, "%s - ulControlHandshake=0x%08x, ulFlowReplace=0x%08x\n",
			__func__, ctl_hs, flow_repl);

	flow_ctl.ulControlHandshake = cpu_to_le32(ctl_hs);
	flow_ctl.ulFlowReplace = cpu_to_le32(flow_repl);

	cp210x_write_reg_block(port, CP210X_SET_FLOW, &flow_ctl,
			sizeof(flow_ctl));
}

static void cp210x_set_termios(struct tty_struct *tty,
		struct usb_serial_port *port, struct ktermios *old_termios)
{
	struct cp210x_serial_private *priv = usb_get_serial_data(port->serial);
	struct device *dev = &port->dev;
	u16 bits;
	int ret;

@@ -1156,42 +1188,7 @@ static void cp210x_set_termios(struct tty_struct *tty,
	if (ret)
		dev_err(&port->dev, "failed to set line control: %d\n", ret);

	if (!old_termios || C_CRTSCTS(tty) != (old_termios->c_cflag & CRTSCTS)) {
		struct cp210x_flow_ctl flow_ctl;
		u32 ctl_hs;
		u32 flow_repl;

		cp210x_read_reg_block(port, CP210X_GET_FLOW, &flow_ctl,
				sizeof(flow_ctl));
		ctl_hs = le32_to_cpu(flow_ctl.ulControlHandshake);
		flow_repl = le32_to_cpu(flow_ctl.ulFlowReplace);

		ctl_hs &= ~CP210X_SERIAL_DSR_HANDSHAKE;
		ctl_hs &= ~CP210X_SERIAL_DCD_HANDSHAKE;
		ctl_hs &= ~CP210X_SERIAL_DSR_SENSITIVITY;
		ctl_hs &= ~CP210X_SERIAL_DTR_MASK;
		ctl_hs |= CP210X_SERIAL_DTR_SHIFT(CP210X_SERIAL_DTR_ACTIVE);
		if (C_CRTSCTS(tty)) {
			ctl_hs |= CP210X_SERIAL_CTS_HANDSHAKE;

			flow_repl &= ~CP210X_SERIAL_RTS_MASK;
			flow_repl |= CP210X_SERIAL_RTS_SHIFT(
					CP210X_SERIAL_RTS_FLOW_CTL);
		} else {
			ctl_hs &= ~CP210X_SERIAL_CTS_HANDSHAKE;

			flow_repl &= ~CP210X_SERIAL_RTS_MASK;
			flow_repl |= CP210X_SERIAL_RTS_SHIFT(
					CP210X_SERIAL_RTS_ACTIVE);
		}

		dev_dbg(dev, "%s - ulControlHandshake=0x%08x, ulFlowReplace=0x%08x\n",
				__func__, ctl_hs, flow_repl);
		flow_ctl.ulControlHandshake = cpu_to_le32(ctl_hs);
		flow_ctl.ulFlowReplace = cpu_to_le32(flow_repl);
		cp210x_write_reg_block(port, CP210X_SET_FLOW, &flow_ctl,
				sizeof(flow_ctl));
	}
	cp210x_set_flow_control(tty, port, old_termios);

	/*
	 * Enable event-insertion mode only if input parity checking is