Author: ian
Date: Thu Aug  6 19:29:26 2015
New Revision: 286382
URL: https://svnweb.freebsd.org/changeset/base/286382

Log:
  Add support to the uftdi driver for reading and writing the serial eeprom
  that can be attached to the chips, via ioctl() calls.

Modified:
  head/sys/dev/usb/serial/uftdi.c
  head/sys/dev/usb/serial/uftdi_reg.h
  head/sys/dev/usb/uftdiio.h

Modified: head/sys/dev/usb/serial/uftdi.c
==============================================================================
--- head/sys/dev/usb/serial/uftdi.c     Thu Aug  6 19:08:33 2015        
(r286381)
+++ head/sys/dev/usb/serial/uftdi.c     Thu Aug  6 19:29:26 2015        
(r286382)
@@ -1791,6 +1791,82 @@ uftdi_set_error_char(struct ucom_softc *
 }
 
 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, uin
                *(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);
        }

Modified: head/sys/dev/usb/serial/uftdi_reg.h
==============================================================================
--- head/sys/dev/usb/serial/uftdi_reg.h Thu Aug  6 19:08:33 2015        
(r286381)
+++ head/sys/dev/usb/serial/uftdi_reg.h Thu Aug  6 19:29:26 2015        
(r286382)
@@ -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 */

Modified: head/sys/dev/usb/uftdiio.h
==============================================================================
--- head/sys/dev/usb/uftdiio.h  Thu Aug  6 19:08:33 2015        (r286381)
+++ head/sys/dev/usb/uftdiio.h  Thu Aug  6 19:29:26 2015        (r286382)
@@ -61,6 +61,26 @@ struct uftdi_bitmode
        uint8_t iomask;
 };
 
+/*
+ * For UFTDIIOC_READ_EEPROM, UFTDIIOC_WRITE_EEPROM:
+ *
+ * IO is done in 16-bit words at the chip level; offset and length are in 
bytes,
+ * but must each be evenly divisible by two.
+ *
+ * It is not necessary to erase before writing.  For the FT232R device (only)
+ * you must set the latency timer to 0x77 before doing a series of eeprom 
writes
+ * (and restore it to the prior value when done).
+ */
+struct uftdi_eeio
+{
+       uint16_t offset;
+       uint16_t length;
+       uint16_t data[64];
+};
+
+/* Pass this value to confirm that eeprom erase request is not accidental. */
+#define        UFTDI_CONFIRM_ERASE     0x26139108
+
 #define        UFTDIIOC_RESET_IO       _IO('c', 0)     /* Reset config, flush 
fifos.*/
 #define        UFTDIIOC_RESET_RX       _IO('c', 1)     /* Flush input fifo. */
 #define        UFTDIIOC_RESET_TX       _IO('c', 2)     /* Flush output fifo. */
@@ -71,5 +91,8 @@ struct uftdi_bitmode
 #define        UFTDIIOC_SET_LATENCY    _IOW('c', 7, int)       /* 1-255 ms */
 #define        UFTDIIOC_GET_LATENCY    _IOR('c', 8, int)
 #define        UFTDIIOC_GET_HWREV      _IOR('c', 9, int)
+#define        UFTDIIOC_READ_EEPROM    _IOWR('c', 10, struct uftdi_eeio)
+#define        UFTDIIOC_WRITE_EEPROM   _IOW('c', 11, struct uftdi_eeio)
+#define        UFTDIIOC_ERASE_EEPROM   _IOW('c', 12, int)
 
 #endif
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to