162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2005 Mike Isely <isely@pobox.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/errno.h> 862306a36Sopenharmony_ci#include <linux/string.h> 962306a36Sopenharmony_ci#include <linux/slab.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/firmware.h> 1262306a36Sopenharmony_ci#include <linux/videodev2.h> 1362306a36Sopenharmony_ci#include <media/v4l2-common.h> 1462306a36Sopenharmony_ci#include <media/tuner.h> 1562306a36Sopenharmony_ci#include "pvrusb2.h" 1662306a36Sopenharmony_ci#include "pvrusb2-std.h" 1762306a36Sopenharmony_ci#include "pvrusb2-util.h" 1862306a36Sopenharmony_ci#include "pvrusb2-hdw.h" 1962306a36Sopenharmony_ci#include "pvrusb2-i2c-core.h" 2062306a36Sopenharmony_ci#include "pvrusb2-eeprom.h" 2162306a36Sopenharmony_ci#include "pvrusb2-hdw-internal.h" 2262306a36Sopenharmony_ci#include "pvrusb2-encoder.h" 2362306a36Sopenharmony_ci#include "pvrusb2-debug.h" 2462306a36Sopenharmony_ci#include "pvrusb2-fx2-cmd.h" 2562306a36Sopenharmony_ci#include "pvrusb2-wm8775.h" 2662306a36Sopenharmony_ci#include "pvrusb2-video-v4l.h" 2762306a36Sopenharmony_ci#include "pvrusb2-cx2584x-v4l.h" 2862306a36Sopenharmony_ci#include "pvrusb2-cs53l32a.h" 2962306a36Sopenharmony_ci#include "pvrusb2-audio.h" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define TV_MIN_FREQ 55250000L 3262306a36Sopenharmony_ci#define TV_MAX_FREQ 850000000L 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* This defines a minimum interval that the decoder must remain quiet 3562306a36Sopenharmony_ci before we are allowed to start it running. */ 3662306a36Sopenharmony_ci#define TIME_MSEC_DECODER_WAIT 50 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* This defines a minimum interval that the decoder must be allowed to run 3962306a36Sopenharmony_ci before we can safely begin using its streaming output. */ 4062306a36Sopenharmony_ci#define TIME_MSEC_DECODER_STABILIZATION_WAIT 300 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* This defines a minimum interval that the encoder must remain quiet 4362306a36Sopenharmony_ci before we are allowed to configure it. */ 4462306a36Sopenharmony_ci#define TIME_MSEC_ENCODER_WAIT 50 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* This defines the minimum interval that the encoder must successfully run 4762306a36Sopenharmony_ci before we consider that the encoder has run at least once since its 4862306a36Sopenharmony_ci firmware has been loaded. This measurement is in important for cases 4962306a36Sopenharmony_ci where we can't do something until we know that the encoder has been run 5062306a36Sopenharmony_ci at least once. */ 5162306a36Sopenharmony_ci#define TIME_MSEC_ENCODER_OK 250 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = NULL}; 5462306a36Sopenharmony_cistatic DEFINE_MUTEX(pvr2_unit_mtx); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic int ctlchg; 5762306a36Sopenharmony_cistatic int procreload; 5862306a36Sopenharmony_cistatic int tuner[PVR_NUM] = { [0 ... PVR_NUM-1] = -1 }; 5962306a36Sopenharmony_cistatic int tolerance[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 }; 6062306a36Sopenharmony_cistatic int video_std[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 }; 6162306a36Sopenharmony_cistatic int init_pause_msec; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cimodule_param(ctlchg, int, S_IRUGO|S_IWUSR); 6462306a36Sopenharmony_ciMODULE_PARM_DESC(ctlchg, "0=optimize ctl change 1=always accept new ctl value"); 6562306a36Sopenharmony_cimodule_param(init_pause_msec, int, S_IRUGO|S_IWUSR); 6662306a36Sopenharmony_ciMODULE_PARM_DESC(init_pause_msec, "hardware initialization settling delay"); 6762306a36Sopenharmony_cimodule_param(procreload, int, S_IRUGO|S_IWUSR); 6862306a36Sopenharmony_ciMODULE_PARM_DESC(procreload, 6962306a36Sopenharmony_ci "Attempt init failure recovery with firmware reload"); 7062306a36Sopenharmony_cimodule_param_array(tuner, int, NULL, 0444); 7162306a36Sopenharmony_ciMODULE_PARM_DESC(tuner,"specify installed tuner type"); 7262306a36Sopenharmony_cimodule_param_array(video_std, int, NULL, 0444); 7362306a36Sopenharmony_ciMODULE_PARM_DESC(video_std,"specify initial video standard"); 7462306a36Sopenharmony_cimodule_param_array(tolerance, int, NULL, 0444); 7562306a36Sopenharmony_ciMODULE_PARM_DESC(tolerance,"specify stream error tolerance"); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/* US Broadcast channel 3 (61.25 MHz), to help with testing */ 7862306a36Sopenharmony_cistatic int default_tv_freq = 61250000L; 7962306a36Sopenharmony_ci/* 104.3 MHz, a usable FM station for my area */ 8062306a36Sopenharmony_cistatic int default_radio_freq = 104300000L; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cimodule_param_named(tv_freq, default_tv_freq, int, 0444); 8362306a36Sopenharmony_ciMODULE_PARM_DESC(tv_freq, "specify initial television frequency"); 8462306a36Sopenharmony_cimodule_param_named(radio_freq, default_radio_freq, int, 0444); 8562306a36Sopenharmony_ciMODULE_PARM_DESC(radio_freq, "specify initial radio frequency"); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci#define PVR2_CTL_WRITE_ENDPOINT 0x01 8862306a36Sopenharmony_ci#define PVR2_CTL_READ_ENDPOINT 0x81 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci#define PVR2_GPIO_IN 0x9008 9162306a36Sopenharmony_ci#define PVR2_GPIO_OUT 0x900c 9262306a36Sopenharmony_ci#define PVR2_GPIO_DIR 0x9020 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci#define trace_firmware(...) pvr2_trace(PVR2_TRACE_FIRMWARE,__VA_ARGS__) 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci#define PVR2_FIRMWARE_ENDPOINT 0x02 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci/* size of a firmware chunk */ 9962306a36Sopenharmony_ci#define FIRMWARE_CHUNK_SIZE 0x2000 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_citypedef void (*pvr2_subdev_update_func)(struct pvr2_hdw *, 10262306a36Sopenharmony_ci struct v4l2_subdev *); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic const pvr2_subdev_update_func pvr2_module_update_functions[] = { 10562306a36Sopenharmony_ci [PVR2_CLIENT_ID_WM8775] = pvr2_wm8775_subdev_update, 10662306a36Sopenharmony_ci [PVR2_CLIENT_ID_SAA7115] = pvr2_saa7115_subdev_update, 10762306a36Sopenharmony_ci [PVR2_CLIENT_ID_MSP3400] = pvr2_msp3400_subdev_update, 10862306a36Sopenharmony_ci [PVR2_CLIENT_ID_CX25840] = pvr2_cx25840_subdev_update, 10962306a36Sopenharmony_ci [PVR2_CLIENT_ID_CS53L32A] = pvr2_cs53l32a_subdev_update, 11062306a36Sopenharmony_ci}; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic const char *module_names[] = { 11362306a36Sopenharmony_ci [PVR2_CLIENT_ID_MSP3400] = "msp3400", 11462306a36Sopenharmony_ci [PVR2_CLIENT_ID_CX25840] = "cx25840", 11562306a36Sopenharmony_ci [PVR2_CLIENT_ID_SAA7115] = "saa7115", 11662306a36Sopenharmony_ci [PVR2_CLIENT_ID_TUNER] = "tuner", 11762306a36Sopenharmony_ci [PVR2_CLIENT_ID_DEMOD] = "tuner", 11862306a36Sopenharmony_ci [PVR2_CLIENT_ID_CS53L32A] = "cs53l32a", 11962306a36Sopenharmony_ci [PVR2_CLIENT_ID_WM8775] = "wm8775", 12062306a36Sopenharmony_ci}; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic const unsigned char *module_i2c_addresses[] = { 12462306a36Sopenharmony_ci [PVR2_CLIENT_ID_TUNER] = "\x60\x61\x62\x63", 12562306a36Sopenharmony_ci [PVR2_CLIENT_ID_DEMOD] = "\x43", 12662306a36Sopenharmony_ci [PVR2_CLIENT_ID_MSP3400] = "\x40", 12762306a36Sopenharmony_ci [PVR2_CLIENT_ID_SAA7115] = "\x21", 12862306a36Sopenharmony_ci [PVR2_CLIENT_ID_WM8775] = "\x1b", 12962306a36Sopenharmony_ci [PVR2_CLIENT_ID_CX25840] = "\x44", 13062306a36Sopenharmony_ci [PVR2_CLIENT_ID_CS53L32A] = "\x11", 13162306a36Sopenharmony_ci}; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic const char *ir_scheme_names[] = { 13562306a36Sopenharmony_ci [PVR2_IR_SCHEME_NONE] = "none", 13662306a36Sopenharmony_ci [PVR2_IR_SCHEME_29XXX] = "29xxx", 13762306a36Sopenharmony_ci [PVR2_IR_SCHEME_24XXX] = "24xxx (29xxx emulation)", 13862306a36Sopenharmony_ci [PVR2_IR_SCHEME_24XXX_MCE] = "24xxx (MCE device)", 13962306a36Sopenharmony_ci [PVR2_IR_SCHEME_ZILOG] = "Zilog", 14062306a36Sopenharmony_ci}; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/* Define the list of additional controls we'll dynamically construct based 14462306a36Sopenharmony_ci on query of the cx2341x module. */ 14562306a36Sopenharmony_cistruct pvr2_mpeg_ids { 14662306a36Sopenharmony_ci const char *strid; 14762306a36Sopenharmony_ci int id; 14862306a36Sopenharmony_ci}; 14962306a36Sopenharmony_cistatic const struct pvr2_mpeg_ids mpeg_ids[] = { 15062306a36Sopenharmony_ci { 15162306a36Sopenharmony_ci .strid = "audio_layer", 15262306a36Sopenharmony_ci .id = V4L2_CID_MPEG_AUDIO_ENCODING, 15362306a36Sopenharmony_ci },{ 15462306a36Sopenharmony_ci .strid = "audio_bitrate", 15562306a36Sopenharmony_ci .id = V4L2_CID_MPEG_AUDIO_L2_BITRATE, 15662306a36Sopenharmony_ci },{ 15762306a36Sopenharmony_ci /* Already using audio_mode elsewhere :-( */ 15862306a36Sopenharmony_ci .strid = "mpeg_audio_mode", 15962306a36Sopenharmony_ci .id = V4L2_CID_MPEG_AUDIO_MODE, 16062306a36Sopenharmony_ci },{ 16162306a36Sopenharmony_ci .strid = "mpeg_audio_mode_extension", 16262306a36Sopenharmony_ci .id = V4L2_CID_MPEG_AUDIO_MODE_EXTENSION, 16362306a36Sopenharmony_ci },{ 16462306a36Sopenharmony_ci .strid = "audio_emphasis", 16562306a36Sopenharmony_ci .id = V4L2_CID_MPEG_AUDIO_EMPHASIS, 16662306a36Sopenharmony_ci },{ 16762306a36Sopenharmony_ci .strid = "audio_crc", 16862306a36Sopenharmony_ci .id = V4L2_CID_MPEG_AUDIO_CRC, 16962306a36Sopenharmony_ci },{ 17062306a36Sopenharmony_ci .strid = "video_aspect", 17162306a36Sopenharmony_ci .id = V4L2_CID_MPEG_VIDEO_ASPECT, 17262306a36Sopenharmony_ci },{ 17362306a36Sopenharmony_ci .strid = "video_b_frames", 17462306a36Sopenharmony_ci .id = V4L2_CID_MPEG_VIDEO_B_FRAMES, 17562306a36Sopenharmony_ci },{ 17662306a36Sopenharmony_ci .strid = "video_gop_size", 17762306a36Sopenharmony_ci .id = V4L2_CID_MPEG_VIDEO_GOP_SIZE, 17862306a36Sopenharmony_ci },{ 17962306a36Sopenharmony_ci .strid = "video_gop_closure", 18062306a36Sopenharmony_ci .id = V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, 18162306a36Sopenharmony_ci },{ 18262306a36Sopenharmony_ci .strid = "video_bitrate_mode", 18362306a36Sopenharmony_ci .id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE, 18462306a36Sopenharmony_ci },{ 18562306a36Sopenharmony_ci .strid = "video_bitrate", 18662306a36Sopenharmony_ci .id = V4L2_CID_MPEG_VIDEO_BITRATE, 18762306a36Sopenharmony_ci },{ 18862306a36Sopenharmony_ci .strid = "video_bitrate_peak", 18962306a36Sopenharmony_ci .id = V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, 19062306a36Sopenharmony_ci },{ 19162306a36Sopenharmony_ci .strid = "video_temporal_decimation", 19262306a36Sopenharmony_ci .id = V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION, 19362306a36Sopenharmony_ci },{ 19462306a36Sopenharmony_ci .strid = "stream_type", 19562306a36Sopenharmony_ci .id = V4L2_CID_MPEG_STREAM_TYPE, 19662306a36Sopenharmony_ci },{ 19762306a36Sopenharmony_ci .strid = "video_spatial_filter_mode", 19862306a36Sopenharmony_ci .id = V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE, 19962306a36Sopenharmony_ci },{ 20062306a36Sopenharmony_ci .strid = "video_spatial_filter", 20162306a36Sopenharmony_ci .id = V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER, 20262306a36Sopenharmony_ci },{ 20362306a36Sopenharmony_ci .strid = "video_luma_spatial_filter_type", 20462306a36Sopenharmony_ci .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE, 20562306a36Sopenharmony_ci },{ 20662306a36Sopenharmony_ci .strid = "video_chroma_spatial_filter_type", 20762306a36Sopenharmony_ci .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE, 20862306a36Sopenharmony_ci },{ 20962306a36Sopenharmony_ci .strid = "video_temporal_filter_mode", 21062306a36Sopenharmony_ci .id = V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE, 21162306a36Sopenharmony_ci },{ 21262306a36Sopenharmony_ci .strid = "video_temporal_filter", 21362306a36Sopenharmony_ci .id = V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER, 21462306a36Sopenharmony_ci },{ 21562306a36Sopenharmony_ci .strid = "video_median_filter_type", 21662306a36Sopenharmony_ci .id = V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE, 21762306a36Sopenharmony_ci },{ 21862306a36Sopenharmony_ci .strid = "video_luma_median_filter_top", 21962306a36Sopenharmony_ci .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP, 22062306a36Sopenharmony_ci },{ 22162306a36Sopenharmony_ci .strid = "video_luma_median_filter_bottom", 22262306a36Sopenharmony_ci .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM, 22362306a36Sopenharmony_ci },{ 22462306a36Sopenharmony_ci .strid = "video_chroma_median_filter_top", 22562306a36Sopenharmony_ci .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP, 22662306a36Sopenharmony_ci },{ 22762306a36Sopenharmony_ci .strid = "video_chroma_median_filter_bottom", 22862306a36Sopenharmony_ci .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM, 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci}; 23162306a36Sopenharmony_ci#define MPEGDEF_COUNT ARRAY_SIZE(mpeg_ids) 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistatic const char *control_values_srate[] = { 23562306a36Sopenharmony_ci [V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100] = "44.1 kHz", 23662306a36Sopenharmony_ci [V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000] = "48 kHz", 23762306a36Sopenharmony_ci [V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000] = "32 kHz", 23862306a36Sopenharmony_ci}; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic const char *control_values_input[] = { 24362306a36Sopenharmony_ci [PVR2_CVAL_INPUT_TV] = "television", /*xawtv needs this name*/ 24462306a36Sopenharmony_ci [PVR2_CVAL_INPUT_DTV] = "dtv", 24562306a36Sopenharmony_ci [PVR2_CVAL_INPUT_RADIO] = "radio", 24662306a36Sopenharmony_ci [PVR2_CVAL_INPUT_SVIDEO] = "s-video", 24762306a36Sopenharmony_ci [PVR2_CVAL_INPUT_COMPOSITE] = "composite", 24862306a36Sopenharmony_ci}; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic const char *control_values_audiomode[] = { 25262306a36Sopenharmony_ci [V4L2_TUNER_MODE_MONO] = "Mono", 25362306a36Sopenharmony_ci [V4L2_TUNER_MODE_STEREO] = "Stereo", 25462306a36Sopenharmony_ci [V4L2_TUNER_MODE_LANG1] = "Lang1", 25562306a36Sopenharmony_ci [V4L2_TUNER_MODE_LANG2] = "Lang2", 25662306a36Sopenharmony_ci [V4L2_TUNER_MODE_LANG1_LANG2] = "Lang1+Lang2", 25762306a36Sopenharmony_ci}; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic const char *control_values_hsm[] = { 26162306a36Sopenharmony_ci [PVR2_CVAL_HSM_FAIL] = "Fail", 26262306a36Sopenharmony_ci [PVR2_CVAL_HSM_HIGH] = "High", 26362306a36Sopenharmony_ci [PVR2_CVAL_HSM_FULL] = "Full", 26462306a36Sopenharmony_ci}; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic const char *pvr2_state_names[] = { 26862306a36Sopenharmony_ci [PVR2_STATE_NONE] = "none", 26962306a36Sopenharmony_ci [PVR2_STATE_DEAD] = "dead", 27062306a36Sopenharmony_ci [PVR2_STATE_COLD] = "cold", 27162306a36Sopenharmony_ci [PVR2_STATE_WARM] = "warm", 27262306a36Sopenharmony_ci [PVR2_STATE_ERROR] = "error", 27362306a36Sopenharmony_ci [PVR2_STATE_READY] = "ready", 27462306a36Sopenharmony_ci [PVR2_STATE_RUN] = "run", 27562306a36Sopenharmony_ci}; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistruct pvr2_fx2cmd_descdef { 27962306a36Sopenharmony_ci unsigned char id; 28062306a36Sopenharmony_ci unsigned char *desc; 28162306a36Sopenharmony_ci}; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic const struct pvr2_fx2cmd_descdef pvr2_fx2cmd_desc[] = { 28462306a36Sopenharmony_ci {FX2CMD_MEM_WRITE_DWORD, "write encoder dword"}, 28562306a36Sopenharmony_ci {FX2CMD_MEM_READ_DWORD, "read encoder dword"}, 28662306a36Sopenharmony_ci {FX2CMD_HCW_ZILOG_RESET, "zilog IR reset control"}, 28762306a36Sopenharmony_ci {FX2CMD_MEM_READ_64BYTES, "read encoder 64bytes"}, 28862306a36Sopenharmony_ci {FX2CMD_REG_WRITE, "write encoder register"}, 28962306a36Sopenharmony_ci {FX2CMD_REG_READ, "read encoder register"}, 29062306a36Sopenharmony_ci {FX2CMD_MEMSEL, "encoder memsel"}, 29162306a36Sopenharmony_ci {FX2CMD_I2C_WRITE, "i2c write"}, 29262306a36Sopenharmony_ci {FX2CMD_I2C_READ, "i2c read"}, 29362306a36Sopenharmony_ci {FX2CMD_GET_USB_SPEED, "get USB speed"}, 29462306a36Sopenharmony_ci {FX2CMD_STREAMING_ON, "stream on"}, 29562306a36Sopenharmony_ci {FX2CMD_STREAMING_OFF, "stream off"}, 29662306a36Sopenharmony_ci {FX2CMD_FWPOST1, "fwpost1"}, 29762306a36Sopenharmony_ci {FX2CMD_POWER_OFF, "power off"}, 29862306a36Sopenharmony_ci {FX2CMD_POWER_ON, "power on"}, 29962306a36Sopenharmony_ci {FX2CMD_DEEP_RESET, "deep reset"}, 30062306a36Sopenharmony_ci {FX2CMD_GET_EEPROM_ADDR, "get rom addr"}, 30162306a36Sopenharmony_ci {FX2CMD_GET_IR_CODE, "get IR code"}, 30262306a36Sopenharmony_ci {FX2CMD_HCW_DEMOD_RESETIN, "hcw demod resetin"}, 30362306a36Sopenharmony_ci {FX2CMD_HCW_DTV_STREAMING_ON, "hcw dtv stream on"}, 30462306a36Sopenharmony_ci {FX2CMD_HCW_DTV_STREAMING_OFF, "hcw dtv stream off"}, 30562306a36Sopenharmony_ci {FX2CMD_ONAIR_DTV_STREAMING_ON, "onair dtv stream on"}, 30662306a36Sopenharmony_ci {FX2CMD_ONAIR_DTV_STREAMING_OFF, "onair dtv stream off"}, 30762306a36Sopenharmony_ci {FX2CMD_ONAIR_DTV_POWER_ON, "onair dtv power on"}, 30862306a36Sopenharmony_ci {FX2CMD_ONAIR_DTV_POWER_OFF, "onair dtv power off"}, 30962306a36Sopenharmony_ci {FX2CMD_HCW_DEMOD_RESET_PIN, "hcw demod reset pin"}, 31062306a36Sopenharmony_ci {FX2CMD_HCW_MAKO_SLEEP_PIN, "hcw mako sleep pin"}, 31162306a36Sopenharmony_ci}; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic int pvr2_hdw_set_input(struct pvr2_hdw *hdw,int v); 31562306a36Sopenharmony_cistatic void pvr2_hdw_state_sched(struct pvr2_hdw *); 31662306a36Sopenharmony_cistatic int pvr2_hdw_state_eval(struct pvr2_hdw *); 31762306a36Sopenharmony_cistatic void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long); 31862306a36Sopenharmony_cistatic void pvr2_hdw_worker_poll(struct work_struct *work); 31962306a36Sopenharmony_cistatic int pvr2_hdw_wait(struct pvr2_hdw *,int state); 32062306a36Sopenharmony_cistatic int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *); 32162306a36Sopenharmony_cistatic void pvr2_hdw_state_log_state(struct pvr2_hdw *); 32262306a36Sopenharmony_cistatic int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl); 32362306a36Sopenharmony_cistatic int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw); 32462306a36Sopenharmony_cistatic int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw); 32562306a36Sopenharmony_cistatic void pvr2_hdw_quiescent_timeout(struct timer_list *); 32662306a36Sopenharmony_cistatic void pvr2_hdw_decoder_stabilization_timeout(struct timer_list *); 32762306a36Sopenharmony_cistatic void pvr2_hdw_encoder_wait_timeout(struct timer_list *); 32862306a36Sopenharmony_cistatic void pvr2_hdw_encoder_run_timeout(struct timer_list *); 32962306a36Sopenharmony_cistatic int pvr2_issue_simple_cmd(struct pvr2_hdw *,u32); 33062306a36Sopenharmony_cistatic int pvr2_send_request_ex(struct pvr2_hdw *hdw, 33162306a36Sopenharmony_ci unsigned int timeout,int probe_fl, 33262306a36Sopenharmony_ci void *write_data,unsigned int write_len, 33362306a36Sopenharmony_ci void *read_data,unsigned int read_len); 33462306a36Sopenharmony_cistatic int pvr2_hdw_check_cropcap(struct pvr2_hdw *hdw); 33562306a36Sopenharmony_cistatic v4l2_std_id pvr2_hdw_get_detected_std(struct pvr2_hdw *hdw); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistatic void trace_stbit(const char *name,int val) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_STBITS, 34062306a36Sopenharmony_ci "State bit %s <-- %s", 34162306a36Sopenharmony_ci name,(val ? "true" : "false")); 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistatic int ctrl_channelfreq_get(struct pvr2_ctrl *cptr,int *vp) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci struct pvr2_hdw *hdw = cptr->hdw; 34762306a36Sopenharmony_ci if ((hdw->freqProgSlot > 0) && (hdw->freqProgSlot <= FREQTABLE_SIZE)) { 34862306a36Sopenharmony_ci *vp = hdw->freqTable[hdw->freqProgSlot-1]; 34962306a36Sopenharmony_ci } else { 35062306a36Sopenharmony_ci *vp = 0; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci return 0; 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic int ctrl_channelfreq_set(struct pvr2_ctrl *cptr,int m,int v) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci struct pvr2_hdw *hdw = cptr->hdw; 35862306a36Sopenharmony_ci unsigned int slotId = hdw->freqProgSlot; 35962306a36Sopenharmony_ci if ((slotId > 0) && (slotId <= FREQTABLE_SIZE)) { 36062306a36Sopenharmony_ci hdw->freqTable[slotId-1] = v; 36162306a36Sopenharmony_ci /* Handle side effects correctly - if we're tuned to this 36262306a36Sopenharmony_ci slot, then forgot the slot id relation since the stored 36362306a36Sopenharmony_ci frequency has been changed. */ 36462306a36Sopenharmony_ci if (hdw->freqSelector) { 36562306a36Sopenharmony_ci if (hdw->freqSlotRadio == slotId) { 36662306a36Sopenharmony_ci hdw->freqSlotRadio = 0; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci } else { 36962306a36Sopenharmony_ci if (hdw->freqSlotTelevision == slotId) { 37062306a36Sopenharmony_ci hdw->freqSlotTelevision = 0; 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci return 0; 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_cistatic int ctrl_channelprog_get(struct pvr2_ctrl *cptr,int *vp) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci *vp = cptr->hdw->freqProgSlot; 38062306a36Sopenharmony_ci return 0; 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistatic int ctrl_channelprog_set(struct pvr2_ctrl *cptr,int m,int v) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci struct pvr2_hdw *hdw = cptr->hdw; 38662306a36Sopenharmony_ci if ((v >= 0) && (v <= FREQTABLE_SIZE)) { 38762306a36Sopenharmony_ci hdw->freqProgSlot = v; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci return 0; 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cistatic int ctrl_channel_get(struct pvr2_ctrl *cptr,int *vp) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci struct pvr2_hdw *hdw = cptr->hdw; 39562306a36Sopenharmony_ci *vp = hdw->freqSelector ? hdw->freqSlotRadio : hdw->freqSlotTelevision; 39662306a36Sopenharmony_ci return 0; 39762306a36Sopenharmony_ci} 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_cistatic int ctrl_channel_set(struct pvr2_ctrl *cptr,int m,int slotId) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci unsigned freq = 0; 40262306a36Sopenharmony_ci struct pvr2_hdw *hdw = cptr->hdw; 40362306a36Sopenharmony_ci if ((slotId < 0) || (slotId > FREQTABLE_SIZE)) return 0; 40462306a36Sopenharmony_ci if (slotId > 0) { 40562306a36Sopenharmony_ci freq = hdw->freqTable[slotId-1]; 40662306a36Sopenharmony_ci if (!freq) return 0; 40762306a36Sopenharmony_ci pvr2_hdw_set_cur_freq(hdw,freq); 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci if (hdw->freqSelector) { 41062306a36Sopenharmony_ci hdw->freqSlotRadio = slotId; 41162306a36Sopenharmony_ci } else { 41262306a36Sopenharmony_ci hdw->freqSlotTelevision = slotId; 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci return 0; 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_cistatic int ctrl_freq_get(struct pvr2_ctrl *cptr,int *vp) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci *vp = pvr2_hdw_get_cur_freq(cptr->hdw); 42062306a36Sopenharmony_ci return 0; 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic int ctrl_freq_is_dirty(struct pvr2_ctrl *cptr) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci return cptr->hdw->freqDirty != 0; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic void ctrl_freq_clear_dirty(struct pvr2_ctrl *cptr) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci cptr->hdw->freqDirty = 0; 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic int ctrl_freq_set(struct pvr2_ctrl *cptr,int m,int v) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci pvr2_hdw_set_cur_freq(cptr->hdw,v); 43662306a36Sopenharmony_ci return 0; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic int ctrl_cropl_min_get(struct pvr2_ctrl *cptr, int *left) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 44262306a36Sopenharmony_ci int stat = pvr2_hdw_check_cropcap(cptr->hdw); 44362306a36Sopenharmony_ci if (stat != 0) { 44462306a36Sopenharmony_ci return stat; 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci *left = cap->bounds.left; 44762306a36Sopenharmony_ci return 0; 44862306a36Sopenharmony_ci} 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cistatic int ctrl_cropl_max_get(struct pvr2_ctrl *cptr, int *left) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 45362306a36Sopenharmony_ci int stat = pvr2_hdw_check_cropcap(cptr->hdw); 45462306a36Sopenharmony_ci if (stat != 0) { 45562306a36Sopenharmony_ci return stat; 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci *left = cap->bounds.left; 45862306a36Sopenharmony_ci if (cap->bounds.width > cptr->hdw->cropw_val) { 45962306a36Sopenharmony_ci *left += cap->bounds.width - cptr->hdw->cropw_val; 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci return 0; 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_cistatic int ctrl_cropt_min_get(struct pvr2_ctrl *cptr, int *top) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 46762306a36Sopenharmony_ci int stat = pvr2_hdw_check_cropcap(cptr->hdw); 46862306a36Sopenharmony_ci if (stat != 0) { 46962306a36Sopenharmony_ci return stat; 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci *top = cap->bounds.top; 47262306a36Sopenharmony_ci return 0; 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cistatic int ctrl_cropt_max_get(struct pvr2_ctrl *cptr, int *top) 47662306a36Sopenharmony_ci{ 47762306a36Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 47862306a36Sopenharmony_ci int stat = pvr2_hdw_check_cropcap(cptr->hdw); 47962306a36Sopenharmony_ci if (stat != 0) { 48062306a36Sopenharmony_ci return stat; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci *top = cap->bounds.top; 48362306a36Sopenharmony_ci if (cap->bounds.height > cptr->hdw->croph_val) { 48462306a36Sopenharmony_ci *top += cap->bounds.height - cptr->hdw->croph_val; 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci return 0; 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cistatic int ctrl_cropw_max_get(struct pvr2_ctrl *cptr, int *width) 49062306a36Sopenharmony_ci{ 49162306a36Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 49262306a36Sopenharmony_ci int stat, bleftend, cleft; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci stat = pvr2_hdw_check_cropcap(cptr->hdw); 49562306a36Sopenharmony_ci if (stat != 0) { 49662306a36Sopenharmony_ci return stat; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci bleftend = cap->bounds.left+cap->bounds.width; 49962306a36Sopenharmony_ci cleft = cptr->hdw->cropl_val; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci *width = cleft < bleftend ? bleftend-cleft : 0; 50262306a36Sopenharmony_ci return 0; 50362306a36Sopenharmony_ci} 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_cistatic int ctrl_croph_max_get(struct pvr2_ctrl *cptr, int *height) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 50862306a36Sopenharmony_ci int stat, btopend, ctop; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci stat = pvr2_hdw_check_cropcap(cptr->hdw); 51162306a36Sopenharmony_ci if (stat != 0) { 51262306a36Sopenharmony_ci return stat; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci btopend = cap->bounds.top+cap->bounds.height; 51562306a36Sopenharmony_ci ctop = cptr->hdw->cropt_val; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci *height = ctop < btopend ? btopend-ctop : 0; 51862306a36Sopenharmony_ci return 0; 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cistatic int ctrl_get_cropcapbl(struct pvr2_ctrl *cptr, int *val) 52262306a36Sopenharmony_ci{ 52362306a36Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 52462306a36Sopenharmony_ci int stat = pvr2_hdw_check_cropcap(cptr->hdw); 52562306a36Sopenharmony_ci if (stat != 0) { 52662306a36Sopenharmony_ci return stat; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci *val = cap->bounds.left; 52962306a36Sopenharmony_ci return 0; 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_cistatic int ctrl_get_cropcapbt(struct pvr2_ctrl *cptr, int *val) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 53562306a36Sopenharmony_ci int stat = pvr2_hdw_check_cropcap(cptr->hdw); 53662306a36Sopenharmony_ci if (stat != 0) { 53762306a36Sopenharmony_ci return stat; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci *val = cap->bounds.top; 54062306a36Sopenharmony_ci return 0; 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_cistatic int ctrl_get_cropcapbw(struct pvr2_ctrl *cptr, int *val) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 54662306a36Sopenharmony_ci int stat = pvr2_hdw_check_cropcap(cptr->hdw); 54762306a36Sopenharmony_ci if (stat != 0) { 54862306a36Sopenharmony_ci return stat; 54962306a36Sopenharmony_ci } 55062306a36Sopenharmony_ci *val = cap->bounds.width; 55162306a36Sopenharmony_ci return 0; 55262306a36Sopenharmony_ci} 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_cistatic int ctrl_get_cropcapbh(struct pvr2_ctrl *cptr, int *val) 55562306a36Sopenharmony_ci{ 55662306a36Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 55762306a36Sopenharmony_ci int stat = pvr2_hdw_check_cropcap(cptr->hdw); 55862306a36Sopenharmony_ci if (stat != 0) { 55962306a36Sopenharmony_ci return stat; 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci *val = cap->bounds.height; 56262306a36Sopenharmony_ci return 0; 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cistatic int ctrl_get_cropcapdl(struct pvr2_ctrl *cptr, int *val) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 56862306a36Sopenharmony_ci int stat = pvr2_hdw_check_cropcap(cptr->hdw); 56962306a36Sopenharmony_ci if (stat != 0) { 57062306a36Sopenharmony_ci return stat; 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci *val = cap->defrect.left; 57362306a36Sopenharmony_ci return 0; 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_cistatic int ctrl_get_cropcapdt(struct pvr2_ctrl *cptr, int *val) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 57962306a36Sopenharmony_ci int stat = pvr2_hdw_check_cropcap(cptr->hdw); 58062306a36Sopenharmony_ci if (stat != 0) { 58162306a36Sopenharmony_ci return stat; 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci *val = cap->defrect.top; 58462306a36Sopenharmony_ci return 0; 58562306a36Sopenharmony_ci} 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_cistatic int ctrl_get_cropcapdw(struct pvr2_ctrl *cptr, int *val) 58862306a36Sopenharmony_ci{ 58962306a36Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 59062306a36Sopenharmony_ci int stat = pvr2_hdw_check_cropcap(cptr->hdw); 59162306a36Sopenharmony_ci if (stat != 0) { 59262306a36Sopenharmony_ci return stat; 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci *val = cap->defrect.width; 59562306a36Sopenharmony_ci return 0; 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_cistatic int ctrl_get_cropcapdh(struct pvr2_ctrl *cptr, int *val) 59962306a36Sopenharmony_ci{ 60062306a36Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 60162306a36Sopenharmony_ci int stat = pvr2_hdw_check_cropcap(cptr->hdw); 60262306a36Sopenharmony_ci if (stat != 0) { 60362306a36Sopenharmony_ci return stat; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci *val = cap->defrect.height; 60662306a36Sopenharmony_ci return 0; 60762306a36Sopenharmony_ci} 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_cistatic int ctrl_get_cropcappan(struct pvr2_ctrl *cptr, int *val) 61062306a36Sopenharmony_ci{ 61162306a36Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 61262306a36Sopenharmony_ci int stat = pvr2_hdw_check_cropcap(cptr->hdw); 61362306a36Sopenharmony_ci if (stat != 0) { 61462306a36Sopenharmony_ci return stat; 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci *val = cap->pixelaspect.numerator; 61762306a36Sopenharmony_ci return 0; 61862306a36Sopenharmony_ci} 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_cistatic int ctrl_get_cropcappad(struct pvr2_ctrl *cptr, int *val) 62162306a36Sopenharmony_ci{ 62262306a36Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 62362306a36Sopenharmony_ci int stat = pvr2_hdw_check_cropcap(cptr->hdw); 62462306a36Sopenharmony_ci if (stat != 0) { 62562306a36Sopenharmony_ci return stat; 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci *val = cap->pixelaspect.denominator; 62862306a36Sopenharmony_ci return 0; 62962306a36Sopenharmony_ci} 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_cistatic int ctrl_vres_max_get(struct pvr2_ctrl *cptr,int *vp) 63262306a36Sopenharmony_ci{ 63362306a36Sopenharmony_ci /* Actual maximum depends on the video standard in effect. */ 63462306a36Sopenharmony_ci if (cptr->hdw->std_mask_cur & V4L2_STD_525_60) { 63562306a36Sopenharmony_ci *vp = 480; 63662306a36Sopenharmony_ci } else { 63762306a36Sopenharmony_ci *vp = 576; 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci return 0; 64062306a36Sopenharmony_ci} 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_cistatic int ctrl_vres_min_get(struct pvr2_ctrl *cptr,int *vp) 64362306a36Sopenharmony_ci{ 64462306a36Sopenharmony_ci /* Actual minimum depends on device digitizer type. */ 64562306a36Sopenharmony_ci if (cptr->hdw->hdw_desc->flag_has_cx25840) { 64662306a36Sopenharmony_ci *vp = 75; 64762306a36Sopenharmony_ci } else { 64862306a36Sopenharmony_ci *vp = 17; 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci return 0; 65162306a36Sopenharmony_ci} 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_cistatic int ctrl_get_input(struct pvr2_ctrl *cptr,int *vp) 65462306a36Sopenharmony_ci{ 65562306a36Sopenharmony_ci *vp = cptr->hdw->input_val; 65662306a36Sopenharmony_ci return 0; 65762306a36Sopenharmony_ci} 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_cistatic int ctrl_check_input(struct pvr2_ctrl *cptr,int v) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci if (v < 0 || v > PVR2_CVAL_INPUT_MAX) 66262306a36Sopenharmony_ci return 0; 66362306a36Sopenharmony_ci return ((1UL << v) & cptr->hdw->input_allowed_mask) != 0; 66462306a36Sopenharmony_ci} 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_cistatic int ctrl_set_input(struct pvr2_ctrl *cptr,int m,int v) 66762306a36Sopenharmony_ci{ 66862306a36Sopenharmony_ci return pvr2_hdw_set_input(cptr->hdw,v); 66962306a36Sopenharmony_ci} 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_cistatic int ctrl_isdirty_input(struct pvr2_ctrl *cptr) 67262306a36Sopenharmony_ci{ 67362306a36Sopenharmony_ci return cptr->hdw->input_dirty != 0; 67462306a36Sopenharmony_ci} 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_cistatic void ctrl_cleardirty_input(struct pvr2_ctrl *cptr) 67762306a36Sopenharmony_ci{ 67862306a36Sopenharmony_ci cptr->hdw->input_dirty = 0; 67962306a36Sopenharmony_ci} 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_cistatic int ctrl_freq_max_get(struct pvr2_ctrl *cptr, int *vp) 68362306a36Sopenharmony_ci{ 68462306a36Sopenharmony_ci unsigned long fv; 68562306a36Sopenharmony_ci struct pvr2_hdw *hdw = cptr->hdw; 68662306a36Sopenharmony_ci if (hdw->tuner_signal_stale) { 68762306a36Sopenharmony_ci pvr2_hdw_status_poll(hdw); 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci fv = hdw->tuner_signal_info.rangehigh; 69062306a36Sopenharmony_ci if (!fv) { 69162306a36Sopenharmony_ci /* Safety fallback */ 69262306a36Sopenharmony_ci *vp = TV_MAX_FREQ; 69362306a36Sopenharmony_ci return 0; 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) { 69662306a36Sopenharmony_ci fv = (fv * 125) / 2; 69762306a36Sopenharmony_ci } else { 69862306a36Sopenharmony_ci fv = fv * 62500; 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci *vp = fv; 70162306a36Sopenharmony_ci return 0; 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_cistatic int ctrl_freq_min_get(struct pvr2_ctrl *cptr, int *vp) 70562306a36Sopenharmony_ci{ 70662306a36Sopenharmony_ci unsigned long fv; 70762306a36Sopenharmony_ci struct pvr2_hdw *hdw = cptr->hdw; 70862306a36Sopenharmony_ci if (hdw->tuner_signal_stale) { 70962306a36Sopenharmony_ci pvr2_hdw_status_poll(hdw); 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci fv = hdw->tuner_signal_info.rangelow; 71262306a36Sopenharmony_ci if (!fv) { 71362306a36Sopenharmony_ci /* Safety fallback */ 71462306a36Sopenharmony_ci *vp = TV_MIN_FREQ; 71562306a36Sopenharmony_ci return 0; 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) { 71862306a36Sopenharmony_ci fv = (fv * 125) / 2; 71962306a36Sopenharmony_ci } else { 72062306a36Sopenharmony_ci fv = fv * 62500; 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci *vp = fv; 72362306a36Sopenharmony_ci return 0; 72462306a36Sopenharmony_ci} 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_cistatic int ctrl_cx2341x_is_dirty(struct pvr2_ctrl *cptr) 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci return cptr->hdw->enc_stale != 0; 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_cistatic void ctrl_cx2341x_clear_dirty(struct pvr2_ctrl *cptr) 73262306a36Sopenharmony_ci{ 73362306a36Sopenharmony_ci cptr->hdw->enc_stale = 0; 73462306a36Sopenharmony_ci cptr->hdw->enc_unsafe_stale = 0; 73562306a36Sopenharmony_ci} 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_cistatic int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp) 73862306a36Sopenharmony_ci{ 73962306a36Sopenharmony_ci int ret; 74062306a36Sopenharmony_ci struct v4l2_ext_controls cs; 74162306a36Sopenharmony_ci struct v4l2_ext_control c1; 74262306a36Sopenharmony_ci memset(&cs,0,sizeof(cs)); 74362306a36Sopenharmony_ci memset(&c1,0,sizeof(c1)); 74462306a36Sopenharmony_ci cs.controls = &c1; 74562306a36Sopenharmony_ci cs.count = 1; 74662306a36Sopenharmony_ci c1.id = cptr->info->v4l_id; 74762306a36Sopenharmony_ci ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state, 0, &cs, 74862306a36Sopenharmony_ci VIDIOC_G_EXT_CTRLS); 74962306a36Sopenharmony_ci if (ret) return ret; 75062306a36Sopenharmony_ci *vp = c1.value; 75162306a36Sopenharmony_ci return 0; 75262306a36Sopenharmony_ci} 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_cistatic int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v) 75562306a36Sopenharmony_ci{ 75662306a36Sopenharmony_ci int ret; 75762306a36Sopenharmony_ci struct pvr2_hdw *hdw = cptr->hdw; 75862306a36Sopenharmony_ci struct v4l2_ext_controls cs; 75962306a36Sopenharmony_ci struct v4l2_ext_control c1; 76062306a36Sopenharmony_ci memset(&cs,0,sizeof(cs)); 76162306a36Sopenharmony_ci memset(&c1,0,sizeof(c1)); 76262306a36Sopenharmony_ci cs.controls = &c1; 76362306a36Sopenharmony_ci cs.count = 1; 76462306a36Sopenharmony_ci c1.id = cptr->info->v4l_id; 76562306a36Sopenharmony_ci c1.value = v; 76662306a36Sopenharmony_ci ret = cx2341x_ext_ctrls(&hdw->enc_ctl_state, 76762306a36Sopenharmony_ci hdw->state_encoder_run, &cs, 76862306a36Sopenharmony_ci VIDIOC_S_EXT_CTRLS); 76962306a36Sopenharmony_ci if (ret == -EBUSY) { 77062306a36Sopenharmony_ci /* Oops. cx2341x is telling us it's not safe to change 77162306a36Sopenharmony_ci this control while we're capturing. Make a note of this 77262306a36Sopenharmony_ci fact so that the pipeline will be stopped the next time 77362306a36Sopenharmony_ci controls are committed. Then go on ahead and store this 77462306a36Sopenharmony_ci change anyway. */ 77562306a36Sopenharmony_ci ret = cx2341x_ext_ctrls(&hdw->enc_ctl_state, 77662306a36Sopenharmony_ci 0, &cs, 77762306a36Sopenharmony_ci VIDIOC_S_EXT_CTRLS); 77862306a36Sopenharmony_ci if (!ret) hdw->enc_unsafe_stale = !0; 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci if (ret) return ret; 78162306a36Sopenharmony_ci hdw->enc_stale = !0; 78262306a36Sopenharmony_ci return 0; 78362306a36Sopenharmony_ci} 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_cistatic unsigned int ctrl_cx2341x_getv4lflags(struct pvr2_ctrl *cptr) 78662306a36Sopenharmony_ci{ 78762306a36Sopenharmony_ci struct v4l2_queryctrl qctrl = {}; 78862306a36Sopenharmony_ci struct pvr2_ctl_info *info; 78962306a36Sopenharmony_ci qctrl.id = cptr->info->v4l_id; 79062306a36Sopenharmony_ci cx2341x_ctrl_query(&cptr->hdw->enc_ctl_state,&qctrl); 79162306a36Sopenharmony_ci /* Strip out the const so we can adjust a function pointer. It's 79262306a36Sopenharmony_ci OK to do this here because we know this is a dynamically created 79362306a36Sopenharmony_ci control, so the underlying storage for the info pointer is (a) 79462306a36Sopenharmony_ci private to us, and (b) not in read-only storage. Either we do 79562306a36Sopenharmony_ci this or we significantly complicate the underlying control 79662306a36Sopenharmony_ci implementation. */ 79762306a36Sopenharmony_ci info = (struct pvr2_ctl_info *)(cptr->info); 79862306a36Sopenharmony_ci if (qctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) { 79962306a36Sopenharmony_ci if (info->set_value) { 80062306a36Sopenharmony_ci info->set_value = NULL; 80162306a36Sopenharmony_ci } 80262306a36Sopenharmony_ci } else { 80362306a36Sopenharmony_ci if (!(info->set_value)) { 80462306a36Sopenharmony_ci info->set_value = ctrl_cx2341x_set; 80562306a36Sopenharmony_ci } 80662306a36Sopenharmony_ci } 80762306a36Sopenharmony_ci return qctrl.flags; 80862306a36Sopenharmony_ci} 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_cistatic int ctrl_streamingenabled_get(struct pvr2_ctrl *cptr,int *vp) 81162306a36Sopenharmony_ci{ 81262306a36Sopenharmony_ci *vp = cptr->hdw->state_pipeline_req; 81362306a36Sopenharmony_ci return 0; 81462306a36Sopenharmony_ci} 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_cistatic int ctrl_masterstate_get(struct pvr2_ctrl *cptr,int *vp) 81762306a36Sopenharmony_ci{ 81862306a36Sopenharmony_ci *vp = cptr->hdw->master_state; 81962306a36Sopenharmony_ci return 0; 82062306a36Sopenharmony_ci} 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_cistatic int ctrl_hsm_get(struct pvr2_ctrl *cptr,int *vp) 82362306a36Sopenharmony_ci{ 82462306a36Sopenharmony_ci int result = pvr2_hdw_is_hsm(cptr->hdw); 82562306a36Sopenharmony_ci *vp = PVR2_CVAL_HSM_FULL; 82662306a36Sopenharmony_ci if (result < 0) *vp = PVR2_CVAL_HSM_FAIL; 82762306a36Sopenharmony_ci if (result) *vp = PVR2_CVAL_HSM_HIGH; 82862306a36Sopenharmony_ci return 0; 82962306a36Sopenharmony_ci} 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_cistatic int ctrl_stddetect_get(struct pvr2_ctrl *cptr, int *vp) 83262306a36Sopenharmony_ci{ 83362306a36Sopenharmony_ci *vp = pvr2_hdw_get_detected_std(cptr->hdw); 83462306a36Sopenharmony_ci return 0; 83562306a36Sopenharmony_ci} 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_cistatic int ctrl_stdavail_get(struct pvr2_ctrl *cptr,int *vp) 83862306a36Sopenharmony_ci{ 83962306a36Sopenharmony_ci *vp = cptr->hdw->std_mask_avail; 84062306a36Sopenharmony_ci return 0; 84162306a36Sopenharmony_ci} 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_cistatic int ctrl_stdavail_set(struct pvr2_ctrl *cptr,int m,int v) 84462306a36Sopenharmony_ci{ 84562306a36Sopenharmony_ci struct pvr2_hdw *hdw = cptr->hdw; 84662306a36Sopenharmony_ci v4l2_std_id ns; 84762306a36Sopenharmony_ci ns = hdw->std_mask_avail; 84862306a36Sopenharmony_ci ns = (ns & ~m) | (v & m); 84962306a36Sopenharmony_ci if (ns == hdw->std_mask_avail) return 0; 85062306a36Sopenharmony_ci hdw->std_mask_avail = ns; 85162306a36Sopenharmony_ci hdw->std_info_cur.def.type_bitmask.valid_bits = hdw->std_mask_avail; 85262306a36Sopenharmony_ci return 0; 85362306a36Sopenharmony_ci} 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_cistatic int ctrl_std_val_to_sym(struct pvr2_ctrl *cptr,int msk,int val, 85662306a36Sopenharmony_ci char *bufPtr,unsigned int bufSize, 85762306a36Sopenharmony_ci unsigned int *len) 85862306a36Sopenharmony_ci{ 85962306a36Sopenharmony_ci *len = pvr2_std_id_to_str(bufPtr,bufSize,msk & val); 86062306a36Sopenharmony_ci return 0; 86162306a36Sopenharmony_ci} 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_cistatic int ctrl_std_sym_to_val(struct pvr2_ctrl *cptr, 86462306a36Sopenharmony_ci const char *bufPtr,unsigned int bufSize, 86562306a36Sopenharmony_ci int *mskp,int *valp) 86662306a36Sopenharmony_ci{ 86762306a36Sopenharmony_ci v4l2_std_id id; 86862306a36Sopenharmony_ci if (!pvr2_std_str_to_id(&id, bufPtr, bufSize)) 86962306a36Sopenharmony_ci return -EINVAL; 87062306a36Sopenharmony_ci if (mskp) *mskp = id; 87162306a36Sopenharmony_ci if (valp) *valp = id; 87262306a36Sopenharmony_ci return 0; 87362306a36Sopenharmony_ci} 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_cistatic int ctrl_stdcur_get(struct pvr2_ctrl *cptr,int *vp) 87662306a36Sopenharmony_ci{ 87762306a36Sopenharmony_ci *vp = cptr->hdw->std_mask_cur; 87862306a36Sopenharmony_ci return 0; 87962306a36Sopenharmony_ci} 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_cistatic int ctrl_stdcur_set(struct pvr2_ctrl *cptr,int m,int v) 88262306a36Sopenharmony_ci{ 88362306a36Sopenharmony_ci struct pvr2_hdw *hdw = cptr->hdw; 88462306a36Sopenharmony_ci v4l2_std_id ns; 88562306a36Sopenharmony_ci ns = hdw->std_mask_cur; 88662306a36Sopenharmony_ci ns = (ns & ~m) | (v & m); 88762306a36Sopenharmony_ci if (ns == hdw->std_mask_cur) return 0; 88862306a36Sopenharmony_ci hdw->std_mask_cur = ns; 88962306a36Sopenharmony_ci hdw->std_dirty = !0; 89062306a36Sopenharmony_ci return 0; 89162306a36Sopenharmony_ci} 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_cistatic int ctrl_stdcur_is_dirty(struct pvr2_ctrl *cptr) 89462306a36Sopenharmony_ci{ 89562306a36Sopenharmony_ci return cptr->hdw->std_dirty != 0; 89662306a36Sopenharmony_ci} 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_cistatic void ctrl_stdcur_clear_dirty(struct pvr2_ctrl *cptr) 89962306a36Sopenharmony_ci{ 90062306a36Sopenharmony_ci cptr->hdw->std_dirty = 0; 90162306a36Sopenharmony_ci} 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_cistatic int ctrl_signal_get(struct pvr2_ctrl *cptr,int *vp) 90462306a36Sopenharmony_ci{ 90562306a36Sopenharmony_ci struct pvr2_hdw *hdw = cptr->hdw; 90662306a36Sopenharmony_ci pvr2_hdw_status_poll(hdw); 90762306a36Sopenharmony_ci *vp = hdw->tuner_signal_info.signal; 90862306a36Sopenharmony_ci return 0; 90962306a36Sopenharmony_ci} 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_cistatic int ctrl_audio_modes_present_get(struct pvr2_ctrl *cptr,int *vp) 91262306a36Sopenharmony_ci{ 91362306a36Sopenharmony_ci int val = 0; 91462306a36Sopenharmony_ci unsigned int subchan; 91562306a36Sopenharmony_ci struct pvr2_hdw *hdw = cptr->hdw; 91662306a36Sopenharmony_ci pvr2_hdw_status_poll(hdw); 91762306a36Sopenharmony_ci subchan = hdw->tuner_signal_info.rxsubchans; 91862306a36Sopenharmony_ci if (subchan & V4L2_TUNER_SUB_MONO) { 91962306a36Sopenharmony_ci val |= (1 << V4L2_TUNER_MODE_MONO); 92062306a36Sopenharmony_ci } 92162306a36Sopenharmony_ci if (subchan & V4L2_TUNER_SUB_STEREO) { 92262306a36Sopenharmony_ci val |= (1 << V4L2_TUNER_MODE_STEREO); 92362306a36Sopenharmony_ci } 92462306a36Sopenharmony_ci if (subchan & V4L2_TUNER_SUB_LANG1) { 92562306a36Sopenharmony_ci val |= (1 << V4L2_TUNER_MODE_LANG1); 92662306a36Sopenharmony_ci } 92762306a36Sopenharmony_ci if (subchan & V4L2_TUNER_SUB_LANG2) { 92862306a36Sopenharmony_ci val |= (1 << V4L2_TUNER_MODE_LANG2); 92962306a36Sopenharmony_ci } 93062306a36Sopenharmony_ci *vp = val; 93162306a36Sopenharmony_ci return 0; 93262306a36Sopenharmony_ci} 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci#define DEFINT(vmin,vmax) \ 93662306a36Sopenharmony_ci .type = pvr2_ctl_int, \ 93762306a36Sopenharmony_ci .def.type_int.min_value = vmin, \ 93862306a36Sopenharmony_ci .def.type_int.max_value = vmax 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci#define DEFENUM(tab) \ 94162306a36Sopenharmony_ci .type = pvr2_ctl_enum, \ 94262306a36Sopenharmony_ci .def.type_enum.count = ARRAY_SIZE(tab), \ 94362306a36Sopenharmony_ci .def.type_enum.value_names = tab 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci#define DEFBOOL \ 94662306a36Sopenharmony_ci .type = pvr2_ctl_bool 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci#define DEFMASK(msk,tab) \ 94962306a36Sopenharmony_ci .type = pvr2_ctl_bitmask, \ 95062306a36Sopenharmony_ci .def.type_bitmask.valid_bits = msk, \ 95162306a36Sopenharmony_ci .def.type_bitmask.bit_names = tab 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci#define DEFREF(vname) \ 95462306a36Sopenharmony_ci .set_value = ctrl_set_##vname, \ 95562306a36Sopenharmony_ci .get_value = ctrl_get_##vname, \ 95662306a36Sopenharmony_ci .is_dirty = ctrl_isdirty_##vname, \ 95762306a36Sopenharmony_ci .clear_dirty = ctrl_cleardirty_##vname 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci#define VCREATE_FUNCS(vname) \ 96162306a36Sopenharmony_cistatic int ctrl_get_##vname(struct pvr2_ctrl *cptr,int *vp) \ 96262306a36Sopenharmony_ci{*vp = cptr->hdw->vname##_val; return 0;} \ 96362306a36Sopenharmony_cistatic int ctrl_set_##vname(struct pvr2_ctrl *cptr,int m,int v) \ 96462306a36Sopenharmony_ci{cptr->hdw->vname##_val = v; cptr->hdw->vname##_dirty = !0; return 0;} \ 96562306a36Sopenharmony_cistatic int ctrl_isdirty_##vname(struct pvr2_ctrl *cptr) \ 96662306a36Sopenharmony_ci{return cptr->hdw->vname##_dirty != 0;} \ 96762306a36Sopenharmony_cistatic void ctrl_cleardirty_##vname(struct pvr2_ctrl *cptr) \ 96862306a36Sopenharmony_ci{cptr->hdw->vname##_dirty = 0;} 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ciVCREATE_FUNCS(brightness) 97162306a36Sopenharmony_ciVCREATE_FUNCS(contrast) 97262306a36Sopenharmony_ciVCREATE_FUNCS(saturation) 97362306a36Sopenharmony_ciVCREATE_FUNCS(hue) 97462306a36Sopenharmony_ciVCREATE_FUNCS(volume) 97562306a36Sopenharmony_ciVCREATE_FUNCS(balance) 97662306a36Sopenharmony_ciVCREATE_FUNCS(bass) 97762306a36Sopenharmony_ciVCREATE_FUNCS(treble) 97862306a36Sopenharmony_ciVCREATE_FUNCS(mute) 97962306a36Sopenharmony_ciVCREATE_FUNCS(cropl) 98062306a36Sopenharmony_ciVCREATE_FUNCS(cropt) 98162306a36Sopenharmony_ciVCREATE_FUNCS(cropw) 98262306a36Sopenharmony_ciVCREATE_FUNCS(croph) 98362306a36Sopenharmony_ciVCREATE_FUNCS(audiomode) 98462306a36Sopenharmony_ciVCREATE_FUNCS(res_hor) 98562306a36Sopenharmony_ciVCREATE_FUNCS(res_ver) 98662306a36Sopenharmony_ciVCREATE_FUNCS(srate) 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci/* Table definition of all controls which can be manipulated */ 98962306a36Sopenharmony_cistatic const struct pvr2_ctl_info control_defs[] = { 99062306a36Sopenharmony_ci { 99162306a36Sopenharmony_ci .v4l_id = V4L2_CID_BRIGHTNESS, 99262306a36Sopenharmony_ci .desc = "Brightness", 99362306a36Sopenharmony_ci .name = "brightness", 99462306a36Sopenharmony_ci .default_value = 128, 99562306a36Sopenharmony_ci DEFREF(brightness), 99662306a36Sopenharmony_ci DEFINT(0,255), 99762306a36Sopenharmony_ci },{ 99862306a36Sopenharmony_ci .v4l_id = V4L2_CID_CONTRAST, 99962306a36Sopenharmony_ci .desc = "Contrast", 100062306a36Sopenharmony_ci .name = "contrast", 100162306a36Sopenharmony_ci .default_value = 68, 100262306a36Sopenharmony_ci DEFREF(contrast), 100362306a36Sopenharmony_ci DEFINT(0,127), 100462306a36Sopenharmony_ci },{ 100562306a36Sopenharmony_ci .v4l_id = V4L2_CID_SATURATION, 100662306a36Sopenharmony_ci .desc = "Saturation", 100762306a36Sopenharmony_ci .name = "saturation", 100862306a36Sopenharmony_ci .default_value = 64, 100962306a36Sopenharmony_ci DEFREF(saturation), 101062306a36Sopenharmony_ci DEFINT(0,127), 101162306a36Sopenharmony_ci },{ 101262306a36Sopenharmony_ci .v4l_id = V4L2_CID_HUE, 101362306a36Sopenharmony_ci .desc = "Hue", 101462306a36Sopenharmony_ci .name = "hue", 101562306a36Sopenharmony_ci .default_value = 0, 101662306a36Sopenharmony_ci DEFREF(hue), 101762306a36Sopenharmony_ci DEFINT(-128,127), 101862306a36Sopenharmony_ci },{ 101962306a36Sopenharmony_ci .v4l_id = V4L2_CID_AUDIO_VOLUME, 102062306a36Sopenharmony_ci .desc = "Volume", 102162306a36Sopenharmony_ci .name = "volume", 102262306a36Sopenharmony_ci .default_value = 62000, 102362306a36Sopenharmony_ci DEFREF(volume), 102462306a36Sopenharmony_ci DEFINT(0,65535), 102562306a36Sopenharmony_ci },{ 102662306a36Sopenharmony_ci .v4l_id = V4L2_CID_AUDIO_BALANCE, 102762306a36Sopenharmony_ci .desc = "Balance", 102862306a36Sopenharmony_ci .name = "balance", 102962306a36Sopenharmony_ci .default_value = 0, 103062306a36Sopenharmony_ci DEFREF(balance), 103162306a36Sopenharmony_ci DEFINT(-32768,32767), 103262306a36Sopenharmony_ci },{ 103362306a36Sopenharmony_ci .v4l_id = V4L2_CID_AUDIO_BASS, 103462306a36Sopenharmony_ci .desc = "Bass", 103562306a36Sopenharmony_ci .name = "bass", 103662306a36Sopenharmony_ci .default_value = 0, 103762306a36Sopenharmony_ci DEFREF(bass), 103862306a36Sopenharmony_ci DEFINT(-32768,32767), 103962306a36Sopenharmony_ci },{ 104062306a36Sopenharmony_ci .v4l_id = V4L2_CID_AUDIO_TREBLE, 104162306a36Sopenharmony_ci .desc = "Treble", 104262306a36Sopenharmony_ci .name = "treble", 104362306a36Sopenharmony_ci .default_value = 0, 104462306a36Sopenharmony_ci DEFREF(treble), 104562306a36Sopenharmony_ci DEFINT(-32768,32767), 104662306a36Sopenharmony_ci },{ 104762306a36Sopenharmony_ci .v4l_id = V4L2_CID_AUDIO_MUTE, 104862306a36Sopenharmony_ci .desc = "Mute", 104962306a36Sopenharmony_ci .name = "mute", 105062306a36Sopenharmony_ci .default_value = 0, 105162306a36Sopenharmony_ci DEFREF(mute), 105262306a36Sopenharmony_ci DEFBOOL, 105362306a36Sopenharmony_ci }, { 105462306a36Sopenharmony_ci .desc = "Capture crop left margin", 105562306a36Sopenharmony_ci .name = "crop_left", 105662306a36Sopenharmony_ci .internal_id = PVR2_CID_CROPL, 105762306a36Sopenharmony_ci .default_value = 0, 105862306a36Sopenharmony_ci DEFREF(cropl), 105962306a36Sopenharmony_ci DEFINT(-129, 340), 106062306a36Sopenharmony_ci .get_min_value = ctrl_cropl_min_get, 106162306a36Sopenharmony_ci .get_max_value = ctrl_cropl_max_get, 106262306a36Sopenharmony_ci .get_def_value = ctrl_get_cropcapdl, 106362306a36Sopenharmony_ci }, { 106462306a36Sopenharmony_ci .desc = "Capture crop top margin", 106562306a36Sopenharmony_ci .name = "crop_top", 106662306a36Sopenharmony_ci .internal_id = PVR2_CID_CROPT, 106762306a36Sopenharmony_ci .default_value = 0, 106862306a36Sopenharmony_ci DEFREF(cropt), 106962306a36Sopenharmony_ci DEFINT(-35, 544), 107062306a36Sopenharmony_ci .get_min_value = ctrl_cropt_min_get, 107162306a36Sopenharmony_ci .get_max_value = ctrl_cropt_max_get, 107262306a36Sopenharmony_ci .get_def_value = ctrl_get_cropcapdt, 107362306a36Sopenharmony_ci }, { 107462306a36Sopenharmony_ci .desc = "Capture crop width", 107562306a36Sopenharmony_ci .name = "crop_width", 107662306a36Sopenharmony_ci .internal_id = PVR2_CID_CROPW, 107762306a36Sopenharmony_ci .default_value = 720, 107862306a36Sopenharmony_ci DEFREF(cropw), 107962306a36Sopenharmony_ci DEFINT(0, 864), 108062306a36Sopenharmony_ci .get_max_value = ctrl_cropw_max_get, 108162306a36Sopenharmony_ci .get_def_value = ctrl_get_cropcapdw, 108262306a36Sopenharmony_ci }, { 108362306a36Sopenharmony_ci .desc = "Capture crop height", 108462306a36Sopenharmony_ci .name = "crop_height", 108562306a36Sopenharmony_ci .internal_id = PVR2_CID_CROPH, 108662306a36Sopenharmony_ci .default_value = 480, 108762306a36Sopenharmony_ci DEFREF(croph), 108862306a36Sopenharmony_ci DEFINT(0, 576), 108962306a36Sopenharmony_ci .get_max_value = ctrl_croph_max_get, 109062306a36Sopenharmony_ci .get_def_value = ctrl_get_cropcapdh, 109162306a36Sopenharmony_ci }, { 109262306a36Sopenharmony_ci .desc = "Capture capability pixel aspect numerator", 109362306a36Sopenharmony_ci .name = "cropcap_pixel_numerator", 109462306a36Sopenharmony_ci .internal_id = PVR2_CID_CROPCAPPAN, 109562306a36Sopenharmony_ci .get_value = ctrl_get_cropcappan, 109662306a36Sopenharmony_ci }, { 109762306a36Sopenharmony_ci .desc = "Capture capability pixel aspect denominator", 109862306a36Sopenharmony_ci .name = "cropcap_pixel_denominator", 109962306a36Sopenharmony_ci .internal_id = PVR2_CID_CROPCAPPAD, 110062306a36Sopenharmony_ci .get_value = ctrl_get_cropcappad, 110162306a36Sopenharmony_ci }, { 110262306a36Sopenharmony_ci .desc = "Capture capability bounds top", 110362306a36Sopenharmony_ci .name = "cropcap_bounds_top", 110462306a36Sopenharmony_ci .internal_id = PVR2_CID_CROPCAPBT, 110562306a36Sopenharmony_ci .get_value = ctrl_get_cropcapbt, 110662306a36Sopenharmony_ci }, { 110762306a36Sopenharmony_ci .desc = "Capture capability bounds left", 110862306a36Sopenharmony_ci .name = "cropcap_bounds_left", 110962306a36Sopenharmony_ci .internal_id = PVR2_CID_CROPCAPBL, 111062306a36Sopenharmony_ci .get_value = ctrl_get_cropcapbl, 111162306a36Sopenharmony_ci }, { 111262306a36Sopenharmony_ci .desc = "Capture capability bounds width", 111362306a36Sopenharmony_ci .name = "cropcap_bounds_width", 111462306a36Sopenharmony_ci .internal_id = PVR2_CID_CROPCAPBW, 111562306a36Sopenharmony_ci .get_value = ctrl_get_cropcapbw, 111662306a36Sopenharmony_ci }, { 111762306a36Sopenharmony_ci .desc = "Capture capability bounds height", 111862306a36Sopenharmony_ci .name = "cropcap_bounds_height", 111962306a36Sopenharmony_ci .internal_id = PVR2_CID_CROPCAPBH, 112062306a36Sopenharmony_ci .get_value = ctrl_get_cropcapbh, 112162306a36Sopenharmony_ci },{ 112262306a36Sopenharmony_ci .desc = "Video Source", 112362306a36Sopenharmony_ci .name = "input", 112462306a36Sopenharmony_ci .internal_id = PVR2_CID_INPUT, 112562306a36Sopenharmony_ci .default_value = PVR2_CVAL_INPUT_TV, 112662306a36Sopenharmony_ci .check_value = ctrl_check_input, 112762306a36Sopenharmony_ci DEFREF(input), 112862306a36Sopenharmony_ci DEFENUM(control_values_input), 112962306a36Sopenharmony_ci },{ 113062306a36Sopenharmony_ci .desc = "Audio Mode", 113162306a36Sopenharmony_ci .name = "audio_mode", 113262306a36Sopenharmony_ci .internal_id = PVR2_CID_AUDIOMODE, 113362306a36Sopenharmony_ci .default_value = V4L2_TUNER_MODE_STEREO, 113462306a36Sopenharmony_ci DEFREF(audiomode), 113562306a36Sopenharmony_ci DEFENUM(control_values_audiomode), 113662306a36Sopenharmony_ci },{ 113762306a36Sopenharmony_ci .desc = "Horizontal capture resolution", 113862306a36Sopenharmony_ci .name = "resolution_hor", 113962306a36Sopenharmony_ci .internal_id = PVR2_CID_HRES, 114062306a36Sopenharmony_ci .default_value = 720, 114162306a36Sopenharmony_ci DEFREF(res_hor), 114262306a36Sopenharmony_ci DEFINT(19,720), 114362306a36Sopenharmony_ci },{ 114462306a36Sopenharmony_ci .desc = "Vertical capture resolution", 114562306a36Sopenharmony_ci .name = "resolution_ver", 114662306a36Sopenharmony_ci .internal_id = PVR2_CID_VRES, 114762306a36Sopenharmony_ci .default_value = 480, 114862306a36Sopenharmony_ci DEFREF(res_ver), 114962306a36Sopenharmony_ci DEFINT(17,576), 115062306a36Sopenharmony_ci /* Hook in check for video standard and adjust maximum 115162306a36Sopenharmony_ci depending on the standard. */ 115262306a36Sopenharmony_ci .get_max_value = ctrl_vres_max_get, 115362306a36Sopenharmony_ci .get_min_value = ctrl_vres_min_get, 115462306a36Sopenharmony_ci },{ 115562306a36Sopenharmony_ci .v4l_id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ, 115662306a36Sopenharmony_ci .default_value = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, 115762306a36Sopenharmony_ci .desc = "Audio Sampling Frequency", 115862306a36Sopenharmony_ci .name = "srate", 115962306a36Sopenharmony_ci DEFREF(srate), 116062306a36Sopenharmony_ci DEFENUM(control_values_srate), 116162306a36Sopenharmony_ci },{ 116262306a36Sopenharmony_ci .desc = "Tuner Frequency (Hz)", 116362306a36Sopenharmony_ci .name = "frequency", 116462306a36Sopenharmony_ci .internal_id = PVR2_CID_FREQUENCY, 116562306a36Sopenharmony_ci .default_value = 0, 116662306a36Sopenharmony_ci .set_value = ctrl_freq_set, 116762306a36Sopenharmony_ci .get_value = ctrl_freq_get, 116862306a36Sopenharmony_ci .is_dirty = ctrl_freq_is_dirty, 116962306a36Sopenharmony_ci .clear_dirty = ctrl_freq_clear_dirty, 117062306a36Sopenharmony_ci DEFINT(0,0), 117162306a36Sopenharmony_ci /* Hook in check for input value (tv/radio) and adjust 117262306a36Sopenharmony_ci max/min values accordingly */ 117362306a36Sopenharmony_ci .get_max_value = ctrl_freq_max_get, 117462306a36Sopenharmony_ci .get_min_value = ctrl_freq_min_get, 117562306a36Sopenharmony_ci },{ 117662306a36Sopenharmony_ci .desc = "Channel", 117762306a36Sopenharmony_ci .name = "channel", 117862306a36Sopenharmony_ci .set_value = ctrl_channel_set, 117962306a36Sopenharmony_ci .get_value = ctrl_channel_get, 118062306a36Sopenharmony_ci DEFINT(0,FREQTABLE_SIZE), 118162306a36Sopenharmony_ci },{ 118262306a36Sopenharmony_ci .desc = "Channel Program Frequency", 118362306a36Sopenharmony_ci .name = "freq_table_value", 118462306a36Sopenharmony_ci .set_value = ctrl_channelfreq_set, 118562306a36Sopenharmony_ci .get_value = ctrl_channelfreq_get, 118662306a36Sopenharmony_ci DEFINT(0,0), 118762306a36Sopenharmony_ci /* Hook in check for input value (tv/radio) and adjust 118862306a36Sopenharmony_ci max/min values accordingly */ 118962306a36Sopenharmony_ci .get_max_value = ctrl_freq_max_get, 119062306a36Sopenharmony_ci .get_min_value = ctrl_freq_min_get, 119162306a36Sopenharmony_ci },{ 119262306a36Sopenharmony_ci .desc = "Channel Program ID", 119362306a36Sopenharmony_ci .name = "freq_table_channel", 119462306a36Sopenharmony_ci .set_value = ctrl_channelprog_set, 119562306a36Sopenharmony_ci .get_value = ctrl_channelprog_get, 119662306a36Sopenharmony_ci DEFINT(0,FREQTABLE_SIZE), 119762306a36Sopenharmony_ci },{ 119862306a36Sopenharmony_ci .desc = "Streaming Enabled", 119962306a36Sopenharmony_ci .name = "streaming_enabled", 120062306a36Sopenharmony_ci .get_value = ctrl_streamingenabled_get, 120162306a36Sopenharmony_ci DEFBOOL, 120262306a36Sopenharmony_ci },{ 120362306a36Sopenharmony_ci .desc = "USB Speed", 120462306a36Sopenharmony_ci .name = "usb_speed", 120562306a36Sopenharmony_ci .get_value = ctrl_hsm_get, 120662306a36Sopenharmony_ci DEFENUM(control_values_hsm), 120762306a36Sopenharmony_ci },{ 120862306a36Sopenharmony_ci .desc = "Master State", 120962306a36Sopenharmony_ci .name = "master_state", 121062306a36Sopenharmony_ci .get_value = ctrl_masterstate_get, 121162306a36Sopenharmony_ci DEFENUM(pvr2_state_names), 121262306a36Sopenharmony_ci },{ 121362306a36Sopenharmony_ci .desc = "Signal Present", 121462306a36Sopenharmony_ci .name = "signal_present", 121562306a36Sopenharmony_ci .get_value = ctrl_signal_get, 121662306a36Sopenharmony_ci DEFINT(0,65535), 121762306a36Sopenharmony_ci },{ 121862306a36Sopenharmony_ci .desc = "Audio Modes Present", 121962306a36Sopenharmony_ci .name = "audio_modes_present", 122062306a36Sopenharmony_ci .get_value = ctrl_audio_modes_present_get, 122162306a36Sopenharmony_ci /* For this type we "borrow" the V4L2_TUNER_MODE enum from 122262306a36Sopenharmony_ci v4l. Nothing outside of this module cares about this, 122362306a36Sopenharmony_ci but I reuse it in order to also reuse the 122462306a36Sopenharmony_ci control_values_audiomode string table. */ 122562306a36Sopenharmony_ci DEFMASK(((1 << V4L2_TUNER_MODE_MONO)| 122662306a36Sopenharmony_ci (1 << V4L2_TUNER_MODE_STEREO)| 122762306a36Sopenharmony_ci (1 << V4L2_TUNER_MODE_LANG1)| 122862306a36Sopenharmony_ci (1 << V4L2_TUNER_MODE_LANG2)), 122962306a36Sopenharmony_ci control_values_audiomode), 123062306a36Sopenharmony_ci },{ 123162306a36Sopenharmony_ci .desc = "Video Standards Available Mask", 123262306a36Sopenharmony_ci .name = "video_standard_mask_available", 123362306a36Sopenharmony_ci .internal_id = PVR2_CID_STDAVAIL, 123462306a36Sopenharmony_ci .skip_init = !0, 123562306a36Sopenharmony_ci .get_value = ctrl_stdavail_get, 123662306a36Sopenharmony_ci .set_value = ctrl_stdavail_set, 123762306a36Sopenharmony_ci .val_to_sym = ctrl_std_val_to_sym, 123862306a36Sopenharmony_ci .sym_to_val = ctrl_std_sym_to_val, 123962306a36Sopenharmony_ci .type = pvr2_ctl_bitmask, 124062306a36Sopenharmony_ci },{ 124162306a36Sopenharmony_ci .desc = "Video Standards In Use Mask", 124262306a36Sopenharmony_ci .name = "video_standard_mask_active", 124362306a36Sopenharmony_ci .internal_id = PVR2_CID_STDCUR, 124462306a36Sopenharmony_ci .skip_init = !0, 124562306a36Sopenharmony_ci .get_value = ctrl_stdcur_get, 124662306a36Sopenharmony_ci .set_value = ctrl_stdcur_set, 124762306a36Sopenharmony_ci .is_dirty = ctrl_stdcur_is_dirty, 124862306a36Sopenharmony_ci .clear_dirty = ctrl_stdcur_clear_dirty, 124962306a36Sopenharmony_ci .val_to_sym = ctrl_std_val_to_sym, 125062306a36Sopenharmony_ci .sym_to_val = ctrl_std_sym_to_val, 125162306a36Sopenharmony_ci .type = pvr2_ctl_bitmask, 125262306a36Sopenharmony_ci },{ 125362306a36Sopenharmony_ci .desc = "Video Standards Detected Mask", 125462306a36Sopenharmony_ci .name = "video_standard_mask_detected", 125562306a36Sopenharmony_ci .internal_id = PVR2_CID_STDDETECT, 125662306a36Sopenharmony_ci .skip_init = !0, 125762306a36Sopenharmony_ci .get_value = ctrl_stddetect_get, 125862306a36Sopenharmony_ci .val_to_sym = ctrl_std_val_to_sym, 125962306a36Sopenharmony_ci .sym_to_val = ctrl_std_sym_to_val, 126062306a36Sopenharmony_ci .type = pvr2_ctl_bitmask, 126162306a36Sopenharmony_ci } 126262306a36Sopenharmony_ci}; 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci#define CTRLDEF_COUNT ARRAY_SIZE(control_defs) 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ciconst char *pvr2_config_get_name(enum pvr2_config cfg) 126862306a36Sopenharmony_ci{ 126962306a36Sopenharmony_ci switch (cfg) { 127062306a36Sopenharmony_ci case pvr2_config_empty: return "empty"; 127162306a36Sopenharmony_ci case pvr2_config_mpeg: return "mpeg"; 127262306a36Sopenharmony_ci case pvr2_config_vbi: return "vbi"; 127362306a36Sopenharmony_ci case pvr2_config_pcm: return "pcm"; 127462306a36Sopenharmony_ci case pvr2_config_rawvideo: return "raw video"; 127562306a36Sopenharmony_ci } 127662306a36Sopenharmony_ci return "<unknown>"; 127762306a36Sopenharmony_ci} 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_cistruct usb_device *pvr2_hdw_get_dev(struct pvr2_hdw *hdw) 128162306a36Sopenharmony_ci{ 128262306a36Sopenharmony_ci return hdw->usb_dev; 128362306a36Sopenharmony_ci} 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ciunsigned long pvr2_hdw_get_sn(struct pvr2_hdw *hdw) 128762306a36Sopenharmony_ci{ 128862306a36Sopenharmony_ci return hdw->serial_number; 128962306a36Sopenharmony_ci} 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ciconst char *pvr2_hdw_get_bus_info(struct pvr2_hdw *hdw) 129362306a36Sopenharmony_ci{ 129462306a36Sopenharmony_ci return hdw->bus_info; 129562306a36Sopenharmony_ci} 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ciconst char *pvr2_hdw_get_device_identifier(struct pvr2_hdw *hdw) 129962306a36Sopenharmony_ci{ 130062306a36Sopenharmony_ci return hdw->identifier; 130162306a36Sopenharmony_ci} 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ciunsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *hdw) 130562306a36Sopenharmony_ci{ 130662306a36Sopenharmony_ci return hdw->freqSelector ? hdw->freqValTelevision : hdw->freqValRadio; 130762306a36Sopenharmony_ci} 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci/* Set the currently tuned frequency and account for all possible 131062306a36Sopenharmony_ci driver-core side effects of this action. */ 131162306a36Sopenharmony_cistatic void pvr2_hdw_set_cur_freq(struct pvr2_hdw *hdw,unsigned long val) 131262306a36Sopenharmony_ci{ 131362306a36Sopenharmony_ci if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) { 131462306a36Sopenharmony_ci if (hdw->freqSelector) { 131562306a36Sopenharmony_ci /* Swing over to radio frequency selection */ 131662306a36Sopenharmony_ci hdw->freqSelector = 0; 131762306a36Sopenharmony_ci hdw->freqDirty = !0; 131862306a36Sopenharmony_ci } 131962306a36Sopenharmony_ci if (hdw->freqValRadio != val) { 132062306a36Sopenharmony_ci hdw->freqValRadio = val; 132162306a36Sopenharmony_ci hdw->freqSlotRadio = 0; 132262306a36Sopenharmony_ci hdw->freqDirty = !0; 132362306a36Sopenharmony_ci } 132462306a36Sopenharmony_ci } else { 132562306a36Sopenharmony_ci if (!(hdw->freqSelector)) { 132662306a36Sopenharmony_ci /* Swing over to television frequency selection */ 132762306a36Sopenharmony_ci hdw->freqSelector = 1; 132862306a36Sopenharmony_ci hdw->freqDirty = !0; 132962306a36Sopenharmony_ci } 133062306a36Sopenharmony_ci if (hdw->freqValTelevision != val) { 133162306a36Sopenharmony_ci hdw->freqValTelevision = val; 133262306a36Sopenharmony_ci hdw->freqSlotTelevision = 0; 133362306a36Sopenharmony_ci hdw->freqDirty = !0; 133462306a36Sopenharmony_ci } 133562306a36Sopenharmony_ci } 133662306a36Sopenharmony_ci} 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ciint pvr2_hdw_get_unit_number(struct pvr2_hdw *hdw) 133962306a36Sopenharmony_ci{ 134062306a36Sopenharmony_ci return hdw->unit_number; 134162306a36Sopenharmony_ci} 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci/* Attempt to locate one of the given set of files. Messages are logged 134562306a36Sopenharmony_ci appropriate to what has been found. The return value will be 0 or 134662306a36Sopenharmony_ci greater on success (it will be the index of the file name found) and 134762306a36Sopenharmony_ci fw_entry will be filled in. Otherwise a negative error is returned on 134862306a36Sopenharmony_ci failure. If the return value is -ENOENT then no viable firmware file 134962306a36Sopenharmony_ci could be located. */ 135062306a36Sopenharmony_cistatic int pvr2_locate_firmware(struct pvr2_hdw *hdw, 135162306a36Sopenharmony_ci const struct firmware **fw_entry, 135262306a36Sopenharmony_ci const char *fwtypename, 135362306a36Sopenharmony_ci unsigned int fwcount, 135462306a36Sopenharmony_ci const char *fwnames[]) 135562306a36Sopenharmony_ci{ 135662306a36Sopenharmony_ci unsigned int idx; 135762306a36Sopenharmony_ci int ret = -EINVAL; 135862306a36Sopenharmony_ci for (idx = 0; idx < fwcount; idx++) { 135962306a36Sopenharmony_ci ret = request_firmware(fw_entry, 136062306a36Sopenharmony_ci fwnames[idx], 136162306a36Sopenharmony_ci &hdw->usb_dev->dev); 136262306a36Sopenharmony_ci if (!ret) { 136362306a36Sopenharmony_ci trace_firmware("Located %s firmware: %s; uploading...", 136462306a36Sopenharmony_ci fwtypename, 136562306a36Sopenharmony_ci fwnames[idx]); 136662306a36Sopenharmony_ci return idx; 136762306a36Sopenharmony_ci } 136862306a36Sopenharmony_ci if (ret == -ENOENT) continue; 136962306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 137062306a36Sopenharmony_ci "request_firmware fatal error with code=%d",ret); 137162306a36Sopenharmony_ci return ret; 137262306a36Sopenharmony_ci } 137362306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 137462306a36Sopenharmony_ci "***WARNING*** Device %s firmware seems to be missing.", 137562306a36Sopenharmony_ci fwtypename); 137662306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 137762306a36Sopenharmony_ci "Did you install the pvrusb2 firmware files in their proper location?"); 137862306a36Sopenharmony_ci if (fwcount == 1) { 137962306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 138062306a36Sopenharmony_ci "request_firmware unable to locate %s file %s", 138162306a36Sopenharmony_ci fwtypename,fwnames[0]); 138262306a36Sopenharmony_ci } else { 138362306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 138462306a36Sopenharmony_ci "request_firmware unable to locate one of the following %s files:", 138562306a36Sopenharmony_ci fwtypename); 138662306a36Sopenharmony_ci for (idx = 0; idx < fwcount; idx++) { 138762306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 138862306a36Sopenharmony_ci "request_firmware: Failed to find %s", 138962306a36Sopenharmony_ci fwnames[idx]); 139062306a36Sopenharmony_ci } 139162306a36Sopenharmony_ci } 139262306a36Sopenharmony_ci return ret; 139362306a36Sopenharmony_ci} 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci/* 139762306a36Sopenharmony_ci * pvr2_upload_firmware1(). 139862306a36Sopenharmony_ci * 139962306a36Sopenharmony_ci * Send the 8051 firmware to the device. After the upload, arrange for 140062306a36Sopenharmony_ci * device to re-enumerate. 140162306a36Sopenharmony_ci * 140262306a36Sopenharmony_ci * NOTE : the pointer to the firmware data given by request_firmware() 140362306a36Sopenharmony_ci * is not suitable for an usb transaction. 140462306a36Sopenharmony_ci * 140562306a36Sopenharmony_ci */ 140662306a36Sopenharmony_cistatic int pvr2_upload_firmware1(struct pvr2_hdw *hdw) 140762306a36Sopenharmony_ci{ 140862306a36Sopenharmony_ci const struct firmware *fw_entry = NULL; 140962306a36Sopenharmony_ci void *fw_ptr; 141062306a36Sopenharmony_ci unsigned int pipe; 141162306a36Sopenharmony_ci unsigned int fwsize; 141262306a36Sopenharmony_ci int ret; 141362306a36Sopenharmony_ci u16 address; 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci if (!hdw->hdw_desc->fx2_firmware.cnt) { 141662306a36Sopenharmony_ci hdw->fw1_state = FW1_STATE_OK; 141762306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 141862306a36Sopenharmony_ci "Connected device type defines no firmware to upload; ignoring firmware"); 141962306a36Sopenharmony_ci return -ENOTTY; 142062306a36Sopenharmony_ci } 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci hdw->fw1_state = FW1_STATE_FAILED; // default result 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci trace_firmware("pvr2_upload_firmware1"); 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci ret = pvr2_locate_firmware(hdw,&fw_entry,"fx2 controller", 142762306a36Sopenharmony_ci hdw->hdw_desc->fx2_firmware.cnt, 142862306a36Sopenharmony_ci hdw->hdw_desc->fx2_firmware.lst); 142962306a36Sopenharmony_ci if (ret < 0) { 143062306a36Sopenharmony_ci if (ret == -ENOENT) hdw->fw1_state = FW1_STATE_MISSING; 143162306a36Sopenharmony_ci return ret; 143262306a36Sopenharmony_ci } 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci usb_clear_halt(hdw->usb_dev, usb_sndbulkpipe(hdw->usb_dev, 0 & 0x7f)); 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci pipe = usb_sndctrlpipe(hdw->usb_dev, 0); 143762306a36Sopenharmony_ci fwsize = fw_entry->size; 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci if ((fwsize != 0x2000) && 144062306a36Sopenharmony_ci (!(hdw->hdw_desc->flag_fx2_16kb && (fwsize == 0x4000)))) { 144162306a36Sopenharmony_ci if (hdw->hdw_desc->flag_fx2_16kb) { 144262306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 144362306a36Sopenharmony_ci "Wrong fx2 firmware size (expected 8192 or 16384, got %u)", 144462306a36Sopenharmony_ci fwsize); 144562306a36Sopenharmony_ci } else { 144662306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 144762306a36Sopenharmony_ci "Wrong fx2 firmware size (expected 8192, got %u)", 144862306a36Sopenharmony_ci fwsize); 144962306a36Sopenharmony_ci } 145062306a36Sopenharmony_ci release_firmware(fw_entry); 145162306a36Sopenharmony_ci return -ENOMEM; 145262306a36Sopenharmony_ci } 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci fw_ptr = kmalloc(0x800, GFP_KERNEL); 145562306a36Sopenharmony_ci if (fw_ptr == NULL){ 145662306a36Sopenharmony_ci release_firmware(fw_entry); 145762306a36Sopenharmony_ci return -ENOMEM; 145862306a36Sopenharmony_ci } 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci /* We have to hold the CPU during firmware upload. */ 146162306a36Sopenharmony_ci pvr2_hdw_cpureset_assert(hdw,1); 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci /* upload the firmware to address 0000-1fff in 2048 (=0x800) bytes 146462306a36Sopenharmony_ci chunk. */ 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci ret = 0; 146762306a36Sopenharmony_ci for (address = 0; address < fwsize; address += 0x800) { 146862306a36Sopenharmony_ci memcpy(fw_ptr, fw_entry->data + address, 0x800); 146962306a36Sopenharmony_ci ret += usb_control_msg(hdw->usb_dev, pipe, 0xa0, 0x40, address, 147062306a36Sopenharmony_ci 0, fw_ptr, 0x800, 1000); 147162306a36Sopenharmony_ci } 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci trace_firmware("Upload done, releasing device's CPU"); 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci /* Now release the CPU. It will disconnect and reconnect later. */ 147662306a36Sopenharmony_ci pvr2_hdw_cpureset_assert(hdw,0); 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci kfree(fw_ptr); 147962306a36Sopenharmony_ci release_firmware(fw_entry); 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci trace_firmware("Upload done (%d bytes sent)",ret); 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci /* We should have written fwsize bytes */ 148462306a36Sopenharmony_ci if (ret == fwsize) { 148562306a36Sopenharmony_ci hdw->fw1_state = FW1_STATE_RELOAD; 148662306a36Sopenharmony_ci return 0; 148762306a36Sopenharmony_ci } 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci return -EIO; 149062306a36Sopenharmony_ci} 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci/* 149462306a36Sopenharmony_ci * pvr2_upload_firmware2() 149562306a36Sopenharmony_ci * 149662306a36Sopenharmony_ci * This uploads encoder firmware on endpoint 2. 149762306a36Sopenharmony_ci * 149862306a36Sopenharmony_ci */ 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ciint pvr2_upload_firmware2(struct pvr2_hdw *hdw) 150162306a36Sopenharmony_ci{ 150262306a36Sopenharmony_ci const struct firmware *fw_entry = NULL; 150362306a36Sopenharmony_ci void *fw_ptr; 150462306a36Sopenharmony_ci unsigned int pipe, fw_len, fw_done, bcnt, icnt; 150562306a36Sopenharmony_ci int actual_length; 150662306a36Sopenharmony_ci int ret = 0; 150762306a36Sopenharmony_ci int fwidx; 150862306a36Sopenharmony_ci static const char *fw_files[] = { 150962306a36Sopenharmony_ci CX2341X_FIRM_ENC_FILENAME, 151062306a36Sopenharmony_ci }; 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci if (hdw->hdw_desc->flag_skip_cx23416_firmware) { 151362306a36Sopenharmony_ci return 0; 151462306a36Sopenharmony_ci } 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci trace_firmware("pvr2_upload_firmware2"); 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci ret = pvr2_locate_firmware(hdw,&fw_entry,"encoder", 151962306a36Sopenharmony_ci ARRAY_SIZE(fw_files), fw_files); 152062306a36Sopenharmony_ci if (ret < 0) return ret; 152162306a36Sopenharmony_ci fwidx = ret; 152262306a36Sopenharmony_ci ret = 0; 152362306a36Sopenharmony_ci /* Since we're about to completely reinitialize the encoder, 152462306a36Sopenharmony_ci invalidate our cached copy of its configuration state. Next 152562306a36Sopenharmony_ci time we configure the encoder, then we'll fully configure it. */ 152662306a36Sopenharmony_ci hdw->enc_cur_valid = 0; 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci /* Encoder is about to be reset so note that as far as we're 152962306a36Sopenharmony_ci concerned now, the encoder has never been run. */ 153062306a36Sopenharmony_ci del_timer_sync(&hdw->encoder_run_timer); 153162306a36Sopenharmony_ci if (hdw->state_encoder_runok) { 153262306a36Sopenharmony_ci hdw->state_encoder_runok = 0; 153362306a36Sopenharmony_ci trace_stbit("state_encoder_runok",hdw->state_encoder_runok); 153462306a36Sopenharmony_ci } 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci /* First prepare firmware loading */ 153762306a36Sopenharmony_ci ret |= pvr2_write_register(hdw, 0x0048, 0xffffffff); /*interrupt mask*/ 153862306a36Sopenharmony_ci ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000088); /*gpio dir*/ 153962306a36Sopenharmony_ci ret |= pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000008); /*gpio output state*/ 154062306a36Sopenharmony_ci ret |= pvr2_hdw_cmd_deep_reset(hdw); 154162306a36Sopenharmony_ci ret |= pvr2_write_register(hdw, 0xa064, 0x00000000); /*APU command*/ 154262306a36Sopenharmony_ci ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000408); /*gpio dir*/ 154362306a36Sopenharmony_ci ret |= pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000008); /*gpio output state*/ 154462306a36Sopenharmony_ci ret |= pvr2_write_register(hdw, 0x9058, 0xffffffed); /*VPU ctrl*/ 154562306a36Sopenharmony_ci ret |= pvr2_write_register(hdw, 0x9054, 0xfffffffd); /*reset hw blocks*/ 154662306a36Sopenharmony_ci ret |= pvr2_write_register(hdw, 0x07f8, 0x80000800); /*encoder SDRAM refresh*/ 154762306a36Sopenharmony_ci ret |= pvr2_write_register(hdw, 0x07fc, 0x0000001a); /*encoder SDRAM pre-charge*/ 154862306a36Sopenharmony_ci ret |= pvr2_write_register(hdw, 0x0700, 0x00000000); /*I2C clock*/ 154962306a36Sopenharmony_ci ret |= pvr2_write_register(hdw, 0xaa00, 0x00000000); /*unknown*/ 155062306a36Sopenharmony_ci ret |= pvr2_write_register(hdw, 0xaa04, 0x00057810); /*unknown*/ 155162306a36Sopenharmony_ci ret |= pvr2_write_register(hdw, 0xaa10, 0x00148500); /*unknown*/ 155262306a36Sopenharmony_ci ret |= pvr2_write_register(hdw, 0xaa18, 0x00840000); /*unknown*/ 155362306a36Sopenharmony_ci ret |= pvr2_issue_simple_cmd(hdw,FX2CMD_FWPOST1); 155462306a36Sopenharmony_ci ret |= pvr2_issue_simple_cmd(hdw,FX2CMD_MEMSEL | (1 << 8) | (0 << 16)); 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci if (ret) { 155762306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 155862306a36Sopenharmony_ci "firmware2 upload prep failed, ret=%d",ret); 155962306a36Sopenharmony_ci release_firmware(fw_entry); 156062306a36Sopenharmony_ci goto done; 156162306a36Sopenharmony_ci } 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci /* Now send firmware */ 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci fw_len = fw_entry->size; 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci if (fw_len % sizeof(u32)) { 156862306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 156962306a36Sopenharmony_ci "size of %s firmware must be a multiple of %zu bytes", 157062306a36Sopenharmony_ci fw_files[fwidx],sizeof(u32)); 157162306a36Sopenharmony_ci release_firmware(fw_entry); 157262306a36Sopenharmony_ci ret = -EINVAL; 157362306a36Sopenharmony_ci goto done; 157462306a36Sopenharmony_ci } 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci fw_ptr = kmalloc(FIRMWARE_CHUNK_SIZE, GFP_KERNEL); 157762306a36Sopenharmony_ci if (fw_ptr == NULL){ 157862306a36Sopenharmony_ci release_firmware(fw_entry); 157962306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 158062306a36Sopenharmony_ci "failed to allocate memory for firmware2 upload"); 158162306a36Sopenharmony_ci ret = -ENOMEM; 158262306a36Sopenharmony_ci goto done; 158362306a36Sopenharmony_ci } 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci pipe = usb_sndbulkpipe(hdw->usb_dev, PVR2_FIRMWARE_ENDPOINT); 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci fw_done = 0; 158862306a36Sopenharmony_ci for (fw_done = 0; fw_done < fw_len;) { 158962306a36Sopenharmony_ci bcnt = fw_len - fw_done; 159062306a36Sopenharmony_ci if (bcnt > FIRMWARE_CHUNK_SIZE) bcnt = FIRMWARE_CHUNK_SIZE; 159162306a36Sopenharmony_ci memcpy(fw_ptr, fw_entry->data + fw_done, bcnt); 159262306a36Sopenharmony_ci /* Usbsnoop log shows that we must swap bytes... */ 159362306a36Sopenharmony_ci /* Some background info: The data being swapped here is a 159462306a36Sopenharmony_ci firmware image destined for the mpeg encoder chip that 159562306a36Sopenharmony_ci lives at the other end of a USB endpoint. The encoder 159662306a36Sopenharmony_ci chip always talks in 32 bit chunks and its storage is 159762306a36Sopenharmony_ci organized into 32 bit words. However from the file 159862306a36Sopenharmony_ci system to the encoder chip everything is purely a byte 159962306a36Sopenharmony_ci stream. The firmware file's contents are always 32 bit 160062306a36Sopenharmony_ci swapped from what the encoder expects. Thus the need 160162306a36Sopenharmony_ci always exists to swap the bytes regardless of the endian 160262306a36Sopenharmony_ci type of the host processor and therefore swab32() makes 160362306a36Sopenharmony_ci the most sense. */ 160462306a36Sopenharmony_ci for (icnt = 0; icnt < bcnt/4 ; icnt++) 160562306a36Sopenharmony_ci ((u32 *)fw_ptr)[icnt] = swab32(((u32 *)fw_ptr)[icnt]); 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci ret |= usb_bulk_msg(hdw->usb_dev, pipe, fw_ptr,bcnt, 160862306a36Sopenharmony_ci &actual_length, 1000); 160962306a36Sopenharmony_ci ret |= (actual_length != bcnt); 161062306a36Sopenharmony_ci if (ret) break; 161162306a36Sopenharmony_ci fw_done += bcnt; 161262306a36Sopenharmony_ci } 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci trace_firmware("upload of %s : %i / %i ", 161562306a36Sopenharmony_ci fw_files[fwidx],fw_done,fw_len); 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_ci kfree(fw_ptr); 161862306a36Sopenharmony_ci release_firmware(fw_entry); 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci if (ret) { 162162306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 162262306a36Sopenharmony_ci "firmware2 upload transfer failure"); 162362306a36Sopenharmony_ci goto done; 162462306a36Sopenharmony_ci } 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci /* Finish upload */ 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci ret |= pvr2_write_register(hdw, 0x9054, 0xffffffff); /*reset hw blocks*/ 162962306a36Sopenharmony_ci ret |= pvr2_write_register(hdw, 0x9058, 0xffffffe8); /*VPU ctrl*/ 163062306a36Sopenharmony_ci ret |= pvr2_issue_simple_cmd(hdw,FX2CMD_MEMSEL | (1 << 8) | (0 << 16)); 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci if (ret) { 163362306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 163462306a36Sopenharmony_ci "firmware2 upload post-proc failure"); 163562306a36Sopenharmony_ci } 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ci done: 163862306a36Sopenharmony_ci if (hdw->hdw_desc->signal_routing_scheme == 163962306a36Sopenharmony_ci PVR2_ROUTING_SCHEME_GOTVIEW) { 164062306a36Sopenharmony_ci /* Ensure that GPIO 11 is set to output for GOTVIEW 164162306a36Sopenharmony_ci hardware. */ 164262306a36Sopenharmony_ci pvr2_hdw_gpio_chg_dir(hdw,(1 << 11),~0); 164362306a36Sopenharmony_ci } 164462306a36Sopenharmony_ci return ret; 164562306a36Sopenharmony_ci} 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_cistatic const char *pvr2_get_state_name(unsigned int st) 164962306a36Sopenharmony_ci{ 165062306a36Sopenharmony_ci if (st < ARRAY_SIZE(pvr2_state_names)) { 165162306a36Sopenharmony_ci return pvr2_state_names[st]; 165262306a36Sopenharmony_ci } 165362306a36Sopenharmony_ci return "???"; 165462306a36Sopenharmony_ci} 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_cistatic int pvr2_decoder_enable(struct pvr2_hdw *hdw,int enablefl) 165762306a36Sopenharmony_ci{ 165862306a36Sopenharmony_ci /* Even though we really only care about the video decoder chip at 165962306a36Sopenharmony_ci this point, we'll broadcast stream on/off to all sub-devices 166062306a36Sopenharmony_ci anyway, just in case somebody else wants to hear the 166162306a36Sopenharmony_ci command... */ 166262306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 stream=%s", 166362306a36Sopenharmony_ci (enablefl ? "on" : "off")); 166462306a36Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, 0, video, s_stream, enablefl); 166562306a36Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, 0, audio, s_stream, enablefl); 166662306a36Sopenharmony_ci if (hdw->decoder_client_id) { 166762306a36Sopenharmony_ci /* We get here if the encoder has been noticed. Otherwise 166862306a36Sopenharmony_ci we'll issue a warning to the user (which should 166962306a36Sopenharmony_ci normally never happen). */ 167062306a36Sopenharmony_ci return 0; 167162306a36Sopenharmony_ci } 167262306a36Sopenharmony_ci if (!hdw->flag_decoder_missed) { 167362306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 167462306a36Sopenharmony_ci "***WARNING*** No decoder present"); 167562306a36Sopenharmony_ci hdw->flag_decoder_missed = !0; 167662306a36Sopenharmony_ci trace_stbit("flag_decoder_missed", 167762306a36Sopenharmony_ci hdw->flag_decoder_missed); 167862306a36Sopenharmony_ci } 167962306a36Sopenharmony_ci return -EIO; 168062306a36Sopenharmony_ci} 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ciint pvr2_hdw_get_state(struct pvr2_hdw *hdw) 168462306a36Sopenharmony_ci{ 168562306a36Sopenharmony_ci return hdw->master_state; 168662306a36Sopenharmony_ci} 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_cistatic int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *hdw) 169062306a36Sopenharmony_ci{ 169162306a36Sopenharmony_ci if (!hdw->flag_tripped) return 0; 169262306a36Sopenharmony_ci hdw->flag_tripped = 0; 169362306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 169462306a36Sopenharmony_ci "Clearing driver error status"); 169562306a36Sopenharmony_ci return !0; 169662306a36Sopenharmony_ci} 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ciint pvr2_hdw_untrip(struct pvr2_hdw *hdw) 170062306a36Sopenharmony_ci{ 170162306a36Sopenharmony_ci int fl; 170262306a36Sopenharmony_ci LOCK_TAKE(hdw->big_lock); do { 170362306a36Sopenharmony_ci fl = pvr2_hdw_untrip_unlocked(hdw); 170462306a36Sopenharmony_ci } while (0); LOCK_GIVE(hdw->big_lock); 170562306a36Sopenharmony_ci if (fl) pvr2_hdw_state_sched(hdw); 170662306a36Sopenharmony_ci return 0; 170762306a36Sopenharmony_ci} 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ciint pvr2_hdw_get_streaming(struct pvr2_hdw *hdw) 171362306a36Sopenharmony_ci{ 171462306a36Sopenharmony_ci return hdw->state_pipeline_req != 0; 171562306a36Sopenharmony_ci} 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ciint pvr2_hdw_set_streaming(struct pvr2_hdw *hdw,int enable_flag) 171962306a36Sopenharmony_ci{ 172062306a36Sopenharmony_ci int ret,st; 172162306a36Sopenharmony_ci LOCK_TAKE(hdw->big_lock); 172262306a36Sopenharmony_ci pvr2_hdw_untrip_unlocked(hdw); 172362306a36Sopenharmony_ci if (!enable_flag != !hdw->state_pipeline_req) { 172462306a36Sopenharmony_ci hdw->state_pipeline_req = enable_flag != 0; 172562306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_START_STOP, 172662306a36Sopenharmony_ci "/*--TRACE_STREAM--*/ %s", 172762306a36Sopenharmony_ci enable_flag ? "enable" : "disable"); 172862306a36Sopenharmony_ci } 172962306a36Sopenharmony_ci pvr2_hdw_state_sched(hdw); 173062306a36Sopenharmony_ci LOCK_GIVE(hdw->big_lock); 173162306a36Sopenharmony_ci if ((ret = pvr2_hdw_wait(hdw,0)) < 0) return ret; 173262306a36Sopenharmony_ci if (enable_flag) { 173362306a36Sopenharmony_ci while ((st = hdw->master_state) != PVR2_STATE_RUN) { 173462306a36Sopenharmony_ci if (st != PVR2_STATE_READY) return -EIO; 173562306a36Sopenharmony_ci if ((ret = pvr2_hdw_wait(hdw,st)) < 0) return ret; 173662306a36Sopenharmony_ci } 173762306a36Sopenharmony_ci } 173862306a36Sopenharmony_ci return 0; 173962306a36Sopenharmony_ci} 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ciint pvr2_hdw_set_stream_type(struct pvr2_hdw *hdw,enum pvr2_config config) 174362306a36Sopenharmony_ci{ 174462306a36Sopenharmony_ci int fl; 174562306a36Sopenharmony_ci LOCK_TAKE(hdw->big_lock); 174662306a36Sopenharmony_ci if ((fl = (hdw->desired_stream_type != config)) != 0) { 174762306a36Sopenharmony_ci hdw->desired_stream_type = config; 174862306a36Sopenharmony_ci hdw->state_pipeline_config = 0; 174962306a36Sopenharmony_ci trace_stbit("state_pipeline_config", 175062306a36Sopenharmony_ci hdw->state_pipeline_config); 175162306a36Sopenharmony_ci pvr2_hdw_state_sched(hdw); 175262306a36Sopenharmony_ci } 175362306a36Sopenharmony_ci LOCK_GIVE(hdw->big_lock); 175462306a36Sopenharmony_ci if (fl) return 0; 175562306a36Sopenharmony_ci return pvr2_hdw_wait(hdw,0); 175662306a36Sopenharmony_ci} 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_cistatic int get_default_tuner_type(struct pvr2_hdw *hdw) 176062306a36Sopenharmony_ci{ 176162306a36Sopenharmony_ci int unit_number = hdw->unit_number; 176262306a36Sopenharmony_ci int tp = -1; 176362306a36Sopenharmony_ci if ((unit_number >= 0) && (unit_number < PVR_NUM)) { 176462306a36Sopenharmony_ci tp = tuner[unit_number]; 176562306a36Sopenharmony_ci } 176662306a36Sopenharmony_ci if (tp < 0) return -EINVAL; 176762306a36Sopenharmony_ci hdw->tuner_type = tp; 176862306a36Sopenharmony_ci hdw->tuner_updated = !0; 176962306a36Sopenharmony_ci return 0; 177062306a36Sopenharmony_ci} 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_cistatic v4l2_std_id get_default_standard(struct pvr2_hdw *hdw) 177462306a36Sopenharmony_ci{ 177562306a36Sopenharmony_ci int unit_number = hdw->unit_number; 177662306a36Sopenharmony_ci int tp = 0; 177762306a36Sopenharmony_ci if ((unit_number >= 0) && (unit_number < PVR_NUM)) { 177862306a36Sopenharmony_ci tp = video_std[unit_number]; 177962306a36Sopenharmony_ci if (tp) return tp; 178062306a36Sopenharmony_ci } 178162306a36Sopenharmony_ci return 0; 178262306a36Sopenharmony_ci} 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_cistatic unsigned int get_default_error_tolerance(struct pvr2_hdw *hdw) 178662306a36Sopenharmony_ci{ 178762306a36Sopenharmony_ci int unit_number = hdw->unit_number; 178862306a36Sopenharmony_ci int tp = 0; 178962306a36Sopenharmony_ci if ((unit_number >= 0) && (unit_number < PVR_NUM)) { 179062306a36Sopenharmony_ci tp = tolerance[unit_number]; 179162306a36Sopenharmony_ci } 179262306a36Sopenharmony_ci return tp; 179362306a36Sopenharmony_ci} 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_cistatic int pvr2_hdw_check_firmware(struct pvr2_hdw *hdw) 179762306a36Sopenharmony_ci{ 179862306a36Sopenharmony_ci /* Try a harmless request to fetch the eeprom's address over 179962306a36Sopenharmony_ci endpoint 1. See what happens. Only the full FX2 image can 180062306a36Sopenharmony_ci respond to this. If this probe fails then likely the FX2 180162306a36Sopenharmony_ci firmware needs be loaded. */ 180262306a36Sopenharmony_ci int result; 180362306a36Sopenharmony_ci LOCK_TAKE(hdw->ctl_lock); do { 180462306a36Sopenharmony_ci hdw->cmd_buffer[0] = FX2CMD_GET_EEPROM_ADDR; 180562306a36Sopenharmony_ci result = pvr2_send_request_ex(hdw,HZ*1,!0, 180662306a36Sopenharmony_ci hdw->cmd_buffer,1, 180762306a36Sopenharmony_ci hdw->cmd_buffer,1); 180862306a36Sopenharmony_ci if (result < 0) break; 180962306a36Sopenharmony_ci } while(0); LOCK_GIVE(hdw->ctl_lock); 181062306a36Sopenharmony_ci if (result) { 181162306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 181262306a36Sopenharmony_ci "Probe of device endpoint 1 result status %d", 181362306a36Sopenharmony_ci result); 181462306a36Sopenharmony_ci } else { 181562306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 181662306a36Sopenharmony_ci "Probe of device endpoint 1 succeeded"); 181762306a36Sopenharmony_ci } 181862306a36Sopenharmony_ci return result == 0; 181962306a36Sopenharmony_ci} 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_cistruct pvr2_std_hack { 182262306a36Sopenharmony_ci v4l2_std_id pat; /* Pattern to match */ 182362306a36Sopenharmony_ci v4l2_std_id msk; /* Which bits we care about */ 182462306a36Sopenharmony_ci v4l2_std_id std; /* What additional standards or default to set */ 182562306a36Sopenharmony_ci}; 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci/* This data structure labels specific combinations of standards from 182862306a36Sopenharmony_ci tveeprom that we'll try to recognize. If we recognize one, then assume 182962306a36Sopenharmony_ci a specified default standard to use. This is here because tveeprom only 183062306a36Sopenharmony_ci tells us about available standards not the intended default standard (if 183162306a36Sopenharmony_ci any) for the device in question. We guess the default based on what has 183262306a36Sopenharmony_ci been reported as available. Note that this is only for guessing a 183362306a36Sopenharmony_ci default - which can always be overridden explicitly - and if the user 183462306a36Sopenharmony_ci has otherwise named a default then that default will always be used in 183562306a36Sopenharmony_ci place of this table. */ 183662306a36Sopenharmony_cistatic const struct pvr2_std_hack std_eeprom_maps[] = { 183762306a36Sopenharmony_ci { /* PAL(B/G) */ 183862306a36Sopenharmony_ci .pat = V4L2_STD_B|V4L2_STD_GH, 183962306a36Sopenharmony_ci .std = V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_PAL_G, 184062306a36Sopenharmony_ci }, 184162306a36Sopenharmony_ci { /* NTSC(M) */ 184262306a36Sopenharmony_ci .pat = V4L2_STD_MN, 184362306a36Sopenharmony_ci .std = V4L2_STD_NTSC_M, 184462306a36Sopenharmony_ci }, 184562306a36Sopenharmony_ci { /* PAL(I) */ 184662306a36Sopenharmony_ci .pat = V4L2_STD_PAL_I, 184762306a36Sopenharmony_ci .std = V4L2_STD_PAL_I, 184862306a36Sopenharmony_ci }, 184962306a36Sopenharmony_ci { /* SECAM(L/L') */ 185062306a36Sopenharmony_ci .pat = V4L2_STD_SECAM_L|V4L2_STD_SECAM_LC, 185162306a36Sopenharmony_ci .std = V4L2_STD_SECAM_L|V4L2_STD_SECAM_LC, 185262306a36Sopenharmony_ci }, 185362306a36Sopenharmony_ci { /* PAL(D/D1/K) */ 185462306a36Sopenharmony_ci .pat = V4L2_STD_DK, 185562306a36Sopenharmony_ci .std = V4L2_STD_PAL_D|V4L2_STD_PAL_D1|V4L2_STD_PAL_K, 185662306a36Sopenharmony_ci }, 185762306a36Sopenharmony_ci}; 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_cistatic void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) 186062306a36Sopenharmony_ci{ 186162306a36Sopenharmony_ci char buf[40]; 186262306a36Sopenharmony_ci unsigned int bcnt; 186362306a36Sopenharmony_ci v4l2_std_id std1,std2,std3; 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci std1 = get_default_standard(hdw); 186662306a36Sopenharmony_ci std3 = std1 ? 0 : hdw->hdw_desc->default_std_mask; 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci bcnt = pvr2_std_id_to_str(buf,sizeof(buf),hdw->std_mask_eeprom); 186962306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_STD, 187062306a36Sopenharmony_ci "Supported video standard(s) reported available in hardware: %.*s", 187162306a36Sopenharmony_ci bcnt,buf); 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci hdw->std_mask_avail = hdw->std_mask_eeprom; 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_ci std2 = (std1|std3) & ~hdw->std_mask_avail; 187662306a36Sopenharmony_ci if (std2) { 187762306a36Sopenharmony_ci bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std2); 187862306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_STD, 187962306a36Sopenharmony_ci "Expanding supported video standards to include: %.*s", 188062306a36Sopenharmony_ci bcnt,buf); 188162306a36Sopenharmony_ci hdw->std_mask_avail |= std2; 188262306a36Sopenharmony_ci } 188362306a36Sopenharmony_ci 188462306a36Sopenharmony_ci hdw->std_info_cur.def.type_bitmask.valid_bits = hdw->std_mask_avail; 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ci if (std1) { 188762306a36Sopenharmony_ci bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std1); 188862306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_STD, 188962306a36Sopenharmony_ci "Initial video standard forced to %.*s", 189062306a36Sopenharmony_ci bcnt,buf); 189162306a36Sopenharmony_ci hdw->std_mask_cur = std1; 189262306a36Sopenharmony_ci hdw->std_dirty = !0; 189362306a36Sopenharmony_ci return; 189462306a36Sopenharmony_ci } 189562306a36Sopenharmony_ci if (std3) { 189662306a36Sopenharmony_ci bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std3); 189762306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_STD, 189862306a36Sopenharmony_ci "Initial video standard (determined by device type): %.*s", 189962306a36Sopenharmony_ci bcnt, buf); 190062306a36Sopenharmony_ci hdw->std_mask_cur = std3; 190162306a36Sopenharmony_ci hdw->std_dirty = !0; 190262306a36Sopenharmony_ci return; 190362306a36Sopenharmony_ci } 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_ci { 190662306a36Sopenharmony_ci unsigned int idx; 190762306a36Sopenharmony_ci for (idx = 0; idx < ARRAY_SIZE(std_eeprom_maps); idx++) { 190862306a36Sopenharmony_ci if (std_eeprom_maps[idx].msk ? 190962306a36Sopenharmony_ci ((std_eeprom_maps[idx].pat ^ 191062306a36Sopenharmony_ci hdw->std_mask_eeprom) & 191162306a36Sopenharmony_ci std_eeprom_maps[idx].msk) : 191262306a36Sopenharmony_ci (std_eeprom_maps[idx].pat != 191362306a36Sopenharmony_ci hdw->std_mask_eeprom)) continue; 191462306a36Sopenharmony_ci bcnt = pvr2_std_id_to_str(buf,sizeof(buf), 191562306a36Sopenharmony_ci std_eeprom_maps[idx].std); 191662306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_STD, 191762306a36Sopenharmony_ci "Initial video standard guessed as %.*s", 191862306a36Sopenharmony_ci bcnt,buf); 191962306a36Sopenharmony_ci hdw->std_mask_cur = std_eeprom_maps[idx].std; 192062306a36Sopenharmony_ci hdw->std_dirty = !0; 192162306a36Sopenharmony_ci return; 192262306a36Sopenharmony_ci } 192362306a36Sopenharmony_ci } 192462306a36Sopenharmony_ci 192562306a36Sopenharmony_ci} 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_cistatic unsigned int pvr2_copy_i2c_addr_list( 192962306a36Sopenharmony_ci unsigned short *dst, const unsigned char *src, 193062306a36Sopenharmony_ci unsigned int dst_max) 193162306a36Sopenharmony_ci{ 193262306a36Sopenharmony_ci unsigned int cnt = 0; 193362306a36Sopenharmony_ci if (!src) return 0; 193462306a36Sopenharmony_ci while (src[cnt] && (cnt + 1) < dst_max) { 193562306a36Sopenharmony_ci dst[cnt] = src[cnt]; 193662306a36Sopenharmony_ci cnt++; 193762306a36Sopenharmony_ci } 193862306a36Sopenharmony_ci dst[cnt] = I2C_CLIENT_END; 193962306a36Sopenharmony_ci return cnt; 194062306a36Sopenharmony_ci} 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_cistatic void pvr2_hdw_cx25840_vbi_hack(struct pvr2_hdw *hdw) 194462306a36Sopenharmony_ci{ 194562306a36Sopenharmony_ci /* 194662306a36Sopenharmony_ci Mike Isely <isely@pobox.com> 19-Nov-2006 - This bit of nuttiness 194762306a36Sopenharmony_ci for cx25840 causes that module to correctly set up its video 194862306a36Sopenharmony_ci scaling. This is really a problem in the cx25840 module itself, 194962306a36Sopenharmony_ci but we work around it here. The problem has not been seen in 195062306a36Sopenharmony_ci ivtv because there VBI is supported and set up. We don't do VBI 195162306a36Sopenharmony_ci here (at least not yet) and thus we never attempted to even set 195262306a36Sopenharmony_ci it up. 195362306a36Sopenharmony_ci */ 195462306a36Sopenharmony_ci struct v4l2_format fmt; 195562306a36Sopenharmony_ci if (hdw->decoder_client_id != PVR2_CLIENT_ID_CX25840) { 195662306a36Sopenharmony_ci /* We're not using a cx25840 so don't enable the hack */ 195762306a36Sopenharmony_ci return; 195862306a36Sopenharmony_ci } 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 196162306a36Sopenharmony_ci "Module ID %u: Executing cx25840 VBI hack", 196262306a36Sopenharmony_ci hdw->decoder_client_id); 196362306a36Sopenharmony_ci memset(&fmt, 0, sizeof(fmt)); 196462306a36Sopenharmony_ci fmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; 196562306a36Sopenharmony_ci fmt.fmt.sliced.service_lines[0][21] = V4L2_SLICED_CAPTION_525; 196662306a36Sopenharmony_ci fmt.fmt.sliced.service_lines[1][21] = V4L2_SLICED_CAPTION_525; 196762306a36Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, hdw->decoder_client_id, 196862306a36Sopenharmony_ci vbi, s_sliced_fmt, &fmt.fmt.sliced); 196962306a36Sopenharmony_ci} 197062306a36Sopenharmony_ci 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_cistatic int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw, 197362306a36Sopenharmony_ci const struct pvr2_device_client_desc *cd) 197462306a36Sopenharmony_ci{ 197562306a36Sopenharmony_ci const char *fname; 197662306a36Sopenharmony_ci unsigned char mid; 197762306a36Sopenharmony_ci struct v4l2_subdev *sd; 197862306a36Sopenharmony_ci unsigned int i2ccnt; 197962306a36Sopenharmony_ci const unsigned char *p; 198062306a36Sopenharmony_ci /* Arbitrary count - max # i2c addresses we will probe */ 198162306a36Sopenharmony_ci unsigned short i2caddr[25]; 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci mid = cd->module_id; 198462306a36Sopenharmony_ci fname = (mid < ARRAY_SIZE(module_names)) ? module_names[mid] : NULL; 198562306a36Sopenharmony_ci if (!fname) { 198662306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 198762306a36Sopenharmony_ci "Module ID %u for device %s has no name? The driver might have a configuration problem.", 198862306a36Sopenharmony_ci mid, 198962306a36Sopenharmony_ci hdw->hdw_desc->description); 199062306a36Sopenharmony_ci return -EINVAL; 199162306a36Sopenharmony_ci } 199262306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 199362306a36Sopenharmony_ci "Module ID %u (%s) for device %s being loaded...", 199462306a36Sopenharmony_ci mid, fname, 199562306a36Sopenharmony_ci hdw->hdw_desc->description); 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci i2ccnt = pvr2_copy_i2c_addr_list(i2caddr, cd->i2c_address_list, 199862306a36Sopenharmony_ci ARRAY_SIZE(i2caddr)); 199962306a36Sopenharmony_ci if (!i2ccnt && ((p = (mid < ARRAY_SIZE(module_i2c_addresses)) ? 200062306a36Sopenharmony_ci module_i2c_addresses[mid] : NULL) != NULL)) { 200162306a36Sopenharmony_ci /* Second chance: Try default i2c address list */ 200262306a36Sopenharmony_ci i2ccnt = pvr2_copy_i2c_addr_list(i2caddr, p, 200362306a36Sopenharmony_ci ARRAY_SIZE(i2caddr)); 200462306a36Sopenharmony_ci if (i2ccnt) { 200562306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 200662306a36Sopenharmony_ci "Module ID %u: Using default i2c address list", 200762306a36Sopenharmony_ci mid); 200862306a36Sopenharmony_ci } 200962306a36Sopenharmony_ci } 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ci if (!i2ccnt) { 201262306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 201362306a36Sopenharmony_ci "Module ID %u (%s) for device %s: No i2c addresses. The driver might have a configuration problem.", 201462306a36Sopenharmony_ci mid, fname, hdw->hdw_desc->description); 201562306a36Sopenharmony_ci return -EINVAL; 201662306a36Sopenharmony_ci } 201762306a36Sopenharmony_ci 201862306a36Sopenharmony_ci if (i2ccnt == 1) { 201962306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 202062306a36Sopenharmony_ci "Module ID %u: Setting up with specified i2c address 0x%x", 202162306a36Sopenharmony_ci mid, i2caddr[0]); 202262306a36Sopenharmony_ci sd = v4l2_i2c_new_subdev(&hdw->v4l2_dev, &hdw->i2c_adap, 202362306a36Sopenharmony_ci fname, i2caddr[0], NULL); 202462306a36Sopenharmony_ci } else { 202562306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 202662306a36Sopenharmony_ci "Module ID %u: Setting up with address probe list", 202762306a36Sopenharmony_ci mid); 202862306a36Sopenharmony_ci sd = v4l2_i2c_new_subdev(&hdw->v4l2_dev, &hdw->i2c_adap, 202962306a36Sopenharmony_ci fname, 0, i2caddr); 203062306a36Sopenharmony_ci } 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_ci if (!sd) { 203362306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 203462306a36Sopenharmony_ci "Module ID %u (%s) for device %s failed to load. Possible missing sub-device kernel module or initialization failure within module.", 203562306a36Sopenharmony_ci mid, fname, hdw->hdw_desc->description); 203662306a36Sopenharmony_ci return -EIO; 203762306a36Sopenharmony_ci } 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_ci /* Tag this sub-device instance with the module ID we know about. 204062306a36Sopenharmony_ci In other places we'll use that tag to determine if the instance 204162306a36Sopenharmony_ci requires special handling. */ 204262306a36Sopenharmony_ci sd->grp_id = mid; 204362306a36Sopenharmony_ci 204462306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INFO, "Attached sub-driver %s", fname); 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_ci 204762306a36Sopenharmony_ci /* client-specific setup... */ 204862306a36Sopenharmony_ci switch (mid) { 204962306a36Sopenharmony_ci case PVR2_CLIENT_ID_CX25840: 205062306a36Sopenharmony_ci case PVR2_CLIENT_ID_SAA7115: 205162306a36Sopenharmony_ci hdw->decoder_client_id = mid; 205262306a36Sopenharmony_ci break; 205362306a36Sopenharmony_ci default: break; 205462306a36Sopenharmony_ci } 205562306a36Sopenharmony_ci 205662306a36Sopenharmony_ci return 0; 205762306a36Sopenharmony_ci} 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_ci 206062306a36Sopenharmony_cistatic void pvr2_hdw_load_modules(struct pvr2_hdw *hdw) 206162306a36Sopenharmony_ci{ 206262306a36Sopenharmony_ci unsigned int idx; 206362306a36Sopenharmony_ci const struct pvr2_string_table *cm; 206462306a36Sopenharmony_ci const struct pvr2_device_client_table *ct; 206562306a36Sopenharmony_ci int okFl = !0; 206662306a36Sopenharmony_ci 206762306a36Sopenharmony_ci cm = &hdw->hdw_desc->client_modules; 206862306a36Sopenharmony_ci for (idx = 0; idx < cm->cnt; idx++) { 206962306a36Sopenharmony_ci request_module(cm->lst[idx]); 207062306a36Sopenharmony_ci } 207162306a36Sopenharmony_ci 207262306a36Sopenharmony_ci ct = &hdw->hdw_desc->client_table; 207362306a36Sopenharmony_ci for (idx = 0; idx < ct->cnt; idx++) { 207462306a36Sopenharmony_ci if (pvr2_hdw_load_subdev(hdw, &ct->lst[idx]) < 0) okFl = 0; 207562306a36Sopenharmony_ci } 207662306a36Sopenharmony_ci if (!okFl) { 207762306a36Sopenharmony_ci hdw->flag_modulefail = !0; 207862306a36Sopenharmony_ci pvr2_hdw_render_useless(hdw); 207962306a36Sopenharmony_ci } 208062306a36Sopenharmony_ci} 208162306a36Sopenharmony_ci 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_cistatic void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) 208462306a36Sopenharmony_ci{ 208562306a36Sopenharmony_ci int ret; 208662306a36Sopenharmony_ci unsigned int idx; 208762306a36Sopenharmony_ci struct pvr2_ctrl *cptr; 208862306a36Sopenharmony_ci int reloadFl = 0; 208962306a36Sopenharmony_ci if (hdw->hdw_desc->fx2_firmware.cnt) { 209062306a36Sopenharmony_ci if (!reloadFl) { 209162306a36Sopenharmony_ci reloadFl = 209262306a36Sopenharmony_ci (hdw->usb_intf->cur_altsetting->desc.bNumEndpoints 209362306a36Sopenharmony_ci == 0); 209462306a36Sopenharmony_ci if (reloadFl) { 209562306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 209662306a36Sopenharmony_ci "USB endpoint config looks strange; possibly firmware needs to be loaded"); 209762306a36Sopenharmony_ci } 209862306a36Sopenharmony_ci } 209962306a36Sopenharmony_ci if (!reloadFl) { 210062306a36Sopenharmony_ci reloadFl = !pvr2_hdw_check_firmware(hdw); 210162306a36Sopenharmony_ci if (reloadFl) { 210262306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 210362306a36Sopenharmony_ci "Check for FX2 firmware failed; possibly firmware needs to be loaded"); 210462306a36Sopenharmony_ci } 210562306a36Sopenharmony_ci } 210662306a36Sopenharmony_ci if (reloadFl) { 210762306a36Sopenharmony_ci if (pvr2_upload_firmware1(hdw) != 0) { 210862306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 210962306a36Sopenharmony_ci "Failure uploading firmware1"); 211062306a36Sopenharmony_ci } 211162306a36Sopenharmony_ci return; 211262306a36Sopenharmony_ci } 211362306a36Sopenharmony_ci } 211462306a36Sopenharmony_ci hdw->fw1_state = FW1_STATE_OK; 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci if (!pvr2_hdw_dev_ok(hdw)) return; 211762306a36Sopenharmony_ci 211862306a36Sopenharmony_ci hdw->force_dirty = !0; 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_ci if (!hdw->hdw_desc->flag_no_powerup) { 212162306a36Sopenharmony_ci pvr2_hdw_cmd_powerup(hdw); 212262306a36Sopenharmony_ci if (!pvr2_hdw_dev_ok(hdw)) return; 212362306a36Sopenharmony_ci } 212462306a36Sopenharmony_ci 212562306a36Sopenharmony_ci /* Take the IR chip out of reset, if appropriate */ 212662306a36Sopenharmony_ci if (hdw->ir_scheme_active == PVR2_IR_SCHEME_ZILOG) { 212762306a36Sopenharmony_ci pvr2_issue_simple_cmd(hdw, 212862306a36Sopenharmony_ci FX2CMD_HCW_ZILOG_RESET | 212962306a36Sopenharmony_ci (1 << 8) | 213062306a36Sopenharmony_ci ((0) << 16)); 213162306a36Sopenharmony_ci } 213262306a36Sopenharmony_ci 213362306a36Sopenharmony_ci /* This step MUST happen after the earlier powerup step */ 213462306a36Sopenharmony_ci pvr2_i2c_core_init(hdw); 213562306a36Sopenharmony_ci if (!pvr2_hdw_dev_ok(hdw)) return; 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_ci /* Reset demod only on Hauppauge 160xxx platform */ 213862306a36Sopenharmony_ci if (le16_to_cpu(hdw->usb_dev->descriptor.idVendor) == 0x2040 && 213962306a36Sopenharmony_ci (le16_to_cpu(hdw->usb_dev->descriptor.idProduct) == 0x7502 || 214062306a36Sopenharmony_ci le16_to_cpu(hdw->usb_dev->descriptor.idProduct) == 0x7510)) { 214162306a36Sopenharmony_ci pr_info("%s(): resetting 160xxx demod\n", __func__); 214262306a36Sopenharmony_ci /* TODO: not sure this is proper place to reset once only */ 214362306a36Sopenharmony_ci pvr2_issue_simple_cmd(hdw, 214462306a36Sopenharmony_ci FX2CMD_HCW_DEMOD_RESET_PIN | 214562306a36Sopenharmony_ci (1 << 8) | 214662306a36Sopenharmony_ci ((0) << 16)); 214762306a36Sopenharmony_ci usleep_range(10000, 10500); 214862306a36Sopenharmony_ci pvr2_issue_simple_cmd(hdw, 214962306a36Sopenharmony_ci FX2CMD_HCW_DEMOD_RESET_PIN | 215062306a36Sopenharmony_ci (1 << 8) | 215162306a36Sopenharmony_ci ((1) << 16)); 215262306a36Sopenharmony_ci usleep_range(10000, 10500); 215362306a36Sopenharmony_ci } 215462306a36Sopenharmony_ci 215562306a36Sopenharmony_ci pvr2_hdw_load_modules(hdw); 215662306a36Sopenharmony_ci if (!pvr2_hdw_dev_ok(hdw)) return; 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, 0, core, load_fw); 215962306a36Sopenharmony_ci 216062306a36Sopenharmony_ci for (idx = 0; idx < CTRLDEF_COUNT; idx++) { 216162306a36Sopenharmony_ci cptr = hdw->controls + idx; 216262306a36Sopenharmony_ci if (cptr->info->skip_init) continue; 216362306a36Sopenharmony_ci if (!cptr->info->set_value) continue; 216462306a36Sopenharmony_ci cptr->info->set_value(cptr,~0,cptr->info->default_value); 216562306a36Sopenharmony_ci } 216662306a36Sopenharmony_ci 216762306a36Sopenharmony_ci pvr2_hdw_cx25840_vbi_hack(hdw); 216862306a36Sopenharmony_ci 216962306a36Sopenharmony_ci /* Set up special default values for the television and radio 217062306a36Sopenharmony_ci frequencies here. It's not really important what these defaults 217162306a36Sopenharmony_ci are, but I set them to something usable in the Chicago area just 217262306a36Sopenharmony_ci to make driver testing a little easier. */ 217362306a36Sopenharmony_ci 217462306a36Sopenharmony_ci hdw->freqValTelevision = default_tv_freq; 217562306a36Sopenharmony_ci hdw->freqValRadio = default_radio_freq; 217662306a36Sopenharmony_ci 217762306a36Sopenharmony_ci // Do not use pvr2_reset_ctl_endpoints() here. It is not 217862306a36Sopenharmony_ci // thread-safe against the normal pvr2_send_request() mechanism. 217962306a36Sopenharmony_ci // (We should make it thread safe). 218062306a36Sopenharmony_ci 218162306a36Sopenharmony_ci if (hdw->hdw_desc->flag_has_hauppauge_rom) { 218262306a36Sopenharmony_ci ret = pvr2_hdw_get_eeprom_addr(hdw); 218362306a36Sopenharmony_ci if (!pvr2_hdw_dev_ok(hdw)) return; 218462306a36Sopenharmony_ci if (ret < 0) { 218562306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 218662306a36Sopenharmony_ci "Unable to determine location of eeprom, skipping"); 218762306a36Sopenharmony_ci } else { 218862306a36Sopenharmony_ci hdw->eeprom_addr = ret; 218962306a36Sopenharmony_ci pvr2_eeprom_analyze(hdw); 219062306a36Sopenharmony_ci if (!pvr2_hdw_dev_ok(hdw)) return; 219162306a36Sopenharmony_ci } 219262306a36Sopenharmony_ci } else { 219362306a36Sopenharmony_ci hdw->tuner_type = hdw->hdw_desc->default_tuner_type; 219462306a36Sopenharmony_ci hdw->tuner_updated = !0; 219562306a36Sopenharmony_ci hdw->std_mask_eeprom = V4L2_STD_ALL; 219662306a36Sopenharmony_ci } 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_ci if (hdw->serial_number) { 219962306a36Sopenharmony_ci idx = scnprintf(hdw->identifier, sizeof(hdw->identifier) - 1, 220062306a36Sopenharmony_ci "sn-%lu", hdw->serial_number); 220162306a36Sopenharmony_ci } else if (hdw->unit_number >= 0) { 220262306a36Sopenharmony_ci idx = scnprintf(hdw->identifier, sizeof(hdw->identifier) - 1, 220362306a36Sopenharmony_ci "unit-%c", 220462306a36Sopenharmony_ci hdw->unit_number + 'a'); 220562306a36Sopenharmony_ci } else { 220662306a36Sopenharmony_ci idx = scnprintf(hdw->identifier, sizeof(hdw->identifier) - 1, 220762306a36Sopenharmony_ci "unit-??"); 220862306a36Sopenharmony_ci } 220962306a36Sopenharmony_ci hdw->identifier[idx] = 0; 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_ci pvr2_hdw_setup_std(hdw); 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci if (!get_default_tuner_type(hdw)) { 221462306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 221562306a36Sopenharmony_ci "pvr2_hdw_setup: Tuner type overridden to %d", 221662306a36Sopenharmony_ci hdw->tuner_type); 221762306a36Sopenharmony_ci } 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_ci 222062306a36Sopenharmony_ci if (!pvr2_hdw_dev_ok(hdw)) return; 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_ci if (hdw->hdw_desc->signal_routing_scheme == 222362306a36Sopenharmony_ci PVR2_ROUTING_SCHEME_GOTVIEW) { 222462306a36Sopenharmony_ci /* Ensure that GPIO 11 is set to output for GOTVIEW 222562306a36Sopenharmony_ci hardware. */ 222662306a36Sopenharmony_ci pvr2_hdw_gpio_chg_dir(hdw,(1 << 11),~0); 222762306a36Sopenharmony_ci } 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_ci pvr2_hdw_commit_setup(hdw); 223062306a36Sopenharmony_ci 223162306a36Sopenharmony_ci hdw->vid_stream = pvr2_stream_create(); 223262306a36Sopenharmony_ci if (!pvr2_hdw_dev_ok(hdw)) return; 223362306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 223462306a36Sopenharmony_ci "pvr2_hdw_setup: video stream is %p",hdw->vid_stream); 223562306a36Sopenharmony_ci if (hdw->vid_stream) { 223662306a36Sopenharmony_ci idx = get_default_error_tolerance(hdw); 223762306a36Sopenharmony_ci if (idx) { 223862306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 223962306a36Sopenharmony_ci "pvr2_hdw_setup: video stream %p setting tolerance %u", 224062306a36Sopenharmony_ci hdw->vid_stream,idx); 224162306a36Sopenharmony_ci } 224262306a36Sopenharmony_ci pvr2_stream_setup(hdw->vid_stream,hdw->usb_dev, 224362306a36Sopenharmony_ci PVR2_VID_ENDPOINT,idx); 224462306a36Sopenharmony_ci } 224562306a36Sopenharmony_ci 224662306a36Sopenharmony_ci if (!pvr2_hdw_dev_ok(hdw)) return; 224762306a36Sopenharmony_ci 224862306a36Sopenharmony_ci hdw->flag_init_ok = !0; 224962306a36Sopenharmony_ci 225062306a36Sopenharmony_ci pvr2_hdw_state_sched(hdw); 225162306a36Sopenharmony_ci} 225262306a36Sopenharmony_ci 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_ci/* Set up the structure and attempt to put the device into a usable state. 225562306a36Sopenharmony_ci This can be a time-consuming operation, which is why it is not done 225662306a36Sopenharmony_ci internally as part of the create() step. */ 225762306a36Sopenharmony_cistatic void pvr2_hdw_setup(struct pvr2_hdw *hdw) 225862306a36Sopenharmony_ci{ 225962306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) begin",hdw); 226062306a36Sopenharmony_ci do { 226162306a36Sopenharmony_ci pvr2_hdw_setup_low(hdw); 226262306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 226362306a36Sopenharmony_ci "pvr2_hdw_setup(hdw=%p) done, ok=%d init_ok=%d", 226462306a36Sopenharmony_ci hdw,pvr2_hdw_dev_ok(hdw),hdw->flag_init_ok); 226562306a36Sopenharmony_ci if (pvr2_hdw_dev_ok(hdw)) { 226662306a36Sopenharmony_ci if (hdw->flag_init_ok) { 226762306a36Sopenharmony_ci pvr2_trace( 226862306a36Sopenharmony_ci PVR2_TRACE_INFO, 226962306a36Sopenharmony_ci "Device initialization completed successfully."); 227062306a36Sopenharmony_ci break; 227162306a36Sopenharmony_ci } 227262306a36Sopenharmony_ci if (hdw->fw1_state == FW1_STATE_RELOAD) { 227362306a36Sopenharmony_ci pvr2_trace( 227462306a36Sopenharmony_ci PVR2_TRACE_INFO, 227562306a36Sopenharmony_ci "Device microcontroller firmware (re)loaded; it should now reset and reconnect."); 227662306a36Sopenharmony_ci break; 227762306a36Sopenharmony_ci } 227862306a36Sopenharmony_ci pvr2_trace( 227962306a36Sopenharmony_ci PVR2_TRACE_ERROR_LEGS, 228062306a36Sopenharmony_ci "Device initialization was not successful."); 228162306a36Sopenharmony_ci if (hdw->fw1_state == FW1_STATE_MISSING) { 228262306a36Sopenharmony_ci pvr2_trace( 228362306a36Sopenharmony_ci PVR2_TRACE_ERROR_LEGS, 228462306a36Sopenharmony_ci "Giving up since device microcontroller firmware appears to be missing."); 228562306a36Sopenharmony_ci break; 228662306a36Sopenharmony_ci } 228762306a36Sopenharmony_ci } 228862306a36Sopenharmony_ci if (hdw->flag_modulefail) { 228962306a36Sopenharmony_ci pvr2_trace( 229062306a36Sopenharmony_ci PVR2_TRACE_ERROR_LEGS, 229162306a36Sopenharmony_ci "***WARNING*** pvrusb2 driver initialization failed due to the failure of one or more sub-device kernel modules."); 229262306a36Sopenharmony_ci pvr2_trace( 229362306a36Sopenharmony_ci PVR2_TRACE_ERROR_LEGS, 229462306a36Sopenharmony_ci "You need to resolve the failing condition before this driver can function. There should be some earlier messages giving more information about the problem."); 229562306a36Sopenharmony_ci break; 229662306a36Sopenharmony_ci } 229762306a36Sopenharmony_ci if (procreload) { 229862306a36Sopenharmony_ci pvr2_trace( 229962306a36Sopenharmony_ci PVR2_TRACE_ERROR_LEGS, 230062306a36Sopenharmony_ci "Attempting pvrusb2 recovery by reloading primary firmware."); 230162306a36Sopenharmony_ci pvr2_trace( 230262306a36Sopenharmony_ci PVR2_TRACE_ERROR_LEGS, 230362306a36Sopenharmony_ci "If this works, device should disconnect and reconnect in a sane state."); 230462306a36Sopenharmony_ci hdw->fw1_state = FW1_STATE_UNKNOWN; 230562306a36Sopenharmony_ci pvr2_upload_firmware1(hdw); 230662306a36Sopenharmony_ci } else { 230762306a36Sopenharmony_ci pvr2_trace( 230862306a36Sopenharmony_ci PVR2_TRACE_ERROR_LEGS, 230962306a36Sopenharmony_ci "***WARNING*** pvrusb2 device hardware appears to be jammed and I can't clear it."); 231062306a36Sopenharmony_ci pvr2_trace( 231162306a36Sopenharmony_ci PVR2_TRACE_ERROR_LEGS, 231262306a36Sopenharmony_ci "You might need to power cycle the pvrusb2 device in order to recover."); 231362306a36Sopenharmony_ci } 231462306a36Sopenharmony_ci } while (0); 231562306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) end",hdw); 231662306a36Sopenharmony_ci} 231762306a36Sopenharmony_ci 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci/* Perform second stage initialization. Set callback pointer first so that 232062306a36Sopenharmony_ci we can avoid a possible initialization race (if the kernel thread runs 232162306a36Sopenharmony_ci before the callback has been set). */ 232262306a36Sopenharmony_ciint pvr2_hdw_initialize(struct pvr2_hdw *hdw, 232362306a36Sopenharmony_ci void (*callback_func)(void *), 232462306a36Sopenharmony_ci void *callback_data) 232562306a36Sopenharmony_ci{ 232662306a36Sopenharmony_ci LOCK_TAKE(hdw->big_lock); do { 232762306a36Sopenharmony_ci if (hdw->flag_disconnected) { 232862306a36Sopenharmony_ci /* Handle a race here: If we're already 232962306a36Sopenharmony_ci disconnected by this point, then give up. If we 233062306a36Sopenharmony_ci get past this then we'll remain connected for 233162306a36Sopenharmony_ci the duration of initialization since the entire 233262306a36Sopenharmony_ci initialization sequence is now protected by the 233362306a36Sopenharmony_ci big_lock. */ 233462306a36Sopenharmony_ci break; 233562306a36Sopenharmony_ci } 233662306a36Sopenharmony_ci hdw->state_data = callback_data; 233762306a36Sopenharmony_ci hdw->state_func = callback_func; 233862306a36Sopenharmony_ci pvr2_hdw_setup(hdw); 233962306a36Sopenharmony_ci } while (0); LOCK_GIVE(hdw->big_lock); 234062306a36Sopenharmony_ci return hdw->flag_init_ok; 234162306a36Sopenharmony_ci} 234262306a36Sopenharmony_ci 234362306a36Sopenharmony_ci 234462306a36Sopenharmony_ci/* Create, set up, and return a structure for interacting with the 234562306a36Sopenharmony_ci underlying hardware. */ 234662306a36Sopenharmony_cistruct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, 234762306a36Sopenharmony_ci const struct usb_device_id *devid) 234862306a36Sopenharmony_ci{ 234962306a36Sopenharmony_ci unsigned int idx,cnt1,cnt2,m; 235062306a36Sopenharmony_ci struct pvr2_hdw *hdw = NULL; 235162306a36Sopenharmony_ci int valid_std_mask; 235262306a36Sopenharmony_ci struct pvr2_ctrl *cptr; 235362306a36Sopenharmony_ci struct usb_device *usb_dev; 235462306a36Sopenharmony_ci const struct pvr2_device_desc *hdw_desc; 235562306a36Sopenharmony_ci __u8 ifnum; 235662306a36Sopenharmony_ci struct v4l2_queryctrl qctrl; 235762306a36Sopenharmony_ci struct pvr2_ctl_info *ciptr; 235862306a36Sopenharmony_ci 235962306a36Sopenharmony_ci usb_dev = interface_to_usbdev(intf); 236062306a36Sopenharmony_ci 236162306a36Sopenharmony_ci hdw_desc = (const struct pvr2_device_desc *)(devid->driver_info); 236262306a36Sopenharmony_ci 236362306a36Sopenharmony_ci if (hdw_desc == NULL) { 236462306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, "pvr2_hdw_create: No device description pointer, unable to continue."); 236562306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 236662306a36Sopenharmony_ci "If you have a new device type, please contact Mike Isely <isely@pobox.com> to get it included in the driver"); 236762306a36Sopenharmony_ci goto fail; 236862306a36Sopenharmony_ci } 236962306a36Sopenharmony_ci 237062306a36Sopenharmony_ci hdw = kzalloc(sizeof(*hdw),GFP_KERNEL); 237162306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"", 237262306a36Sopenharmony_ci hdw,hdw_desc->description); 237362306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INFO, "Hardware description: %s", 237462306a36Sopenharmony_ci hdw_desc->description); 237562306a36Sopenharmony_ci if (hdw_desc->flag_is_experimental) { 237662306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INFO, "**********"); 237762306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INFO, 237862306a36Sopenharmony_ci "***WARNING*** Support for this device (%s) is experimental.", 237962306a36Sopenharmony_ci hdw_desc->description); 238062306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INFO, 238162306a36Sopenharmony_ci "Important functionality might not be entirely working."); 238262306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INFO, 238362306a36Sopenharmony_ci "Please consider contacting the driver author to help with further stabilization of the driver."); 238462306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INFO, "**********"); 238562306a36Sopenharmony_ci } 238662306a36Sopenharmony_ci if (!hdw) goto fail; 238762306a36Sopenharmony_ci 238862306a36Sopenharmony_ci timer_setup(&hdw->quiescent_timer, pvr2_hdw_quiescent_timeout, 0); 238962306a36Sopenharmony_ci 239062306a36Sopenharmony_ci timer_setup(&hdw->decoder_stabilization_timer, 239162306a36Sopenharmony_ci pvr2_hdw_decoder_stabilization_timeout, 0); 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_ci timer_setup(&hdw->encoder_wait_timer, pvr2_hdw_encoder_wait_timeout, 239462306a36Sopenharmony_ci 0); 239562306a36Sopenharmony_ci 239662306a36Sopenharmony_ci timer_setup(&hdw->encoder_run_timer, pvr2_hdw_encoder_run_timeout, 0); 239762306a36Sopenharmony_ci 239862306a36Sopenharmony_ci hdw->master_state = PVR2_STATE_DEAD; 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_ci init_waitqueue_head(&hdw->state_wait_data); 240162306a36Sopenharmony_ci 240262306a36Sopenharmony_ci hdw->tuner_signal_stale = !0; 240362306a36Sopenharmony_ci cx2341x_fill_defaults(&hdw->enc_ctl_state); 240462306a36Sopenharmony_ci 240562306a36Sopenharmony_ci /* Calculate which inputs are OK */ 240662306a36Sopenharmony_ci m = 0; 240762306a36Sopenharmony_ci if (hdw_desc->flag_has_analogtuner) m |= 1 << PVR2_CVAL_INPUT_TV; 240862306a36Sopenharmony_ci if (hdw_desc->digital_control_scheme != PVR2_DIGITAL_SCHEME_NONE) { 240962306a36Sopenharmony_ci m |= 1 << PVR2_CVAL_INPUT_DTV; 241062306a36Sopenharmony_ci } 241162306a36Sopenharmony_ci if (hdw_desc->flag_has_svideo) m |= 1 << PVR2_CVAL_INPUT_SVIDEO; 241262306a36Sopenharmony_ci if (hdw_desc->flag_has_composite) m |= 1 << PVR2_CVAL_INPUT_COMPOSITE; 241362306a36Sopenharmony_ci if (hdw_desc->flag_has_fmradio) m |= 1 << PVR2_CVAL_INPUT_RADIO; 241462306a36Sopenharmony_ci hdw->input_avail_mask = m; 241562306a36Sopenharmony_ci hdw->input_allowed_mask = hdw->input_avail_mask; 241662306a36Sopenharmony_ci 241762306a36Sopenharmony_ci /* If not a hybrid device, pathway_state never changes. So 241862306a36Sopenharmony_ci initialize it here to what it should forever be. */ 241962306a36Sopenharmony_ci if (!(hdw->input_avail_mask & (1 << PVR2_CVAL_INPUT_DTV))) { 242062306a36Sopenharmony_ci hdw->pathway_state = PVR2_PATHWAY_ANALOG; 242162306a36Sopenharmony_ci } else if (!(hdw->input_avail_mask & (1 << PVR2_CVAL_INPUT_TV))) { 242262306a36Sopenharmony_ci hdw->pathway_state = PVR2_PATHWAY_DIGITAL; 242362306a36Sopenharmony_ci } 242462306a36Sopenharmony_ci 242562306a36Sopenharmony_ci hdw->control_cnt = CTRLDEF_COUNT; 242662306a36Sopenharmony_ci hdw->control_cnt += MPEGDEF_COUNT; 242762306a36Sopenharmony_ci hdw->controls = kcalloc(hdw->control_cnt, sizeof(struct pvr2_ctrl), 242862306a36Sopenharmony_ci GFP_KERNEL); 242962306a36Sopenharmony_ci if (!hdw->controls) goto fail; 243062306a36Sopenharmony_ci hdw->hdw_desc = hdw_desc; 243162306a36Sopenharmony_ci hdw->ir_scheme_active = hdw->hdw_desc->ir_scheme; 243262306a36Sopenharmony_ci for (idx = 0; idx < hdw->control_cnt; idx++) { 243362306a36Sopenharmony_ci cptr = hdw->controls + idx; 243462306a36Sopenharmony_ci cptr->hdw = hdw; 243562306a36Sopenharmony_ci } 243662306a36Sopenharmony_ci for (idx = 0; idx < 32; idx++) { 243762306a36Sopenharmony_ci hdw->std_mask_ptrs[idx] = hdw->std_mask_names[idx]; 243862306a36Sopenharmony_ci } 243962306a36Sopenharmony_ci for (idx = 0; idx < CTRLDEF_COUNT; idx++) { 244062306a36Sopenharmony_ci cptr = hdw->controls + idx; 244162306a36Sopenharmony_ci cptr->info = control_defs+idx; 244262306a36Sopenharmony_ci } 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_ci /* Ensure that default input choice is a valid one. */ 244562306a36Sopenharmony_ci m = hdw->input_avail_mask; 244662306a36Sopenharmony_ci if (m) for (idx = 0; idx < (sizeof(m) << 3); idx++) { 244762306a36Sopenharmony_ci if (!((1UL << idx) & m)) continue; 244862306a36Sopenharmony_ci hdw->input_val = idx; 244962306a36Sopenharmony_ci break; 245062306a36Sopenharmony_ci } 245162306a36Sopenharmony_ci 245262306a36Sopenharmony_ci /* Define and configure additional controls from cx2341x module. */ 245362306a36Sopenharmony_ci hdw->mpeg_ctrl_info = kcalloc(MPEGDEF_COUNT, 245462306a36Sopenharmony_ci sizeof(*(hdw->mpeg_ctrl_info)), 245562306a36Sopenharmony_ci GFP_KERNEL); 245662306a36Sopenharmony_ci if (!hdw->mpeg_ctrl_info) goto fail; 245762306a36Sopenharmony_ci for (idx = 0; idx < MPEGDEF_COUNT; idx++) { 245862306a36Sopenharmony_ci cptr = hdw->controls + idx + CTRLDEF_COUNT; 245962306a36Sopenharmony_ci ciptr = &(hdw->mpeg_ctrl_info[idx].info); 246062306a36Sopenharmony_ci ciptr->desc = hdw->mpeg_ctrl_info[idx].desc; 246162306a36Sopenharmony_ci ciptr->name = mpeg_ids[idx].strid; 246262306a36Sopenharmony_ci ciptr->v4l_id = mpeg_ids[idx].id; 246362306a36Sopenharmony_ci ciptr->skip_init = !0; 246462306a36Sopenharmony_ci ciptr->get_value = ctrl_cx2341x_get; 246562306a36Sopenharmony_ci ciptr->get_v4lflags = ctrl_cx2341x_getv4lflags; 246662306a36Sopenharmony_ci ciptr->is_dirty = ctrl_cx2341x_is_dirty; 246762306a36Sopenharmony_ci if (!idx) ciptr->clear_dirty = ctrl_cx2341x_clear_dirty; 246862306a36Sopenharmony_ci qctrl.id = ciptr->v4l_id; 246962306a36Sopenharmony_ci cx2341x_ctrl_query(&hdw->enc_ctl_state,&qctrl); 247062306a36Sopenharmony_ci if (!(qctrl.flags & V4L2_CTRL_FLAG_READ_ONLY)) { 247162306a36Sopenharmony_ci ciptr->set_value = ctrl_cx2341x_set; 247262306a36Sopenharmony_ci } 247362306a36Sopenharmony_ci strscpy(hdw->mpeg_ctrl_info[idx].desc, qctrl.name, 247462306a36Sopenharmony_ci sizeof(hdw->mpeg_ctrl_info[idx].desc)); 247562306a36Sopenharmony_ci ciptr->default_value = qctrl.default_value; 247662306a36Sopenharmony_ci switch (qctrl.type) { 247762306a36Sopenharmony_ci default: 247862306a36Sopenharmony_ci case V4L2_CTRL_TYPE_INTEGER: 247962306a36Sopenharmony_ci ciptr->type = pvr2_ctl_int; 248062306a36Sopenharmony_ci ciptr->def.type_int.min_value = qctrl.minimum; 248162306a36Sopenharmony_ci ciptr->def.type_int.max_value = qctrl.maximum; 248262306a36Sopenharmony_ci break; 248362306a36Sopenharmony_ci case V4L2_CTRL_TYPE_BOOLEAN: 248462306a36Sopenharmony_ci ciptr->type = pvr2_ctl_bool; 248562306a36Sopenharmony_ci break; 248662306a36Sopenharmony_ci case V4L2_CTRL_TYPE_MENU: 248762306a36Sopenharmony_ci ciptr->type = pvr2_ctl_enum; 248862306a36Sopenharmony_ci ciptr->def.type_enum.value_names = 248962306a36Sopenharmony_ci cx2341x_ctrl_get_menu(&hdw->enc_ctl_state, 249062306a36Sopenharmony_ci ciptr->v4l_id); 249162306a36Sopenharmony_ci for (cnt1 = 0; 249262306a36Sopenharmony_ci ciptr->def.type_enum.value_names[cnt1] != NULL; 249362306a36Sopenharmony_ci cnt1++) { } 249462306a36Sopenharmony_ci ciptr->def.type_enum.count = cnt1; 249562306a36Sopenharmony_ci break; 249662306a36Sopenharmony_ci } 249762306a36Sopenharmony_ci cptr->info = ciptr; 249862306a36Sopenharmony_ci } 249962306a36Sopenharmony_ci 250062306a36Sopenharmony_ci // Initialize control data regarding video standard masks 250162306a36Sopenharmony_ci valid_std_mask = pvr2_std_get_usable(); 250262306a36Sopenharmony_ci for (idx = 0; idx < 32; idx++) { 250362306a36Sopenharmony_ci if (!(valid_std_mask & (1UL << idx))) continue; 250462306a36Sopenharmony_ci cnt1 = pvr2_std_id_to_str( 250562306a36Sopenharmony_ci hdw->std_mask_names[idx], 250662306a36Sopenharmony_ci sizeof(hdw->std_mask_names[idx])-1, 250762306a36Sopenharmony_ci 1UL << idx); 250862306a36Sopenharmony_ci hdw->std_mask_names[idx][cnt1] = 0; 250962306a36Sopenharmony_ci } 251062306a36Sopenharmony_ci cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDAVAIL); 251162306a36Sopenharmony_ci if (cptr) { 251262306a36Sopenharmony_ci memcpy(&hdw->std_info_avail,cptr->info, 251362306a36Sopenharmony_ci sizeof(hdw->std_info_avail)); 251462306a36Sopenharmony_ci cptr->info = &hdw->std_info_avail; 251562306a36Sopenharmony_ci hdw->std_info_avail.def.type_bitmask.bit_names = 251662306a36Sopenharmony_ci hdw->std_mask_ptrs; 251762306a36Sopenharmony_ci hdw->std_info_avail.def.type_bitmask.valid_bits = 251862306a36Sopenharmony_ci valid_std_mask; 251962306a36Sopenharmony_ci } 252062306a36Sopenharmony_ci cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR); 252162306a36Sopenharmony_ci if (cptr) { 252262306a36Sopenharmony_ci memcpy(&hdw->std_info_cur,cptr->info, 252362306a36Sopenharmony_ci sizeof(hdw->std_info_cur)); 252462306a36Sopenharmony_ci cptr->info = &hdw->std_info_cur; 252562306a36Sopenharmony_ci hdw->std_info_cur.def.type_bitmask.bit_names = 252662306a36Sopenharmony_ci hdw->std_mask_ptrs; 252762306a36Sopenharmony_ci hdw->std_info_cur.def.type_bitmask.valid_bits = 252862306a36Sopenharmony_ci valid_std_mask; 252962306a36Sopenharmony_ci } 253062306a36Sopenharmony_ci cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDDETECT); 253162306a36Sopenharmony_ci if (cptr) { 253262306a36Sopenharmony_ci memcpy(&hdw->std_info_detect,cptr->info, 253362306a36Sopenharmony_ci sizeof(hdw->std_info_detect)); 253462306a36Sopenharmony_ci cptr->info = &hdw->std_info_detect; 253562306a36Sopenharmony_ci hdw->std_info_detect.def.type_bitmask.bit_names = 253662306a36Sopenharmony_ci hdw->std_mask_ptrs; 253762306a36Sopenharmony_ci hdw->std_info_detect.def.type_bitmask.valid_bits = 253862306a36Sopenharmony_ci valid_std_mask; 253962306a36Sopenharmony_ci } 254062306a36Sopenharmony_ci 254162306a36Sopenharmony_ci hdw->cropcap_stale = !0; 254262306a36Sopenharmony_ci hdw->eeprom_addr = -1; 254362306a36Sopenharmony_ci hdw->unit_number = -1; 254462306a36Sopenharmony_ci hdw->v4l_minor_number_video = -1; 254562306a36Sopenharmony_ci hdw->v4l_minor_number_vbi = -1; 254662306a36Sopenharmony_ci hdw->v4l_minor_number_radio = -1; 254762306a36Sopenharmony_ci hdw->ctl_write_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL); 254862306a36Sopenharmony_ci if (!hdw->ctl_write_buffer) goto fail; 254962306a36Sopenharmony_ci hdw->ctl_read_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL); 255062306a36Sopenharmony_ci if (!hdw->ctl_read_buffer) goto fail; 255162306a36Sopenharmony_ci hdw->ctl_write_urb = usb_alloc_urb(0,GFP_KERNEL); 255262306a36Sopenharmony_ci if (!hdw->ctl_write_urb) goto fail; 255362306a36Sopenharmony_ci hdw->ctl_read_urb = usb_alloc_urb(0,GFP_KERNEL); 255462306a36Sopenharmony_ci if (!hdw->ctl_read_urb) goto fail; 255562306a36Sopenharmony_ci 255662306a36Sopenharmony_ci if (v4l2_device_register(&intf->dev, &hdw->v4l2_dev) != 0) { 255762306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 255862306a36Sopenharmony_ci "Error registering with v4l core, giving up"); 255962306a36Sopenharmony_ci goto fail; 256062306a36Sopenharmony_ci } 256162306a36Sopenharmony_ci mutex_lock(&pvr2_unit_mtx); 256262306a36Sopenharmony_ci do { 256362306a36Sopenharmony_ci for (idx = 0; idx < PVR_NUM; idx++) { 256462306a36Sopenharmony_ci if (unit_pointers[idx]) continue; 256562306a36Sopenharmony_ci hdw->unit_number = idx; 256662306a36Sopenharmony_ci unit_pointers[idx] = hdw; 256762306a36Sopenharmony_ci break; 256862306a36Sopenharmony_ci } 256962306a36Sopenharmony_ci } while (0); 257062306a36Sopenharmony_ci mutex_unlock(&pvr2_unit_mtx); 257162306a36Sopenharmony_ci 257262306a36Sopenharmony_ci INIT_WORK(&hdw->workpoll, pvr2_hdw_worker_poll); 257362306a36Sopenharmony_ci 257462306a36Sopenharmony_ci if (hdw->unit_number == -1) 257562306a36Sopenharmony_ci goto fail; 257662306a36Sopenharmony_ci 257762306a36Sopenharmony_ci cnt1 = 0; 257862306a36Sopenharmony_ci cnt2 = scnprintf(hdw->name+cnt1,sizeof(hdw->name)-cnt1,"pvrusb2"); 257962306a36Sopenharmony_ci cnt1 += cnt2; 258062306a36Sopenharmony_ci if (hdw->unit_number >= 0) { 258162306a36Sopenharmony_ci cnt2 = scnprintf(hdw->name+cnt1,sizeof(hdw->name)-cnt1,"_%c", 258262306a36Sopenharmony_ci ('a' + hdw->unit_number)); 258362306a36Sopenharmony_ci cnt1 += cnt2; 258462306a36Sopenharmony_ci } 258562306a36Sopenharmony_ci if (cnt1 >= sizeof(hdw->name)) cnt1 = sizeof(hdw->name)-1; 258662306a36Sopenharmony_ci hdw->name[cnt1] = 0; 258762306a36Sopenharmony_ci 258862306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s", 258962306a36Sopenharmony_ci hdw->unit_number,hdw->name); 259062306a36Sopenharmony_ci 259162306a36Sopenharmony_ci hdw->tuner_type = -1; 259262306a36Sopenharmony_ci hdw->flag_ok = !0; 259362306a36Sopenharmony_ci 259462306a36Sopenharmony_ci hdw->usb_intf = intf; 259562306a36Sopenharmony_ci hdw->usb_dev = usb_dev; 259662306a36Sopenharmony_ci 259762306a36Sopenharmony_ci usb_make_path(hdw->usb_dev, hdw->bus_info, sizeof(hdw->bus_info)); 259862306a36Sopenharmony_ci 259962306a36Sopenharmony_ci ifnum = hdw->usb_intf->cur_altsetting->desc.bInterfaceNumber; 260062306a36Sopenharmony_ci usb_set_interface(hdw->usb_dev,ifnum,0); 260162306a36Sopenharmony_ci 260262306a36Sopenharmony_ci mutex_init(&hdw->ctl_lock_mutex); 260362306a36Sopenharmony_ci mutex_init(&hdw->big_lock_mutex); 260462306a36Sopenharmony_ci 260562306a36Sopenharmony_ci return hdw; 260662306a36Sopenharmony_ci fail: 260762306a36Sopenharmony_ci if (hdw) { 260862306a36Sopenharmony_ci timer_shutdown_sync(&hdw->quiescent_timer); 260962306a36Sopenharmony_ci timer_shutdown_sync(&hdw->decoder_stabilization_timer); 261062306a36Sopenharmony_ci timer_shutdown_sync(&hdw->encoder_run_timer); 261162306a36Sopenharmony_ci timer_shutdown_sync(&hdw->encoder_wait_timer); 261262306a36Sopenharmony_ci flush_work(&hdw->workpoll); 261362306a36Sopenharmony_ci v4l2_device_unregister(&hdw->v4l2_dev); 261462306a36Sopenharmony_ci usb_free_urb(hdw->ctl_read_urb); 261562306a36Sopenharmony_ci usb_free_urb(hdw->ctl_write_urb); 261662306a36Sopenharmony_ci kfree(hdw->ctl_read_buffer); 261762306a36Sopenharmony_ci kfree(hdw->ctl_write_buffer); 261862306a36Sopenharmony_ci kfree(hdw->controls); 261962306a36Sopenharmony_ci kfree(hdw->mpeg_ctrl_info); 262062306a36Sopenharmony_ci kfree(hdw); 262162306a36Sopenharmony_ci } 262262306a36Sopenharmony_ci return NULL; 262362306a36Sopenharmony_ci} 262462306a36Sopenharmony_ci 262562306a36Sopenharmony_ci 262662306a36Sopenharmony_ci/* Remove _all_ associations between this driver and the underlying USB 262762306a36Sopenharmony_ci layer. */ 262862306a36Sopenharmony_cistatic void pvr2_hdw_remove_usb_stuff(struct pvr2_hdw *hdw) 262962306a36Sopenharmony_ci{ 263062306a36Sopenharmony_ci if (hdw->flag_disconnected) return; 263162306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_remove_usb_stuff: hdw=%p",hdw); 263262306a36Sopenharmony_ci if (hdw->ctl_read_urb) { 263362306a36Sopenharmony_ci usb_kill_urb(hdw->ctl_read_urb); 263462306a36Sopenharmony_ci usb_free_urb(hdw->ctl_read_urb); 263562306a36Sopenharmony_ci hdw->ctl_read_urb = NULL; 263662306a36Sopenharmony_ci } 263762306a36Sopenharmony_ci if (hdw->ctl_write_urb) { 263862306a36Sopenharmony_ci usb_kill_urb(hdw->ctl_write_urb); 263962306a36Sopenharmony_ci usb_free_urb(hdw->ctl_write_urb); 264062306a36Sopenharmony_ci hdw->ctl_write_urb = NULL; 264162306a36Sopenharmony_ci } 264262306a36Sopenharmony_ci if (hdw->ctl_read_buffer) { 264362306a36Sopenharmony_ci kfree(hdw->ctl_read_buffer); 264462306a36Sopenharmony_ci hdw->ctl_read_buffer = NULL; 264562306a36Sopenharmony_ci } 264662306a36Sopenharmony_ci if (hdw->ctl_write_buffer) { 264762306a36Sopenharmony_ci kfree(hdw->ctl_write_buffer); 264862306a36Sopenharmony_ci hdw->ctl_write_buffer = NULL; 264962306a36Sopenharmony_ci } 265062306a36Sopenharmony_ci hdw->flag_disconnected = !0; 265162306a36Sopenharmony_ci /* If we don't do this, then there will be a dangling struct device 265262306a36Sopenharmony_ci reference to our disappearing device persisting inside the V4L 265362306a36Sopenharmony_ci core... */ 265462306a36Sopenharmony_ci v4l2_device_disconnect(&hdw->v4l2_dev); 265562306a36Sopenharmony_ci hdw->usb_dev = NULL; 265662306a36Sopenharmony_ci hdw->usb_intf = NULL; 265762306a36Sopenharmony_ci pvr2_hdw_render_useless(hdw); 265862306a36Sopenharmony_ci} 265962306a36Sopenharmony_ci 266062306a36Sopenharmony_civoid pvr2_hdw_set_v4l2_dev(struct pvr2_hdw *hdw, struct video_device *vdev) 266162306a36Sopenharmony_ci{ 266262306a36Sopenharmony_ci vdev->v4l2_dev = &hdw->v4l2_dev; 266362306a36Sopenharmony_ci} 266462306a36Sopenharmony_ci 266562306a36Sopenharmony_ci/* Destroy hardware interaction structure */ 266662306a36Sopenharmony_civoid pvr2_hdw_destroy(struct pvr2_hdw *hdw) 266762306a36Sopenharmony_ci{ 266862306a36Sopenharmony_ci if (!hdw) return; 266962306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_destroy: hdw=%p",hdw); 267062306a36Sopenharmony_ci flush_work(&hdw->workpoll); 267162306a36Sopenharmony_ci timer_shutdown_sync(&hdw->quiescent_timer); 267262306a36Sopenharmony_ci timer_shutdown_sync(&hdw->decoder_stabilization_timer); 267362306a36Sopenharmony_ci timer_shutdown_sync(&hdw->encoder_run_timer); 267462306a36Sopenharmony_ci timer_shutdown_sync(&hdw->encoder_wait_timer); 267562306a36Sopenharmony_ci if (hdw->fw_buffer) { 267662306a36Sopenharmony_ci kfree(hdw->fw_buffer); 267762306a36Sopenharmony_ci hdw->fw_buffer = NULL; 267862306a36Sopenharmony_ci } 267962306a36Sopenharmony_ci if (hdw->vid_stream) { 268062306a36Sopenharmony_ci pvr2_stream_destroy(hdw->vid_stream); 268162306a36Sopenharmony_ci hdw->vid_stream = NULL; 268262306a36Sopenharmony_ci } 268362306a36Sopenharmony_ci v4l2_device_unregister(&hdw->v4l2_dev); 268462306a36Sopenharmony_ci pvr2_hdw_disconnect(hdw); 268562306a36Sopenharmony_ci mutex_lock(&pvr2_unit_mtx); 268662306a36Sopenharmony_ci do { 268762306a36Sopenharmony_ci if ((hdw->unit_number >= 0) && 268862306a36Sopenharmony_ci (hdw->unit_number < PVR_NUM) && 268962306a36Sopenharmony_ci (unit_pointers[hdw->unit_number] == hdw)) { 269062306a36Sopenharmony_ci unit_pointers[hdw->unit_number] = NULL; 269162306a36Sopenharmony_ci } 269262306a36Sopenharmony_ci } while (0); 269362306a36Sopenharmony_ci mutex_unlock(&pvr2_unit_mtx); 269462306a36Sopenharmony_ci kfree(hdw->controls); 269562306a36Sopenharmony_ci kfree(hdw->mpeg_ctrl_info); 269662306a36Sopenharmony_ci kfree(hdw); 269762306a36Sopenharmony_ci} 269862306a36Sopenharmony_ci 269962306a36Sopenharmony_ci 270062306a36Sopenharmony_ciint pvr2_hdw_dev_ok(struct pvr2_hdw *hdw) 270162306a36Sopenharmony_ci{ 270262306a36Sopenharmony_ci return (hdw && hdw->flag_ok); 270362306a36Sopenharmony_ci} 270462306a36Sopenharmony_ci 270562306a36Sopenharmony_ci 270662306a36Sopenharmony_ci/* Called when hardware has been unplugged */ 270762306a36Sopenharmony_civoid pvr2_hdw_disconnect(struct pvr2_hdw *hdw) 270862306a36Sopenharmony_ci{ 270962306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_disconnect(hdw=%p)",hdw); 271062306a36Sopenharmony_ci LOCK_TAKE(hdw->big_lock); 271162306a36Sopenharmony_ci pvr2_i2c_core_done(hdw); 271262306a36Sopenharmony_ci LOCK_TAKE(hdw->ctl_lock); 271362306a36Sopenharmony_ci pvr2_hdw_remove_usb_stuff(hdw); 271462306a36Sopenharmony_ci LOCK_GIVE(hdw->ctl_lock); 271562306a36Sopenharmony_ci LOCK_GIVE(hdw->big_lock); 271662306a36Sopenharmony_ci} 271762306a36Sopenharmony_ci 271862306a36Sopenharmony_ci 271962306a36Sopenharmony_ci/* Get the number of defined controls */ 272062306a36Sopenharmony_ciunsigned int pvr2_hdw_get_ctrl_count(struct pvr2_hdw *hdw) 272162306a36Sopenharmony_ci{ 272262306a36Sopenharmony_ci return hdw->control_cnt; 272362306a36Sopenharmony_ci} 272462306a36Sopenharmony_ci 272562306a36Sopenharmony_ci 272662306a36Sopenharmony_ci/* Retrieve a control handle given its index (0..count-1) */ 272762306a36Sopenharmony_cistruct pvr2_ctrl *pvr2_hdw_get_ctrl_by_index(struct pvr2_hdw *hdw, 272862306a36Sopenharmony_ci unsigned int idx) 272962306a36Sopenharmony_ci{ 273062306a36Sopenharmony_ci if (idx >= hdw->control_cnt) return NULL; 273162306a36Sopenharmony_ci return hdw->controls + idx; 273262306a36Sopenharmony_ci} 273362306a36Sopenharmony_ci 273462306a36Sopenharmony_ci 273562306a36Sopenharmony_ci/* Retrieve a control handle given its index (0..count-1) */ 273662306a36Sopenharmony_cistruct pvr2_ctrl *pvr2_hdw_get_ctrl_by_id(struct pvr2_hdw *hdw, 273762306a36Sopenharmony_ci unsigned int ctl_id) 273862306a36Sopenharmony_ci{ 273962306a36Sopenharmony_ci struct pvr2_ctrl *cptr; 274062306a36Sopenharmony_ci unsigned int idx; 274162306a36Sopenharmony_ci int i; 274262306a36Sopenharmony_ci 274362306a36Sopenharmony_ci /* This could be made a lot more efficient, but for now... */ 274462306a36Sopenharmony_ci for (idx = 0; idx < hdw->control_cnt; idx++) { 274562306a36Sopenharmony_ci cptr = hdw->controls + idx; 274662306a36Sopenharmony_ci i = cptr->info->internal_id; 274762306a36Sopenharmony_ci if (i && (i == ctl_id)) return cptr; 274862306a36Sopenharmony_ci } 274962306a36Sopenharmony_ci return NULL; 275062306a36Sopenharmony_ci} 275162306a36Sopenharmony_ci 275262306a36Sopenharmony_ci 275362306a36Sopenharmony_ci/* Given a V4L ID, retrieve the control structure associated with it. */ 275462306a36Sopenharmony_cistruct pvr2_ctrl *pvr2_hdw_get_ctrl_v4l(struct pvr2_hdw *hdw,unsigned int ctl_id) 275562306a36Sopenharmony_ci{ 275662306a36Sopenharmony_ci struct pvr2_ctrl *cptr; 275762306a36Sopenharmony_ci unsigned int idx; 275862306a36Sopenharmony_ci int i; 275962306a36Sopenharmony_ci 276062306a36Sopenharmony_ci /* This could be made a lot more efficient, but for now... */ 276162306a36Sopenharmony_ci for (idx = 0; idx < hdw->control_cnt; idx++) { 276262306a36Sopenharmony_ci cptr = hdw->controls + idx; 276362306a36Sopenharmony_ci i = cptr->info->v4l_id; 276462306a36Sopenharmony_ci if (i && (i == ctl_id)) return cptr; 276562306a36Sopenharmony_ci } 276662306a36Sopenharmony_ci return NULL; 276762306a36Sopenharmony_ci} 276862306a36Sopenharmony_ci 276962306a36Sopenharmony_ci 277062306a36Sopenharmony_ci/* Given a V4L ID for its immediate predecessor, retrieve the control 277162306a36Sopenharmony_ci structure associated with it. */ 277262306a36Sopenharmony_cistruct pvr2_ctrl *pvr2_hdw_get_ctrl_nextv4l(struct pvr2_hdw *hdw, 277362306a36Sopenharmony_ci unsigned int ctl_id) 277462306a36Sopenharmony_ci{ 277562306a36Sopenharmony_ci struct pvr2_ctrl *cptr,*cp2; 277662306a36Sopenharmony_ci unsigned int idx; 277762306a36Sopenharmony_ci int i; 277862306a36Sopenharmony_ci 277962306a36Sopenharmony_ci /* This could be made a lot more efficient, but for now... */ 278062306a36Sopenharmony_ci cp2 = NULL; 278162306a36Sopenharmony_ci for (idx = 0; idx < hdw->control_cnt; idx++) { 278262306a36Sopenharmony_ci cptr = hdw->controls + idx; 278362306a36Sopenharmony_ci i = cptr->info->v4l_id; 278462306a36Sopenharmony_ci if (!i) continue; 278562306a36Sopenharmony_ci if (i <= ctl_id) continue; 278662306a36Sopenharmony_ci if (cp2 && (cp2->info->v4l_id < i)) continue; 278762306a36Sopenharmony_ci cp2 = cptr; 278862306a36Sopenharmony_ci } 278962306a36Sopenharmony_ci return cp2; 279062306a36Sopenharmony_ci return NULL; 279162306a36Sopenharmony_ci} 279262306a36Sopenharmony_ci 279362306a36Sopenharmony_ci 279462306a36Sopenharmony_cistatic const char *get_ctrl_typename(enum pvr2_ctl_type tp) 279562306a36Sopenharmony_ci{ 279662306a36Sopenharmony_ci switch (tp) { 279762306a36Sopenharmony_ci case pvr2_ctl_int: return "integer"; 279862306a36Sopenharmony_ci case pvr2_ctl_enum: return "enum"; 279962306a36Sopenharmony_ci case pvr2_ctl_bool: return "boolean"; 280062306a36Sopenharmony_ci case pvr2_ctl_bitmask: return "bitmask"; 280162306a36Sopenharmony_ci } 280262306a36Sopenharmony_ci return ""; 280362306a36Sopenharmony_ci} 280462306a36Sopenharmony_ci 280562306a36Sopenharmony_ci 280662306a36Sopenharmony_cistatic void pvr2_subdev_set_control(struct pvr2_hdw *hdw, int id, 280762306a36Sopenharmony_ci const char *name, int val) 280862306a36Sopenharmony_ci{ 280962306a36Sopenharmony_ci struct v4l2_control ctrl; 281062306a36Sopenharmony_ci struct v4l2_subdev *sd; 281162306a36Sopenharmony_ci 281262306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 %s=%d", name, val); 281362306a36Sopenharmony_ci memset(&ctrl, 0, sizeof(ctrl)); 281462306a36Sopenharmony_ci ctrl.id = id; 281562306a36Sopenharmony_ci ctrl.value = val; 281662306a36Sopenharmony_ci 281762306a36Sopenharmony_ci v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) 281862306a36Sopenharmony_ci v4l2_s_ctrl(NULL, sd->ctrl_handler, &ctrl); 281962306a36Sopenharmony_ci} 282062306a36Sopenharmony_ci 282162306a36Sopenharmony_ci#define PVR2_SUBDEV_SET_CONTROL(hdw, id, lab) \ 282262306a36Sopenharmony_ci if ((hdw)->lab##_dirty || (hdw)->force_dirty) { \ 282362306a36Sopenharmony_ci pvr2_subdev_set_control(hdw, id, #lab, (hdw)->lab##_val); \ 282462306a36Sopenharmony_ci } 282562306a36Sopenharmony_ci 282662306a36Sopenharmony_cistatic v4l2_std_id pvr2_hdw_get_detected_std(struct pvr2_hdw *hdw) 282762306a36Sopenharmony_ci{ 282862306a36Sopenharmony_ci v4l2_std_id std; 282962306a36Sopenharmony_ci std = (v4l2_std_id)hdw->std_mask_avail; 283062306a36Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, 0, 283162306a36Sopenharmony_ci video, querystd, &std); 283262306a36Sopenharmony_ci return std; 283362306a36Sopenharmony_ci} 283462306a36Sopenharmony_ci 283562306a36Sopenharmony_ci/* Execute whatever commands are required to update the state of all the 283662306a36Sopenharmony_ci sub-devices so that they match our current control values. */ 283762306a36Sopenharmony_cistatic void pvr2_subdev_update(struct pvr2_hdw *hdw) 283862306a36Sopenharmony_ci{ 283962306a36Sopenharmony_ci struct v4l2_subdev *sd; 284062306a36Sopenharmony_ci unsigned int id; 284162306a36Sopenharmony_ci pvr2_subdev_update_func fp; 284262306a36Sopenharmony_ci 284362306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_CHIPS, "subdev update..."); 284462306a36Sopenharmony_ci 284562306a36Sopenharmony_ci if (hdw->tuner_updated || hdw->force_dirty) { 284662306a36Sopenharmony_ci struct tuner_setup setup; 284762306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_CHIPS, "subdev tuner set_type(%d)", 284862306a36Sopenharmony_ci hdw->tuner_type); 284962306a36Sopenharmony_ci if (((int)(hdw->tuner_type)) >= 0) { 285062306a36Sopenharmony_ci memset(&setup, 0, sizeof(setup)); 285162306a36Sopenharmony_ci setup.addr = ADDR_UNSET; 285262306a36Sopenharmony_ci setup.type = hdw->tuner_type; 285362306a36Sopenharmony_ci setup.mode_mask = T_RADIO | T_ANALOG_TV; 285462306a36Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, 0, 285562306a36Sopenharmony_ci tuner, s_type_addr, &setup); 285662306a36Sopenharmony_ci } 285762306a36Sopenharmony_ci } 285862306a36Sopenharmony_ci 285962306a36Sopenharmony_ci if (hdw->input_dirty || hdw->std_dirty || hdw->force_dirty) { 286062306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_standard"); 286162306a36Sopenharmony_ci if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) { 286262306a36Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, 0, 286362306a36Sopenharmony_ci tuner, s_radio); 286462306a36Sopenharmony_ci } else { 286562306a36Sopenharmony_ci v4l2_std_id vs; 286662306a36Sopenharmony_ci vs = hdw->std_mask_cur; 286762306a36Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, 0, 286862306a36Sopenharmony_ci video, s_std, vs); 286962306a36Sopenharmony_ci pvr2_hdw_cx25840_vbi_hack(hdw); 287062306a36Sopenharmony_ci } 287162306a36Sopenharmony_ci hdw->tuner_signal_stale = !0; 287262306a36Sopenharmony_ci hdw->cropcap_stale = !0; 287362306a36Sopenharmony_ci } 287462306a36Sopenharmony_ci 287562306a36Sopenharmony_ci PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_BRIGHTNESS, brightness); 287662306a36Sopenharmony_ci PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_CONTRAST, contrast); 287762306a36Sopenharmony_ci PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_SATURATION, saturation); 287862306a36Sopenharmony_ci PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_HUE, hue); 287962306a36Sopenharmony_ci PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_MUTE, mute); 288062306a36Sopenharmony_ci PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_VOLUME, volume); 288162306a36Sopenharmony_ci PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_BALANCE, balance); 288262306a36Sopenharmony_ci PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_BASS, bass); 288362306a36Sopenharmony_ci PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_TREBLE, treble); 288462306a36Sopenharmony_ci 288562306a36Sopenharmony_ci if (hdw->input_dirty || hdw->audiomode_dirty || hdw->force_dirty) { 288662306a36Sopenharmony_ci struct v4l2_tuner vt; 288762306a36Sopenharmony_ci memset(&vt, 0, sizeof(vt)); 288862306a36Sopenharmony_ci vt.type = (hdw->input_val == PVR2_CVAL_INPUT_RADIO) ? 288962306a36Sopenharmony_ci V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; 289062306a36Sopenharmony_ci vt.audmode = hdw->audiomode_val; 289162306a36Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner, s_tuner, &vt); 289262306a36Sopenharmony_ci } 289362306a36Sopenharmony_ci 289462306a36Sopenharmony_ci if (hdw->freqDirty || hdw->force_dirty) { 289562306a36Sopenharmony_ci unsigned long fv; 289662306a36Sopenharmony_ci struct v4l2_frequency freq; 289762306a36Sopenharmony_ci fv = pvr2_hdw_get_cur_freq(hdw); 289862306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_freq(%lu)", fv); 289962306a36Sopenharmony_ci if (hdw->tuner_signal_stale) pvr2_hdw_status_poll(hdw); 290062306a36Sopenharmony_ci memset(&freq, 0, sizeof(freq)); 290162306a36Sopenharmony_ci if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) { 290262306a36Sopenharmony_ci /* ((fv * 1000) / 62500) */ 290362306a36Sopenharmony_ci freq.frequency = (fv * 2) / 125; 290462306a36Sopenharmony_ci } else { 290562306a36Sopenharmony_ci freq.frequency = fv / 62500; 290662306a36Sopenharmony_ci } 290762306a36Sopenharmony_ci /* tuner-core currently doesn't seem to care about this, but 290862306a36Sopenharmony_ci let's set it anyway for completeness. */ 290962306a36Sopenharmony_ci if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) { 291062306a36Sopenharmony_ci freq.type = V4L2_TUNER_RADIO; 291162306a36Sopenharmony_ci } else { 291262306a36Sopenharmony_ci freq.type = V4L2_TUNER_ANALOG_TV; 291362306a36Sopenharmony_ci } 291462306a36Sopenharmony_ci freq.tuner = 0; 291562306a36Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner, 291662306a36Sopenharmony_ci s_frequency, &freq); 291762306a36Sopenharmony_ci } 291862306a36Sopenharmony_ci 291962306a36Sopenharmony_ci if (hdw->res_hor_dirty || hdw->res_ver_dirty || hdw->force_dirty) { 292062306a36Sopenharmony_ci struct v4l2_subdev_format format = { 292162306a36Sopenharmony_ci .which = V4L2_SUBDEV_FORMAT_ACTIVE, 292262306a36Sopenharmony_ci }; 292362306a36Sopenharmony_ci 292462306a36Sopenharmony_ci format.format.width = hdw->res_hor_val; 292562306a36Sopenharmony_ci format.format.height = hdw->res_ver_val; 292662306a36Sopenharmony_ci format.format.code = MEDIA_BUS_FMT_FIXED; 292762306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_size(%dx%d)", 292862306a36Sopenharmony_ci format.format.width, format.format.height); 292962306a36Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, 0, pad, set_fmt, 293062306a36Sopenharmony_ci NULL, &format); 293162306a36Sopenharmony_ci } 293262306a36Sopenharmony_ci 293362306a36Sopenharmony_ci if (hdw->srate_dirty || hdw->force_dirty) { 293462306a36Sopenharmony_ci u32 val; 293562306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_audio %d", 293662306a36Sopenharmony_ci hdw->srate_val); 293762306a36Sopenharmony_ci switch (hdw->srate_val) { 293862306a36Sopenharmony_ci default: 293962306a36Sopenharmony_ci case V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000: 294062306a36Sopenharmony_ci val = 48000; 294162306a36Sopenharmony_ci break; 294262306a36Sopenharmony_ci case V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100: 294362306a36Sopenharmony_ci val = 44100; 294462306a36Sopenharmony_ci break; 294562306a36Sopenharmony_ci case V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000: 294662306a36Sopenharmony_ci val = 32000; 294762306a36Sopenharmony_ci break; 294862306a36Sopenharmony_ci } 294962306a36Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, 0, 295062306a36Sopenharmony_ci audio, s_clock_freq, val); 295162306a36Sopenharmony_ci } 295262306a36Sopenharmony_ci 295362306a36Sopenharmony_ci /* Unable to set crop parameters; there is apparently no equivalent 295462306a36Sopenharmony_ci for VIDIOC_S_CROP */ 295562306a36Sopenharmony_ci 295662306a36Sopenharmony_ci v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) { 295762306a36Sopenharmony_ci id = sd->grp_id; 295862306a36Sopenharmony_ci if (id >= ARRAY_SIZE(pvr2_module_update_functions)) continue; 295962306a36Sopenharmony_ci fp = pvr2_module_update_functions[id]; 296062306a36Sopenharmony_ci if (!fp) continue; 296162306a36Sopenharmony_ci (*fp)(hdw, sd); 296262306a36Sopenharmony_ci } 296362306a36Sopenharmony_ci 296462306a36Sopenharmony_ci if (hdw->tuner_signal_stale || hdw->cropcap_stale) { 296562306a36Sopenharmony_ci pvr2_hdw_status_poll(hdw); 296662306a36Sopenharmony_ci } 296762306a36Sopenharmony_ci} 296862306a36Sopenharmony_ci 296962306a36Sopenharmony_ci 297062306a36Sopenharmony_ci/* Figure out if we need to commit control changes. If so, mark internal 297162306a36Sopenharmony_ci state flags to indicate this fact and return true. Otherwise do nothing 297262306a36Sopenharmony_ci else and return false. */ 297362306a36Sopenharmony_cistatic int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw) 297462306a36Sopenharmony_ci{ 297562306a36Sopenharmony_ci unsigned int idx; 297662306a36Sopenharmony_ci struct pvr2_ctrl *cptr; 297762306a36Sopenharmony_ci int value; 297862306a36Sopenharmony_ci int commit_flag = hdw->force_dirty; 297962306a36Sopenharmony_ci char buf[100]; 298062306a36Sopenharmony_ci unsigned int bcnt,ccnt; 298162306a36Sopenharmony_ci 298262306a36Sopenharmony_ci for (idx = 0; idx < hdw->control_cnt; idx++) { 298362306a36Sopenharmony_ci cptr = hdw->controls + idx; 298462306a36Sopenharmony_ci if (!cptr->info->is_dirty) continue; 298562306a36Sopenharmony_ci if (!cptr->info->is_dirty(cptr)) continue; 298662306a36Sopenharmony_ci commit_flag = !0; 298762306a36Sopenharmony_ci 298862306a36Sopenharmony_ci if (!(pvrusb2_debug & PVR2_TRACE_CTL)) continue; 298962306a36Sopenharmony_ci bcnt = scnprintf(buf,sizeof(buf),"\"%s\" <-- ", 299062306a36Sopenharmony_ci cptr->info->name); 299162306a36Sopenharmony_ci value = 0; 299262306a36Sopenharmony_ci cptr->info->get_value(cptr,&value); 299362306a36Sopenharmony_ci pvr2_ctrl_value_to_sym_internal(cptr,~0,value, 299462306a36Sopenharmony_ci buf+bcnt, 299562306a36Sopenharmony_ci sizeof(buf)-bcnt,&ccnt); 299662306a36Sopenharmony_ci bcnt += ccnt; 299762306a36Sopenharmony_ci bcnt += scnprintf(buf+bcnt,sizeof(buf)-bcnt," <%s>", 299862306a36Sopenharmony_ci get_ctrl_typename(cptr->info->type)); 299962306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_CTL, 300062306a36Sopenharmony_ci "/*--TRACE_COMMIT--*/ %.*s", 300162306a36Sopenharmony_ci bcnt,buf); 300262306a36Sopenharmony_ci } 300362306a36Sopenharmony_ci 300462306a36Sopenharmony_ci if (!commit_flag) { 300562306a36Sopenharmony_ci /* Nothing has changed */ 300662306a36Sopenharmony_ci return 0; 300762306a36Sopenharmony_ci } 300862306a36Sopenharmony_ci 300962306a36Sopenharmony_ci hdw->state_pipeline_config = 0; 301062306a36Sopenharmony_ci trace_stbit("state_pipeline_config",hdw->state_pipeline_config); 301162306a36Sopenharmony_ci pvr2_hdw_state_sched(hdw); 301262306a36Sopenharmony_ci 301362306a36Sopenharmony_ci return !0; 301462306a36Sopenharmony_ci} 301562306a36Sopenharmony_ci 301662306a36Sopenharmony_ci 301762306a36Sopenharmony_ci/* Perform all operations needed to commit all control changes. This must 301862306a36Sopenharmony_ci be performed in synchronization with the pipeline state and is thus 301962306a36Sopenharmony_ci expected to be called as part of the driver's worker thread. Return 302062306a36Sopenharmony_ci true if commit successful, otherwise return false to indicate that 302162306a36Sopenharmony_ci commit isn't possible at this time. */ 302262306a36Sopenharmony_cistatic int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw) 302362306a36Sopenharmony_ci{ 302462306a36Sopenharmony_ci unsigned int idx; 302562306a36Sopenharmony_ci struct pvr2_ctrl *cptr; 302662306a36Sopenharmony_ci int disruptive_change; 302762306a36Sopenharmony_ci 302862306a36Sopenharmony_ci if (hdw->input_dirty && hdw->state_pathway_ok && 302962306a36Sopenharmony_ci (((hdw->input_val == PVR2_CVAL_INPUT_DTV) ? 303062306a36Sopenharmony_ci PVR2_PATHWAY_DIGITAL : PVR2_PATHWAY_ANALOG) != 303162306a36Sopenharmony_ci hdw->pathway_state)) { 303262306a36Sopenharmony_ci /* Change of mode being asked for... */ 303362306a36Sopenharmony_ci hdw->state_pathway_ok = 0; 303462306a36Sopenharmony_ci trace_stbit("state_pathway_ok", hdw->state_pathway_ok); 303562306a36Sopenharmony_ci } 303662306a36Sopenharmony_ci if (!hdw->state_pathway_ok) { 303762306a36Sopenharmony_ci /* Can't commit anything until pathway is ok. */ 303862306a36Sopenharmony_ci return 0; 303962306a36Sopenharmony_ci } 304062306a36Sopenharmony_ci 304162306a36Sopenharmony_ci /* Handle some required side effects when the video standard is 304262306a36Sopenharmony_ci changed.... */ 304362306a36Sopenharmony_ci if (hdw->std_dirty) { 304462306a36Sopenharmony_ci int nvres; 304562306a36Sopenharmony_ci int gop_size; 304662306a36Sopenharmony_ci if (hdw->std_mask_cur & V4L2_STD_525_60) { 304762306a36Sopenharmony_ci nvres = 480; 304862306a36Sopenharmony_ci gop_size = 15; 304962306a36Sopenharmony_ci } else { 305062306a36Sopenharmony_ci nvres = 576; 305162306a36Sopenharmony_ci gop_size = 12; 305262306a36Sopenharmony_ci } 305362306a36Sopenharmony_ci /* Rewrite the vertical resolution to be appropriate to the 305462306a36Sopenharmony_ci video standard that has been selected. */ 305562306a36Sopenharmony_ci if (nvres != hdw->res_ver_val) { 305662306a36Sopenharmony_ci hdw->res_ver_val = nvres; 305762306a36Sopenharmony_ci hdw->res_ver_dirty = !0; 305862306a36Sopenharmony_ci } 305962306a36Sopenharmony_ci /* Rewrite the GOP size to be appropriate to the video 306062306a36Sopenharmony_ci standard that has been selected. */ 306162306a36Sopenharmony_ci if (gop_size != hdw->enc_ctl_state.video_gop_size) { 306262306a36Sopenharmony_ci struct v4l2_ext_controls cs; 306362306a36Sopenharmony_ci struct v4l2_ext_control c1; 306462306a36Sopenharmony_ci memset(&cs, 0, sizeof(cs)); 306562306a36Sopenharmony_ci memset(&c1, 0, sizeof(c1)); 306662306a36Sopenharmony_ci cs.controls = &c1; 306762306a36Sopenharmony_ci cs.count = 1; 306862306a36Sopenharmony_ci c1.id = V4L2_CID_MPEG_VIDEO_GOP_SIZE; 306962306a36Sopenharmony_ci c1.value = gop_size; 307062306a36Sopenharmony_ci cx2341x_ext_ctrls(&hdw->enc_ctl_state, 0, &cs, 307162306a36Sopenharmony_ci VIDIOC_S_EXT_CTRLS); 307262306a36Sopenharmony_ci } 307362306a36Sopenharmony_ci } 307462306a36Sopenharmony_ci 307562306a36Sopenharmony_ci /* The broadcast decoder can only scale down, so if 307662306a36Sopenharmony_ci * res_*_dirty && crop window < output format ==> enlarge crop. 307762306a36Sopenharmony_ci * 307862306a36Sopenharmony_ci * The mpeg encoder receives fields of res_hor_val dots and 307962306a36Sopenharmony_ci * res_ver_val halflines. Limits: hor<=720, ver<=576. 308062306a36Sopenharmony_ci */ 308162306a36Sopenharmony_ci if (hdw->res_hor_dirty && hdw->cropw_val < hdw->res_hor_val) { 308262306a36Sopenharmony_ci hdw->cropw_val = hdw->res_hor_val; 308362306a36Sopenharmony_ci hdw->cropw_dirty = !0; 308462306a36Sopenharmony_ci } else if (hdw->cropw_dirty) { 308562306a36Sopenharmony_ci hdw->res_hor_dirty = !0; /* must rescale */ 308662306a36Sopenharmony_ci hdw->res_hor_val = min(720, hdw->cropw_val); 308762306a36Sopenharmony_ci } 308862306a36Sopenharmony_ci if (hdw->res_ver_dirty && hdw->croph_val < hdw->res_ver_val) { 308962306a36Sopenharmony_ci hdw->croph_val = hdw->res_ver_val; 309062306a36Sopenharmony_ci hdw->croph_dirty = !0; 309162306a36Sopenharmony_ci } else if (hdw->croph_dirty) { 309262306a36Sopenharmony_ci int nvres = hdw->std_mask_cur & V4L2_STD_525_60 ? 480 : 576; 309362306a36Sopenharmony_ci hdw->res_ver_dirty = !0; 309462306a36Sopenharmony_ci hdw->res_ver_val = min(nvres, hdw->croph_val); 309562306a36Sopenharmony_ci } 309662306a36Sopenharmony_ci 309762306a36Sopenharmony_ci /* If any of the below has changed, then we can't do the update 309862306a36Sopenharmony_ci while the pipeline is running. Pipeline must be paused first 309962306a36Sopenharmony_ci and decoder -> encoder connection be made quiescent before we 310062306a36Sopenharmony_ci can proceed. */ 310162306a36Sopenharmony_ci disruptive_change = 310262306a36Sopenharmony_ci (hdw->std_dirty || 310362306a36Sopenharmony_ci hdw->enc_unsafe_stale || 310462306a36Sopenharmony_ci hdw->srate_dirty || 310562306a36Sopenharmony_ci hdw->res_ver_dirty || 310662306a36Sopenharmony_ci hdw->res_hor_dirty || 310762306a36Sopenharmony_ci hdw->cropw_dirty || 310862306a36Sopenharmony_ci hdw->croph_dirty || 310962306a36Sopenharmony_ci hdw->input_dirty || 311062306a36Sopenharmony_ci (hdw->active_stream_type != hdw->desired_stream_type)); 311162306a36Sopenharmony_ci if (disruptive_change && !hdw->state_pipeline_idle) { 311262306a36Sopenharmony_ci /* Pipeline is not idle; we can't proceed. Arrange to 311362306a36Sopenharmony_ci cause pipeline to stop so that we can try this again 311462306a36Sopenharmony_ci later.... */ 311562306a36Sopenharmony_ci hdw->state_pipeline_pause = !0; 311662306a36Sopenharmony_ci return 0; 311762306a36Sopenharmony_ci } 311862306a36Sopenharmony_ci 311962306a36Sopenharmony_ci if (hdw->srate_dirty) { 312062306a36Sopenharmony_ci /* Write new sample rate into control structure since 312162306a36Sopenharmony_ci * the master copy is stale. We must track srate 312262306a36Sopenharmony_ci * separate from the mpeg control structure because 312362306a36Sopenharmony_ci * other logic also uses this value. */ 312462306a36Sopenharmony_ci struct v4l2_ext_controls cs; 312562306a36Sopenharmony_ci struct v4l2_ext_control c1; 312662306a36Sopenharmony_ci memset(&cs,0,sizeof(cs)); 312762306a36Sopenharmony_ci memset(&c1,0,sizeof(c1)); 312862306a36Sopenharmony_ci cs.controls = &c1; 312962306a36Sopenharmony_ci cs.count = 1; 313062306a36Sopenharmony_ci c1.id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ; 313162306a36Sopenharmony_ci c1.value = hdw->srate_val; 313262306a36Sopenharmony_ci cx2341x_ext_ctrls(&hdw->enc_ctl_state, 0, &cs,VIDIOC_S_EXT_CTRLS); 313362306a36Sopenharmony_ci } 313462306a36Sopenharmony_ci 313562306a36Sopenharmony_ci if (hdw->active_stream_type != hdw->desired_stream_type) { 313662306a36Sopenharmony_ci /* Handle any side effects of stream config here */ 313762306a36Sopenharmony_ci hdw->active_stream_type = hdw->desired_stream_type; 313862306a36Sopenharmony_ci } 313962306a36Sopenharmony_ci 314062306a36Sopenharmony_ci if (hdw->hdw_desc->signal_routing_scheme == 314162306a36Sopenharmony_ci PVR2_ROUTING_SCHEME_GOTVIEW) { 314262306a36Sopenharmony_ci u32 b; 314362306a36Sopenharmony_ci /* Handle GOTVIEW audio switching */ 314462306a36Sopenharmony_ci pvr2_hdw_gpio_get_out(hdw,&b); 314562306a36Sopenharmony_ci if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) { 314662306a36Sopenharmony_ci /* Set GPIO 11 */ 314762306a36Sopenharmony_ci pvr2_hdw_gpio_chg_out(hdw,(1 << 11),~0); 314862306a36Sopenharmony_ci } else { 314962306a36Sopenharmony_ci /* Clear GPIO 11 */ 315062306a36Sopenharmony_ci pvr2_hdw_gpio_chg_out(hdw,(1 << 11),0); 315162306a36Sopenharmony_ci } 315262306a36Sopenharmony_ci } 315362306a36Sopenharmony_ci 315462306a36Sopenharmony_ci /* Check and update state for all sub-devices. */ 315562306a36Sopenharmony_ci pvr2_subdev_update(hdw); 315662306a36Sopenharmony_ci 315762306a36Sopenharmony_ci hdw->tuner_updated = 0; 315862306a36Sopenharmony_ci hdw->force_dirty = 0; 315962306a36Sopenharmony_ci for (idx = 0; idx < hdw->control_cnt; idx++) { 316062306a36Sopenharmony_ci cptr = hdw->controls + idx; 316162306a36Sopenharmony_ci if (!cptr->info->clear_dirty) continue; 316262306a36Sopenharmony_ci cptr->info->clear_dirty(cptr); 316362306a36Sopenharmony_ci } 316462306a36Sopenharmony_ci 316562306a36Sopenharmony_ci if ((hdw->pathway_state == PVR2_PATHWAY_ANALOG) && 316662306a36Sopenharmony_ci hdw->state_encoder_run) { 316762306a36Sopenharmony_ci /* If encoder isn't running or it can't be touched, then 316862306a36Sopenharmony_ci this will get worked out later when we start the 316962306a36Sopenharmony_ci encoder. */ 317062306a36Sopenharmony_ci if (pvr2_encoder_adjust(hdw) < 0) return !0; 317162306a36Sopenharmony_ci } 317262306a36Sopenharmony_ci 317362306a36Sopenharmony_ci hdw->state_pipeline_config = !0; 317462306a36Sopenharmony_ci /* Hardware state may have changed in a way to cause the cropping 317562306a36Sopenharmony_ci capabilities to have changed. So mark it stale, which will 317662306a36Sopenharmony_ci cause a later re-fetch. */ 317762306a36Sopenharmony_ci trace_stbit("state_pipeline_config",hdw->state_pipeline_config); 317862306a36Sopenharmony_ci return !0; 317962306a36Sopenharmony_ci} 318062306a36Sopenharmony_ci 318162306a36Sopenharmony_ci 318262306a36Sopenharmony_ciint pvr2_hdw_commit_ctl(struct pvr2_hdw *hdw) 318362306a36Sopenharmony_ci{ 318462306a36Sopenharmony_ci int fl; 318562306a36Sopenharmony_ci LOCK_TAKE(hdw->big_lock); 318662306a36Sopenharmony_ci fl = pvr2_hdw_commit_setup(hdw); 318762306a36Sopenharmony_ci LOCK_GIVE(hdw->big_lock); 318862306a36Sopenharmony_ci if (!fl) return 0; 318962306a36Sopenharmony_ci return pvr2_hdw_wait(hdw,0); 319062306a36Sopenharmony_ci} 319162306a36Sopenharmony_ci 319262306a36Sopenharmony_ci 319362306a36Sopenharmony_cistatic void pvr2_hdw_worker_poll(struct work_struct *work) 319462306a36Sopenharmony_ci{ 319562306a36Sopenharmony_ci int fl = 0; 319662306a36Sopenharmony_ci struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,workpoll); 319762306a36Sopenharmony_ci LOCK_TAKE(hdw->big_lock); do { 319862306a36Sopenharmony_ci fl = pvr2_hdw_state_eval(hdw); 319962306a36Sopenharmony_ci } while (0); LOCK_GIVE(hdw->big_lock); 320062306a36Sopenharmony_ci if (fl && hdw->state_func) { 320162306a36Sopenharmony_ci hdw->state_func(hdw->state_data); 320262306a36Sopenharmony_ci } 320362306a36Sopenharmony_ci} 320462306a36Sopenharmony_ci 320562306a36Sopenharmony_ci 320662306a36Sopenharmony_cistatic int pvr2_hdw_wait(struct pvr2_hdw *hdw,int state) 320762306a36Sopenharmony_ci{ 320862306a36Sopenharmony_ci return wait_event_interruptible( 320962306a36Sopenharmony_ci hdw->state_wait_data, 321062306a36Sopenharmony_ci (hdw->state_stale == 0) && 321162306a36Sopenharmony_ci (!state || (hdw->master_state != state))); 321262306a36Sopenharmony_ci} 321362306a36Sopenharmony_ci 321462306a36Sopenharmony_ci 321562306a36Sopenharmony_ci/* Return name for this driver instance */ 321662306a36Sopenharmony_ciconst char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw) 321762306a36Sopenharmony_ci{ 321862306a36Sopenharmony_ci return hdw->name; 321962306a36Sopenharmony_ci} 322062306a36Sopenharmony_ci 322162306a36Sopenharmony_ci 322262306a36Sopenharmony_ciconst char *pvr2_hdw_get_desc(struct pvr2_hdw *hdw) 322362306a36Sopenharmony_ci{ 322462306a36Sopenharmony_ci return hdw->hdw_desc->description; 322562306a36Sopenharmony_ci} 322662306a36Sopenharmony_ci 322762306a36Sopenharmony_ci 322862306a36Sopenharmony_ciconst char *pvr2_hdw_get_type(struct pvr2_hdw *hdw) 322962306a36Sopenharmony_ci{ 323062306a36Sopenharmony_ci return hdw->hdw_desc->shortname; 323162306a36Sopenharmony_ci} 323262306a36Sopenharmony_ci 323362306a36Sopenharmony_ci 323462306a36Sopenharmony_ciint pvr2_hdw_is_hsm(struct pvr2_hdw *hdw) 323562306a36Sopenharmony_ci{ 323662306a36Sopenharmony_ci int result; 323762306a36Sopenharmony_ci LOCK_TAKE(hdw->ctl_lock); do { 323862306a36Sopenharmony_ci hdw->cmd_buffer[0] = FX2CMD_GET_USB_SPEED; 323962306a36Sopenharmony_ci result = pvr2_send_request(hdw, 324062306a36Sopenharmony_ci hdw->cmd_buffer,1, 324162306a36Sopenharmony_ci hdw->cmd_buffer,1); 324262306a36Sopenharmony_ci if (result < 0) break; 324362306a36Sopenharmony_ci result = (hdw->cmd_buffer[0] != 0); 324462306a36Sopenharmony_ci } while(0); LOCK_GIVE(hdw->ctl_lock); 324562306a36Sopenharmony_ci return result; 324662306a36Sopenharmony_ci} 324762306a36Sopenharmony_ci 324862306a36Sopenharmony_ci 324962306a36Sopenharmony_ci/* Execute poll of tuner status */ 325062306a36Sopenharmony_civoid pvr2_hdw_execute_tuner_poll(struct pvr2_hdw *hdw) 325162306a36Sopenharmony_ci{ 325262306a36Sopenharmony_ci LOCK_TAKE(hdw->big_lock); do { 325362306a36Sopenharmony_ci pvr2_hdw_status_poll(hdw); 325462306a36Sopenharmony_ci } while (0); LOCK_GIVE(hdw->big_lock); 325562306a36Sopenharmony_ci} 325662306a36Sopenharmony_ci 325762306a36Sopenharmony_ci 325862306a36Sopenharmony_cistatic int pvr2_hdw_check_cropcap(struct pvr2_hdw *hdw) 325962306a36Sopenharmony_ci{ 326062306a36Sopenharmony_ci if (!hdw->cropcap_stale) { 326162306a36Sopenharmony_ci return 0; 326262306a36Sopenharmony_ci } 326362306a36Sopenharmony_ci pvr2_hdw_status_poll(hdw); 326462306a36Sopenharmony_ci if (hdw->cropcap_stale) { 326562306a36Sopenharmony_ci return -EIO; 326662306a36Sopenharmony_ci } 326762306a36Sopenharmony_ci return 0; 326862306a36Sopenharmony_ci} 326962306a36Sopenharmony_ci 327062306a36Sopenharmony_ci 327162306a36Sopenharmony_ci/* Return information about cropping capabilities */ 327262306a36Sopenharmony_ciint pvr2_hdw_get_cropcap(struct pvr2_hdw *hdw, struct v4l2_cropcap *pp) 327362306a36Sopenharmony_ci{ 327462306a36Sopenharmony_ci int stat = 0; 327562306a36Sopenharmony_ci LOCK_TAKE(hdw->big_lock); 327662306a36Sopenharmony_ci stat = pvr2_hdw_check_cropcap(hdw); 327762306a36Sopenharmony_ci if (!stat) { 327862306a36Sopenharmony_ci memcpy(pp, &hdw->cropcap_info, sizeof(hdw->cropcap_info)); 327962306a36Sopenharmony_ci } 328062306a36Sopenharmony_ci LOCK_GIVE(hdw->big_lock); 328162306a36Sopenharmony_ci return stat; 328262306a36Sopenharmony_ci} 328362306a36Sopenharmony_ci 328462306a36Sopenharmony_ci 328562306a36Sopenharmony_ci/* Return information about the tuner */ 328662306a36Sopenharmony_ciint pvr2_hdw_get_tuner_status(struct pvr2_hdw *hdw,struct v4l2_tuner *vtp) 328762306a36Sopenharmony_ci{ 328862306a36Sopenharmony_ci LOCK_TAKE(hdw->big_lock); 328962306a36Sopenharmony_ci do { 329062306a36Sopenharmony_ci if (hdw->tuner_signal_stale) { 329162306a36Sopenharmony_ci pvr2_hdw_status_poll(hdw); 329262306a36Sopenharmony_ci } 329362306a36Sopenharmony_ci memcpy(vtp,&hdw->tuner_signal_info,sizeof(struct v4l2_tuner)); 329462306a36Sopenharmony_ci } while (0); 329562306a36Sopenharmony_ci LOCK_GIVE(hdw->big_lock); 329662306a36Sopenharmony_ci return 0; 329762306a36Sopenharmony_ci} 329862306a36Sopenharmony_ci 329962306a36Sopenharmony_ci 330062306a36Sopenharmony_ci/* Get handle to video output stream */ 330162306a36Sopenharmony_cistruct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *hp) 330262306a36Sopenharmony_ci{ 330362306a36Sopenharmony_ci return hp->vid_stream; 330462306a36Sopenharmony_ci} 330562306a36Sopenharmony_ci 330662306a36Sopenharmony_ci 330762306a36Sopenharmony_civoid pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw) 330862306a36Sopenharmony_ci{ 330962306a36Sopenharmony_ci int nr = pvr2_hdw_get_unit_number(hdw); 331062306a36Sopenharmony_ci LOCK_TAKE(hdw->big_lock); 331162306a36Sopenharmony_ci do { 331262306a36Sopenharmony_ci pr_info("pvrusb2: ================= START STATUS CARD #%d =================\n", nr); 331362306a36Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, 0, core, log_status); 331462306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INFO,"cx2341x config:"); 331562306a36Sopenharmony_ci cx2341x_log_status(&hdw->enc_ctl_state, "pvrusb2"); 331662306a36Sopenharmony_ci pvr2_hdw_state_log_state(hdw); 331762306a36Sopenharmony_ci pr_info("pvrusb2: ================== END STATUS CARD #%d ==================\n", nr); 331862306a36Sopenharmony_ci } while (0); 331962306a36Sopenharmony_ci LOCK_GIVE(hdw->big_lock); 332062306a36Sopenharmony_ci} 332162306a36Sopenharmony_ci 332262306a36Sopenharmony_ci 332362306a36Sopenharmony_ci/* Grab EEPROM contents, needed for direct method. */ 332462306a36Sopenharmony_ci#define EEPROM_SIZE 8192 332562306a36Sopenharmony_ci#define trace_eeprom(...) pvr2_trace(PVR2_TRACE_EEPROM,__VA_ARGS__) 332662306a36Sopenharmony_cistatic u8 *pvr2_full_eeprom_fetch(struct pvr2_hdw *hdw) 332762306a36Sopenharmony_ci{ 332862306a36Sopenharmony_ci struct i2c_msg msg[2]; 332962306a36Sopenharmony_ci u8 *eeprom; 333062306a36Sopenharmony_ci u8 iadd[2]; 333162306a36Sopenharmony_ci u8 addr; 333262306a36Sopenharmony_ci u16 eepromSize; 333362306a36Sopenharmony_ci unsigned int offs; 333462306a36Sopenharmony_ci int ret; 333562306a36Sopenharmony_ci int mode16 = 0; 333662306a36Sopenharmony_ci unsigned pcnt,tcnt; 333762306a36Sopenharmony_ci eeprom = kzalloc(EEPROM_SIZE, GFP_KERNEL); 333862306a36Sopenharmony_ci if (!eeprom) { 333962306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 334062306a36Sopenharmony_ci "Failed to allocate memory required to read eeprom"); 334162306a36Sopenharmony_ci return NULL; 334262306a36Sopenharmony_ci } 334362306a36Sopenharmony_ci 334462306a36Sopenharmony_ci trace_eeprom("Value for eeprom addr from controller was 0x%x", 334562306a36Sopenharmony_ci hdw->eeprom_addr); 334662306a36Sopenharmony_ci addr = hdw->eeprom_addr; 334762306a36Sopenharmony_ci /* Seems that if the high bit is set, then the *real* eeprom 334862306a36Sopenharmony_ci address is shifted right now bit position (noticed this in 334962306a36Sopenharmony_ci newer PVR USB2 hardware) */ 335062306a36Sopenharmony_ci if (addr & 0x80) addr >>= 1; 335162306a36Sopenharmony_ci 335262306a36Sopenharmony_ci /* FX2 documentation states that a 16bit-addressed eeprom is 335362306a36Sopenharmony_ci expected if the I2C address is an odd number (yeah, this is 335462306a36Sopenharmony_ci strange but it's what they do) */ 335562306a36Sopenharmony_ci mode16 = (addr & 1); 335662306a36Sopenharmony_ci eepromSize = (mode16 ? EEPROM_SIZE : 256); 335762306a36Sopenharmony_ci trace_eeprom("Examining %d byte eeprom at location 0x%x using %d bit addressing", 335862306a36Sopenharmony_ci eepromSize, addr, 335962306a36Sopenharmony_ci mode16 ? 16 : 8); 336062306a36Sopenharmony_ci 336162306a36Sopenharmony_ci msg[0].addr = addr; 336262306a36Sopenharmony_ci msg[0].flags = 0; 336362306a36Sopenharmony_ci msg[0].len = mode16 ? 2 : 1; 336462306a36Sopenharmony_ci msg[0].buf = iadd; 336562306a36Sopenharmony_ci msg[1].addr = addr; 336662306a36Sopenharmony_ci msg[1].flags = I2C_M_RD; 336762306a36Sopenharmony_ci 336862306a36Sopenharmony_ci /* We have to do the actual eeprom data fetch ourselves, because 336962306a36Sopenharmony_ci (1) we're only fetching part of the eeprom, and (2) if we were 337062306a36Sopenharmony_ci getting the whole thing our I2C driver can't grab it in one 337162306a36Sopenharmony_ci pass - which is what tveeprom is otherwise going to attempt */ 337262306a36Sopenharmony_ci for (tcnt = 0; tcnt < EEPROM_SIZE; tcnt += pcnt) { 337362306a36Sopenharmony_ci pcnt = 16; 337462306a36Sopenharmony_ci if (pcnt + tcnt > EEPROM_SIZE) pcnt = EEPROM_SIZE-tcnt; 337562306a36Sopenharmony_ci offs = tcnt + (eepromSize - EEPROM_SIZE); 337662306a36Sopenharmony_ci if (mode16) { 337762306a36Sopenharmony_ci iadd[0] = offs >> 8; 337862306a36Sopenharmony_ci iadd[1] = offs; 337962306a36Sopenharmony_ci } else { 338062306a36Sopenharmony_ci iadd[0] = offs; 338162306a36Sopenharmony_ci } 338262306a36Sopenharmony_ci msg[1].len = pcnt; 338362306a36Sopenharmony_ci msg[1].buf = eeprom+tcnt; 338462306a36Sopenharmony_ci if ((ret = i2c_transfer(&hdw->i2c_adap, 338562306a36Sopenharmony_ci msg,ARRAY_SIZE(msg))) != 2) { 338662306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 338762306a36Sopenharmony_ci "eeprom fetch set offs err=%d",ret); 338862306a36Sopenharmony_ci kfree(eeprom); 338962306a36Sopenharmony_ci return NULL; 339062306a36Sopenharmony_ci } 339162306a36Sopenharmony_ci } 339262306a36Sopenharmony_ci return eeprom; 339362306a36Sopenharmony_ci} 339462306a36Sopenharmony_ci 339562306a36Sopenharmony_ci 339662306a36Sopenharmony_civoid pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, 339762306a36Sopenharmony_ci int mode, 339862306a36Sopenharmony_ci int enable_flag) 339962306a36Sopenharmony_ci{ 340062306a36Sopenharmony_ci int ret; 340162306a36Sopenharmony_ci u16 address; 340262306a36Sopenharmony_ci unsigned int pipe; 340362306a36Sopenharmony_ci LOCK_TAKE(hdw->big_lock); 340462306a36Sopenharmony_ci do { 340562306a36Sopenharmony_ci if ((hdw->fw_buffer == NULL) == !enable_flag) break; 340662306a36Sopenharmony_ci 340762306a36Sopenharmony_ci if (!enable_flag) { 340862306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_FIRMWARE, 340962306a36Sopenharmony_ci "Cleaning up after CPU firmware fetch"); 341062306a36Sopenharmony_ci kfree(hdw->fw_buffer); 341162306a36Sopenharmony_ci hdw->fw_buffer = NULL; 341262306a36Sopenharmony_ci hdw->fw_size = 0; 341362306a36Sopenharmony_ci if (hdw->fw_cpu_flag) { 341462306a36Sopenharmony_ci /* Now release the CPU. It will disconnect 341562306a36Sopenharmony_ci and reconnect later. */ 341662306a36Sopenharmony_ci pvr2_hdw_cpureset_assert(hdw,0); 341762306a36Sopenharmony_ci } 341862306a36Sopenharmony_ci break; 341962306a36Sopenharmony_ci } 342062306a36Sopenharmony_ci 342162306a36Sopenharmony_ci hdw->fw_cpu_flag = (mode != 2); 342262306a36Sopenharmony_ci if (hdw->fw_cpu_flag) { 342362306a36Sopenharmony_ci hdw->fw_size = (mode == 1) ? 0x4000 : 0x2000; 342462306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_FIRMWARE, 342562306a36Sopenharmony_ci "Preparing to suck out CPU firmware (size=%u)", 342662306a36Sopenharmony_ci hdw->fw_size); 342762306a36Sopenharmony_ci hdw->fw_buffer = kzalloc(hdw->fw_size,GFP_KERNEL); 342862306a36Sopenharmony_ci if (!hdw->fw_buffer) { 342962306a36Sopenharmony_ci hdw->fw_size = 0; 343062306a36Sopenharmony_ci break; 343162306a36Sopenharmony_ci } 343262306a36Sopenharmony_ci 343362306a36Sopenharmony_ci /* We have to hold the CPU during firmware upload. */ 343462306a36Sopenharmony_ci pvr2_hdw_cpureset_assert(hdw,1); 343562306a36Sopenharmony_ci 343662306a36Sopenharmony_ci /* download the firmware from address 0000-1fff in 2048 343762306a36Sopenharmony_ci (=0x800) bytes chunk. */ 343862306a36Sopenharmony_ci 343962306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_FIRMWARE, 344062306a36Sopenharmony_ci "Grabbing CPU firmware"); 344162306a36Sopenharmony_ci pipe = usb_rcvctrlpipe(hdw->usb_dev, 0); 344262306a36Sopenharmony_ci for(address = 0; address < hdw->fw_size; 344362306a36Sopenharmony_ci address += 0x800) { 344462306a36Sopenharmony_ci ret = usb_control_msg(hdw->usb_dev,pipe, 344562306a36Sopenharmony_ci 0xa0,0xc0, 344662306a36Sopenharmony_ci address,0, 344762306a36Sopenharmony_ci hdw->fw_buffer+address, 344862306a36Sopenharmony_ci 0x800,1000); 344962306a36Sopenharmony_ci if (ret < 0) break; 345062306a36Sopenharmony_ci } 345162306a36Sopenharmony_ci 345262306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_FIRMWARE, 345362306a36Sopenharmony_ci "Done grabbing CPU firmware"); 345462306a36Sopenharmony_ci } else { 345562306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_FIRMWARE, 345662306a36Sopenharmony_ci "Sucking down EEPROM contents"); 345762306a36Sopenharmony_ci hdw->fw_buffer = pvr2_full_eeprom_fetch(hdw); 345862306a36Sopenharmony_ci if (!hdw->fw_buffer) { 345962306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_FIRMWARE, 346062306a36Sopenharmony_ci "EEPROM content suck failed."); 346162306a36Sopenharmony_ci break; 346262306a36Sopenharmony_ci } 346362306a36Sopenharmony_ci hdw->fw_size = EEPROM_SIZE; 346462306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_FIRMWARE, 346562306a36Sopenharmony_ci "Done sucking down EEPROM contents"); 346662306a36Sopenharmony_ci } 346762306a36Sopenharmony_ci } while (0); 346862306a36Sopenharmony_ci LOCK_GIVE(hdw->big_lock); 346962306a36Sopenharmony_ci} 347062306a36Sopenharmony_ci 347162306a36Sopenharmony_ci 347262306a36Sopenharmony_ci/* Return true if we're in a mode for retrieval CPU firmware */ 347362306a36Sopenharmony_ciint pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *hdw) 347462306a36Sopenharmony_ci{ 347562306a36Sopenharmony_ci return hdw->fw_buffer != NULL; 347662306a36Sopenharmony_ci} 347762306a36Sopenharmony_ci 347862306a36Sopenharmony_ci 347962306a36Sopenharmony_ciint pvr2_hdw_cpufw_get(struct pvr2_hdw *hdw,unsigned int offs, 348062306a36Sopenharmony_ci char *buf,unsigned int cnt) 348162306a36Sopenharmony_ci{ 348262306a36Sopenharmony_ci int ret = -EINVAL; 348362306a36Sopenharmony_ci LOCK_TAKE(hdw->big_lock); 348462306a36Sopenharmony_ci do { 348562306a36Sopenharmony_ci if (!buf) break; 348662306a36Sopenharmony_ci if (!cnt) break; 348762306a36Sopenharmony_ci 348862306a36Sopenharmony_ci if (!hdw->fw_buffer) { 348962306a36Sopenharmony_ci ret = -EIO; 349062306a36Sopenharmony_ci break; 349162306a36Sopenharmony_ci } 349262306a36Sopenharmony_ci 349362306a36Sopenharmony_ci if (offs >= hdw->fw_size) { 349462306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_FIRMWARE, 349562306a36Sopenharmony_ci "Read firmware data offs=%d EOF", 349662306a36Sopenharmony_ci offs); 349762306a36Sopenharmony_ci ret = 0; 349862306a36Sopenharmony_ci break; 349962306a36Sopenharmony_ci } 350062306a36Sopenharmony_ci 350162306a36Sopenharmony_ci if (offs + cnt > hdw->fw_size) cnt = hdw->fw_size - offs; 350262306a36Sopenharmony_ci 350362306a36Sopenharmony_ci memcpy(buf,hdw->fw_buffer+offs,cnt); 350462306a36Sopenharmony_ci 350562306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_FIRMWARE, 350662306a36Sopenharmony_ci "Read firmware data offs=%d cnt=%d", 350762306a36Sopenharmony_ci offs,cnt); 350862306a36Sopenharmony_ci ret = cnt; 350962306a36Sopenharmony_ci } while (0); 351062306a36Sopenharmony_ci LOCK_GIVE(hdw->big_lock); 351162306a36Sopenharmony_ci 351262306a36Sopenharmony_ci return ret; 351362306a36Sopenharmony_ci} 351462306a36Sopenharmony_ci 351562306a36Sopenharmony_ci 351662306a36Sopenharmony_ciint pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *hdw, 351762306a36Sopenharmony_ci enum pvr2_v4l_type index) 351862306a36Sopenharmony_ci{ 351962306a36Sopenharmony_ci switch (index) { 352062306a36Sopenharmony_ci case pvr2_v4l_type_video: return hdw->v4l_minor_number_video; 352162306a36Sopenharmony_ci case pvr2_v4l_type_vbi: return hdw->v4l_minor_number_vbi; 352262306a36Sopenharmony_ci case pvr2_v4l_type_radio: return hdw->v4l_minor_number_radio; 352362306a36Sopenharmony_ci default: return -1; 352462306a36Sopenharmony_ci } 352562306a36Sopenharmony_ci} 352662306a36Sopenharmony_ci 352762306a36Sopenharmony_ci 352862306a36Sopenharmony_ci/* Store a v4l minor device number */ 352962306a36Sopenharmony_civoid pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *hdw, 353062306a36Sopenharmony_ci enum pvr2_v4l_type index,int v) 353162306a36Sopenharmony_ci{ 353262306a36Sopenharmony_ci switch (index) { 353362306a36Sopenharmony_ci case pvr2_v4l_type_video: hdw->v4l_minor_number_video = v;break; 353462306a36Sopenharmony_ci case pvr2_v4l_type_vbi: hdw->v4l_minor_number_vbi = v;break; 353562306a36Sopenharmony_ci case pvr2_v4l_type_radio: hdw->v4l_minor_number_radio = v;break; 353662306a36Sopenharmony_ci default: break; 353762306a36Sopenharmony_ci } 353862306a36Sopenharmony_ci} 353962306a36Sopenharmony_ci 354062306a36Sopenharmony_ci 354162306a36Sopenharmony_cistatic void pvr2_ctl_write_complete(struct urb *urb) 354262306a36Sopenharmony_ci{ 354362306a36Sopenharmony_ci struct pvr2_hdw *hdw = urb->context; 354462306a36Sopenharmony_ci hdw->ctl_write_pend_flag = 0; 354562306a36Sopenharmony_ci if (hdw->ctl_read_pend_flag) return; 354662306a36Sopenharmony_ci complete(&hdw->ctl_done); 354762306a36Sopenharmony_ci} 354862306a36Sopenharmony_ci 354962306a36Sopenharmony_ci 355062306a36Sopenharmony_cistatic void pvr2_ctl_read_complete(struct urb *urb) 355162306a36Sopenharmony_ci{ 355262306a36Sopenharmony_ci struct pvr2_hdw *hdw = urb->context; 355362306a36Sopenharmony_ci hdw->ctl_read_pend_flag = 0; 355462306a36Sopenharmony_ci if (hdw->ctl_write_pend_flag) return; 355562306a36Sopenharmony_ci complete(&hdw->ctl_done); 355662306a36Sopenharmony_ci} 355762306a36Sopenharmony_ci 355862306a36Sopenharmony_cistruct hdw_timer { 355962306a36Sopenharmony_ci struct timer_list timer; 356062306a36Sopenharmony_ci struct pvr2_hdw *hdw; 356162306a36Sopenharmony_ci}; 356262306a36Sopenharmony_ci 356362306a36Sopenharmony_cistatic void pvr2_ctl_timeout(struct timer_list *t) 356462306a36Sopenharmony_ci{ 356562306a36Sopenharmony_ci struct hdw_timer *timer = from_timer(timer, t, timer); 356662306a36Sopenharmony_ci struct pvr2_hdw *hdw = timer->hdw; 356762306a36Sopenharmony_ci 356862306a36Sopenharmony_ci if (hdw->ctl_write_pend_flag || hdw->ctl_read_pend_flag) { 356962306a36Sopenharmony_ci hdw->ctl_timeout_flag = !0; 357062306a36Sopenharmony_ci if (hdw->ctl_write_pend_flag) 357162306a36Sopenharmony_ci usb_unlink_urb(hdw->ctl_write_urb); 357262306a36Sopenharmony_ci if (hdw->ctl_read_pend_flag) 357362306a36Sopenharmony_ci usb_unlink_urb(hdw->ctl_read_urb); 357462306a36Sopenharmony_ci } 357562306a36Sopenharmony_ci} 357662306a36Sopenharmony_ci 357762306a36Sopenharmony_ci 357862306a36Sopenharmony_ci/* Issue a command and get a response from the device. This extended 357962306a36Sopenharmony_ci version includes a probe flag (which if set means that device errors 358062306a36Sopenharmony_ci should not be logged or treated as fatal) and a timeout in jiffies. 358162306a36Sopenharmony_ci This can be used to non-lethally probe the health of endpoint 1. */ 358262306a36Sopenharmony_cistatic int pvr2_send_request_ex(struct pvr2_hdw *hdw, 358362306a36Sopenharmony_ci unsigned int timeout,int probe_fl, 358462306a36Sopenharmony_ci void *write_data,unsigned int write_len, 358562306a36Sopenharmony_ci void *read_data,unsigned int read_len) 358662306a36Sopenharmony_ci{ 358762306a36Sopenharmony_ci unsigned int idx; 358862306a36Sopenharmony_ci int status = 0; 358962306a36Sopenharmony_ci struct hdw_timer timer = { 359062306a36Sopenharmony_ci .hdw = hdw, 359162306a36Sopenharmony_ci }; 359262306a36Sopenharmony_ci 359362306a36Sopenharmony_ci if (!hdw->ctl_lock_held) { 359462306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 359562306a36Sopenharmony_ci "Attempted to execute control transfer without lock!!"); 359662306a36Sopenharmony_ci return -EDEADLK; 359762306a36Sopenharmony_ci } 359862306a36Sopenharmony_ci if (!hdw->flag_ok && !probe_fl) { 359962306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 360062306a36Sopenharmony_ci "Attempted to execute control transfer when device not ok"); 360162306a36Sopenharmony_ci return -EIO; 360262306a36Sopenharmony_ci } 360362306a36Sopenharmony_ci if (!(hdw->ctl_read_urb && hdw->ctl_write_urb)) { 360462306a36Sopenharmony_ci if (!probe_fl) { 360562306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 360662306a36Sopenharmony_ci "Attempted to execute control transfer when USB is disconnected"); 360762306a36Sopenharmony_ci } 360862306a36Sopenharmony_ci return -ENOTTY; 360962306a36Sopenharmony_ci } 361062306a36Sopenharmony_ci 361162306a36Sopenharmony_ci /* Ensure that we have sane parameters */ 361262306a36Sopenharmony_ci if (!write_data) write_len = 0; 361362306a36Sopenharmony_ci if (!read_data) read_len = 0; 361462306a36Sopenharmony_ci if (write_len > PVR2_CTL_BUFFSIZE) { 361562306a36Sopenharmony_ci pvr2_trace( 361662306a36Sopenharmony_ci PVR2_TRACE_ERROR_LEGS, 361762306a36Sopenharmony_ci "Attempted to execute %d byte control-write transfer (limit=%d)", 361862306a36Sopenharmony_ci write_len,PVR2_CTL_BUFFSIZE); 361962306a36Sopenharmony_ci return -EINVAL; 362062306a36Sopenharmony_ci } 362162306a36Sopenharmony_ci if (read_len > PVR2_CTL_BUFFSIZE) { 362262306a36Sopenharmony_ci pvr2_trace( 362362306a36Sopenharmony_ci PVR2_TRACE_ERROR_LEGS, 362462306a36Sopenharmony_ci "Attempted to execute %d byte control-read transfer (limit=%d)", 362562306a36Sopenharmony_ci write_len,PVR2_CTL_BUFFSIZE); 362662306a36Sopenharmony_ci return -EINVAL; 362762306a36Sopenharmony_ci } 362862306a36Sopenharmony_ci if ((!write_len) && (!read_len)) { 362962306a36Sopenharmony_ci pvr2_trace( 363062306a36Sopenharmony_ci PVR2_TRACE_ERROR_LEGS, 363162306a36Sopenharmony_ci "Attempted to execute null control transfer?"); 363262306a36Sopenharmony_ci return -EINVAL; 363362306a36Sopenharmony_ci } 363462306a36Sopenharmony_ci 363562306a36Sopenharmony_ci 363662306a36Sopenharmony_ci hdw->cmd_debug_state = 1; 363762306a36Sopenharmony_ci if (write_len && write_data) 363862306a36Sopenharmony_ci hdw->cmd_debug_code = ((unsigned char *)write_data)[0]; 363962306a36Sopenharmony_ci else 364062306a36Sopenharmony_ci hdw->cmd_debug_code = 0; 364162306a36Sopenharmony_ci hdw->cmd_debug_write_len = write_len; 364262306a36Sopenharmony_ci hdw->cmd_debug_read_len = read_len; 364362306a36Sopenharmony_ci 364462306a36Sopenharmony_ci /* Initialize common stuff */ 364562306a36Sopenharmony_ci init_completion(&hdw->ctl_done); 364662306a36Sopenharmony_ci hdw->ctl_timeout_flag = 0; 364762306a36Sopenharmony_ci hdw->ctl_write_pend_flag = 0; 364862306a36Sopenharmony_ci hdw->ctl_read_pend_flag = 0; 364962306a36Sopenharmony_ci timer_setup_on_stack(&timer.timer, pvr2_ctl_timeout, 0); 365062306a36Sopenharmony_ci timer.timer.expires = jiffies + timeout; 365162306a36Sopenharmony_ci 365262306a36Sopenharmony_ci if (write_len && write_data) { 365362306a36Sopenharmony_ci hdw->cmd_debug_state = 2; 365462306a36Sopenharmony_ci /* Transfer write data to internal buffer */ 365562306a36Sopenharmony_ci for (idx = 0; idx < write_len; idx++) { 365662306a36Sopenharmony_ci hdw->ctl_write_buffer[idx] = 365762306a36Sopenharmony_ci ((unsigned char *)write_data)[idx]; 365862306a36Sopenharmony_ci } 365962306a36Sopenharmony_ci /* Initiate a write request */ 366062306a36Sopenharmony_ci usb_fill_bulk_urb(hdw->ctl_write_urb, 366162306a36Sopenharmony_ci hdw->usb_dev, 366262306a36Sopenharmony_ci usb_sndbulkpipe(hdw->usb_dev, 366362306a36Sopenharmony_ci PVR2_CTL_WRITE_ENDPOINT), 366462306a36Sopenharmony_ci hdw->ctl_write_buffer, 366562306a36Sopenharmony_ci write_len, 366662306a36Sopenharmony_ci pvr2_ctl_write_complete, 366762306a36Sopenharmony_ci hdw); 366862306a36Sopenharmony_ci hdw->ctl_write_urb->actual_length = 0; 366962306a36Sopenharmony_ci hdw->ctl_write_pend_flag = !0; 367062306a36Sopenharmony_ci if (usb_urb_ep_type_check(hdw->ctl_write_urb)) { 367162306a36Sopenharmony_ci pvr2_trace( 367262306a36Sopenharmony_ci PVR2_TRACE_ERROR_LEGS, 367362306a36Sopenharmony_ci "Invalid write control endpoint"); 367462306a36Sopenharmony_ci return -EINVAL; 367562306a36Sopenharmony_ci } 367662306a36Sopenharmony_ci status = usb_submit_urb(hdw->ctl_write_urb,GFP_KERNEL); 367762306a36Sopenharmony_ci if (status < 0) { 367862306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 367962306a36Sopenharmony_ci "Failed to submit write-control URB status=%d", 368062306a36Sopenharmony_cistatus); 368162306a36Sopenharmony_ci hdw->ctl_write_pend_flag = 0; 368262306a36Sopenharmony_ci goto done; 368362306a36Sopenharmony_ci } 368462306a36Sopenharmony_ci } 368562306a36Sopenharmony_ci 368662306a36Sopenharmony_ci if (read_len) { 368762306a36Sopenharmony_ci hdw->cmd_debug_state = 3; 368862306a36Sopenharmony_ci memset(hdw->ctl_read_buffer,0x43,read_len); 368962306a36Sopenharmony_ci /* Initiate a read request */ 369062306a36Sopenharmony_ci usb_fill_bulk_urb(hdw->ctl_read_urb, 369162306a36Sopenharmony_ci hdw->usb_dev, 369262306a36Sopenharmony_ci usb_rcvbulkpipe(hdw->usb_dev, 369362306a36Sopenharmony_ci PVR2_CTL_READ_ENDPOINT), 369462306a36Sopenharmony_ci hdw->ctl_read_buffer, 369562306a36Sopenharmony_ci read_len, 369662306a36Sopenharmony_ci pvr2_ctl_read_complete, 369762306a36Sopenharmony_ci hdw); 369862306a36Sopenharmony_ci hdw->ctl_read_urb->actual_length = 0; 369962306a36Sopenharmony_ci hdw->ctl_read_pend_flag = !0; 370062306a36Sopenharmony_ci if (usb_urb_ep_type_check(hdw->ctl_read_urb)) { 370162306a36Sopenharmony_ci pvr2_trace( 370262306a36Sopenharmony_ci PVR2_TRACE_ERROR_LEGS, 370362306a36Sopenharmony_ci "Invalid read control endpoint"); 370462306a36Sopenharmony_ci return -EINVAL; 370562306a36Sopenharmony_ci } 370662306a36Sopenharmony_ci status = usb_submit_urb(hdw->ctl_read_urb,GFP_KERNEL); 370762306a36Sopenharmony_ci if (status < 0) { 370862306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 370962306a36Sopenharmony_ci "Failed to submit read-control URB status=%d", 371062306a36Sopenharmony_cistatus); 371162306a36Sopenharmony_ci hdw->ctl_read_pend_flag = 0; 371262306a36Sopenharmony_ci goto done; 371362306a36Sopenharmony_ci } 371462306a36Sopenharmony_ci } 371562306a36Sopenharmony_ci 371662306a36Sopenharmony_ci /* Start timer */ 371762306a36Sopenharmony_ci add_timer(&timer.timer); 371862306a36Sopenharmony_ci 371962306a36Sopenharmony_ci /* Now wait for all I/O to complete */ 372062306a36Sopenharmony_ci hdw->cmd_debug_state = 4; 372162306a36Sopenharmony_ci while (hdw->ctl_write_pend_flag || hdw->ctl_read_pend_flag) { 372262306a36Sopenharmony_ci wait_for_completion(&hdw->ctl_done); 372362306a36Sopenharmony_ci } 372462306a36Sopenharmony_ci hdw->cmd_debug_state = 5; 372562306a36Sopenharmony_ci 372662306a36Sopenharmony_ci /* Stop timer */ 372762306a36Sopenharmony_ci del_timer_sync(&timer.timer); 372862306a36Sopenharmony_ci 372962306a36Sopenharmony_ci hdw->cmd_debug_state = 6; 373062306a36Sopenharmony_ci status = 0; 373162306a36Sopenharmony_ci 373262306a36Sopenharmony_ci if (hdw->ctl_timeout_flag) { 373362306a36Sopenharmony_ci status = -ETIMEDOUT; 373462306a36Sopenharmony_ci if (!probe_fl) { 373562306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 373662306a36Sopenharmony_ci "Timed out control-write"); 373762306a36Sopenharmony_ci } 373862306a36Sopenharmony_ci goto done; 373962306a36Sopenharmony_ci } 374062306a36Sopenharmony_ci 374162306a36Sopenharmony_ci if (write_len) { 374262306a36Sopenharmony_ci /* Validate results of write request */ 374362306a36Sopenharmony_ci if ((hdw->ctl_write_urb->status != 0) && 374462306a36Sopenharmony_ci (hdw->ctl_write_urb->status != -ENOENT) && 374562306a36Sopenharmony_ci (hdw->ctl_write_urb->status != -ESHUTDOWN) && 374662306a36Sopenharmony_ci (hdw->ctl_write_urb->status != -ECONNRESET)) { 374762306a36Sopenharmony_ci /* USB subsystem is reporting some kind of failure 374862306a36Sopenharmony_ci on the write */ 374962306a36Sopenharmony_ci status = hdw->ctl_write_urb->status; 375062306a36Sopenharmony_ci if (!probe_fl) { 375162306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 375262306a36Sopenharmony_ci "control-write URB failure, status=%d", 375362306a36Sopenharmony_ci status); 375462306a36Sopenharmony_ci } 375562306a36Sopenharmony_ci goto done; 375662306a36Sopenharmony_ci } 375762306a36Sopenharmony_ci if (hdw->ctl_write_urb->actual_length < write_len) { 375862306a36Sopenharmony_ci /* Failed to write enough data */ 375962306a36Sopenharmony_ci status = -EIO; 376062306a36Sopenharmony_ci if (!probe_fl) { 376162306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 376262306a36Sopenharmony_ci "control-write URB short, expected=%d got=%d", 376362306a36Sopenharmony_ci write_len, 376462306a36Sopenharmony_ci hdw->ctl_write_urb->actual_length); 376562306a36Sopenharmony_ci } 376662306a36Sopenharmony_ci goto done; 376762306a36Sopenharmony_ci } 376862306a36Sopenharmony_ci } 376962306a36Sopenharmony_ci if (read_len && read_data) { 377062306a36Sopenharmony_ci /* Validate results of read request */ 377162306a36Sopenharmony_ci if ((hdw->ctl_read_urb->status != 0) && 377262306a36Sopenharmony_ci (hdw->ctl_read_urb->status != -ENOENT) && 377362306a36Sopenharmony_ci (hdw->ctl_read_urb->status != -ESHUTDOWN) && 377462306a36Sopenharmony_ci (hdw->ctl_read_urb->status != -ECONNRESET)) { 377562306a36Sopenharmony_ci /* USB subsystem is reporting some kind of failure 377662306a36Sopenharmony_ci on the read */ 377762306a36Sopenharmony_ci status = hdw->ctl_read_urb->status; 377862306a36Sopenharmony_ci if (!probe_fl) { 377962306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 378062306a36Sopenharmony_ci "control-read URB failure, status=%d", 378162306a36Sopenharmony_ci status); 378262306a36Sopenharmony_ci } 378362306a36Sopenharmony_ci goto done; 378462306a36Sopenharmony_ci } 378562306a36Sopenharmony_ci if (hdw->ctl_read_urb->actual_length < read_len) { 378662306a36Sopenharmony_ci /* Failed to read enough data */ 378762306a36Sopenharmony_ci status = -EIO; 378862306a36Sopenharmony_ci if (!probe_fl) { 378962306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 379062306a36Sopenharmony_ci "control-read URB short, expected=%d got=%d", 379162306a36Sopenharmony_ci read_len, 379262306a36Sopenharmony_ci hdw->ctl_read_urb->actual_length); 379362306a36Sopenharmony_ci } 379462306a36Sopenharmony_ci goto done; 379562306a36Sopenharmony_ci } 379662306a36Sopenharmony_ci /* Transfer retrieved data out from internal buffer */ 379762306a36Sopenharmony_ci for (idx = 0; idx < read_len; idx++) { 379862306a36Sopenharmony_ci ((unsigned char *)read_data)[idx] = 379962306a36Sopenharmony_ci hdw->ctl_read_buffer[idx]; 380062306a36Sopenharmony_ci } 380162306a36Sopenharmony_ci } 380262306a36Sopenharmony_ci 380362306a36Sopenharmony_ci done: 380462306a36Sopenharmony_ci 380562306a36Sopenharmony_ci hdw->cmd_debug_state = 0; 380662306a36Sopenharmony_ci if ((status < 0) && (!probe_fl)) { 380762306a36Sopenharmony_ci pvr2_hdw_render_useless(hdw); 380862306a36Sopenharmony_ci } 380962306a36Sopenharmony_ci destroy_timer_on_stack(&timer.timer); 381062306a36Sopenharmony_ci 381162306a36Sopenharmony_ci return status; 381262306a36Sopenharmony_ci} 381362306a36Sopenharmony_ci 381462306a36Sopenharmony_ci 381562306a36Sopenharmony_ciint pvr2_send_request(struct pvr2_hdw *hdw, 381662306a36Sopenharmony_ci void *write_data,unsigned int write_len, 381762306a36Sopenharmony_ci void *read_data,unsigned int read_len) 381862306a36Sopenharmony_ci{ 381962306a36Sopenharmony_ci return pvr2_send_request_ex(hdw,HZ*4,0, 382062306a36Sopenharmony_ci write_data,write_len, 382162306a36Sopenharmony_ci read_data,read_len); 382262306a36Sopenharmony_ci} 382362306a36Sopenharmony_ci 382462306a36Sopenharmony_ci 382562306a36Sopenharmony_cistatic int pvr2_issue_simple_cmd(struct pvr2_hdw *hdw,u32 cmdcode) 382662306a36Sopenharmony_ci{ 382762306a36Sopenharmony_ci int ret; 382862306a36Sopenharmony_ci unsigned int cnt = 1; 382962306a36Sopenharmony_ci unsigned int args = 0; 383062306a36Sopenharmony_ci LOCK_TAKE(hdw->ctl_lock); 383162306a36Sopenharmony_ci hdw->cmd_buffer[0] = cmdcode & 0xffu; 383262306a36Sopenharmony_ci args = (cmdcode >> 8) & 0xffu; 383362306a36Sopenharmony_ci args = (args > 2) ? 2 : args; 383462306a36Sopenharmony_ci if (args) { 383562306a36Sopenharmony_ci cnt += args; 383662306a36Sopenharmony_ci hdw->cmd_buffer[1] = (cmdcode >> 16) & 0xffu; 383762306a36Sopenharmony_ci if (args > 1) { 383862306a36Sopenharmony_ci hdw->cmd_buffer[2] = (cmdcode >> 24) & 0xffu; 383962306a36Sopenharmony_ci } 384062306a36Sopenharmony_ci } 384162306a36Sopenharmony_ci if (pvrusb2_debug & PVR2_TRACE_INIT) { 384262306a36Sopenharmony_ci unsigned int idx; 384362306a36Sopenharmony_ci unsigned int ccnt,bcnt; 384462306a36Sopenharmony_ci char tbuf[50]; 384562306a36Sopenharmony_ci cmdcode &= 0xffu; 384662306a36Sopenharmony_ci bcnt = 0; 384762306a36Sopenharmony_ci ccnt = scnprintf(tbuf+bcnt, 384862306a36Sopenharmony_ci sizeof(tbuf)-bcnt, 384962306a36Sopenharmony_ci "Sending FX2 command 0x%x",cmdcode); 385062306a36Sopenharmony_ci bcnt += ccnt; 385162306a36Sopenharmony_ci for (idx = 0; idx < ARRAY_SIZE(pvr2_fx2cmd_desc); idx++) { 385262306a36Sopenharmony_ci if (pvr2_fx2cmd_desc[idx].id == cmdcode) { 385362306a36Sopenharmony_ci ccnt = scnprintf(tbuf+bcnt, 385462306a36Sopenharmony_ci sizeof(tbuf)-bcnt, 385562306a36Sopenharmony_ci " \"%s\"", 385662306a36Sopenharmony_ci pvr2_fx2cmd_desc[idx].desc); 385762306a36Sopenharmony_ci bcnt += ccnt; 385862306a36Sopenharmony_ci break; 385962306a36Sopenharmony_ci } 386062306a36Sopenharmony_ci } 386162306a36Sopenharmony_ci if (args) { 386262306a36Sopenharmony_ci ccnt = scnprintf(tbuf+bcnt, 386362306a36Sopenharmony_ci sizeof(tbuf)-bcnt, 386462306a36Sopenharmony_ci " (%u",hdw->cmd_buffer[1]); 386562306a36Sopenharmony_ci bcnt += ccnt; 386662306a36Sopenharmony_ci if (args > 1) { 386762306a36Sopenharmony_ci ccnt = scnprintf(tbuf+bcnt, 386862306a36Sopenharmony_ci sizeof(tbuf)-bcnt, 386962306a36Sopenharmony_ci ",%u",hdw->cmd_buffer[2]); 387062306a36Sopenharmony_ci bcnt += ccnt; 387162306a36Sopenharmony_ci } 387262306a36Sopenharmony_ci ccnt = scnprintf(tbuf+bcnt, 387362306a36Sopenharmony_ci sizeof(tbuf)-bcnt, 387462306a36Sopenharmony_ci ")"); 387562306a36Sopenharmony_ci bcnt += ccnt; 387662306a36Sopenharmony_ci } 387762306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT,"%.*s",bcnt,tbuf); 387862306a36Sopenharmony_ci } 387962306a36Sopenharmony_ci ret = pvr2_send_request(hdw,hdw->cmd_buffer,cnt,NULL,0); 388062306a36Sopenharmony_ci LOCK_GIVE(hdw->ctl_lock); 388162306a36Sopenharmony_ci return ret; 388262306a36Sopenharmony_ci} 388362306a36Sopenharmony_ci 388462306a36Sopenharmony_ci 388562306a36Sopenharmony_ciint pvr2_write_register(struct pvr2_hdw *hdw, u16 reg, u32 data) 388662306a36Sopenharmony_ci{ 388762306a36Sopenharmony_ci int ret; 388862306a36Sopenharmony_ci 388962306a36Sopenharmony_ci LOCK_TAKE(hdw->ctl_lock); 389062306a36Sopenharmony_ci 389162306a36Sopenharmony_ci hdw->cmd_buffer[0] = FX2CMD_REG_WRITE; /* write register prefix */ 389262306a36Sopenharmony_ci PVR2_DECOMPOSE_LE(hdw->cmd_buffer,1,data); 389362306a36Sopenharmony_ci hdw->cmd_buffer[5] = 0; 389462306a36Sopenharmony_ci hdw->cmd_buffer[6] = (reg >> 8) & 0xff; 389562306a36Sopenharmony_ci hdw->cmd_buffer[7] = reg & 0xff; 389662306a36Sopenharmony_ci 389762306a36Sopenharmony_ci 389862306a36Sopenharmony_ci ret = pvr2_send_request(hdw, hdw->cmd_buffer, 8, hdw->cmd_buffer, 0); 389962306a36Sopenharmony_ci 390062306a36Sopenharmony_ci LOCK_GIVE(hdw->ctl_lock); 390162306a36Sopenharmony_ci 390262306a36Sopenharmony_ci return ret; 390362306a36Sopenharmony_ci} 390462306a36Sopenharmony_ci 390562306a36Sopenharmony_ci 390662306a36Sopenharmony_cistatic int pvr2_read_register(struct pvr2_hdw *hdw, u16 reg, u32 *data) 390762306a36Sopenharmony_ci{ 390862306a36Sopenharmony_ci int ret = 0; 390962306a36Sopenharmony_ci 391062306a36Sopenharmony_ci LOCK_TAKE(hdw->ctl_lock); 391162306a36Sopenharmony_ci 391262306a36Sopenharmony_ci hdw->cmd_buffer[0] = FX2CMD_REG_READ; /* read register prefix */ 391362306a36Sopenharmony_ci hdw->cmd_buffer[1] = 0; 391462306a36Sopenharmony_ci hdw->cmd_buffer[2] = 0; 391562306a36Sopenharmony_ci hdw->cmd_buffer[3] = 0; 391662306a36Sopenharmony_ci hdw->cmd_buffer[4] = 0; 391762306a36Sopenharmony_ci hdw->cmd_buffer[5] = 0; 391862306a36Sopenharmony_ci hdw->cmd_buffer[6] = (reg >> 8) & 0xff; 391962306a36Sopenharmony_ci hdw->cmd_buffer[7] = reg & 0xff; 392062306a36Sopenharmony_ci 392162306a36Sopenharmony_ci ret |= pvr2_send_request(hdw, hdw->cmd_buffer, 8, hdw->cmd_buffer, 4); 392262306a36Sopenharmony_ci *data = PVR2_COMPOSE_LE(hdw->cmd_buffer,0); 392362306a36Sopenharmony_ci 392462306a36Sopenharmony_ci LOCK_GIVE(hdw->ctl_lock); 392562306a36Sopenharmony_ci 392662306a36Sopenharmony_ci return ret; 392762306a36Sopenharmony_ci} 392862306a36Sopenharmony_ci 392962306a36Sopenharmony_ci 393062306a36Sopenharmony_civoid pvr2_hdw_render_useless(struct pvr2_hdw *hdw) 393162306a36Sopenharmony_ci{ 393262306a36Sopenharmony_ci if (!hdw->flag_ok) return; 393362306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 393462306a36Sopenharmony_ci "Device being rendered inoperable"); 393562306a36Sopenharmony_ci if (hdw->vid_stream) { 393662306a36Sopenharmony_ci pvr2_stream_setup(hdw->vid_stream,NULL,0,0); 393762306a36Sopenharmony_ci } 393862306a36Sopenharmony_ci hdw->flag_ok = 0; 393962306a36Sopenharmony_ci trace_stbit("flag_ok",hdw->flag_ok); 394062306a36Sopenharmony_ci pvr2_hdw_state_sched(hdw); 394162306a36Sopenharmony_ci} 394262306a36Sopenharmony_ci 394362306a36Sopenharmony_ci 394462306a36Sopenharmony_civoid pvr2_hdw_device_reset(struct pvr2_hdw *hdw) 394562306a36Sopenharmony_ci{ 394662306a36Sopenharmony_ci int ret; 394762306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT,"Performing a device reset..."); 394862306a36Sopenharmony_ci ret = usb_lock_device_for_reset(hdw->usb_dev,NULL); 394962306a36Sopenharmony_ci if (ret == 0) { 395062306a36Sopenharmony_ci ret = usb_reset_device(hdw->usb_dev); 395162306a36Sopenharmony_ci usb_unlock_device(hdw->usb_dev); 395262306a36Sopenharmony_ci } else { 395362306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 395462306a36Sopenharmony_ci "Failed to lock USB device ret=%d",ret); 395562306a36Sopenharmony_ci } 395662306a36Sopenharmony_ci if (init_pause_msec) { 395762306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INFO, 395862306a36Sopenharmony_ci "Waiting %u msec for hardware to settle", 395962306a36Sopenharmony_ci init_pause_msec); 396062306a36Sopenharmony_ci msleep(init_pause_msec); 396162306a36Sopenharmony_ci } 396262306a36Sopenharmony_ci 396362306a36Sopenharmony_ci} 396462306a36Sopenharmony_ci 396562306a36Sopenharmony_ci 396662306a36Sopenharmony_civoid pvr2_hdw_cpureset_assert(struct pvr2_hdw *hdw,int val) 396762306a36Sopenharmony_ci{ 396862306a36Sopenharmony_ci char *da; 396962306a36Sopenharmony_ci unsigned int pipe; 397062306a36Sopenharmony_ci int ret; 397162306a36Sopenharmony_ci 397262306a36Sopenharmony_ci if (!hdw->usb_dev) return; 397362306a36Sopenharmony_ci 397462306a36Sopenharmony_ci da = kmalloc(16, GFP_KERNEL); 397562306a36Sopenharmony_ci 397662306a36Sopenharmony_ci if (da == NULL) { 397762306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 397862306a36Sopenharmony_ci "Unable to allocate memory to control CPU reset"); 397962306a36Sopenharmony_ci return; 398062306a36Sopenharmony_ci } 398162306a36Sopenharmony_ci 398262306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT,"cpureset_assert(%d)",val); 398362306a36Sopenharmony_ci 398462306a36Sopenharmony_ci da[0] = val ? 0x01 : 0x00; 398562306a36Sopenharmony_ci 398662306a36Sopenharmony_ci /* Write the CPUCS register on the 8051. The lsb of the register 398762306a36Sopenharmony_ci is the reset bit; a 1 asserts reset while a 0 clears it. */ 398862306a36Sopenharmony_ci pipe = usb_sndctrlpipe(hdw->usb_dev, 0); 398962306a36Sopenharmony_ci ret = usb_control_msg(hdw->usb_dev,pipe,0xa0,0x40,0xe600,0,da,1,1000); 399062306a36Sopenharmony_ci if (ret < 0) { 399162306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 399262306a36Sopenharmony_ci "cpureset_assert(%d) error=%d",val,ret); 399362306a36Sopenharmony_ci pvr2_hdw_render_useless(hdw); 399462306a36Sopenharmony_ci } 399562306a36Sopenharmony_ci 399662306a36Sopenharmony_ci kfree(da); 399762306a36Sopenharmony_ci} 399862306a36Sopenharmony_ci 399962306a36Sopenharmony_ci 400062306a36Sopenharmony_ciint pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *hdw) 400162306a36Sopenharmony_ci{ 400262306a36Sopenharmony_ci return pvr2_issue_simple_cmd(hdw,FX2CMD_DEEP_RESET); 400362306a36Sopenharmony_ci} 400462306a36Sopenharmony_ci 400562306a36Sopenharmony_ci 400662306a36Sopenharmony_ciint pvr2_hdw_cmd_powerup(struct pvr2_hdw *hdw) 400762306a36Sopenharmony_ci{ 400862306a36Sopenharmony_ci return pvr2_issue_simple_cmd(hdw,FX2CMD_POWER_ON); 400962306a36Sopenharmony_ci} 401062306a36Sopenharmony_ci 401162306a36Sopenharmony_ci 401262306a36Sopenharmony_ci 401362306a36Sopenharmony_ciint pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *hdw) 401462306a36Sopenharmony_ci{ 401562306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 401662306a36Sopenharmony_ci "Requesting decoder reset"); 401762306a36Sopenharmony_ci if (hdw->decoder_client_id) { 401862306a36Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, hdw->decoder_client_id, 401962306a36Sopenharmony_ci core, reset, 0); 402062306a36Sopenharmony_ci pvr2_hdw_cx25840_vbi_hack(hdw); 402162306a36Sopenharmony_ci return 0; 402262306a36Sopenharmony_ci } 402362306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 402462306a36Sopenharmony_ci "Unable to reset decoder: nothing attached"); 402562306a36Sopenharmony_ci return -ENOTTY; 402662306a36Sopenharmony_ci} 402762306a36Sopenharmony_ci 402862306a36Sopenharmony_ci 402962306a36Sopenharmony_cistatic int pvr2_hdw_cmd_hcw_demod_reset(struct pvr2_hdw *hdw, int onoff) 403062306a36Sopenharmony_ci{ 403162306a36Sopenharmony_ci hdw->flag_ok = !0; 403262306a36Sopenharmony_ci 403362306a36Sopenharmony_ci /* Use this for Hauppauge 160xxx only */ 403462306a36Sopenharmony_ci if (le16_to_cpu(hdw->usb_dev->descriptor.idVendor) == 0x2040 && 403562306a36Sopenharmony_ci (le16_to_cpu(hdw->usb_dev->descriptor.idProduct) == 0x7502 || 403662306a36Sopenharmony_ci le16_to_cpu(hdw->usb_dev->descriptor.idProduct) == 0x7510)) { 403762306a36Sopenharmony_ci pr_debug("%s(): resetting demod on Hauppauge 160xxx platform skipped\n", 403862306a36Sopenharmony_ci __func__); 403962306a36Sopenharmony_ci /* Can't reset 160xxx or it will trash Demod tristate */ 404062306a36Sopenharmony_ci return pvr2_issue_simple_cmd(hdw, 404162306a36Sopenharmony_ci FX2CMD_HCW_MAKO_SLEEP_PIN | 404262306a36Sopenharmony_ci (1 << 8) | 404362306a36Sopenharmony_ci ((onoff ? 1 : 0) << 16)); 404462306a36Sopenharmony_ci } 404562306a36Sopenharmony_ci 404662306a36Sopenharmony_ci return pvr2_issue_simple_cmd(hdw, 404762306a36Sopenharmony_ci FX2CMD_HCW_DEMOD_RESETIN | 404862306a36Sopenharmony_ci (1 << 8) | 404962306a36Sopenharmony_ci ((onoff ? 1 : 0) << 16)); 405062306a36Sopenharmony_ci} 405162306a36Sopenharmony_ci 405262306a36Sopenharmony_ci 405362306a36Sopenharmony_cistatic int pvr2_hdw_cmd_onair_fe_power_ctrl(struct pvr2_hdw *hdw, int onoff) 405462306a36Sopenharmony_ci{ 405562306a36Sopenharmony_ci hdw->flag_ok = !0; 405662306a36Sopenharmony_ci return pvr2_issue_simple_cmd(hdw,(onoff ? 405762306a36Sopenharmony_ci FX2CMD_ONAIR_DTV_POWER_ON : 405862306a36Sopenharmony_ci FX2CMD_ONAIR_DTV_POWER_OFF)); 405962306a36Sopenharmony_ci} 406062306a36Sopenharmony_ci 406162306a36Sopenharmony_ci 406262306a36Sopenharmony_cistatic int pvr2_hdw_cmd_onair_digital_path_ctrl(struct pvr2_hdw *hdw, 406362306a36Sopenharmony_ci int onoff) 406462306a36Sopenharmony_ci{ 406562306a36Sopenharmony_ci return pvr2_issue_simple_cmd(hdw,(onoff ? 406662306a36Sopenharmony_ci FX2CMD_ONAIR_DTV_STREAMING_ON : 406762306a36Sopenharmony_ci FX2CMD_ONAIR_DTV_STREAMING_OFF)); 406862306a36Sopenharmony_ci} 406962306a36Sopenharmony_ci 407062306a36Sopenharmony_ci 407162306a36Sopenharmony_cistatic void pvr2_hdw_cmd_modeswitch(struct pvr2_hdw *hdw,int digitalFl) 407262306a36Sopenharmony_ci{ 407362306a36Sopenharmony_ci int cmode; 407462306a36Sopenharmony_ci /* Compare digital/analog desired setting with current setting. If 407562306a36Sopenharmony_ci they don't match, fix it... */ 407662306a36Sopenharmony_ci cmode = (digitalFl ? PVR2_PATHWAY_DIGITAL : PVR2_PATHWAY_ANALOG); 407762306a36Sopenharmony_ci if (cmode == hdw->pathway_state) { 407862306a36Sopenharmony_ci /* They match; nothing to do */ 407962306a36Sopenharmony_ci return; 408062306a36Sopenharmony_ci } 408162306a36Sopenharmony_ci 408262306a36Sopenharmony_ci switch (hdw->hdw_desc->digital_control_scheme) { 408362306a36Sopenharmony_ci case PVR2_DIGITAL_SCHEME_HAUPPAUGE: 408462306a36Sopenharmony_ci pvr2_hdw_cmd_hcw_demod_reset(hdw,digitalFl); 408562306a36Sopenharmony_ci if (cmode == PVR2_PATHWAY_ANALOG) { 408662306a36Sopenharmony_ci /* If moving to analog mode, also force the decoder 408762306a36Sopenharmony_ci to reset. If no decoder is attached, then it's 408862306a36Sopenharmony_ci ok to ignore this because if/when the decoder 408962306a36Sopenharmony_ci attaches, it will reset itself at that time. */ 409062306a36Sopenharmony_ci pvr2_hdw_cmd_decoder_reset(hdw); 409162306a36Sopenharmony_ci } 409262306a36Sopenharmony_ci break; 409362306a36Sopenharmony_ci case PVR2_DIGITAL_SCHEME_ONAIR: 409462306a36Sopenharmony_ci /* Supposedly we should always have the power on whether in 409562306a36Sopenharmony_ci digital or analog mode. But for now do what appears to 409662306a36Sopenharmony_ci work... */ 409762306a36Sopenharmony_ci pvr2_hdw_cmd_onair_fe_power_ctrl(hdw,digitalFl); 409862306a36Sopenharmony_ci break; 409962306a36Sopenharmony_ci default: break; 410062306a36Sopenharmony_ci } 410162306a36Sopenharmony_ci 410262306a36Sopenharmony_ci pvr2_hdw_untrip_unlocked(hdw); 410362306a36Sopenharmony_ci hdw->pathway_state = cmode; 410462306a36Sopenharmony_ci} 410562306a36Sopenharmony_ci 410662306a36Sopenharmony_ci 410762306a36Sopenharmony_cistatic void pvr2_led_ctrl_hauppauge(struct pvr2_hdw *hdw, int onoff) 410862306a36Sopenharmony_ci{ 410962306a36Sopenharmony_ci /* change some GPIO data 411062306a36Sopenharmony_ci * 411162306a36Sopenharmony_ci * note: bit d7 of dir appears to control the LED, 411262306a36Sopenharmony_ci * so we shut it off here. 411362306a36Sopenharmony_ci * 411462306a36Sopenharmony_ci */ 411562306a36Sopenharmony_ci if (onoff) { 411662306a36Sopenharmony_ci pvr2_hdw_gpio_chg_dir(hdw, 0xffffffff, 0x00000481); 411762306a36Sopenharmony_ci } else { 411862306a36Sopenharmony_ci pvr2_hdw_gpio_chg_dir(hdw, 0xffffffff, 0x00000401); 411962306a36Sopenharmony_ci } 412062306a36Sopenharmony_ci pvr2_hdw_gpio_chg_out(hdw, 0xffffffff, 0x00000000); 412162306a36Sopenharmony_ci} 412262306a36Sopenharmony_ci 412362306a36Sopenharmony_ci 412462306a36Sopenharmony_citypedef void (*led_method_func)(struct pvr2_hdw *,int); 412562306a36Sopenharmony_ci 412662306a36Sopenharmony_cistatic led_method_func led_methods[] = { 412762306a36Sopenharmony_ci [PVR2_LED_SCHEME_HAUPPAUGE] = pvr2_led_ctrl_hauppauge, 412862306a36Sopenharmony_ci}; 412962306a36Sopenharmony_ci 413062306a36Sopenharmony_ci 413162306a36Sopenharmony_ci/* Toggle LED */ 413262306a36Sopenharmony_cistatic void pvr2_led_ctrl(struct pvr2_hdw *hdw,int onoff) 413362306a36Sopenharmony_ci{ 413462306a36Sopenharmony_ci unsigned int scheme_id; 413562306a36Sopenharmony_ci led_method_func fp; 413662306a36Sopenharmony_ci 413762306a36Sopenharmony_ci if ((!onoff) == (!hdw->led_on)) return; 413862306a36Sopenharmony_ci 413962306a36Sopenharmony_ci hdw->led_on = onoff != 0; 414062306a36Sopenharmony_ci 414162306a36Sopenharmony_ci scheme_id = hdw->hdw_desc->led_scheme; 414262306a36Sopenharmony_ci if (scheme_id < ARRAY_SIZE(led_methods)) { 414362306a36Sopenharmony_ci fp = led_methods[scheme_id]; 414462306a36Sopenharmony_ci } else { 414562306a36Sopenharmony_ci fp = NULL; 414662306a36Sopenharmony_ci } 414762306a36Sopenharmony_ci 414862306a36Sopenharmony_ci if (fp) (*fp)(hdw,onoff); 414962306a36Sopenharmony_ci} 415062306a36Sopenharmony_ci 415162306a36Sopenharmony_ci 415262306a36Sopenharmony_ci/* Stop / start video stream transport */ 415362306a36Sopenharmony_cistatic int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl) 415462306a36Sopenharmony_ci{ 415562306a36Sopenharmony_ci int ret; 415662306a36Sopenharmony_ci 415762306a36Sopenharmony_ci /* If we're in analog mode, then just issue the usual analog 415862306a36Sopenharmony_ci command. */ 415962306a36Sopenharmony_ci if (hdw->pathway_state == PVR2_PATHWAY_ANALOG) { 416062306a36Sopenharmony_ci return pvr2_issue_simple_cmd(hdw, 416162306a36Sopenharmony_ci (runFl ? 416262306a36Sopenharmony_ci FX2CMD_STREAMING_ON : 416362306a36Sopenharmony_ci FX2CMD_STREAMING_OFF)); 416462306a36Sopenharmony_ci /*Note: Not reached */ 416562306a36Sopenharmony_ci } 416662306a36Sopenharmony_ci 416762306a36Sopenharmony_ci if (hdw->pathway_state != PVR2_PATHWAY_DIGITAL) { 416862306a36Sopenharmony_ci /* Whoops, we don't know what mode we're in... */ 416962306a36Sopenharmony_ci return -EINVAL; 417062306a36Sopenharmony_ci } 417162306a36Sopenharmony_ci 417262306a36Sopenharmony_ci /* To get here we have to be in digital mode. The mechanism here 417362306a36Sopenharmony_ci is unfortunately different for different vendors. So we switch 417462306a36Sopenharmony_ci on the device's digital scheme attribute in order to figure out 417562306a36Sopenharmony_ci what to do. */ 417662306a36Sopenharmony_ci switch (hdw->hdw_desc->digital_control_scheme) { 417762306a36Sopenharmony_ci case PVR2_DIGITAL_SCHEME_HAUPPAUGE: 417862306a36Sopenharmony_ci return pvr2_issue_simple_cmd(hdw, 417962306a36Sopenharmony_ci (runFl ? 418062306a36Sopenharmony_ci FX2CMD_HCW_DTV_STREAMING_ON : 418162306a36Sopenharmony_ci FX2CMD_HCW_DTV_STREAMING_OFF)); 418262306a36Sopenharmony_ci case PVR2_DIGITAL_SCHEME_ONAIR: 418362306a36Sopenharmony_ci ret = pvr2_issue_simple_cmd(hdw, 418462306a36Sopenharmony_ci (runFl ? 418562306a36Sopenharmony_ci FX2CMD_STREAMING_ON : 418662306a36Sopenharmony_ci FX2CMD_STREAMING_OFF)); 418762306a36Sopenharmony_ci if (ret) return ret; 418862306a36Sopenharmony_ci return pvr2_hdw_cmd_onair_digital_path_ctrl(hdw,runFl); 418962306a36Sopenharmony_ci default: 419062306a36Sopenharmony_ci return -EINVAL; 419162306a36Sopenharmony_ci } 419262306a36Sopenharmony_ci} 419362306a36Sopenharmony_ci 419462306a36Sopenharmony_ci 419562306a36Sopenharmony_ci/* Evaluate whether or not state_pathway_ok can change */ 419662306a36Sopenharmony_cistatic int state_eval_pathway_ok(struct pvr2_hdw *hdw) 419762306a36Sopenharmony_ci{ 419862306a36Sopenharmony_ci if (hdw->state_pathway_ok) { 419962306a36Sopenharmony_ci /* Nothing to do if pathway is already ok */ 420062306a36Sopenharmony_ci return 0; 420162306a36Sopenharmony_ci } 420262306a36Sopenharmony_ci if (!hdw->state_pipeline_idle) { 420362306a36Sopenharmony_ci /* Not allowed to change anything if pipeline is not idle */ 420462306a36Sopenharmony_ci return 0; 420562306a36Sopenharmony_ci } 420662306a36Sopenharmony_ci pvr2_hdw_cmd_modeswitch(hdw,hdw->input_val == PVR2_CVAL_INPUT_DTV); 420762306a36Sopenharmony_ci hdw->state_pathway_ok = !0; 420862306a36Sopenharmony_ci trace_stbit("state_pathway_ok",hdw->state_pathway_ok); 420962306a36Sopenharmony_ci return !0; 421062306a36Sopenharmony_ci} 421162306a36Sopenharmony_ci 421262306a36Sopenharmony_ci 421362306a36Sopenharmony_ci/* Evaluate whether or not state_encoder_ok can change */ 421462306a36Sopenharmony_cistatic int state_eval_encoder_ok(struct pvr2_hdw *hdw) 421562306a36Sopenharmony_ci{ 421662306a36Sopenharmony_ci if (hdw->state_encoder_ok) return 0; 421762306a36Sopenharmony_ci if (hdw->flag_tripped) return 0; 421862306a36Sopenharmony_ci if (hdw->state_encoder_run) return 0; 421962306a36Sopenharmony_ci if (hdw->state_encoder_config) return 0; 422062306a36Sopenharmony_ci if (hdw->state_decoder_run) return 0; 422162306a36Sopenharmony_ci if (hdw->state_usbstream_run) return 0; 422262306a36Sopenharmony_ci if (hdw->pathway_state == PVR2_PATHWAY_DIGITAL) { 422362306a36Sopenharmony_ci if (!hdw->hdw_desc->flag_digital_requires_cx23416) return 0; 422462306a36Sopenharmony_ci } else if (hdw->pathway_state != PVR2_PATHWAY_ANALOG) { 422562306a36Sopenharmony_ci return 0; 422662306a36Sopenharmony_ci } 422762306a36Sopenharmony_ci 422862306a36Sopenharmony_ci if (pvr2_upload_firmware2(hdw) < 0) { 422962306a36Sopenharmony_ci hdw->flag_tripped = !0; 423062306a36Sopenharmony_ci trace_stbit("flag_tripped",hdw->flag_tripped); 423162306a36Sopenharmony_ci return !0; 423262306a36Sopenharmony_ci } 423362306a36Sopenharmony_ci hdw->state_encoder_ok = !0; 423462306a36Sopenharmony_ci trace_stbit("state_encoder_ok",hdw->state_encoder_ok); 423562306a36Sopenharmony_ci return !0; 423662306a36Sopenharmony_ci} 423762306a36Sopenharmony_ci 423862306a36Sopenharmony_ci 423962306a36Sopenharmony_ci/* Evaluate whether or not state_encoder_config can change */ 424062306a36Sopenharmony_cistatic int state_eval_encoder_config(struct pvr2_hdw *hdw) 424162306a36Sopenharmony_ci{ 424262306a36Sopenharmony_ci if (hdw->state_encoder_config) { 424362306a36Sopenharmony_ci if (hdw->state_encoder_ok) { 424462306a36Sopenharmony_ci if (hdw->state_pipeline_req && 424562306a36Sopenharmony_ci !hdw->state_pipeline_pause) return 0; 424662306a36Sopenharmony_ci } 424762306a36Sopenharmony_ci hdw->state_encoder_config = 0; 424862306a36Sopenharmony_ci hdw->state_encoder_waitok = 0; 424962306a36Sopenharmony_ci trace_stbit("state_encoder_waitok",hdw->state_encoder_waitok); 425062306a36Sopenharmony_ci /* paranoia - solve race if timer just completed */ 425162306a36Sopenharmony_ci del_timer_sync(&hdw->encoder_wait_timer); 425262306a36Sopenharmony_ci } else { 425362306a36Sopenharmony_ci if (!hdw->state_pathway_ok || 425462306a36Sopenharmony_ci (hdw->pathway_state != PVR2_PATHWAY_ANALOG) || 425562306a36Sopenharmony_ci !hdw->state_encoder_ok || 425662306a36Sopenharmony_ci !hdw->state_pipeline_idle || 425762306a36Sopenharmony_ci hdw->state_pipeline_pause || 425862306a36Sopenharmony_ci !hdw->state_pipeline_req || 425962306a36Sopenharmony_ci !hdw->state_pipeline_config) { 426062306a36Sopenharmony_ci /* We must reset the enforced wait interval if 426162306a36Sopenharmony_ci anything has happened that might have disturbed 426262306a36Sopenharmony_ci the encoder. This should be a rare case. */ 426362306a36Sopenharmony_ci if (timer_pending(&hdw->encoder_wait_timer)) { 426462306a36Sopenharmony_ci del_timer_sync(&hdw->encoder_wait_timer); 426562306a36Sopenharmony_ci } 426662306a36Sopenharmony_ci if (hdw->state_encoder_waitok) { 426762306a36Sopenharmony_ci /* Must clear the state - therefore we did 426862306a36Sopenharmony_ci something to a state bit and must also 426962306a36Sopenharmony_ci return true. */ 427062306a36Sopenharmony_ci hdw->state_encoder_waitok = 0; 427162306a36Sopenharmony_ci trace_stbit("state_encoder_waitok", 427262306a36Sopenharmony_ci hdw->state_encoder_waitok); 427362306a36Sopenharmony_ci return !0; 427462306a36Sopenharmony_ci } 427562306a36Sopenharmony_ci return 0; 427662306a36Sopenharmony_ci } 427762306a36Sopenharmony_ci if (!hdw->state_encoder_waitok) { 427862306a36Sopenharmony_ci if (!timer_pending(&hdw->encoder_wait_timer)) { 427962306a36Sopenharmony_ci /* waitok flag wasn't set and timer isn't 428062306a36Sopenharmony_ci running. Check flag once more to avoid 428162306a36Sopenharmony_ci a race then start the timer. This is 428262306a36Sopenharmony_ci the point when we measure out a minimal 428362306a36Sopenharmony_ci quiet interval before doing something to 428462306a36Sopenharmony_ci the encoder. */ 428562306a36Sopenharmony_ci if (!hdw->state_encoder_waitok) { 428662306a36Sopenharmony_ci hdw->encoder_wait_timer.expires = 428762306a36Sopenharmony_ci jiffies + msecs_to_jiffies( 428862306a36Sopenharmony_ci TIME_MSEC_ENCODER_WAIT); 428962306a36Sopenharmony_ci add_timer(&hdw->encoder_wait_timer); 429062306a36Sopenharmony_ci } 429162306a36Sopenharmony_ci } 429262306a36Sopenharmony_ci /* We can't continue until we know we have been 429362306a36Sopenharmony_ci quiet for the interval measured by this 429462306a36Sopenharmony_ci timer. */ 429562306a36Sopenharmony_ci return 0; 429662306a36Sopenharmony_ci } 429762306a36Sopenharmony_ci pvr2_encoder_configure(hdw); 429862306a36Sopenharmony_ci if (hdw->state_encoder_ok) hdw->state_encoder_config = !0; 429962306a36Sopenharmony_ci } 430062306a36Sopenharmony_ci trace_stbit("state_encoder_config",hdw->state_encoder_config); 430162306a36Sopenharmony_ci return !0; 430262306a36Sopenharmony_ci} 430362306a36Sopenharmony_ci 430462306a36Sopenharmony_ci 430562306a36Sopenharmony_ci/* Return true if the encoder should not be running. */ 430662306a36Sopenharmony_cistatic int state_check_disable_encoder_run(struct pvr2_hdw *hdw) 430762306a36Sopenharmony_ci{ 430862306a36Sopenharmony_ci if (!hdw->state_encoder_ok) { 430962306a36Sopenharmony_ci /* Encoder isn't healthy at the moment, so stop it. */ 431062306a36Sopenharmony_ci return !0; 431162306a36Sopenharmony_ci } 431262306a36Sopenharmony_ci if (!hdw->state_pathway_ok) { 431362306a36Sopenharmony_ci /* Mode is not understood at the moment (i.e. it wants to 431462306a36Sopenharmony_ci change), so encoder must be stopped. */ 431562306a36Sopenharmony_ci return !0; 431662306a36Sopenharmony_ci } 431762306a36Sopenharmony_ci 431862306a36Sopenharmony_ci switch (hdw->pathway_state) { 431962306a36Sopenharmony_ci case PVR2_PATHWAY_ANALOG: 432062306a36Sopenharmony_ci if (!hdw->state_decoder_run) { 432162306a36Sopenharmony_ci /* We're in analog mode and the decoder is not 432262306a36Sopenharmony_ci running; thus the encoder should be stopped as 432362306a36Sopenharmony_ci well. */ 432462306a36Sopenharmony_ci return !0; 432562306a36Sopenharmony_ci } 432662306a36Sopenharmony_ci break; 432762306a36Sopenharmony_ci case PVR2_PATHWAY_DIGITAL: 432862306a36Sopenharmony_ci if (hdw->state_encoder_runok) { 432962306a36Sopenharmony_ci /* This is a funny case. We're in digital mode so 433062306a36Sopenharmony_ci really the encoder should be stopped. However 433162306a36Sopenharmony_ci if it really is running, only kill it after 433262306a36Sopenharmony_ci runok has been set. This gives a chance for the 433362306a36Sopenharmony_ci onair quirk to function (encoder must run 433462306a36Sopenharmony_ci briefly first, at least once, before onair 433562306a36Sopenharmony_ci digital streaming can work). */ 433662306a36Sopenharmony_ci return !0; 433762306a36Sopenharmony_ci } 433862306a36Sopenharmony_ci break; 433962306a36Sopenharmony_ci default: 434062306a36Sopenharmony_ci /* Unknown mode; so encoder should be stopped. */ 434162306a36Sopenharmony_ci return !0; 434262306a36Sopenharmony_ci } 434362306a36Sopenharmony_ci 434462306a36Sopenharmony_ci /* If we get here, we haven't found a reason to stop the 434562306a36Sopenharmony_ci encoder. */ 434662306a36Sopenharmony_ci return 0; 434762306a36Sopenharmony_ci} 434862306a36Sopenharmony_ci 434962306a36Sopenharmony_ci 435062306a36Sopenharmony_ci/* Return true if the encoder should be running. */ 435162306a36Sopenharmony_cistatic int state_check_enable_encoder_run(struct pvr2_hdw *hdw) 435262306a36Sopenharmony_ci{ 435362306a36Sopenharmony_ci if (!hdw->state_encoder_ok) { 435462306a36Sopenharmony_ci /* Don't run the encoder if it isn't healthy... */ 435562306a36Sopenharmony_ci return 0; 435662306a36Sopenharmony_ci } 435762306a36Sopenharmony_ci if (!hdw->state_pathway_ok) { 435862306a36Sopenharmony_ci /* Don't run the encoder if we don't (yet) know what mode 435962306a36Sopenharmony_ci we need to be in... */ 436062306a36Sopenharmony_ci return 0; 436162306a36Sopenharmony_ci } 436262306a36Sopenharmony_ci 436362306a36Sopenharmony_ci switch (hdw->pathway_state) { 436462306a36Sopenharmony_ci case PVR2_PATHWAY_ANALOG: 436562306a36Sopenharmony_ci if (hdw->state_decoder_run && hdw->state_decoder_ready) { 436662306a36Sopenharmony_ci /* In analog mode, if the decoder is running, then 436762306a36Sopenharmony_ci run the encoder. */ 436862306a36Sopenharmony_ci return !0; 436962306a36Sopenharmony_ci } 437062306a36Sopenharmony_ci break; 437162306a36Sopenharmony_ci case PVR2_PATHWAY_DIGITAL: 437262306a36Sopenharmony_ci if ((hdw->hdw_desc->digital_control_scheme == 437362306a36Sopenharmony_ci PVR2_DIGITAL_SCHEME_ONAIR) && 437462306a36Sopenharmony_ci !hdw->state_encoder_runok) { 437562306a36Sopenharmony_ci /* This is a quirk. OnAir hardware won't stream 437662306a36Sopenharmony_ci digital until the encoder has been run at least 437762306a36Sopenharmony_ci once, for a minimal period of time (empiricially 437862306a36Sopenharmony_ci measured to be 1/4 second). So if we're on 437962306a36Sopenharmony_ci OnAir hardware and the encoder has never been 438062306a36Sopenharmony_ci run at all, then start the encoder. Normal 438162306a36Sopenharmony_ci state machine logic in the driver will 438262306a36Sopenharmony_ci automatically handle the remaining bits. */ 438362306a36Sopenharmony_ci return !0; 438462306a36Sopenharmony_ci } 438562306a36Sopenharmony_ci break; 438662306a36Sopenharmony_ci default: 438762306a36Sopenharmony_ci /* For completeness (unknown mode; encoder won't run ever) */ 438862306a36Sopenharmony_ci break; 438962306a36Sopenharmony_ci } 439062306a36Sopenharmony_ci /* If we get here, then we haven't found any reason to run the 439162306a36Sopenharmony_ci encoder, so don't run it. */ 439262306a36Sopenharmony_ci return 0; 439362306a36Sopenharmony_ci} 439462306a36Sopenharmony_ci 439562306a36Sopenharmony_ci 439662306a36Sopenharmony_ci/* Evaluate whether or not state_encoder_run can change */ 439762306a36Sopenharmony_cistatic int state_eval_encoder_run(struct pvr2_hdw *hdw) 439862306a36Sopenharmony_ci{ 439962306a36Sopenharmony_ci if (hdw->state_encoder_run) { 440062306a36Sopenharmony_ci if (!state_check_disable_encoder_run(hdw)) return 0; 440162306a36Sopenharmony_ci if (hdw->state_encoder_ok) { 440262306a36Sopenharmony_ci del_timer_sync(&hdw->encoder_run_timer); 440362306a36Sopenharmony_ci if (pvr2_encoder_stop(hdw) < 0) return !0; 440462306a36Sopenharmony_ci } 440562306a36Sopenharmony_ci hdw->state_encoder_run = 0; 440662306a36Sopenharmony_ci } else { 440762306a36Sopenharmony_ci if (!state_check_enable_encoder_run(hdw)) return 0; 440862306a36Sopenharmony_ci if (pvr2_encoder_start(hdw) < 0) return !0; 440962306a36Sopenharmony_ci hdw->state_encoder_run = !0; 441062306a36Sopenharmony_ci if (!hdw->state_encoder_runok) { 441162306a36Sopenharmony_ci hdw->encoder_run_timer.expires = jiffies + 441262306a36Sopenharmony_ci msecs_to_jiffies(TIME_MSEC_ENCODER_OK); 441362306a36Sopenharmony_ci add_timer(&hdw->encoder_run_timer); 441462306a36Sopenharmony_ci } 441562306a36Sopenharmony_ci } 441662306a36Sopenharmony_ci trace_stbit("state_encoder_run",hdw->state_encoder_run); 441762306a36Sopenharmony_ci return !0; 441862306a36Sopenharmony_ci} 441962306a36Sopenharmony_ci 442062306a36Sopenharmony_ci 442162306a36Sopenharmony_ci/* Timeout function for quiescent timer. */ 442262306a36Sopenharmony_cistatic void pvr2_hdw_quiescent_timeout(struct timer_list *t) 442362306a36Sopenharmony_ci{ 442462306a36Sopenharmony_ci struct pvr2_hdw *hdw = from_timer(hdw, t, quiescent_timer); 442562306a36Sopenharmony_ci hdw->state_decoder_quiescent = !0; 442662306a36Sopenharmony_ci trace_stbit("state_decoder_quiescent",hdw->state_decoder_quiescent); 442762306a36Sopenharmony_ci hdw->state_stale = !0; 442862306a36Sopenharmony_ci schedule_work(&hdw->workpoll); 442962306a36Sopenharmony_ci} 443062306a36Sopenharmony_ci 443162306a36Sopenharmony_ci 443262306a36Sopenharmony_ci/* Timeout function for decoder stabilization timer. */ 443362306a36Sopenharmony_cistatic void pvr2_hdw_decoder_stabilization_timeout(struct timer_list *t) 443462306a36Sopenharmony_ci{ 443562306a36Sopenharmony_ci struct pvr2_hdw *hdw = from_timer(hdw, t, decoder_stabilization_timer); 443662306a36Sopenharmony_ci hdw->state_decoder_ready = !0; 443762306a36Sopenharmony_ci trace_stbit("state_decoder_ready", hdw->state_decoder_ready); 443862306a36Sopenharmony_ci hdw->state_stale = !0; 443962306a36Sopenharmony_ci schedule_work(&hdw->workpoll); 444062306a36Sopenharmony_ci} 444162306a36Sopenharmony_ci 444262306a36Sopenharmony_ci 444362306a36Sopenharmony_ci/* Timeout function for encoder wait timer. */ 444462306a36Sopenharmony_cistatic void pvr2_hdw_encoder_wait_timeout(struct timer_list *t) 444562306a36Sopenharmony_ci{ 444662306a36Sopenharmony_ci struct pvr2_hdw *hdw = from_timer(hdw, t, encoder_wait_timer); 444762306a36Sopenharmony_ci hdw->state_encoder_waitok = !0; 444862306a36Sopenharmony_ci trace_stbit("state_encoder_waitok",hdw->state_encoder_waitok); 444962306a36Sopenharmony_ci hdw->state_stale = !0; 445062306a36Sopenharmony_ci schedule_work(&hdw->workpoll); 445162306a36Sopenharmony_ci} 445262306a36Sopenharmony_ci 445362306a36Sopenharmony_ci 445462306a36Sopenharmony_ci/* Timeout function for encoder run timer. */ 445562306a36Sopenharmony_cistatic void pvr2_hdw_encoder_run_timeout(struct timer_list *t) 445662306a36Sopenharmony_ci{ 445762306a36Sopenharmony_ci struct pvr2_hdw *hdw = from_timer(hdw, t, encoder_run_timer); 445862306a36Sopenharmony_ci if (!hdw->state_encoder_runok) { 445962306a36Sopenharmony_ci hdw->state_encoder_runok = !0; 446062306a36Sopenharmony_ci trace_stbit("state_encoder_runok",hdw->state_encoder_runok); 446162306a36Sopenharmony_ci hdw->state_stale = !0; 446262306a36Sopenharmony_ci schedule_work(&hdw->workpoll); 446362306a36Sopenharmony_ci } 446462306a36Sopenharmony_ci} 446562306a36Sopenharmony_ci 446662306a36Sopenharmony_ci 446762306a36Sopenharmony_ci/* Evaluate whether or not state_decoder_run can change */ 446862306a36Sopenharmony_cistatic int state_eval_decoder_run(struct pvr2_hdw *hdw) 446962306a36Sopenharmony_ci{ 447062306a36Sopenharmony_ci if (hdw->state_decoder_run) { 447162306a36Sopenharmony_ci if (hdw->state_encoder_ok) { 447262306a36Sopenharmony_ci if (hdw->state_pipeline_req && 447362306a36Sopenharmony_ci !hdw->state_pipeline_pause && 447462306a36Sopenharmony_ci hdw->state_pathway_ok) return 0; 447562306a36Sopenharmony_ci } 447662306a36Sopenharmony_ci if (!hdw->flag_decoder_missed) { 447762306a36Sopenharmony_ci pvr2_decoder_enable(hdw,0); 447862306a36Sopenharmony_ci } 447962306a36Sopenharmony_ci hdw->state_decoder_quiescent = 0; 448062306a36Sopenharmony_ci hdw->state_decoder_run = 0; 448162306a36Sopenharmony_ci /* paranoia - solve race if timer(s) just completed */ 448262306a36Sopenharmony_ci del_timer_sync(&hdw->quiescent_timer); 448362306a36Sopenharmony_ci /* Kill the stabilization timer, in case we're killing the 448462306a36Sopenharmony_ci encoder before the previous stabilization interval has 448562306a36Sopenharmony_ci been properly timed. */ 448662306a36Sopenharmony_ci del_timer_sync(&hdw->decoder_stabilization_timer); 448762306a36Sopenharmony_ci hdw->state_decoder_ready = 0; 448862306a36Sopenharmony_ci } else { 448962306a36Sopenharmony_ci if (!hdw->state_decoder_quiescent) { 449062306a36Sopenharmony_ci if (!timer_pending(&hdw->quiescent_timer)) { 449162306a36Sopenharmony_ci /* We don't do something about the 449262306a36Sopenharmony_ci quiescent timer until right here because 449362306a36Sopenharmony_ci we also want to catch cases where the 449462306a36Sopenharmony_ci decoder was already not running (like 449562306a36Sopenharmony_ci after initialization) as opposed to 449662306a36Sopenharmony_ci knowing that we had just stopped it. 449762306a36Sopenharmony_ci The second flag check is here to cover a 449862306a36Sopenharmony_ci race - the timer could have run and set 449962306a36Sopenharmony_ci this flag just after the previous check 450062306a36Sopenharmony_ci but before we did the pending check. */ 450162306a36Sopenharmony_ci if (!hdw->state_decoder_quiescent) { 450262306a36Sopenharmony_ci hdw->quiescent_timer.expires = 450362306a36Sopenharmony_ci jiffies + msecs_to_jiffies( 450462306a36Sopenharmony_ci TIME_MSEC_DECODER_WAIT); 450562306a36Sopenharmony_ci add_timer(&hdw->quiescent_timer); 450662306a36Sopenharmony_ci } 450762306a36Sopenharmony_ci } 450862306a36Sopenharmony_ci /* Don't allow decoder to start again until it has 450962306a36Sopenharmony_ci been quiesced first. This little detail should 451062306a36Sopenharmony_ci hopefully further stabilize the encoder. */ 451162306a36Sopenharmony_ci return 0; 451262306a36Sopenharmony_ci } 451362306a36Sopenharmony_ci if (!hdw->state_pathway_ok || 451462306a36Sopenharmony_ci (hdw->pathway_state != PVR2_PATHWAY_ANALOG) || 451562306a36Sopenharmony_ci !hdw->state_pipeline_req || 451662306a36Sopenharmony_ci hdw->state_pipeline_pause || 451762306a36Sopenharmony_ci !hdw->state_pipeline_config || 451862306a36Sopenharmony_ci !hdw->state_encoder_config || 451962306a36Sopenharmony_ci !hdw->state_encoder_ok) return 0; 452062306a36Sopenharmony_ci del_timer_sync(&hdw->quiescent_timer); 452162306a36Sopenharmony_ci if (hdw->flag_decoder_missed) return 0; 452262306a36Sopenharmony_ci if (pvr2_decoder_enable(hdw,!0) < 0) return 0; 452362306a36Sopenharmony_ci hdw->state_decoder_quiescent = 0; 452462306a36Sopenharmony_ci hdw->state_decoder_ready = 0; 452562306a36Sopenharmony_ci hdw->state_decoder_run = !0; 452662306a36Sopenharmony_ci if (hdw->decoder_client_id == PVR2_CLIENT_ID_SAA7115) { 452762306a36Sopenharmony_ci hdw->decoder_stabilization_timer.expires = 452862306a36Sopenharmony_ci jiffies + msecs_to_jiffies( 452962306a36Sopenharmony_ci TIME_MSEC_DECODER_STABILIZATION_WAIT); 453062306a36Sopenharmony_ci add_timer(&hdw->decoder_stabilization_timer); 453162306a36Sopenharmony_ci } else { 453262306a36Sopenharmony_ci hdw->state_decoder_ready = !0; 453362306a36Sopenharmony_ci } 453462306a36Sopenharmony_ci } 453562306a36Sopenharmony_ci trace_stbit("state_decoder_quiescent",hdw->state_decoder_quiescent); 453662306a36Sopenharmony_ci trace_stbit("state_decoder_run",hdw->state_decoder_run); 453762306a36Sopenharmony_ci trace_stbit("state_decoder_ready", hdw->state_decoder_ready); 453862306a36Sopenharmony_ci return !0; 453962306a36Sopenharmony_ci} 454062306a36Sopenharmony_ci 454162306a36Sopenharmony_ci 454262306a36Sopenharmony_ci/* Evaluate whether or not state_usbstream_run can change */ 454362306a36Sopenharmony_cistatic int state_eval_usbstream_run(struct pvr2_hdw *hdw) 454462306a36Sopenharmony_ci{ 454562306a36Sopenharmony_ci if (hdw->state_usbstream_run) { 454662306a36Sopenharmony_ci int fl = !0; 454762306a36Sopenharmony_ci if (hdw->pathway_state == PVR2_PATHWAY_ANALOG) { 454862306a36Sopenharmony_ci fl = (hdw->state_encoder_ok && 454962306a36Sopenharmony_ci hdw->state_encoder_run); 455062306a36Sopenharmony_ci } else if ((hdw->pathway_state == PVR2_PATHWAY_DIGITAL) && 455162306a36Sopenharmony_ci (hdw->hdw_desc->flag_digital_requires_cx23416)) { 455262306a36Sopenharmony_ci fl = hdw->state_encoder_ok; 455362306a36Sopenharmony_ci } 455462306a36Sopenharmony_ci if (fl && 455562306a36Sopenharmony_ci hdw->state_pipeline_req && 455662306a36Sopenharmony_ci !hdw->state_pipeline_pause && 455762306a36Sopenharmony_ci hdw->state_pathway_ok) { 455862306a36Sopenharmony_ci return 0; 455962306a36Sopenharmony_ci } 456062306a36Sopenharmony_ci pvr2_hdw_cmd_usbstream(hdw,0); 456162306a36Sopenharmony_ci hdw->state_usbstream_run = 0; 456262306a36Sopenharmony_ci } else { 456362306a36Sopenharmony_ci if (!hdw->state_pipeline_req || 456462306a36Sopenharmony_ci hdw->state_pipeline_pause || 456562306a36Sopenharmony_ci !hdw->state_pathway_ok) return 0; 456662306a36Sopenharmony_ci if (hdw->pathway_state == PVR2_PATHWAY_ANALOG) { 456762306a36Sopenharmony_ci if (!hdw->state_encoder_ok || 456862306a36Sopenharmony_ci !hdw->state_encoder_run) return 0; 456962306a36Sopenharmony_ci } else if ((hdw->pathway_state == PVR2_PATHWAY_DIGITAL) && 457062306a36Sopenharmony_ci (hdw->hdw_desc->flag_digital_requires_cx23416)) { 457162306a36Sopenharmony_ci if (!hdw->state_encoder_ok) return 0; 457262306a36Sopenharmony_ci if (hdw->state_encoder_run) return 0; 457362306a36Sopenharmony_ci if (hdw->hdw_desc->digital_control_scheme == 457462306a36Sopenharmony_ci PVR2_DIGITAL_SCHEME_ONAIR) { 457562306a36Sopenharmony_ci /* OnAir digital receivers won't stream 457662306a36Sopenharmony_ci unless the analog encoder has run first. 457762306a36Sopenharmony_ci Why? I have no idea. But don't even 457862306a36Sopenharmony_ci try until we know the analog side is 457962306a36Sopenharmony_ci known to have run. */ 458062306a36Sopenharmony_ci if (!hdw->state_encoder_runok) return 0; 458162306a36Sopenharmony_ci } 458262306a36Sopenharmony_ci } 458362306a36Sopenharmony_ci if (pvr2_hdw_cmd_usbstream(hdw,!0) < 0) return 0; 458462306a36Sopenharmony_ci hdw->state_usbstream_run = !0; 458562306a36Sopenharmony_ci } 458662306a36Sopenharmony_ci trace_stbit("state_usbstream_run",hdw->state_usbstream_run); 458762306a36Sopenharmony_ci return !0; 458862306a36Sopenharmony_ci} 458962306a36Sopenharmony_ci 459062306a36Sopenharmony_ci 459162306a36Sopenharmony_ci/* Attempt to configure pipeline, if needed */ 459262306a36Sopenharmony_cistatic int state_eval_pipeline_config(struct pvr2_hdw *hdw) 459362306a36Sopenharmony_ci{ 459462306a36Sopenharmony_ci if (hdw->state_pipeline_config || 459562306a36Sopenharmony_ci hdw->state_pipeline_pause) return 0; 459662306a36Sopenharmony_ci pvr2_hdw_commit_execute(hdw); 459762306a36Sopenharmony_ci return !0; 459862306a36Sopenharmony_ci} 459962306a36Sopenharmony_ci 460062306a36Sopenharmony_ci 460162306a36Sopenharmony_ci/* Update pipeline idle and pipeline pause tracking states based on other 460262306a36Sopenharmony_ci inputs. This must be called whenever the other relevant inputs have 460362306a36Sopenharmony_ci changed. */ 460462306a36Sopenharmony_cistatic int state_update_pipeline_state(struct pvr2_hdw *hdw) 460562306a36Sopenharmony_ci{ 460662306a36Sopenharmony_ci unsigned int st; 460762306a36Sopenharmony_ci int updatedFl = 0; 460862306a36Sopenharmony_ci /* Update pipeline state */ 460962306a36Sopenharmony_ci st = !(hdw->state_encoder_run || 461062306a36Sopenharmony_ci hdw->state_decoder_run || 461162306a36Sopenharmony_ci hdw->state_usbstream_run || 461262306a36Sopenharmony_ci (!hdw->state_decoder_quiescent)); 461362306a36Sopenharmony_ci if (!st != !hdw->state_pipeline_idle) { 461462306a36Sopenharmony_ci hdw->state_pipeline_idle = st; 461562306a36Sopenharmony_ci updatedFl = !0; 461662306a36Sopenharmony_ci } 461762306a36Sopenharmony_ci if (hdw->state_pipeline_idle && hdw->state_pipeline_pause) { 461862306a36Sopenharmony_ci hdw->state_pipeline_pause = 0; 461962306a36Sopenharmony_ci updatedFl = !0; 462062306a36Sopenharmony_ci } 462162306a36Sopenharmony_ci return updatedFl; 462262306a36Sopenharmony_ci} 462362306a36Sopenharmony_ci 462462306a36Sopenharmony_ci 462562306a36Sopenharmony_citypedef int (*state_eval_func)(struct pvr2_hdw *); 462662306a36Sopenharmony_ci 462762306a36Sopenharmony_ci/* Set of functions to be run to evaluate various states in the driver. */ 462862306a36Sopenharmony_cistatic const state_eval_func eval_funcs[] = { 462962306a36Sopenharmony_ci state_eval_pathway_ok, 463062306a36Sopenharmony_ci state_eval_pipeline_config, 463162306a36Sopenharmony_ci state_eval_encoder_ok, 463262306a36Sopenharmony_ci state_eval_encoder_config, 463362306a36Sopenharmony_ci state_eval_decoder_run, 463462306a36Sopenharmony_ci state_eval_encoder_run, 463562306a36Sopenharmony_ci state_eval_usbstream_run, 463662306a36Sopenharmony_ci}; 463762306a36Sopenharmony_ci 463862306a36Sopenharmony_ci 463962306a36Sopenharmony_ci/* Process various states and return true if we did anything interesting. */ 464062306a36Sopenharmony_cistatic int pvr2_hdw_state_update(struct pvr2_hdw *hdw) 464162306a36Sopenharmony_ci{ 464262306a36Sopenharmony_ci unsigned int i; 464362306a36Sopenharmony_ci int state_updated = 0; 464462306a36Sopenharmony_ci int check_flag; 464562306a36Sopenharmony_ci 464662306a36Sopenharmony_ci if (!hdw->state_stale) return 0; 464762306a36Sopenharmony_ci if ((hdw->fw1_state != FW1_STATE_OK) || 464862306a36Sopenharmony_ci !hdw->flag_ok) { 464962306a36Sopenharmony_ci hdw->state_stale = 0; 465062306a36Sopenharmony_ci return !0; 465162306a36Sopenharmony_ci } 465262306a36Sopenharmony_ci /* This loop is the heart of the entire driver. It keeps trying to 465362306a36Sopenharmony_ci evaluate various bits of driver state until nothing changes for 465462306a36Sopenharmony_ci one full iteration. Each "bit of state" tracks some global 465562306a36Sopenharmony_ci aspect of the driver, e.g. whether decoder should run, if 465662306a36Sopenharmony_ci pipeline is configured, usb streaming is on, etc. We separately 465762306a36Sopenharmony_ci evaluate each of those questions based on other driver state to 465862306a36Sopenharmony_ci arrive at the correct running configuration. */ 465962306a36Sopenharmony_ci do { 466062306a36Sopenharmony_ci check_flag = 0; 466162306a36Sopenharmony_ci state_update_pipeline_state(hdw); 466262306a36Sopenharmony_ci /* Iterate over each bit of state */ 466362306a36Sopenharmony_ci for (i = 0; (i<ARRAY_SIZE(eval_funcs)) && hdw->flag_ok; i++) { 466462306a36Sopenharmony_ci if ((*eval_funcs[i])(hdw)) { 466562306a36Sopenharmony_ci check_flag = !0; 466662306a36Sopenharmony_ci state_updated = !0; 466762306a36Sopenharmony_ci state_update_pipeline_state(hdw); 466862306a36Sopenharmony_ci } 466962306a36Sopenharmony_ci } 467062306a36Sopenharmony_ci } while (check_flag && hdw->flag_ok); 467162306a36Sopenharmony_ci hdw->state_stale = 0; 467262306a36Sopenharmony_ci trace_stbit("state_stale",hdw->state_stale); 467362306a36Sopenharmony_ci return state_updated; 467462306a36Sopenharmony_ci} 467562306a36Sopenharmony_ci 467662306a36Sopenharmony_ci 467762306a36Sopenharmony_cistatic unsigned int print_input_mask(unsigned int msk, 467862306a36Sopenharmony_ci char *buf,unsigned int acnt) 467962306a36Sopenharmony_ci{ 468062306a36Sopenharmony_ci unsigned int idx,ccnt; 468162306a36Sopenharmony_ci unsigned int tcnt = 0; 468262306a36Sopenharmony_ci for (idx = 0; idx < ARRAY_SIZE(control_values_input); idx++) { 468362306a36Sopenharmony_ci if (!((1UL << idx) & msk)) continue; 468462306a36Sopenharmony_ci ccnt = scnprintf(buf+tcnt, 468562306a36Sopenharmony_ci acnt-tcnt, 468662306a36Sopenharmony_ci "%s%s", 468762306a36Sopenharmony_ci (tcnt ? ", " : ""), 468862306a36Sopenharmony_ci control_values_input[idx]); 468962306a36Sopenharmony_ci tcnt += ccnt; 469062306a36Sopenharmony_ci } 469162306a36Sopenharmony_ci return tcnt; 469262306a36Sopenharmony_ci} 469362306a36Sopenharmony_ci 469462306a36Sopenharmony_ci 469562306a36Sopenharmony_cistatic const char *pvr2_pathway_state_name(int id) 469662306a36Sopenharmony_ci{ 469762306a36Sopenharmony_ci switch (id) { 469862306a36Sopenharmony_ci case PVR2_PATHWAY_ANALOG: return "analog"; 469962306a36Sopenharmony_ci case PVR2_PATHWAY_DIGITAL: return "digital"; 470062306a36Sopenharmony_ci default: return "unknown"; 470162306a36Sopenharmony_ci } 470262306a36Sopenharmony_ci} 470362306a36Sopenharmony_ci 470462306a36Sopenharmony_ci 470562306a36Sopenharmony_cistatic unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which, 470662306a36Sopenharmony_ci char *buf,unsigned int acnt) 470762306a36Sopenharmony_ci{ 470862306a36Sopenharmony_ci switch (which) { 470962306a36Sopenharmony_ci case 0: 471062306a36Sopenharmony_ci return scnprintf( 471162306a36Sopenharmony_ci buf,acnt, 471262306a36Sopenharmony_ci "driver:%s%s%s%s%s <mode=%s>", 471362306a36Sopenharmony_ci (hdw->flag_ok ? " <ok>" : " <fail>"), 471462306a36Sopenharmony_ci (hdw->flag_init_ok ? " <init>" : " <uninitialized>"), 471562306a36Sopenharmony_ci (hdw->flag_disconnected ? " <disconnected>" : 471662306a36Sopenharmony_ci " <connected>"), 471762306a36Sopenharmony_ci (hdw->flag_tripped ? " <tripped>" : ""), 471862306a36Sopenharmony_ci (hdw->flag_decoder_missed ? " <no decoder>" : ""), 471962306a36Sopenharmony_ci pvr2_pathway_state_name(hdw->pathway_state)); 472062306a36Sopenharmony_ci 472162306a36Sopenharmony_ci case 1: 472262306a36Sopenharmony_ci return scnprintf( 472362306a36Sopenharmony_ci buf,acnt, 472462306a36Sopenharmony_ci "pipeline:%s%s%s%s", 472562306a36Sopenharmony_ci (hdw->state_pipeline_idle ? " <idle>" : ""), 472662306a36Sopenharmony_ci (hdw->state_pipeline_config ? 472762306a36Sopenharmony_ci " <configok>" : " <stale>"), 472862306a36Sopenharmony_ci (hdw->state_pipeline_req ? " <req>" : ""), 472962306a36Sopenharmony_ci (hdw->state_pipeline_pause ? " <pause>" : "")); 473062306a36Sopenharmony_ci case 2: 473162306a36Sopenharmony_ci return scnprintf( 473262306a36Sopenharmony_ci buf,acnt, 473362306a36Sopenharmony_ci "worker:%s%s%s%s%s%s%s", 473462306a36Sopenharmony_ci (hdw->state_decoder_run ? 473562306a36Sopenharmony_ci (hdw->state_decoder_ready ? 473662306a36Sopenharmony_ci "<decode:run>" : " <decode:start>") : 473762306a36Sopenharmony_ci (hdw->state_decoder_quiescent ? 473862306a36Sopenharmony_ci "" : " <decode:stop>")), 473962306a36Sopenharmony_ci (hdw->state_decoder_quiescent ? 474062306a36Sopenharmony_ci " <decode:quiescent>" : ""), 474162306a36Sopenharmony_ci (hdw->state_encoder_ok ? 474262306a36Sopenharmony_ci "" : " <encode:init>"), 474362306a36Sopenharmony_ci (hdw->state_encoder_run ? 474462306a36Sopenharmony_ci (hdw->state_encoder_runok ? 474562306a36Sopenharmony_ci " <encode:run>" : 474662306a36Sopenharmony_ci " <encode:firstrun>") : 474762306a36Sopenharmony_ci (hdw->state_encoder_runok ? 474862306a36Sopenharmony_ci " <encode:stop>" : 474962306a36Sopenharmony_ci " <encode:virgin>")), 475062306a36Sopenharmony_ci (hdw->state_encoder_config ? 475162306a36Sopenharmony_ci " <encode:configok>" : 475262306a36Sopenharmony_ci (hdw->state_encoder_waitok ? 475362306a36Sopenharmony_ci "" : " <encode:waitok>")), 475462306a36Sopenharmony_ci (hdw->state_usbstream_run ? 475562306a36Sopenharmony_ci " <usb:run>" : " <usb:stop>"), 475662306a36Sopenharmony_ci (hdw->state_pathway_ok ? 475762306a36Sopenharmony_ci " <pathway:ok>" : "")); 475862306a36Sopenharmony_ci case 3: 475962306a36Sopenharmony_ci return scnprintf( 476062306a36Sopenharmony_ci buf,acnt, 476162306a36Sopenharmony_ci "state: %s", 476262306a36Sopenharmony_ci pvr2_get_state_name(hdw->master_state)); 476362306a36Sopenharmony_ci case 4: { 476462306a36Sopenharmony_ci unsigned int tcnt = 0; 476562306a36Sopenharmony_ci unsigned int ccnt; 476662306a36Sopenharmony_ci 476762306a36Sopenharmony_ci ccnt = scnprintf(buf, 476862306a36Sopenharmony_ci acnt, 476962306a36Sopenharmony_ci "Hardware supported inputs: "); 477062306a36Sopenharmony_ci tcnt += ccnt; 477162306a36Sopenharmony_ci tcnt += print_input_mask(hdw->input_avail_mask, 477262306a36Sopenharmony_ci buf+tcnt, 477362306a36Sopenharmony_ci acnt-tcnt); 477462306a36Sopenharmony_ci if (hdw->input_avail_mask != hdw->input_allowed_mask) { 477562306a36Sopenharmony_ci ccnt = scnprintf(buf+tcnt, 477662306a36Sopenharmony_ci acnt-tcnt, 477762306a36Sopenharmony_ci "; allowed inputs: "); 477862306a36Sopenharmony_ci tcnt += ccnt; 477962306a36Sopenharmony_ci tcnt += print_input_mask(hdw->input_allowed_mask, 478062306a36Sopenharmony_ci buf+tcnt, 478162306a36Sopenharmony_ci acnt-tcnt); 478262306a36Sopenharmony_ci } 478362306a36Sopenharmony_ci return tcnt; 478462306a36Sopenharmony_ci } 478562306a36Sopenharmony_ci case 5: { 478662306a36Sopenharmony_ci struct pvr2_stream_stats stats; 478762306a36Sopenharmony_ci if (!hdw->vid_stream) break; 478862306a36Sopenharmony_ci pvr2_stream_get_stats(hdw->vid_stream, 478962306a36Sopenharmony_ci &stats, 479062306a36Sopenharmony_ci 0); 479162306a36Sopenharmony_ci return scnprintf( 479262306a36Sopenharmony_ci buf,acnt, 479362306a36Sopenharmony_ci "Bytes streamed=%u URBs: queued=%u idle=%u ready=%u processed=%u failed=%u", 479462306a36Sopenharmony_ci stats.bytes_processed, 479562306a36Sopenharmony_ci stats.buffers_in_queue, 479662306a36Sopenharmony_ci stats.buffers_in_idle, 479762306a36Sopenharmony_ci stats.buffers_in_ready, 479862306a36Sopenharmony_ci stats.buffers_processed, 479962306a36Sopenharmony_ci stats.buffers_failed); 480062306a36Sopenharmony_ci } 480162306a36Sopenharmony_ci case 6: { 480262306a36Sopenharmony_ci unsigned int id = hdw->ir_scheme_active; 480362306a36Sopenharmony_ci return scnprintf(buf, acnt, "ir scheme: id=%d %s", id, 480462306a36Sopenharmony_ci (id >= ARRAY_SIZE(ir_scheme_names) ? 480562306a36Sopenharmony_ci "?" : ir_scheme_names[id])); 480662306a36Sopenharmony_ci } 480762306a36Sopenharmony_ci default: break; 480862306a36Sopenharmony_ci } 480962306a36Sopenharmony_ci return 0; 481062306a36Sopenharmony_ci} 481162306a36Sopenharmony_ci 481262306a36Sopenharmony_ci 481362306a36Sopenharmony_ci/* Generate report containing info about attached sub-devices and attached 481462306a36Sopenharmony_ci i2c clients, including an indication of which attached i2c clients are 481562306a36Sopenharmony_ci actually sub-devices. */ 481662306a36Sopenharmony_cistatic unsigned int pvr2_hdw_report_clients(struct pvr2_hdw *hdw, 481762306a36Sopenharmony_ci char *buf, unsigned int acnt) 481862306a36Sopenharmony_ci{ 481962306a36Sopenharmony_ci struct v4l2_subdev *sd; 482062306a36Sopenharmony_ci unsigned int tcnt = 0; 482162306a36Sopenharmony_ci unsigned int ccnt; 482262306a36Sopenharmony_ci struct i2c_client *client; 482362306a36Sopenharmony_ci const char *p; 482462306a36Sopenharmony_ci unsigned int id; 482562306a36Sopenharmony_ci 482662306a36Sopenharmony_ci ccnt = scnprintf(buf, acnt, "Associated v4l2-subdev drivers and I2C clients:\n"); 482762306a36Sopenharmony_ci tcnt += ccnt; 482862306a36Sopenharmony_ci v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) { 482962306a36Sopenharmony_ci id = sd->grp_id; 483062306a36Sopenharmony_ci p = NULL; 483162306a36Sopenharmony_ci if (id < ARRAY_SIZE(module_names)) p = module_names[id]; 483262306a36Sopenharmony_ci if (p) { 483362306a36Sopenharmony_ci ccnt = scnprintf(buf + tcnt, acnt - tcnt, " %s:", p); 483462306a36Sopenharmony_ci tcnt += ccnt; 483562306a36Sopenharmony_ci } else { 483662306a36Sopenharmony_ci ccnt = scnprintf(buf + tcnt, acnt - tcnt, 483762306a36Sopenharmony_ci " (unknown id=%u):", id); 483862306a36Sopenharmony_ci tcnt += ccnt; 483962306a36Sopenharmony_ci } 484062306a36Sopenharmony_ci client = v4l2_get_subdevdata(sd); 484162306a36Sopenharmony_ci if (client) { 484262306a36Sopenharmony_ci ccnt = scnprintf(buf + tcnt, acnt - tcnt, 484362306a36Sopenharmony_ci " %s @ %02x\n", client->name, 484462306a36Sopenharmony_ci client->addr); 484562306a36Sopenharmony_ci tcnt += ccnt; 484662306a36Sopenharmony_ci } else { 484762306a36Sopenharmony_ci ccnt = scnprintf(buf + tcnt, acnt - tcnt, 484862306a36Sopenharmony_ci " no i2c client\n"); 484962306a36Sopenharmony_ci tcnt += ccnt; 485062306a36Sopenharmony_ci } 485162306a36Sopenharmony_ci } 485262306a36Sopenharmony_ci return tcnt; 485362306a36Sopenharmony_ci} 485462306a36Sopenharmony_ci 485562306a36Sopenharmony_ci 485662306a36Sopenharmony_ciunsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw, 485762306a36Sopenharmony_ci char *buf,unsigned int acnt) 485862306a36Sopenharmony_ci{ 485962306a36Sopenharmony_ci unsigned int bcnt,ccnt,idx; 486062306a36Sopenharmony_ci bcnt = 0; 486162306a36Sopenharmony_ci LOCK_TAKE(hdw->big_lock); 486262306a36Sopenharmony_ci for (idx = 0; ; idx++) { 486362306a36Sopenharmony_ci ccnt = pvr2_hdw_report_unlocked(hdw,idx,buf,acnt); 486462306a36Sopenharmony_ci if (!ccnt) break; 486562306a36Sopenharmony_ci bcnt += ccnt; acnt -= ccnt; buf += ccnt; 486662306a36Sopenharmony_ci if (!acnt) break; 486762306a36Sopenharmony_ci buf[0] = '\n'; ccnt = 1; 486862306a36Sopenharmony_ci bcnt += ccnt; acnt -= ccnt; buf += ccnt; 486962306a36Sopenharmony_ci } 487062306a36Sopenharmony_ci ccnt = pvr2_hdw_report_clients(hdw, buf, acnt); 487162306a36Sopenharmony_ci bcnt += ccnt; acnt -= ccnt; buf += ccnt; 487262306a36Sopenharmony_ci LOCK_GIVE(hdw->big_lock); 487362306a36Sopenharmony_ci return bcnt; 487462306a36Sopenharmony_ci} 487562306a36Sopenharmony_ci 487662306a36Sopenharmony_ci 487762306a36Sopenharmony_cistatic void pvr2_hdw_state_log_state(struct pvr2_hdw *hdw) 487862306a36Sopenharmony_ci{ 487962306a36Sopenharmony_ci char buf[256]; 488062306a36Sopenharmony_ci unsigned int idx, ccnt; 488162306a36Sopenharmony_ci unsigned int lcnt, ucnt; 488262306a36Sopenharmony_ci 488362306a36Sopenharmony_ci for (idx = 0; ; idx++) { 488462306a36Sopenharmony_ci ccnt = pvr2_hdw_report_unlocked(hdw,idx,buf,sizeof(buf)); 488562306a36Sopenharmony_ci if (!ccnt) break; 488662306a36Sopenharmony_ci pr_info("%s %.*s\n", hdw->name, ccnt, buf); 488762306a36Sopenharmony_ci } 488862306a36Sopenharmony_ci ccnt = pvr2_hdw_report_clients(hdw, buf, sizeof(buf)); 488962306a36Sopenharmony_ci if (ccnt >= sizeof(buf)) 489062306a36Sopenharmony_ci ccnt = sizeof(buf); 489162306a36Sopenharmony_ci 489262306a36Sopenharmony_ci ucnt = 0; 489362306a36Sopenharmony_ci while (ucnt < ccnt) { 489462306a36Sopenharmony_ci lcnt = 0; 489562306a36Sopenharmony_ci while ((lcnt + ucnt < ccnt) && (buf[lcnt + ucnt] != '\n')) { 489662306a36Sopenharmony_ci lcnt++; 489762306a36Sopenharmony_ci } 489862306a36Sopenharmony_ci pr_info("%s %.*s\n", hdw->name, lcnt, buf + ucnt); 489962306a36Sopenharmony_ci ucnt += lcnt + 1; 490062306a36Sopenharmony_ci } 490162306a36Sopenharmony_ci} 490262306a36Sopenharmony_ci 490362306a36Sopenharmony_ci 490462306a36Sopenharmony_ci/* Evaluate and update the driver's current state, taking various actions 490562306a36Sopenharmony_ci as appropriate for the update. */ 490662306a36Sopenharmony_cistatic int pvr2_hdw_state_eval(struct pvr2_hdw *hdw) 490762306a36Sopenharmony_ci{ 490862306a36Sopenharmony_ci unsigned int st; 490962306a36Sopenharmony_ci int state_updated = 0; 491062306a36Sopenharmony_ci int callback_flag = 0; 491162306a36Sopenharmony_ci int analog_mode; 491262306a36Sopenharmony_ci 491362306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_STBITS, 491462306a36Sopenharmony_ci "Drive state check START"); 491562306a36Sopenharmony_ci if (pvrusb2_debug & PVR2_TRACE_STBITS) { 491662306a36Sopenharmony_ci pvr2_hdw_state_log_state(hdw); 491762306a36Sopenharmony_ci } 491862306a36Sopenharmony_ci 491962306a36Sopenharmony_ci /* Process all state and get back over disposition */ 492062306a36Sopenharmony_ci state_updated = pvr2_hdw_state_update(hdw); 492162306a36Sopenharmony_ci 492262306a36Sopenharmony_ci analog_mode = (hdw->pathway_state != PVR2_PATHWAY_DIGITAL); 492362306a36Sopenharmony_ci 492462306a36Sopenharmony_ci /* Update master state based upon all other states. */ 492562306a36Sopenharmony_ci if (!hdw->flag_ok) { 492662306a36Sopenharmony_ci st = PVR2_STATE_DEAD; 492762306a36Sopenharmony_ci } else if (hdw->fw1_state != FW1_STATE_OK) { 492862306a36Sopenharmony_ci st = PVR2_STATE_COLD; 492962306a36Sopenharmony_ci } else if ((analog_mode || 493062306a36Sopenharmony_ci hdw->hdw_desc->flag_digital_requires_cx23416) && 493162306a36Sopenharmony_ci !hdw->state_encoder_ok) { 493262306a36Sopenharmony_ci st = PVR2_STATE_WARM; 493362306a36Sopenharmony_ci } else if (hdw->flag_tripped || 493462306a36Sopenharmony_ci (analog_mode && hdw->flag_decoder_missed)) { 493562306a36Sopenharmony_ci st = PVR2_STATE_ERROR; 493662306a36Sopenharmony_ci } else if (hdw->state_usbstream_run && 493762306a36Sopenharmony_ci (!analog_mode || 493862306a36Sopenharmony_ci (hdw->state_encoder_run && hdw->state_decoder_run))) { 493962306a36Sopenharmony_ci st = PVR2_STATE_RUN; 494062306a36Sopenharmony_ci } else { 494162306a36Sopenharmony_ci st = PVR2_STATE_READY; 494262306a36Sopenharmony_ci } 494362306a36Sopenharmony_ci if (hdw->master_state != st) { 494462306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_STATE, 494562306a36Sopenharmony_ci "Device state change from %s to %s", 494662306a36Sopenharmony_ci pvr2_get_state_name(hdw->master_state), 494762306a36Sopenharmony_ci pvr2_get_state_name(st)); 494862306a36Sopenharmony_ci pvr2_led_ctrl(hdw,st == PVR2_STATE_RUN); 494962306a36Sopenharmony_ci hdw->master_state = st; 495062306a36Sopenharmony_ci state_updated = !0; 495162306a36Sopenharmony_ci callback_flag = !0; 495262306a36Sopenharmony_ci } 495362306a36Sopenharmony_ci if (state_updated) { 495462306a36Sopenharmony_ci /* Trigger anyone waiting on any state changes here. */ 495562306a36Sopenharmony_ci wake_up(&hdw->state_wait_data); 495662306a36Sopenharmony_ci } 495762306a36Sopenharmony_ci 495862306a36Sopenharmony_ci if (pvrusb2_debug & PVR2_TRACE_STBITS) { 495962306a36Sopenharmony_ci pvr2_hdw_state_log_state(hdw); 496062306a36Sopenharmony_ci } 496162306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_STBITS, 496262306a36Sopenharmony_ci "Drive state check DONE callback=%d",callback_flag); 496362306a36Sopenharmony_ci 496462306a36Sopenharmony_ci return callback_flag; 496562306a36Sopenharmony_ci} 496662306a36Sopenharmony_ci 496762306a36Sopenharmony_ci 496862306a36Sopenharmony_ci/* Cause kernel thread to check / update driver state */ 496962306a36Sopenharmony_cistatic void pvr2_hdw_state_sched(struct pvr2_hdw *hdw) 497062306a36Sopenharmony_ci{ 497162306a36Sopenharmony_ci if (hdw->state_stale) return; 497262306a36Sopenharmony_ci hdw->state_stale = !0; 497362306a36Sopenharmony_ci trace_stbit("state_stale",hdw->state_stale); 497462306a36Sopenharmony_ci schedule_work(&hdw->workpoll); 497562306a36Sopenharmony_ci} 497662306a36Sopenharmony_ci 497762306a36Sopenharmony_ci 497862306a36Sopenharmony_ciint pvr2_hdw_gpio_get_dir(struct pvr2_hdw *hdw,u32 *dp) 497962306a36Sopenharmony_ci{ 498062306a36Sopenharmony_ci return pvr2_read_register(hdw,PVR2_GPIO_DIR,dp); 498162306a36Sopenharmony_ci} 498262306a36Sopenharmony_ci 498362306a36Sopenharmony_ci 498462306a36Sopenharmony_ciint pvr2_hdw_gpio_get_out(struct pvr2_hdw *hdw,u32 *dp) 498562306a36Sopenharmony_ci{ 498662306a36Sopenharmony_ci return pvr2_read_register(hdw,PVR2_GPIO_OUT,dp); 498762306a36Sopenharmony_ci} 498862306a36Sopenharmony_ci 498962306a36Sopenharmony_ci 499062306a36Sopenharmony_ciint pvr2_hdw_gpio_get_in(struct pvr2_hdw *hdw,u32 *dp) 499162306a36Sopenharmony_ci{ 499262306a36Sopenharmony_ci return pvr2_read_register(hdw,PVR2_GPIO_IN,dp); 499362306a36Sopenharmony_ci} 499462306a36Sopenharmony_ci 499562306a36Sopenharmony_ci 499662306a36Sopenharmony_ciint pvr2_hdw_gpio_chg_dir(struct pvr2_hdw *hdw,u32 msk,u32 val) 499762306a36Sopenharmony_ci{ 499862306a36Sopenharmony_ci u32 cval,nval; 499962306a36Sopenharmony_ci int ret; 500062306a36Sopenharmony_ci if (~msk) { 500162306a36Sopenharmony_ci ret = pvr2_read_register(hdw,PVR2_GPIO_DIR,&cval); 500262306a36Sopenharmony_ci if (ret) return ret; 500362306a36Sopenharmony_ci nval = (cval & ~msk) | (val & msk); 500462306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_GPIO, 500562306a36Sopenharmony_ci "GPIO direction changing 0x%x:0x%x from 0x%x to 0x%x", 500662306a36Sopenharmony_ci msk,val,cval,nval); 500762306a36Sopenharmony_ci } else { 500862306a36Sopenharmony_ci nval = val; 500962306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_GPIO, 501062306a36Sopenharmony_ci "GPIO direction changing to 0x%x",nval); 501162306a36Sopenharmony_ci } 501262306a36Sopenharmony_ci return pvr2_write_register(hdw,PVR2_GPIO_DIR,nval); 501362306a36Sopenharmony_ci} 501462306a36Sopenharmony_ci 501562306a36Sopenharmony_ci 501662306a36Sopenharmony_ciint pvr2_hdw_gpio_chg_out(struct pvr2_hdw *hdw,u32 msk,u32 val) 501762306a36Sopenharmony_ci{ 501862306a36Sopenharmony_ci u32 cval,nval; 501962306a36Sopenharmony_ci int ret; 502062306a36Sopenharmony_ci if (~msk) { 502162306a36Sopenharmony_ci ret = pvr2_read_register(hdw,PVR2_GPIO_OUT,&cval); 502262306a36Sopenharmony_ci if (ret) return ret; 502362306a36Sopenharmony_ci nval = (cval & ~msk) | (val & msk); 502462306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_GPIO, 502562306a36Sopenharmony_ci "GPIO output changing 0x%x:0x%x from 0x%x to 0x%x", 502662306a36Sopenharmony_ci msk,val,cval,nval); 502762306a36Sopenharmony_ci } else { 502862306a36Sopenharmony_ci nval = val; 502962306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_GPIO, 503062306a36Sopenharmony_ci "GPIO output changing to 0x%x",nval); 503162306a36Sopenharmony_ci } 503262306a36Sopenharmony_ci return pvr2_write_register(hdw,PVR2_GPIO_OUT,nval); 503362306a36Sopenharmony_ci} 503462306a36Sopenharmony_ci 503562306a36Sopenharmony_ci 503662306a36Sopenharmony_civoid pvr2_hdw_status_poll(struct pvr2_hdw *hdw) 503762306a36Sopenharmony_ci{ 503862306a36Sopenharmony_ci struct v4l2_tuner *vtp = &hdw->tuner_signal_info; 503962306a36Sopenharmony_ci memset(vtp, 0, sizeof(*vtp)); 504062306a36Sopenharmony_ci vtp->type = (hdw->input_val == PVR2_CVAL_INPUT_RADIO) ? 504162306a36Sopenharmony_ci V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; 504262306a36Sopenharmony_ci hdw->tuner_signal_stale = 0; 504362306a36Sopenharmony_ci /* Note: There apparently is no replacement for VIDIOC_CROPCAP 504462306a36Sopenharmony_ci using v4l2-subdev - therefore we can't support that AT ALL right 504562306a36Sopenharmony_ci now. (Of course, no sub-drivers seem to implement it either. 504662306a36Sopenharmony_ci But now it's a chicken and egg problem...) */ 504762306a36Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner, g_tuner, vtp); 504862306a36Sopenharmony_ci pvr2_trace(PVR2_TRACE_CHIPS, "subdev status poll type=%u strength=%u audio=0x%x cap=0x%x low=%u hi=%u", 504962306a36Sopenharmony_ci vtp->type, 505062306a36Sopenharmony_ci vtp->signal, vtp->rxsubchans, vtp->capability, 505162306a36Sopenharmony_ci vtp->rangelow, vtp->rangehigh); 505262306a36Sopenharmony_ci 505362306a36Sopenharmony_ci /* We have to do this to avoid getting into constant polling if 505462306a36Sopenharmony_ci there's nobody to answer a poll of cropcap info. */ 505562306a36Sopenharmony_ci hdw->cropcap_stale = 0; 505662306a36Sopenharmony_ci} 505762306a36Sopenharmony_ci 505862306a36Sopenharmony_ci 505962306a36Sopenharmony_ciunsigned int pvr2_hdw_get_input_available(struct pvr2_hdw *hdw) 506062306a36Sopenharmony_ci{ 506162306a36Sopenharmony_ci return hdw->input_avail_mask; 506262306a36Sopenharmony_ci} 506362306a36Sopenharmony_ci 506462306a36Sopenharmony_ci 506562306a36Sopenharmony_ciunsigned int pvr2_hdw_get_input_allowed(struct pvr2_hdw *hdw) 506662306a36Sopenharmony_ci{ 506762306a36Sopenharmony_ci return hdw->input_allowed_mask; 506862306a36Sopenharmony_ci} 506962306a36Sopenharmony_ci 507062306a36Sopenharmony_ci 507162306a36Sopenharmony_cistatic int pvr2_hdw_set_input(struct pvr2_hdw *hdw,int v) 507262306a36Sopenharmony_ci{ 507362306a36Sopenharmony_ci if (hdw->input_val != v) { 507462306a36Sopenharmony_ci hdw->input_val = v; 507562306a36Sopenharmony_ci hdw->input_dirty = !0; 507662306a36Sopenharmony_ci } 507762306a36Sopenharmony_ci 507862306a36Sopenharmony_ci /* Handle side effects - if we switch to a mode that needs the RF 507962306a36Sopenharmony_ci tuner, then select the right frequency choice as well and mark 508062306a36Sopenharmony_ci it dirty. */ 508162306a36Sopenharmony_ci if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) { 508262306a36Sopenharmony_ci hdw->freqSelector = 0; 508362306a36Sopenharmony_ci hdw->freqDirty = !0; 508462306a36Sopenharmony_ci } else if ((hdw->input_val == PVR2_CVAL_INPUT_TV) || 508562306a36Sopenharmony_ci (hdw->input_val == PVR2_CVAL_INPUT_DTV)) { 508662306a36Sopenharmony_ci hdw->freqSelector = 1; 508762306a36Sopenharmony_ci hdw->freqDirty = !0; 508862306a36Sopenharmony_ci } 508962306a36Sopenharmony_ci return 0; 509062306a36Sopenharmony_ci} 509162306a36Sopenharmony_ci 509262306a36Sopenharmony_ci 509362306a36Sopenharmony_ciint pvr2_hdw_set_input_allowed(struct pvr2_hdw *hdw, 509462306a36Sopenharmony_ci unsigned int change_mask, 509562306a36Sopenharmony_ci unsigned int change_val) 509662306a36Sopenharmony_ci{ 509762306a36Sopenharmony_ci int ret = 0; 509862306a36Sopenharmony_ci unsigned int nv,m,idx; 509962306a36Sopenharmony_ci LOCK_TAKE(hdw->big_lock); 510062306a36Sopenharmony_ci do { 510162306a36Sopenharmony_ci nv = hdw->input_allowed_mask & ~change_mask; 510262306a36Sopenharmony_ci nv |= (change_val & change_mask); 510362306a36Sopenharmony_ci nv &= hdw->input_avail_mask; 510462306a36Sopenharmony_ci if (!nv) { 510562306a36Sopenharmony_ci /* No legal modes left; return error instead. */ 510662306a36Sopenharmony_ci ret = -EPERM; 510762306a36Sopenharmony_ci break; 510862306a36Sopenharmony_ci } 510962306a36Sopenharmony_ci hdw->input_allowed_mask = nv; 511062306a36Sopenharmony_ci if ((1UL << hdw->input_val) & hdw->input_allowed_mask) { 511162306a36Sopenharmony_ci /* Current mode is still in the allowed mask, so 511262306a36Sopenharmony_ci we're done. */ 511362306a36Sopenharmony_ci break; 511462306a36Sopenharmony_ci } 511562306a36Sopenharmony_ci /* Select and switch to a mode that is still in the allowed 511662306a36Sopenharmony_ci mask */ 511762306a36Sopenharmony_ci if (!hdw->input_allowed_mask) { 511862306a36Sopenharmony_ci /* Nothing legal; give up */ 511962306a36Sopenharmony_ci break; 512062306a36Sopenharmony_ci } 512162306a36Sopenharmony_ci m = hdw->input_allowed_mask; 512262306a36Sopenharmony_ci for (idx = 0; idx < (sizeof(m) << 3); idx++) { 512362306a36Sopenharmony_ci if (!((1UL << idx) & m)) continue; 512462306a36Sopenharmony_ci pvr2_hdw_set_input(hdw,idx); 512562306a36Sopenharmony_ci break; 512662306a36Sopenharmony_ci } 512762306a36Sopenharmony_ci } while (0); 512862306a36Sopenharmony_ci LOCK_GIVE(hdw->big_lock); 512962306a36Sopenharmony_ci return ret; 513062306a36Sopenharmony_ci} 513162306a36Sopenharmony_ci 513262306a36Sopenharmony_ci 513362306a36Sopenharmony_ci/* Find I2C address of eeprom */ 513462306a36Sopenharmony_cistatic int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw) 513562306a36Sopenharmony_ci{ 513662306a36Sopenharmony_ci int result; 513762306a36Sopenharmony_ci LOCK_TAKE(hdw->ctl_lock); do { 513862306a36Sopenharmony_ci hdw->cmd_buffer[0] = FX2CMD_GET_EEPROM_ADDR; 513962306a36Sopenharmony_ci result = pvr2_send_request(hdw, 514062306a36Sopenharmony_ci hdw->cmd_buffer,1, 514162306a36Sopenharmony_ci hdw->cmd_buffer,1); 514262306a36Sopenharmony_ci if (result < 0) break; 514362306a36Sopenharmony_ci result = hdw->cmd_buffer[0]; 514462306a36Sopenharmony_ci } while(0); LOCK_GIVE(hdw->ctl_lock); 514562306a36Sopenharmony_ci return result; 514662306a36Sopenharmony_ci} 5147