Re: [PATCH v2] Input: atmel_mxt_ts - fix the firmware update

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

 



On Fri, Apr 20, 2018 at 07:21:51PM +0200, Sebastian Reichel wrote:
> Hi,
> 
> On Wed, Apr 18, 2018 at 06:15:44PM -0300, Ezequiel Garcia wrote:
> > From: Nick Dyer <nick@xxxxxxxxxxxxx>
> > 
> > The automatic update mechanism will trigger an update if the
> > info block CRCs are different between maxtouch configuration
> > file (maxtouch.cfg) and chip.
> > 
> > The driver compared the CRCs without retrieving the chip CRC,
> > resulting always in a failure and firmware flashing action
> > triggered. Fix this issue by retrieving the chip info block
> > CRC before the check.
> > 
> > Note that this solution has the benefit that by reading the
> > information block and the object table into a contiguous region
> > of memory, we can verify the checksum at probe time. This means
> > we make sure that we are indeed talking to a chip that supports
> > object protocol correctly.
> > 
> > Using this patch on a kevin chromebook, the touchscreen and
> > touchpad drivers are able to match the CRC:
> > 
> >   atmel_mxt_ts 3-004b: Family: 164 Variant: 14 Firmware V2.3.AA Objects: 40
> >   atmel_mxt_ts 5-004a: Family: 164 Variant: 17 Firmware V2.0.AA Objects: 31
> >   atmel_mxt_ts 3-004b: Resetting device
> >   atmel_mxt_ts 5-004a: Resetting device
> >   atmel_mxt_ts 3-004b: Config CRC 0x573E89: OK
> >   atmel_mxt_ts 3-004b: Touchscreen size X4095Y2729
> >   input: Atmel maXTouch Touchscreen as /devices/platform/ff130000.i2c/i2c-3/3-004b/input/input5
> >   atmel_mxt_ts 5-004a: Config CRC 0x0AF6BA: OK
> >   atmel_mxt_ts 5-004a: Touchscreen size X1920Y1080
> >   input: Atmel maXTouch Touchpad as /devices/platform/ff140000.i2c/i2c-5/5-004a/input/input6
> > 
> > Signed-off-by: Nick Dyer <nick.dyer@xxxxxxxxxxxxx>
> > Acked-by: Benson Leung <bleung@xxxxxxxxxxxx>
> > [Ezequiel: minor patch massage]
> > Signed-off-by: Ezequiel Garcia <ezequiel@xxxxxxxxxxxxx>
> > ---
> 
> [On GE Healthcare PPD and Motorola Droid 4]
> Tested-by: Sebastian Reichel <sebastian.reichel@xxxxxxxxxxxxxxx>

Applied, thank you.

> 
> -- Sebastian
> 
> > Nick, Sebastian:
> > 
> > After discussing it with Sebastian, I took the liberty
> > of re-submitting this, with some massage and a commit log.
> > 
> > Patch applies to v4.17-rc1. Let me know how it looks.
> > 
> >  drivers/input/touchscreen/atmel_mxt_ts.c | 186 ++++++++++++++++++-------------
> >  1 file changed, 110 insertions(+), 76 deletions(-)
> > 
> > diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
> > index 5d9699fe1b55..51bfed43f42a 100644
> > --- a/drivers/input/touchscreen/atmel_mxt_ts.c
> > +++ b/drivers/input/touchscreen/atmel_mxt_ts.c
> > @@ -280,7 +280,8 @@ struct mxt_data {
> >  	struct input_dev *input_dev;
> >  	char phys[64];		/* device physical location */
> >  	struct mxt_object *object_table;
> > -	struct mxt_info info;
> > +	struct mxt_info *info;
> > +	void *raw_info_block;
> >  	unsigned int irq;
> >  	unsigned int max_x;
> >  	unsigned int max_y;
> > @@ -460,12 +461,13 @@ static int mxt_lookup_bootloader_address(struct mxt_data *data, bool retry)
> >  {
> >  	u8 appmode = data->client->addr;
> >  	u8 bootloader;
> > +	u8 family_id = data->info ? data->info->family_id : 0;
> >  
> >  	switch (appmode) {
> >  	case 0x4a:
> >  	case 0x4b:
> >  		/* Chips after 1664S use different scheme */
> > -		if (retry || data->info.family_id >= 0xa2) {
> > +		if (retry || family_id >= 0xa2) {
> >  			bootloader = appmode - 0x24;
> >  			break;
> >  		}
> > @@ -692,7 +694,7 @@ mxt_get_object(struct mxt_data *data, u8 type)
> >  	struct mxt_object *object;
> >  	int i;
> >  
> > -	for (i = 0; i < data->info.object_num; i++) {
> > +	for (i = 0; i < data->info->object_num; i++) {
> >  		object = data->object_table + i;
> >  		if (object->type == type)
> >  			return object;
> > @@ -1462,12 +1464,12 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg)
> >  		data_pos += offset;
> >  	}
> >  
> > -	if (cfg_info.family_id != data->info.family_id) {
> > +	if (cfg_info.family_id != data->info->family_id) {
> >  		dev_err(dev, "Family ID mismatch!\n");
> >  		return -EINVAL;
> >  	}
> >  
> > -	if (cfg_info.variant_id != data->info.variant_id) {
> > +	if (cfg_info.variant_id != data->info->variant_id) {
> >  		dev_err(dev, "Variant ID mismatch!\n");
> >  		return -EINVAL;
> >  	}
> > @@ -1512,7 +1514,7 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg)
> >  
> >  	/* Malloc memory to store configuration */
> >  	cfg_start_ofs = MXT_OBJECT_START +
> > -			data->info.object_num * sizeof(struct mxt_object) +
> > +			data->info->object_num * sizeof(struct mxt_object) +
> >  			MXT_INFO_CHECKSUM_SIZE;
> >  	config_mem_size = data->mem_size - cfg_start_ofs;
> >  	config_mem = kzalloc(config_mem_size, GFP_KERNEL);
> > @@ -1563,20 +1565,6 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg)
> >  	return ret;
> >  }
> >  
> > -static int mxt_get_info(struct mxt_data *data)
> > -{
> > -	struct i2c_client *client = data->client;
> > -	struct mxt_info *info = &data->info;
> > -	int error;
> > -
> > -	/* Read 7-byte info block starting at address 0 */
> > -	error = __mxt_read_reg(client, 0, sizeof(*info), info);
> > -	if (error)
> > -		return error;
> > -
> > -	return 0;
> > -}
> > -
> >  static void mxt_free_input_device(struct mxt_data *data)
> >  {
> >  	if (data->input_dev) {
> > @@ -1591,9 +1579,10 @@ static void mxt_free_object_table(struct mxt_data *data)
> >  	video_unregister_device(&data->dbg.vdev);
> >  	v4l2_device_unregister(&data->dbg.v4l2);
> >  #endif
> > -
> > -	kfree(data->object_table);
> >  	data->object_table = NULL;
> > +	data->info = NULL;
> > +	kfree(data->raw_info_block);
> > +	data->raw_info_block = NULL;
> >  	kfree(data->msg_buf);
> >  	data->msg_buf = NULL;
> >  	data->T5_address = 0;
> > @@ -1609,34 +1598,18 @@ static void mxt_free_object_table(struct mxt_data *data)
> >  	data->max_reportid = 0;
> >  }
> >  
> > -static int mxt_get_object_table(struct mxt_data *data)
> > +static int mxt_parse_object_table(struct mxt_data *data,
> > +				  struct mxt_object *object_table)
> >  {
> >  	struct i2c_client *client = data->client;
> > -	size_t table_size;
> > -	struct mxt_object *object_table;
> > -	int error;
> >  	int i;
> >  	u8 reportid;
> >  	u16 end_address;
> >  
> > -	table_size = data->info.object_num * sizeof(struct mxt_object);
> > -	object_table = kzalloc(table_size, GFP_KERNEL);
> > -	if (!object_table) {
> > -		dev_err(&data->client->dev, "Failed to allocate memory\n");
> > -		return -ENOMEM;
> > -	}
> > -
> > -	error = __mxt_read_reg(client, MXT_OBJECT_START, table_size,
> > -			object_table);
> > -	if (error) {
> > -		kfree(object_table);
> > -		return error;
> > -	}
> > -
> >  	/* Valid Report IDs start counting from 1 */
> >  	reportid = 1;
> >  	data->mem_size = 0;
> > -	for (i = 0; i < data->info.object_num; i++) {
> > +	for (i = 0; i < data->info->object_num; i++) {
> >  		struct mxt_object *object = object_table + i;
> >  		u8 min_id, max_id;
> >  
> > @@ -1660,8 +1633,8 @@ static int mxt_get_object_table(struct mxt_data *data)
> >  
> >  		switch (object->type) {
> >  		case MXT_GEN_MESSAGE_T5:
> > -			if (data->info.family_id == 0x80 &&
> > -			    data->info.version < 0x20) {
> > +			if (data->info->family_id == 0x80 &&
> > +			    data->info->version < 0x20) {
> >  				/*
> >  				 * On mXT224 firmware versions prior to V2.0
> >  				 * read and discard unused CRC byte otherwise
> > @@ -1716,24 +1689,102 @@ static int mxt_get_object_table(struct mxt_data *data)
> >  	/* If T44 exists, T5 position has to be directly after */
> >  	if (data->T44_address && (data->T5_address != data->T44_address + 1)) {
> >  		dev_err(&client->dev, "Invalid T44 position\n");
> > -		error = -EINVAL;
> > -		goto free_object_table;
> > +		return -EINVAL;
> >  	}
> >  
> >  	data->msg_buf = kcalloc(data->max_reportid,
> >  				data->T5_msg_size, GFP_KERNEL);
> > -	if (!data->msg_buf) {
> > -		dev_err(&client->dev, "Failed to allocate message buffer\n");
> > +	if (!data->msg_buf)
> > +		return -ENOMEM;
> > +
> > +	return 0;
> > +}
> > +
> > +static int mxt_read_info_block(struct mxt_data *data)
> > +{
> > +	struct i2c_client *client = data->client;
> > +	int error;
> > +	size_t size;
> > +	void *id_buf, *buf;
> > +	uint8_t num_objects;
> > +	u32 calculated_crc;
> > +	u8 *crc_ptr;
> > +
> > +	/* If info block already allocated, free it */
> > +	if (data->raw_info_block)
> > +		mxt_free_object_table(data);
> > +
> > +	/* Read 7-byte ID information block starting at address 0 */
> > +	size = sizeof(struct mxt_info);
> > +	id_buf = kzalloc(size, GFP_KERNEL);
> > +	if (!id_buf)
> > +		return -ENOMEM;
> > +
> > +	error = __mxt_read_reg(client, 0, size, id_buf);
> > +	if (error)
> > +		goto err_free_mem;
> > +
> > +	/* Resize buffer to give space for rest of info block */
> > +	num_objects = ((struct mxt_info *)id_buf)->object_num;
> > +	size += (num_objects * sizeof(struct mxt_object))
> > +		+ MXT_INFO_CHECKSUM_SIZE;
> > +
> > +	buf = krealloc(id_buf, size, GFP_KERNEL);
> > +	if (!buf) {
> >  		error = -ENOMEM;
> > -		goto free_object_table;
> > +		goto err_free_mem;
> > +	}
> > +	id_buf = buf;
> > +
> > +	/* Read rest of info block */
> > +	error = __mxt_read_reg(client, MXT_OBJECT_START,
> > +			       size - MXT_OBJECT_START,
> > +			       id_buf + MXT_OBJECT_START);
> > +	if (error)
> > +		goto err_free_mem;
> > +
> > +	/* Extract & calculate checksum */
> > +	crc_ptr = id_buf + size - MXT_INFO_CHECKSUM_SIZE;
> > +	data->info_crc = crc_ptr[0] | (crc_ptr[1] << 8) | (crc_ptr[2] << 16);
> > +
> > +	calculated_crc = mxt_calculate_crc(id_buf, 0,
> > +					   size - MXT_INFO_CHECKSUM_SIZE);
> > +
> > +	/*
> > +	 * CRC mismatch can be caused by data corruption due to I2C comms
> > +	 * issue or else device is not using Object Based Protocol (eg i2c-hid)
> > +	 */
> > +	if ((data->info_crc == 0) || (data->info_crc != calculated_crc)) {
> > +		dev_err(&client->dev,
> > +			"Info Block CRC error calculated=0x%06X read=0x%06X\n",
> > +			calculated_crc, data->info_crc);
> > +		error = -EIO;
> > +		goto err_free_mem;
> > +	}
> > +
> > +	data->raw_info_block = id_buf;
> > +	data->info = (struct mxt_info *)id_buf;
> > +
> > +	dev_info(&client->dev,
> > +		 "Family: %u Variant: %u Firmware V%u.%u.%02X Objects: %u\n",
> > +		 data->info->family_id, data->info->variant_id,
> > +		 data->info->version >> 4, data->info->version & 0xf,
> > +		 data->info->build, data->info->object_num);
> > +
> > +	/* Parse object table information */
> > +	error = mxt_parse_object_table(data, id_buf + MXT_OBJECT_START);
> > +	if (error) {
> > +		dev_err(&client->dev, "Error %d parsing object table\n", error);
> > +		mxt_free_object_table(data);
> > +		goto err_free_mem;
> >  	}
> >  
> > -	data->object_table = object_table;
> > +	data->object_table = (struct mxt_object *)(id_buf + MXT_OBJECT_START);
> >  
> >  	return 0;
> >  
> > -free_object_table:
> > -	mxt_free_object_table(data);
> > +err_free_mem:
> > +	kfree(id_buf);
> >  	return error;
> >  }
> >  
> > @@ -2046,7 +2097,7 @@ static int mxt_initialize(struct mxt_data *data)
> >  	int error;
> >  
> >  	while (1) {
> > -		error = mxt_get_info(data);
> > +		error = mxt_read_info_block(data);
> >  		if (!error)
> >  			break;
> >  
> > @@ -2077,16 +2128,9 @@ static int mxt_initialize(struct mxt_data *data)
> >  		msleep(MXT_FW_RESET_TIME);
> >  	}
> >  
> > -	/* Get object table information */
> > -	error = mxt_get_object_table(data);
> > -	if (error) {
> > -		dev_err(&client->dev, "Error %d reading object table\n", error);
> > -		return error;
> > -	}
> > -
> >  	error = mxt_acquire_irq(data);
> >  	if (error)
> > -		goto err_free_object_table;
> > +		return error;
> >  
> >  	error = request_firmware_nowait(THIS_MODULE, true, MXT_CFG_NAME,
> >  					&client->dev, GFP_KERNEL, data,
> > @@ -2094,14 +2138,10 @@ static int mxt_initialize(struct mxt_data *data)
> >  	if (error) {
> >  		dev_err(&client->dev, "Failed to invoke firmware loader: %d\n",
> >  			error);
> > -		goto err_free_object_table;
> > +		return error;
> >  	}
> >  
> >  	return 0;
> > -
> > -err_free_object_table:
> > -	mxt_free_object_table(data);
> > -	return error;
> >  }
> >  
> >  static int mxt_set_t7_power_cfg(struct mxt_data *data, u8 sleep)
> > @@ -2162,7 +2202,7 @@ static int mxt_init_t7_power_cfg(struct mxt_data *data)
> >  static u16 mxt_get_debug_value(struct mxt_data *data, unsigned int x,
> >  			       unsigned int y)
> >  {
> > -	struct mxt_info *info = &data->info;
> > +	struct mxt_info *info = data->info;
> >  	struct mxt_dbg *dbg = &data->dbg;
> >  	unsigned int ofs, page;
> >  	unsigned int col = 0;
> > @@ -2490,7 +2530,7 @@ static const struct video_device mxt_video_device = {
> >  
> >  static void mxt_debug_init(struct mxt_data *data)
> >  {
> > -	struct mxt_info *info = &data->info;
> > +	struct mxt_info *info = data->info;
> >  	struct mxt_dbg *dbg = &data->dbg;
> >  	struct mxt_object *object;
> >  	int error;
> > @@ -2576,7 +2616,6 @@ static int mxt_configure_objects(struct mxt_data *data,
> >  				 const struct firmware *cfg)
> >  {
> >  	struct device *dev = &data->client->dev;
> > -	struct mxt_info *info = &data->info;
> >  	int error;
> >  
> >  	error = mxt_init_t7_power_cfg(data);
> > @@ -2601,11 +2640,6 @@ static int mxt_configure_objects(struct mxt_data *data,
> >  
> >  	mxt_debug_init(data);
> >  
> > -	dev_info(dev,
> > -		 "Family: %u Variant: %u Firmware V%u.%u.%02X Objects: %u\n",
> > -		 info->family_id, info->variant_id, info->version >> 4,
> > -		 info->version & 0xf, info->build, info->object_num);
> > -
> >  	return 0;
> >  }
> >  
> > @@ -2614,7 +2648,7 @@ static ssize_t mxt_fw_version_show(struct device *dev,
> >  				   struct device_attribute *attr, char *buf)
> >  {
> >  	struct mxt_data *data = dev_get_drvdata(dev);
> > -	struct mxt_info *info = &data->info;
> > +	struct mxt_info *info = data->info;
> >  	return scnprintf(buf, PAGE_SIZE, "%u.%u.%02X\n",
> >  			 info->version >> 4, info->version & 0xf, info->build);
> >  }
> > @@ -2624,7 +2658,7 @@ static ssize_t mxt_hw_version_show(struct device *dev,
> >  				   struct device_attribute *attr, char *buf)
> >  {
> >  	struct mxt_data *data = dev_get_drvdata(dev);
> > -	struct mxt_info *info = &data->info;
> > +	struct mxt_info *info = data->info;
> >  	return scnprintf(buf, PAGE_SIZE, "%u.%u\n",
> >  			 info->family_id, info->variant_id);
> >  }
> > @@ -2663,7 +2697,7 @@ static ssize_t mxt_object_show(struct device *dev,
> >  		return -ENOMEM;
> >  
> >  	error = 0;
> > -	for (i = 0; i < data->info.object_num; i++) {
> > +	for (i = 0; i < data->info->object_num; i++) {
> >  		object = data->object_table + i;
> >  
> >  		if (!mxt_object_readable(object->type))
> > -- 
> > 2.16.3
> > 



-- 
Dmitry
--
To unsubscribe from this list: send the line "unsubscribe linux-input" 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 Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux