Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 17 May 2013 19:13:31 +0000 (UTC)
From:      Gavin Atkinson <gavin@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r250749 - head/sys/dev/usb/serial
Message-ID:  <201305171913.r4HJDVXK082459@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: gavin
Date: Fri May 17 19:13:31 2013
New Revision: 250749
URL: http://svnweb.freebsd.org/changeset/base/250749

Log:
  o  Retrive the part number (CP2103 etc) from the hardware on attach.
  o  The CP2101 and CP2102 do not support GPIO pin use at all, enforce this.
  o  Support reading the GPIO status on the second port of the CP2105.  More
     work is needed before the CP2105 GPIO pins can be used as outputs.
  
  Hardware donated by:	Silicon Labs
  MFC after:		3 weeks

Modified:
  head/sys/dev/usb/serial/uslcom.c

Modified: head/sys/dev/usb/serial/uslcom.c
==============================================================================
--- head/sys/dev/usb/serial/uslcom.c	Fri May 17 19:02:36 2013	(r250748)
+++ head/sys/dev/usb/serial/uslcom.c	Fri May 17 19:13:31 2013	(r250749)
@@ -119,9 +119,17 @@ SYSCTL_INT(_hw_usb_uslcom, OID_AUTO, deb
 #define	USLCOM_FLOW_RTS_HS      0x00000080 /* RTS handshake */
 
 /* USLCOM_VENDOR_SPECIFIC values */
+#define	USLCOM_GET_PARTNUM	0x370B
 #define	USLCOM_WRITE_LATCH	0x37E1
 #define	USLCOM_READ_LATCH	0x00C2
 
+/* USLCOM_GET_PARTNUM values from hardware */
+#define	USLCOM_PARTNUM_CP2101	1
+#define	USLCOM_PARTNUM_CP2102	2
+#define	USLCOM_PARTNUM_CP2103	3
+#define	USLCOM_PARTNUM_CP2104	4
+#define	USLCOM_PARTNUM_CP2105	5
+
 enum {
 	USLCOM_BULK_DT_WR,
 	USLCOM_BULK_DT_RD,
@@ -141,6 +149,7 @@ struct uslcom_softc {
 	uint8_t		 sc_msr;
 	uint8_t		 sc_lsr;
 	uint8_t		 sc_iface_no;
+	uint8_t		 sc_partnum;
 };
 
 static device_probe_t uslcom_probe;
@@ -155,6 +164,7 @@ static usb_callback_t uslcom_control_cal
 static void	uslcom_free(struct ucom_softc *);
 static void uslcom_open(struct ucom_softc *);
 static void uslcom_close(struct ucom_softc *);
+static uint8_t uslcom_get_partnum(struct uslcom_softc *);
 static void uslcom_set_dtr(struct ucom_softc *, uint8_t);
 static void uslcom_set_rts(struct ucom_softc *, uint8_t);
 static void uslcom_set_break(struct ucom_softc *, uint8_t);
@@ -408,6 +418,8 @@ uslcom_attach(device_t dev)
 	usbd_xfer_set_stall(sc->sc_xfer[USLCOM_BULK_DT_RD]);
 	mtx_unlock(&sc->sc_mtx);
 
+	sc->sc_partnum = uslcom_get_partnum(sc);
+
 	error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc,
 	    &uslcom_callback, &sc->sc_mtx);
 	if (error) {
@@ -500,6 +512,28 @@ uslcom_close(struct ucom_softc *ucom)
 	}
 }
 
+static uint8_t
+uslcom_get_partnum(struct uslcom_softc *sc)
+{
+	struct usb_device_request req;
+	uint8_t partnum;
+
+	/* Find specific chip type */
+	partnum = 0;
+	req.bmRequestType = USLCOM_READ;
+	req.bRequest = USLCOM_VENDOR_SPECIFIC;
+	USETW(req.wValue, USLCOM_GET_PARTNUM);
+	USETW(req.wIndex, sc->sc_iface_no);
+	USETW(req.wLength, sizeof(partnum));
+
+	if (usbd_do_request_flags(sc->sc_udev, NULL,
+	    &req, &partnum, 0, NULL, 1000)) {
+		DPRINTF("GET_PARTNUM failed\n");
+	}
+
+	return(partnum);
+}
+
 static void
 uslcom_set_dtr(struct ucom_softc *ucom, uint8_t onoff)
 {
@@ -679,10 +713,14 @@ uslcom_ioctl(struct ucom_softc *ucom, ui
 
 	switch (cmd) {
 	case USB_GET_GPIO:
+		if (sc->sc_partnum < USLCOM_PARTNUM_CP2103) {
+			error = ENODEV;
+			break;
+		}
 		req.bmRequestType = USLCOM_READ;
 		req.bRequest = USLCOM_VENDOR_SPECIFIC;
 		USETW(req.wValue, USLCOM_READ_LATCH);
-		USETW(req.wIndex, 0);
+		USETW(req.wIndex, sc->sc_iface_no);
 		USETW(req.wLength, sizeof(latch));
 
 		if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 
@@ -694,17 +732,23 @@ uslcom_ioctl(struct ucom_softc *ucom, ui
 		break;
 
 	case USB_SET_GPIO:
-		req.bmRequestType = USLCOM_WRITE;
-		req.bRequest = USLCOM_VENDOR_SPECIFIC;
-		USETW(req.wValue, USLCOM_WRITE_LATCH);
-		USETW(req.wIndex, (*(int *)data));
-		USETW(req.wLength, 0);
-		
-		if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 
-		    &req, NULL, 0, 1000)) {
-			DPRINTF("Set LATCH failed\n");
-			error = EIO;
-		}
+		if (sc->sc_partnum < USLCOM_PARTNUM_CP2103)
+			error = ENODEV;
+		else if ((sc->sc_partnum == USLCOM_PARTNUM_CP2103) ||
+		    (sc->sc_partnum == USLCOM_PARTNUM_CP2104)) {
+			req.bmRequestType = USLCOM_WRITE;
+			req.bRequest = USLCOM_VENDOR_SPECIFIC;
+			USETW(req.wValue, USLCOM_WRITE_LATCH);
+			USETW(req.wIndex, (*(int *)data));
+			USETW(req.wLength, 0);
+
+			if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom, 
+			    &req, NULL, 0, 1000)) {
+				DPRINTF("Set LATCH failed\n");
+				error = EIO;
+			}
+		} else
+			error = ENODEV;	/* Not yet */
 		break;
 
 	default:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201305171913.r4HJDVXK082459>