summaryrefslogtreecommitdiff
path: root/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c')
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c260
1 files changed, 108 insertions, 152 deletions
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 0fce806ea..b07bd58ea 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -40,8 +40,6 @@
#define TV_MIN_FREQ 55250000L
#define TV_MAX_FREQ 850000000L
-#define RADIO_MIN_FREQ 87000000L
-#define RADIO_MAX_FREQ 108000000L
struct usb_device_id pvr2_device_table[] = {
[PVR2_HDW_TYPE_29XXX] = { USB_DEVICE(0x2040, 0x2900) },
@@ -77,12 +75,10 @@ static const char *pvr2_client_29xxx[] = {
static struct pvr2_string_table pvr2_client_lists[] = {
[PVR2_HDW_TYPE_29XXX] = {
- pvr2_client_29xxx,
- sizeof(pvr2_client_29xxx)/sizeof(pvr2_client_29xxx[0]),
+ pvr2_client_29xxx, ARRAY_SIZE(pvr2_client_29xxx)
},
[PVR2_HDW_TYPE_24XXX] = {
- pvr2_client_24xxx,
- sizeof(pvr2_client_24xxx)/sizeof(pvr2_client_24xxx[0]),
+ pvr2_client_24xxx, ARRAY_SIZE(pvr2_client_24xxx)
},
};
@@ -95,7 +91,6 @@ static int procreload = 0;
static int tuner[PVR_NUM] = { [0 ... PVR_NUM-1] = -1 };
static int tolerance[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 };
static int video_std[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 };
-static int auto_mode_switch[PVR_NUM];
static int init_pause_msec = 0;
module_param(ctlchg, int, S_IRUGO|S_IWUSR);
@@ -113,8 +108,6 @@ module_param_array(video_std, int, NULL, 0444);
MODULE_PARM_DESC(video_std,"specify initial video standard");
module_param_array(tolerance, int, NULL, 0444);
MODULE_PARM_DESC(tolerance,"specify stream error tolerance");
-module_param_array(auto_mode_switch, int, NULL, 0444);
-MODULE_PARM_DESC(auto_mode_switch,"Enable TV/Radio automatic mode switch based on freq");
#define PVR2_CTL_WRITE_ENDPOINT 0x01
#define PVR2_CTL_READ_ENDPOINT 0x81
@@ -218,7 +211,7 @@ static const struct pvr2_mpeg_ids mpeg_ids[] = {
.id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM,
}
};
-#define MPEGDEF_COUNT (sizeof(mpeg_ids)/sizeof(mpeg_ids[0]))
+#define MPEGDEF_COUNT ARRAY_SIZE(mpeg_ids)
static const char *control_values_srate[] = {
@@ -265,7 +258,6 @@ static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long);
static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl);
static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw);
static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw);
-static unsigned int pvr2_hdw_get_signal_status_internal(struct pvr2_hdw *hdw);
static void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw);
static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw);
static void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw);
@@ -437,34 +429,48 @@ static void ctrl_cleardirty_input(struct pvr2_ctrl *cptr)
cptr->hdw->input_dirty = 0;
}
-static int ctrl_freq_check(struct pvr2_ctrl *cptr,int v)
-{
- /* Both ranges are simultaneously considered legal, in order to
- permit implicit mode switching, i.e. set a frequency in the
- other range and the mode will switch */
- return (((v >= RADIO_MIN_FREQ) && (v <= RADIO_MAX_FREQ)) ||
- ((v >= TV_MIN_FREQ) && (v <= TV_MAX_FREQ)));
-}
static int ctrl_freq_max_get(struct pvr2_ctrl *cptr, int *vp)
{
- /* Actual maximum depends on radio/tv mode */
- if (cptr->hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
- *vp = RADIO_MAX_FREQ;
- } else {
+ unsigned long fv;
+ struct pvr2_hdw *hdw = cptr->hdw;
+ if (hdw->tuner_signal_stale) {
+ pvr2_i2c_core_status_poll(hdw);
+ }
+ fv = hdw->tuner_signal_info.rangehigh;
+ if (!fv) {
+ /* Safety fallback */
*vp = TV_MAX_FREQ;
+ return 0;
+ }
+ if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) {
+ fv = (fv * 125) / 2;
+ } else {
+ fv = fv * 62500;
}
+ *vp = fv;
return 0;
}
static int ctrl_freq_min_get(struct pvr2_ctrl *cptr, int *vp)
{
- /* Actual minimum depends on radio/tv mode */
- if (cptr->hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
- *vp = RADIO_MIN_FREQ;
- } else {
+ unsigned long fv;
+ struct pvr2_hdw *hdw = cptr->hdw;
+ if (hdw->tuner_signal_stale) {
+ pvr2_i2c_core_status_poll(hdw);
+ }
+ fv = hdw->tuner_signal_info.rangelow;
+ if (!fv) {
+ /* Safety fallback */
*vp = TV_MIN_FREQ;
+ return 0;
+ }
+ if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) {
+ fv = (fv * 125) / 2;
+ } else {
+ fv = fv * 62500;
}
+ *vp = fv;
return 0;
}
@@ -624,8 +630,32 @@ static void ctrl_stdcur_clear_dirty(struct pvr2_ctrl *cptr)
static int ctrl_signal_get(struct pvr2_ctrl *cptr,int *vp)
{
- *vp = ((pvr2_hdw_get_signal_status_internal(cptr->hdw) &
- PVR2_SIGNAL_OK) ? 1 : 0);
+ struct pvr2_hdw *hdw = cptr->hdw;
+ pvr2_i2c_core_status_poll(hdw);
+ *vp = hdw->tuner_signal_info.signal;
+ return 0;
+}
+
+static int ctrl_audio_modes_present_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ int val = 0;
+ unsigned int subchan;
+ struct pvr2_hdw *hdw = cptr->hdw;
+ pvr2_i2c_core_status_poll(hdw);
+ subchan = hdw->tuner_signal_info.rxsubchans;
+ if (subchan & V4L2_TUNER_SUB_MONO) {
+ val |= (1 << V4L2_TUNER_MODE_MONO);
+ }
+ if (subchan & V4L2_TUNER_SUB_STEREO) {
+ val |= (1 << V4L2_TUNER_MODE_STEREO);
+ }
+ if (subchan & V4L2_TUNER_SUB_LANG1) {
+ val |= (1 << V4L2_TUNER_MODE_LANG1);
+ }
+ if (subchan & V4L2_TUNER_SUB_LANG2) {
+ val |= (1 << V4L2_TUNER_MODE_LANG2);
+ }
+ *vp = val;
return 0;
}
@@ -694,7 +724,7 @@ static void ctrl_stdenumcur_clear_dirty(struct pvr2_ctrl *cptr)
#define DEFENUM(tab) \
.type = pvr2_ctl_enum, \
- .def.type_enum.count = (sizeof(tab)/sizeof((tab)[0])), \
+ .def.type_enum.count = ARRAY_SIZE(tab), \
.def.type_enum.value_names = tab
#define DEFBOOL \
@@ -735,7 +765,6 @@ VCREATE_FUNCS(audiomode)
VCREATE_FUNCS(res_hor)
VCREATE_FUNCS(res_ver)
VCREATE_FUNCS(srate)
-VCREATE_FUNCS(automodeswitch)
/* Table definition of all controls which can be manipulated */
static const struct pvr2_ctl_info control_defs[] = {
@@ -835,12 +864,6 @@ static const struct pvr2_ctl_info control_defs[] = {
.get_max_value = ctrl_vres_max_get,
.get_min_value = ctrl_vres_min_get,
},{
- .desc = "Automatic TV / Radio mode switch based on frequency",
- .name = "auto_mode_switch",
- .default_value = 0,
- DEFREF(automodeswitch),
- DEFBOOL,
- },{
.v4l_id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
.default_value = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
.desc = "Audio Sampling Frequency",
@@ -856,10 +879,9 @@ static const struct pvr2_ctl_info control_defs[] = {
.get_value = ctrl_freq_get,
.is_dirty = ctrl_freq_is_dirty,
.clear_dirty = ctrl_freq_clear_dirty,
- DEFINT(TV_MIN_FREQ,TV_MAX_FREQ),
+ DEFINT(0,0),
/* Hook in check for input value (tv/radio) and adjust
max/min values accordingly */
- .check_value = ctrl_freq_check,
.get_max_value = ctrl_freq_max_get,
.get_min_value = ctrl_freq_min_get,
},{
@@ -873,10 +895,9 @@ static const struct pvr2_ctl_info control_defs[] = {
.name = "freq_table_value",
.set_value = ctrl_channelfreq_set,
.get_value = ctrl_channelfreq_get,
- DEFINT(TV_MIN_FREQ,TV_MAX_FREQ),
+ DEFINT(0,0),
/* Hook in check for input value (tv/radio) and adjust
max/min values accordingly */
- .check_value = ctrl_freq_check,
.get_max_value = ctrl_freq_max_get,
.get_min_value = ctrl_freq_min_get,
},{
@@ -899,7 +920,20 @@ static const struct pvr2_ctl_info control_defs[] = {
.desc = "Signal Present",
.name = "signal_present",
.get_value = ctrl_signal_get,
- DEFBOOL,
+ DEFINT(0,65535),
+ },{
+ .desc = "Audio Modes Present",
+ .name = "audio_modes_present",
+ .get_value = ctrl_audio_modes_present_get,
+ /* For this type we "borrow" the V4L2_TUNER_MODE enum from
+ v4l. Nothing outside of this module cares about this,
+ but I reuse it in order to also reuse the
+ control_values_audiomode string table. */
+ DEFMASK(((1 << V4L2_TUNER_MODE_MONO)|
+ (1 << V4L2_TUNER_MODE_STEREO)|
+ (1 << V4L2_TUNER_MODE_LANG1)|
+ (1 << V4L2_TUNER_MODE_LANG2)),
+ control_values_audiomode),
},{
.desc = "Video Standards Available Mask",
.name = "video_standard_mask_available",
@@ -949,7 +983,7 @@ static const struct pvr2_ctl_info control_defs[] = {
}
};
-#define CTRLDEF_COUNT (sizeof(control_defs)/sizeof(control_defs[0]))
+#define CTRLDEF_COUNT ARRAY_SIZE(control_defs)
const char *pvr2_config_get_name(enum pvr2_config cfg)
@@ -985,71 +1019,28 @@ unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *hdw)
driver-core side effects of this action. */
void pvr2_hdw_set_cur_freq(struct pvr2_hdw *hdw,unsigned long val)
{
- int mode = 0;
-
- /* If hdw->automodeswitch_val is set, then we do something clever:
- Look at the desired frequency and see if it looks like FM or TV.
- Execute a possible mode switch based on this result. Otherwise
- we use the current input setting to determine which frequency
- register we need to adjust. */
- if (hdw->automodeswitch_val) {
- /* Note that since FM RADIO frequency range sits *inside*
- the TV spectrum that we must therefore check the radio
- range first... */
- if ((val >= RADIO_MIN_FREQ) && (val <= RADIO_MAX_FREQ)) {
- mode = 1;
- } else if ((val >= TV_MIN_FREQ) && (val <= TV_MAX_FREQ)) {
- mode = 2;
- }
- } else {
- if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
- mode = 1;
- } else {
- mode = 2;
- }
- }
-
- switch (mode) {
- case 1:
+ if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
if (hdw->freqSelector) {
/* Swing over to radio frequency selection */
hdw->freqSelector = 0;
hdw->freqDirty = !0;
}
- if (hdw->input_val == PVR2_CVAL_INPUT_TV) {
- /* Force switch to radio mode */
- hdw->input_val = PVR2_CVAL_INPUT_RADIO;
- hdw->input_dirty = !0;
- }
if (hdw->freqValRadio != val) {
hdw->freqValRadio = val;
hdw->freqSlotRadio = 0;
- if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
- hdw->freqDirty = !0;
- }
+ hdw->freqDirty = !0;
}
- break;
- case 2:
+ } else {
if (!(hdw->freqSelector)) {
/* Swing over to television frequency selection */
hdw->freqSelector = 1;
hdw->freqDirty = !0;
}
- if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
- /* Force switch to television mode */
- hdw->input_val = PVR2_CVAL_INPUT_TV;
- hdw->input_dirty = !0;
- }
if (hdw->freqValTelevision != val) {
hdw->freqValTelevision = val;
hdw->freqSlotTelevision = 0;
- if (hdw->input_val == PVR2_CVAL_INPUT_TV) {
- hdw->freqDirty = !0;
- }
+ hdw->freqDirty = !0;
}
- break;
- default:
- break;
}
}
@@ -1150,12 +1141,10 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw)
};
static const struct pvr2_string_table fw_file_defs[] = {
[PVR2_HDW_TYPE_29XXX] = {
- fw_files_29xxx,
- sizeof(fw_files_29xxx)/sizeof(fw_files_29xxx[0]),
+ fw_files_29xxx, ARRAY_SIZE(fw_files_29xxx)
},
[PVR2_HDW_TYPE_24XXX] = {
- fw_files_24xxx,
- sizeof(fw_files_24xxx)/sizeof(fw_files_24xxx[0]),
+ fw_files_24xxx, ARRAY_SIZE(fw_files_24xxx)
},
};
hdw->fw1_state = FW1_STATE_FAILED; // default result
@@ -1242,8 +1231,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
trace_firmware("pvr2_upload_firmware2");
ret = pvr2_locate_firmware(hdw,&fw_entry,"encoder",
- sizeof(fw_files)/sizeof(fw_files[0]),
- fw_files);
+ ARRAY_SIZE(fw_files), fw_files);
if (ret < 0) return ret;
fwidx = ret;
ret = 0;
@@ -1828,11 +1816,6 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
/* 104.3 MHz, a usable FM station for my area */
hdw->freqValRadio = 104300000L;
- /* Default value for auto mode switch based on module option */
- if ((hdw->unit_number >= 0) && (hdw->unit_number < PVR_NUM)) {
- hdw->automodeswitch_val = auto_mode_switch[hdw->unit_number];
- }
-
// Do not use pvr2_reset_ctl_endpoints() here. It is not
// thread-safe against the normal pvr2_send_request() mechanism.
// (We should make it thread safe).
@@ -1972,26 +1955,24 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
struct pvr2_ctl_info *ciptr;
hdw_type = devid - pvr2_device_table;
- if (hdw_type >=
- sizeof(pvr2_device_names)/sizeof(pvr2_device_names[0])) {
+ if (hdw_type >= ARRAY_SIZE(pvr2_device_names)) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"Bogus device type of %u reported",hdw_type);
return NULL;
}
- hdw = kmalloc(sizeof(*hdw),GFP_KERNEL);
+ hdw = kzalloc(sizeof(*hdw),GFP_KERNEL);
pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"",
hdw,pvr2_device_names[hdw_type]);
if (!hdw) goto fail;
- memset(hdw,0,sizeof(*hdw));
+ hdw->tuner_signal_stale = !0;
cx2341x_fill_defaults(&hdw->enc_ctl_state);
hdw->control_cnt = CTRLDEF_COUNT;
hdw->control_cnt += MPEGDEF_COUNT;
- hdw->controls = kmalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt,
+ hdw->controls = kzalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt,
GFP_KERNEL);
if (!hdw->controls) goto fail;
- memset(hdw->controls,0,sizeof(struct pvr2_ctrl) * hdw->control_cnt);
hdw->hdw_type = hdw_type;
for (idx = 0; idx < hdw->control_cnt; idx++) {
cptr = hdw->controls + idx;
@@ -2005,11 +1986,9 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
cptr->info = control_defs+idx;
}
/* Define and configure additional controls from cx2341x module. */
- hdw->mpeg_ctrl_info = kmalloc(
+ hdw->mpeg_ctrl_info = kzalloc(
sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT, GFP_KERNEL);
if (!hdw->mpeg_ctrl_info) goto fail;
- memset(hdw->mpeg_ctrl_info,0,
- sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT);
for (idx = 0; idx < MPEGDEF_COUNT; idx++) {
cptr = hdw->controls + idx + CTRLDEF_COUNT;
ciptr = &(hdw->mpeg_ctrl_info[idx].info);
@@ -2206,9 +2185,6 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
pvr2_stream_destroy(hdw->vid_stream);
hdw->vid_stream = NULL;
}
- if (hdw->audio_stat) {
- hdw->audio_stat->detach(hdw->audio_stat->ctxt);
- }
if (hdw->decoder_ctrl) {
hdw->decoder_ctrl->detach(hdw->decoder_ctrl->ctxt);
}
@@ -2434,10 +2410,9 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
cptr = hdw->controls + idx;
if (cptr->info->is_dirty == 0) continue;
if (!cptr->info->is_dirty(cptr)) continue;
- if (!commit_flag) {
- commit_flag = !0;
- }
+ commit_flag = !0;
+ if (!(pvrusb2_debug & PVR2_TRACE_CTL)) continue;
bcnt = scnprintf(buf,sizeof(buf),"\"%s\" <-- ",
cptr->info->name);
value = 0;
@@ -2586,34 +2561,6 @@ const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
}
-/* Return bit mask indicating signal status */
-static unsigned int pvr2_hdw_get_signal_status_internal(struct pvr2_hdw *hdw)
-{
- unsigned int msk = 0;
- switch (hdw->input_val) {
- case PVR2_CVAL_INPUT_TV:
- case PVR2_CVAL_INPUT_RADIO:
- if (hdw->decoder_ctrl &&
- hdw->decoder_ctrl->tuned(hdw->decoder_ctrl->ctxt)) {
- msk |= PVR2_SIGNAL_OK;
- if (hdw->audio_stat &&
- hdw->audio_stat->status(hdw->audio_stat->ctxt)) {
- if (hdw->flag_stereo) {
- msk |= PVR2_SIGNAL_STEREO;
- }
- if (hdw->flag_bilingual) {
- msk |= PVR2_SIGNAL_SAP;
- }
- }
- }
- break;
- default:
- msk |= PVR2_SIGNAL_OK | PVR2_SIGNAL_STEREO;
- }
- return msk;
-}
-
-
int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
{
int result;
@@ -2629,14 +2576,25 @@ int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
}
-/* Return bit mask indicating signal status */
-unsigned int pvr2_hdw_get_signal_status(struct pvr2_hdw *hdw)
+/* Execute poll of tuner status */
+void pvr2_hdw_execute_tuner_poll(struct pvr2_hdw *hdw)
+{
+ LOCK_TAKE(hdw->big_lock); do {
+ pvr2_i2c_core_status_poll(hdw);
+ } while (0); LOCK_GIVE(hdw->big_lock);
+}
+
+
+/* Return information about the tuner */
+int pvr2_hdw_get_tuner_status(struct pvr2_hdw *hdw,struct v4l2_tuner *vtp)
{
- unsigned int msk = 0;
LOCK_TAKE(hdw->big_lock); do {
- msk = pvr2_hdw_get_signal_status_internal(hdw);
+ if (hdw->tuner_signal_stale) {
+ pvr2_i2c_core_status_poll(hdw);
+ }
+ memcpy(vtp,&hdw->tuner_signal_info,sizeof(struct v4l2_tuner));
} while (0); LOCK_GIVE(hdw->big_lock);
- return msk;
+ return 0;
}
@@ -2685,14 +2643,12 @@ void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, int enable_flag)
pvr2_trace(PVR2_TRACE_FIRMWARE,
"Preparing to suck out CPU firmware");
hdw->fw_size = 0x2000;
- hdw->fw_buffer = kmalloc(hdw->fw_size,GFP_KERNEL);
+ hdw->fw_buffer = kzalloc(hdw->fw_size,GFP_KERNEL);
if (!hdw->fw_buffer) {
hdw->fw_size = 0;
break;
}
- memset(hdw->fw_buffer,0,hdw->fw_size);
-
/* We have to hold the CPU during firmware upload. */
pvr2_hdw_cpureset_assert(hdw,1);