Re: [PATCH v2] USB: serial: ftdi_sio: Add MTP NVM support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Ajay,

Thanks for the review.

On 21 June 2018 at 19:34, Ajay Gupta <ajaykuee@xxxxxxxxx> wrote:
> Hi Loic
>
> On 6/21/18, Loic Poulain <loic.poulain@xxxxxxxxxx> wrote:
>> Most of FTDI's devices have an EEPROM which records FTDI devices
>> configuration setting (e.g. the VID, PID, I/O config...) and user
>> data. FT230R chip integrates a 128-byte eeprom, FT230X a 2048-byte
>> eeprom...
>>
>> This patch adds support for FTDI EEPROM read/write via USB control
>> transfers and register a new nvm device to the nvmem core.
>>
>> This permits to expose the eeprom as a sysfs file, allowing userspace
>> to read/modify FTDI configuration and its user data without having to
>> rely on a specific userspace USB driver.
>>
>> Moreover, any upcoming new tentative to add CBUS GPIO support could
>> integrate CBUS EEPROM configuration reading in order to determine
>> which of the CBUS pins are available as GPIO.
>>
>> Signed-off-by: Loic Poulain <loic.poulain@xxxxxxxxxx>
>> ---
>>  v2: Use ifdef instead of IS_ENABLED
>>      error message in case of nvmem registering failure
>>      Fix space/tab in Kconfig
>>
>>  drivers/usb/serial/Kconfig    |  13 ++++-
>>  drivers/usb/serial/ftdi_sio.c | 111
>> ++++++++++++++++++++++++++++++++++++++++++
>>  drivers/usb/serial/ftdi_sio.h |  28 +++++++++++
>>  3 files changed, 151 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
>> index 533f127..f05af5f 100644
>> --- a/drivers/usb/serial/Kconfig
>> +++ b/drivers/usb/serial/Kconfig
>> @@ -153,7 +153,7 @@ config USB_SERIAL_CYPRESS_M8
>>
>>         Supported microcontrollers in the CY4601 family are:
>>               CY7C63741 CY7C63742 CY7C63743 CY7C64013
>> -
>> +
> There is no change here so please remove it.
>
>>         To compile this driver as a module, choose M here: the
>>         module will be called cypress_m8.
>>
>> @@ -181,6 +181,17 @@ config USB_SERIAL_FTDI_SIO
>>         To compile this driver as a module, choose M here: the
>>         module will be called ftdi_sio.
>>
>> +config USB_SERIAL_FTDI_SIO_NVMEM
>> +     bool "FTDI MTP non-volatile memory support"
>> +     depends on USB_SERIAL_FTDI_SIO
>> +     select NVMEM
>> +     default y
>> +     help
>> +       Say yes here to add support for the MTP non-volatile memory
>> +       present on FTDI. Most of FTDI's devices have an EEPROM which
>> +       records FTDI device's configuration setting as well as user
>> +       data.
>> +
>>  config USB_SERIAL_VISOR
>>       tristate "USB Handspring Visor / Palm m50x / Sony Clie Driver"
>>       help
>> diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
>> index 7ea221d..9e242e8 100644
>> --- a/drivers/usb/serial/ftdi_sio.c
>> +++ b/drivers/usb/serial/ftdi_sio.c
>> @@ -40,6 +40,7 @@
>>  #include <linux/usb.h>
>>  #include <linux/serial.h>
>>  #include <linux/usb/serial.h>
>> +#include <linux/nvmem-provider.h>
>>  #include "ftdi_sio.h"
>>  #include "ftdi_sio_ids.h"
>>
>> @@ -73,6 +74,8 @@ struct ftdi_private {
>>       unsigned int latency;           /* latency setting in use */
>>       unsigned short max_packet_size;
>>       struct mutex cfg_lock; /* Avoid mess by parallel calls of config ioctl()
>> and change_speed() */
>> +
>> +     struct nvmem_device *eeprom;
>>  };
>>
>>  /* struct ftdi_sio_quirk is used by devices requiring special attention.
>> */
>> @@ -1529,6 +1532,104 @@ static int get_lsr_info(struct usb_serial_port
>> *port,
>>       return 0;
>>  }
>>
>> +#ifdef CONFIG_USB_SERIAL_FTDI_SIO_NVMEM
>> +
>> +static int write_eeprom(void *priv, unsigned int off, void *_val, size_t
>> bytes)
>> +{
>> +     struct usb_serial_port *port = priv;
>> +     struct usb_serial *serial = port->serial;
>> +     struct usb_device *udev = serial->dev;
>> +     unsigned char *buf = _val;
>> +
>> +     while (bytes) { /* bytes value is always a multiple of 2 */
>
> We should add check that 'bytes' is always multiple of 2 otherwise in
> case its not then there will be memory overrun due to buf[1] access
> below.
> while (bytes / 2) {
> }
>

This is in theory something which is guaranteed by the nvmem core since
we specified a 2-byte word size on registering. But looking at the code,
word-size is only checked on userspace access, not with kernel API
(e.g. nvmem_device_write). So yes It could be worth to double check here.


>> +             uint16_t val;
>> +             int rv;
>> +
>> +             val = buf[0] + (buf[1] << 8);
>> +
>> +             rv = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
>> +                                  FTDI_SIO_WRITE_EEPROM_REQUEST,
>> +                                  FTDI_SIO_WRITE_EEPROM_REQUEST_TYPE,
>> +                                  val, off / 2, NULL, 0, WDR_TIMEOUT);
>> +             if (rv < 0)
>> +                     return rv;
>> +
>> +             off += 2;
>> +             buf += 2;
>> +             bytes -= 2;
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +static int read_eeprom(void *priv, unsigned int off, void *val, size_t
>> bytes)
>> +{
>> +     struct usb_serial_port *port = priv;
>> +     struct usb_serial *serial = port->serial;
>> +     struct usb_device *udev = serial->dev;
>> +     unsigned char *buf = val;
>> +
>> +     while (bytes) { /* bytes value is always a multiple of 2 */
> same here

Ok.

>
>> +             int rv;
>> +
>> +             rv = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
>> +                                  FTDI_SIO_READ_EEPROM_REQUEST,
>> +                                  FTDI_SIO_READ_EEPROM_REQUEST_TYPE,
>> +                                  0, off / 2, buf, 2, WDR_TIMEOUT);
>> +             if (rv < 0)
>> +                     return rv;
>> +
>> +             off += 2;
>> +             buf += 2;
>> +             bytes -= 2;
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +static int register_eeprom(struct usb_serial_port *port)
>> +{
>> +     struct ftdi_private *priv = usb_get_serial_port_data(port);
>> +     struct nvmem_config nvmconf = {};
>> +
>> +     switch (priv->chip_type) {
>> +     case FTX:
>> +             nvmconf.size = 2048;
> Better to have macro for 2048 and 128 instead of hardcoded value.
>

Ok.

> Thanks
> Ajay
>> +             break;
>> +     case FT232RL:
>> +             nvmconf.size = 128;
>> +             break;
>> +     default:
>> +             return 0;
>> +     }
>> +
>> +     nvmconf.word_size = 2;
>> +     nvmconf.stride = 2;
>> +     nvmconf.read_only = false;
>> +     nvmconf.priv = port;
>> +     nvmconf.dev = &port->dev;
>> +     nvmconf.reg_read = read_eeprom;
>> +     nvmconf.reg_write = write_eeprom;
>> +     nvmconf.owner = THIS_MODULE;
>> +
>> +     priv->eeprom = nvmem_register(&nvmconf);
>> +     if (IS_ERR(priv->eeprom)) {
>> +             priv->eeprom = NULL;
>> +             return -ENOMEM;
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +static void unregister_eeprom(struct usb_serial_port *port)
>> +{
>> +     struct ftdi_private *priv = usb_get_serial_port_data(port);
>> +
>> +     if (priv->eeprom)
>> +             nvmem_unregister(priv->eeprom);
>> +}
>> +
>> +#endif /* CONFIG_USB_SERIAL_FTDI_SIO_NVMEM */
>>
>>  /* Determine type of FTDI chip based on USB config and descriptor. */
>>  static void ftdi_determine_type(struct usb_serial_port *port)
>> @@ -1814,6 +1915,13 @@ static int ftdi_sio_port_probe(struct usb_serial_port
>> *port)
>>               priv->latency = 16;
>>       write_latency_timer(port);
>>       create_sysfs_attrs(port);
>> +#ifdef CONFIG_USB_SERIAL_FTDI_SIO_NVMEM
>> +     if (register_eeprom(port)) {
>> +             dev_err(&port->dev, "Unable to register FTDI EEPROM\n");
>> +             /* non-fatal */
>> +     }
>> +#endif
>> +
>>       return 0;
>>  }
>>
>> @@ -1931,6 +2039,9 @@ static int ftdi_sio_port_remove(struct usb_serial_port
>> *port)
>>  {
>>       struct ftdi_private *priv = usb_get_serial_port_data(port);
>>
>> +#ifdef CONFIG_USB_SERIAL_FTDI_SIO_NVMEM
>> +     unregister_eeprom(port);
>> +#endif
>>       remove_sysfs_attrs(port);
>>
>>       kfree(priv);
>> diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
>> index dcd0b6e..9eab961 100644
>> --- a/drivers/usb/serial/ftdi_sio.h
>> +++ b/drivers/usb/serial/ftdi_sio.h
>> @@ -36,6 +36,8 @@
>>  #define FTDI_SIO_SET_ERROR_CHAR              7 /* Set the error character */
>>  #define FTDI_SIO_SET_LATENCY_TIMER   9 /* Set the latency timer */
>>  #define FTDI_SIO_GET_LATENCY_TIMER   10 /* Get the latency timer */
>> +#define FTDI_SIO_READ_EEPROM         0x90 /* Read eeprom */
>> +#define FTDI_SIO_WRITE_EEPROM                0x91 /* Write eeprom */
>>
>>  /* Interface indices for FT2232, FT2232H and FT4232H devices */
>>  #define INTERFACE_A          1
>> @@ -400,6 +402,32 @@ enum ftdi_sio_baudrate {
>>   *
>>   */
>>
>> + /* FTDI_SIO_READ_EEPROM */
>> +#define FTDI_SIO_READ_EEPROM_REQUEST_TYPE 0xc0
>> +#define FTDI_SIO_READ_EEPROM_REQUEST FTDI_SIO_READ_EEPROM
>> +/*
>> + *  BmRequestType:   1100 0000b
>> + *  bRequest:        FTDI_SIO_READ_EEPROM
>> + *  wValue:          0
>> + *  wIndex:          Word Index
>> + *  wLength:         2
>> + *  Data:            return data (a word)
>> + *
>> + */
>> +
>> +/* FTDI_SIO_WRITE_EEPROM */
>> +#define FTDI_SIO_WRITE_EEPROM_REQUEST_TYPE 0x40
>> +#define FTDI_SIO_WRITE_EEPROM_REQUEST FTDI_SIO_WRITE_EEPROM
>> +/*
>> + *  BmRequestType:   0100 0000b
>> + *  bRequest:        FTDI_SIO_WRITE_EEPROM
>> + *  wValue:          Data (word)
>> + *  wIndex:          Word Index
>> + *  wLength:         0
>> + *  Data:            None
>> + *
>> + */
>> +
>>  /* FTDI_SIO_GET_MODEM_STATUS */
>>  /* Retrieve the current value of the modem status register */
>>
>> --
>> 2.7.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
>> the body of a message to majordomo@xxxxxxxxxxxxxxx
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>

Regards,
Loic
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux