diff options
| author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2014-08-08 12:29:06 -0400 |
|---|---|---|
| committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2014-08-13 12:16:11 -0400 |
| commit | efdbd7ae44f35cbb2b29d825640b917723319f7b (patch) | |
| tree | 049280c9ff4809027e20988913b2c240d069b047 /drivers/input/touchscreen | |
| parent | 6cd1ab0fb67f21e6e35eee35106d8dd2f08b544c (diff) | |
Input: atmel_mxt_ts - split config update a bit
Let's split config update code a bit so it is hopefully a bit easier to
read. Also, the firmware update callback should be the entity releasing
firmware blob, not lower layers.
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
Diffstat (limited to 'drivers/input/touchscreen')
| -rw-r--r-- | drivers/input/touchscreen/atmel_mxt_ts.c | 270 |
1 files changed, 145 insertions, 125 deletions
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index a5f943dedb20..bbaf3ff680ed 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c | |||
| @@ -1064,6 +1064,133 @@ static u32 mxt_calculate_crc(u8 *base, off_t start_off, off_t end_off) | |||
| 1064 | return crc; | 1064 | return crc; |
| 1065 | } | 1065 | } |
| 1066 | 1066 | ||
| 1067 | static int mxt_prepare_cfg_mem(struct mxt_data *data, | ||
| 1068 | const struct firmware *cfg, | ||
| 1069 | unsigned int data_pos, | ||
| 1070 | unsigned int cfg_start_ofs, | ||
| 1071 | u8 *config_mem, | ||
| 1072 | size_t config_mem_size) | ||
| 1073 | { | ||
| 1074 | struct device *dev = &data->client->dev; | ||
| 1075 | struct mxt_object *object; | ||
| 1076 | unsigned int type, instance, size, byte_offset; | ||
| 1077 | int offset; | ||
| 1078 | int ret; | ||
| 1079 | int i; | ||
| 1080 | u16 reg; | ||
| 1081 | u8 val; | ||
| 1082 | |||
| 1083 | while (data_pos < cfg->size) { | ||
| 1084 | /* Read type, instance, length */ | ||
| 1085 | ret = sscanf(cfg->data + data_pos, "%x %x %x%n", | ||
| 1086 | &type, &instance, &size, &offset); | ||
| 1087 | if (ret == 0) { | ||
| 1088 | /* EOF */ | ||
| 1089 | break; | ||
| 1090 | } else if (ret != 3) { | ||
| 1091 | dev_err(dev, "Bad format: failed to parse object\n"); | ||
| 1092 | return -EINVAL; | ||
| 1093 | } | ||
| 1094 | data_pos += offset; | ||
| 1095 | |||
| 1096 | object = mxt_get_object(data, type); | ||
| 1097 | if (!object) { | ||
| 1098 | /* Skip object */ | ||
| 1099 | for (i = 0; i < size; i++) { | ||
| 1100 | ret = sscanf(cfg->data + data_pos, "%hhx%n", | ||
| 1101 | &val, | ||
| 1102 | &offset); | ||
| 1103 | data_pos += offset; | ||
| 1104 | } | ||
| 1105 | continue; | ||
| 1106 | } | ||
| 1107 | |||
| 1108 | if (size > mxt_obj_size(object)) { | ||
| 1109 | /* | ||
| 1110 | * Either we are in fallback mode due to wrong | ||
| 1111 | * config or config from a later fw version, | ||
| 1112 | * or the file is corrupt or hand-edited. | ||
| 1113 | */ | ||
| 1114 | dev_warn(dev, "Discarding %zu byte(s) in T%u\n", | ||
| 1115 | size - mxt_obj_size(object), type); | ||
| 1116 | } else if (mxt_obj_size(object) > size) { | ||
| 1117 | /* | ||
| 1118 | * If firmware is upgraded, new bytes may be added to | ||
| 1119 | * end of objects. It is generally forward compatible | ||
| 1120 | * to zero these bytes - previous behaviour will be | ||
| 1121 | * retained. However this does invalidate the CRC and | ||
| 1122 | * will force fallback mode until the configuration is | ||
| 1123 | * updated. We warn here but do nothing else - the | ||
| 1124 | * malloc has zeroed the entire configuration. | ||
| 1125 | */ | ||
| 1126 | dev_warn(dev, "Zeroing %zu byte(s) in T%d\n", | ||
| 1127 | mxt_obj_size(object) - size, type); | ||
| 1128 | } | ||
| 1129 | |||
| 1130 | if (instance >= mxt_obj_instances(object)) { | ||
| 1131 | dev_err(dev, "Object instances exceeded!\n"); | ||
| 1132 | return -EINVAL; | ||
| 1133 | } | ||
| 1134 | |||
| 1135 | reg = object->start_address + mxt_obj_size(object) * instance; | ||
| 1136 | |||
| 1137 | for (i = 0; i < size; i++) { | ||
| 1138 | ret = sscanf(cfg->data + data_pos, "%hhx%n", | ||
| 1139 | &val, | ||
| 1140 | &offset); | ||
| 1141 | if (ret != 1) { | ||
| 1142 | dev_err(dev, "Bad format in T%d\n", type); | ||
| 1143 | return -EINVAL; | ||
| 1144 | } | ||
| 1145 | data_pos += offset; | ||
| 1146 | |||
| 1147 | if (i > mxt_obj_size(object)) | ||
| 1148 | continue; | ||
| 1149 | |||
| 1150 | byte_offset = reg + i - cfg_start_ofs; | ||
| 1151 | |||
| 1152 | if (byte_offset >= 0 && | ||
| 1153 | byte_offset <= config_mem_size) { | ||
| 1154 | *(config_mem + byte_offset) = val; | ||
| 1155 | } else { | ||
| 1156 | dev_err(dev, "Bad object: reg:%d, T%d, ofs=%d\n", | ||
| 1157 | reg, object->type, byte_offset); | ||
| 1158 | return -EINVAL; | ||
| 1159 | } | ||
| 1160 | } | ||
| 1161 | } | ||
| 1162 | |||
| 1163 | return 0; | ||
| 1164 | } | ||
| 1165 | |||
| 1166 | static int mxt_upload_cfg_mem(struct mxt_data *data, unsigned int cfg_start, | ||
| 1167 | u8 *config_mem, size_t config_mem_size) | ||
| 1168 | { | ||
| 1169 | unsigned int byte_offset = 0; | ||
| 1170 | int error; | ||
| 1171 | |||
| 1172 | /* Write configuration as blocks */ | ||
| 1173 | while (byte_offset < config_mem_size) { | ||
| 1174 | unsigned int size = config_mem_size - byte_offset; | ||
| 1175 | |||
| 1176 | if (size > MXT_MAX_BLOCK_WRITE) | ||
| 1177 | size = MXT_MAX_BLOCK_WRITE; | ||
| 1178 | |||
| 1179 | error = __mxt_write_reg(data->client, | ||
| 1180 | cfg_start + byte_offset, | ||
| 1181 | size, config_mem + byte_offset); | ||
| 1182 | if (error) { | ||
| 1183 | dev_err(&data->client->dev, | ||
| 1184 | "Config write error, ret=%d\n", error); | ||
| 1185 | return error; | ||
| 1186 | } | ||
| 1187 | |||
| 1188 | byte_offset += size; | ||
| 1189 | } | ||
| 1190 | |||
| 1191 | return 0; | ||
| 1192 | } | ||
| 1193 | |||
| 1067 | /* | 1194 | /* |
| 1068 | * mxt_update_cfg - download configuration to chip | 1195 | * mxt_update_cfg - download configuration to chip |
| 1069 | * | 1196 | * |
| @@ -1087,26 +1214,20 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg) | |||
| 1087 | { | 1214 | { |
| 1088 | struct device *dev = &data->client->dev; | 1215 | struct device *dev = &data->client->dev; |
| 1089 | struct mxt_info cfg_info; | 1216 | struct mxt_info cfg_info; |
| 1090 | struct mxt_object *object; | ||
| 1091 | int ret; | 1217 | int ret; |
| 1092 | int offset; | 1218 | int offset; |
| 1093 | int data_pos; | 1219 | int data_pos; |
| 1094 | int byte_offset; | ||
| 1095 | int i; | 1220 | int i; |
| 1096 | int cfg_start_ofs; | 1221 | int cfg_start_ofs; |
| 1097 | u32 info_crc, config_crc, calculated_crc; | 1222 | u32 info_crc, config_crc, calculated_crc; |
| 1098 | u8 *config_mem; | 1223 | u8 *config_mem; |
| 1099 | size_t config_mem_size; | 1224 | size_t config_mem_size; |
| 1100 | unsigned int type, instance, size; | ||
| 1101 | u8 val; | ||
| 1102 | u16 reg; | ||
| 1103 | 1225 | ||
| 1104 | mxt_update_crc(data, MXT_COMMAND_REPORTALL, 1); | 1226 | mxt_update_crc(data, MXT_COMMAND_REPORTALL, 1); |
| 1105 | 1227 | ||
| 1106 | if (strncmp(cfg->data, MXT_CFG_MAGIC, strlen(MXT_CFG_MAGIC))) { | 1228 | if (strncmp(cfg->data, MXT_CFG_MAGIC, strlen(MXT_CFG_MAGIC))) { |
| 1107 | dev_err(dev, "Unrecognised config file\n"); | 1229 | dev_err(dev, "Unrecognised config file\n"); |
| 1108 | ret = -EINVAL; | 1230 | return -EINVAL; |
| 1109 | goto release; | ||
| 1110 | } | 1231 | } |
| 1111 | 1232 | ||
| 1112 | data_pos = strlen(MXT_CFG_MAGIC); | 1233 | data_pos = strlen(MXT_CFG_MAGIC); |
| @@ -1118,8 +1239,7 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg) | |||
| 1118 | &offset); | 1239 | &offset); |
| 1119 | if (ret != 1) { | 1240 | if (ret != 1) { |
| 1120 | dev_err(dev, "Bad format\n"); | ||
