diff options
-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) |