USB-serial updates for 5.5-rc1

Here are the USB-serial updates for 5.5-rc1, including:
 
  - support for a new class of pl2303 devices
  - improved divisor calculations for ch341
  - fixes for a remote-wakeup bug in the moschip drivers
  - improved device-type handling in mos7840
  - various cleanups of mos7840
 
 Included are also some new device ids.
 
 All have been in linux-next with no reported issues.
 
 Signed-off-by: Johan Hovold <johan@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYIAB0WIQQHbPq+cpGvN/peuzMLxc3C7H1lCAUCXc52mwAKCRALxc3C7H1l
 CDKaAQCZonIg8g1Wu3wdZmTOg4jmL2tiur3sp8oWKYFgKld3iQEAi6pTSKdrVYHf
 FviCzUi1UnZGjtZYyj1h8NqiAS8vJA0=
 =33aM
 -----END PGP SIGNATURE-----

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

Johan writes:

USB-serial updates for 5.5-rc1

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

 - support for a new class of pl2303 devices
 - improved divisor calculations for ch341
 - fixes for a remote-wakeup bug in the moschip drivers
 - improved device-type handling in mos7840
 - various cleanups of mos7840

Included are also some new device ids.

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

Signed-off-by: Johan Hovold <johan@kernel.org>

* tag 'usb-serial-5.5-rc1' of https://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial:
  USB: serial: ftdi_sio: add device IDs for U-Blox C099-F9P
  USB: serial: option: add support for Foxconn T77W968 LTE modules
  USB: serial: mos7840: drop port open flag
  USB: serial: mos7840: drop read-urb check
  USB: serial: mos7840: drop port driver data accessors
  USB: serial: mos7840: drop serial struct accessor
  USB: serial: mos7840: drop paranoid serial checks
  USB: serial: mos7840: drop paranoid port checks
  USB: serial: mos7840: drop redundant urb context check
  USB: serial: mos7840: rip out broken interrupt handling
  USB: serial: mos7840: fix probe error handling
  USB: serial: mos7840: document MCS7810 detection hack
  USB: serial: mos7840: clean up device-type handling
  USB: serial: mos7840: fix remote wakeup
  USB: serial: mos7720: fix remote wakeup
  USB: serial: option: add support for DW5821e with eSIM support
  USB: serial: mos7840: add USB ID to support Moxa UPort 2210
  USB: serial: ch341: reimplement line-speed handling
  USB: serial: pl2303: add support for PL2303HXN
This commit is contained in:
Greg Kroah-Hartman 2019-11-15 18:11:53 +08:00
commit 6e0f30604d
8 changed files with 300 additions and 710 deletions

View File

@ -48,12 +48,6 @@
#define CH341_BIT_DCD 0x08
#define CH341_BITS_MODEM_STAT 0x0f /* all bits */
/*******************************/
/* baudrate calculation factor */
/*******************************/
#define CH341_BAUDBASE_FACTOR 1532620800
#define CH341_BAUDBASE_DIVMAX 3
/* Break support - the information used to implement this was gleaned from
* the Net/FreeBSD uchcom.c driver by Takanori Watanabe. Domo arigato.
*/
@ -144,37 +138,96 @@ static int ch341_control_in(struct usb_device *dev,
return 0;
}
#define CH341_CLKRATE 48000000
#define CH341_CLK_DIV(ps, fact) (1 << (12 - 3 * (ps) - (fact)))
#define CH341_MIN_RATE(ps) (CH341_CLKRATE / (CH341_CLK_DIV((ps), 1) * 512))
static const speed_t ch341_min_rates[] = {
CH341_MIN_RATE(0),
CH341_MIN_RATE(1),
CH341_MIN_RATE(2),
CH341_MIN_RATE(3),
};
/*
* The device line speed is given by the following equation:
*
* baudrate = 48000000 / (2^(12 - 3 * ps - fact) * div), where
*
* 0 <= ps <= 3,
* 0 <= fact <= 1,
* 2 <= div <= 256 if fact = 0, or
* 9 <= div <= 256 if fact = 1
*/
static int ch341_get_divisor(speed_t speed)
{
unsigned int fact, div, clk_div;
int ps;
/*
* Clamp to supported range, this makes the (ps < 0) and (div < 2)
* sanity checks below redundant.
*/
speed = clamp(speed, 46U, 3000000U);
/*
* Start with highest possible base clock (fact = 1) that will give a
* divisor strictly less than 512.
*/
fact = 1;
for (ps = 3; ps >= 0; ps--) {
if (speed > ch341_min_rates[ps])
break;
}
if (ps < 0)
return -EINVAL;
/* Determine corresponding divisor, rounding down. */
clk_div = CH341_CLK_DIV(ps, fact);
div = CH341_CLKRATE / (clk_div * speed);
/* Halve base clock (fact = 0) if required. */
if (div < 9 || div > 255) {
div /= 2;
clk_div *= 2;
fact = 0;
}
if (div < 2)
return -EINVAL;
/*
* Pick next divisor if resulting rate is closer to the requested one,
* scale up to avoid rounding errors on low rates.
*/
if (16 * CH341_CLKRATE / (clk_div * div) - 16 * speed >=
16 * speed - 16 * CH341_CLKRATE / (clk_div * (div + 1)))
div++;
return (0x100 - div) << 8 | fact << 2 | ps;
}
static int ch341_set_baudrate_lcr(struct usb_device *dev,
struct ch341_private *priv, u8 lcr)
{
short a;
int val;
int r;
unsigned long factor;
short divisor;
if (!priv->baud_rate)
return -EINVAL;
factor = (CH341_BAUDBASE_FACTOR / priv->baud_rate);
divisor = CH341_BAUDBASE_DIVMAX;
while ((factor > 0xfff0) && divisor) {
factor >>= 3;
divisor--;
}
if (factor > 0xfff0)
val = ch341_get_divisor(priv->baud_rate);
if (val < 0)
return -EINVAL;
factor = 0x10000 - factor;
a = (factor & 0xff00) | divisor;
/*
* CH341A buffers data until a full endpoint-size packet (32 bytes)
* has been received unless bit 7 is set.
*/
a |= BIT(7);
val |= BIT(7);
r = ch341_control_out(dev, CH341_REQ_WRITE_REG, 0x1312, a);
r = ch341_control_out(dev, CH341_REQ_WRITE_REG, 0x1312, val);
if (r)
return r;

View File

@ -1033,6 +1033,9 @@ static const struct usb_device_id id_table_combined[] = {
/* Sienna devices */
{ USB_DEVICE(FTDI_VID, FTDI_SIENNA_PID) },
{ USB_DEVICE(ECHELON_VID, ECHELON_U20_PID) },
/* U-Blox devices */
{ USB_DEVICE(UBLOX_VID, UBLOX_C099F9P_ZED_PID) },
{ USB_DEVICE(UBLOX_VID, UBLOX_C099F9P_ODIN_PID) },
{ } /* Terminating entry */
};

View File

@ -1558,3 +1558,10 @@
*/
#define UNJO_VID 0x22B7
#define UNJO_ISODEBUG_V1_PID 0x150D
/*
* U-Blox products (http://www.u-blox.com).
*/
#define UBLOX_VID 0x1546
#define UBLOX_C099F9P_ZED_PID 0x0502
#define UBLOX_C099F9P_ODIN_PID 0x0503

View File

@ -1833,10 +1833,6 @@ static int mos7720_startup(struct usb_serial *serial)
product = le16_to_cpu(serial->dev->descriptor.idProduct);
dev = serial->dev;
/* setting configuration feature to one */
usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
(__u8)0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5000);
if (product == MOSCHIP_DEVICE_ID_7715) {
struct urb *urb = serial->port[0]->interrupt_in_urb;

File diff suppressed because it is too large Load Diff

View File

@ -197,6 +197,7 @@ static void option_instat_callback(struct urb *urb);
#define DELL_PRODUCT_5804_MINICARD_ATT 0x819b /* Novatel E371 */
#define DELL_PRODUCT_5821E 0x81d7
#define DELL_PRODUCT_5821E_ESIM 0x81e0
#define KYOCERA_VENDOR_ID 0x0c88
#define KYOCERA_PRODUCT_KPC650 0x17da
@ -1044,6 +1045,8 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5804_MINICARD_ATT, 0xff, 0xff, 0xff) },
{ USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5821E),
.driver_info = RSVD(0) | RSVD(1) | RSVD(6) },
{ USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5821E_ESIM),
.driver_info = RSVD(0) | RSVD(1) | RSVD(6) },
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) }, /* ADU-E100, ADU-310 */
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) },
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_620UW) },
@ -1990,6 +1993,10 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0xa31d, 0xff, 0x06, 0x13) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0xa31d, 0xff, 0x06, 0x14) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0xa31d, 0xff, 0x06, 0x1b) },
{ USB_DEVICE(0x0489, 0xe0b4), /* Foxconn T77W968 */
.driver_info = RSVD(0) | RSVD(1) | RSVD(6) },
{ USB_DEVICE(0x0489, 0xe0b5), /* Foxconn T77W968 ESIM */
.driver_info = RSVD(0) | RSVD(1) | RSVD(6) },
{ USB_DEVICE(0x1508, 0x1001), /* Fibocom NL668 */
.driver_info = RSVD(4) | RSVD(5) | RSVD(6) },
{ USB_DEVICE(0x2cb7, 0x0104), /* Fibocom NL678 series */

View File

@ -47,6 +47,12 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ZTEK) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_TB) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GC) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GB) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GT) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GL) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GE) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GS) },
{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID),
@ -130,9 +136,11 @@ MODULE_DEVICE_TABLE(usb, id_table);
#define VENDOR_WRITE_REQUEST_TYPE 0x40
#define VENDOR_WRITE_REQUEST 0x01
#define VENDOR_WRITE_NREQUEST 0x80
#define VENDOR_READ_REQUEST_TYPE 0xc0
#define VENDOR_READ_REQUEST 0x01
#define VENDOR_READ_NREQUEST 0x81
#define UART_STATE_INDEX 8
#define UART_STATE_MSR_MASK 0x8b
@ -148,11 +156,24 @@ MODULE_DEVICE_TABLE(usb, id_table);
#define PL2303_FLOWCTRL_MASK 0xf0
#define PL2303_READ_TYPE_HX_STATUS 0x8080
#define PL2303_HXN_RESET_REG 0x07
#define PL2303_HXN_RESET_UPSTREAM_PIPE 0x02
#define PL2303_HXN_RESET_DOWNSTREAM_PIPE 0x01
#define PL2303_HXN_FLOWCTRL_REG 0x0a
#define PL2303_HXN_FLOWCTRL_MASK 0x1c
#define PL2303_HXN_FLOWCTRL_NONE 0x1c
#define PL2303_HXN_FLOWCTRL_RTS_CTS 0x18
#define PL2303_HXN_FLOWCTRL_XON_XOFF 0x0c
static void pl2303_set_break(struct usb_serial_port *port, bool enable);
enum pl2303_type {
TYPE_01, /* Type 0 and 1 (difference unknown) */
TYPE_HX, /* HX version of the pl2303 chip */
TYPE_HXN, /* HXN version of the pl2303 chip */
TYPE_COUNT
};
@ -184,16 +205,26 @@ static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = {
[TYPE_HX] = {
.max_baud_rate = 12000000,
},
[TYPE_HXN] = {
.max_baud_rate = 12000000,
},
};
static int pl2303_vendor_read(struct usb_serial *serial, u16 value,
unsigned char buf[1])
{
struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
struct device *dev = &serial->interface->dev;
u8 request;
int res;
if (spriv->type == &pl2303_type_data[TYPE_HXN])
request = VENDOR_READ_NREQUEST;
else
request = VENDOR_READ_REQUEST;
res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
request, VENDOR_READ_REQUEST_TYPE,
value, 0, buf, 1, 100);
if (res != 1) {
dev_err(dev, "%s - failed to read [%04x]: %d\n", __func__,
@ -211,13 +242,20 @@ static int pl2303_vendor_read(struct usb_serial *serial, u16 value,
static int pl2303_vendor_write(struct usb_serial *serial, u16 value, u16 index)
{
struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
struct device *dev = &serial->interface->dev;
u8 request;
int res;
dev_dbg(dev, "%s - [%04x] = %02x\n", __func__, value, index);
if (spriv->type == &pl2303_type_data[TYPE_HXN])
request = VENDOR_WRITE_NREQUEST;
else
request = VENDOR_WRITE_REQUEST;
res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
request, VENDOR_WRITE_REQUEST_TYPE,
value, index, NULL, 0, 100);
if (res) {
dev_err(dev, "%s - failed to write [%04x]: %d\n", __func__,
@ -230,6 +268,7 @@ static int pl2303_vendor_write(struct usb_serial *serial, u16 value, u16 index)
static int pl2303_update_reg(struct usb_serial *serial, u8 reg, u8 mask, u8 val)
{
struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
int ret = 0;
u8 *buf;
@ -237,7 +276,11 @@ static int pl2303_update_reg(struct usb_serial *serial, u8 reg, u8 mask, u8 val)
if (!buf)
return -ENOMEM;
ret = pl2303_vendor_read(serial, reg | 0x80, buf);
if (spriv->type == &pl2303_type_data[TYPE_HXN])
ret = pl2303_vendor_read(serial, reg, buf);
else
ret = pl2303_vendor_read(serial, reg | 0x80, buf);
if (ret)
goto out_free;
@ -320,6 +363,7 @@ static int pl2303_startup(struct usb_serial *serial)
struct pl2303_serial_private *spriv;
enum pl2303_type type = TYPE_01;
unsigned char *buf;
int res;
spriv = kzalloc(sizeof(*spriv), GFP_KERNEL);
if (!spriv)
@ -341,26 +385,37 @@ static int pl2303_startup(struct usb_serial *serial)
type = TYPE_01; /* type 1 */
dev_dbg(&serial->interface->dev, "device type: %d\n", type);
if (type == TYPE_HX) {
res = usb_control_msg(serial->dev,
usb_rcvctrlpipe(serial->dev, 0),
VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
PL2303_READ_TYPE_HX_STATUS, 0, buf, 1, 100);
if (res != 1)
type = TYPE_HXN;
}
spriv->type = &pl2303_type_data[type];
spriv->quirks = (unsigned long)usb_get_serial_data(serial);
spriv->quirks |= spriv->type->quirks;
usb_set_serial_data(serial, spriv);
pl2303_vendor_read(serial, 0x8484, buf);
pl2303_vendor_write(serial, 0x0404, 0);
pl2303_vendor_read(serial, 0x8484, buf);
pl2303_vendor_read(serial, 0x8383, buf);
pl2303_vendor_read(serial, 0x8484, buf);
pl2303_vendor_write(serial, 0x0404, 1);
pl2303_vendor_read(serial, 0x8484, buf);
pl2303_vendor_read(serial, 0x8383, buf);
pl2303_vendor_write(serial, 0, 1);
pl2303_vendor_write(serial, 1, 0);
if (spriv->quirks & PL2303_QUIRK_LEGACY)
pl2303_vendor_write(serial, 2, 0x24);
else
pl2303_vendor_write(serial, 2, 0x44);
if (type != TYPE_HXN) {
pl2303_vendor_read(serial, 0x8484, buf);
pl2303_vendor_write(serial, 0x0404, 0);
pl2303_vendor_read(serial, 0x8484, buf);
pl2303_vendor_read(serial, 0x8383, buf);
pl2303_vendor_read(serial, 0x8484, buf);
pl2303_vendor_write(serial, 0x0404, 1);
pl2303_vendor_read(serial, 0x8484, buf);
pl2303_vendor_read(serial, 0x8383, buf);
pl2303_vendor_write(serial, 0, 1);
pl2303_vendor_write(serial, 1, 0);
if (spriv->quirks & PL2303_QUIRK_LEGACY)
pl2303_vendor_write(serial, 2, 0x24);
else
pl2303_vendor_write(serial, 2, 0x44);
}
kfree(buf);
@ -719,14 +774,31 @@ static void pl2303_set_termios(struct tty_struct *tty,
}
if (C_CRTSCTS(tty)) {
if (spriv->quirks & PL2303_QUIRK_LEGACY)
if (spriv->quirks & PL2303_QUIRK_LEGACY) {
pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0x40);
else
} else if (spriv->type == &pl2303_type_data[TYPE_HXN]) {
pl2303_update_reg(serial, PL2303_HXN_FLOWCTRL_REG,
PL2303_HXN_FLOWCTRL_MASK,
PL2303_HXN_FLOWCTRL_RTS_CTS);
} else {
pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0x60);
}
} else if (pl2303_enable_xonxoff(tty, spriv->type)) {
pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0xc0);
if (spriv->type == &pl2303_type_data[TYPE_HXN]) {
pl2303_update_reg(serial, PL2303_HXN_FLOWCTRL_REG,
PL2303_HXN_FLOWCTRL_MASK,
PL2303_HXN_FLOWCTRL_XON_XOFF);
} else {
pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0xc0);
}
} else {
pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0);
if (spriv->type == &pl2303_type_data[TYPE_HXN]) {
pl2303_update_reg(serial, PL2303_HXN_FLOWCTRL_REG,
PL2303_HXN_FLOWCTRL_MASK,
PL2303_HXN_FLOWCTRL_NONE);
} else {
pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0);
}
}
kfree(buf);
@ -767,8 +839,14 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
usb_clear_halt(serial->dev, port->read_urb->pipe);
} else {
/* reset upstream data pipes */
pl2303_vendor_write(serial, 8, 0);
pl2303_vendor_write(serial, 9, 0);
if (spriv->type == &pl2303_type_data[TYPE_HXN]) {
pl2303_vendor_write(serial, PL2303_HXN_RESET_REG,
PL2303_HXN_RESET_UPSTREAM_PIPE |
PL2303_HXN_RESET_DOWNSTREAM_PIPE);
} else {
pl2303_vendor_write(serial, 8, 0);
pl2303_vendor_write(serial, 9, 0);
}
}
/* Setup termios */

View File

@ -9,6 +9,12 @@
#define PL2303_VENDOR_ID 0x067b
#define PL2303_PRODUCT_ID 0x2303
#define PL2303_PRODUCT_ID_TB 0x2304
#define PL2303_PRODUCT_ID_GC 0x23a3
#define PL2303_PRODUCT_ID_GB 0x23b3
#define PL2303_PRODUCT_ID_GT 0x23c3
#define PL2303_PRODUCT_ID_GL 0x23d3
#define PL2303_PRODUCT_ID_GE 0x23e3
#define PL2303_PRODUCT_ID_GS 0x23f3
#define PL2303_PRODUCT_ID_RSAQ2 0x04bb
#define PL2303_PRODUCT_ID_DCU11 0x1234
#define PL2303_PRODUCT_ID_PHAROS 0xaaa0