aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb/b2c2
diff options
context:
space:
mode:
authorTrent Piepho <xyzzy@speakeasy.org>2009-06-11 04:33:00 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-06-16 18:07:40 -0400
commiteccd15aad72f774b2059f708bc422dbb8493bb30 (patch)
tree43ee9f9dc6665c4c12eadbe2bfe5500a8ff711b5 /drivers/media/dvb/b2c2
parentf6a061bb0f143ff40070e6fd3d38fde5bd60027c (diff)
V4L/DVB (11964): b2c2: Fix problems with frontend attachment
The frontend attachment code didn't handle cases where the frontend partially failed to attach. For instance, when the demod was attached successfully but the tuner driver wasn't compiled or fails to init for some reason. In these cases we try to clean up the partial attachment and fail instead of proceeding with a broken frontend. If frontend registration fails, clean up with dvb_frontend_detach() rather than just calling the frontend's main release method. The former does some additional stuff, like release an attached tuner and take care of putting symbols when dynamic binding is used. In skystar2_rev23_attach() it's not necessary to set fc->dev_type, that gets set before skystar2_rev23_attach() is called. Signed-off-by: Trent Piepho <xyzzy@speakeasy.org> Signed-off-by: Patrick Boettcher <pboettcher@kernellabs.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/dvb/b2c2')
-rw-r--r--drivers/media/dvb/b2c2/flexcop-fe-tuner.c196
1 files changed, 113 insertions, 83 deletions
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index 3f485bf13121..efb4a6c2b57a 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -175,23 +175,23 @@ static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend *fe,
175 return 0; 175 return 0;
176} 176}
177 177
178static void skystar2_rev23_attach(struct flexcop_device *fc, 178static int skystar2_rev23_attach(struct flexcop_device *fc,
179 struct i2c_adapter *i2c) 179 struct i2c_adapter *i2c)
180{ 180{
181 fc->fe = dvb_attach(mt312_attach, 181 fc->fe = dvb_attach(mt312_attach, &skystar23_samsung_tbdu18132_config, i2c);
182 &skystar23_samsung_tbdu18132_config, i2c);
183 if (fc->fe != NULL) { 182 if (fc->fe != NULL) {
184 struct dvb_frontend_ops *ops = &fc->fe->ops; 183 struct dvb_frontend_ops *ops = &fc->fe->ops;
185 ops->tuner_ops.set_params \ 184 ops->tuner_ops.set_params =
186 = skystar23_samsung_tbdu18132_tuner_set_params; 185 skystar23_samsung_tbdu18132_tuner_set_params;
187 ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd; 186 ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
188 ops->diseqc_send_burst = flexcop_diseqc_send_burst; 187 ops->diseqc_send_burst = flexcop_diseqc_send_burst;
189 ops->set_tone = flexcop_set_tone; 188 ops->set_tone = flexcop_set_tone;
190 ops->set_voltage = flexcop_set_voltage; 189 ops->set_voltage = flexcop_set_voltage;
191 fc->fe_sleep = ops->sleep; 190 fc->fe_sleep = ops->sleep;
192 ops->sleep = flexcop_sleep; 191 ops->sleep = flexcop_sleep;
193 fc->dev_type = FC_SKY_REV23; 192 return 1;
194 } 193 }
194 return 0;
195} 195}
196#endif 196#endif
197 197
@@ -307,7 +307,7 @@ static struct stv0299_config samsung_tbmu24112_config = {
307 .set_symbol_rate = samsung_tbmu24112_set_symbol_rate, 307 .set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
308}; 308};
309 309
310static void skystar2_rev26_attach(struct flexcop_device *fc, 310static int skystar2_rev26_attach(struct flexcop_device *fc,
311 struct i2c_adapter *i2c) 311 struct i2c_adapter *i2c)
312{ 312{
313 fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c); 313 fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c);
@@ -317,7 +317,9 @@ static void skystar2_rev26_attach(struct flexcop_device *fc,
317 ops->set_voltage = flexcop_set_voltage; 317 ops->set_voltage = flexcop_set_voltage;
318 fc->fe_sleep = ops->sleep; 318 fc->fe_sleep = ops->sleep;
319 ops->sleep = flexcop_sleep; 319 ops->sleep = flexcop_sleep;
320 return 1;
320 } 321 }
322 return 0;
321} 323}
322#endif 324#endif
323 325
@@ -334,43 +336,54 @@ static struct itd1000_config skystar2_rev2_7_itd1000_config = {
334 .i2c_address = 0x61, 336 .i2c_address = 0x61,
335}; 337};
336 338
337static void skystar2_rev27_attach(struct flexcop_device *fc, 339static int skystar2_rev27_attach(struct flexcop_device *fc,
338 struct i2c_adapter *i2c) 340 struct i2c_adapter *i2c)
339{ 341{
342 flexcop_ibi_value r108;
343 struct i2c_adapter *i2c_tuner;
344
340 /* enable no_base_addr - no repeated start when reading */ 345 /* enable no_base_addr - no repeated start when reading */
341 fc->fc_i2c_adap[0].no_base_addr = 1; 346 fc->fc_i2c_adap[0].no_base_addr = 1;
342 fc->fe = dvb_attach(s5h1420_attach, 347 fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config,
343 &skystar2_rev2_7_s5h1420_config, i2c); 348 i2c);
344 if (fc->fe != NULL) { 349 if (!fc->fe)
345 flexcop_ibi_value r108; 350 goto fail;
346 struct i2c_adapter *i2c_tuner \
347 = s5h1420_get_tuner_i2c_adapter(fc->fe);
348 struct dvb_frontend_ops *ops = &fc->fe->ops;
349 351
350 fc->fe_sleep = ops->sleep; 352 i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe);
351 ops->sleep = flexcop_sleep; 353 if (!i2c_tuner)
352 354 goto fail;
353 /* enable no_base_addr - no repeated start when reading */ 355
354 fc->fc_i2c_adap[2].no_base_addr = 1; 356 fc->fe_sleep = fc->fe->ops.sleep;
355 if (dvb_attach(isl6421_attach, fc->fe, 357 fc->fe->ops.sleep = flexcop_sleep;
356 &fc->fc_i2c_adap[2].i2c_adap, 0x08, 1, 1) == NULL) 358
357 err("ISL6421 could NOT be attached"); 359 /* enable no_base_addr - no repeated start when reading */
358 else 360 fc->fc_i2c_adap[2].no_base_addr = 1;
359 info("ISL6421 successfully attached"); 361 if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
360 362 0x08, 1, 1)) {
361 /* the ITD1000 requires a lower i2c clock - is it a problem ? */ 363 err("ISL6421 could NOT be attached");
362 r108.raw = 0x00000506; 364 goto fail_isl;
363 fc->write_ibi_reg(fc, tw_sm_c_108, r108); 365 }
364 if (i2c_tuner) { 366 info("ISL6421 successfully attached");
365 if (dvb_attach(itd1000_attach, fc->fe, i2c_tuner, 367
366 &skystar2_rev2_7_itd1000_config) == NULL) 368 /* the ITD1000 requires a lower i2c clock - is it a problem ? */
367 err("ITD1000 could NOT be attached"); 369 r108.raw = 0x00000506;
368 else 370 fc->write_ibi_reg(fc, tw_sm_c_108, r108);
369 info("ITD1000 successfully attached"); 371 if (!dvb_attach(itd1000_attach, fc->fe, i2c_tuner,
370 } 372 &skystar2_rev2_7_itd1000_config)) {
371 } else 373 err("ITD1000 could NOT be attached");
372 fc->fc_i2c_adap[0].no_base_addr = 0; 374 /* Should i2c clock be restored? */
373 /* for the next devices we need it again */ 375 goto fail_isl;
376 }
377 info("ITD1000 successfully attached");
378
379 return 1;
380
381fail_isl:
382 fc->fc_i2c_adap[2].no_base_addr = 0;
383fail:
384 /* for the next devices we need it again */
385 fc->fc_i2c_adap[0].no_base_addr = 0;
386 return 0;
374} 387}
375#endif 388#endif
376 389
@@ -387,32 +400,38 @@ static const struct cx24113_config skystar2_rev2_8_cx24113_config = {
387 .xtal_khz = 10111, 400 .xtal_khz = 10111,
388}; 401};
389 402
390static void skystar2_rev28_attach(struct flexcop_device *fc, 403static int skystar2_rev28_attach(struct flexcop_device *fc,
391 struct i2c_adapter *i2c) 404 struct i2c_adapter *i2c)
392{ 405{
393 fc->fe = dvb_attach(cx24123_attach, 406 struct i2c_adapter *i2c_tuner;
394 &skystar2_rev2_8_cx24123_config, i2c); 407
395 if (fc->fe != NULL) { 408 fc->fe = dvb_attach(cx24123_attach, &skystar2_rev2_8_cx24123_config,
396 struct i2c_adapter *i2c_tuner \ 409 i2c);
397 = cx24123_get_tuner_i2c_adapter(fc->fe); 410 if (!fc->fe)
398 if (i2c_tuner != NULL) { 411 return 0;
399 if (dvb_attach(cx24113_attach, fc->fe, 412
400 &skystar2_rev2_8_cx24113_config, 413 i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);;
401 i2c_tuner) == NULL) 414 if (!i2c_tuner)
402 err("CX24113 could NOT be attached"); 415 return 0;
403 else
404 info("CX24113 successfully attached");
405 }
406 416
407 fc->fc_i2c_adap[2].no_base_addr = 1; 417 if (!dvb_attach(cx24113_attach, fc->fe, &skystar2_rev2_8_cx24113_config,
408 if (dvb_attach(isl6421_attach, fc->fe, 418 i2c_tuner)) {
409 &fc->fc_i2c_adap[2].i2c_adap, 0x08, 0, 0) == NULL) 419 err("CX24113 could NOT be attached");
410 err("ISL6421 could NOT be attached"); 420 return 0;
411 else 421 }
412 info("ISL6421 successfully attached"); 422 info("CX24113 successfully attached");
423
424 fc->fc_i2c_adap[2].no_base_addr = 1;
425 if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
426 0x08, 0, 0)) {
427 err("ISL6421 could NOT be attached");
428 fc->fc_i2c_adap[2].no_base_addr = 0;
429 return 0;
430 }
431 info("ISL6421 successfully attached");
413 /* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an 432 /* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an
414 * IR-receiver (PIC16F818) - but the card has no input for that ??? */ 433 * IR-receiver (PIC16F818) - but the card has no input for that ??? */
415 } 434 return 1;
416} 435}
417#endif 436#endif
418 437
@@ -466,12 +485,15 @@ static struct mt352_config samsung_tdtc9251dh0_config = {
466 .demod_init = samsung_tdtc9251dh0_demod_init, 485 .demod_init = samsung_tdtc9251dh0_demod_init,
467}; 486};
468 487
469static void airstar_dvbt_attach(struct flexcop_device *fc, 488static int airstar_dvbt_attach(struct flexcop_device *fc,
470 struct i2c_adapter *i2c) 489 struct i2c_adapter *i2c)
471{ 490{
472 fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c); 491 fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c);
473 if (fc->fe != NULL) 492 if (fc->fe != NULL) {
474 fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs; 493 fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
494 return 1;
495 }
496 return 0;
475} 497}
476#endif 498#endif
477 499
@@ -489,10 +511,11 @@ static struct bcm3510_config air2pc_atsc_first_gen_config = {
489 .request_firmware = flexcop_fe_request_firmware, 511 .request_firmware = flexcop_fe_request_firmware,
490}; 512};
491 513
492static void airstar_atsc1_attach(struct flexcop_device *fc, 514static int airstar_atsc1_attach(struct flexcop_device *fc,
493 struct i2c_adapter *i2c) 515 struct i2c_adapter *i2c)
494{ 516{
495 fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c); 517 fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c);
518 return fc->fe != NULL;
496} 519}
497#endif 520#endif
498 521
@@ -502,13 +525,15 @@ static struct nxt200x_config samsung_tbmv_config = {
502 .demod_address = 0x0a, 525 .demod_address = 0x0a,
503}; 526};
504 527
505static void airstar_atsc2_attach(struct flexcop_device *fc, 528static int airstar_atsc2_attach(struct flexcop_device *fc,
506 struct i2c_adapter *i2c) 529 struct i2c_adapter *i2c)
507{ 530{
508 fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c); 531 fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c);
509 if (fc->fe != NULL) 532 if (!fc->fe)
510 dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, 533 return 0;
511 DVB_PLL_SAMSUNG_TBMV); 534
535 return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
536 DVB_PLL_SAMSUNG_TBMV);
512} 537}
513#endif 538#endif
514 539
@@ -521,14 +546,15 @@ static struct lgdt330x_config air2pc_atsc_hd5000_config = {
521 .clock_polarity_flip = 1, 546 .clock_polarity_flip = 1,
522}; 547};
523 548
524static void airstar_atsc3_attach(struct flexcop_device *fc, 549static int airstar_atsc3_attach(struct flexcop_device *fc,
525 struct i2c_adapter *i2c) 550 struct i2c_adapter *i2c)
526{ 551{
527 fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c); 552 fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c);
528 if (fc->fe != NULL) { 553 if (!fc->fe)
529 dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61, 554 return 0;
530 TUNER_LG_TDVS_H06XF); 555
531 } 556 return !!dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61,
557 TUNER_LG_TDVS_H06XF);
532} 558}
533#endif 559#endif
534 560
@@ -659,22 +685,24 @@ static struct stv0297_config alps_tdee4_stv0297_config = {
659 .inittab = alps_tdee4_stv0297_inittab, 685 .inittab = alps_tdee4_stv0297_inittab,
660}; 686};
661 687
662static void cablestar2_attach(struct flexcop_device *fc, 688static int cablestar2_attach(struct flexcop_device *fc,
663 struct i2c_adapter *i2c) 689 struct i2c_adapter *i2c)
664{ 690{
665 fc->fc_i2c_adap[0].no_base_addr = 1; 691 fc->fc_i2c_adap[0].no_base_addr = 1;
666 fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c); 692 fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c);
667 if (fc->fe != NULL) 693 if (!fc->fe) {
668 fc->fe->ops.tuner_ops.set_params \ 694 /* Reset for next frontend to try */
669 = alps_tdee4_stv0297_tuner_set_params;
670 else
671 fc->fc_i2c_adap[0].no_base_addr = 0; 695 fc->fc_i2c_adap[0].no_base_addr = 0;
696 return 0;
697 }
698 fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
699 return 1;
672} 700}
673#endif 701#endif
674 702
675static struct { 703static struct {
676 flexcop_device_type_t type; 704 flexcop_device_type_t type;
677 void (*attach)(struct flexcop_device *, struct i2c_adapter *); 705 int (*attach)(struct flexcop_device *, struct i2c_adapter *);
678} flexcop_frontends[] = { 706} flexcop_frontends[] = {
679#if defined(CONFIG_DVB_S5H1420_MODULE) 707#if defined(CONFIG_DVB_S5H1420_MODULE)
680 { FC_SKY_REV27, skystar2_rev27_attach }, 708 { FC_SKY_REV27, skystar2_rev27_attach },
@@ -713,9 +741,13 @@ int flexcop_frontend_init(struct flexcop_device *fc)
713 /* type needs to be set before, because of some workarounds 741 /* type needs to be set before, because of some workarounds
714 * done based on the probed card type */ 742 * done based on the probed card type */
715 fc->dev_type = flexcop_frontends[i].type; 743 fc->dev_type = flexcop_frontends[i].type;
716 flexcop_frontends[i].attach(fc, &fc->fc_i2c_adap[0].i2c_adap); 744 if (flexcop_frontends[i].attach(fc, &fc->fc_i2c_adap[0].i2c_adap))
717 if (fc->fe != NULL)
718 goto fe_found; 745 goto fe_found;
746 /* Clean up partially attached frontend */
747 if (fc->fe) {
748 dvb_frontend_detach(fc->fe);
749 fc->fe = NULL;
750 }
719 } 751 }
720 fc->dev_type = FC_UNK; 752 fc->dev_type = FC_UNK;
721 err("no frontend driver found for this B2C2/FlexCop adapter"); 753 err("no frontend driver found for this B2C2/FlexCop adapter");
@@ -724,10 +756,8 @@ int flexcop_frontend_init(struct flexcop_device *fc)
724fe_found: 756fe_found:
725 info("found '%s' .", fc->fe->ops.info.name); 757 info("found '%s' .", fc->fe->ops.info.name);
726 if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) { 758 if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
727 struct dvb_frontend_ops *ops = &fc->fe->ops;
728 err("frontend registration failed!"); 759 err("frontend registration failed!");
729 if (ops->release != NULL) 760 dvb_frontend_detach(fc->fe);
730 ops->release(fc->fe);
731 fc->fe = NULL; 761 fc->fe = NULL;
732 return -EINVAL; 762 return -EINVAL;
733 } 763 }