USB: serial: pl2303: amend device-type detection
Subsystems (2)
Johan Hovold
maintainercover USB: serial: pl2303: amend device-type detection
This series cleans up, amends and tightens the pl2303 device-type detection.
There are number of different PL2303 devices out there with various features and we need to be able to detect more types reliably.
Specifically this will be used to add support for the alternate divisor encoding scheme that is used by TA devices.
Johan
Johan Hovold (5):
USB: serial: pl2303: clean up type detection
USB: serial: pl2303: amend and tighten type detection
USB: serial: pl2303: rename legacy PL2303H type
USB: serial: pl2303: tighten type HXN (G) detection
USB: serial: pl2303: add device-type names
drivers/usb/serial/pl2303.c | 131 +++++++++++++++++++++++++++--------- 1 file changed, 98 insertions(+), 33 deletions(-)
Signature · 1 line
2.26.2
Johan Hovold
maintainerPATCH 1/5 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.
--- drivers/usb/serial/pl2303.c | 68 +++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 26 deletions(-)
drivers/usb/serial/pl2303.c +42 -26
@@ -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 ; }
Signature · 1 line
2.26.2
Johan Hovold
maintainerPATCH 2/5 USB: serial: pl2303: amend and tighten type detection
In reply to Johan HovoldAdd support for detecting the HX, TA, TB and HXD device types and refuse to bind to any unknown types.
Note that the HX type includes the XA variant, while the HXD type includes the EA, RA and SA variants.
--- drivers/usb/serial/pl2303.c | 50 +++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 8 deletions(-)
drivers/usb/serial/pl2303.c +42 -8
@@ -174,8 +174,11 @@ 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_HX , +TYPE_TA , +TYPE_TB , +TYPE_HXD , +TYPE_HXN ,TYPE_COUNT };
@@ -206,6 +209,15 @@ static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = { .no_autoxonxoff = true, }, [TYPE_HX] = { + .max_baud_rate = 6000000, + }, + [TYPE_TA] = { + .max_baud_rate = 6000000, + }, + [TYPE_TB] = { + .max_baud_rate = 12000000, + }, + [TYPE_HXD] = { .max_baud_rate = 12000000, }, [TYPE_HXN] = {
@@ -362,9 +374,10 @@ static int pl2303_calc_num_ports(struct usb_serial *serial,return 1 ; } -static enum pl2303_type pl2303_detect_type (struct usb_serial *serial) +static int pl2303_detect_type (struct usb_serial *serial) {struct usb_device_descriptor *desc = &serial->dev->descriptor; +u16 bcdDevice, bcdUSB;int ret;u8 buf;
@@ -391,7 +404,24 @@ static enum pl2303_type pl2303_detect_type(struct usb_serial *serial)if (ret)return TYPE_HXN ; -return TYPE_HX ; + bcdDevice =le16_to_cpu (desc->bcdDevice); + bcdUSB =le16_to_cpu (desc->bcdUSB); + +switch (bcdDevice) { +case 0x300 : +if (bcdUSB ==0x200 ) +return TYPE_TA ; + +return TYPE_HX ; +case 0x400 : +return TYPE_HXD ; +case 0x500 : +return TYPE_TB ; + } + +dev_err (&serial->interface->dev, +"unknown device type, please report to [email protected]\n" ); +return -ENODEV ; }static int pl2303_startup (struct usb_serial *serial)
@@ -399,15 +429,19 @@ static int pl2303_startup(struct usb_serial *serial)struct pl2303_serial_private *spriv;enum pl2303_type type;unsigned char *buf; +int ret; + + ret =pl2303_detect_type (serial); +if (ret <0 ) +return ret; + + type = ret; +dev_dbg (&serial->interface->dev,"device type: %d\n" , type); spriv =kzalloc (sizeof (*spriv),GFP_KERNEL );if (!spriv)return -ENOMEM ; - type =pl2303_detect_type (serial); - -dev_dbg (&serial->interface->dev,"device type: %d\n" , type); - spriv->type = &pl2303_type_data[type]; spriv->quirks = (unsigned long )usb_get_serial_data (serial); spriv->quirks |= spriv->type->quirks;
Signature · 1 line
2.26.2
Johan Hovold
maintainerPATCH 3/5 USB: serial: pl2303: rename legacy PL2303H type
In reply to Johan HovoldRename the legacy type which is supposedly a PL2303H which came in two variants (and which we handle the same way).
--- drivers/usb/serial/pl2303.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/usb/serial/pl2303.c +6 -6
@@ -173,7 +173,7 @@ MODULE_DEVICE_TABLE(usb, id_table);static void pl2303_set_break (struct usb_serial_port *port,bool enable);enum pl2303_type { -TYPE_01 ,/* Type 0 and 1 (difference unknown) */ +TYPE_H ,TYPE_HX ,TYPE_TA ,TYPE_TB ,
@@ -203,7 +203,7 @@ struct pl2303_private { };static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT ] = { - [TYPE_01 ] = { + [TYPE_H ] = { .max_baud_rate =1228800 , .quirks =PL2303_QUIRK_LEGACY , .no_autoxonxoff = true,
@@ -382,16 +382,16 @@ static int pl2303_detect_type(struct usb_serial *serial)u8 buf;/* -* Legacy types 0 and 1, difference unknown. +* Legacy PL2303H, variants 0 and 1 (difference unknown). */ if (desc->bDeviceClass ==0x02 ) -return TYPE_01 ;/* type 0 */ +return TYPE_H ;/* variant 0 */ if (desc->bMaxPacketSize0 !=0x40 ) {if (desc->bDeviceClass ==0x00 || desc->bDeviceClass ==0xff ) -return TYPE_01 ;/* type 1 */ +return TYPE_H ;/* variant 1 */ -return TYPE_01 ;/* type 0 */ +return TYPE_H ;/* variant 0 */ }/*
Signature · 1 line
2.26.2
Johan Hovold
maintainerPATCH 4/5 USB: serial: pl2303: tighten type HXN (G) detection
In reply to Johan HovoldTighten the detection of the new HXN (G) type instead of assuming that every device which doesn't support the old read request is an HXN.
--- drivers/usb/serial/pl2303.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-)
drivers/usb/serial/pl2303.c +20 -12
@@ -374,12 +374,22 @@ static int pl2303_calc_num_ports(struct usb_serial *serial,return 1 ; } +static bool pl2303_supports_hx_status (struct usb_serial *serial) +{ +int ret; +u8 buf; + + 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 ); + +return ret ==0 ; +} +static int pl2303_detect_type (struct usb_serial *serial) {struct usb_device_descriptor *desc = &serial->dev->descriptor;u16 bcdDevice, bcdUSB; -int ret; -u8 buf;/* * Legacy PL2303H, variants 0 and 1 (difference unknown).
@@ -394,20 +404,18 @@ static int pl2303_detect_type(struct usb_serial *serial)return TYPE_H ;/* variant 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 ; - bcdDevice =le16_to_cpu (desc->bcdDevice); bcdUSB =le16_to_cpu (desc->bcdUSB);switch (bcdDevice) { +case 0x100 : +/* +* Assume it's an HXN-type if the device doesn't support the old read +* request value. +*/ +if (bcdUSB ==0x200 && !pl2303_supports_hx_status (serial)) +return TYPE_HXN ; +break ;case 0x300 :if (bcdUSB ==0x200 )return TYPE_TA ;
Signature · 1 line
2.26.2
Johan Hovold
maintainerPATCH 5/5 USB: serial: pl2303: add device-type names
In reply to Johan HovoldAdd names for the device types to be printed at probe when debugging is enabled.
Note that the HXN type is referred to as G for now as that is the name the vendor uses.
--- drivers/usb/serial/pl2303.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/usb/serial/pl2303.c +8 -1
@@ -183,6 +183,7 @@ enum pl2303_type { };struct pl2303_type_data { +const char *name;speed_t max_baud_rate;unsigned long quirks;unsigned int no_autoxonxoff:1 ;
@@ -204,23 +205,29 @@ struct pl2303_private {static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT ] = { [TYPE_H ] = { + .name ="H" , .max_baud_rate =1228800 , .quirks =PL2303_QUIRK_LEGACY , .no_autoxonxoff = true, }, [TYPE_HX ] = { + .name ="HX" , .max_baud_rate =6000000 , }, [TYPE_TA ] = { + .name ="TA" , .max_baud_rate =6000000 , }, [TYPE_TB ] = { + .name ="TB" , .max_baud_rate =12000000 , }, [TYPE_HXD ] = { + .name ="HXD" , .max_baud_rate =12000000 , }, [TYPE_HXN ] = { + .name ="G" , .max_baud_rate =12000000 , .no_divisors = true, },
@@ -444,7 +451,7 @@ static int pl2303_startup(struct usb_serial *serial)return ret; type = ret; -dev_dbg (&serial->interface->dev,"device type: %d\n" , type); +dev_dbg (&serial->interface->dev,"device type: %s\n" , pl2303_type_data[type].name); spriv =kzalloc (sizeof (*spriv),GFP_KERNEL );if (!spriv)
Signature · 1 line
2.26.2