[PATCH 06/29] USB: serial: pl2303: clean up legacy endpoint hack

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Implement the "horrible endpoint hack" for some legacy devices as a
quirk and clean up the code somewhat.

Note that the bulk-endpoint check can be removed as core will already
have verified this.

Signed-off-by: Johan Hovold <johan@xxxxxxxxxx>
---
 drivers/usb/serial/pl2303.c | 84 +++++++++++++++++++++++++--------------------
 1 file changed, 46 insertions(+), 38 deletions(-)

diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index b8edd7bc71f2..c9ebefd8f35f 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -33,9 +33,11 @@
 
 #define PL2303_QUIRK_UART_STATE_IDX0		BIT(0)
 #define PL2303_QUIRK_LEGACY			BIT(1)
+#define PL2303_QUIRK_ENDPOINT_HACK		BIT(2)
 
 static const struct usb_device_id id_table[] = {
-	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
+	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID),
+		.driver_info = PL2303_QUIRK_ENDPOINT_HACK },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
@@ -48,7 +50,8 @@ static const struct usb_device_id id_table[] = {
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ZTEK) },
 	{ 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) },
+	{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID),
+		.driver_info = PL2303_QUIRK_ENDPOINT_HACK },
 	{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID2) },
 	{ USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
 	{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
@@ -68,7 +71,8 @@ static const struct usb_device_id id_table[] = {
 		.driver_info = PL2303_QUIRK_UART_STATE_IDX0 },
 	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75),
 		.driver_info = PL2303_QUIRK_UART_STATE_IDX0 },
-	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
+	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81),
+		.driver_info = PL2303_QUIRK_ENDPOINT_HACK },
 	{ USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */
 	{ USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
 	{ USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
@@ -78,7 +82,8 @@ static const struct usb_device_id id_table[] = {
 	{ USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
 	{ USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
 	{ USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
-	{ USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
+	{ USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID),
+		.driver_info = PL2303_QUIRK_ENDPOINT_HACK },
 	{ USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
 	{ USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
 	{ USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
@@ -218,7 +223,12 @@ static int pl2303_probe(struct usb_serial *serial,
 	return 0;
 }
 
-static int pl2303_calc_num_ports(struct usb_serial *serial,
+/*
+ * Use interrupt endpoint from first interface if available.
+ *
+ * This is needed due to the looney way its endpoints are set up.
+ */
+static int pl2303_endpoint_hack(struct usb_serial *serial,
 					struct usb_serial_endpoints *epds)
 {
 	struct usb_interface *interface = serial->interface;
@@ -228,43 +238,41 @@ static int pl2303_calc_num_ports(struct usb_serial *serial,
 	struct usb_endpoint_descriptor *endpoint;
 	unsigned int i;
 
-	/* BEGIN HORRIBLE HACK FOR PL2303 */
-	/* this is needed due to the looney way its endpoints are set up */
-	if (((le16_to_cpu(dev->descriptor.idVendor) == PL2303_VENDOR_ID) &&
-	     (le16_to_cpu(dev->descriptor.idProduct) == PL2303_PRODUCT_ID)) ||
-	    ((le16_to_cpu(dev->descriptor.idVendor) == ATEN_VENDOR_ID) &&
-	     (le16_to_cpu(dev->descriptor.idProduct) == ATEN_PRODUCT_ID)) ||
-	    ((le16_to_cpu(dev->descriptor.idVendor) == ALCOR_VENDOR_ID) &&
-	     (le16_to_cpu(dev->descriptor.idProduct) == ALCOR_PRODUCT_ID)) ||
-	    ((le16_to_cpu(dev->descriptor.idVendor) == SIEMENS_VENDOR_ID) &&
-	     (le16_to_cpu(dev->descriptor.idProduct) == SIEMENS_PRODUCT_ID_EF81))) {
-		if (interface != dev->actconfig->interface[0]) {
-			/* check out the endpoints of the other interface*/
-			iface_desc = dev->actconfig->interface[0]->cur_altsetting;
-			for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
-				endpoint = &iface_desc->endpoint[i].desc;
-				if (usb_endpoint_is_int_in(endpoint)) {
-					/* we found a interrupt in endpoint */
-					dev_dbg(ddev, "found interrupt in for Prolific device on separate interface\n");
-					if (epds->num_interrupt_in < ARRAY_SIZE(epds->interrupt_in))
-						epds->interrupt_in[epds->num_interrupt_in++] = endpoint;
-				}
-			}
-		}
+	if (interface == dev->actconfig->interface[0])
+		return 0;
 
-		/* Now make sure the PL-2303 is configured correctly.
-		 * If not, give up now and hope this hack will work
-		 * properly during a later invocation of usb_serial_probe
-		 */
-		if (epds->num_bulk_in == 0 || epds->num_bulk_out == 0) {
-			dev_info(ddev, "PL-2303 hack: descriptors matched but endpoints did not\n");
-			return -ENODEV;
-		}
+	/* check out the endpoints of the other interface */
+	iface_desc = dev->actconfig->interface[0]->cur_altsetting;
+
+	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+		endpoint = &iface_desc->endpoint[i].desc;
+
+		if (!usb_endpoint_is_int_in(endpoint))
+			continue;
+
+		dev_dbg(ddev, "found interrupt in on separate interface\n");
+		if (epds->num_interrupt_in < ARRAY_SIZE(epds->interrupt_in))
+			epds->interrupt_in[epds->num_interrupt_in++] = endpoint;
+	}
+
+	return 0;
+}
+
+static int pl2303_calc_num_ports(struct usb_serial *serial,
+					struct usb_serial_endpoints *epds)
+{
+	unsigned long quirks = (unsigned long)usb_get_serial_data(serial);
+	struct device *dev = &serial->interface->dev;
+	int ret;
+
+	if (quirks & PL2303_QUIRK_ENDPOINT_HACK) {
+		ret = pl2303_endpoint_hack(serial, epds);
+		if (ret)
+			return ret;
 	}
-	/* END HORRIBLE HACK FOR PL2303 */
 
 	if (epds->num_interrupt_in < 1) {
-		dev_err(ddev, "required interrupt-in endpoint missing\n");
+		dev_err(dev, "required interrupt-in endpoint missing\n");
 		return -ENODEV;
 	}
 
-- 
2.12.0

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux