aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
authorMike Isely <isely@pobox.com>2006-12-27 21:30:13 -0500
committerMauro Carvalho Chehab <mchehab@infradead.org>2007-02-21 10:34:33 -0500
commit1bde02891b3d4d17ee743584bb49ed5f275dff01 (patch)
tree11e758f74dbddf7b19f6a4da0bb8047cf665a258 /drivers/media
parent5549f54f46c2375761f42cd2741364316e3b2a13 (diff)
V4L/DVB (5051): Pvrusb2: Better radio versus tv frequency handling
Separate track radio versus tv frequency so that when we switch modes we can also switch to a sane frequency appropriate for the mode. Also implement logic to automate mode switching in certain cases. Signed-off-by: Mike Isely <isely@pobox.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h11
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c213
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c2
3 files changed, 196 insertions, 30 deletions
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index da29ae2fb05d..b9df52c882a8 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -214,7 +214,6 @@ struct pvr2_hdw {
214 /* Frequency table */ 214 /* Frequency table */
215 unsigned int freqTable[FREQTABLE_SIZE]; 215 unsigned int freqTable[FREQTABLE_SIZE];
216 unsigned int freqProgSlot; 216 unsigned int freqProgSlot;
217 unsigned int freqSlot;
218 217
219 /* Stuff for handling low level control interaction with device */ 218 /* Stuff for handling low level control interaction with device */
220 struct mutex ctl_lock_mutex; 219 struct mutex ctl_lock_mutex;
@@ -260,7 +259,11 @@ struct pvr2_hdw {
260 /* Tuner / frequency control stuff */ 259 /* Tuner / frequency control stuff */
261 unsigned int tuner_type; 260 unsigned int tuner_type;
262 int tuner_updated; 261 int tuner_updated;
263 unsigned int freqVal; 262 unsigned int freqValTelevision; /* Current freq for tv mode */
263 unsigned int freqValRadio; /* Current freq for radio mode */
264 unsigned int freqSlotTelevision; /* Current slot for tv mode */
265 unsigned int freqSlotRadio; /* Current slot for radio mode */
266 unsigned int freqSelector; /* 0=radio 1=television */
264 int freqDirty; 267 int freqDirty;
265 268
266 /* Video standard handling */ 269 /* Video standard handling */
@@ -323,6 +326,7 @@ struct pvr2_hdw {
323 VCREATE_DATA(res_hor); 326 VCREATE_DATA(res_hor);
324 VCREATE_DATA(res_ver); 327 VCREATE_DATA(res_ver);
325 VCREATE_DATA(srate); 328 VCREATE_DATA(srate);
329 VCREATE_DATA(automodeswitch);
326#undef VCREATE_DATA 330#undef VCREATE_DATA
327 331
328 struct pvr2_ctld_info *mpeg_ctrl_info; 332 struct pvr2_ctld_info *mpeg_ctrl_info;
@@ -331,6 +335,9 @@ struct pvr2_hdw {
331 unsigned int control_cnt; 335 unsigned int control_cnt;
332}; 336};
333 337
338/* This function gets the current frequency */
339unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *);
340
334#endif /* __PVRUSB2_HDW_INTERNAL_H */ 341#endif /* __PVRUSB2_HDW_INTERNAL_H */
335 342
336/* 343/*
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 04e746932217..38e165913dd6 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -37,10 +37,9 @@
37#include "pvrusb2-encoder.h" 37#include "pvrusb2-encoder.h"
38#include "pvrusb2-debug.h" 38#include "pvrusb2-debug.h"
39 39
40#define TV_MIN_FREQ 55250000L 40#define TV_MIN_FREQ 55250000L
41#define TV_MAX_FREQ 850000000L 41#define TV_MAX_FREQ 850000000L
42 42#define RADIO_MIN_FREQ 87000000L
43#define RADIO_MIN_FREQ 87000000L
44#define RADIO_MAX_FREQ 108000000L 43#define RADIO_MAX_FREQ 108000000L
45 44
46struct usb_device_id pvr2_device_table[] = { 45struct usb_device_id pvr2_device_table[] = {
@@ -95,6 +94,7 @@ static int procreload = 0;
95static int tuner[PVR_NUM] = { [0 ... PVR_NUM-1] = -1 }; 94static int tuner[PVR_NUM] = { [0 ... PVR_NUM-1] = -1 };
96static int tolerance[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 }; 95static int tolerance[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 };
97static int video_std[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 }; 96static int video_std[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 };
97static int auto_mode_switch[PVR_NUM];
98static int init_pause_msec = 0; 98static int init_pause_msec = 0;
99 99
100module_param(ctlchg, int, S_IRUGO|S_IWUSR); 100module_param(ctlchg, int, S_IRUGO|S_IWUSR);
@@ -112,6 +112,8 @@ module_param_array(video_std, int, NULL, 0444);
112MODULE_PARM_DESC(video_std,"specify initial video standard"); 112MODULE_PARM_DESC(video_std,"specify initial video standard");
113module_param_array(tolerance, int, NULL, 0444); 113module_param_array(tolerance, int, NULL, 0444);
114MODULE_PARM_DESC(tolerance,"specify stream error tolerance"); 114MODULE_PARM_DESC(tolerance,"specify stream error tolerance");
115module_param_array(auto_mode_switch, int, NULL, 0444);
116MODULE_PARM_DESC(auto_mode_switch,"Enable TV/Radio automatic mode switch based on freq");
115 117
116#define PVR2_CTL_WRITE_ENDPOINT 0x01 118#define PVR2_CTL_WRITE_ENDPOINT 0x01
117#define PVR2_CTL_READ_ENDPOINT 0x81 119#define PVR2_CTL_READ_ENDPOINT 0x81
@@ -258,6 +260,7 @@ static const char *control_values_subsystem[] = {
258 [PVR2_SUBSYS_B_ENC_RUN] = "enc_run", 260 [PVR2_SUBSYS_B_ENC_RUN] = "enc_run",
259}; 261};
260 262
263static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long);
261static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl); 264static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl);
262static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw); 265static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw);
263static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw); 266static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw);
@@ -292,8 +295,21 @@ static int ctrl_channelfreq_get(struct pvr2_ctrl *cptr,int *vp)
292static int ctrl_channelfreq_set(struct pvr2_ctrl *cptr,int m,int v) 295static int ctrl_channelfreq_set(struct pvr2_ctrl *cptr,int m,int v)
293{ 296{
294 struct pvr2_hdw *hdw = cptr->hdw; 297 struct pvr2_hdw *hdw = cptr->hdw;
295 if ((hdw->freqProgSlot > 0) && (hdw->freqProgSlot <= FREQTABLE_SIZE)) { 298 unsigned int slotId = hdw->freqProgSlot;
296 hdw->freqTable[hdw->freqProgSlot-1] = v; 299 if ((slotId > 0) && (slotId <= FREQTABLE_SIZE)) {
300 hdw->freqTable[slotId-1] = v;
301 /* Handle side effects correctly - if we're tuned to this
302 slot, then forgot the slot id relation since the stored
303 frequency has been changed. */
304 if (hdw->freqSelector) {
305 if (hdw->freqSlotRadio == slotId) {
306 hdw->freqSlotRadio = 0;
307 }
308 } else {
309 if (hdw->freqSlotTelevision == slotId) {
310 hdw->freqSlotTelevision = 0;
311 }
312 }
297 } 313 }
298 return 0; 314 return 0;
299} 315}
@@ -315,28 +331,32 @@ static int ctrl_channelprog_set(struct pvr2_ctrl *cptr,int m,int v)
315 331
316static int ctrl_channel_get(struct pvr2_ctrl *cptr,int *vp) 332static int ctrl_channel_get(struct pvr2_ctrl *cptr,int *vp)
317{ 333{
318 *vp = cptr->hdw->freqSlot; 334 struct pvr2_hdw *hdw = cptr->hdw;
335 *vp = hdw->freqSelector ? hdw->freqSlotRadio : hdw->freqSlotTelevision;
319 return 0; 336 return 0;
320} 337}
321 338
322static int ctrl_channel_set(struct pvr2_ctrl *cptr,int m,int v) 339static int ctrl_channel_set(struct pvr2_ctrl *cptr,int m,int slotId)
323{ 340{
324 unsigned freq = 0; 341 unsigned freq = 0;
325 struct pvr2_hdw *hdw = cptr->hdw; 342 struct pvr2_hdw *hdw = cptr->hdw;
326 hdw->freqSlot = v; 343 if ((slotId < 0) || (slotId > FREQTABLE_SIZE)) return 0;
327 if ((hdw->freqSlot > 0) && (hdw->freqSlot <= FREQTABLE_SIZE)) { 344 if (slotId > 0) {
328 freq = hdw->freqTable[hdw->freqSlot-1]; 345 freq = hdw->freqTable[slotId-1];
329 } 346 if (!freq) return 0;
330 if (freq && (freq != hdw->freqVal)) { 347 pvr2_hdw_set_cur_freq(hdw,freq);
331 hdw->freqVal = freq; 348 }
332 hdw->freqDirty = !0; 349 if (hdw->freqSelector) {
350 hdw->freqSlotRadio = slotId;
351 } else {
352 hdw->freqSlotTelevision = slotId;
333 } 353 }
334 return 0; 354 return 0;
335} 355}
336 356
337static int ctrl_freq_get(struct pvr2_ctrl *cptr,int *vp) 357static int ctrl_freq_get(struct pvr2_ctrl *cptr,int *vp)
338{ 358{
339 *vp = cptr->hdw->freqVal; 359 *vp = pvr2_hdw_get_cur_freq(cptr->hdw);
340 return 0; 360 return 0;
341} 361}
342 362
@@ -352,10 +372,7 @@ static void ctrl_freq_clear_dirty(struct pvr2_ctrl *cptr)
352 372
353static int ctrl_freq_set(struct pvr2_ctrl *cptr,int m,int v) 373static int ctrl_freq_set(struct pvr2_ctrl *cptr,int m,int v)
354{ 374{
355 struct pvr2_hdw *hdw = cptr->hdw; 375 pvr2_hdw_set_cur_freq(cptr->hdw,v);
356 hdw->freqVal = v;
357 hdw->freqDirty = !0;
358 hdw->freqSlot = 0;
359 return 0; 376 return 0;
360} 377}
361 378
@@ -381,13 +398,51 @@ static int ctrl_vres_min_get(struct pvr2_ctrl *cptr,int *vp)
381 return 0; 398 return 0;
382} 399}
383 400
384static int ctrl_freq_check(struct pvr2_ctrl *cptr,int v) 401static int ctrl_get_input(struct pvr2_ctrl *cptr,int *vp)
385{ 402{
386 if (cptr->hdw->input_val == PVR2_CVAL_INPUT_RADIO) { 403 *vp = cptr->hdw->input_val;
387 return ((v >= RADIO_MIN_FREQ) && (v <= RADIO_MAX_FREQ)); 404 return 0;
388 } else { 405}
389 return ((v >= TV_MIN_FREQ) && (v <= TV_MAX_FREQ)); 406
407static int ctrl_set_input(struct pvr2_ctrl *cptr,int m,int v)
408{
409 struct pvr2_hdw *hdw = cptr->hdw;
410
411 if (hdw->input_val != v) {
412 hdw->input_val = v;
413 hdw->input_dirty = !0;
414 }
415
416 /* Handle side effects - if we switch to a mode that needs the RF
417 tuner, then select the right frequency choice as well and mark
418 it dirty. */
419 if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
420 hdw->freqSelector = 0;
421 hdw->freqDirty = !0;
422 } else if (hdw->input_val == PVR2_CVAL_INPUT_TV) {
423 hdw->freqSelector = 1;
424 hdw->freqDirty = !0;
390 } 425 }
426 return 0;
427}
428
429static int ctrl_isdirty_input(struct pvr2_ctrl *cptr)
430{
431 return cptr->hdw->input_dirty != 0;
432}
433
434static void ctrl_cleardirty_input(struct pvr2_ctrl *cptr)
435{
436 cptr->hdw->input_dirty = 0;
437}
438
439static int ctrl_freq_check(struct pvr2_ctrl *cptr,int v)
440{
441 /* Both ranges are simultaneously considered legal, in order to
442 permit implicit mode switching, i.e. set a frequency in the
443 other range and the mode will switch */
444 return (((v >= RADIO_MIN_FREQ) && (v <= RADIO_MAX_FREQ)) ||
445 ((v >= TV_MIN_FREQ) && (v <= TV_MAX_FREQ)));
391} 446}
392 447
393static int ctrl_freq_max_get(struct pvr2_ctrl *cptr, int *vp) 448static int ctrl_freq_max_get(struct pvr2_ctrl *cptr, int *vp)
@@ -675,11 +730,11 @@ VCREATE_FUNCS(balance)
675VCREATE_FUNCS(bass) 730VCREATE_FUNCS(bass)
676VCREATE_FUNCS(treble) 731VCREATE_FUNCS(treble)
677VCREATE_FUNCS(mute) 732VCREATE_FUNCS(mute)
678VCREATE_FUNCS(input)
679VCREATE_FUNCS(audiomode) 733VCREATE_FUNCS(audiomode)
680VCREATE_FUNCS(res_hor) 734VCREATE_FUNCS(res_hor)
681VCREATE_FUNCS(res_ver) 735VCREATE_FUNCS(res_ver)
682VCREATE_FUNCS(srate) 736VCREATE_FUNCS(srate)
737VCREATE_FUNCS(automodeswitch)
683 738
684/* Table definition of all controls which can be manipulated */ 739/* Table definition of all controls which can be manipulated */
685static const struct pvr2_ctl_info control_defs[] = { 740static const struct pvr2_ctl_info control_defs[] = {
@@ -779,6 +834,13 @@ static const struct pvr2_ctl_info control_defs[] = {
779 .get_max_value = ctrl_vres_max_get, 834 .get_max_value = ctrl_vres_max_get,
780 .get_min_value = ctrl_vres_min_get, 835 .get_min_value = ctrl_vres_min_get,
781 },{ 836 },{
837 .v4l_id = V4L2_CID_AUDIO_MUTE,
838 .desc = "Automatic TV / Radio mode switch based on frequency",
839 .name = "auto_mode_switch",
840 .default_value = 0,
841 DEFREF(automodeswitch),
842 DEFBOOL,
843 },{
782 .v4l_id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ, 844 .v4l_id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
783 .default_value = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, 845 .default_value = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
784 .desc = "Audio Sampling Frequency", 846 .desc = "Audio Sampling Frequency",
@@ -789,7 +851,7 @@ static const struct pvr2_ctl_info control_defs[] = {
789 .desc = "Tuner Frequency (Hz)", 851 .desc = "Tuner Frequency (Hz)",
790 .name = "frequency", 852 .name = "frequency",
791 .internal_id = PVR2_CID_FREQUENCY, 853 .internal_id = PVR2_CID_FREQUENCY,
792 .default_value = 175250000L, 854 .default_value = 0,
793 .set_value = ctrl_freq_set, 855 .set_value = ctrl_freq_set,
794 .get_value = ctrl_freq_get, 856 .get_value = ctrl_freq_get,
795 .is_dirty = ctrl_freq_is_dirty, 857 .is_dirty = ctrl_freq_is_dirty,
@@ -812,6 +874,11 @@ static const struct pvr2_ctl_info control_defs[] = {
812 .set_value = ctrl_channelfreq_set, 874 .set_value = ctrl_channelfreq_set,
813 .get_value = ctrl_channelfreq_get, 875 .get_value = ctrl_channelfreq_get,
814 DEFINT(TV_MIN_FREQ,TV_MAX_FREQ), 876 DEFINT(TV_MIN_FREQ,TV_MAX_FREQ),
877 /* Hook in check for input value (tv/radio) and adjust
878 max/min values accordingly */
879 .check_value = ctrl_freq_check,
880 .get_max_value = ctrl_freq_max_get,
881 .get_min_value = ctrl_freq_min_get,
815 },{ 882 },{
816 .desc = "Channel Program ID", 883 .desc = "Channel Program ID",
817 .name = "freq_table_channel", 884 .name = "freq_table_channel",
@@ -908,6 +975,83 @@ unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *hdw)
908 return hdw->serial_number; 975 return hdw->serial_number;
909} 976}
910 977
978unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *hdw)
979{
980 return hdw->freqSelector ? hdw->freqValTelevision : hdw->freqValRadio;
981}
982
983/* Set the currently tuned frequency and account for all possible
984 driver-core side effects of this action. */
985void pvr2_hdw_set_cur_freq(struct pvr2_hdw *hdw,unsigned long val)
986{
987 int mode = 0;
988
989 /* If hdw->automodeswitch_val is set, then we do something clever:
990 Look at the desired frequency and see if it looks like FM or TV.
991 Execute a possible mode switch based on this result. Otherwise
992 we use the current input setting to determine which frequency
993 register we need to adjust. */
994 if (hdw->automodeswitch_val) {
995 /* Note that since FM RADIO frequency range sits *inside*
996 the TV spectrum that we must therefore check the radio
997 range first... */
998 if ((val >= RADIO_MIN_FREQ) && (val <= RADIO_MAX_FREQ)) {
999 mode = 1;
1000 } else if ((val >= TV_MIN_FREQ) && (val <= TV_MAX_FREQ)) {
1001 mode = 2;
1002 }
1003 } else {
1004 if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
1005 mode = 1;
1006 } else {
1007 mode = 2;
1008 }
1009 }
1010
1011 switch (mode) {
1012 case 1:
1013 if (hdw->freqSelector) {
1014 /* Swing over to radio frequency selection */
1015 hdw->freqSelector = 0;
1016 hdw->freqDirty = !0;
1017 }
1018 if (hdw->input_val == PVR2_CVAL_INPUT_TV) {
1019 /* Force switch to radio mode */
1020 hdw->input_val = PVR2_CVAL_INPUT_RADIO;
1021 hdw->input_dirty = !0;
1022 }
1023 if (hdw->freqValRadio != val) {
1024 hdw->freqValRadio = val;
1025 hdw->freqSlotRadio = 0;
1026 if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
1027 hdw->freqDirty = !0;
1028 }
1029 }
1030 break;
1031 case 2:
1032 if (!(hdw->freqSelector)) {
1033 /* Swing over to television frequency selection */
1034 hdw->freqSelector = 1;
1035 hdw->freqDirty = !0;
1036 }
1037 if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
1038 /* Force switch to television mode */
1039 hdw->input_val = PVR2_CVAL_INPUT_TV;
1040 hdw->input_dirty = !0;
1041 }
1042 if (hdw->freqValTelevision != val) {
1043 hdw->freqValTelevision = val;
1044 hdw->freqSlotTelevision = 0;
1045 if (hdw->input_val == PVR2_CVAL_INPUT_TV) {
1046 hdw->freqDirty = !0;
1047 }
1048 }
1049 break;
1050 default:
1051 break;
1052 }
1053}
1054
911int pvr2_hdw_get_unit_number(struct pvr2_hdw *hdw) 1055int pvr2_hdw_get_unit_number(struct pvr2_hdw *hdw)
912{ 1056{
913 return hdw->unit_number; 1057 return hdw->unit_number;
@@ -1647,6 +1791,21 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
1647 cptr->info->set_value(cptr,~0,cptr->info->default_value); 1791 cptr->info->set_value(cptr,~0,cptr->info->default_value);
1648 } 1792 }
1649 1793
1794 /* Set up special default values for the television and radio
1795 frequencies here. It's not really important what these defaults
1796 are, but I set them to something usable in the Chicago area just
1797 to make driver testing a little easier. */
1798
1799 /* US Broadcast channel 7 (175.25 MHz) */
1800 hdw->freqValTelevision = 175250000L;
1801 /* 104.3 MHz, a usable FM station for my area */
1802 hdw->freqValRadio = 104300000L;
1803
1804 /* Default value for auto mode switch based on module option */
1805 if ((hdw->unit_number >= 0) && (hdw->unit_number < PVR_NUM)) {
1806 hdw->automodeswitch_val = auto_mode_switch[hdw->unit_number];
1807 }
1808
1650 // Do not use pvr2_reset_ctl_endpoints() here. It is not 1809 // Do not use pvr2_reset_ctl_endpoints() here. It is not
1651 // thread-safe against the normal pvr2_send_request() mechanism. 1810 // thread-safe against the normal pvr2_send_request() mechanism.
1652 // (We should make it thread safe). 1811 // (We should make it thread safe).
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
index c885a9c25e76..a6a9e4142311 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
@@ -143,7 +143,7 @@ static void set_frequency(struct pvr2_hdw *hdw)
143{ 143{
144 unsigned long fv; 144 unsigned long fv;
145 struct v4l2_frequency freq; 145 struct v4l2_frequency freq;
146 fv = hdw->freqVal; 146 fv = pvr2_hdw_get_cur_freq(hdw);
147 pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_freq(%lu)",fv); 147 pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_freq(%lu)",fv);
148 memset(&freq,0,sizeof(freq)); 148 memset(&freq,0,sizeof(freq));
149 if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) { 149 if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {