/drivers/media/video/pvrusb2/pvrusb2-hdw.c
https://bitbucket.org/wisechild/galaxy-nexus · C · 5322 lines · 4253 code · 603 blank · 466 comment · 714 complexity · 7c94954335ac73ba1975e7d8876f4c34 MD5 · raw file
Large files are truncated click here to view the full file
- /*
- *
- *
- * Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
- #include <linux/errno.h>
- #include <linux/string.h>
- #include <linux/slab.h>
- #include <linux/firmware.h>
- #include <linux/videodev2.h>
- #include <media/v4l2-common.h>
- #include <media/tuner.h>
- #include "pvrusb2.h"
- #include "pvrusb2-std.h"
- #include "pvrusb2-util.h"
- #include "pvrusb2-hdw.h"
- #include "pvrusb2-i2c-core.h"
- #include "pvrusb2-eeprom.h"
- #include "pvrusb2-hdw-internal.h"
- #include "pvrusb2-encoder.h"
- #include "pvrusb2-debug.h"
- #include "pvrusb2-fx2-cmd.h"
- #include "pvrusb2-wm8775.h"
- #include "pvrusb2-video-v4l.h"
- #include "pvrusb2-cx2584x-v4l.h"
- #include "pvrusb2-cs53l32a.h"
- #include "pvrusb2-audio.h"
- #define TV_MIN_FREQ 55250000L
- #define TV_MAX_FREQ 850000000L
- /* This defines a minimum interval that the decoder must remain quiet
- before we are allowed to start it running. */
- #define TIME_MSEC_DECODER_WAIT 50
- /* This defines a minimum interval that the decoder must be allowed to run
- before we can safely begin using its streaming output. */
- #define TIME_MSEC_DECODER_STABILIZATION_WAIT 300
- /* This defines a minimum interval that the encoder must remain quiet
- before we are allowed to configure it. */
- #define TIME_MSEC_ENCODER_WAIT 50
- /* This defines the minimum interval that the encoder must successfully run
- before we consider that the encoder has run at least once since its
- firmware has been loaded. This measurement is in important for cases
- where we can't do something until we know that the encoder has been run
- at least once. */
- #define TIME_MSEC_ENCODER_OK 250
- static struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = NULL};
- static DEFINE_MUTEX(pvr2_unit_mtx);
- static int ctlchg;
- static int procreload;
- 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 init_pause_msec;
- module_param(ctlchg, int, S_IRUGO|S_IWUSR);
- MODULE_PARM_DESC(ctlchg, "0=optimize ctl change 1=always accept new ctl value");
- module_param(init_pause_msec, int, S_IRUGO|S_IWUSR);
- MODULE_PARM_DESC(init_pause_msec, "hardware initialization settling delay");
- module_param(procreload, int, S_IRUGO|S_IWUSR);
- MODULE_PARM_DESC(procreload,
- "Attempt init failure recovery with firmware reload");
- module_param_array(tuner, int, NULL, 0444);
- MODULE_PARM_DESC(tuner,"specify installed tuner type");
- 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");
- /* US Broadcast channel 3 (61.25 MHz), to help with testing */
- static int default_tv_freq = 61250000L;
- /* 104.3 MHz, a usable FM station for my area */
- static int default_radio_freq = 104300000L;
- module_param_named(tv_freq, default_tv_freq, int, 0444);
- MODULE_PARM_DESC(tv_freq, "specify initial television frequency");
- module_param_named(radio_freq, default_radio_freq, int, 0444);
- MODULE_PARM_DESC(radio_freq, "specify initial radio frequency");
- #define PVR2_CTL_WRITE_ENDPOINT 0x01
- #define PVR2_CTL_READ_ENDPOINT 0x81
- #define PVR2_GPIO_IN 0x9008
- #define PVR2_GPIO_OUT 0x900c
- #define PVR2_GPIO_DIR 0x9020
- #define trace_firmware(...) pvr2_trace(PVR2_TRACE_FIRMWARE,__VA_ARGS__)
- #define PVR2_FIRMWARE_ENDPOINT 0x02
- /* size of a firmware chunk */
- #define FIRMWARE_CHUNK_SIZE 0x2000
- typedef void (*pvr2_subdev_update_func)(struct pvr2_hdw *,
- struct v4l2_subdev *);
- static const pvr2_subdev_update_func pvr2_module_update_functions[] = {
- [PVR2_CLIENT_ID_WM8775] = pvr2_wm8775_subdev_update,
- [PVR2_CLIENT_ID_SAA7115] = pvr2_saa7115_subdev_update,
- [PVR2_CLIENT_ID_MSP3400] = pvr2_msp3400_subdev_update,
- [PVR2_CLIENT_ID_CX25840] = pvr2_cx25840_subdev_update,
- [PVR2_CLIENT_ID_CS53L32A] = pvr2_cs53l32a_subdev_update,
- };
- static const char *module_names[] = {
- [PVR2_CLIENT_ID_MSP3400] = "msp3400",
- [PVR2_CLIENT_ID_CX25840] = "cx25840",
- [PVR2_CLIENT_ID_SAA7115] = "saa7115",
- [PVR2_CLIENT_ID_TUNER] = "tuner",
- [PVR2_CLIENT_ID_DEMOD] = "tuner",
- [PVR2_CLIENT_ID_CS53L32A] = "cs53l32a",
- [PVR2_CLIENT_ID_WM8775] = "wm8775",
- };
- static const unsigned char *module_i2c_addresses[] = {
- [PVR2_CLIENT_ID_TUNER] = "\x60\x61\x62\x63",
- [PVR2_CLIENT_ID_DEMOD] = "\x43",
- [PVR2_CLIENT_ID_MSP3400] = "\x40",
- [PVR2_CLIENT_ID_SAA7115] = "\x21",
- [PVR2_CLIENT_ID_WM8775] = "\x1b",
- [PVR2_CLIENT_ID_CX25840] = "\x44",
- [PVR2_CLIENT_ID_CS53L32A] = "\x11",
- };
- static const char *ir_scheme_names[] = {
- [PVR2_IR_SCHEME_NONE] = "none",
- [PVR2_IR_SCHEME_29XXX] = "29xxx",
- [PVR2_IR_SCHEME_24XXX] = "24xxx (29xxx emulation)",
- [PVR2_IR_SCHEME_24XXX_MCE] = "24xxx (MCE device)",
- [PVR2_IR_SCHEME_ZILOG] = "Zilog",
- };
- /* Define the list of additional controls we'll dynamically construct based
- on query of the cx2341x module. */
- struct pvr2_mpeg_ids {
- const char *strid;
- int id;
- };
- static const struct pvr2_mpeg_ids mpeg_ids[] = {
- {
- .strid = "audio_layer",
- .id = V4L2_CID_MPEG_AUDIO_ENCODING,
- },{
- .strid = "audio_bitrate",
- .id = V4L2_CID_MPEG_AUDIO_L2_BITRATE,
- },{
- /* Already using audio_mode elsewhere :-( */
- .strid = "mpeg_audio_mode",
- .id = V4L2_CID_MPEG_AUDIO_MODE,
- },{
- .strid = "mpeg_audio_mode_extension",
- .id = V4L2_CID_MPEG_AUDIO_MODE_EXTENSION,
- },{
- .strid = "audio_emphasis",
- .id = V4L2_CID_MPEG_AUDIO_EMPHASIS,
- },{
- .strid = "audio_crc",
- .id = V4L2_CID_MPEG_AUDIO_CRC,
- },{
- .strid = "video_aspect",
- .id = V4L2_CID_MPEG_VIDEO_ASPECT,
- },{
- .strid = "video_b_frames",
- .id = V4L2_CID_MPEG_VIDEO_B_FRAMES,
- },{
- .strid = "video_gop_size",
- .id = V4L2_CID_MPEG_VIDEO_GOP_SIZE,
- },{
- .strid = "video_gop_closure",
- .id = V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
- },{
- .strid = "video_bitrate_mode",
- .id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
- },{
- .strid = "video_bitrate",
- .id = V4L2_CID_MPEG_VIDEO_BITRATE,
- },{
- .strid = "video_bitrate_peak",
- .id = V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
- },{
- .strid = "video_temporal_decimation",
- .id = V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION,
- },{
- .strid = "stream_type",
- .id = V4L2_CID_MPEG_STREAM_TYPE,
- },{
- .strid = "video_spatial_filter_mode",
- .id = V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE,
- },{
- .strid = "video_spatial_filter",
- .id = V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER,
- },{
- .strid = "video_luma_spatial_filter_type",
- .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE,
- },{
- .strid = "video_chroma_spatial_filter_type",
- .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE,
- },{
- .strid = "video_temporal_filter_mode",
- .id = V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE,
- },{
- .strid = "video_temporal_filter",
- .id = V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER,
- },{
- .strid = "video_median_filter_type",
- .id = V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE,
- },{
- .strid = "video_luma_median_filter_top",
- .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP,
- },{
- .strid = "video_luma_median_filter_bottom",
- .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM,
- },{
- .strid = "video_chroma_median_filter_top",
- .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP,
- },{
- .strid = "video_chroma_median_filter_bottom",
- .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM,
- }
- };
- #define MPEGDEF_COUNT ARRAY_SIZE(mpeg_ids)
- static const char *control_values_srate[] = {
- [V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100] = "44.1 kHz",
- [V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000] = "48 kHz",
- [V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000] = "32 kHz",
- };
- static const char *control_values_input[] = {
- [PVR2_CVAL_INPUT_TV] = "television", /*xawtv needs this name*/
- [PVR2_CVAL_INPUT_DTV] = "dtv",
- [PVR2_CVAL_INPUT_RADIO] = "radio",
- [PVR2_CVAL_INPUT_SVIDEO] = "s-video",
- [PVR2_CVAL_INPUT_COMPOSITE] = "composite",
- };
- static const char *control_values_audiomode[] = {
- [V4L2_TUNER_MODE_MONO] = "Mono",
- [V4L2_TUNER_MODE_STEREO] = "Stereo",
- [V4L2_TUNER_MODE_LANG1] = "Lang1",
- [V4L2_TUNER_MODE_LANG2] = "Lang2",
- [V4L2_TUNER_MODE_LANG1_LANG2] = "Lang1+Lang2",
- };
- static const char *control_values_hsm[] = {
- [PVR2_CVAL_HSM_FAIL] = "Fail",
- [PVR2_CVAL_HSM_HIGH] = "High",
- [PVR2_CVAL_HSM_FULL] = "Full",
- };
- static const char *pvr2_state_names[] = {
- [PVR2_STATE_NONE] = "none",
- [PVR2_STATE_DEAD] = "dead",
- [PVR2_STATE_COLD] = "cold",
- [PVR2_STATE_WARM] = "warm",
- [PVR2_STATE_ERROR] = "error",
- [PVR2_STATE_READY] = "ready",
- [PVR2_STATE_RUN] = "run",
- };
- struct pvr2_fx2cmd_descdef {
- unsigned char id;
- unsigned char *desc;
- };
- static const struct pvr2_fx2cmd_descdef pvr2_fx2cmd_desc[] = {
- {FX2CMD_MEM_WRITE_DWORD, "write encoder dword"},
- {FX2CMD_MEM_READ_DWORD, "read encoder dword"},
- {FX2CMD_HCW_ZILOG_RESET, "zilog IR reset control"},
- {FX2CMD_MEM_READ_64BYTES, "read encoder 64bytes"},
- {FX2CMD_REG_WRITE, "write encoder register"},
- {FX2CMD_REG_READ, "read encoder register"},
- {FX2CMD_MEMSEL, "encoder memsel"},
- {FX2CMD_I2C_WRITE, "i2c write"},
- {FX2CMD_I2C_READ, "i2c read"},
- {FX2CMD_GET_USB_SPEED, "get USB speed"},
- {FX2CMD_STREAMING_ON, "stream on"},
- {FX2CMD_STREAMING_OFF, "stream off"},
- {FX2CMD_FWPOST1, "fwpost1"},
- {FX2CMD_POWER_OFF, "power off"},
- {FX2CMD_POWER_ON, "power on"},
- {FX2CMD_DEEP_RESET, "deep reset"},
- {FX2CMD_GET_EEPROM_ADDR, "get rom addr"},
- {FX2CMD_GET_IR_CODE, "get IR code"},
- {FX2CMD_HCW_DEMOD_RESETIN, "hcw demod resetin"},
- {FX2CMD_HCW_DTV_STREAMING_ON, "hcw dtv stream on"},
- {FX2CMD_HCW_DTV_STREAMING_OFF, "hcw dtv stream off"},
- {FX2CMD_ONAIR_DTV_STREAMING_ON, "onair dtv stream on"},
- {FX2CMD_ONAIR_DTV_STREAMING_OFF, "onair dtv stream off"},
- {FX2CMD_ONAIR_DTV_POWER_ON, "onair dtv power on"},
- {FX2CMD_ONAIR_DTV_POWER_OFF, "onair dtv power off"},
- };
- static int pvr2_hdw_set_input(struct pvr2_hdw *hdw,int v);
- static void pvr2_hdw_state_sched(struct pvr2_hdw *);
- static int pvr2_hdw_state_eval(struct pvr2_hdw *);
- static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long);
- static void pvr2_hdw_worker_poll(struct work_struct *work);
- static int pvr2_hdw_wait(struct pvr2_hdw *,int state);
- static int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *);
- static void pvr2_hdw_state_log_state(struct pvr2_hdw *);
- static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl);
- static int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw);
- static int pvr2_hdw_get_eeprom_addr(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_quiescent_timeout(unsigned long);
- static void pvr2_hdw_decoder_stabilization_timeout(unsigned long);
- static void pvr2_hdw_encoder_wait_timeout(unsigned long);
- static void pvr2_hdw_encoder_run_timeout(unsigned long);
- static int pvr2_issue_simple_cmd(struct pvr2_hdw *,u32);
- static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
- unsigned int timeout,int probe_fl,
- void *write_data,unsigned int write_len,
- void *read_data,unsigned int read_len);
- static int pvr2_hdw_check_cropcap(struct pvr2_hdw *hdw);
- static void trace_stbit(const char *name,int val)
- {
- pvr2_trace(PVR2_TRACE_STBITS,
- "State bit %s <-- %s",
- name,(val ? "true" : "false"));
- }
- static int ctrl_channelfreq_get(struct pvr2_ctrl *cptr,int *vp)
- {
- struct pvr2_hdw *hdw = cptr->hdw;
- if ((hdw->freqProgSlot > 0) && (hdw->freqProgSlot <= FREQTABLE_SIZE)) {
- *vp = hdw->freqTable[hdw->freqProgSlot-1];
- } else {
- *vp = 0;
- }
- return 0;
- }
- static int ctrl_channelfreq_set(struct pvr2_ctrl *cptr,int m,int v)
- {
- struct pvr2_hdw *hdw = cptr->hdw;
- unsigned int slotId = hdw->freqProgSlot;
- if ((slotId > 0) && (slotId <= FREQTABLE_SIZE)) {
- hdw->freqTable[slotId-1] = v;
- /* Handle side effects correctly - if we're tuned to this
- slot, then forgot the slot id relation since the stored
- frequency has been changed. */
- if (hdw->freqSelector) {
- if (hdw->freqSlotRadio == slotId) {
- hdw->freqSlotRadio = 0;
- }
- } else {
- if (hdw->freqSlotTelevision == slotId) {
- hdw->freqSlotTelevision = 0;
- }
- }
- }
- return 0;
- }
- static int ctrl_channelprog_get(struct pvr2_ctrl *cptr,int *vp)
- {
- *vp = cptr->hdw->freqProgSlot;
- return 0;
- }
- static int ctrl_channelprog_set(struct pvr2_ctrl *cptr,int m,int v)
- {
- struct pvr2_hdw *hdw = cptr->hdw;
- if ((v >= 0) && (v <= FREQTABLE_SIZE)) {
- hdw->freqProgSlot = v;
- }
- return 0;
- }
- static int ctrl_channel_get(struct pvr2_ctrl *cptr,int *vp)
- {
- struct pvr2_hdw *hdw = cptr->hdw;
- *vp = hdw->freqSelector ? hdw->freqSlotRadio : hdw->freqSlotTelevision;
- return 0;
- }
- static int ctrl_channel_set(struct pvr2_ctrl *cptr,int m,int slotId)
- {
- unsigned freq = 0;
- struct pvr2_hdw *hdw = cptr->hdw;
- if ((slotId < 0) || (slotId > FREQTABLE_SIZE)) return 0;
- if (slotId > 0) {
- freq = hdw->freqTable[slotId-1];
- if (!freq) return 0;
- pvr2_hdw_set_cur_freq(hdw,freq);
- }
- if (hdw->freqSelector) {
- hdw->freqSlotRadio = slotId;
- } else {
- hdw->freqSlotTelevision = slotId;
- }
- return 0;
- }
- static int ctrl_freq_get(struct pvr2_ctrl *cptr,int *vp)
- {
- *vp = pvr2_hdw_get_cur_freq(cptr->hdw);
- return 0;
- }
- static int ctrl_freq_is_dirty(struct pvr2_ctrl *cptr)
- {
- return cptr->hdw->freqDirty != 0;
- }
- static void ctrl_freq_clear_dirty(struct pvr2_ctrl *cptr)
- {
- cptr->hdw->freqDirty = 0;
- }
- static int ctrl_freq_set(struct pvr2_ctrl *cptr,int m,int v)
- {
- pvr2_hdw_set_cur_freq(cptr->hdw,v);
- return 0;
- }
- static int ctrl_cropl_min_get(struct pvr2_ctrl *cptr, int *left)
- {
- struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
- int stat = pvr2_hdw_check_cropcap(cptr->hdw);
- if (stat != 0) {
- return stat;
- }
- *left = cap->bounds.left;
- return 0;
- }
- static int ctrl_cropl_max_get(struct pvr2_ctrl *cptr, int *left)
- {
- struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
- int stat = pvr2_hdw_check_cropcap(cptr->hdw);
- if (stat != 0) {
- return stat;
- }
- *left = cap->bounds.left;
- if (cap->bounds.width > cptr->hdw->cropw_val) {
- *left += cap->bounds.width - cptr->hdw->cropw_val;
- }
- return 0;
- }
- static int ctrl_cropt_min_get(struct pvr2_ctrl *cptr, int *top)
- {
- struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
- int stat = pvr2_hdw_check_cropcap(cptr->hdw);
- if (stat != 0) {
- return stat;
- }
- *top = cap->bounds.top;
- return 0;
- }
- static int ctrl_cropt_max_get(struct pvr2_ctrl *cptr, int *top)
- {
- struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
- int stat = pvr2_hdw_check_cropcap(cptr->hdw);
- if (stat != 0) {
- return stat;
- }
- *top = cap->bounds.top;
- if (cap->bounds.height > cptr->hdw->croph_val) {
- *top += cap->bounds.height - cptr->hdw->croph_val;
- }
- return 0;
- }
- static int ctrl_cropw_max_get(struct pvr2_ctrl *cptr, int *width)
- {
- struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
- int stat, bleftend, cleft;
- stat = pvr2_hdw_check_cropcap(cptr->hdw);
- if (stat != 0) {
- return stat;
- }
- bleftend = cap->bounds.left+cap->bounds.width;
- cleft = cptr->hdw->cropl_val;
- *width = cleft < bleftend ? bleftend-cleft : 0;
- return 0;
- }
- static int ctrl_croph_max_get(struct pvr2_ctrl *cptr, int *height)
- {
- struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
- int stat, btopend, ctop;
- stat = pvr2_hdw_check_cropcap(cptr->hdw);
- if (stat != 0) {
- return stat;
- }
- btopend = cap->bounds.top+cap->bounds.height;
- ctop = cptr->hdw->cropt_val;
- *height = ctop < btopend ? btopend-ctop : 0;
- return 0;
- }
- static int ctrl_get_cropcapbl(struct pvr2_ctrl *cptr, int *val)
- {
- struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
- int stat = pvr2_hdw_check_cropcap(cptr->hdw);
- if (stat != 0) {
- return stat;
- }
- *val = cap->bounds.left;
- return 0;
- }
- static int ctrl_get_cropcapbt(struct pvr2_ctrl *cptr, int *val)
- {
- struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
- int stat = pvr2_hdw_check_cropcap(cptr->hdw);
- if (stat != 0) {
- return stat;
- }
- *val = cap->bounds.top;
- return 0;
- }
- static int ctrl_get_cropcapbw(struct pvr2_ctrl *cptr, int *val)
- {
- struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
- int stat = pvr2_hdw_check_cropcap(cptr->hdw);
- if (stat != 0) {
- return stat;
- }
- *val = cap->bounds.width;
- return 0;
- }
- static int ctrl_get_cropcapbh(struct pvr2_ctrl *cptr, int *val)
- {
- struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
- int stat = pvr2_hdw_check_cropcap(cptr->hdw);
- if (stat != 0) {
- return stat;
- }
- *val = cap->bounds.height;
- return 0;
- }
- static int ctrl_get_cropcapdl(struct pvr2_ctrl *cptr, int *val)
- {
- struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
- int stat = pvr2_hdw_check_cropcap(cptr->hdw);
- if (stat != 0) {
- return stat;
- }
- *val = cap->defrect.left;
- return 0;
- }
- static int ctrl_get_cropcapdt(struct pvr2_ctrl *cptr, int *val)
- {
- struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
- int stat = pvr2_hdw_check_cropcap(cptr->hdw);
- if (stat != 0) {
- return stat;
- }
- *val = cap->defrect.top;
- return 0;
- }
- static int ctrl_get_cropcapdw(struct pvr2_ctrl *cptr, int *val)
- {
- struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
- int stat = pvr2_hdw_check_cropcap(cptr->hdw);
- if (stat != 0) {
- return stat;
- }
- *val = cap->defrect.width;
- return 0;
- }
- static int ctrl_get_cropcapdh(struct pvr2_ctrl *cptr, int *val)
- {
- struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
- int stat = pvr2_hdw_check_cropcap(cptr->hdw);
- if (stat != 0) {
- return stat;
- }
- *val = cap->defrect.height;
- return 0;
- }
- static int ctrl_get_cropcappan(struct pvr2_ctrl *cptr, int *val)
- {
- struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
- int stat = pvr2_hdw_check_cropcap(cptr->hdw);
- if (stat != 0) {
- return stat;
- }
- *val = cap->pixelaspect.numerator;
- return 0;
- }
- static int ctrl_get_cropcappad(struct pvr2_ctrl *cptr, int *val)
- {
- struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
- int stat = pvr2_hdw_check_cropcap(cptr->hdw);
- if (stat != 0) {
- return stat;
- }
- *val = cap->pixelaspect.denominator;
- return 0;
- }
- static int ctrl_vres_max_get(struct pvr2_ctrl *cptr,int *vp)
- {
- /* Actual maximum depends on the video standard in effect. */
- if (cptr->hdw->std_mask_cur & V4L2_STD_525_60) {
- *vp = 480;
- } else {
- *vp = 576;
- }
- return 0;
- }
- static int ctrl_vres_min_get(struct pvr2_ctrl *cptr,int *vp)
- {
- /* Actual minimum depends on device digitizer type. */
- if (cptr->hdw->hdw_desc->flag_has_cx25840) {
- *vp = 75;
- } else {
- *vp = 17;
- }
- return 0;
- }
- static int ctrl_get_input(struct pvr2_ctrl *cptr,int *vp)
- {
- *vp = cptr->hdw->input_val;
- return 0;
- }
- static int ctrl_check_input(struct pvr2_ctrl *cptr,int v)
- {
- return ((1 << v) & cptr->hdw->input_allowed_mask) != 0;
- }
- static int ctrl_set_input(struct pvr2_ctrl *cptr,int m,int v)
- {
- return pvr2_hdw_set_input(cptr->hdw,v);
- }
- static int ctrl_isdirty_input(struct pvr2_ctrl *cptr)
- {
- return cptr->hdw->input_dirty != 0;
- }
- static void ctrl_cleardirty_input(struct pvr2_ctrl *cptr)
- {
- cptr->hdw->input_dirty = 0;
- }
- static int ctrl_freq_max_get(struct pvr2_ctrl *cptr, int *vp)
- {
- unsigned long fv;
- struct pvr2_hdw *hdw = cptr->hdw;
- if (hdw->tuner_signal_stale) {
- pvr2_hdw_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)
- {
- unsigned long fv;
- struct pvr2_hdw *hdw = cptr->hdw;
- if (hdw->tuner_signal_stale) {
- pvr2_hdw_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;
- }
- static int ctrl_cx2341x_is_dirty(struct pvr2_ctrl *cptr)
- {
- return cptr->hdw->enc_stale != 0;
- }
- static void ctrl_cx2341x_clear_dirty(struct pvr2_ctrl *cptr)
- {
- cptr->hdw->enc_stale = 0;
- cptr->hdw->enc_unsafe_stale = 0;
- }
- static int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp)
- {
- int ret;
- struct v4l2_ext_controls cs;
- struct v4l2_ext_control c1;
- memset(&cs,0,sizeof(cs));
- memset(&c1,0,sizeof(c1));
- cs.controls = &c1;
- cs.count = 1;
- c1.id = cptr->info->v4l_id;
- ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state, 0, &cs,
- VIDIOC_G_EXT_CTRLS);
- if (ret) return ret;
- *vp = c1.value;
- return 0;
- }
- static int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v)
- {
- int ret;
- struct pvr2_hdw *hdw = cptr->hdw;
- struct v4l2_ext_controls cs;
- struct v4l2_ext_control c1;
- memset(&cs,0,sizeof(cs));
- memset(&c1,0,sizeof(c1));
- cs.controls = &c1;
- cs.count = 1;
- c1.id = cptr->info->v4l_id;
- c1.value = v;
- ret = cx2341x_ext_ctrls(&hdw->enc_ctl_state,
- hdw->state_encoder_run, &cs,
- VIDIOC_S_EXT_CTRLS);
- if (ret == -EBUSY) {
- /* Oops. cx2341x is telling us it's not safe to change
- this control while we're capturing. Make a note of this
- fact so that the pipeline will be stopped the next time
- controls are committed. Then go on ahead and store this
- change anyway. */
- ret = cx2341x_ext_ctrls(&hdw->enc_ctl_state,
- 0, &cs,
- VIDIOC_S_EXT_CTRLS);
- if (!ret) hdw->enc_unsafe_stale = !0;
- }
- if (ret) return ret;
- hdw->enc_stale = !0;
- return 0;
- }
- static unsigned int ctrl_cx2341x_getv4lflags(struct pvr2_ctrl *cptr)
- {
- struct v4l2_queryctrl qctrl;
- struct pvr2_ctl_info *info;
- qctrl.id = cptr->info->v4l_id;
- cx2341x_ctrl_query(&cptr->hdw->enc_ctl_state,&qctrl);
- /* Strip out the const so we can adjust a function pointer. It's
- OK to do this here because we know this is a dynamically created
- control, so the underlying storage for the info pointer is (a)
- private to us, and (b) not in read-only storage. Either we do
- this or we significantly complicate the underlying control
- implementation. */
- info = (struct pvr2_ctl_info *)(cptr->info);
- if (qctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) {
- if (info->set_value) {
- info->set_value = NULL;
- }
- } else {
- if (!(info->set_value)) {
- info->set_value = ctrl_cx2341x_set;
- }
- }
- return qctrl.flags;
- }
- static int ctrl_streamingenabled_get(struct pvr2_ctrl *cptr,int *vp)
- {
- *vp = cptr->hdw->state_pipeline_req;
- return 0;
- }
- static int ctrl_masterstate_get(struct pvr2_ctrl *cptr,int *vp)
- {
- *vp = cptr->hdw->master_state;
- return 0;
- }
- static int ctrl_hsm_get(struct pvr2_ctrl *cptr,int *vp)
- {
- int result = pvr2_hdw_is_hsm(cptr->hdw);
- *vp = PVR2_CVAL_HSM_FULL;
- if (result < 0) *vp = PVR2_CVAL_HSM_FAIL;
- if (result) *vp = PVR2_CVAL_HSM_HIGH;
- return 0;
- }
- static int ctrl_stdavail_get(struct pvr2_ctrl *cptr,int *vp)
- {
- *vp = cptr->hdw->std_mask_avail;
- return 0;
- }
- static int ctrl_stdavail_set(struct pvr2_ctrl *cptr,int m,int v)
- {
- struct pvr2_hdw *hdw = cptr->hdw;
- v4l2_std_id ns;
- ns = hdw->std_mask_avail;
- ns = (ns & ~m) | (v & m);
- if (ns == hdw->std_mask_avail) return 0;
- hdw->std_mask_avail = ns;
- pvr2_hdw_internal_set_std_avail(hdw);
- pvr2_hdw_internal_find_stdenum(hdw);
- return 0;
- }
- static int ctrl_std_val_to_sym(struct pvr2_ctrl *cptr,int msk,int val,
- char *bufPtr,unsigned int bufSize,
- unsigned int *len)
- {
- *len = pvr2_std_id_to_str(bufPtr,bufSize,msk & val);
- return 0;
- }
- static int ctrl_std_sym_to_val(struct pvr2_ctrl *cptr,
- const char *bufPtr,unsigned int bufSize,
- int *mskp,int *valp)
- {
- int ret;
- v4l2_std_id id;
- ret = pvr2_std_str_to_id(&id,bufPtr,bufSize);
- if (ret < 0) return ret;
- if (mskp) *mskp = id;
- if (valp) *valp = id;
- return 0;
- }
- static int ctrl_stdcur_get(struct pvr2_ctrl *cptr,int *vp)
- {
- *vp = cptr->hdw->std_mask_cur;
- return 0;
- }
- static int ctrl_stdcur_set(struct pvr2_ctrl *cptr,int m,int v)
- {
- struct pvr2_hdw *hdw = cptr->hdw;
- v4l2_std_id ns;
- ns = hdw->std_mask_cur;
- ns = (ns & ~m) | (v & m);
- if (ns == hdw->std_mask_cur) return 0;
- hdw->std_mask_cur = ns;
- hdw->std_dirty = !0;
- pvr2_hdw_internal_find_stdenum(hdw);
- return 0;
- }
- static int ctrl_stdcur_is_dirty(struct pvr2_ctrl *cptr)
- {
- return cptr->hdw->std_dirty != 0;
- }
- static void ctrl_stdcur_clear_dirty(struct pvr2_ctrl *cptr)
- {
- cptr->hdw->std_dirty = 0;
- }
- static int ctrl_signal_get(struct pvr2_ctrl *cptr,int *vp)
- {
- struct pvr2_hdw *hdw = cptr->hdw;
- pvr2_hdw_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_hdw_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;
- }
- static int ctrl_stdenumcur_set(struct pvr2_ctrl *cptr,int m,int v)
- {
- struct pvr2_hdw *hdw = cptr->hdw;
- if (v < 0) return -EINVAL;
- if (v > hdw->std_enum_cnt) return -EINVAL;
- hdw->std_enum_cur = v;
- if (!v) return 0;
- v--;
- if (hdw->std_mask_cur == hdw->std_defs[v].id) return 0;
- hdw->std_mask_cur = hdw->std_defs[v].id;
- hdw->std_dirty = !0;
- return 0;
- }
- static int ctrl_stdenumcur_get(struct pvr2_ctrl *cptr,int *vp)
- {
- *vp = cptr->hdw->std_enum_cur;
- return 0;
- }
- static int ctrl_stdenumcur_is_dirty(struct pvr2_ctrl *cptr)
- {
- return cptr->hdw->std_dirty != 0;
- }
- static void ctrl_stdenumcur_clear_dirty(struct pvr2_ctrl *cptr)
- {
- cptr->hdw->std_dirty = 0;
- }
- #define DEFINT(vmin,vmax) \
- .type = pvr2_ctl_int, \
- .def.type_int.min_value = vmin, \
- .def.type_int.max_value = vmax
- #define DEFENUM(tab) \
- .type = pvr2_ctl_enum, \
- .def.type_enum.count = ARRAY_SIZE(tab), \
- .def.type_enum.value_names = tab
- #define DEFBOOL \
- .type = pvr2_ctl_bool
- #define DEFMASK(msk,tab) \
- .type = pvr2_ctl_bitmask, \
- .def.type_bitmask.valid_bits = msk, \
- .def.type_bitmask.bit_names = tab
- #define DEFREF(vname) \
- .set_value = ctrl_set_##vname, \
- .get_value = ctrl_get_##vname, \
- .is_dirty = ctrl_isdirty_##vname, \
- .clear_dirty = ctrl_cleardirty_##vname
- #define VCREATE_FUNCS(vname) \
- static int ctrl_get_##vname(struct pvr2_ctrl *cptr,int *vp) \
- {*vp = cptr->hdw->vname##_val; return 0;} \
- static int ctrl_set_##vname(struct pvr2_ctrl *cptr,int m,int v) \
- {cptr->hdw->vname##_val = v; cptr->hdw->vname##_dirty = !0; return 0;} \
- static int ctrl_isdirty_##vname(struct pvr2_ctrl *cptr) \
- {return cptr->hdw->vname##_dirty != 0;} \
- static void ctrl_cleardirty_##vname(struct pvr2_ctrl *cptr) \
- {cptr->hdw->vname##_dirty = 0;}
- VCREATE_FUNCS(brightness)
- VCREATE_FUNCS(contrast)
- VCREATE_FUNCS(saturation)
- VCREATE_FUNCS(hue)
- VCREATE_FUNCS(volume)
- VCREATE_FUNCS(balance)
- VCREATE_FUNCS(bass)
- VCREATE_FUNCS(treble)
- VCREATE_FUNCS(mute)
- VCREATE_FUNCS(cropl)
- VCREATE_FUNCS(cropt)
- VCREATE_FUNCS(cropw)
- VCREATE_FUNCS(croph)
- VCREATE_FUNCS(audiomode)
- VCREATE_FUNCS(res_hor)
- VCREATE_FUNCS(res_ver)
- VCREATE_FUNCS(srate)
- /* Table definition of all controls which can be manipulated */
- static const struct pvr2_ctl_info control_defs[] = {
- {
- .v4l_id = V4L2_CID_BRIGHTNESS,
- .desc = "Brightness",
- .name = "brightness",
- .default_value = 128,
- DEFREF(brightness),
- DEFINT(0,255),
- },{
- .v4l_id = V4L2_CID_CONTRAST,
- .desc = "Contrast",
- .name = "contrast",
- .default_value = 68,
- DEFREF(contrast),
- DEFINT(0,127),
- },{
- .v4l_id = V4L2_CID_SATURATION,
- .desc = "Saturation",
- .name = "saturation",
- .default_value = 64,
- DEFREF(saturation),
- DEFINT(0,127),
- },{
- .v4l_id = V4L2_CID_HUE,
- .desc = "Hue",
- .name = "hue",
- .default_value = 0,
- DEFREF(hue),
- DEFINT(-128,127),
- },{
- .v4l_id = V4L2_CID_AUDIO_VOLUME,
- .desc = "Volume",
- .name = "volume",
- .default_value = 62000,
- DEFREF(volume),
- DEFINT(0,65535),
- },{
- .v4l_id = V4L2_CID_AUDIO_BALANCE,
- .desc = "Balance",
- .name = "balance",
- .default_value = 0,
- DEFREF(balance),
- DEFINT(-32768,32767),
- },{
- .v4l_id = V4L2_CID_AUDIO_BASS,
- .desc = "Bass",
- .name = "bass",
- .default_value = 0,
- DEFREF(bass),
- DEFINT(-32768,32767),
- },{
- .v4l_id = V4L2_CID_AUDIO_TREBLE,
- .desc = "Treble",
- .name = "treble",
- .default_value = 0,
- DEFREF(treble),
- DEFINT(-32768,32767),
- },{
- .v4l_id = V4L2_CID_AUDIO_MUTE,
- .desc = "Mute",
- .name = "mute",
- .default_value = 0,
- DEFREF(mute),
- DEFBOOL,
- }, {
- .desc = "Capture crop left margin",
- .name = "crop_left",
- .internal_id = PVR2_CID_CROPL,
- .default_value = 0,
- DEFREF(cropl),
- DEFINT(-129, 340),
- .get_min_value = ctrl_cropl_min_get,
- .get_max_value = ctrl_cropl_max_get,
- .get_def_value = ctrl_get_cropcapdl,
- }, {
- .desc = "Capture crop top margin",
- .name = "crop_top",
- .internal_id = PVR2_CID_CROPT,
- .default_value = 0,
- DEFREF(cropt),
- DEFINT(-35, 544),
- .get_min_value = ctrl_cropt_min_get,
- .get_max_value = ctrl_cropt_max_get,
- .get_def_value = ctrl_get_cropcapdt,
- }, {
- .desc = "Capture crop width",
- .name = "crop_width",
- .internal_id = PVR2_CID_CROPW,
- .default_value = 720,
- DEFREF(cropw),
- DEFINT(0, 864),
- .get_max_value = ctrl_cropw_max_get,
- .get_def_value = ctrl_get_cropcapdw,
- }, {
- .desc = "Capture crop height",
- .name = "crop_height",
- .internal_id = PVR2_CID_CROPH,
- .default_value = 480,
- DEFREF(croph),
- DEFINT(0, 576),
- .get_max_value = ctrl_croph_max_get,
- .get_def_value = ctrl_get_cropcapdh,
- }, {
- .desc = "Capture capability pixel aspect numerator",
- .name = "cropcap_pixel_numerator",
- .internal_id = PVR2_CID_CROPCAPPAN,
- .get_value = ctrl_get_cropcappan,
- }, {
- .desc = "Capture capability pixel aspect denominator",
- .name = "cropcap_pixel_denominator",
- .internal_id = PVR2_CID_CROPCAPPAD,
- .get_value = ctrl_get_cropcappad,
- }, {
- .desc = "Capture capability bounds top",
- .name = "cropcap_bounds_top",
- .internal_id = PVR2_CID_CROPCAPBT,
- .get_value = ctrl_get_cropcapbt,
- }, {
- .desc = "Capture capability bounds left",
- .name = "cropcap_bounds_left",
- .internal_id = PVR2_CID_CROPCAPBL,
- .get_value = ctrl_get_cropcapbl,
- }, {
- .desc = "Capture capability bounds width",
- .name = "cropcap_bounds_width",
- .internal_id = PVR2_CID_CROPCAPBW,
- .get_value = ctrl_get_cropcapbw,
- }, {
- .desc = "Capture capability bounds height",
- .name = "cropcap_bounds_height",
- .internal_id = PVR2_CID_CROPCAPBH,
- .get_value = ctrl_get_cropcapbh,
- },{
- .desc = "Video Source",
- .name = "input",
- .internal_id = PVR2_CID_INPUT,
- .default_value = PVR2_CVAL_INPUT_TV,
- .check_value = ctrl_check_input,
- DEFREF(input),
- DEFENUM(control_values_input),
- },{
- .desc = "Audio Mode",
- .name = "audio_mode",
- .internal_id = PVR2_CID_AUDIOMODE,
- .default_value = V4L2_TUNER_MODE_STEREO,
- DEFREF(audiomode),
- DEFENUM(control_values_audiomode),
- },{
- .desc = "Horizontal capture resolution",
- .name = "resolution_hor",
- .internal_id = PVR2_CID_HRES,
- .default_value = 720,
- DEFREF(res_hor),
- DEFINT(19,720),
- },{
- .desc = "Vertical capture resolution",
- .name = "resolution_ver",
- .internal_id = PVR2_CID_VRES,
- .default_value = 480,
- DEFREF(res_ver),
- DEFINT(17,576),
- /* Hook in check for video standard and adjust maximum
- depending on the standard. */
- .get_max_value = ctrl_vres_max_get,
- .get_min_value = ctrl_vres_min_get,
- },{
- .v4l_id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
- .default_value = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
- .desc = "Audio Sampling Frequency",
- .name = "srate",
- DEFREF(srate),
- DEFENUM(control_values_srate),
- },{
- .desc = "Tuner Frequency (Hz)",
- .name = "frequency",
- .internal_id = PVR2_CID_FREQUENCY,
- .default_value = 0,
- .set_value = ctrl_freq_set,
- .get_value = ctrl_freq_get,
- .is_dirty = ctrl_freq_is_dirty,
- .clear_dirty = ctrl_freq_clear_dirty,
- DEFINT(0,0),
- /* Hook in check for input value (tv/radio) and adjust
- max/min values accordingly */
- .get_max_value = ctrl_freq_max_get,
- .get_min_value = ctrl_freq_min_get,
- },{
- .desc = "Channel",
- .name = "channel",
- .set_value = ctrl_channel_set,
- .get_value = ctrl_channel_get,
- DEFINT(0,FREQTABLE_SIZE),
- },{
- .desc = "Channel Program Frequency",
- .name = "freq_table_value",
- .set_value = ctrl_channelfreq_set,
- .get_value = ctrl_channelfreq_get,
- DEFINT(0,0),
- /* Hook in check for input value (tv/radio) and adjust
- max/min values accordingly */
- .get_max_value = ctrl_freq_max_get,
- .get_min_value = ctrl_freq_min_get,
- },{
- .desc = "Channel Program ID",
- .name = "freq_table_channel",
- .set_value = ctrl_channelprog_set,
- .get_value = ctrl_channelprog_get,
- DEFINT(0,FREQTABLE_SIZE),
- },{
- .desc = "Streaming Enabled",
- .name = "streaming_enabled",
- .get_value = ctrl_streamingenabled_get,
- DEFBOOL,
- },{
- .desc = "USB Speed",
- .name = "usb_speed",
- .get_value = ctrl_hsm_get,
- DEFENUM(control_values_hsm),
- },{
- .desc = "Master State",
- .name = "master_state",
- .get_value = ctrl_masterstate_get,
- DEFENUM(pvr2_state_names),
- },{
- .desc = "Signal Present",
- .name = "signal_present",
- .get_value = ctrl_signal_get,
- 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",
- .internal_id = PVR2_CID_STDAVAIL,
- .skip_init = !0,
- .get_value = ctrl_stdavail_get,
- .set_value = ctrl_stdavail_set,
- .val_to_sym = ctrl_std_val_to_sym,
- .sym_to_val = ctrl_std_sym_to_val,
- .type = pvr2_ctl_bitmask,
- },{
- .desc = "Video Standards In Use Mask",
- .name = "video_standard_mask_active",
- .internal_id = PVR2_CID_STDCUR,
- .skip_init = !0,
- .get_value = ctrl_stdcur_get,
- .set_value = ctrl_stdcur_set,
- .is_dirty = ctrl_stdcur_is_dirty,
- .clear_dirty = ctrl_stdcur_clear_dirty,
- .val_to_sym = ctrl_std_val_to_sym,
- .sym_to_val = ctrl_std_sym_to_val,
- .type = pvr2_ctl_bitmask,
- },{
- .desc = "Video Standard Name",
- .name = "video_standard",
- .internal_id = PVR2_CID_STDENUM,
- .skip_init = !0,
- .get_value = ctrl_stdenumcur_get,
- .set_value = ctrl_stdenumcur_set,
- .is_dirty = ctrl_stdenumcur_is_dirty,
- .clear_dirty = ctrl_stdenumcur_clear_dirty,
- .type = pvr2_ctl_enum,
- }
- };
- #define CTRLDEF_COUNT ARRAY_SIZE(control_defs)
- const char *pvr2_config_get_name(enum pvr2_config cfg)
- {
- switch (cfg) {
- case pvr2_config_empty: return "empty";
- case pvr2_config_mpeg: return "mpeg";
- case pvr2_config_vbi: return "vbi";
- case pvr2_config_pcm: return "pcm";
- case pvr2_config_rawvideo: return "raw video";
- }
- return "<unknown>";
- }
- struct usb_device *pvr2_hdw_get_dev(struct pvr2_hdw *hdw)
- {
- return hdw->usb_dev;
- }
- unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *hdw)
- {
- return hdw->serial_number;
- }
- const char *pvr2_hdw_get_bus_info(struct pvr2_hdw *hdw)
- {
- return hdw->bus_info;
- }
- const char *pvr2_hdw_get_device_identifier(struct pvr2_hdw *hdw)
- {
- return hdw->identifier;
- }
- unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *hdw)
- {
- return hdw->freqSelector ? hdw->freqValTelevision : hdw->freqValRadio;
- }
- /* Set the currently tuned frequency and account for all possible
- driver-core side effects of this action. */
- static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *hdw,unsigned long val)
- {
- 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->freqValRadio != val) {
- hdw->freqValRadio = val;
- hdw->freqSlotRadio = 0;
- hdw->freqDirty = !0;
- }
- } else {
- if (!(hdw->freqSelector)) {
- /* Swing over to television frequency selection */
- hdw->freqSelector = 1;
- hdw->freqDirty = !0;
- }
- if (hdw->freqValTelevision != val) {
- hdw->freqValTelevision = val;
- hdw->freqSlotTelevision = 0;
- hdw->freqDirty = !0;
- }
- }
- }
- int pvr2_hdw_get_unit_number(struct pvr2_hdw *hdw)
- {
- return hdw->unit_number;
- }
- /* Attempt to locate one of the given set of files. Messages are logged
- appropriate to what has been found. The return value will be 0 or
- greater on success (it will be the index of the file name found) and
- fw_entry will be filled in. Otherwise a negative error is returned on
- failure. If the return value is -ENOENT then no viable firmware file
- could be located. */
- static int pvr2_locate_firmware(struct pvr2_hdw *hdw,
- const struct firmware **fw_entry,
- const char *fwtypename,
- unsigned int fwcount,
- const char *fwnames[])
- {
- unsigned int idx;
- int ret = -EINVAL;
- for (idx = 0; idx < fwcount; idx++) {
- ret = request_firmware(fw_entry,
- fwnames[idx],
- &hdw->usb_dev->dev);
- if (!ret) {
- trace_firmware("Located %s firmware: %s;"
- " uploading...",
- fwtypename,
- fwnames[idx]);
- return idx;
- }
- if (ret == -ENOENT) continue;
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "request_firmware fatal error with code=%d",ret);
- return ret;
- }
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "***WARNING***"
- " Device %s firmware"
- " seems to be missing.",
- fwtypename);
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "Did you install the pvrusb2 firmware files"
- " in their proper location?");
- if (fwcount == 1) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "request_firmware unable to locate %s file %s",
- fwtypename,fwnames[0]);
- } else {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "request_firmware unable to locate"
- " one of the following %s files:",
- fwtypename);
- for (idx = 0; idx < fwcount; idx++) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "request_firmware: Failed to find %s",
- fwnames[idx]);
- }
- }
- return ret;
- }
- /*
- * pvr2_upload_firmware1().
- *
- * Send the 8051 firmware to the device. After the upload, arrange for
- * device to re-enumerate.
- *
- * NOTE : the pointer to the firmware data given by request_firmware()
- * is not suitable for an usb transaction.
- *
- */
- static int pvr2_upload_firmware1(struct pvr2_hdw *hdw)
- {
- const struct firmware *fw_entry = NULL;
- void *fw_ptr;
- unsigned int pipe;
- unsigned int fwsize;
- int ret;
- u16 address;
- if (!hdw->hdw_desc->fx2_firmware.cnt) {
- hdw->fw1_state = FW1_STATE_OK;
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "Connected device type defines"
- " no firmware to upload; ignoring firmware");
- return -ENOTTY;
- }
- hdw->fw1_state = FW1_STATE_FAILED; // default result
- trace_firmware("pvr2_upload_firmware1");
- ret = pvr2_locate_firmware(hdw,&fw_entry,"fx2 controller",
- hdw->hdw_desc->fx2_firmware.cnt,
- hdw->hdw_desc->fx2_firmware.lst);
- if (ret < 0) {
- if (ret == -ENOENT) hdw->fw1_state = FW1_STATE_MISSING;
- return ret;
- }
- usb_clear_halt(hdw->usb_dev, usb_sndbulkpipe(hdw->usb_dev, 0 & 0x7f));
- pipe = usb_sndctrlpipe(hdw->usb_dev, 0);
- fwsize = fw_entry->size;
- if ((fwsize != 0x2000) &&
- (!(hdw->hdw_desc->flag_fx2_16kb && (fwsize == 0x4000)))) {
- if (hdw->hdw_desc->flag_fx2_16kb) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "Wrong fx2 firmware size"
- " (expected 8192 or 16384, got %u)",
- fwsize);
- } else {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "Wrong fx2 firmware size"
- " (expected 8192, got %u)",
- fwsize);
- }
- release_firmware(fw_entry);
- return -ENOMEM;
- }
- fw_ptr = kmalloc(0x800, GFP_KERNEL);
- if (fw_ptr == NULL){
- release_firmware(fw_entry);
- return -ENOMEM;
- }
- /* We have to hold the CPU during firmware upload. */
- pvr2_hdw_cpureset_assert(hdw,1);
- /* upload the firmware to address 0000-1fff in 2048 (=0x800) bytes
- chunk. */
- ret = 0;
- for (address = 0; address < fwsize; address += 0x800) {
- memcpy(fw_ptr, fw_entry->data + address, 0x800);
- ret += usb_control_msg(hdw->usb_dev, pipe, 0xa0, 0x40, address,
- 0, fw_ptr, 0x800, HZ);
- }
- trace_firmware("Upload done, releasing device's CPU");
- /* Now release the CPU. It will disconnect and reconnect later. */
- pvr2_hdw_cpureset_assert(hdw,0);
- kfree(fw_ptr);
- release_firmware(fw_entry);
- trace_firmware("Upload done (%d bytes sent)",ret);
- /* We should have written fwsize bytes */
- if (ret == fwsize) {
- hdw->fw1_state = FW1_STATE_RELOAD;
- return 0;
- }
- return -EIO;
- }
- /*
- * pvr2_upload_firmware2()
- *
- * This uploads encoder firmware on endpoint 2.
- *
- */
- int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
- {
- const struct firmware *fw_entry = NULL;
- void *fw_ptr;
- unsigned int pipe, fw_len, fw_done, bcnt, icnt;
- int actual_length;
- int ret = 0;
- int fwidx;
- static const char *fw_files[] = {
- CX2341X_FIRM_ENC_FILENAME,
- };
- if (hdw->hdw_desc->flag_skip_cx23416_firmware) {
- return 0;
- }
- trace_firmware("pvr2_upload_firmware2");
- ret = pvr2_locate_firmware(hdw,&fw_entry,"encoder",
- ARRAY_SIZE(fw_files), fw_files);
- if (ret < 0) return ret;
- fwidx = ret;
- ret = 0;
- /* Since we're about to completely reinitialize the encoder,
- invalidate our cached copy of its configuration state. Next
- time we configure the encoder, then we'll fully configure it. */
- hdw->enc_cur_valid = 0;
- /* Encoder is about to be reset so note that as far as we're
- concerned now, the encoder has never been run. */
- del_timer_sync(&hdw->encoder_run_timer);
- if (hdw->state_encoder_runok) {
- hdw->state_encoder_runok = 0;
- trace_stbit("state_encoder_runok",hdw->state_encoder_runok);
- }
- /* First prepare firmware loading */
- ret |= pvr2_write_register(hdw, 0x0048, 0xffffffff); /*interrupt mask*/
- ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000088); /*gpio dir*/
- ret |= pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000008); /*gpio output state*/
- ret |= pvr2_hdw_cmd_deep_reset(hdw);
- ret |= pvr2_write_register(hdw, 0xa064, 0x00000000); /*APU command*/
- ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000408); /*gpio dir*/
- ret |= pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000008); /*gpio output state*/
- ret |= pvr2_write_register(hdw, 0x9058, 0xffffffed); /*VPU ctrl*/
- ret |= pvr2_write_register(hdw, 0x9054, 0xfffffffd); /*reset hw blocks*/
- ret |= pvr2_write_register(hdw, 0x07f8, 0x80000800); /*encoder SDRAM refresh*/
- ret |= pvr2_write_register(hdw, 0x07fc, 0x0000001a); /*encoder SDRAM pre-charge*/
- ret |= pvr2_write_register(hdw, 0x0700, 0x00000000); /*I2C clock*/
- ret |= pvr2_write_register(hdw, 0xaa00, 0x00000000); /*unknown*/
- ret |= pvr2_write_register(hdw, 0xaa04, 0x00057810); /*unknown*/
- ret |= pvr2_write_register(hdw, 0xaa10, 0x00148500); /*unknown*/
- ret |= pvr2_write_register(hdw, 0xaa18, 0x00840000); /*unknown*/
- ret |= pvr2_issue_simple_cmd(hdw,FX2CMD_FWPOST1);
- ret |= pvr2_issue_simple_cmd(hdw,FX2CMD_MEMSEL | (1 << 8) | (0 << 16));
- if (ret) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "firmware2 upload prep failed, ret=%d",ret);
- release_firmware(fw_entry);
- goto done;
- }
- /* Now send firmware */
- fw_len = fw_entry->size;
- if (fw_len % sizeof(u32)) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "size of %s firmware"
- " must be a multiple of %zu bytes",
- fw_files[fwidx],sizeof(u32));
- release_firmware(fw_entry);
- ret = -EINVAL;
- goto done;
- }
- fw_ptr = kmalloc(FIRMWARE_CHUNK_SIZE, GFP_KERNEL);
- if (fw_ptr == NULL){
- release_firmware(fw_entry);
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "failed to allocate memory for firmware2 upload");
- ret = -ENOMEM;
- goto done;
- }
- pipe = usb_sndbulkpipe(hdw->usb_dev, PVR2_FIRMWARE_ENDPOINT);
- fw_done = 0;
- for (fw_done = 0; fw_done < fw_len;) {
- bcnt = fw_len - fw_done;
- if (bcnt > FIRMWARE_CHUNK_SIZE) bcnt = FIRMWARE_CHUNK_SIZE;
- memcpy(fw_ptr, fw_entry->data + fw_done, bcnt);
- /* Usbsnoop log shows that we must swap bytes... */
- /* Some background info: The data being swapped here is a
- firmware image destined for the mpeg encoder chip that
- lives at the other end of a USB endpoint. The encoder
- chip always talks in 32 bit chunks and its storage is
- organized into 32 bit words. However from the file
- system to the encoder chip everything is purely a byte
- stream. The firmware file's contents are always 32 bit
- swapped from what the encoder expects. Thus the need
- always exists to swap the bytes regardless of the endian
- type of the host processor and therefore swab32() makes
- the most sense. */
- for (icnt = 0; icnt < bcnt/4 ; icnt++)
- ((u32 *)fw_ptr)[icnt] = swab32(((u32 *)fw_ptr)[icnt]);
- ret |= usb_bulk_msg(hdw->usb_dev, pipe, fw_ptr,bcnt,
- &actual_length, HZ);
- ret |= (actual_length != bcnt);
- if (ret) break;
- fw_done += bcnt;
- }
- trace_firmware("upload of %s : %i / %i ",
- fw_files[fwidx],fw_done,fw_len);
- kfree(fw_ptr);
- release_firmware(fw_entry);
- if (ret) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "firmware2 upload transfer failure");
- goto done;
- }
- /* Finish upload */
- ret |= pvr2_write_register(hdw, 0x9054, 0xffffffff); /*reset hw blocks*/
- ret |= pvr2_write_register(hdw, 0x9058, 0xffffffe8); /*VPU ctrl*/
- ret |= pvr2_issue_simple_cmd(hdw,FX2CMD_MEMSEL | (1 << 8) | (0 << 16));
- if (ret) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "firmware2 upload post-proc failure");
- }
- done:
- if (hdw->hdw_desc->signal_routing_scheme ==
- PVR2_ROUTING_SCHEME_GOTVIEW) {
- /* Ensure that GPIO 11 is set to output for GOTVIEW
- hardware. */
- pvr2_hdw_gpio_chg_dir(hdw,(1 << 11),~0);
- }
- return ret;
- }
- static const char *pvr2_get_state_name(unsigned int st)
- {
- if (st < ARRAY_SIZE(pvr2_state_names)) {
- return pvr2_state_names[st];
- }
- return "???";
- }
- static int pvr2_decoder_enable(struct pvr2_hdw *hdw,int enablefl)
- {
- /* Even though we really only care about the video decoder chip at
- this point, we'll broadcast stream on/off to all sub-devices
- anyway, just in case somebody else wants to hear the
- command... */
- pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 stream=%s",
- (enablefl ? "on" : "off"));
- v4l2_device_call_all(&hdw->v4l2_dev, 0, video, s_stream, enablefl);
- v4l2_device_call_all(&hdw->v4l2_dev, 0, audio, s_stream, enablefl);
- if (hdw->decoder_client_id) {
- /* We get here if the encoder has been noticed. Otherwise
- we'll issue a warning to the user (which should
- normally never happen). */
- return 0;
- }
- if (!hdw->flag_decoder_missed) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "WARNING: No decoder present");
- hdw->flag_decoder_missed = !0;
- trace_stbit("flag_decoder_missed",
- hdw->flag_decoder_missed);
- }
- return -EIO;
- }
- int pvr2_hdw_get_state(struct pvr2_hdw *hdw)
- {
- return hdw->master_state;
- }
- static int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *hdw)
- {
- if (!hdw->flag_tripped) return 0;
- hdw->flag_tripped = 0;
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "Clearing driver error statuss");
- return !0;
- }
- int pvr2_hdw_untrip(struct pvr2_hdw *hdw)
- {
- int fl;
- LOCK_TAKE(hdw->big_lock); do {
- fl = pvr2_hdw_untrip_unlocked(hdw);
- } while (0); LOCK_GIVE(hdw->big_lock);
- if (fl) pvr2_hdw_state_sched(hdw);
- return 0;
- }
- int pvr2_hdw_get_streaming(struct pvr2_hdw *hdw)
- {
- return hdw->state_pipeline_req != 0;
- }
- int pvr2_hdw_set_streaming(struct pvr2_hdw *hdw,int enable_flag)
- {
- int ret,st;
- LOCK_TAKE(hdw->big_lock); do {
- pvr2_hdw_untrip_unlocked(hdw);
- if ((!enable_flag) != !(hdw->state_pipeline_req)) {
- hdw->state_pipeline_req = enable_flag != 0;
- pvr2_trace(PVR2_TRACE_START_STOP,
- "/*--TRACE_STREAM--*/ %s",
- enable_flag ? "enable" : "disable");
- }
- pvr2_hdw_state_sched(hdw);
- } while (0); LOCK_GIVE(hdw->big_lock);
- if ((ret = pvr2_hdw_wait(hdw,0)) < 0) return ret;
- if (enable_flag) {
- while ((st = hdw->master_state) != PVR2_STATE_RUN) {
- if (st != PVR2_STATE_READY) return -EIO;
- if ((ret = pvr2_hdw_wait(hdw,st)) < 0) return ret;
- }
- }
- return 0;
- }
- int pvr2_hdw_set_stream_type(struct pvr2_hdw *hdw,enum pvr2_config config)
- {
- int fl;
- LOCK_TAKE(hdw->big_lock);
- if ((fl = (hdw->desired_stream_type != config)) != 0) {
- hdw->desired_stream_type = config;
- hdw->state_pipeline_config = 0;
- trace_stbit("state_pipeline_config",
- hdw->state_pipeline_config);
- pvr2_hdw_state_sched(hdw);
- }
- LOCK_GIVE(hdw->big_lock);
- if (fl) return 0;
- return pvr2_hdw_wait(hdw,0);
- }
- static int get_default_tuner_type(struct pvr2_hdw *hdw)
- {
- int unit_number = hdw->unit_number;
- int tp = -1;
- if ((unit_number >= 0) && (unit_number < PVR_NUM)) {
- tp = tuner[unit_number];
- }
- if (tp < 0) return -EINVAL;
- hdw->tuner_type = tp;
- hdw->tuner_updated = !0;
- return 0;
- }
- static v4l2_std_id get_default_standard(struct pvr2_hdw *hdw)
- {
- int unit_number = hdw->unit_number;
- int tp = 0;
- if ((unit_number >= 0) && (unit_number < PVR_NUM)) {
- tp = video_std[unit_number];
- if (tp) return tp;
- }
- return 0;
- }
- static unsigned int get_default_error_tolerance(struct pvr2_hdw *hdw)
- {
- int unit_number = hdw->unit_number;
- int tp = 0;
- if ((unit_number >= 0) && (unit_number < PVR_NUM)) {
- tp = tolerance[unit_number];
- }
- return tp;
- }
- static int pvr2_hdw_check_firmware(struct pvr2_hdw *hdw)
- {
- /* Try a harmless request to fetch the eeprom's address over
- endpoint 1. See what happens. Only the full FX2 image can
- respond to this. If this probe fails then likely the FX2
- firmware needs be loaded. */
- int result;
- LOCK_TAKE(hdw->ctl_lock); do {
- hdw->cmd_buffer[0] = FX2CMD_GET_EEPROM_ADDR;
- result = pvr2_send_request_e…