Message ID | 20180418211544.20043-1-ezequiel@collabora.com (mailing list archive) |
---|---|
State | Accepted |
Headers | show |
Hi, On Wed, Apr 18, 2018 at 06:15:44PM -0300, Ezequiel Garcia wrote: > From: Nick Dyer <nick@shmanahar.org> > > 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@shmanahar.org> > Acked-by: Benson Leung <bleung@chromium.org> > [Ezequiel: minor patch massage] > Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com> > --- [On GE Healthcare PPD and Motorola Droid 4] Tested-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> -- 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 >
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@shmanahar.org> > > > > 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@shmanahar.org> > > Acked-by: Benson Leung <bleung@chromium.org> > > [Ezequiel: minor patch massage] > > Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com> > > --- > > [On GE Healthcare PPD and Motorola Droid 4] > Tested-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk> 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 > >
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))