diff options
author | ian <ian@FreeBSD.org> | 2015-08-06 19:29:26 +0000 |
---|---|---|
committer | ian <ian@FreeBSD.org> | 2015-08-06 19:29:26 +0000 |
commit | 9f97d12240da60d94cc4ef7f0e1ea32f0fe7fe33 (patch) | |
tree | 917bc12a577272656f6396186241e7613b1ad140 /sys/dev/usb/serial | |
parent | cb8b7b20d877054461c450d19c4a131dc73aa3f6 (diff) | |
download | FreeBSD-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.c | 85 | ||||
-rw-r--r-- | sys/dev/usb/serial/uftdi_reg.h | 5 |
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 */ |