aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorNick Dyer <nick.dyer@itdev.co.uk>2014-07-23 15:40:09 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2014-07-23 17:42:08 -0400
commit4ce6fa017f48e892cc3465caa7fbb3dead5a6ca6 (patch)
treedf6ee6662152f8adc047ab675c61f042140ee629 /drivers
parent50a77c658b80e7e3303e3bcec195b30e2b62d513 (diff)
Input: atmel_mxt_ts - calculate and check CRC in config file
By validating the checksum, we can identify if the configuration is corrupt. In addition, this patch writes the configuration in a short series of block writes rather than as many individual values. Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk> Acked-by: Benson Leung <bleung@chromium.org> Acked-by: Yufeng Shen <miletus@chromium.org> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/input/touchscreen/atmel_mxt_ts.c232
1 files changed, 177 insertions, 55 deletions
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index c6b5e7dbd942..d2feb9c771a4 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -48,6 +48,8 @@
48#define MXT_OBJECT_START 0x07 48#define MXT_OBJECT_START 0x07
49 49
50#define MXT_OBJECT_SIZE 6 50#define MXT_OBJECT_SIZE 6
51#define MXT_INFO_CHECKSUM_SIZE 3
52#define MXT_MAX_BLOCK_WRITE 256
51 53
52/* Object types */ 54/* Object types */
53#define MXT_DEBUG_DIAGNOSTIC_T37 37 55#define MXT_DEBUG_DIAGNOSTIC_T37 37
@@ -238,12 +240,15 @@ struct mxt_data {
238 unsigned int max_x; 240 unsigned int max_x;
239 unsigned int max_y; 241 unsigned int max_y;
240 bool in_bootloader; 242 bool in_bootloader;
243 u16 mem_size;
241 u32 config_crc; 244 u32 config_crc;
245 u32 info_crc;
242 u8 bootloader_addr; 246 u8 bootloader_addr;
243 247
244 /* Cached parameters from object table */ 248 /* Cached parameters from object table */
245 u8 T6_reportid; 249 u8 T6_reportid;
246 u16 T6_address; 250 u16 T6_address;
251 u16 T7_address;
247 u8 T9_reportid_min; 252 u8 T9_reportid_min;
248 u8 T9_reportid_max; 253 u8 T9_reportid_max;
249 u8 T19_reportid; 254 u8 T19_reportid;
@@ -849,6 +854,45 @@ static void mxt_update_crc(struct mxt_data *data, u8 cmd, u8 value)
849 mxt_wait_for_completion(data, &data->crc_completion, MXT_CRC_TIMEOUT); 854 mxt_wait_for_completion(data, &data->crc_completion, MXT_CRC_TIMEOUT);
850} 855}
851 856
857static void mxt_calc_crc24(u32 *crc, u8 firstbyte, u8 secondbyte)
858{
859 static const unsigned int crcpoly = 0x80001B;
860 u32 result;
861 u32 data_word;
862
863 data_word = (secondbyte << 8) | firstbyte;
864 result = ((*crc << 1) ^ data_word);
865
866 if (result & 0x1000000)
867 result ^= crcpoly;
868
869 *crc = result;
870}
871
872static u32 mxt_calculate_crc(u8 *base, off_t start_off, off_t end_off)
873{
874 u32 crc = 0;
875 u8 *ptr = base + start_off;
876 u8 *last_val = base + end_off - 1;
877
878 if (end_off < start_off)
879 return -EINVAL;
880
881 while (ptr < last_val) {
882 mxt_calc_crc24(&crc, *ptr, *(ptr + 1));
883 ptr += 2;
884 }
885
886 /* if len is odd, fill the last byte with 0 */
887 if (ptr == last_val)
888 mxt_calc_crc24(&crc, *ptr, 0);
889
890 /* Mask to 24-bit */
891 crc &= 0x00FFFFFF;
892
893 return crc;
894}
895
852/* 896/*
853 * mxt_update_cfg - download configuration to chip 897 * mxt_update_cfg - download configuration to chip
854 * 898 *
@@ -875,9 +919,13 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg)
875 struct mxt_object *object; 919 struct mxt_object *object;
876 int ret; 920 int ret;
877 int offset; 921 int offset;
878 int pos; 922 int data_pos;
923 int byte_offset;
879 int i; 924 int i;
880 u32 info_crc, config_crc; 925 int cfg_start_ofs;
926 u32 info_crc, config_crc, calculated_crc;
927 u8 *config_mem;
928 size_t config_mem_size;
881 unsigned int type, instance, size; 929 unsigned int type, instance, size;
882 u8 val; 930 u8 val;
883 u16 reg; 931 u16 reg;
@@ -890,11 +938,11 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg)
890 goto release; 938 goto release;
891 } 939 }
892 940
893 pos = strlen(MXT_CFG_MAGIC); 941 data_pos = strlen(MXT_CFG_MAGIC);
894 942
895 /* Load information block and check */ 943 /* Load information block and check */
896 for (i = 0; i < sizeof(struct mxt_info); i++) { 944 for (i = 0; i < sizeof(struct mxt_info); i++) {
897 ret = sscanf(cfg->data + pos, "%hhx%n", 945 ret = sscanf(cfg->data + data_pos, "%hhx%n",
898 (unsigned char *)&cfg_info + i, 946 (unsigned char *)&cfg_info + i,
899 &offset); 947 &offset);
900 if (ret != 1) { 948 if (ret != 1) {
@@ -903,7 +951,7 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg)
903 goto release; 951 goto release;
904 } 952 }
905 953
906 pos += offset; 954 data_pos += offset;
907 } 955 }
908 956
909 if (cfg_info.family_id != data->info.family_id) { 957 if (cfg_info.family_id != data->info.family_id) {
@@ -918,125 +966,188 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg)
918 goto release; 966 goto release;
919 } 967 }
920 968
921 if (cfg_info.version != data->info.version) 969 /* Read CRCs */
922 dev_err(dev, "Warning: version mismatch!\n"); 970 ret = sscanf(cfg->data + data_pos, "%x%n", &info_crc, &offset);
923
924 if (cfg_info.build != data->info.build)
925 dev_err(dev, "Warning: build num mismatch!\n");
926
927 ret = sscanf(cfg->data + pos, "%x%n", &info_crc, &offset);
928 if (ret != 1) { 971 if (ret != 1) {
929 dev_err(dev, "Bad format: failed to parse Info CRC\n"); 972 dev_err(dev, "Bad format: failed to parse Info CRC\n");
930 ret = -EINVAL; 973 ret = -EINVAL;
931 goto release; 974 goto release;
932 } 975 }
933 pos += offset; 976 data_pos += offset;
934 977
935 /* Check config CRC */ 978 ret = sscanf(cfg->data + data_pos, "%x%n", &config_crc, &offset);
936 ret = sscanf(cfg->data + pos, "%x%n", &config_crc, &offset);
937 if (ret != 1) { 979 if (ret != 1) {
938 dev_err(dev, "Bad format: failed to parse Config CRC\n"); 980 dev_err(dev, "Bad format: failed to parse Config CRC\n");
939 ret = -EINVAL; 981 ret = -EINVAL;
940 goto release; 982 goto release;
941 } 983 }
942 pos += offset; 984 data_pos += offset;
943 985
944 if (data->config_crc == config_crc) { 986 /*
945 dev_dbg(dev, "Config CRC 0x%06X: OK\n", config_crc); 987 * The Info Block CRC is calculated over mxt_info and the object
946 ret = 0; 988 * table. If it does not match then we are trying to load the
947 goto release; 989 * configuration from a different chip or firmware version, so
990 * the configuration CRC is invalid anyway.
991 */
992 if (info_crc == data->info_crc) {
993 if (config_crc == 0 || data->config_crc == 0) {
994 dev_info(dev, "CRC zero, attempting to apply config\n");
995 } else if (config_crc == data->config_crc) {
996 dev_dbg(dev, "Config CRC 0x%06X: OK\n",
997 data->config_crc);
998 ret = 0;