Add support to the uftdi driver for reading and writing the serial eeprom
that can be attached to the chips, via ioctl() calls.
This commit is contained in:
parent
7d89732757
commit
fc43ff0865
@ -1790,6 +1790,82 @@ uftdi_set_error_char(struct ucom_softc *ucom, int echar)
|
||||
return (usbd_do_request(sc->sc_udev, &sc->sc_mtx, &req, NULL));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user