提交 114aa0a1 编写于 作者: J Johan Hovold 提交者: Zheng Zengkai

USB: serial: cp210x: fix dropped characters with CP2102

stable inclusion
from stable-5.10.70
commit 8373d58c89be9406f64f8facb311ab10b97cd026
bugzilla: 182949 https://gitee.com/openeuler/kernel/issues/I4I3GQ

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=8373d58c89be9406f64f8facb311ab10b97cd026

--------------------------------

commit c32dfec6 upstream.

Some CP2102 do not support event-insertion mode but return no error when
attempting to enable it.

This means that any event escape characters in the input stream will not
be escaped by the device and consequently regular data may be
interpreted as escape sequences and be removed from the stream by the
driver.

The reporter's device has batch number DCL00X etched into it and as
discovered by the SHA2017 Badge team, counterfeit devices with that
marking can be detected by sending malformed vendor requests. [1][2]

Tests confirm that the possibly counterfeit CP2102 returns a single byte
in response to a malformed two-byte part-number request, while an
original CP2102 returns two bytes. Assume that every CP2102 that behaves
this way also does not support event-insertion mode (e.g. cannot report
parity errors).

[1] https://mobile.twitter.com/sha2017badge/status/1167902087289532418
[2] https://hackaday.com/2017/08/14/hands-on-with-the-shacamp-2017-badge/#comment-3903376Reported-by: NMalte Di Donato <malte@neo-soft.org>
Tested-by: NMalte Di Donato <malte@neo-soft.org>
Fixes: a7207e98 ("USB: serial: cp210x: add support for line-status events")
Cc: stable@vger.kernel.org	# 5.9
Link: https://lore.kernel.org/r/20210922113100.20888-1-johan@kernel.orgSigned-off-by: NJohan Hovold <johan@kernel.org>
Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: NChen Jun <chenjun102@huawei.com>
Acked-by: NWeilong Chen <chenweilong@huawei.com>
Signed-off-by: NChen Jun <chenjun102@huawei.com>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
上级 b8372221
...@@ -261,6 +261,7 @@ struct cp210x_serial_private { ...@@ -261,6 +261,7 @@ struct cp210x_serial_private {
speed_t min_speed; speed_t min_speed;
speed_t max_speed; speed_t max_speed;
bool use_actual_rate; bool use_actual_rate;
bool no_event_mode;
}; };
enum cp210x_event_state { enum cp210x_event_state {
...@@ -1332,12 +1333,16 @@ static void cp210x_change_speed(struct tty_struct *tty, ...@@ -1332,12 +1333,16 @@ static void cp210x_change_speed(struct tty_struct *tty,
static void cp210x_enable_event_mode(struct usb_serial_port *port) static void cp210x_enable_event_mode(struct usb_serial_port *port)
{ {
struct cp210x_serial_private *priv = usb_get_serial_data(port->serial);
struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
int ret; int ret;
if (port_priv->event_mode) if (port_priv->event_mode)
return; return;
if (priv->no_event_mode)
return;
port_priv->event_state = ES_DATA; port_priv->event_state = ES_DATA;
port_priv->event_mode = true; port_priv->event_mode = true;
...@@ -2087,6 +2092,46 @@ static void cp210x_init_max_speed(struct usb_serial *serial) ...@@ -2087,6 +2092,46 @@ static void cp210x_init_max_speed(struct usb_serial *serial)
priv->use_actual_rate = use_actual_rate; priv->use_actual_rate = use_actual_rate;
} }
static void cp2102_determine_quirks(struct usb_serial *serial)
{
struct cp210x_serial_private *priv = usb_get_serial_data(serial);
u8 *buf;
int ret;
buf = kmalloc(2, GFP_KERNEL);
if (!buf)
return;
/*
* Some (possibly counterfeit) CP2102 do not support event-insertion
* mode and respond differently to malformed vendor requests.
* Specifically, they return one instead of two bytes when sent a
* two-byte part-number request.
*/
ret = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
CP210X_VENDOR_SPECIFIC, REQTYPE_DEVICE_TO_HOST,
CP210X_GET_PARTNUM, 0, buf, 2, USB_CTRL_GET_TIMEOUT);
if (ret == 1) {
dev_dbg(&serial->interface->dev,
"device does not support event-insertion mode\n");
priv->no_event_mode = true;
}
kfree(buf);
}
static void cp210x_determine_quirks(struct usb_serial *serial)
{
struct cp210x_serial_private *priv = usb_get_serial_data(serial);
switch (priv->partnum) {
case CP210X_PARTNUM_CP2102:
cp2102_determine_quirks(serial);
break;
default:
break;
}
}
static int cp210x_attach(struct usb_serial *serial) static int cp210x_attach(struct usb_serial *serial)
{ {
int result; int result;
...@@ -2107,6 +2152,7 @@ static int cp210x_attach(struct usb_serial *serial) ...@@ -2107,6 +2152,7 @@ static int cp210x_attach(struct usb_serial *serial)
usb_set_serial_data(serial, priv); usb_set_serial_data(serial, priv);
cp210x_determine_quirks(serial);
cp210x_init_max_speed(serial); cp210x_init_max_speed(serial);
result = cp210x_gpio_init(serial); result = cp210x_gpio_init(serial);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册