|
@@ -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;
|
|
|
}
|
|
|
|