[PATCH] Better chips distinguishing code for uplcom(4)

Hasso Tepper hasso at estpak.ee
Sat Jul 28 05:44:46 PDT 2007


# HG changeset patch
# User Hasso Tepper <hasso at estpak.ee>
# Date 1185626194 -10800
# Branch HEAD
# Node ID e934355abc88da7910c99487c22d12e2c021dfd6
# Parent  f7c2990c9f78edd4b38694bcfa1a17f66182c35d
Better chips distinguishing code for uplcom(4).

Kill current method to distinguish between old PL-2303(H) and newer
PL-2303(H)X chips. Instead of managing list try as hard as possible to
make it automatic: look at known device release numbers at first and if
it fails, try to determine chip via looking at other fields (magic values
borrowed from Linux driver) in the device descriptor.

diff --git a/sys/dev/usbmisc/uplcom/uplcom.c b/sys/dev/usbmisc/uplcom/uplcom.c
--- a/sys/dev/usbmisc/uplcom/uplcom.c
+++ b/sys/dev/usbmisc/uplcom/uplcom.c
@@ -68,15 +68,16 @@
 
 /*
  * This driver supports several USB-to-RS232 serial adapters driven by
- * Prolific PL-2303, PL-2303X and probably PL-2303HX USB-to-RS232
- * bridge chip.  The adapters are sold under many different brand
- * names.
+ * Prolific PL-2303 (known also as PL-2303H), PL-2303X and PL-2303HX
+ * USB-to-RS232 bridge chip. The adapters are sold under many different
+ * brand names.
  *
  * Datasheets are available at Prolific www site at
  * http://www.prolific.com.tw.  The datasheets don't contain full
  * programming information for the chip.
  *
- * PL-2303HX is probably programmed the same as PL-2303X.
+ * PL-2303HX has the same features as PL-2303X (at least from the point of
+ * view of device driver) but is pin-to-pin compatible with PL-2303.
  *
  * There are several differences between PL-2303 and PL-2303(H)X.
  * PL-2303(H)X can do higher bitrate in bulk mode, has _probably_
@@ -144,6 +145,10 @@ SYSCTL_INT(_hw_usb_uplcom, OID_AUTO, deb
 #define RSAQ_STATUS_DSR			0x02
 #define RSAQ_STATUS_DCD			0x01
 
+#define CHIP_PL2303			0x0202
+#define CHIP_PL2303X			0x0300
+#define CHIP_PL2303HX			0x0400
+
 #define TYPE_PL2303			0
 #define TYPE_PL2303X			1
 
@@ -209,60 +214,42 @@ struct ucom_callback uplcom_callback = {
 	NULL
 };
 
-static const struct uplcom_product {
-	uint16_t	vendor;
-	uint16_t	product;
-	int32_t		release;	 /* release is a 16bit entity,
-					  * if -1 is specified we "don't care"
-					  * This is a floor value.  The table
-					  * must have newer revs before older
-					  * revs (and -1 last).
-					  */
-	char		chiptype;
-} uplcom_products [] = {
-	{ USB_VENDOR_RADIOSHACK, USB_PRODUCT_RADIOSHACK_USBCABLE, -1, TYPE_PL2303 },
+static const struct usb_devno uplcom_devs[] = {
+	{ USB_VENDOR_RADIOSHACK, USB_PRODUCT_RADIOSHACK_USBCABLE },
 
 	/* I/O DATA USB-RSAQ */
-	{ USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBRSAQ, -1, TYPE_PL2303 },
+	{ USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBRSAQ },
 	/* Prolific Pharos */
-	{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303X, -1, TYPE_PL2303 },
+	{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303X },
 	/* I/O DATA USB-RSAQ2 */
-	{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ2, -1, TYPE_PL2303 },
+	{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ2 },
 	/* I/O DATA USB-RSAQ3 */
-	{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ3, -1, TYPE_PL2303X },
+	{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ3 },
 	/* Willcom W-SIM */
-	{ USB_VENDOR_PROLIFIC2, USB_PRODUCT_PROLIFIC2_WSIM, -1, TYPE_PL2303X},
+	{ USB_VENDOR_PROLIFIC2, USB_PRODUCT_PROLIFIC2_WSIM },
 	/* PLANEX USB-RS232 URS-03 */
-	{ USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC232A, -1, TYPE_PL2303 },
-	/* ST Lab USB-SERIAL-4 */
-	{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303,
-	  0x300, TYPE_PL2303X },
-	/* IOGEAR/ATEN UC-232A (also ST Lab USB-SERIAL-1) */
-	{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303, -1, TYPE_PL2303 },
-	/* HAMLET exagerate XURS232 */
-	{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303, -1, TYPE_PL2303X },
+	{ USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC232A },
+	/* IOGEAR/ATEN UC-232A, ST Lab USB-SERIAL-X etc */
+	{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303 },
 	/* TDK USB-PHS Adapter UHA6400 */
-	{ USB_VENDOR_TDK, USB_PRODUCT_TDK_UHA6400, -1, TYPE_PL2303 },
+	{ USB_VENDOR_TDK, USB_PRODUCT_TDK_UHA6400 },
 	/* RATOC REX-USB60 */
-	{ USB_VENDOR_RATOC, USB_PRODUCT_RATOC_REXUSB60, -1, TYPE_PL2303 },
+	{ USB_VENDOR_RATOC, USB_PRODUCT_RATOC_REXUSB60 },
 	/* ELECOM UC-SGT */
-	{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT, -1, TYPE_PL2303 },
-	{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT0, -1, TYPE_PL2303 },
+	{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT },
+	{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT0 },
 	/* Sony Ericsson USB Cable */
-	{ USB_VENDOR_SONYERICSSON, USB_PRODUCT_SONYERICSSON_DCU10,
-	  -1,TYPE_PL2303 },
+	{ USB_VENDOR_SONYERICSSON, USB_PRODUCT_SONYERICSSON_DCU10 },
 	/* SOURCENEXT KeikaiDenwa 8 */
-	{ USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8,
-	  -1, TYPE_PL2303 },
+	{ USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8 },
 	/* SOURCENEXT KeikaiDenwa 8 with charger */
-	{ USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8_CHG,
-	  -1, TYPE_PL2303 },
+	{ USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8_CHG },
 	/* HAL Corporation Crossam2+USB */
-	{ USB_VENDOR_HAL, USB_PRODUCT_HAL_IMR001, -1, TYPE_PL2303 },
+	{ USB_VENDOR_HAL, USB_PRODUCT_HAL_IMR001 },
 	/* Sitecom USB to Serial */
-	{ USB_VENDOR_MCT, USB_PRODUCT_MCT_SITECOM_USB232, -1, TYPE_PL2303 },
+	{ USB_VENDOR_MCT, USB_PRODUCT_MCT_SITECOM_USB232 },
 	/* Tripp-Lite U209-000-R */
-	{ USB_VENDOR_TRIPPLITE, USB_PRODUCT_TRIPPLITE_U209, -1, TYPE_PL2303X },
+	{ USB_VENDOR_TRIPPLITE, USB_PRODUCT_TRIPPLITE_U209 },
 	{ 0, 0 }
 };
 
@@ -316,20 +303,12 @@ uplcom_match(device_t self)
 uplcom_match(device_t self)
 {
 	struct usb_attach_arg *uaa = device_get_ivars(self);
-	int i;
 
 	if (uaa->iface != NULL)
 		return (UMATCH_NONE);
 
-	for (i = 0; uplcom_products[i].vendor != 0; i++) {
-		if (uplcom_products[i].vendor == uaa->vendor &&
-		    uplcom_products[i].product == uaa->product &&
-		    (uplcom_products[i].release <= uaa->release ||
-		     uplcom_products[i].release == -1)) {
-			return (UMATCH_VENDOR_PRODUCT);
-		}
-	}
-	return (UMATCH_NONE);
+	return (usb_lookup(uplcom_devs, uaa->vendor, uaa->product) != NULL ?
+		UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
 }
 
 static int
@@ -338,6 +317,7 @@ uplcom_attach(device_t self)
 	struct uplcom_softc *sc = device_get_softc(self);
 	struct usb_attach_arg *uaa = device_get_ivars(self);
 	usbd_device_handle dev = uaa->device;
+	usb_device_descriptor_t *dd;
 	struct ucom_softc *ucom;
 	usb_config_descriptor_t *cdesc;
 	usb_interface_descriptor_t *id;
@@ -364,35 +344,61 @@ uplcom_attach(device_t self)
 
 	DPRINTF(("uplcom attach: sc = %p\n", sc));
 
-	/* determine chip type */
-	for (i = 0; uplcom_products[i].vendor != 0; i++) {
-		if (uplcom_products[i].vendor == uaa->vendor &&
-		    uplcom_products[i].product == uaa->product &&
-		    (uplcom_products[i].release == uaa->release ||
-		     uplcom_products[i].release == -1)) {
-			sc->sc_chiptype = uplcom_products[i].chiptype;
-			break;
-		}
-	}
+	dd = usbd_get_device_descriptor(uaa->device);
+
+	if (!dd)
+		goto error;
 
 	/*
-	 * check we found the device - attach should have ensured we
-	 * don't get here without matching device
+	 * Determine chip type. At first we try to match known device
+	 * release numbers.
 	 */
-	if (uplcom_products[i].vendor == 0) {
-		kprintf("%s: didn't match\n", devname);
-		ucom->sc_dying = 1;
-		goto error;
-	}
-
+	if (UGETW(dd->bcdDevice) == CHIP_PL2303HX) {
+		sc->sc_chiptype = TYPE_PL2303X;
 #ifdef USB_DEBUG
-	/* print the chip type */
-	if (sc->sc_chiptype == TYPE_PL2303X) {
-		DPRINTF(("uplcom_attach: chiptype 2303X\n"));
-	} else {
-		DPRINTF(("uplcom_attach: chiptype 2303\n"));
-	}
+		DPRINTF(("uplcom_attach: chiptype PL-2303HX (rev D)\n"));
 #endif
+	}
+	else if (UGETW(dd->bcdDevice) == CHIP_PL2303X) {
+		sc->sc_chiptype = TYPE_PL2303X;
+#ifdef USB_DEBUG
+		DPRINTF(("uplcom_attach: chiptype PL-2303X or" \
+			 " PL-2303HX (rev A)\n"));
+#endif
+	}
+	else if (UGETW(dd->bcdDevice) == CHIP_PL2303) {
+		sc->sc_chiptype = TYPE_PL2303;
+#ifdef USB_DEBUG
+		DPRINTF(("uplcom_attach: chiptype PL-2303 (rel 2.02)\n"));
+#endif
+	}
+	/*
+	 * If it doesn't work, try matching sequence Linux driver uses
+	 * (device release number in chip could be replaced by the contents
+	 * of external EEPROM). As I don't have access to any adequate old
+	 * PL-2303 datasheet, I can't comment how bulletproof it is.
+	 *
+	 * FIXME Fix it if more info will appear.
+	 */
+	else if (dd->bDeviceClass == 0x02) {
+		sc->sc_chiptype = TYPE_PL2303;
+#ifdef USB_DEBUG
+		DPRINTF(("uplcom_attach: chiptype PL-2303\n"));
+#endif
+	}
+	else if (dd->bMaxPacketSize == 0x40) {
+		sc->sc_chiptype = TYPE_PL2303X;
+#ifdef USB_DEBUG
+		DPRINTF(("uplcom_attach: chiptype PL-2303(H)X\n"));
+#endif
+	}
+	/* Fallback to PL-2303. */
+	else {
+		sc->sc_chiptype = TYPE_PL2303;
+#ifdef USB_DEBUG
+		DPRINTF(("uplcom_attach: fallback to chiptype PL-2303\n"));
+#endif
+	}
 
 	/* initialize endpoints */
 	ucom->sc_bulkin_no = ucom->sc_bulkout_no = -1;





More information about the Submit mailing list