diff options
Diffstat (limited to 'linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c')
-rw-r--r-- | linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c | 260 |
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); |