summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohan Hovold <johan@kernel.org>2021-03-11 19:14:47 +0300
committerJohan Hovold <johan@kernel.org>2021-03-17 11:16:19 +0300
commite5f48c812679ff46c8fe5e0c4a9f2881cb56ea1a (patch)
tree58dd22850513f54ac462bb7e6e565b6b74ed924a
parent8747fb3b14dda3a3e8f934ceb8beab9bd34d927e (diff)
downloadlinux-e5f48c812679ff46c8fe5e0c4a9f2881cb56ea1a.tar.xz
USB: serial: pl2303: clean up type detection
Clean up the type detection somewhat in preparation for adding support for more types. Note this also fixes the type debug printk for the new HXN type. Signed-off-by: Johan Hovold <johan@kernel.org>
-rw-r--r--drivers/usb/serial/pl2303.c68
1 files changed, 42 insertions, 26 deletions
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index eed9acd1ae08..db840b471adb 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -362,42 +362,52 @@ static int pl2303_calc_num_ports(struct usb_serial *serial,
return 1;
}
+static enum pl2303_type pl2303_detect_type(struct usb_serial *serial)
+{
+ struct usb_device_descriptor *desc = &serial->dev->descriptor;
+ int ret;
+ u8 buf;
+
+ /*
+ * Legacy types 0 and 1, difference unknown.
+ */
+ if (desc->bDeviceClass == 0x02)
+ return TYPE_01; /* type 0 */
+
+ if (desc->bMaxPacketSize0 != 0x40) {
+ if (desc->bDeviceClass == 0x00 || desc->bDeviceClass == 0xff)
+ return TYPE_01; /* type 1 */
+
+ return TYPE_01; /* type 0 */
+ }
+
+ /*
+ * Assume it's an HXN-type if the device doesn't support the old read
+ * request value.
+ */
+ ret = usb_control_msg_recv(serial->dev, 0, VENDOR_READ_REQUEST,
+ VENDOR_READ_REQUEST_TYPE, PL2303_READ_TYPE_HX_STATUS,
+ 0, &buf, 1, 100, GFP_KERNEL);
+ if (ret)
+ return TYPE_HXN;
+
+ return TYPE_HX;
+}
+
static int pl2303_startup(struct usb_serial *serial)
{
struct pl2303_serial_private *spriv;
- enum pl2303_type type = TYPE_01;
+ enum pl2303_type type;
unsigned char *buf;
- int res;
spriv = kzalloc(sizeof(*spriv), GFP_KERNEL);
if (!spriv)
return -ENOMEM;
- buf = kmalloc(1, GFP_KERNEL);
- if (!buf) {
- kfree(spriv);
- return -ENOMEM;
- }
+ type = pl2303_detect_type(serial);
- if (serial->dev->descriptor.bDeviceClass == 0x02)
- type = TYPE_01; /* type 0 */
- else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
- type = TYPE_HX;
- else if (serial->dev->descriptor.bDeviceClass == 0x00)
- type = TYPE_01; /* type 1 */
- else if (serial->dev->descriptor.bDeviceClass == 0xFF)
- 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;
@@ -405,6 +415,12 @@ static int pl2303_startup(struct usb_serial *serial)
usb_set_serial_data(serial, spriv);
if (type != TYPE_HXN) {
+ buf = kmalloc(1, GFP_KERNEL);
+ if (!buf) {
+ kfree(spriv);
+ return -ENOMEM;
+ }
+
pl2303_vendor_read(serial, 0x8484, buf);
pl2303_vendor_write(serial, 0x0404, 0);
pl2303_vendor_read(serial, 0x8484, buf);
@@ -419,9 +435,9 @@ static int pl2303_startup(struct usb_serial *serial)
pl2303_vendor_write(serial, 2, 0x24);
else
pl2303_vendor_write(serial, 2, 0x44);
- }
- kfree(buf);
+ kfree(buf);
+ }
return 0;
}