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:
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to