summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authorgavin <gavin@FreeBSD.org>2013-05-17 19:13:31 +0000
committergavin <gavin@FreeBSD.org>2013-05-17 19:13:31 +0000
commitc519844bb9454e15fd95b2f0cb9e9839aac5bc9c (patch)
treecf826ce9591e0ede0fff2e232cfac8fc684d6219 /sys/dev
parentd5c05f4a928a30d6ad1334e26d6890e038377c7c (diff)
downloadFreeBSD-src-c519844bb9454e15fd95b2f0cb9e9839aac5bc9c.zip
FreeBSD-src-c519844bb9454e15fd95b2f0cb9e9839aac5bc9c.tar.gz
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
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/usb/serial/uslcom.c68
1 files changed, 56 insertions, 12 deletions
diff --git a/sys/dev/usb/serial/uslcom.c b/sys/dev/usb/serial/uslcom.c
index d6fa4ec..69950f2 100644
--- a/sys/dev/usb/serial/uslcom.c
+++ b/sys/dev/usb/serial/uslcom.c
@@ -119,9 +119,17 @@ SYSCTL_INT(_hw_usb_uslcom, OID_AUTO, debug, CTLFLAG_RW,
#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_callback;
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, uint32_t cmd, caddr_t data,
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, uint32_t cmd, caddr_t data,
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:
OpenPOWER on IntegriCloud