From 49bba71fe5ddf6c5ceddc1948bfde9e085c14620 Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Thu, 10 Mar 2016 15:35:26 +0000 Subject: [PATCH 01/10] Input: atmel_mxt_ts - fix warning in mxt_set_up_active_stylus Signed-off-by: Nick Dyer --- drivers/input/touchscreen/atmel_mxt_ts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 328537e61bf5d2..ee714f4938c4df 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -2364,7 +2364,7 @@ static int mxt_set_up_active_stylus(struct input_dev *input_dev, error = __mxt_read_reg(client, object->start_address, 1, &ctrl); if (error) - return; + return error; /* Check enable bit */ if (!(ctrl & 0x01)) From c03ddbc6251d945ad43582d5debc559180373550 Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Sun, 10 Jan 2016 18:29:34 -0800 Subject: [PATCH 02/10] Input: atmel_mxt_ts - improve touchscreen size/orientation handling Both T100 and T9 handle range and orientation in a similar fashion. Reduce duplication between the two implementations. Signed-off-by: Nick Dyer Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 69 +++++++++--------------- 1 file changed, 26 insertions(+), 43 deletions(-) diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index ee714f4938c4df..121329e7542f44 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -120,8 +120,8 @@ struct t7_config { #define MXT_T9_DETECT BIT(7) struct t9_range { - u16 x; - u16 y; + __le16 x; + __le16 y; } __packed; /* MXT_TOUCH_MULTI_T9 orient */ @@ -266,6 +266,7 @@ struct mxt_data { unsigned int irq; unsigned int max_x; unsigned int max_y; + bool xy_switch; bool in_bootloader; u16 mem_size; u8 t100_aux_ampl; @@ -2318,8 +2319,8 @@ static int mxt_read_t9_resolution(struct mxt_data *data) if (error) return error; - le16_to_cpus(&range.x); - le16_to_cpus(&range.y); + data->max_x = get_unaligned_le16(&range.x); + data->max_y = get_unaligned_le16(&range.y); error = __mxt_read_reg(client, object->start_address + MXT_T9_ORIENT, @@ -2327,23 +2328,7 @@ static int mxt_read_t9_resolution(struct mxt_data *data) if (error) return error; - /* Handle default values */ - if (range.x == 0) - range.x = 1023; - - if (range.y == 0) - range.y = 1023; - - if (orient & MXT_T9_ORIENT_SWITCH) { - data->max_x = range.y; - data->max_y = range.x; - } else { - data->max_x = range.x; - data->max_y = range.y; - } - - dev_dbg(&client->dev, - "Touchscreen size X%uY%u\n", data->max_x, data->max_y); + data->xy_switch = orient & MXT_T9_ORIENT_SWITCH; return 0; } @@ -2409,13 +2394,14 @@ static int mxt_read_t100_config(struct mxt_data *data) if (!object) return -EINVAL; + /* read touchscreen dimensions */ error = __mxt_read_reg(client, object->start_address + MXT_T100_XRANGE, sizeof(range_x), &range_x); if (error) return error; - le16_to_cpus(&range_x); + data->max_x = get_unaligned_le16(&range_x); error = __mxt_read_reg(client, object->start_address + MXT_T100_YRANGE, @@ -2423,36 +2409,24 @@ static int mxt_read_t100_config(struct mxt_data *data) if (error) return error; - le16_to_cpus(&range_y); + data->max_y = get_unaligned_le16(&range_y); + /* read orientation config */ error = __mxt_read_reg(client, object->start_address + MXT_T100_CFG1, 1, &cfg); if (error) return error; + data->xy_switch = cfg & MXT_T100_CFG_SWITCHXY; + + /* allocate aux bytes */ error = __mxt_read_reg(client, object->start_address + MXT_T100_TCHAUX, 1, &tchaux); if (error) return error; - /* Handle default values */ - if (range_x == 0) - range_x = 1023; - - if (range_y == 0) - range_y = 1023; - - if (cfg & MXT_T100_CFG_SWITCHXY) { - data->max_x = range_y; - data->max_y = range_x; - } else { - data->max_x = range_x; - data->max_y = range_y; - } - - /* allocate aux bytes */ aux = 6; if (tchaux & MXT_T100_TCHAUX_VECT) @@ -2468,9 +2442,6 @@ static int mxt_read_t100_config(struct mxt_data *data) "T100 aux mappings vect:%u ampl:%u area:%u\n", data->t100_aux_vect, data->t100_aux_ampl, data->t100_aux_area); - dev_info(&client->dev, - "T100 Touchscreen size X%uY%u\n", data->max_x, data->max_y); - return 0; } @@ -2523,7 +2494,6 @@ static int mxt_initialize_input_device(struct mxt_data *data) error = mxt_read_t100_config(data); if (error) dev_warn(dev, "Failed to read T100 config\n"); - break; default: @@ -2531,6 +2501,19 @@ static int mxt_initialize_input_device(struct mxt_data *data) return -EINVAL; } + /* Handle default values and orientation switch */ + if (data->max_x == 0) + data->max_x = 1023; + + if (data->max_y == 0) + data->max_y = 1023; + + if (data->xy_switch) + swap(data->max_x, data->max_y); + + dev_info(dev, "Touchscreen size X%uY%u\n", data->max_x, data->max_y); + + /* Register input device */ input_dev = input_allocate_device(); if (!input_dev) return -ENOMEM; From f371bc405c4467a5beb5174f08b4934f8b8ca32f Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Tue, 15 Mar 2016 17:27:27 +0000 Subject: [PATCH 03/10] Input: atmel_mxt_ts - use min() macro --- drivers/input/touchscreen/atmel_mxt_ts.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 121329e7542f44..cc4771332f20de 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -816,7 +816,6 @@ static int __mxt_read_reg(struct i2c_client *client, return 0; } -#define MIN(a, b) (a > b ? b : a) static int mxt_read_blks(struct mxt_data *data, u16 start, u16 count, u8 *buf) { u16 offset = 0; @@ -824,7 +823,7 @@ static int mxt_read_blks(struct mxt_data *data, u16 start, u16 count, u8 *buf) u16 size; while (offset < count) { - size = MIN(MXT_MAX_BLOCK_WRITE, count - offset); + size = min(MXT_MAX_BLOCK_WRITE, count - offset); error = __mxt_read_reg(data->client, start + offset, From f1804f18cfe0fbc62cb02dcf6cb2c57f40016085 Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Tue, 15 Mar 2016 17:28:13 +0000 Subject: [PATCH 04/10] Input: atmel_mxt_ts - remove debug msg in correct places --- drivers/input/touchscreen/atmel_mxt_ts.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index cc4771332f20de..95bc26cebe8a2f 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -1964,8 +1964,6 @@ static void mxt_free_input_device(struct mxt_data *data) static void mxt_free_object_table(struct mxt_data *data) { - mxt_debug_msg_remove(data); - data->object_table = NULL; data->info = NULL; kfree(data->raw_info_block); @@ -2947,6 +2945,7 @@ static int mxt_enter_bootloader(struct mxt_data *data) return ret; data->in_bootloader = true; + mxt_debug_msg_remove(data); mxt_sysfs_remove(data); mxt_free_input_device(data); mxt_free_object_table(data); @@ -3694,6 +3693,7 @@ static int mxt_remove(struct i2c_client *client) struct mxt_data *data = i2c_get_clientdata(client); sysfs_remove_group(&client->dev.kobj, &mxt_fw_attr_group); + mxt_debug_msg_remove(data); mxt_sysfs_remove(data); if (data->irq) From 11a72ee5faebe679343e906aca65c0cc49da5377 Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Tue, 15 Mar 2016 17:28:30 +0000 Subject: [PATCH 05/10] Input: atmel_mxt_ts - remove some blank lines --- drivers/input/touchscreen/atmel_mxt_ts.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 95bc26cebe8a2f..ffa5054429aef3 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -2631,6 +2631,7 @@ static int mxt_initialize_input_device(struct mxt_data *data) static int mxt_sysfs_init(struct mxt_data *data); static void mxt_sysfs_remove(struct mxt_data *data); + static int mxt_configure_objects(struct mxt_data *data, const struct firmware *cfg); @@ -2817,7 +2818,6 @@ static ssize_t mxt_fw_version_show(struct device *dev, struct device_attribute *attr, char *buf) { struct mxt_data *data = dev_get_drvdata(dev); - return scnprintf(buf, PAGE_SIZE, "%u.%u.%02X\n", data->info->version >> 4, data->info->version & 0xf, data->info->build); @@ -2828,7 +2828,6 @@ static ssize_t mxt_hw_version_show(struct device *dev, struct device_attribute *attr, char *buf) { struct mxt_data *data = dev_get_drvdata(dev); - return scnprintf(buf, PAGE_SIZE, "%u.%u\n", data->info->family_id, data->info->variant_id); } From fa6d3538747ccca9e98c038d5149ea7840392577 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 11 Dec 2015 13:22:39 -0800 Subject: [PATCH 06/10] Input: atmel_mxt_ts - add maxtouch to I2C table for module autoload The Atmel maxtouch DT binding documents that the compatible string for the device is "atmel,maxtouch" and the I2C core always reports a module alias of the form i2c:alias where alias is the compatible string model: $ grep MODALIAS /sys/devices/platform/12e00000.i2c/i2c-8/8-004b/uevent MODALIAS=i2c:maxtouch But there isn't maxtouch entry in the I2C device ID table so when the i2c:maxtouch MODALIAS uevent is reported, kmod is not able to match the alias with a module to load: $ modinfo atmel_mxt_ts | grep alias alias: of:N*T*Catmel,maxtouch alias: i2c:mXT224 alias: i2c:atmel_mxt_tp alias: i2c:atmel_mxt_ts alias: i2c:qt602240_ts So add the maxtouch entry to the I2C device ID table to allow the module to be autoloaded when the device is registered via OF. Signed-off-by: Javier Martinez Canillas Signed-off-by: Dmitry Torokhov Signed-off-by: Nick Dyer --- drivers/input/touchscreen/atmel_mxt_ts.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index ffa5054429aef3..28884dee5b0d72 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -3766,6 +3766,7 @@ static const struct i2c_device_id mxt_id[] = { { "qt602240_ts", 0 }, { "atmel_mxt_ts", 0 }, { "atmel_mxt_tp", 0 }, + { "maxtouch", 0 }, { "mXT224", 0 }, { } }; From 71b2796d5be5f9db4814662477ad0df76871c0a9 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 20 Nov 2015 10:58:07 -0800 Subject: [PATCH 07/10] Input: atmel_mxt_ts - add generic platform data for Chromebooks Apparently people are installing generic Linux distributions not only on Pixels but also on other Chromebooks. Unfortunately on all of them Atmel parts assigned names ATML0000 and ATML0001, and do not carry any other configuration data. So let's create generic instance of platform data that should cover most of them (we assume that they will not be using T100 objects, since with those Google mapped BTN_LEFT onto a different GPIO, so slightly different keymap would be needed, but I think we used parts with T100 on ARM devices where we thankfully have DTS and can describe the devices better). Tested-by: Rich K Reviewed-by: Javier Martinez Canillas Signed-off-by: Dmitry Torokhov Signed-off-by: Nick Dyer --- drivers/input/touchscreen/atmel_mxt_ts.c | 33 ++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 28884dee5b0d72..b47daceca9ef7f 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -3523,6 +3523,31 @@ static struct mxt_acpi_platform_data samus_platform_data[] = { { } }; +static unsigned int chromebook_tp_buttons[] = { + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + BTN_LEFT +}; + +static struct mxt_acpi_platform_data chromebook_platform_data[] = { + { + /* Touchpad */ + .hid = "ATML0000", + .pdata = { + .t19_num_keys = ARRAY_SIZE(chromebook_tp_buttons), + .t19_keymap = chromebook_tp_buttons, + }, + }, + { + /* Touchscreen */ + .hid = "ATML0001", + }, + { } +}; + static const struct dmi_system_id mxt_dmi_table[] = { { /* 2015 Google Pixel */ @@ -3533,6 +3558,14 @@ static const struct dmi_system_id mxt_dmi_table[] = { }, .driver_data = samus_platform_data, }, + { + /* Other Google Chromebooks */ + .ident = "Chromebook", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), + }, + .driver_data = chromebook_platform_data, + }, { } }; From 90ddd8b58898ba9fcd404f92ecbc6ae693c9a7bb Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Tue, 15 Mar 2016 17:30:44 +0000 Subject: [PATCH 08/10] Input: atmel_mxt_ts - create fw attr before mxt_initialize --- drivers/input/touchscreen/atmel_mxt_ts.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index b47daceca9ef7f..e913c6d39f4dd9 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -3699,10 +3699,6 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) disable_irq(data->irq); } - error = mxt_initialize(data); - if (error) - goto err_free_irq; - error = sysfs_create_group(&client->dev.kobj, &mxt_fw_attr_group); if (error) { dev_err(&client->dev, "Failure %d creating fw sysfs group\n", @@ -3710,6 +3706,10 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) return error; } + error = mxt_initialize(data); + if (error) + goto err_free_irq; + return 0; err_free_irq: From f83c9bbef2d0bdb4e4ef3b39446994c74c62e0ba Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Fri, 22 Apr 2016 17:12:51 +0100 Subject: [PATCH 09/10] Input: atmel_mxt_ts - refactor config update code to add context struct Signed-off-by: Nick Dyer --- drivers/input/touchscreen/atmel_mxt_ts.c | 108 ++++++++++++----------- 1 file changed, 56 insertions(+), 52 deletions(-) diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index e913c6d39f4dd9..8cb04dd072c2df 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -240,6 +240,19 @@ struct mxt_fw_frame { u8 data[]; }; +/* Config update context */ +struct mxt_cfg { + u8 *raw; + size_t raw_size; + off_t raw_pos; + + u8 *mem; + size_t mem_size; + int start_ofs; + + struct mxt_info info; +}; + /* Firmware update context */ struct mxt_flash { struct mxt_data *data; @@ -1632,12 +1645,7 @@ static int mxt_check_retrigen(struct mxt_data *data) return 0; } -static int mxt_prepare_cfg_mem(struct mxt_data *data, - const struct firmware *cfg, - unsigned int data_pos, - unsigned int cfg_start_ofs, - u8 *config_mem, - size_t config_mem_size) +static int mxt_prepare_cfg_mem(struct mxt_data *data, struct mxt_cfg *cfg) { struct device *dev = &data->client->dev; struct mxt_object *object; @@ -1648,9 +1656,9 @@ static int mxt_prepare_cfg_mem(struct mxt_data *data, u16 reg; u8 val; - while (data_pos < cfg->size) { + while (cfg->raw_pos < cfg->raw_size) { /* Read type, instance, length */ - ret = sscanf(cfg->data + data_pos, "%x %x %x%n", + ret = sscanf(cfg->raw + cfg->raw_pos, "%x %x %x%n", &type, &instance, &size, &offset); if (ret == 0) { /* EOF */ @@ -1659,20 +1667,20 @@ static int mxt_prepare_cfg_mem(struct mxt_data *data, dev_err(dev, "Bad format: failed to parse object\n"); return -EINVAL; } - data_pos += offset; + cfg->raw_pos += offset; object = mxt_get_object(data, type); if (!object) { /* Skip object */ for (i = 0; i < size; i++) { - ret = sscanf(cfg->data + data_pos, "%hhx%n", + ret = sscanf(cfg->raw + cfg->raw_pos, "%hhx%n", &val, &offset); if (ret != 1) { dev_err(dev, "Bad format in T%d at %d\n", type, i); return -EINVAL; } - data_pos += offset; + cfg->raw_pos += offset; } continue; } @@ -1707,7 +1715,7 @@ static int mxt_prepare_cfg_mem(struct mxt_data *data, reg = object->start_address + mxt_obj_size(object) * instance; for (i = 0; i < size; i++) { - ret = sscanf(cfg->data + data_pos, "%hhx%n", + ret = sscanf(cfg->raw + cfg->raw_pos, "%hhx%n", &val, &offset); if (ret != 1) { @@ -1715,15 +1723,15 @@ static int mxt_prepare_cfg_mem(struct mxt_data *data, type, i); return -EINVAL; } - data_pos += offset; + cfg->raw_pos += offset; if (i > mxt_obj_size(object)) continue; - byte_offset = reg + i - cfg_start_ofs; + byte_offset = reg + i - cfg->start_ofs; - if (byte_offset >= 0 && byte_offset < config_mem_size) { - *(config_mem + byte_offset) = val; + if (byte_offset >= 0 && byte_offset < cfg->mem_size) { + *(cfg->mem + byte_offset) = val; } else { dev_err(dev, "Bad object: reg:%d, T%d, ofs=%d\n", reg, object->type, byte_offset); @@ -1735,22 +1743,21 @@ static int mxt_prepare_cfg_mem(struct mxt_data *data, return 0; } -static int mxt_upload_cfg_mem(struct mxt_data *data, unsigned int cfg_start, - u8 *config_mem, size_t config_mem_size) +static int mxt_upload_cfg_mem(struct mxt_data *data, struct mxt_cfg *cfg) { unsigned int byte_offset = 0; int error; /* Write configuration as blocks */ - while (byte_offset < config_mem_size) { - unsigned int size = config_mem_size - byte_offset; + while (byte_offset < cfg->mem_size) { + unsigned int size = cfg->mem_size - byte_offset; if (size > MXT_MAX_BLOCK_WRITE) size = MXT_MAX_BLOCK_WRITE; error = __mxt_write_reg(data->client, - cfg_start + byte_offset, - size, config_mem + byte_offset); + cfg->start_ofs + byte_offset, + size, cfg->mem + byte_offset); if (error) { dev_err(&data->client->dev, "Config write error, ret=%d\n", error); @@ -1784,66 +1791,65 @@ static int mxt_init_t7_power_cfg(struct mxt_data *data); * - 2-byte object size as hex * - array of 1-byte hex values */ -static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg) +static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw) { struct device *dev = &data->client->dev; - struct mxt_info cfg_info; + struct mxt_cfg cfg; int ret; int offset; - int data_pos; int i; - int cfg_start_ofs; u32 info_crc, config_crc, calculated_crc; - u8 *config_mem; - size_t config_mem_size; u16 crc_start = 0; + cfg.raw = fw->data; + cfg.raw_size = fw->size; + mxt_update_crc(data, MXT_COMMAND_REPORTALL, 1); - if (strncmp(cfg->data, MXT_CFG_MAGIC, strlen(MXT_CFG_MAGIC))) { + if (strncmp(cfg.raw, MXT_CFG_MAGIC, strlen(MXT_CFG_MAGIC))) { dev_err(dev, "Unrecognised config file\n"); return -EINVAL; } - data_pos = strlen(MXT_CFG_MAGIC); + cfg.raw_pos = strlen(MXT_CFG_MAGIC); /* Load information block and check */ for (i = 0; i < sizeof(struct mxt_info); i++) { - ret = sscanf(cfg->data + data_pos, "%hhx%n", - (unsigned char *)&cfg_info + i, + ret = sscanf(cfg.raw + cfg.raw_pos, "%hhx%n", + (unsigned char *)&cfg.info + i, &offset); if (ret != 1) { dev_err(dev, "Bad format\n"); return -EINVAL; } - data_pos += offset; + cfg.raw_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; } /* Read CRCs */ - ret = sscanf(cfg->data + data_pos, "%x%n", &info_crc, &offset); + ret = sscanf(cfg.raw + cfg.raw_pos, "%x%n", &info_crc, &offset); if (ret != 1) { dev_err(dev, "Bad format: failed to parse Info CRC\n"); return -EINVAL; } - data_pos += offset; + cfg.raw_pos += offset; - ret = sscanf(cfg->data + data_pos, "%x%n", &config_crc, &offset); + ret = sscanf(cfg.raw + cfg.raw_pos, "%x%n", &config_crc, &offset); if (ret != 1) { dev_err(dev, "Bad format: failed to parse Config CRC\n"); return -EINVAL; } - data_pos += offset; + cfg.raw_pos += offset; /* * The Info Block CRC is calculated over mxt_info and the object @@ -1869,16 +1875,15 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg) } /* Malloc memory to store configuration */ - cfg_start_ofs = MXT_OBJECT_START + + cfg.start_ofs = MXT_OBJECT_START + 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); - if (!config_mem) + cfg.mem_size = data->mem_size - cfg.start_ofs; + cfg.mem = kzalloc(cfg.mem_size, GFP_KERNEL); + if (!cfg.mem) return -ENOMEM; - ret = mxt_prepare_cfg_mem(data, cfg, data_pos, cfg_start_ofs, - config_mem, config_mem_size); + ret = mxt_prepare_cfg_mem(data, &cfg); if (ret) goto release_mem; @@ -1890,18 +1895,17 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg) else dev_warn(dev, "Could not find CRC start\n"); - if (crc_start > cfg_start_ofs) { - calculated_crc = mxt_calculate_crc(config_mem, - crc_start - cfg_start_ofs, - config_mem_size); + if (crc_start > cfg.start_ofs) { + calculated_crc = mxt_calculate_crc(cfg.mem, + crc_start - cfg.start_ofs, + cfg.mem_size); if (config_crc > 0 && config_crc != calculated_crc) dev_warn(dev, "Config CRC in file inconsistent, calculated=%06X, file=%06X\n", calculated_crc, config_crc); } - ret = mxt_upload_cfg_mem(data, cfg_start_ofs, - config_mem, config_mem_size); + ret = mxt_upload_cfg_mem(data, &cfg); if (ret) goto release_mem; @@ -1921,7 +1925,7 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg) mxt_init_t7_power_cfg(data); release_mem: - kfree(config_mem); + kfree(cfg.mem); return ret; } From 4c720900a95d46a3c4b4f8a0f9d6ff0bf6e33e1b Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Fri, 22 Apr 2016 17:10:16 +0100 Subject: [PATCH 10/10] Input: atmel_mxt_ts - zero terminate config firmware file We use sscanf to parse the configuration file, so it's necessary to zero terminate the configuration otherwise a truncated file can cause the parser to run off into uninitialised memory. Signed-off-by: Nick Dyer --- drivers/input/touchscreen/atmel_mxt_ts.c | 34 +++++++++++++++++------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 8cb04dd072c2df..fb7f00d27c6539 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -1801,14 +1801,21 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw) u32 info_crc, config_crc, calculated_crc; u16 crc_start = 0; - cfg.raw = fw->data; + /* Make zero terminated copy of the OBP_RAW file */ + cfg.raw = kzalloc(fw->size + 1, GFP_KERNEL); + if (!cfg.raw) + return -ENOMEM; + + memcpy(cfg.raw, fw->data, fw->size); + cfg.raw[fw->size] = '\0'; cfg.raw_size = fw->size; mxt_update_crc(data, MXT_COMMAND_REPORTALL, 1); if (strncmp(cfg.raw, MXT_CFG_MAGIC, strlen(MXT_CFG_MAGIC))) { dev_err(dev, "Unrecognised config file\n"); - return -EINVAL; + ret = -EINVAL; + goto release_raw; } cfg.raw_pos = strlen(MXT_CFG_MAGIC); @@ -1820,7 +1827,8 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw) &offset); if (ret != 1) { dev_err(dev, "Bad format\n"); - return -EINVAL; + ret = -EINVAL; + goto release_raw; } cfg.raw_pos += offset; @@ -1828,26 +1836,30 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw) if (cfg.info.family_id != data->info->family_id) { dev_err(dev, "Family ID mismatch!\n"); - return -EINVAL; + ret = -EINVAL; + goto release_raw; } if (cfg.info.variant_id != data->info->variant_id) { dev_err(dev, "Variant ID mismatch!\n"); - return -EINVAL; + ret = -EINVAL; + goto release_raw; } /* Read CRCs */ ret = sscanf(cfg.raw + cfg.raw_pos, "%x%n", &info_crc, &offset); if (ret != 1) { dev_err(dev, "Bad format: failed to parse Info CRC\n"); - return -EINVAL; + ret = -EINVAL; + goto release_raw; } cfg.raw_pos += offset; ret = sscanf(cfg.raw + cfg.raw_pos, "%x%n", &config_crc, &offset); if (ret != 1) { dev_err(dev, "Bad format: failed to parse Config CRC\n"); - return -EINVAL; + ret = -EINVAL; + goto release_raw; } cfg.raw_pos += offset; @@ -1880,8 +1892,10 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw) MXT_INFO_CHECKSUM_SIZE; cfg.mem_size = data->mem_size - cfg.start_ofs; cfg.mem = kzalloc(cfg.mem_size, GFP_KERNEL); - if (!cfg.mem) - return -ENOMEM; + if (!cfg.mem) { + ret = -ENOMEM; + goto release_raw; + } ret = mxt_prepare_cfg_mem(data, &cfg); if (ret) @@ -1924,6 +1938,8 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw) /* T7 config may have changed */ mxt_init_t7_power_cfg(data); +release_raw: + kfree(cfg.raw); release_mem: kfree(cfg.mem); return ret;