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 | |
| 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>
| -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"); | 1241 | dev_err(dev, "Bad format\n"); |
| 1121 | ret = -EINVAL; | 1242 | return -EINVAL; |
| 1122 | goto release; | ||
| 1123 | } | 1243 | } |
| 1124 | 1244 | ||
| 1125 | data_pos += offset; | 1245 | data_pos += offset; |
| @@ -1127,30 +1247,26 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg) | |||
| 1127 | 1247 | ||
| 1128 | if (cfg_info.family_id != data->info.family_id) { | 1248 | if (cfg_info.family_id != data->info.family_id) { |
| 1129 | dev_err(dev, "Family ID mismatch!\n"); | 1249 | dev_err(dev, "Family ID mismatch!\n"); |
| 1130 | ret = -EINVAL; | 1250 | return -EINVAL; |
| 1131 | goto release; | ||
| 1132 | } | 1251 | } |
| 1133 | 1252 | ||
| 1134 | if (cfg_info.variant_id != data->info.variant_id) { | 1253 | if (cfg_info.variant_id != data->info.variant_id) { |
| 1135 | dev_err(dev, "Variant ID mismatch!\n"); | 1254 | dev_err(dev, "Variant ID mismatch!\n"); |
| 1136 | ret = -EINVAL; | 1255 | return -EINVAL; |
| 1137 | goto release; | ||
| 1138 | } | 1256 | } |
| 1139 | 1257 | ||
| 1140 | /* Read CRCs */ | 1258 | /* Read CRCs */ |
| 1141 | ret = sscanf(cfg->data + data_pos, "%x%n", &info_crc, &offset); | 1259 | ret = sscanf(cfg->data + data_pos, "%x%n", &info_crc, &offset); |
| 1142 | if (ret != 1) { | 1260 | if (ret != 1) { |
| 1143 | dev_err(dev, "Bad format: failed to parse Info CRC\n"); | 1261 | dev_err(dev, "Bad format: failed to parse Info CRC\n"); |
| 1144 | ret = -EINVAL; | 1262 | return -EINVAL; |
| 1145 | goto release; | ||
| 1146 | } | 1263 | } |
| 1147 | data_pos += offset; | 1264 | data_pos += offset; |
| 1148 | 1265 | ||
| 1149 | ret = sscanf(cfg->data + data_pos, "%x%n", &config_crc, &offset); | 1266 | ret = sscanf(cfg->data + data_pos, "%x%n", &config_crc, &offset); |
| 1150 | if (ret != 1) { | 1267 | if (ret != 1) { |
| 1151 | dev_err(dev, "Bad format: failed to parse Config CRC\n"); | 1268 | dev_err(dev, "Bad format: failed to parse Config CRC\n"); |
| 1152 | ret = -EINVAL; | 1269 | return -EINVAL; |
| 1153 | goto release; | ||
| 1154 | } | 1270 | } |
| 1155 | data_pos += offset; | 1271 | data_pos += offset; |
| 1156 | 1272 | ||
| @@ -1166,8 +1282,7 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg) | |||
| 1166 | } else if (config_crc == data->config_crc) { | 1282 | } else if (config_crc == data->config_crc) { |
| 1167 | dev_dbg(dev, "Config CRC 0x%06X: OK\n", | 1283 | dev_dbg(dev, "Config CRC 0x%06X: OK\n", |
| 1168 | data->config_crc); | 1284 | data->config_crc); |
| 1169 | ret = 0; | 1285 | return 0; |
| 1170 | goto release; | ||
| 1171 | } else { | 1286 | } else { |
| 1172 | dev_info(dev, "Config CRC 0x%06X: does not match file 0x%06X\n", | 1287 | dev_info(dev, "Config CRC 0x%06X: does not match file 0x%06X\n", |
| 1173 | data->config_crc, config_crc); | 1288 | data->config_crc, config_crc); |
| @@ -1186,93 +1301,13 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg) | |||
| 1186 | config_mem = kzalloc(config_mem_size, GFP_KERNEL); | 1301 | config_mem = kzalloc(config_mem_size, GFP_KERNEL); |
| 1187 | if (!config_mem) { | 1302 | if (!config_mem) { |
| 1188 | dev_err(dev, "Failed to allocate memory\n"); | 1303 | dev_err(dev, "Failed to allocate memory\n"); |
| 1189 | ret = -ENOMEM; | 1304 | return -ENOMEM; |
| 1190 | goto release; | ||
| 1191 | } | 1305 | } |
| 1192 | 1306 | ||
| 1193 | while (data_pos < cfg->size) { | 1307 | ret = mxt_prepare_cfg_mem(data, cfg, data_pos, cfg_start_ofs, |
| 1194 | /* Read type, instance, length */ | 1308 | config_mem, config_mem_size); |
| 1195 | ret = sscanf(cfg->data + data_pos, "%x %x %x%n", | 1309 | if (ret) |
| 1196 | &type, &instance, &size, &offset); | 1310 | goto release_mem; |
| 1197 | if (ret == 0) { | ||
| 1198 | /* EOF */ | ||
| 1199 | break; | ||
| 1200 | } else if (ret != 3) { | ||
| 1201 | dev_err(dev, "Bad format: failed to parse object\n"); | ||
| 1202 | ret = -EINVAL; | ||
| 1203 | goto release_mem; | ||
| 1204 | } | ||
| 1205 | data_pos += offset; | ||
| 1206 | |||
| 1207 | object = mxt_get_object(data, type); | ||
| 1208 | if (!object) { | ||
| 1209 | /* Skip object */ | ||
| 1210 | for (i = 0; i < size; i++) { | ||
| 1211 | ret = sscanf(cfg->data + data_pos, "%hhx%n", | ||
| 1212 | &val, | ||
| 1213 | &offset); | ||
| 1214 | data_pos += offset; | ||
| 1215 | } | ||
| 1216 | continue; | ||
| 1217 | } | ||
| 1218 | |||
| 1219 | if (size > mxt_obj_size(object)) { | ||
| 1220 | /* | ||
| 1221 | * Either we are in fallback mode due to wrong | ||
| 1222 | * config or config from a later fw version, | ||
| 1223 | * or the file is corrupt or hand-edited. | ||
| 1224 | */ | ||
| 1225 | dev_warn(dev, "Discarding %zu byte(s) in T%u\n", | ||
| 1226 | size - mxt_obj_size(object), type); | ||
| 1227 | } else if (mxt_obj_size(object) > size) { | ||
| 1228 | /* | ||
| 1229 | * If firmware is upgraded, new bytes may be added to | ||
| 1230 | * end of objects. It is generally forward compatible | ||
| 1231 | * to zero these bytes - previous behaviour will be | ||
| 1232 | * retained. However this does invalidate the CRC and | ||
| 1233 | * will force fallback mode until the configuration is | ||
| 1234 | * updated. We warn here but do nothing else - the | ||
| 1235 | * malloc has zeroed the entire configuration. | ||
| 1236 | */ | ||
| 1237 | dev_warn(dev, "Zeroing %zu byte(s) in T%d\n", | ||
| 1238 | mxt_obj_size(object) - size, type); | ||
| 1239 | } | ||
| 1240 | |||
| 1241 | if (instance >= mxt_obj_instances(object)) { | ||
| 1242 | dev_err(dev, "Object instances exceeded!\n"); | ||
| 1243 | ret = -EINVAL; | ||
| 1244 | goto release_mem; | ||
| 1245 | } | ||
| 1246 | |||
| 1247 | reg = object->start_address + mxt_obj_size(object) * instance; | ||
| 1248 | |||
| 1249 | for (i = 0; i < size; i++) { | ||
| 1250 | ret = sscanf(cfg->data + data_pos, "%hhx%n", | ||
| 1251 | &val, | ||
| 1252 | &offset); | ||
| 1253 | if (ret != 1) { | ||
| 1254 | dev_err(dev, "Bad format in T%d\n", type); | ||
| 1255 | ret = -EINVAL; | ||
| 1256 | goto release_mem; | ||
| 1257 | } | ||
| 1258 | data_pos += offset; | ||
| 1259 | |||
| 1260 | if (i > mxt_obj_size(object)) | ||
| 1261 | continue; | ||
| 1262 | |||
| 1263 | byte_offset = reg + i - cfg_start_ofs; | ||
| 1264 | |||
| 1265 | if ((byte_offset >= 0) | ||
| 1266 | && (byte_offset <= config_mem_size)) { | ||
| 1267 | *(config_mem + byte_offset) = val; | ||
| 1268 | } else { | ||
| 1269 | dev_err(dev, "Bad object: reg:%d, T%d, ofs=%d\n", | ||
| 1270 | reg, object->type, byte_offset); | ||
| 1271 | ret = -EINVAL; | ||
| 1272 | goto release_mem; | ||
| 1273 | } | ||
| 1274 | } | ||
| 1275 | } | ||
| 1276 | 1311 | ||
| 1277 | /* Calculate crc of the received configs (not the raw config file) */ | 1312 | /* Calculate crc of the received configs (not the raw config file) */ |
| 1278 | if (data->T7_address < cfg_start_ofs) { | 1313 | if (data->T7_address < cfg_start_ofs) { |
| @@ -1286,28 +1321,14 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg) | |||
| 1286 | data->T7_address - cfg_start_ofs, | 1321 | data->T7_address - cfg_start_ofs, |
| 1287 | config_mem_size); | 1322 | config_mem_size); |
| 1288 | 1323 | ||
| 1289 | if (config_crc > 0 && (config_crc != calculated_crc)) | 1324 | if (config_crc > 0 && config_crc != calculated_crc) |
| 1290 | dev_warn(dev, "Config CRC error, calculated=%06X, file=%06X\n", | 1325 | dev_warn(dev, "Config CRC error, calculated=%06X, file=%06X\n", |
| 1291 | calculated_crc, config_crc); | 1326 | calculated_crc, config_crc); |
| 1292 | 1327 | ||
| 1293 | /* Write configuration as blocks */ | 1328 | ret = mxt_upload_cfg_mem(data, cfg_start_ofs, |
| 1294 | byte_offset = 0; | 1329 | config_mem, config_mem_size); |
| 1295 | while (byte_offset < config_mem_size) { | 1330 | if (ret) |
| 1296 | size = config_mem_size - byte_offset; | 1331 | goto release_mem; |
| 1297 | |||
| 1298 | if (size > MXT_MAX_BLOCK_WRITE) | ||
| 1299 | size = MXT_MAX_BLOCK_WRITE; | ||
| 1300 | |||
| 1301 | ret = __mxt_write_reg(data->client, | ||
| 1302 | cfg_start_ofs + byte_offset, | ||
| 1303 | size, config_mem + byte_offset); | ||
| 1304 | if (ret != 0) { | ||
| 1305 | dev_err(dev, "Config write error, ret=%d\n", ret); | ||
| 1306 | goto release_mem; | ||
| 1307 | } | ||
| 1308 | |||
| 1309 | byte_offset += size; | ||
| 1310 | } | ||
| 1311 | 1332 | ||
| 1312 | mxt_update_crc(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE); | 1333 | mxt_update_crc(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE); |
| 1313 | 1334 | ||
| @@ -1319,8 +1340,6 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg) | |||
| 1319 | 1340 | ||
| 1320 | release_mem: | 1341 | release_mem: |
| 1321 | kfree(config_mem); | 1342 | kfree(config_mem); |
| 1322 | release: | ||
| 1323 | release_firmware(cfg); | ||
| 1324 | return ret; | 1343 | return ret; |
| 1325 | } | 1344 | } |
| 1326 | 1345 | ||
| @@ -1640,6 +1659,7 @@ static int mxt_configure_objects(struct mxt_data *data, | |||
| 1640 | static void mxt_config_cb(const struct firmware *cfg, void *ctx) | 1659 | static void mxt_config_cb(const struct firmware *cfg, void *ctx) |
| 1641 | { | 1660 | { |
| 1642 | mxt_configure_objects(ctx, cfg); | 1661 | mxt_configure_objects(ctx, cfg); |
| 1662 | release_firmware(cfg); | ||
| 1643 | } | 1663 | } |
| 1644 | 1664 | ||
| 1645 | static int mxt_initialize(struct mxt_data *data) | 1665 | static int mxt_initialize(struct mxt_data *data) |
