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

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

 



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) {
}

> +		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

> +		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.

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
>
--
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