diff options
Diffstat (limited to 'drivers/media/common')
-rw-r--r-- | drivers/media/common/tuners/tuner-xc2028.c | 178 |
1 files changed, 129 insertions, 49 deletions
diff --git a/drivers/media/common/tuners/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c index b5ee3ebfcfca..9638a69f36b2 100644 --- a/drivers/media/common/tuners/tuner-xc2028.c +++ b/drivers/media/common/tuners/tuner-xc2028.c | |||
@@ -90,11 +90,22 @@ struct firmware_properties { | |||
90 | int scode_nr; | 90 | int scode_nr; |
91 | }; | 91 | }; |
92 | 92 | ||
93 | enum xc2028_state { | ||
94 | XC2028_NO_FIRMWARE = 0, | ||
95 | XC2028_WAITING_FIRMWARE, | ||
96 | XC2028_ACTIVE, | ||
97 | XC2028_SLEEP, | ||
98 | XC2028_NODEV, | ||
99 | }; | ||
100 | |||
93 | struct xc2028_data { | 101 | struct xc2028_data { |
94 | struct list_head hybrid_tuner_instance_list; | 102 | struct list_head hybrid_tuner_instance_list; |
95 | struct tuner_i2c_props i2c_props; | 103 | struct tuner_i2c_props i2c_props; |
96 | __u32 frequency; | 104 | __u32 frequency; |
97 | 105 | ||
106 | enum xc2028_state state; | ||
107 | const char *fname; | ||
108 | |||
98 | struct firmware_description *firm; | 109 | struct firmware_description *firm; |
99 | int firm_size; | 110 | int firm_size; |
100 | __u16 firm_version; | 111 | __u16 firm_version; |
@@ -255,6 +266,21 @@ static v4l2_std_id parse_audio_std_option(void) | |||
255 | return 0; | 266 | return 0; |
256 | } | 267 | } |
257 | 268 | ||
269 | static int check_device_status(struct xc2028_data *priv) | ||
270 | { | ||
271 | switch (priv->state) { | ||
272 | case XC2028_NO_FIRMWARE: | ||
273 | case XC2028_WAITING_FIRMWARE: | ||
274 | return -EAGAIN; | ||
275 | case XC2028_ACTIVE: | ||
276 | case XC2028_SLEEP: | ||
277 | return 0; | ||
278 | case XC2028_NODEV: | ||
279 | return -ENODEV; | ||
280 | } | ||
281 | return 0; | ||
282 | } | ||
283 | |||
258 | static void free_firmware(struct xc2028_data *priv) | 284 | static void free_firmware(struct xc2028_data *priv) |
259 | { | 285 | { |
260 | int i; | 286 | int i; |
@@ -270,45 +296,28 @@ static void free_firmware(struct xc2028_data *priv) | |||
270 | 296 | ||
271 | priv->firm = NULL; | 297 | priv->firm = NULL; |
272 | priv->firm_size = 0; | 298 | priv->firm_size = 0; |
299 | priv->state = XC2028_NO_FIRMWARE; | ||
273 | 300 | ||
274 | memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); | 301 | memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); |
275 | } | 302 | } |
276 | 303 | ||
277 | static int load_all_firmwares(struct dvb_frontend *fe) | 304 | static int load_all_firmwares(struct dvb_frontend *fe, |
305 | const struct firmware *fw) | ||
278 | { | 306 | { |
279 | struct xc2028_data *priv = fe->tuner_priv; | 307 | struct xc2028_data *priv = fe->tuner_priv; |
280 | const struct firmware *fw = NULL; | ||
281 | const unsigned char *p, *endp; | 308 | const unsigned char *p, *endp; |
282 | int rc = 0; | 309 | int rc = 0; |
283 | int n, n_array; | 310 | int n, n_array; |
284 | char name[33]; | 311 | char name[33]; |
285 | char *fname; | ||
286 | 312 | ||
287 | tuner_dbg("%s called\n", __func__); | 313 | tuner_dbg("%s called\n", __func__); |
288 | 314 | ||
289 | if (!firmware_name[0]) | ||
290 | fname = priv->ctrl.fname; | ||
291 | else | ||
292 | fname = firmware_name; | ||
293 | |||
294 | tuner_dbg("Reading firmware %s\n", fname); | ||
295 | rc = request_firmware(&fw, fname, priv->i2c_props.adap->dev.parent); | ||
296 | if (rc < 0) { | ||
297 | if (rc == -ENOENT) | ||
298 | tuner_err("Error: firmware %s not found.\n", | ||
299 | fname); | ||
300 | else | ||
301 | tuner_err("Error %d while requesting firmware %s \n", | ||
302 | rc, fname); | ||
303 | |||
304 | return rc; | ||
305 | } | ||
306 | p = fw->data; | 315 | p = fw->data; |
307 | endp = p + fw->size; | 316 | endp = p + fw->size; |
308 | 317 | ||
309 | if (fw->size < sizeof(name) - 1 + 2 + 2) { | 318 | if (fw->size < sizeof(name) - 1 + 2 + 2) { |
310 | tuner_err("Error: firmware file %s has invalid size!\n", | 319 | tuner_err("Error: firmware file %s has invalid size!\n", |
311 | fname); | 320 | priv->fname); |
312 | goto corrupt; | 321 | goto corrupt; |
313 | } | 322 | } |
314 | 323 | ||
@@ -323,7 +332,7 @@ static int load_all_firmwares(struct dvb_frontend *fe) | |||
323 | p += 2; | 332 | p += 2; |
324 | 333 | ||
325 | tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n", | 334 | tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n", |
326 | n_array, fname, name, | 335 | n_array, priv->fname, name, |
327 | priv->firm_version >> 8, priv->firm_version & 0xff); | 336 | priv->firm_version >> 8, priv->firm_version & 0xff); |
328 | 337 | ||
329 | priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL); | 338 | priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL); |
@@ -417,9 +426,10 @@ err: | |||
417 | free_firmware(priv); | 426 | free_firmware(priv); |
418 | 427 | ||
419 | done: | 428 | done: |
420 | release_firmware(fw); | ||
421 | if (rc == 0) | 429 | if (rc == 0) |
422 | tuner_dbg("Firmware files loaded.\n"); | 430 | tuner_dbg("Firmware files loaded.\n"); |
431 | else | ||
432 | priv->state = XC2028_NODEV; | ||
423 | 433 | ||
424 | return rc; | 434 | return rc; |
425 | } | 435 | } |
@@ -707,22 +717,15 @@ static int check_firmware(struct dvb_frontend *fe, unsigned int type, | |||
707 | { | 717 | { |
708 | struct xc2028_data *priv = fe->tuner_priv; | 718 | struct xc2028_data *priv = fe->tuner_priv; |
709 | struct firmware_properties new_fw; | 719 | struct firmware_properties new_fw; |
710 | int rc = 0, retry_count = 0; | 720 | int rc, retry_count = 0; |
711 | u16 version, hwmodel; | 721 | u16 version, hwmodel; |
712 | v4l2_std_id std0; | 722 | v4l2_std_id std0; |
713 | 723 | ||
714 | tuner_dbg("%s called\n", __func__); | 724 | tuner_dbg("%s called\n", __func__); |
715 | 725 | ||
716 | if (!priv->firm) { | 726 | rc = check_device_status(priv); |
717 | if (!priv->ctrl.fname) { | 727 | if (rc < 0) |
718 | tuner_info("xc2028/3028 firmware name not set!\n"); | 728 | return rc; |
719 | return -EINVAL; | ||
720 | } | ||
721 | |||
722 | rc = load_all_firmwares(fe); | ||
723 | if (rc < 0) | ||
724 | return rc; | ||
725 | } | ||
726 | 729 | ||
727 | if (priv->ctrl.mts && !(type & FM)) | 730 | if (priv->ctrl.mts && !(type & FM)) |
728 | type |= MTS; | 731 | type |= MTS; |
@@ -749,9 +752,13 @@ retry: | |||
749 | printk("scode_nr %d\n", new_fw.scode_nr); | 752 | printk("scode_nr %d\n", new_fw.scode_nr); |
750 | } | 753 | } |
751 | 754 | ||
752 | /* No need to reload base firmware if it matches */ | 755 | /* |
753 | if (((BASE | new_fw.type) & BASE_TYPES) == | 756 | * No need to reload base firmware if it matches and if the tuner |
754 | (priv->cur_fw.type & BASE_TYPES)) { | 757 | * is not at sleep mode |
758 | */ | ||
759 | if ((priv->state = XC2028_ACTIVE) && | ||
760 | (((BASE | new_fw.type) & BASE_TYPES) == | ||
761 | (priv->cur_fw.type & BASE_TYPES))) { | ||
755 | tuner_dbg("BASE firmware not changed.\n"); | 762 | tuner_dbg("BASE firmware not changed.\n"); |
756 | goto skip_base; | 763 | goto skip_base; |
757 | } | 764 | } |
@@ -872,10 +879,13 @@ read_not_reliable: | |||
872 | * 2. Tell whether BASE firmware was just changed the next time through. | 879 | * 2. Tell whether BASE firmware was just changed the next time through. |
873 | */ | 880 | */ |
874 | priv->cur_fw.type |= BASE; | 881 | priv->cur_fw.type |= BASE; |
882 | priv->state = XC2028_ACTIVE; | ||
875 | 883 | ||
876 | return 0; | 884 | return 0; |
877 | 885 | ||
878 | fail: | 886 | fail: |
887 | priv->state = XC2028_SLEEP; | ||
888 | |||
879 | memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); | 889 | memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); |
880 | if (retry_count < 8) { | 890 | if (retry_count < 8) { |
881 | msleep(50); | 891 | msleep(50); |
@@ -897,6 +907,10 @@ static int xc2028_signal(struct dvb_frontend *fe, u16 *strength) | |||
897 | 907 | ||
898 | tuner_dbg("%s called\n", __func__); | 908 | tuner_dbg("%s called\n", __func__); |
899 | 909 | ||
910 | rc = check_device_status(priv); | ||
911 | if (rc < 0) | ||
912 | return rc; | ||
913 | |||
900 | mutex_lock(&priv->lock); | 914 | mutex_lock(&priv->lock); |
901 | 915 | ||
902 | /* Sync Lock Indicator */ | 916 | /* Sync Lock Indicator */ |
@@ -1111,11 +1125,16 @@ static int xc2028_set_params(struct dvb_frontend *fe) | |||
1111 | u32 delsys = c->delivery_system; | 1125 | u32 delsys = c->delivery_system; |
1112 | u32 bw = c->bandwidth_hz; | 1126 | u32 bw = c->bandwidth_hz; |
1113 | struct xc2028_data *priv = fe->tuner_priv; | 1127 | struct xc2028_data *priv = fe->tuner_priv; |
1114 | unsigned int type=0; | 1128 | int rc; |
1129 | unsigned int type = 0; | ||
1115 | u16 demod = 0; | 1130 | u16 demod = 0; |
1116 | 1131 | ||
1117 | tuner_dbg("%s called\n", __func__); | 1132 | tuner_dbg("%s called\n", __func__); |
1118 | 1133 | ||
1134 | rc = check_device_status(priv); | ||
1135 | if (rc < 0) | ||
1136 | return rc; | ||
1137 | |||
1119 | switch (delsys) { | 1138 | switch (delsys) { |
1120 | case SYS_DVBT: | 1139 | case SYS_DVBT: |
1121 | case SYS_DVBT2: | 1140 | case SYS_DVBT2: |
@@ -1201,7 +1220,11 @@ static int xc2028_set_params(struct dvb_frontend *fe) | |||
1201 | static int xc2028_sleep(struct dvb_frontend *fe) | 1220 | static int xc2028_sleep(struct dvb_frontend *fe) |
1202 | { | 1221 | { |
1203 | struct xc2028_data *priv = fe->tuner_priv; | 1222 | struct xc2028_data *priv = fe->tuner_priv; |
1204 | int rc = 0; | 1223 | int rc; |
1224 | |||
1225 | rc = check_device_status(priv); | ||
1226 | if (rc < 0) | ||
1227 | return rc; | ||
1205 | 1228 | ||
1206 | /* Avoid firmware reload on slow devices or if PM disabled */ | 1229 | /* Avoid firmware reload on slow devices or if PM disabled */ |
1207 | if (no_poweroff || priv->ctrl.disable_power_mgmt) | 1230 | if (no_poweroff || priv->ctrl.disable_power_mgmt) |
@@ -1220,7 +1243,7 @@ static int xc2028_sleep(struct dvb_frontend *fe) | |||
1220 | else | 1243 | else |
1221 | rc = send_seq(priv, {0x80, XREG_POWER_DOWN, 0x00, 0x00}); | 1244 | rc = send_seq(priv, {0x80, XREG_POWER_DOWN, 0x00, 0x00}); |
1222 | 1245 | ||
1223 | priv->cur_fw.type = 0; /* need firmware reload */ | 1246 | priv->state = XC2028_SLEEP; |
1224 | 1247 | ||
1225 | mutex_unlock(&priv->lock); | 1248 | mutex_unlock(&priv->lock); |
1226 | 1249 | ||
@@ -1237,8 +1260,9 @@ static int xc2028_dvb_release(struct dvb_frontend *fe) | |||
1237 | 1260 | ||
1238 | /* only perform final cleanup if this is the last instance */ | 1261 | /* only perform final cleanup if this is the last instance */ |
1239 | if (hybrid_tuner_report_instance_count(priv) == 1) { | 1262 | if (hybrid_tuner_report_instance_count(priv) == 1) { |
1240 | kfree(priv->ctrl.fname); | ||
1241 | free_firmware(priv); | 1263 | free_firmware(priv); |
1264 | kfree(priv->ctrl.fname); | ||
1265 | priv->ctrl.fname = NULL; | ||
1242 | } | 1266 | } |
1243 | 1267 | ||
1244 | if (priv) | 1268 | if (priv) |
@@ -1254,14 +1278,42 @@ static int xc2028_dvb_release(struct dvb_frontend *fe) | |||
1254 | static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency) | 1278 | static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency) |
1255 | { | 1279 | { |
1256 | struct xc2028_data *priv = fe->tuner_priv; | 1280 | struct xc2028_data *priv = fe->tuner_priv; |
1281 | int rc; | ||
1257 | 1282 | ||
1258 | tuner_dbg("%s called\n", __func__); | 1283 | tuner_dbg("%s called\n", __func__); |
1259 | 1284 | ||
1285 | rc = check_device_status(priv); | ||
1286 | if (rc < 0) | ||
1287 | return rc; | ||
1288 | |||
1260 | *frequency = priv->frequency; | 1289 | *frequency = priv->frequency; |
1261 | 1290 | ||
1262 | return 0; | 1291 | return 0; |
1263 | } | 1292 | } |
1264 | 1293 | ||
1294 | static void load_firmware_cb(const struct firmware *fw, | ||
1295 | void *context) | ||
1296 | { | ||
1297 | struct dvb_frontend *fe = context; | ||
1298 | struct xc2028_data *priv = fe->tuner_priv; | ||
1299 | int rc; | ||
1300 | |||
1301 | tuner_dbg("request_firmware_nowait(): %s\n", fw ? "OK" : "error"); | ||
1302 | if (!fw) { | ||
1303 | tuner_err("Could not load firmware %s.\n", priv->fname); | ||
1304 | priv->state = XC2028_NODEV; | ||
1305 | return; | ||
1306 | } | ||
1307 | |||
1308 | rc = load_all_firmwares(fe, fw); | ||
1309 | |||
1310 | release_firmware(fw); | ||
1311 | |||
1312 | if (rc < 0) | ||
1313 | return; | ||
1314 | priv->state = XC2028_SLEEP; | ||
1315 | } | ||
1316 | |||
1265 | static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) | 1317 | static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) |
1266 | { | 1318 | { |
1267 | struct xc2028_data *priv = fe->tuner_priv; | 1319 | struct xc2028_data *priv = fe->tuner_priv; |
@@ -1272,21 +1324,49 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) | |||
1272 | 1324 | ||
1273 | mutex_lock(&priv->lock); | 1325 | mutex_lock(&priv->lock); |
1274 | 1326 | ||
1327 | /* | ||
1328 | * Copy the config data. | ||
1329 | * For the firmware name, keep a local copy of the string, | ||
1330 | * in order to avoid troubles during device release. | ||
1331 | */ | ||
1332 | if (priv->ctrl.fname) | ||
1333 | kfree(priv->ctrl.fname); | ||
1275 | memcpy(&priv->ctrl, p, sizeof(priv->ctrl)); | 1334 | memcpy(&priv->ctrl, p, sizeof(priv->ctrl)); |
1276 | if (priv->ctrl.max_len < 9) | ||
1277 | priv->ctrl.max_len = 13; | ||
1278 | |||
1279 | if (p->fname) { | 1335 | if (p->fname) { |
1280 | if (priv->ctrl.fname && strcmp(p->fname, priv->ctrl.fname)) { | ||
1281 | kfree(priv->ctrl.fname); | ||
1282 | free_firmware(priv); | ||
1283 | } | ||
1284 | |||
1285 | priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL); | 1336 | priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL); |
1286 | if (priv->ctrl.fname == NULL) | 1337 | if (priv->ctrl.fname == NULL) |
1287 | rc = -ENOMEM; | 1338 | rc = -ENOMEM; |
1288 | } | 1339 | } |
1289 | 1340 | ||
1341 | /* | ||
1342 | * If firmware name changed, frees firmware. As free_firmware will | ||
1343 | * reset the status to NO_FIRMWARE, this forces a new request_firmware | ||
1344 | */ | ||
1345 | if (!firmware_name[0] && p->fname && | ||
1346 | priv->fname && strcmp(p->fname, priv->fname)) | ||
1347 | free_firmware(priv); | ||
1348 | |||
1349 | if (priv->ctrl.max_len < 9) | ||
1350 | priv->ctrl.max_len = 13; | ||
1351 | |||
1352 | if (priv->state == XC2028_NO_FIRMWARE) { | ||
1353 | if (!firmware_name[0]) | ||
1354 | priv->fname = priv->ctrl.fname; | ||
1355 | else | ||
1356 | priv->fname = firmware_name; | ||
1357 | |||
1358 | rc = request_firmware_nowait(THIS_MODULE, 1, | ||
1359 | priv->fname, | ||
1360 | priv->i2c_props.adap->dev.parent, | ||
1361 | GFP_KERNEL, | ||
1362 | fe, load_firmware_cb); | ||
1363 | if (rc < 0) { | ||
1364 | tuner_err("Failed to request firmware %s\n", | ||
1365 | priv->fname); | ||
1366 | priv->state = XC2028_NODEV; | ||
1367 | } | ||
1368 | priv->state = XC2028_WAITING_FIRMWARE; | ||
1369 | } | ||
1290 | mutex_unlock(&priv->lock); | 1370 | mutex_unlock(&priv->lock); |
1291 | 1371 | ||
1292 | return rc; | 1372 | return rc; |