Commit c47055e9 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
Browse files

Merge tag 'usb-serial-5.16-rc1' of...

Merge tag 'usb-serial-5.16-rc1' of https://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial into usb-next

Johan writes:

USB-serial updates for 5.16-rc1

Here are the USB-serial updates for 5.16-rc1, including:

 - conversions of usb_control_msg() calls to use the new wrappers where
   appropriate
 - fix of the keyspan probe error handling after a low-order allocation
   failure (e.g. due to fault injection)
 - allow hung up ports to be runtime suspended

Included are also some related clean ups.

All have been in linux-next with no reported issues.

* tag 'usb-serial-5.16-rc1' of https://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial:
  USB: serial: keyspan: fix memleak on probe errors
  USB: serial: cp210x: use usb_control_msg_recv() and usb_control_msg_send()
  USB: serial: ch314: use usb_control_msg_recv()
  USB: serial: kl5kusb105: drop line-status helper
  USB: serial: kl5kusb105: simplify line-status handling
  USB: serial: kl5kusb105: clean up line-status handling
  USB: serial: kl5kusb105: use usb_control_msg_recv() and usb_control_msg_send()
  USB: serial: keyspan_pda: use usb_control_msg_recv()
  USB: serial: ftdi_sio: use usb_control_msg_recv()
  USB: serial: f81232: use usb_control_msg_recv() and usb_control_msg_send()
  USB: serial: allow hung up ports to be suspended
  USB: serial: clean up core error labels
parents 79a4479a 910c9963
Loading
Loading
Loading
Loading
+26 −59
Original line number Diff line number Diff line
@@ -131,17 +131,11 @@ static int ch341_control_in(struct usb_device *dev,
	dev_dbg(&dev->dev, "%s - (%02x,%04x,%04x,%u)\n", __func__,
		request, value, index, bufsize);

	r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request,
	r = usb_control_msg_recv(dev, 0, request,
				 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
			    value, index, buf, bufsize, DEFAULT_TIMEOUT);
	if (r < (int)bufsize) {
		if (r >= 0) {
			dev_err(&dev->dev,
				"short control message received (%d < %u)\n",
				r, bufsize);
			r = -EIO;
		}

				 value, index, buf, bufsize, DEFAULT_TIMEOUT,
				 GFP_KERNEL);
	if (r) {
		dev_err(&dev->dev, "failed to receive control message: %d\n",
			r);
		return r;
@@ -287,24 +281,19 @@ static int ch341_set_handshake(struct usb_device *dev, u8 control)
static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv)
{
	const unsigned int size = 2;
	char *buffer;
	u8 buffer[2];
	int r;
	unsigned long flags;

	buffer = kmalloc(size, GFP_KERNEL);
	if (!buffer)
		return -ENOMEM;

	r = ch341_control_in(dev, CH341_REQ_READ_REG, 0x0706, 0, buffer, size);
	if (r < 0)
		goto out;
	if (r)
		return r;

	spin_lock_irqsave(&priv->lock, flags);
	priv->msr = (~(*buffer)) & CH341_BITS_MODEM_STAT;
	spin_unlock_irqrestore(&priv->lock, flags);

out:	kfree(buffer);
	return r;
	return 0;
}

/* -------------------------------------------------------------------------- */
@@ -312,31 +301,28 @@ out: kfree(buffer);
static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
{
	const unsigned int size = 2;
	char *buffer;
	u8 buffer[2];
	int r;

	buffer = kmalloc(size, GFP_KERNEL);
	if (!buffer)
		return -ENOMEM;

	/* expect two bytes 0x27 0x00 */
	r = ch341_control_in(dev, CH341_REQ_READ_VERSION, 0, 0, buffer, size);
	if (r < 0)
		goto out;
	if (r)
		return r;
	dev_dbg(&dev->dev, "Chip version: 0x%02x\n", buffer[0]);

	r = ch341_control_out(dev, CH341_REQ_SERIAL_INIT, 0, 0);
	if (r < 0)
		goto out;
		return r;

	r = ch341_set_baudrate_lcr(dev, priv, priv->baud_rate, priv->lcr);
	if (r < 0)
		goto out;
		return r;

	r = ch341_set_handshake(dev, priv->mcr);

out:	kfree(buffer);
	if (r < 0)
		return r;

	return 0;
}

static int ch341_detect_quirks(struct usb_serial_port *port)
@@ -345,40 +331,27 @@ static int ch341_detect_quirks(struct usb_serial_port *port)
	struct usb_device *udev = port->serial->dev;
	const unsigned int size = 2;
	unsigned long quirks = 0;
	char *buffer;
	u8 buffer[2];
	int r;

	buffer = kmalloc(size, GFP_KERNEL);
	if (!buffer)
		return -ENOMEM;

	/*
	 * A subset of CH34x devices does not support all features. The
	 * prescaler is limited and there is no support for sending a RS232
	 * break condition. A read failure when trying to set up the latter is
	 * used to detect these devices.
	 */
	r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), CH341_REQ_READ_REG,
	r = usb_control_msg_recv(udev, 0, CH341_REQ_READ_REG,
				 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
			    CH341_REG_BREAK, 0, buffer, size, DEFAULT_TIMEOUT);
				 CH341_REG_BREAK, 0, &buffer, size,
				 DEFAULT_TIMEOUT, GFP_KERNEL);
	if (r == -EPIPE) {
		dev_info(&port->dev, "break control not supported, using simulated break\n");
		quirks = CH341_QUIRK_LIMITED_PRESCALER | CH341_QUIRK_SIMULATE_BREAK;
		r = 0;
		goto out;
	}

	if (r != size) {
		if (r >= 0)
			r = -EIO;
	} else if (r) {
		dev_err(&port->dev, "failed to read break control: %d\n", r);
		goto out;
	}

	r = 0;
out:
	kfree(buffer);

	if (quirks) {
		dev_dbg(&port->dev, "enabling quirk flags: 0x%02lx\n", quirks);
		priv->quirks |= quirks;
@@ -647,23 +620,19 @@ static void ch341_break_ctl(struct tty_struct *tty, int break_state)
	struct ch341_private *priv = usb_get_serial_port_data(port);
	int r;
	uint16_t reg_contents;
	uint8_t *break_reg;
	uint8_t break_reg[2];

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

	break_reg = kmalloc(2, GFP_KERNEL);
	if (!break_reg)
		return;

	r = ch341_control_in(port->serial->dev, CH341_REQ_READ_REG,
			ch341_break_reg, 0, break_reg, 2);
	if (r < 0) {
	if (r) {
		dev_err(&port->dev, "%s - USB control read error (%d)\n",
				__func__, r);
		goto out;
		return;
	}
	dev_dbg(&port->dev, "%s - initial ch341 break register contents - reg1: %x, reg2: %x\n",
		__func__, break_reg[0], break_reg[1]);
@@ -684,8 +653,6 @@ static void ch341_break_ctl(struct tty_struct *tty, int break_state)
	if (r < 0)
		dev_err(&port->dev, "%s - USB control write error (%d)\n",
				__func__, r);
out:
	kfree(break_reg);
}

static int ch341_tiocmset(struct tty_struct *tty,
+31 −78
Original line number Diff line number Diff line
@@ -631,30 +631,20 @@ static int cp210x_read_reg_block(struct usb_serial_port *port, u8 req,
{
	struct usb_serial *serial = port->serial;
	struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
	void *dmabuf;
	int result;

	dmabuf = kmalloc(bufsize, GFP_KERNEL);
	if (!dmabuf)
		return -ENOMEM;

	result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
			req, REQTYPE_INTERFACE_TO_HOST, 0,
			port_priv->bInterfaceNumber, dmabuf, bufsize,
			USB_CTRL_GET_TIMEOUT);
	if (result == bufsize) {
		memcpy(buf, dmabuf, bufsize);
		result = 0;
	} else {
	result = usb_control_msg_recv(serial->dev, 0, req,
			REQTYPE_INTERFACE_TO_HOST, 0,
			port_priv->bInterfaceNumber, buf, bufsize,
			USB_CTRL_SET_TIMEOUT, GFP_KERNEL);
	if (result) {
		dev_err(&port->dev, "failed get req 0x%x size %d status: %d\n",
				req, bufsize, result);
		if (result >= 0)
			result = -EIO;
		return result;
	}

	kfree(dmabuf);

	return result;
	return 0;
}

/*
@@ -672,31 +662,19 @@ static int cp210x_read_u8_reg(struct usb_serial_port *port, u8 req, u8 *val)
static int cp210x_read_vendor_block(struct usb_serial *serial, u8 type, u16 val,
				    void *buf, int bufsize)
{
	void *dmabuf;
	int result;

	dmabuf = kmalloc(bufsize, GFP_KERNEL);
	if (!dmabuf)
		return -ENOMEM;

	result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
				 CP210X_VENDOR_SPECIFIC, type, val,
				 cp210x_interface_num(serial), dmabuf, bufsize,
				 USB_CTRL_GET_TIMEOUT);
	if (result == bufsize) {
		memcpy(buf, dmabuf, bufsize);
		result = 0;
	} else {
	result = usb_control_msg_recv(serial->dev, 0, CP210X_VENDOR_SPECIFIC,
			type, val, cp210x_interface_num(serial), buf, bufsize,
			USB_CTRL_GET_TIMEOUT, GFP_KERNEL);
	if (result) {
		dev_err(&serial->interface->dev,
			"failed to get vendor val 0x%04x size %d: %d\n", val,
			bufsize, result);
		if (result >= 0)
			result = -EIO;
		return result;
	}

	kfree(dmabuf);

	return result;
	return 0;
}

/*
@@ -730,21 +708,13 @@ static int cp210x_write_reg_block(struct usb_serial_port *port, u8 req,
{
	struct usb_serial *serial = port->serial;
	struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
	void *dmabuf;
	int result;

	dmabuf = kmemdup(buf, bufsize, GFP_KERNEL);
	if (!dmabuf)
		return -ENOMEM;

	result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
			req, REQTYPE_HOST_TO_INTERFACE, 0,
			port_priv->bInterfaceNumber, dmabuf, bufsize,
			USB_CTRL_SET_TIMEOUT);

	kfree(dmabuf);

	if (result < 0) {
	result = usb_control_msg_send(serial->dev, 0, req,
			REQTYPE_HOST_TO_INTERFACE, 0,
			port_priv->bInterfaceNumber, buf, bufsize,
			USB_CTRL_SET_TIMEOUT, GFP_KERNEL);
	if (result) {
		dev_err(&port->dev, "failed set req 0x%x size %d status: %d\n",
				req, bufsize, result);
		return result;
@@ -773,21 +743,12 @@ static int cp210x_write_u32_reg(struct usb_serial_port *port, u8 req, u32 val)
static int cp210x_write_vendor_block(struct usb_serial *serial, u8 type,
				     u16 val, void *buf, int bufsize)
{
	void *dmabuf;
	int result;

	dmabuf = kmemdup(buf, bufsize, GFP_KERNEL);
	if (!dmabuf)
		return -ENOMEM;

	result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
				 CP210X_VENDOR_SPECIFIC, type, val,
				 cp210x_interface_num(serial), dmabuf, bufsize,
				 USB_CTRL_SET_TIMEOUT);

	kfree(dmabuf);

	if (result < 0) {
	result = usb_control_msg_send(serial->dev, 0, CP210X_VENDOR_SPECIFIC,
			type, val, cp210x_interface_num(serial), buf, bufsize,
			USB_CTRL_SET_TIMEOUT, GFP_KERNEL);
	if (result) {
		dev_err(&serial->interface->dev,
			"failed to set vendor val 0x%04x size %d: %d\n", val,
			bufsize, result);
@@ -952,29 +913,21 @@ static int cp210x_get_tx_queue_byte_count(struct usb_serial_port *port,
{
	struct usb_serial *serial = port->serial;
	struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
	struct cp210x_comm_status *sts;
	struct cp210x_comm_status sts;
	int result;

	sts = kmalloc(sizeof(*sts), GFP_KERNEL);
	if (!sts)
		return -ENOMEM;

	result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
			CP210X_GET_COMM_STATUS, REQTYPE_INTERFACE_TO_HOST,
			0, port_priv->bInterfaceNumber, sts, sizeof(*sts),
			USB_CTRL_GET_TIMEOUT);
	if (result == sizeof(*sts)) {
		*count = le32_to_cpu(sts->ulAmountInOutQueue);
		result = 0;
	} else {
	result = usb_control_msg_recv(serial->dev, 0, CP210X_GET_COMM_STATUS,
			REQTYPE_INTERFACE_TO_HOST, 0,
			port_priv->bInterfaceNumber, &sts, sizeof(sts),
			USB_CTRL_GET_TIMEOUT, GFP_KERNEL);
	if (result) {
		dev_err(&port->dev, "failed to get comm status: %d\n", result);
		if (result >= 0)
			result = -EIO;
		return result;
	}

	kfree(sts);
	*count = le32_to_cpu(sts.ulAmountInOutQueue);

	return result;
	return 0;
}

static bool cp210x_tx_empty(struct usb_serial_port *port)
+34 −62
Original line number Diff line number Diff line
@@ -139,67 +139,46 @@ static int calc_baud_divisor(speed_t baudrate, speed_t clockrate)
static int f81232_get_register(struct usb_serial_port *port, u16 reg, u8 *val)
{
	int status;
	u8 *tmp;
	struct usb_device *dev = port->serial->dev;

	tmp = kmalloc(sizeof(*val), GFP_KERNEL);
	if (!tmp)
		return -ENOMEM;

	status = usb_control_msg(dev,
				usb_rcvctrlpipe(dev, 0),
	status = usb_control_msg_recv(dev,
				      0,
				      F81232_REGISTER_REQUEST,
				      F81232_GET_REGISTER,
				      reg,
				      0,
				tmp,
				      val,
				      sizeof(*val),
				USB_CTRL_GET_TIMEOUT);
	if (status != sizeof(*val)) {
				      USB_CTRL_GET_TIMEOUT,
				      GFP_KERNEL);
	if (status) {
		dev_err(&port->dev, "%s failed status: %d\n", __func__, status);

		if (status < 0)
		status = usb_translate_errors(status);
		else
			status = -EIO;
	} else {
		status = 0;
		*val = *tmp;
	}

	kfree(tmp);
	return status;
}

static int f81232_set_register(struct usb_serial_port *port, u16 reg, u8 val)
{
	int status;
	u8 *tmp;
	struct usb_device *dev = port->serial->dev;

	tmp = kmalloc(sizeof(val), GFP_KERNEL);
	if (!tmp)
		return -ENOMEM;

	*tmp = val;

	status = usb_control_msg(dev,
				usb_sndctrlpipe(dev, 0),
	status = usb_control_msg_send(dev,
				      0,
				      F81232_REGISTER_REQUEST,
				      F81232_SET_REGISTER,
				      reg,
				      0,
				tmp,
				      &val,
				      sizeof(val),
				USB_CTRL_SET_TIMEOUT);
	if (status < 0) {
				      USB_CTRL_SET_TIMEOUT,
				      GFP_KERNEL);
	if (status) {
		dev_err(&port->dev, "%s failed status: %d\n", __func__, status);
		status = usb_translate_errors(status);
	} else {
		status = 0;
	}

	kfree(tmp);
	return status;
}

@@ -857,28 +836,22 @@ static int f81534a_ctrl_set_register(struct usb_interface *intf, u16 reg,
	struct usb_device *dev = interface_to_usbdev(intf);
	int retry = F81534A_ACCESS_REG_RETRY;
	int status;
	u8 *tmp;

	tmp = kmemdup(val, size, GFP_KERNEL);
	if (!tmp)
		return -ENOMEM;

	while (retry--) {
		status = usb_control_msg(dev,
					usb_sndctrlpipe(dev, 0),
		status = usb_control_msg_send(dev,
					      0,
					      F81232_REGISTER_REQUEST,
					      F81232_SET_REGISTER,
					      reg,
					      0,
					tmp,
					      val,
					      size,
					USB_CTRL_SET_TIMEOUT);
		if (status < 0) {
					      USB_CTRL_SET_TIMEOUT,
					      GFP_KERNEL);
		if (status) {
			status = usb_translate_errors(status);
			if (status == -EIO)
				continue;
		} else {
			status = 0;
		}

		break;
@@ -889,7 +862,6 @@ static int f81534a_ctrl_set_register(struct usb_interface *intf, u16 reg,
				reg, status);
	}

	kfree(tmp);
	return status;
}

+15 −38
Original line number Diff line number Diff line
@@ -1437,27 +1437,15 @@ static int _read_latency_timer(struct usb_serial_port *port)
{
	struct ftdi_private *priv = usb_get_serial_port_data(port);
	struct usb_device *udev = port->serial->dev;
	unsigned char *buf;
	u8 buf;
	int rv;

	buf = kmalloc(1, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

	rv = usb_control_msg(udev,
			     usb_rcvctrlpipe(udev, 0),
			     FTDI_SIO_GET_LATENCY_TIMER_REQUEST,
			     FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE,
			     0, priv->interface,
			     buf, 1, WDR_TIMEOUT);
	if (rv < 1) {
		if (rv >= 0)
			rv = -EIO;
	} else {
		rv = buf[0];
	}

	kfree(buf);
	rv = usb_control_msg_recv(udev, 0, FTDI_SIO_GET_LATENCY_TIMER_REQUEST,
				  FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE, 0,
				  priv->interface, &buf, 1, WDR_TIMEOUT,
				  GFP_KERNEL);
	if (rv == 0)
		rv = buf;

	return rv;
}
@@ -1852,32 +1840,21 @@ static int ftdi_read_cbus_pins(struct usb_serial_port *port)
{
	struct ftdi_private *priv = usb_get_serial_port_data(port);
	struct usb_serial *serial = port->serial;
	unsigned char *buf;
	u8 buf;
	int result;

	result = usb_autopm_get_interface(serial->interface);
	if (result)
		return result;

	buf = kmalloc(1, GFP_KERNEL);
	if (!buf) {
		usb_autopm_put_interface(serial->interface);
		return -ENOMEM;
	}

	result = usb_control_msg(serial->dev,
				 usb_rcvctrlpipe(serial->dev, 0),
	result = usb_control_msg_recv(serial->dev, 0,
				      FTDI_SIO_READ_PINS_REQUEST,
				      FTDI_SIO_READ_PINS_REQUEST_TYPE, 0,
				 priv->interface, buf, 1, WDR_TIMEOUT);
	if (result < 1) {
		if (result >= 0)
			result = -EIO;
	} else {
		result = buf[0];
	}
				      priv->interface, &buf, 1, WDR_TIMEOUT,
				      GFP_KERNEL);
	if (result == 0)
		result = buf;

	kfree(buf);
	usb_autopm_put_interface(serial->interface);

	return result;
+7 −8
Original line number Diff line number Diff line
@@ -2890,22 +2890,22 @@ static int keyspan_port_probe(struct usb_serial_port *port)
	for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i) {
		p_priv->in_buffer[i] = kzalloc(IN_BUFLEN, GFP_KERNEL);
		if (!p_priv->in_buffer[i])
			goto err_in_buffer;
			goto err_free_in_buffer;
	}

	for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i) {
		p_priv->out_buffer[i] = kzalloc(OUT_BUFLEN, GFP_KERNEL);
		if (!p_priv->out_buffer[i])
			goto err_out_buffer;
			goto err_free_out_buffer;
	}

	p_priv->inack_buffer = kzalloc(INACK_BUFLEN, GFP_KERNEL);
	if (!p_priv->inack_buffer)
		goto err_inack_buffer;
		goto err_free_out_buffer;

	p_priv->outcont_buffer = kzalloc(OUTCONT_BUFLEN, GFP_KERNEL);
	if (!p_priv->outcont_buffer)
		goto err_outcont_buffer;
		goto err_free_inack_buffer;

	p_priv->device_details = d_details;

@@ -2951,15 +2951,14 @@ static int keyspan_port_probe(struct usb_serial_port *port)

	return 0;

err_outcont_buffer:
err_free_inack_buffer:
	kfree(p_priv->inack_buffer);
err_inack_buffer:
err_free_out_buffer:
	for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i)
		kfree(p_priv->out_buffer[i]);
err_out_buffer:
err_free_in_buffer:
	for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i)
		kfree(p_priv->in_buffer[i]);
err_in_buffer:
	kfree(p_priv);

	return -ENOMEM;
Loading