aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/tuner-core.c
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil@xs4all.nl>2006-01-15 12:04:52 -0500
committerMauro Carvalho Chehab <mchehab@brturbo.com.br>2006-01-15 18:25:32 -0500
commit27487d44712aaa37710cc508d5bd6119f5e9f976 (patch)
tree474acfb51469cc730cd76ebdf6f34680b3809442 /drivers/media/video/tuner-core.c
parent8f0bb9c069fc487dadebe4cdd1e03f0df5ebf0e6 (diff)
V4L/DVB (3384): Separate tv & radio freqs, fix cb/freq transmit order for tuners that need this.
- Moved MSP_SET_MATRIX to v4l2-common.h - Fix typos and integer overflows in tea5767.c - Split old freq field into a tv_freq and a radio_freq. Prevents that a radio tuner is initialized with a tv frequency or vice versa. - When switching to radio mode initialize the tuner with the last used radio frequency (this was already done for the TV mode). As a result of these changes the tuner module now remembers the last set radio and TV frequencies, which is what you would expect to happen. - Move out of range frequencies to the closest valid frequency as per v4l2 API spec. - Fix incorrect initial radio frequency (multiplier is 16000, not 16) - Add boundary check for out of range frequencies. - Use new flag to check if the order of the CB and freq. depends on the last set frequency. That is needed for some tuners or you can get static as a result. The flag is added for those tuners where I know that the datasheet indicates that this is necessary. - For this new check use the last set div value, not the last frequency as radio frequencies are always much higher due to the 16000 multiplier. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/tuner-core.c')
-rw-r--r--drivers/media/video/tuner-core.c85
1 files changed, 52 insertions, 33 deletions
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index f30ef79d795..2995b22acb4 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -82,7 +82,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
82 tuner_warn ("tuner type not set\n"); 82 tuner_warn ("tuner type not set\n");
83 return; 83 return;
84 } 84 }
85 if (NULL == t->tv_freq) { 85 if (NULL == t->set_tv_freq) {
86 tuner_warn ("Tuner has no way to set tv freq\n"); 86 tuner_warn ("Tuner has no way to set tv freq\n");
87 return; 87 return;
88 } 88 }
@@ -90,8 +90,14 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
90 tuner_dbg ("TV freq (%d.%02d) out of range (%d-%d)\n", 90 tuner_dbg ("TV freq (%d.%02d) out of range (%d-%d)\n",
91 freq / 16, freq % 16 * 100 / 16, tv_range[0], 91 freq / 16, freq % 16 * 100 / 16, tv_range[0],
92 tv_range[1]); 92 tv_range[1]);
93 /* V4L2 spec: if the freq is not possible then the closest
94 possible value should be selected */
95 if (freq < tv_range[0] * 16)
96 freq = tv_range[0] * 16;
97 else
98 freq = tv_range[1] * 16;
93 } 99 }
94 t->tv_freq(c, freq); 100 t->set_tv_freq(c, freq);
95} 101}
96 102
97static void set_radio_freq(struct i2c_client *c, unsigned int freq) 103static void set_radio_freq(struct i2c_client *c, unsigned int freq)
@@ -102,18 +108,23 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq)
102 tuner_warn ("tuner type not set\n"); 108 tuner_warn ("tuner type not set\n");
103 return; 109 return;
104 } 110 }
105 if (NULL == t->radio_freq) { 111 if (NULL == t->set_radio_freq) {
106 tuner_warn ("tuner has no way to set radio frequency\n"); 112 tuner_warn ("tuner has no way to set radio frequency\n");
107 return; 113 return;
108 } 114 }
109 if (freq <= radio_range[0] * 16000 || freq >= radio_range[1] * 16000) { 115 if (freq < radio_range[0] * 16000 || freq > radio_range[1] * 16000) {
110 tuner_dbg ("radio freq (%d.%02d) out of range (%d-%d)\n", 116 tuner_dbg ("radio freq (%d.%02d) out of range (%d-%d)\n",
111 freq / 16000, freq % 16000 * 100 / 16000, 117 freq / 16000, freq % 16000 * 100 / 16000,
112 radio_range[0], radio_range[1]); 118 radio_range[0], radio_range[1]);
119 /* V4L2 spec: if the freq is not possible then the closest
120 possible value should be selected */
121 if (freq < radio_range[0] * 16000)
122 freq = radio_range[0] * 16000;
123 else
124 freq = radio_range[1] * 16000;
113 } 125 }
114 126
115 t->radio_freq(c, freq); 127 t->set_radio_freq(c, freq);
116 return;
117} 128}
118 129
119static void set_freq(struct i2c_client *c, unsigned long freq) 130static void set_freq(struct i2c_client *c, unsigned long freq)
@@ -125,15 +136,16 @@ static void set_freq(struct i2c_client *c, unsigned long freq)
125 tuner_dbg("radio freq set to %lu.%02lu\n", 136 tuner_dbg("radio freq set to %lu.%02lu\n",
126 freq / 16000, freq % 16000 * 100 / 16000); 137 freq / 16000, freq % 16000 * 100 / 16000);
127 set_radio_freq(c, freq); 138 set_radio_freq(c, freq);
139 t->radio_freq = freq;
128 break; 140 break;
129 case V4L2_TUNER_ANALOG_TV: 141 case V4L2_TUNER_ANALOG_TV:
130 case V4L2_TUNER_DIGITAL_TV: 142 case V4L2_TUNER_DIGITAL_TV:
131 tuner_dbg("tv freq set to %lu.%02lu\n", 143 tuner_dbg("tv freq set to %lu.%02lu\n",
132 freq / 16, freq % 16 * 100 / 16); 144 freq / 16, freq % 16 * 100 / 16);
133 set_tv_freq(c, freq); 145 set_tv_freq(c, freq);
146 t->tv_freq = freq;
134 break; 147 break;
135 } 148 }
136 t->freq = freq;
137} 149}
138 150
139static void set_type(struct i2c_client *c, unsigned int type, 151static void set_type(struct i2c_client *c, unsigned int type,
@@ -212,7 +224,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
212 if (t->mode_mask == T_UNINITIALIZED) 224 if (t->mode_mask == T_UNINITIALIZED)
213 t->mode_mask = new_mode_mask; 225 t->mode_mask = new_mode_mask;
214 226
215 set_freq(c, t->freq); 227 set_freq(c, (V4L2_TUNER_RADIO == t->mode) ? t->radio_freq : t->tv_freq);
216 tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n", 228 tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
217 c->adapter->name, c->driver->driver.name, c->addr << 1, type, 229 c->adapter->name, c->driver->driver.name, c->addr << 1, type,
218 t->mode_mask); 230 t->mode_mask);
@@ -377,11 +389,11 @@ static void tuner_status(struct i2c_client *client)
377 default: p = "undefined"; break; 389 default: p = "undefined"; break;
378 } 390 }
379 if (t->mode == V4L2_TUNER_RADIO) { 391 if (t->mode == V4L2_TUNER_RADIO) {
380 freq = t->freq / 16000; 392 freq = t->radio_freq / 16000;
381 freq_fraction = (t->freq % 16000) * 100 / 16000; 393 freq_fraction = (t->radio_freq % 16000) * 100 / 16000;
382 } else { 394 } else {
383 freq = t->freq / 16; 395 freq = t->tv_freq / 16;
384 freq_fraction = (t->freq % 16) * 100 / 16; 396 freq_fraction = (t->tv_freq % 16) * 100 / 16;
385 } 397 }
386 tuner_info("Tuner mode: %s\n", p); 398 tuner_info("Tuner mode: %s\n", p);
387 tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction); 399 tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction);
@@ -456,7 +468,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
456 t->type = TUNER_TEA5767; 468 t->type = TUNER_TEA5767;
457 t->mode_mask = T_RADIO; 469 t->mode_mask = T_RADIO;
458 t->mode = T_STANDBY; 470 t->mode = T_STANDBY;
459 t->freq = 87.5 * 16; /* Sets freq to FM range */ 471 t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
460 default_mode_mask &= ~T_RADIO; 472 default_mode_mask &= ~T_RADIO;
461 473
462 goto register_client; 474 goto register_client;
@@ -469,7 +481,8 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
469 if (default_mode_mask != T_UNINITIALIZED) { 481 if (default_mode_mask != T_UNINITIALIZED) {
470 tuner_dbg ("Setting mode_mask to 0x%02x\n", default_mode_mask); 482 tuner_dbg ("Setting mode_mask to 0x%02x\n", default_mode_mask);
471 t->mode_mask = default_mode_mask; 483 t->mode_mask = default_mode_mask;
472 t->freq = 400 * 16; /* Sets freq to VHF High */ 484 t->tv_freq = 400 * 16; /* Sets freq to VHF High */
485 t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
473 default_mode_mask = T_UNINITIALIZED; 486 default_mode_mask = T_UNINITIALIZED;
474 } 487 }
475 488
@@ -565,16 +578,18 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
565 set_addr(client, (struct tuner_setup *)arg); 578 set_addr(client, (struct tuner_setup *)arg);
566 break; 579 break;
567 case AUDC_SET_RADIO: 580 case AUDC_SET_RADIO:
568 set_mode(client,t,V4L2_TUNER_RADIO, "AUDC_SET_RADIO"); 581 if (set_mode(client, t, V4L2_TUNER_RADIO, "AUDC_SET_RADIO")
582 == EINVAL)
583 return 0;
584 if (t->radio_freq)
585 set_freq(client, t->radio_freq);
569 break; 586 break;
570 case TUNER_SET_STANDBY: 587 case TUNER_SET_STANDBY:
571 { 588 if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
572 if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL) 589 return 0;
573 return 0; 590 if (t->standby)
574 if (t->standby) 591 t->standby (client);
575 t->standby (client); 592 break;
576 break;
577 }
578 case VIDIOCSAUDIO: 593 case VIDIOCSAUDIO:
579 if (check_mode(t, "VIDIOCSAUDIO") == EINVAL) 594 if (check_mode(t, "VIDIOCSAUDIO") == EINVAL)
580 return 0; 595 return 0;
@@ -583,7 +598,6 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
583 598
584 /* Should be implemented, since bttv calls it */ 599 /* Should be implemented, since bttv calls it */
585 tuner_dbg("VIDIOCSAUDIO not implemented.\n"); 600 tuner_dbg("VIDIOCSAUDIO not implemented.\n");
586
587 break; 601 break;
588 /* --- v4l ioctls --- */ 602 /* --- v4l ioctls --- */
589 /* take care: bttv does userspace copying, we'll get a 603 /* take care: bttv does userspace copying, we'll get a
@@ -609,8 +623,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
609 if (vc->norm < ARRAY_SIZE(map)) 623 if (vc->norm < ARRAY_SIZE(map))
610 t->std = map[vc->norm]; 624 t->std = map[vc->norm];
611 tuner_fixup_std(t); 625 tuner_fixup_std(t);
612 if (t->freq) 626 if (t->tv_freq)
613 set_tv_freq(client, t->freq); 627 set_tv_freq(client, t->tv_freq);
614 return 0; 628 return 0;
615 } 629 }
616 case VIDIOCSFREQ: 630 case VIDIOCSFREQ:
@@ -684,15 +698,14 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
684 698
685 t->std = *id; 699 t->std = *id;
686 tuner_fixup_std(t); 700 tuner_fixup_std(t);
687 if (t->freq) 701 if (t->tv_freq)
688 set_freq(client, t->freq); 702 set_freq(client, t->tv_freq);
689 break; 703 break;
690 } 704 }
691 case VIDIOC_S_FREQUENCY: 705 case VIDIOC_S_FREQUENCY:
692 { 706 {
693 struct v4l2_frequency *f = arg; 707 struct v4l2_frequency *f = arg;
694 708
695 t->freq = f->frequency;
696 switch_v4l2(); 709 switch_v4l2();
697 if (V4L2_TUNER_RADIO == f->type && 710 if (V4L2_TUNER_RADIO == f->type &&
698 V4L2_TUNER_RADIO != t->mode) { 711 V4L2_TUNER_RADIO != t->mode) {
@@ -700,7 +713,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
700 == EINVAL) 713 == EINVAL)
701 return 0; 714 return 0;
702 } 715 }
703 set_freq(client,t->freq); 716 set_freq(client,f->frequency);
704 717
705 break; 718 break;
706 } 719 }
@@ -712,7 +725,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
712 return 0; 725 return 0;
713 switch_v4l2(); 726 switch_v4l2();
714 f->type = t->mode; 727 f->type = t->mode;
715 f->frequency = t->freq; 728 f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
729 t->radio_freq : t->tv_freq;
716 break; 730 break;
717 } 731 }
718 case VIDIOC_G_TUNER: 732 case VIDIOC_G_TUNER:
@@ -763,7 +777,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
763 777
764 if (V4L2_TUNER_RADIO == t->mode) { 778 if (V4L2_TUNER_RADIO == t->mode) {
765 t->audmode = tuner->audmode; 779 t->audmode = tuner->audmode;
766 set_radio_freq(client, t->freq); 780 set_radio_freq(client, t->radio_freq);
767 } 781 }
768 break; 782 break;
769 } 783 }
@@ -791,8 +805,13 @@ static int tuner_resume(struct device *dev)
791 struct tuner *t = i2c_get_clientdata (c); 805 struct tuner *t = i2c_get_clientdata (c);
792 806
793 tuner_dbg ("resume\n"); 807 tuner_dbg ("resume\n");
794 if (t->freq) 808 if (V4L2_TUNER_RADIO == t->mode) {
795 set_freq(c, t->freq); 809 if (t->radio_freq)
810 set_freq(c, t->radio_freq);
811 } else {
812 if (t->tv_freq)
813 set_freq(c, t->tv_freq);
814 }
796 return 0; 815 return 0;
797} 816}
798 817