summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/serial
diff options
context:
space:
mode:
authorian <ian@FreeBSD.org>2015-08-06 19:29:26 +0000
committerian <ian@FreeBSD.org>2015-08-06 19:29:26 +0000
commit9f97d12240da60d94cc4ef7f0e1ea32f0fe7fe33 (patch)
tree917bc12a577272656f6396186241e7613b1ad140 /sys/dev/usb/serial
parentcb8b7b20d877054461c450d19c4a131dc73aa3f6 (diff)
downloadFreeBSD-src-9f97d12240da60d94cc4ef7f0e1ea32f0fe7fe33.zip
FreeBSD-src-9f97d12240da60d94cc4ef7f0e1ea32f0fe7fe33.tar.gz
Add support to the uftdi driver for reading and writing the serial eeprom
that can be attached to the chips, via ioctl() calls.
Diffstat (limited to 'sys/dev/usb/serial')
-rw-r--r--sys/dev/usb/serial/uftdi.c85
-rw-r--r--sys/dev/usb/serial/uftdi_reg.h5
2 files changed, 89 insertions, 1 deletions
diff --git a/sys/dev/usb/serial/uftdi.c b/sys/dev/usb/serial/uftdi.c
index c0dc79f..cf46804 100644
--- a/sys/dev/usb/serial/uftdi.c
+++ b/sys/dev/usb/serial/uftdi.c
@@ -1791,6 +1791,82 @@ uftdi_set_error_char(struct ucom_softc *ucom, int echar)
}
static int
+uftdi_read_eeprom(struct ucom_softc *ucom, struct uftdi_eeio *eeio)
+{
+ struct uftdi_softc *sc = ucom->sc_parent;
+ usb_device_request_t req;
+ usb_error_t err;
+ uint16_t widx, wlength, woffset;
+
+ /* Offset and length must both be evenly divisible by two. */
+ if ((eeio->offset | eeio->length) & 0x01)
+ return (EINVAL);
+
+ woffset = eeio->offset / 2U;
+ wlength = eeio->length / 2U;
+ for (widx = 0; widx < wlength; widx++) {
+ req.bmRequestType = UT_READ_VENDOR_DEVICE;
+ req.bRequest = FTDI_SIO_READ_EEPROM;
+ USETW(req.wIndex, widx + woffset);
+ USETW(req.wLength, 2);
+ USETW(req.wValue, 0);
+ err = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req,
+ &eeio->data[widx]);
+ if (err != USB_ERR_NORMAL_COMPLETION)
+ return (err);
+ }
+ return (USB_ERR_NORMAL_COMPLETION);
+}
+
+static int
+uftdi_write_eeprom(struct ucom_softc *ucom, struct uftdi_eeio *eeio)
+{
+ struct uftdi_softc *sc = ucom->sc_parent;
+ usb_device_request_t req;
+ usb_error_t err;
+ uint16_t widx, wlength, woffset;
+
+ /* Offset and length must both be evenly divisible by two. */
+ if ((eeio->offset | eeio->length) & 0x01)
+ return (EINVAL);
+
+ woffset = eeio->offset / 2U;
+ wlength = eeio->length / 2U;
+ for (widx = 0; widx < wlength; widx++) {
+ req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req.bRequest = FTDI_SIO_WRITE_EEPROM;
+ USETW(req.wIndex, widx + woffset);
+ USETW(req.wLength, 0);
+ USETW(req.wValue, eeio->data[widx]);
+ err = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL);
+ if (err != USB_ERR_NORMAL_COMPLETION)
+ return (err);
+ }
+ return (USB_ERR_NORMAL_COMPLETION);
+}
+
+static int
+uftdi_erase_eeprom(struct ucom_softc *ucom, int confirmation)
+{
+ struct uftdi_softc *sc = ucom->sc_parent;
+ usb_device_request_t req;
+ usb_error_t err;
+
+ /* Small effort to prevent accidental erasure. */
+ if (confirmation != UFTDI_CONFIRM_ERASE)
+ return (EINVAL);
+
+ req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req.bRequest = FTDI_SIO_ERASE_EEPROM;
+ USETW(req.wIndex, 0);
+ USETW(req.wLength, 0);
+ USETW(req.wValue, 0);
+ err = usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL);
+
+ return (err);
+}
+
+static int
uftdi_ioctl(struct ucom_softc *ucom, uint32_t cmd, caddr_t data,
int flag, struct thread *td)
{
@@ -1833,6 +1909,15 @@ uftdi_ioctl(struct ucom_softc *ucom, uint32_t cmd, caddr_t data,
*(int *)data = sc->sc_bcdDevice;
err = 0;
break;
+ case UFTDIIOC_READ_EEPROM:
+ err = uftdi_read_eeprom(ucom, (struct uftdi_eeio *)data);
+ break;
+ case UFTDIIOC_WRITE_EEPROM:
+ err = uftdi_write_eeprom(ucom, (struct uftdi_eeio *)data);
+ break;
+ case UFTDIIOC_ERASE_EEPROM:
+ err = uftdi_erase_eeprom(ucom, *(int *)data);
+ break;
default:
return (ENOIOCTL);
}
diff --git a/sys/dev/usb/serial/uftdi_reg.h b/sys/dev/usb/serial/uftdi_reg.h
index a2d6e38..a1ea325 100644
--- a/sys/dev/usb/serial/uftdi_reg.h
+++ b/sys/dev/usb/serial/uftdi_reg.h
@@ -31,7 +31,10 @@
#define FTDI_SIO_SET_LATENCY 9 /* Set the latency timer */
#define FTDI_SIO_GET_LATENCY 10 /* Read the latency timer */
#define FTDI_SIO_SET_BITMODE 11 /* Set the bit bang I/O mode */
-#define FTDI_SIO_GET_BITMODE 12 /* Read pin states in bit bang mode */
+#define FTDI_SIO_GET_BITMODE 12 /* Read pin states from any mode */
+#define FTDI_SIO_READ_EEPROM 144 /* Read eeprom word */
+#define FTDI_SIO_WRITE_EEPROM 145 /* Write eeprom word */
+#define FTDI_SIO_ERASE_EEPROM 146 /* Erase entire eeprom */
/* Port Identifier Table */
#define FTDI_PIT_DEFAULT 0 /* SIOA */
OpenPOWER on IntegriCloud