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

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

Merge tag 'usb-serial-4.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial

 into usb-next

Johan writes:

USB-serial updates for v4.11-rc1

These updates include

 - a new driver for Renesas uPD78F0730-based devices

 - several fixes of failures to check for short transfers, some of which could
   lead to minor information leaks, and in one case a loop-condition underflow

 - a fix of a long-standing regression in the ftdi_sio driver which resulted
   in excessive bulk-in interrupts

 - a fix for ftdi_sio line-status over-reporting which could lead to an
   endless stream of NULL-characters being forwarded to user space

 - a fix for a regression in the console driver

 - a fix for another mos7840 NULL-pointer dereference due to a missing endpoint
   sanity check

Included are also some clean ups and fixes for various minor issues, as well as
a couple of new device IDs that came in late.

All but the final patch have been in linux-next with no reported issues.

Signed-off-by: default avatarJohan Hovold <johan@kernel.org>
parents 25534828 5182c2cf
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -713,6 +713,15 @@ config USB_SERIAL_QT2
	  To compile this driver as a module, choose M here: the
	  module will be called quatech-serial.

config USB_SERIAL_UPD78F0730
	tristate "USB Renesas uPD78F0730 Single Port Serial Driver"
	help
	  Say Y here if you want to use the Renesas uPD78F0730
	  serial driver.

	  To compile this driver as a module, choose M here: the
	  module will be called upd78f0730.

config USB_SERIAL_DEBUG
	tristate "USB Debugging Device"
	help
+1 −0
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ obj-$(CONFIG_USB_SERIAL_SSU100) += ssu100.o
obj-$(CONFIG_USB_SERIAL_SYMBOL)			+= symbolserial.o
obj-$(CONFIG_USB_SERIAL_WWAN)			+= usb_wwan.o
obj-$(CONFIG_USB_SERIAL_TI)			+= ti_usb_3410_5052.o
obj-$(CONFIG_USB_SERIAL_UPD78F0730)		+= upd78f0730.o
obj-$(CONFIG_USB_SERIAL_VISOR)			+= visor.o
obj-$(CONFIG_USB_SERIAL_WISHBONE)		+= wishbone-serial.o
obj-$(CONFIG_USB_SERIAL_WHITEHEAT)		+= whiteheat.o
+42 −32
Original line number Diff line number Diff line
@@ -99,9 +99,16 @@ static int ark3116_read_reg(struct usb_serial *serial,
				 usb_rcvctrlpipe(serial->dev, 0),
				 0xfe, 0xc0, 0, reg,
				 buf, 1, ARK_TIMEOUT);
	if (result < 0)
	if (result < 1) {
		dev_err(&serial->interface->dev,
				"failed to read register %u: %d\n",
				reg, result);
		if (result >= 0)
			result = -EIO;

		return result;
	else
	}

	return buf[0];
}

@@ -118,17 +125,11 @@ static inline int calc_divisor(int bps)
static int ark3116_attach(struct usb_serial *serial)
{
	/* make sure we have our end-points */
	if ((serial->num_bulk_in == 0) ||
	    (serial->num_bulk_out == 0) ||
	    (serial->num_interrupt_in == 0)) {
		dev_err(&serial->dev->dev,
			"%s - missing endpoint - "
			"bulk in: %d, bulk out: %d, int in %d\n",
			KBUILD_MODNAME,
			serial->num_bulk_in,
			serial->num_bulk_out,
			serial->num_interrupt_in);
		return -EINVAL;
	if (serial->num_bulk_in == 0 ||
			serial->num_bulk_out == 0 ||
			serial->num_interrupt_in == 0) {
		dev_err(&serial->interface->dev, "missing endpoint\n");
		return -ENODEV;
	}

	return 0;
@@ -186,10 +187,8 @@ static int ark3116_port_probe(struct usb_serial_port *port)
	if (priv->irda)
		ark3116_write_reg(serial, 0x9, 0);

	dev_info(&serial->dev->dev,
		"%s using %s mode\n",
		KBUILD_MODNAME,
		priv->irda ? "IrDA" : "RS232");
	dev_info(&port->dev, "using %s mode\n", priv->irda ? "IrDA" : "RS232");

	return 0;
}

@@ -325,9 +324,8 @@ static void ark3116_set_termios(struct tty_struct *tty,

	/* check for software flow control */
	if (I_IXOFF(tty) || I_IXON(tty)) {
		dev_warn(&serial->dev->dev,
			 "%s: don't know how to do software flow control\n",
			 KBUILD_MODNAME);
		dev_warn(&port->dev,
				"software flow control not implemented\n");
	}

	/* Don't rewrite B0 */
@@ -346,7 +344,7 @@ static void ark3116_close(struct usb_serial_port *port)
	ark3116_write_reg(serial, UART_IER, 0);

	usb_serial_generic_close(port);
	if (serial->num_interrupt_in)

	usb_kill_urb(port->interrupt_in_urb);
}

@@ -366,23 +364,29 @@ static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port)
		dev_dbg(&port->dev,
			"%s - usb_serial_generic_open failed: %d\n",
			__func__, result);
		goto err_out;
		goto err_free;
	}

	/* remove any data still left: also clears error state */
	ark3116_read_reg(serial, UART_RX, buf);

	/* read modem status */
	priv->msr = ark3116_read_reg(serial, UART_MSR, buf);
	result = ark3116_read_reg(serial, UART_MSR, buf);
	if (result < 0)
		goto err_close;
	priv->msr = *buf;

	/* read line status */
	priv->lsr = ark3116_read_reg(serial, UART_LSR, buf);
	result = ark3116_read_reg(serial, UART_LSR, buf);
	if (result < 0)
		goto err_close;
	priv->lsr = *buf;

	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
	if (result) {
		dev_err(&port->dev, "submit irq_in urb failed %d\n",
			result);
		ark3116_close(port);
		goto err_out;
		goto err_close;
	}

	/* activate interrupts */
@@ -395,8 +399,15 @@ static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port)
	if (tty)
		ark3116_set_termios(tty, port, NULL);

err_out:
	kfree(buf);

	return 0;

err_close:
	usb_serial_generic_close(port);
err_free:
	kfree(buf);

	return result;
}

@@ -602,9 +613,8 @@ static void ark3116_read_int_callback(struct urb *urb)

	result = usb_submit_urb(urb, GFP_ATOMIC);
	if (result)
		dev_err(&urb->dev->dev,
			"%s - Error %d submitting interrupt urb\n",
			__func__, result);
		dev_err(&port->dev, "failed to resubmit interrupt urb: %d\n",
			result);
}


+55 −63
Original line number Diff line number Diff line
@@ -93,8 +93,8 @@ MODULE_DEVICE_TABLE(usb, id_table);
struct ch341_private {
	spinlock_t lock; /* access lock */
	unsigned baud_rate; /* set baud rate */
	u8 line_control; /* set line control value RTS/DTR */
	u8 line_status; /* active status of modem control inputs */
	u8 mcr;
	u8 msr;
	u8 lcr;
};

@@ -107,8 +107,8 @@ static int ch341_control_out(struct usb_device *dev, u8 request,
{
	int r;

	dev_dbg(&dev->dev, "ch341_control_out(%02x,%02x,%04x,%04x)\n",
		USB_DIR_OUT|0x40, (int)request, (int)value, (int)index);
	dev_dbg(&dev->dev, "%s - (%02x,%04x,%04x)\n", __func__,
		request, value, index);

	r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request,
			    USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
@@ -125,9 +125,8 @@ static int ch341_control_in(struct usb_device *dev,
{
	int r;

	dev_dbg(&dev->dev, "ch341_control_in(%02x,%02x,%04x,%04x,%p,%u)\n",
		USB_DIR_IN|0x40, (int)request, (int)value, (int)index, buf,
		(int)bufsize);
	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,
			    USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
@@ -210,7 +209,7 @@ static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv)
		goto out;

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

out:	kfree(buffer);
@@ -239,30 +238,11 @@ static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
	if (r < 0)
		goto out;

	/* expect two bytes 0x56 0x00 */
	r = ch341_control_in(dev, CH341_REQ_READ_REG, 0x2518, 0, buffer, size);
	if (r < 0)
		goto out;

	r = ch341_control_out(dev, CH341_REQ_WRITE_REG, 0x2518, 0x0050);
	if (r < 0)
		goto out;

	/* expect 0xff 0xee */
	r = ch341_get_status(dev, priv);
	if (r < 0)
		goto out;

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

	r = ch341_set_handshake(dev, priv->line_control);
	if (r < 0)
		goto out;

	/* expect 0x9f 0xee */
	r = ch341_get_status(dev, priv);
	r = ch341_set_handshake(dev, priv->mcr);

out:	kfree(buffer);
	return r;
@@ -279,6 +259,11 @@ static int ch341_port_probe(struct usb_serial_port *port)

	spin_lock_init(&priv->lock);
	priv->baud_rate = DEFAULT_BAUD_RATE;
	/*
	 * Some CH340 devices appear unable to change the initial LCR
	 * settings, so set a sane 8N1 default.
	 */
	priv->lcr = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX | CH341_LCR_CS8;

	r = ch341_configure(port->serial->dev, priv);
	if (r < 0)
@@ -304,7 +289,7 @@ static int ch341_port_remove(struct usb_serial_port *port)
static int ch341_carrier_raised(struct usb_serial_port *port)
{
	struct ch341_private *priv = usb_get_serial_port_data(port);
	if (priv->line_status & CH341_BIT_DCD)
	if (priv->msr & CH341_BIT_DCD)
		return 1;
	return 0;
}
@@ -317,11 +302,11 @@ static void ch341_dtr_rts(struct usb_serial_port *port, int on)
	/* drop DTR and RTS */
	spin_lock_irqsave(&priv->lock, flags);
	if (on)
		priv->line_control |= CH341_BIT_RTS | CH341_BIT_DTR;
		priv->mcr |= CH341_BIT_RTS | CH341_BIT_DTR;
	else
		priv->line_control &= ~(CH341_BIT_RTS | CH341_BIT_DTR);
		priv->mcr &= ~(CH341_BIT_RTS | CH341_BIT_DTR);
	spin_unlock_irqrestore(&priv->lock, flags);
	ch341_set_handshake(port->serial->dev, priv->line_control);
	ch341_set_handshake(port->serial->dev, priv->mcr);
}

static void ch341_close(struct usb_serial_port *port)
@@ -334,14 +319,9 @@ static void ch341_close(struct usb_serial_port *port)
/* open this device, set default parameters */
static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port)
{
	struct usb_serial *serial = port->serial;
	struct ch341_private *priv = usb_get_serial_port_data(port);
	int r;

	r = ch341_configure(serial->dev, priv);
	if (r)
		return r;

	if (tty)
		ch341_set_termios(tty, port, NULL);

@@ -353,6 +333,12 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port)
		return r;
	}

	r = ch341_get_status(port->serial->dev, priv);
	if (r < 0) {
		dev_err(&port->dev, "failed to read modem status: %d\n", r);
		goto err_kill_interrupt_urb;
	}

	r = usb_serial_generic_open(tty, port);
	if (r)
		goto err_kill_interrupt_urb;
@@ -374,7 +360,7 @@ static void ch341_set_termios(struct tty_struct *tty,
	struct ch341_private *priv = usb_get_serial_port_data(port);
	unsigned baud_rate;
	unsigned long flags;
	unsigned char ctrl;
	u8 lcr;
	int r;

	/* redundant changes may cause the chip to lose bytes */
@@ -383,54 +369,54 @@ static void ch341_set_termios(struct tty_struct *tty,

	baud_rate = tty_get_baud_rate(tty);

	ctrl = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX;
	lcr = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX;

	switch (C_CSIZE(tty)) {
	case CS5:
		ctrl |= CH341_LCR_CS5;
		lcr |= CH341_LCR_CS5;
		break;
	case CS6:
		ctrl |= CH341_LCR_CS6;
		lcr |= CH341_LCR_CS6;
		break;
	case CS7:
		ctrl |= CH341_LCR_CS7;
		lcr |= CH341_LCR_CS7;
		break;
	case CS8:
		ctrl |= CH341_LCR_CS8;
		lcr |= CH341_LCR_CS8;
		break;
	}

	if (C_PARENB(tty)) {
		ctrl |= CH341_LCR_ENABLE_PAR;
		lcr |= CH341_LCR_ENABLE_PAR;
		if (C_PARODD(tty) == 0)
			ctrl |= CH341_LCR_PAR_EVEN;
			lcr |= CH341_LCR_PAR_EVEN;
		if (C_CMSPAR(tty))
			ctrl |= CH341_LCR_MARK_SPACE;
			lcr |= CH341_LCR_MARK_SPACE;
	}

	if (C_CSTOPB(tty))
		ctrl |= CH341_LCR_STOP_BITS_2;
		lcr |= CH341_LCR_STOP_BITS_2;

	if (baud_rate) {
		priv->baud_rate = baud_rate;

		r = ch341_set_baudrate_lcr(port->serial->dev, priv, ctrl);
		r = ch341_set_baudrate_lcr(port->serial->dev, priv, lcr);
		if (r < 0 && old_termios) {
			priv->baud_rate = tty_termios_baud_rate(old_termios);
			tty_termios_copy_hw(&tty->termios, old_termios);
		} else if (r == 0) {
			priv->lcr = ctrl;
			priv->lcr = lcr;
		}
	}

	spin_lock_irqsave(&priv->lock, flags);
	if (C_BAUD(tty) == B0)
		priv->line_control &= ~(CH341_BIT_DTR | CH341_BIT_RTS);
		priv->mcr &= ~(CH341_BIT_DTR | CH341_BIT_RTS);
	else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
		priv->line_control |= (CH341_BIT_DTR | CH341_BIT_RTS);
		priv->mcr |= (CH341_BIT_DTR | CH341_BIT_RTS);
	spin_unlock_irqrestore(&priv->lock, flags);

	ch341_set_handshake(port->serial->dev, priv->line_control);
	ch341_set_handshake(port->serial->dev, priv->mcr);
}

static void ch341_break_ctl(struct tty_struct *tty, int break_state)
@@ -486,20 +472,20 @@ static int ch341_tiocmset(struct tty_struct *tty,

	spin_lock_irqsave(&priv->lock, flags);
	if (set & TIOCM_RTS)
		priv->line_control |= CH341_BIT_RTS;
		priv->mcr |= CH341_BIT_RTS;
	if (set & TIOCM_DTR)
		priv->line_control |= CH341_BIT_DTR;
		priv->mcr |= CH341_BIT_DTR;
	if (clear & TIOCM_RTS)
		priv->line_control &= ~CH341_BIT_RTS;
		priv->mcr &= ~CH341_BIT_RTS;
	if (clear & TIOCM_DTR)
		priv->line_control &= ~CH341_BIT_DTR;
	control = priv->line_control;
		priv->mcr &= ~CH341_BIT_DTR;
	control = priv->mcr;
	spin_unlock_irqrestore(&priv->lock, flags);

	return ch341_set_handshake(port->serial->dev, control);
}

static void ch341_update_line_status(struct usb_serial_port *port,
static void ch341_update_status(struct usb_serial_port *port,
					unsigned char *data, size_t len)
{
	struct ch341_private *priv = usb_get_serial_port_data(port);
@@ -514,8 +500,8 @@ static void ch341_update_line_status(struct usb_serial_port *port,
	status = ~data[2] & CH341_BITS_MODEM_STAT;

	spin_lock_irqsave(&priv->lock, flags);
	delta = status ^ priv->line_status;
	priv->line_status = status;
	delta = status ^ priv->msr;
	priv->msr = status;
	spin_unlock_irqrestore(&priv->lock, flags);

	if (data[1] & CH341_MULT_STAT)
@@ -568,7 +554,7 @@ static void ch341_read_int_callback(struct urb *urb)
	}

	usb_serial_debug_data(&port->dev, __func__, len, data);
	ch341_update_line_status(port, data, len);
	ch341_update_status(port, data, len);
exit:
	status = usb_submit_urb(urb, GFP_ATOMIC);
	if (status) {
@@ -587,8 +573,8 @@ static int ch341_tiocmget(struct tty_struct *tty)
	unsigned int result;

	spin_lock_irqsave(&priv->lock, flags);
	mcr = priv->line_control;
	status = priv->line_status;
	mcr = priv->mcr;
	status = priv->msr;
	spin_unlock_irqrestore(&priv->lock, flags);

	result = ((mcr & CH341_BIT_DTR)		? TIOCM_DTR : 0)
@@ -619,6 +605,12 @@ static int ch341_reset_resume(struct usb_serial *serial)
				ret);
			return ret;
		}

		ret = ch341_get_status(port->serial->dev, priv);
		if (ret < 0) {
			dev_err(&port->dev, "failed to read modem status: %d\n",
				ret);
		}
	}

	return usb_serial_generic_resume(serial);
+2 −2
Original line number Diff line number Diff line
@@ -143,6 +143,7 @@ static int usb_console_setup(struct console *co, char *options)
			tty->driver = usb_serial_tty_driver;
			tty->index = co->index;
			init_ldsem(&tty->ldisc_sem);
			spin_lock_init(&tty->files_lock);
			INIT_LIST_HEAD(&tty->tty_files);
			kref_get(&tty->driver->kref);
			__module_get(tty->driver->owner);
@@ -264,8 +265,7 @@ static struct console usbcons = {

void usb_serial_console_disconnect(struct usb_serial *serial)
{
	if (serial && serial->port && serial->port[0]
				&& serial->port[0] == usbcons_info.port) {
	if (serial->port[0] == usbcons_info.port) {
		usb_serial_console_exit();
		usb_serial_put(serial);
	}
Loading