18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2005 Mike Isely <isely@pobox.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/errno.h> 88c2ecf20Sopenharmony_ci#include <linux/string.h> 98c2ecf20Sopenharmony_ci#include <linux/slab.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/firmware.h> 128c2ecf20Sopenharmony_ci#include <linux/videodev2.h> 138c2ecf20Sopenharmony_ci#include <media/v4l2-common.h> 148c2ecf20Sopenharmony_ci#include <media/tuner.h> 158c2ecf20Sopenharmony_ci#include "pvrusb2.h" 168c2ecf20Sopenharmony_ci#include "pvrusb2-std.h" 178c2ecf20Sopenharmony_ci#include "pvrusb2-util.h" 188c2ecf20Sopenharmony_ci#include "pvrusb2-hdw.h" 198c2ecf20Sopenharmony_ci#include "pvrusb2-i2c-core.h" 208c2ecf20Sopenharmony_ci#include "pvrusb2-eeprom.h" 218c2ecf20Sopenharmony_ci#include "pvrusb2-hdw-internal.h" 228c2ecf20Sopenharmony_ci#include "pvrusb2-encoder.h" 238c2ecf20Sopenharmony_ci#include "pvrusb2-debug.h" 248c2ecf20Sopenharmony_ci#include "pvrusb2-fx2-cmd.h" 258c2ecf20Sopenharmony_ci#include "pvrusb2-wm8775.h" 268c2ecf20Sopenharmony_ci#include "pvrusb2-video-v4l.h" 278c2ecf20Sopenharmony_ci#include "pvrusb2-cx2584x-v4l.h" 288c2ecf20Sopenharmony_ci#include "pvrusb2-cs53l32a.h" 298c2ecf20Sopenharmony_ci#include "pvrusb2-audio.h" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define TV_MIN_FREQ 55250000L 328c2ecf20Sopenharmony_ci#define TV_MAX_FREQ 850000000L 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* This defines a minimum interval that the decoder must remain quiet 358c2ecf20Sopenharmony_ci before we are allowed to start it running. */ 368c2ecf20Sopenharmony_ci#define TIME_MSEC_DECODER_WAIT 50 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* This defines a minimum interval that the decoder must be allowed to run 398c2ecf20Sopenharmony_ci before we can safely begin using its streaming output. */ 408c2ecf20Sopenharmony_ci#define TIME_MSEC_DECODER_STABILIZATION_WAIT 300 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* This defines a minimum interval that the encoder must remain quiet 438c2ecf20Sopenharmony_ci before we are allowed to configure it. */ 448c2ecf20Sopenharmony_ci#define TIME_MSEC_ENCODER_WAIT 50 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/* This defines the minimum interval that the encoder must successfully run 478c2ecf20Sopenharmony_ci before we consider that the encoder has run at least once since its 488c2ecf20Sopenharmony_ci firmware has been loaded. This measurement is in important for cases 498c2ecf20Sopenharmony_ci where we can't do something until we know that the encoder has been run 508c2ecf20Sopenharmony_ci at least once. */ 518c2ecf20Sopenharmony_ci#define TIME_MSEC_ENCODER_OK 250 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = NULL}; 548c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(pvr2_unit_mtx); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic int ctlchg; 578c2ecf20Sopenharmony_cistatic int procreload; 588c2ecf20Sopenharmony_cistatic int tuner[PVR_NUM] = { [0 ... PVR_NUM-1] = -1 }; 598c2ecf20Sopenharmony_cistatic int tolerance[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 }; 608c2ecf20Sopenharmony_cistatic int video_std[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 }; 618c2ecf20Sopenharmony_cistatic int init_pause_msec; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cimodule_param(ctlchg, int, S_IRUGO|S_IWUSR); 648c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ctlchg, "0=optimize ctl change 1=always accept new ctl value"); 658c2ecf20Sopenharmony_cimodule_param(init_pause_msec, int, S_IRUGO|S_IWUSR); 668c2ecf20Sopenharmony_ciMODULE_PARM_DESC(init_pause_msec, "hardware initialization settling delay"); 678c2ecf20Sopenharmony_cimodule_param(procreload, int, S_IRUGO|S_IWUSR); 688c2ecf20Sopenharmony_ciMODULE_PARM_DESC(procreload, 698c2ecf20Sopenharmony_ci "Attempt init failure recovery with firmware reload"); 708c2ecf20Sopenharmony_cimodule_param_array(tuner, int, NULL, 0444); 718c2ecf20Sopenharmony_ciMODULE_PARM_DESC(tuner,"specify installed tuner type"); 728c2ecf20Sopenharmony_cimodule_param_array(video_std, int, NULL, 0444); 738c2ecf20Sopenharmony_ciMODULE_PARM_DESC(video_std,"specify initial video standard"); 748c2ecf20Sopenharmony_cimodule_param_array(tolerance, int, NULL, 0444); 758c2ecf20Sopenharmony_ciMODULE_PARM_DESC(tolerance,"specify stream error tolerance"); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* US Broadcast channel 3 (61.25 MHz), to help with testing */ 788c2ecf20Sopenharmony_cistatic int default_tv_freq = 61250000L; 798c2ecf20Sopenharmony_ci/* 104.3 MHz, a usable FM station for my area */ 808c2ecf20Sopenharmony_cistatic int default_radio_freq = 104300000L; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cimodule_param_named(tv_freq, default_tv_freq, int, 0444); 838c2ecf20Sopenharmony_ciMODULE_PARM_DESC(tv_freq, "specify initial television frequency"); 848c2ecf20Sopenharmony_cimodule_param_named(radio_freq, default_radio_freq, int, 0444); 858c2ecf20Sopenharmony_ciMODULE_PARM_DESC(radio_freq, "specify initial radio frequency"); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci#define PVR2_CTL_WRITE_ENDPOINT 0x01 888c2ecf20Sopenharmony_ci#define PVR2_CTL_READ_ENDPOINT 0x81 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci#define PVR2_GPIO_IN 0x9008 918c2ecf20Sopenharmony_ci#define PVR2_GPIO_OUT 0x900c 928c2ecf20Sopenharmony_ci#define PVR2_GPIO_DIR 0x9020 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci#define trace_firmware(...) pvr2_trace(PVR2_TRACE_FIRMWARE,__VA_ARGS__) 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci#define PVR2_FIRMWARE_ENDPOINT 0x02 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/* size of a firmware chunk */ 998c2ecf20Sopenharmony_ci#define FIRMWARE_CHUNK_SIZE 0x2000 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_citypedef void (*pvr2_subdev_update_func)(struct pvr2_hdw *, 1028c2ecf20Sopenharmony_ci struct v4l2_subdev *); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic const pvr2_subdev_update_func pvr2_module_update_functions[] = { 1058c2ecf20Sopenharmony_ci [PVR2_CLIENT_ID_WM8775] = pvr2_wm8775_subdev_update, 1068c2ecf20Sopenharmony_ci [PVR2_CLIENT_ID_SAA7115] = pvr2_saa7115_subdev_update, 1078c2ecf20Sopenharmony_ci [PVR2_CLIENT_ID_MSP3400] = pvr2_msp3400_subdev_update, 1088c2ecf20Sopenharmony_ci [PVR2_CLIENT_ID_CX25840] = pvr2_cx25840_subdev_update, 1098c2ecf20Sopenharmony_ci [PVR2_CLIENT_ID_CS53L32A] = pvr2_cs53l32a_subdev_update, 1108c2ecf20Sopenharmony_ci}; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic const char *module_names[] = { 1138c2ecf20Sopenharmony_ci [PVR2_CLIENT_ID_MSP3400] = "msp3400", 1148c2ecf20Sopenharmony_ci [PVR2_CLIENT_ID_CX25840] = "cx25840", 1158c2ecf20Sopenharmony_ci [PVR2_CLIENT_ID_SAA7115] = "saa7115", 1168c2ecf20Sopenharmony_ci [PVR2_CLIENT_ID_TUNER] = "tuner", 1178c2ecf20Sopenharmony_ci [PVR2_CLIENT_ID_DEMOD] = "tuner", 1188c2ecf20Sopenharmony_ci [PVR2_CLIENT_ID_CS53L32A] = "cs53l32a", 1198c2ecf20Sopenharmony_ci [PVR2_CLIENT_ID_WM8775] = "wm8775", 1208c2ecf20Sopenharmony_ci}; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic const unsigned char *module_i2c_addresses[] = { 1248c2ecf20Sopenharmony_ci [PVR2_CLIENT_ID_TUNER] = "\x60\x61\x62\x63", 1258c2ecf20Sopenharmony_ci [PVR2_CLIENT_ID_DEMOD] = "\x43", 1268c2ecf20Sopenharmony_ci [PVR2_CLIENT_ID_MSP3400] = "\x40", 1278c2ecf20Sopenharmony_ci [PVR2_CLIENT_ID_SAA7115] = "\x21", 1288c2ecf20Sopenharmony_ci [PVR2_CLIENT_ID_WM8775] = "\x1b", 1298c2ecf20Sopenharmony_ci [PVR2_CLIENT_ID_CX25840] = "\x44", 1308c2ecf20Sopenharmony_ci [PVR2_CLIENT_ID_CS53L32A] = "\x11", 1318c2ecf20Sopenharmony_ci}; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic const char *ir_scheme_names[] = { 1358c2ecf20Sopenharmony_ci [PVR2_IR_SCHEME_NONE] = "none", 1368c2ecf20Sopenharmony_ci [PVR2_IR_SCHEME_29XXX] = "29xxx", 1378c2ecf20Sopenharmony_ci [PVR2_IR_SCHEME_24XXX] = "24xxx (29xxx emulation)", 1388c2ecf20Sopenharmony_ci [PVR2_IR_SCHEME_24XXX_MCE] = "24xxx (MCE device)", 1398c2ecf20Sopenharmony_ci [PVR2_IR_SCHEME_ZILOG] = "Zilog", 1408c2ecf20Sopenharmony_ci}; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci/* Define the list of additional controls we'll dynamically construct based 1448c2ecf20Sopenharmony_ci on query of the cx2341x module. */ 1458c2ecf20Sopenharmony_cistruct pvr2_mpeg_ids { 1468c2ecf20Sopenharmony_ci const char *strid; 1478c2ecf20Sopenharmony_ci int id; 1488c2ecf20Sopenharmony_ci}; 1498c2ecf20Sopenharmony_cistatic const struct pvr2_mpeg_ids mpeg_ids[] = { 1508c2ecf20Sopenharmony_ci { 1518c2ecf20Sopenharmony_ci .strid = "audio_layer", 1528c2ecf20Sopenharmony_ci .id = V4L2_CID_MPEG_AUDIO_ENCODING, 1538c2ecf20Sopenharmony_ci },{ 1548c2ecf20Sopenharmony_ci .strid = "audio_bitrate", 1558c2ecf20Sopenharmony_ci .id = V4L2_CID_MPEG_AUDIO_L2_BITRATE, 1568c2ecf20Sopenharmony_ci },{ 1578c2ecf20Sopenharmony_ci /* Already using audio_mode elsewhere :-( */ 1588c2ecf20Sopenharmony_ci .strid = "mpeg_audio_mode", 1598c2ecf20Sopenharmony_ci .id = V4L2_CID_MPEG_AUDIO_MODE, 1608c2ecf20Sopenharmony_ci },{ 1618c2ecf20Sopenharmony_ci .strid = "mpeg_audio_mode_extension", 1628c2ecf20Sopenharmony_ci .id = V4L2_CID_MPEG_AUDIO_MODE_EXTENSION, 1638c2ecf20Sopenharmony_ci },{ 1648c2ecf20Sopenharmony_ci .strid = "audio_emphasis", 1658c2ecf20Sopenharmony_ci .id = V4L2_CID_MPEG_AUDIO_EMPHASIS, 1668c2ecf20Sopenharmony_ci },{ 1678c2ecf20Sopenharmony_ci .strid = "audio_crc", 1688c2ecf20Sopenharmony_ci .id = V4L2_CID_MPEG_AUDIO_CRC, 1698c2ecf20Sopenharmony_ci },{ 1708c2ecf20Sopenharmony_ci .strid = "video_aspect", 1718c2ecf20Sopenharmony_ci .id = V4L2_CID_MPEG_VIDEO_ASPECT, 1728c2ecf20Sopenharmony_ci },{ 1738c2ecf20Sopenharmony_ci .strid = "video_b_frames", 1748c2ecf20Sopenharmony_ci .id = V4L2_CID_MPEG_VIDEO_B_FRAMES, 1758c2ecf20Sopenharmony_ci },{ 1768c2ecf20Sopenharmony_ci .strid = "video_gop_size", 1778c2ecf20Sopenharmony_ci .id = V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1788c2ecf20Sopenharmony_ci },{ 1798c2ecf20Sopenharmony_ci .strid = "video_gop_closure", 1808c2ecf20Sopenharmony_ci .id = V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, 1818c2ecf20Sopenharmony_ci },{ 1828c2ecf20Sopenharmony_ci .strid = "video_bitrate_mode", 1838c2ecf20Sopenharmony_ci .id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE, 1848c2ecf20Sopenharmony_ci },{ 1858c2ecf20Sopenharmony_ci .strid = "video_bitrate", 1868c2ecf20Sopenharmony_ci .id = V4L2_CID_MPEG_VIDEO_BITRATE, 1878c2ecf20Sopenharmony_ci },{ 1888c2ecf20Sopenharmony_ci .strid = "video_bitrate_peak", 1898c2ecf20Sopenharmony_ci .id = V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, 1908c2ecf20Sopenharmony_ci },{ 1918c2ecf20Sopenharmony_ci .strid = "video_temporal_decimation", 1928c2ecf20Sopenharmony_ci .id = V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION, 1938c2ecf20Sopenharmony_ci },{ 1948c2ecf20Sopenharmony_ci .strid = "stream_type", 1958c2ecf20Sopenharmony_ci .id = V4L2_CID_MPEG_STREAM_TYPE, 1968c2ecf20Sopenharmony_ci },{ 1978c2ecf20Sopenharmony_ci .strid = "video_spatial_filter_mode", 1988c2ecf20Sopenharmony_ci .id = V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE, 1998c2ecf20Sopenharmony_ci },{ 2008c2ecf20Sopenharmony_ci .strid = "video_spatial_filter", 2018c2ecf20Sopenharmony_ci .id = V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER, 2028c2ecf20Sopenharmony_ci },{ 2038c2ecf20Sopenharmony_ci .strid = "video_luma_spatial_filter_type", 2048c2ecf20Sopenharmony_ci .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE, 2058c2ecf20Sopenharmony_ci },{ 2068c2ecf20Sopenharmony_ci .strid = "video_chroma_spatial_filter_type", 2078c2ecf20Sopenharmony_ci .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE, 2088c2ecf20Sopenharmony_ci },{ 2098c2ecf20Sopenharmony_ci .strid = "video_temporal_filter_mode", 2108c2ecf20Sopenharmony_ci .id = V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE, 2118c2ecf20Sopenharmony_ci },{ 2128c2ecf20Sopenharmony_ci .strid = "video_temporal_filter", 2138c2ecf20Sopenharmony_ci .id = V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER, 2148c2ecf20Sopenharmony_ci },{ 2158c2ecf20Sopenharmony_ci .strid = "video_median_filter_type", 2168c2ecf20Sopenharmony_ci .id = V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE, 2178c2ecf20Sopenharmony_ci },{ 2188c2ecf20Sopenharmony_ci .strid = "video_luma_median_filter_top", 2198c2ecf20Sopenharmony_ci .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP, 2208c2ecf20Sopenharmony_ci },{ 2218c2ecf20Sopenharmony_ci .strid = "video_luma_median_filter_bottom", 2228c2ecf20Sopenharmony_ci .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM, 2238c2ecf20Sopenharmony_ci },{ 2248c2ecf20Sopenharmony_ci .strid = "video_chroma_median_filter_top", 2258c2ecf20Sopenharmony_ci .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP, 2268c2ecf20Sopenharmony_ci },{ 2278c2ecf20Sopenharmony_ci .strid = "video_chroma_median_filter_bottom", 2288c2ecf20Sopenharmony_ci .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM, 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci}; 2318c2ecf20Sopenharmony_ci#define MPEGDEF_COUNT ARRAY_SIZE(mpeg_ids) 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic const char *control_values_srate[] = { 2358c2ecf20Sopenharmony_ci [V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100] = "44.1 kHz", 2368c2ecf20Sopenharmony_ci [V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000] = "48 kHz", 2378c2ecf20Sopenharmony_ci [V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000] = "32 kHz", 2388c2ecf20Sopenharmony_ci}; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic const char *control_values_input[] = { 2438c2ecf20Sopenharmony_ci [PVR2_CVAL_INPUT_TV] = "television", /*xawtv needs this name*/ 2448c2ecf20Sopenharmony_ci [PVR2_CVAL_INPUT_DTV] = "dtv", 2458c2ecf20Sopenharmony_ci [PVR2_CVAL_INPUT_RADIO] = "radio", 2468c2ecf20Sopenharmony_ci [PVR2_CVAL_INPUT_SVIDEO] = "s-video", 2478c2ecf20Sopenharmony_ci [PVR2_CVAL_INPUT_COMPOSITE] = "composite", 2488c2ecf20Sopenharmony_ci}; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic const char *control_values_audiomode[] = { 2528c2ecf20Sopenharmony_ci [V4L2_TUNER_MODE_MONO] = "Mono", 2538c2ecf20Sopenharmony_ci [V4L2_TUNER_MODE_STEREO] = "Stereo", 2548c2ecf20Sopenharmony_ci [V4L2_TUNER_MODE_LANG1] = "Lang1", 2558c2ecf20Sopenharmony_ci [V4L2_TUNER_MODE_LANG2] = "Lang2", 2568c2ecf20Sopenharmony_ci [V4L2_TUNER_MODE_LANG1_LANG2] = "Lang1+Lang2", 2578c2ecf20Sopenharmony_ci}; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic const char *control_values_hsm[] = { 2618c2ecf20Sopenharmony_ci [PVR2_CVAL_HSM_FAIL] = "Fail", 2628c2ecf20Sopenharmony_ci [PVR2_CVAL_HSM_HIGH] = "High", 2638c2ecf20Sopenharmony_ci [PVR2_CVAL_HSM_FULL] = "Full", 2648c2ecf20Sopenharmony_ci}; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic const char *pvr2_state_names[] = { 2688c2ecf20Sopenharmony_ci [PVR2_STATE_NONE] = "none", 2698c2ecf20Sopenharmony_ci [PVR2_STATE_DEAD] = "dead", 2708c2ecf20Sopenharmony_ci [PVR2_STATE_COLD] = "cold", 2718c2ecf20Sopenharmony_ci [PVR2_STATE_WARM] = "warm", 2728c2ecf20Sopenharmony_ci [PVR2_STATE_ERROR] = "error", 2738c2ecf20Sopenharmony_ci [PVR2_STATE_READY] = "ready", 2748c2ecf20Sopenharmony_ci [PVR2_STATE_RUN] = "run", 2758c2ecf20Sopenharmony_ci}; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistruct pvr2_fx2cmd_descdef { 2798c2ecf20Sopenharmony_ci unsigned char id; 2808c2ecf20Sopenharmony_ci unsigned char *desc; 2818c2ecf20Sopenharmony_ci}; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic const struct pvr2_fx2cmd_descdef pvr2_fx2cmd_desc[] = { 2848c2ecf20Sopenharmony_ci {FX2CMD_MEM_WRITE_DWORD, "write encoder dword"}, 2858c2ecf20Sopenharmony_ci {FX2CMD_MEM_READ_DWORD, "read encoder dword"}, 2868c2ecf20Sopenharmony_ci {FX2CMD_HCW_ZILOG_RESET, "zilog IR reset control"}, 2878c2ecf20Sopenharmony_ci {FX2CMD_MEM_READ_64BYTES, "read encoder 64bytes"}, 2888c2ecf20Sopenharmony_ci {FX2CMD_REG_WRITE, "write encoder register"}, 2898c2ecf20Sopenharmony_ci {FX2CMD_REG_READ, "read encoder register"}, 2908c2ecf20Sopenharmony_ci {FX2CMD_MEMSEL, "encoder memsel"}, 2918c2ecf20Sopenharmony_ci {FX2CMD_I2C_WRITE, "i2c write"}, 2928c2ecf20Sopenharmony_ci {FX2CMD_I2C_READ, "i2c read"}, 2938c2ecf20Sopenharmony_ci {FX2CMD_GET_USB_SPEED, "get USB speed"}, 2948c2ecf20Sopenharmony_ci {FX2CMD_STREAMING_ON, "stream on"}, 2958c2ecf20Sopenharmony_ci {FX2CMD_STREAMING_OFF, "stream off"}, 2968c2ecf20Sopenharmony_ci {FX2CMD_FWPOST1, "fwpost1"}, 2978c2ecf20Sopenharmony_ci {FX2CMD_POWER_OFF, "power off"}, 2988c2ecf20Sopenharmony_ci {FX2CMD_POWER_ON, "power on"}, 2998c2ecf20Sopenharmony_ci {FX2CMD_DEEP_RESET, "deep reset"}, 3008c2ecf20Sopenharmony_ci {FX2CMD_GET_EEPROM_ADDR, "get rom addr"}, 3018c2ecf20Sopenharmony_ci {FX2CMD_GET_IR_CODE, "get IR code"}, 3028c2ecf20Sopenharmony_ci {FX2CMD_HCW_DEMOD_RESETIN, "hcw demod resetin"}, 3038c2ecf20Sopenharmony_ci {FX2CMD_HCW_DTV_STREAMING_ON, "hcw dtv stream on"}, 3048c2ecf20Sopenharmony_ci {FX2CMD_HCW_DTV_STREAMING_OFF, "hcw dtv stream off"}, 3058c2ecf20Sopenharmony_ci {FX2CMD_ONAIR_DTV_STREAMING_ON, "onair dtv stream on"}, 3068c2ecf20Sopenharmony_ci {FX2CMD_ONAIR_DTV_STREAMING_OFF, "onair dtv stream off"}, 3078c2ecf20Sopenharmony_ci {FX2CMD_ONAIR_DTV_POWER_ON, "onair dtv power on"}, 3088c2ecf20Sopenharmony_ci {FX2CMD_ONAIR_DTV_POWER_OFF, "onair dtv power off"}, 3098c2ecf20Sopenharmony_ci {FX2CMD_HCW_DEMOD_RESET_PIN, "hcw demod reset pin"}, 3108c2ecf20Sopenharmony_ci {FX2CMD_HCW_MAKO_SLEEP_PIN, "hcw mako sleep pin"}, 3118c2ecf20Sopenharmony_ci}; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic int pvr2_hdw_set_input(struct pvr2_hdw *hdw,int v); 3158c2ecf20Sopenharmony_cistatic void pvr2_hdw_state_sched(struct pvr2_hdw *); 3168c2ecf20Sopenharmony_cistatic int pvr2_hdw_state_eval(struct pvr2_hdw *); 3178c2ecf20Sopenharmony_cistatic void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long); 3188c2ecf20Sopenharmony_cistatic void pvr2_hdw_worker_poll(struct work_struct *work); 3198c2ecf20Sopenharmony_cistatic int pvr2_hdw_wait(struct pvr2_hdw *,int state); 3208c2ecf20Sopenharmony_cistatic int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *); 3218c2ecf20Sopenharmony_cistatic void pvr2_hdw_state_log_state(struct pvr2_hdw *); 3228c2ecf20Sopenharmony_cistatic int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl); 3238c2ecf20Sopenharmony_cistatic int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw); 3248c2ecf20Sopenharmony_cistatic int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw); 3258c2ecf20Sopenharmony_cistatic void pvr2_hdw_quiescent_timeout(struct timer_list *); 3268c2ecf20Sopenharmony_cistatic void pvr2_hdw_decoder_stabilization_timeout(struct timer_list *); 3278c2ecf20Sopenharmony_cistatic void pvr2_hdw_encoder_wait_timeout(struct timer_list *); 3288c2ecf20Sopenharmony_cistatic void pvr2_hdw_encoder_run_timeout(struct timer_list *); 3298c2ecf20Sopenharmony_cistatic int pvr2_issue_simple_cmd(struct pvr2_hdw *,u32); 3308c2ecf20Sopenharmony_cistatic int pvr2_send_request_ex(struct pvr2_hdw *hdw, 3318c2ecf20Sopenharmony_ci unsigned int timeout,int probe_fl, 3328c2ecf20Sopenharmony_ci void *write_data,unsigned int write_len, 3338c2ecf20Sopenharmony_ci void *read_data,unsigned int read_len); 3348c2ecf20Sopenharmony_cistatic int pvr2_hdw_check_cropcap(struct pvr2_hdw *hdw); 3358c2ecf20Sopenharmony_cistatic v4l2_std_id pvr2_hdw_get_detected_std(struct pvr2_hdw *hdw); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cistatic void trace_stbit(const char *name,int val) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_STBITS, 3408c2ecf20Sopenharmony_ci "State bit %s <-- %s", 3418c2ecf20Sopenharmony_ci name,(val ? "true" : "false")); 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic int ctrl_channelfreq_get(struct pvr2_ctrl *cptr,int *vp) 3458c2ecf20Sopenharmony_ci{ 3468c2ecf20Sopenharmony_ci struct pvr2_hdw *hdw = cptr->hdw; 3478c2ecf20Sopenharmony_ci if ((hdw->freqProgSlot > 0) && (hdw->freqProgSlot <= FREQTABLE_SIZE)) { 3488c2ecf20Sopenharmony_ci *vp = hdw->freqTable[hdw->freqProgSlot-1]; 3498c2ecf20Sopenharmony_ci } else { 3508c2ecf20Sopenharmony_ci *vp = 0; 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci return 0; 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cistatic int ctrl_channelfreq_set(struct pvr2_ctrl *cptr,int m,int v) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci struct pvr2_hdw *hdw = cptr->hdw; 3588c2ecf20Sopenharmony_ci unsigned int slotId = hdw->freqProgSlot; 3598c2ecf20Sopenharmony_ci if ((slotId > 0) && (slotId <= FREQTABLE_SIZE)) { 3608c2ecf20Sopenharmony_ci hdw->freqTable[slotId-1] = v; 3618c2ecf20Sopenharmony_ci /* Handle side effects correctly - if we're tuned to this 3628c2ecf20Sopenharmony_ci slot, then forgot the slot id relation since the stored 3638c2ecf20Sopenharmony_ci frequency has been changed. */ 3648c2ecf20Sopenharmony_ci if (hdw->freqSelector) { 3658c2ecf20Sopenharmony_ci if (hdw->freqSlotRadio == slotId) { 3668c2ecf20Sopenharmony_ci hdw->freqSlotRadio = 0; 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci } else { 3698c2ecf20Sopenharmony_ci if (hdw->freqSlotTelevision == slotId) { 3708c2ecf20Sopenharmony_ci hdw->freqSlotTelevision = 0; 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci return 0; 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic int ctrl_channelprog_get(struct pvr2_ctrl *cptr,int *vp) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci *vp = cptr->hdw->freqProgSlot; 3808c2ecf20Sopenharmony_ci return 0; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic int ctrl_channelprog_set(struct pvr2_ctrl *cptr,int m,int v) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci struct pvr2_hdw *hdw = cptr->hdw; 3868c2ecf20Sopenharmony_ci if ((v >= 0) && (v <= FREQTABLE_SIZE)) { 3878c2ecf20Sopenharmony_ci hdw->freqProgSlot = v; 3888c2ecf20Sopenharmony_ci } 3898c2ecf20Sopenharmony_ci return 0; 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic int ctrl_channel_get(struct pvr2_ctrl *cptr,int *vp) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci struct pvr2_hdw *hdw = cptr->hdw; 3958c2ecf20Sopenharmony_ci *vp = hdw->freqSelector ? hdw->freqSlotRadio : hdw->freqSlotTelevision; 3968c2ecf20Sopenharmony_ci return 0; 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic int ctrl_channel_set(struct pvr2_ctrl *cptr,int m,int slotId) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci unsigned freq = 0; 4028c2ecf20Sopenharmony_ci struct pvr2_hdw *hdw = cptr->hdw; 4038c2ecf20Sopenharmony_ci if ((slotId < 0) || (slotId > FREQTABLE_SIZE)) return 0; 4048c2ecf20Sopenharmony_ci if (slotId > 0) { 4058c2ecf20Sopenharmony_ci freq = hdw->freqTable[slotId-1]; 4068c2ecf20Sopenharmony_ci if (!freq) return 0; 4078c2ecf20Sopenharmony_ci pvr2_hdw_set_cur_freq(hdw,freq); 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci if (hdw->freqSelector) { 4108c2ecf20Sopenharmony_ci hdw->freqSlotRadio = slotId; 4118c2ecf20Sopenharmony_ci } else { 4128c2ecf20Sopenharmony_ci hdw->freqSlotTelevision = slotId; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci return 0; 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic int ctrl_freq_get(struct pvr2_ctrl *cptr,int *vp) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci *vp = pvr2_hdw_get_cur_freq(cptr->hdw); 4208c2ecf20Sopenharmony_ci return 0; 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic int ctrl_freq_is_dirty(struct pvr2_ctrl *cptr) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci return cptr->hdw->freqDirty != 0; 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cistatic void ctrl_freq_clear_dirty(struct pvr2_ctrl *cptr) 4298c2ecf20Sopenharmony_ci{ 4308c2ecf20Sopenharmony_ci cptr->hdw->freqDirty = 0; 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic int ctrl_freq_set(struct pvr2_ctrl *cptr,int m,int v) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci pvr2_hdw_set_cur_freq(cptr->hdw,v); 4368c2ecf20Sopenharmony_ci return 0; 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic int ctrl_cropl_min_get(struct pvr2_ctrl *cptr, int *left) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 4428c2ecf20Sopenharmony_ci int stat = pvr2_hdw_check_cropcap(cptr->hdw); 4438c2ecf20Sopenharmony_ci if (stat != 0) { 4448c2ecf20Sopenharmony_ci return stat; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci *left = cap->bounds.left; 4478c2ecf20Sopenharmony_ci return 0; 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cistatic int ctrl_cropl_max_get(struct pvr2_ctrl *cptr, int *left) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 4538c2ecf20Sopenharmony_ci int stat = pvr2_hdw_check_cropcap(cptr->hdw); 4548c2ecf20Sopenharmony_ci if (stat != 0) { 4558c2ecf20Sopenharmony_ci return stat; 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci *left = cap->bounds.left; 4588c2ecf20Sopenharmony_ci if (cap->bounds.width > cptr->hdw->cropw_val) { 4598c2ecf20Sopenharmony_ci *left += cap->bounds.width - cptr->hdw->cropw_val; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci return 0; 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_cistatic int ctrl_cropt_min_get(struct pvr2_ctrl *cptr, int *top) 4658c2ecf20Sopenharmony_ci{ 4668c2ecf20Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 4678c2ecf20Sopenharmony_ci int stat = pvr2_hdw_check_cropcap(cptr->hdw); 4688c2ecf20Sopenharmony_ci if (stat != 0) { 4698c2ecf20Sopenharmony_ci return stat; 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci *top = cap->bounds.top; 4728c2ecf20Sopenharmony_ci return 0; 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_cistatic int ctrl_cropt_max_get(struct pvr2_ctrl *cptr, int *top) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 4788c2ecf20Sopenharmony_ci int stat = pvr2_hdw_check_cropcap(cptr->hdw); 4798c2ecf20Sopenharmony_ci if (stat != 0) { 4808c2ecf20Sopenharmony_ci return stat; 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci *top = cap->bounds.top; 4838c2ecf20Sopenharmony_ci if (cap->bounds.height > cptr->hdw->croph_val) { 4848c2ecf20Sopenharmony_ci *top += cap->bounds.height - cptr->hdw->croph_val; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci return 0; 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic int ctrl_cropw_max_get(struct pvr2_ctrl *cptr, int *width) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 4928c2ecf20Sopenharmony_ci int stat, bleftend, cleft; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci stat = pvr2_hdw_check_cropcap(cptr->hdw); 4958c2ecf20Sopenharmony_ci if (stat != 0) { 4968c2ecf20Sopenharmony_ci return stat; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci bleftend = cap->bounds.left+cap->bounds.width; 4998c2ecf20Sopenharmony_ci cleft = cptr->hdw->cropl_val; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci *width = cleft < bleftend ? bleftend-cleft : 0; 5028c2ecf20Sopenharmony_ci return 0; 5038c2ecf20Sopenharmony_ci} 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_cistatic int ctrl_croph_max_get(struct pvr2_ctrl *cptr, int *height) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 5088c2ecf20Sopenharmony_ci int stat, btopend, ctop; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci stat = pvr2_hdw_check_cropcap(cptr->hdw); 5118c2ecf20Sopenharmony_ci if (stat != 0) { 5128c2ecf20Sopenharmony_ci return stat; 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci btopend = cap->bounds.top+cap->bounds.height; 5158c2ecf20Sopenharmony_ci ctop = cptr->hdw->cropt_val; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci *height = ctop < btopend ? btopend-ctop : 0; 5188c2ecf20Sopenharmony_ci return 0; 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic int ctrl_get_cropcapbl(struct pvr2_ctrl *cptr, int *val) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 5248c2ecf20Sopenharmony_ci int stat = pvr2_hdw_check_cropcap(cptr->hdw); 5258c2ecf20Sopenharmony_ci if (stat != 0) { 5268c2ecf20Sopenharmony_ci return stat; 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci *val = cap->bounds.left; 5298c2ecf20Sopenharmony_ci return 0; 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cistatic int ctrl_get_cropcapbt(struct pvr2_ctrl *cptr, int *val) 5338c2ecf20Sopenharmony_ci{ 5348c2ecf20Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 5358c2ecf20Sopenharmony_ci int stat = pvr2_hdw_check_cropcap(cptr->hdw); 5368c2ecf20Sopenharmony_ci if (stat != 0) { 5378c2ecf20Sopenharmony_ci return stat; 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci *val = cap->bounds.top; 5408c2ecf20Sopenharmony_ci return 0; 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistatic int ctrl_get_cropcapbw(struct pvr2_ctrl *cptr, int *val) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 5468c2ecf20Sopenharmony_ci int stat = pvr2_hdw_check_cropcap(cptr->hdw); 5478c2ecf20Sopenharmony_ci if (stat != 0) { 5488c2ecf20Sopenharmony_ci return stat; 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci *val = cap->bounds.width; 5518c2ecf20Sopenharmony_ci return 0; 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_cistatic int ctrl_get_cropcapbh(struct pvr2_ctrl *cptr, int *val) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 5578c2ecf20Sopenharmony_ci int stat = pvr2_hdw_check_cropcap(cptr->hdw); 5588c2ecf20Sopenharmony_ci if (stat != 0) { 5598c2ecf20Sopenharmony_ci return stat; 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci *val = cap->bounds.height; 5628c2ecf20Sopenharmony_ci return 0; 5638c2ecf20Sopenharmony_ci} 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_cistatic int ctrl_get_cropcapdl(struct pvr2_ctrl *cptr, int *val) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 5688c2ecf20Sopenharmony_ci int stat = pvr2_hdw_check_cropcap(cptr->hdw); 5698c2ecf20Sopenharmony_ci if (stat != 0) { 5708c2ecf20Sopenharmony_ci return stat; 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci *val = cap->defrect.left; 5738c2ecf20Sopenharmony_ci return 0; 5748c2ecf20Sopenharmony_ci} 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_cistatic int ctrl_get_cropcapdt(struct pvr2_ctrl *cptr, int *val) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 5798c2ecf20Sopenharmony_ci int stat = pvr2_hdw_check_cropcap(cptr->hdw); 5808c2ecf20Sopenharmony_ci if (stat != 0) { 5818c2ecf20Sopenharmony_ci return stat; 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci *val = cap->defrect.top; 5848c2ecf20Sopenharmony_ci return 0; 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_cistatic int ctrl_get_cropcapdw(struct pvr2_ctrl *cptr, int *val) 5888c2ecf20Sopenharmony_ci{ 5898c2ecf20Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 5908c2ecf20Sopenharmony_ci int stat = pvr2_hdw_check_cropcap(cptr->hdw); 5918c2ecf20Sopenharmony_ci if (stat != 0) { 5928c2ecf20Sopenharmony_ci return stat; 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci *val = cap->defrect.width; 5958c2ecf20Sopenharmony_ci return 0; 5968c2ecf20Sopenharmony_ci} 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_cistatic int ctrl_get_cropcapdh(struct pvr2_ctrl *cptr, int *val) 5998c2ecf20Sopenharmony_ci{ 6008c2ecf20Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 6018c2ecf20Sopenharmony_ci int stat = pvr2_hdw_check_cropcap(cptr->hdw); 6028c2ecf20Sopenharmony_ci if (stat != 0) { 6038c2ecf20Sopenharmony_ci return stat; 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci *val = cap->defrect.height; 6068c2ecf20Sopenharmony_ci return 0; 6078c2ecf20Sopenharmony_ci} 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_cistatic int ctrl_get_cropcappan(struct pvr2_ctrl *cptr, int *val) 6108c2ecf20Sopenharmony_ci{ 6118c2ecf20Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 6128c2ecf20Sopenharmony_ci int stat = pvr2_hdw_check_cropcap(cptr->hdw); 6138c2ecf20Sopenharmony_ci if (stat != 0) { 6148c2ecf20Sopenharmony_ci return stat; 6158c2ecf20Sopenharmony_ci } 6168c2ecf20Sopenharmony_ci *val = cap->pixelaspect.numerator; 6178c2ecf20Sopenharmony_ci return 0; 6188c2ecf20Sopenharmony_ci} 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_cistatic int ctrl_get_cropcappad(struct pvr2_ctrl *cptr, int *val) 6218c2ecf20Sopenharmony_ci{ 6228c2ecf20Sopenharmony_ci struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; 6238c2ecf20Sopenharmony_ci int stat = pvr2_hdw_check_cropcap(cptr->hdw); 6248c2ecf20Sopenharmony_ci if (stat != 0) { 6258c2ecf20Sopenharmony_ci return stat; 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_ci *val = cap->pixelaspect.denominator; 6288c2ecf20Sopenharmony_ci return 0; 6298c2ecf20Sopenharmony_ci} 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_cistatic int ctrl_vres_max_get(struct pvr2_ctrl *cptr,int *vp) 6328c2ecf20Sopenharmony_ci{ 6338c2ecf20Sopenharmony_ci /* Actual maximum depends on the video standard in effect. */ 6348c2ecf20Sopenharmony_ci if (cptr->hdw->std_mask_cur & V4L2_STD_525_60) { 6358c2ecf20Sopenharmony_ci *vp = 480; 6368c2ecf20Sopenharmony_ci } else { 6378c2ecf20Sopenharmony_ci *vp = 576; 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci return 0; 6408c2ecf20Sopenharmony_ci} 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_cistatic int ctrl_vres_min_get(struct pvr2_ctrl *cptr,int *vp) 6438c2ecf20Sopenharmony_ci{ 6448c2ecf20Sopenharmony_ci /* Actual minimum depends on device digitizer type. */ 6458c2ecf20Sopenharmony_ci if (cptr->hdw->hdw_desc->flag_has_cx25840) { 6468c2ecf20Sopenharmony_ci *vp = 75; 6478c2ecf20Sopenharmony_ci } else { 6488c2ecf20Sopenharmony_ci *vp = 17; 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci return 0; 6518c2ecf20Sopenharmony_ci} 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_cistatic int ctrl_get_input(struct pvr2_ctrl *cptr,int *vp) 6548c2ecf20Sopenharmony_ci{ 6558c2ecf20Sopenharmony_ci *vp = cptr->hdw->input_val; 6568c2ecf20Sopenharmony_ci return 0; 6578c2ecf20Sopenharmony_ci} 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_cistatic int ctrl_check_input(struct pvr2_ctrl *cptr,int v) 6608c2ecf20Sopenharmony_ci{ 6618c2ecf20Sopenharmony_ci if (v < 0 || v > PVR2_CVAL_INPUT_MAX) 6628c2ecf20Sopenharmony_ci return 0; 6638c2ecf20Sopenharmony_ci return ((1UL << v) & cptr->hdw->input_allowed_mask) != 0; 6648c2ecf20Sopenharmony_ci} 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_cistatic int ctrl_set_input(struct pvr2_ctrl *cptr,int m,int v) 6678c2ecf20Sopenharmony_ci{ 6688c2ecf20Sopenharmony_ci return pvr2_hdw_set_input(cptr->hdw,v); 6698c2ecf20Sopenharmony_ci} 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_cistatic int ctrl_isdirty_input(struct pvr2_ctrl *cptr) 6728c2ecf20Sopenharmony_ci{ 6738c2ecf20Sopenharmony_ci return cptr->hdw->input_dirty != 0; 6748c2ecf20Sopenharmony_ci} 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_cistatic void ctrl_cleardirty_input(struct pvr2_ctrl *cptr) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci cptr->hdw->input_dirty = 0; 6798c2ecf20Sopenharmony_ci} 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_cistatic int ctrl_freq_max_get(struct pvr2_ctrl *cptr, int *vp) 6838c2ecf20Sopenharmony_ci{ 6848c2ecf20Sopenharmony_ci unsigned long fv; 6858c2ecf20Sopenharmony_ci struct pvr2_hdw *hdw = cptr->hdw; 6868c2ecf20Sopenharmony_ci if (hdw->tuner_signal_stale) { 6878c2ecf20Sopenharmony_ci pvr2_hdw_status_poll(hdw); 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci fv = hdw->tuner_signal_info.rangehigh; 6908c2ecf20Sopenharmony_ci if (!fv) { 6918c2ecf20Sopenharmony_ci /* Safety fallback */ 6928c2ecf20Sopenharmony_ci *vp = TV_MAX_FREQ; 6938c2ecf20Sopenharmony_ci return 0; 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) { 6968c2ecf20Sopenharmony_ci fv = (fv * 125) / 2; 6978c2ecf20Sopenharmony_ci } else { 6988c2ecf20Sopenharmony_ci fv = fv * 62500; 6998c2ecf20Sopenharmony_ci } 7008c2ecf20Sopenharmony_ci *vp = fv; 7018c2ecf20Sopenharmony_ci return 0; 7028c2ecf20Sopenharmony_ci} 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_cistatic int ctrl_freq_min_get(struct pvr2_ctrl *cptr, int *vp) 7058c2ecf20Sopenharmony_ci{ 7068c2ecf20Sopenharmony_ci unsigned long fv; 7078c2ecf20Sopenharmony_ci struct pvr2_hdw *hdw = cptr->hdw; 7088c2ecf20Sopenharmony_ci if (hdw->tuner_signal_stale) { 7098c2ecf20Sopenharmony_ci pvr2_hdw_status_poll(hdw); 7108c2ecf20Sopenharmony_ci } 7118c2ecf20Sopenharmony_ci fv = hdw->tuner_signal_info.rangelow; 7128c2ecf20Sopenharmony_ci if (!fv) { 7138c2ecf20Sopenharmony_ci /* Safety fallback */ 7148c2ecf20Sopenharmony_ci *vp = TV_MIN_FREQ; 7158c2ecf20Sopenharmony_ci return 0; 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) { 7188c2ecf20Sopenharmony_ci fv = (fv * 125) / 2; 7198c2ecf20Sopenharmony_ci } else { 7208c2ecf20Sopenharmony_ci fv = fv * 62500; 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci *vp = fv; 7238c2ecf20Sopenharmony_ci return 0; 7248c2ecf20Sopenharmony_ci} 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_cistatic int ctrl_cx2341x_is_dirty(struct pvr2_ctrl *cptr) 7278c2ecf20Sopenharmony_ci{ 7288c2ecf20Sopenharmony_ci return cptr->hdw->enc_stale != 0; 7298c2ecf20Sopenharmony_ci} 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_cistatic void ctrl_cx2341x_clear_dirty(struct pvr2_ctrl *cptr) 7328c2ecf20Sopenharmony_ci{ 7338c2ecf20Sopenharmony_ci cptr->hdw->enc_stale = 0; 7348c2ecf20Sopenharmony_ci cptr->hdw->enc_unsafe_stale = 0; 7358c2ecf20Sopenharmony_ci} 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_cistatic int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp) 7388c2ecf20Sopenharmony_ci{ 7398c2ecf20Sopenharmony_ci int ret; 7408c2ecf20Sopenharmony_ci struct v4l2_ext_controls cs; 7418c2ecf20Sopenharmony_ci struct v4l2_ext_control c1; 7428c2ecf20Sopenharmony_ci memset(&cs,0,sizeof(cs)); 7438c2ecf20Sopenharmony_ci memset(&c1,0,sizeof(c1)); 7448c2ecf20Sopenharmony_ci cs.controls = &c1; 7458c2ecf20Sopenharmony_ci cs.count = 1; 7468c2ecf20Sopenharmony_ci c1.id = cptr->info->v4l_id; 7478c2ecf20Sopenharmony_ci ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state, 0, &cs, 7488c2ecf20Sopenharmony_ci VIDIOC_G_EXT_CTRLS); 7498c2ecf20Sopenharmony_ci if (ret) return ret; 7508c2ecf20Sopenharmony_ci *vp = c1.value; 7518c2ecf20Sopenharmony_ci return 0; 7528c2ecf20Sopenharmony_ci} 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_cistatic int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v) 7558c2ecf20Sopenharmony_ci{ 7568c2ecf20Sopenharmony_ci int ret; 7578c2ecf20Sopenharmony_ci struct pvr2_hdw *hdw = cptr->hdw; 7588c2ecf20Sopenharmony_ci struct v4l2_ext_controls cs; 7598c2ecf20Sopenharmony_ci struct v4l2_ext_control c1; 7608c2ecf20Sopenharmony_ci memset(&cs,0,sizeof(cs)); 7618c2ecf20Sopenharmony_ci memset(&c1,0,sizeof(c1)); 7628c2ecf20Sopenharmony_ci cs.controls = &c1; 7638c2ecf20Sopenharmony_ci cs.count = 1; 7648c2ecf20Sopenharmony_ci c1.id = cptr->info->v4l_id; 7658c2ecf20Sopenharmony_ci c1.value = v; 7668c2ecf20Sopenharmony_ci ret = cx2341x_ext_ctrls(&hdw->enc_ctl_state, 7678c2ecf20Sopenharmony_ci hdw->state_encoder_run, &cs, 7688c2ecf20Sopenharmony_ci VIDIOC_S_EXT_CTRLS); 7698c2ecf20Sopenharmony_ci if (ret == -EBUSY) { 7708c2ecf20Sopenharmony_ci /* Oops. cx2341x is telling us it's not safe to change 7718c2ecf20Sopenharmony_ci this control while we're capturing. Make a note of this 7728c2ecf20Sopenharmony_ci fact so that the pipeline will be stopped the next time 7738c2ecf20Sopenharmony_ci controls are committed. Then go on ahead and store this 7748c2ecf20Sopenharmony_ci change anyway. */ 7758c2ecf20Sopenharmony_ci ret = cx2341x_ext_ctrls(&hdw->enc_ctl_state, 7768c2ecf20Sopenharmony_ci 0, &cs, 7778c2ecf20Sopenharmony_ci VIDIOC_S_EXT_CTRLS); 7788c2ecf20Sopenharmony_ci if (!ret) hdw->enc_unsafe_stale = !0; 7798c2ecf20Sopenharmony_ci } 7808c2ecf20Sopenharmony_ci if (ret) return ret; 7818c2ecf20Sopenharmony_ci hdw->enc_stale = !0; 7828c2ecf20Sopenharmony_ci return 0; 7838c2ecf20Sopenharmony_ci} 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_cistatic unsigned int ctrl_cx2341x_getv4lflags(struct pvr2_ctrl *cptr) 7868c2ecf20Sopenharmony_ci{ 7878c2ecf20Sopenharmony_ci struct v4l2_queryctrl qctrl = {}; 7888c2ecf20Sopenharmony_ci struct pvr2_ctl_info *info; 7898c2ecf20Sopenharmony_ci qctrl.id = cptr->info->v4l_id; 7908c2ecf20Sopenharmony_ci cx2341x_ctrl_query(&cptr->hdw->enc_ctl_state,&qctrl); 7918c2ecf20Sopenharmony_ci /* Strip out the const so we can adjust a function pointer. It's 7928c2ecf20Sopenharmony_ci OK to do this here because we know this is a dynamically created 7938c2ecf20Sopenharmony_ci control, so the underlying storage for the info pointer is (a) 7948c2ecf20Sopenharmony_ci private to us, and (b) not in read-only storage. Either we do 7958c2ecf20Sopenharmony_ci this or we significantly complicate the underlying control 7968c2ecf20Sopenharmony_ci implementation. */ 7978c2ecf20Sopenharmony_ci info = (struct pvr2_ctl_info *)(cptr->info); 7988c2ecf20Sopenharmony_ci if (qctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) { 7998c2ecf20Sopenharmony_ci if (info->set_value) { 8008c2ecf20Sopenharmony_ci info->set_value = NULL; 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci } else { 8038c2ecf20Sopenharmony_ci if (!(info->set_value)) { 8048c2ecf20Sopenharmony_ci info->set_value = ctrl_cx2341x_set; 8058c2ecf20Sopenharmony_ci } 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci return qctrl.flags; 8088c2ecf20Sopenharmony_ci} 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_cistatic int ctrl_streamingenabled_get(struct pvr2_ctrl *cptr,int *vp) 8118c2ecf20Sopenharmony_ci{ 8128c2ecf20Sopenharmony_ci *vp = cptr->hdw->state_pipeline_req; 8138c2ecf20Sopenharmony_ci return 0; 8148c2ecf20Sopenharmony_ci} 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_cistatic int ctrl_masterstate_get(struct pvr2_ctrl *cptr,int *vp) 8178c2ecf20Sopenharmony_ci{ 8188c2ecf20Sopenharmony_ci *vp = cptr->hdw->master_state; 8198c2ecf20Sopenharmony_ci return 0; 8208c2ecf20Sopenharmony_ci} 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_cistatic int ctrl_hsm_get(struct pvr2_ctrl *cptr,int *vp) 8238c2ecf20Sopenharmony_ci{ 8248c2ecf20Sopenharmony_ci int result = pvr2_hdw_is_hsm(cptr->hdw); 8258c2ecf20Sopenharmony_ci *vp = PVR2_CVAL_HSM_FULL; 8268c2ecf20Sopenharmony_ci if (result < 0) *vp = PVR2_CVAL_HSM_FAIL; 8278c2ecf20Sopenharmony_ci if (result) *vp = PVR2_CVAL_HSM_HIGH; 8288c2ecf20Sopenharmony_ci return 0; 8298c2ecf20Sopenharmony_ci} 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_cistatic int ctrl_stddetect_get(struct pvr2_ctrl *cptr, int *vp) 8328c2ecf20Sopenharmony_ci{ 8338c2ecf20Sopenharmony_ci *vp = pvr2_hdw_get_detected_std(cptr->hdw); 8348c2ecf20Sopenharmony_ci return 0; 8358c2ecf20Sopenharmony_ci} 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_cistatic int ctrl_stdavail_get(struct pvr2_ctrl *cptr,int *vp) 8388c2ecf20Sopenharmony_ci{ 8398c2ecf20Sopenharmony_ci *vp = cptr->hdw->std_mask_avail; 8408c2ecf20Sopenharmony_ci return 0; 8418c2ecf20Sopenharmony_ci} 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_cistatic int ctrl_stdavail_set(struct pvr2_ctrl *cptr,int m,int v) 8448c2ecf20Sopenharmony_ci{ 8458c2ecf20Sopenharmony_ci struct pvr2_hdw *hdw = cptr->hdw; 8468c2ecf20Sopenharmony_ci v4l2_std_id ns; 8478c2ecf20Sopenharmony_ci ns = hdw->std_mask_avail; 8488c2ecf20Sopenharmony_ci ns = (ns & ~m) | (v & m); 8498c2ecf20Sopenharmony_ci if (ns == hdw->std_mask_avail) return 0; 8508c2ecf20Sopenharmony_ci hdw->std_mask_avail = ns; 8518c2ecf20Sopenharmony_ci hdw->std_info_cur.def.type_bitmask.valid_bits = hdw->std_mask_avail; 8528c2ecf20Sopenharmony_ci return 0; 8538c2ecf20Sopenharmony_ci} 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_cistatic int ctrl_std_val_to_sym(struct pvr2_ctrl *cptr,int msk,int val, 8568c2ecf20Sopenharmony_ci char *bufPtr,unsigned int bufSize, 8578c2ecf20Sopenharmony_ci unsigned int *len) 8588c2ecf20Sopenharmony_ci{ 8598c2ecf20Sopenharmony_ci *len = pvr2_std_id_to_str(bufPtr,bufSize,msk & val); 8608c2ecf20Sopenharmony_ci return 0; 8618c2ecf20Sopenharmony_ci} 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_cistatic int ctrl_std_sym_to_val(struct pvr2_ctrl *cptr, 8648c2ecf20Sopenharmony_ci const char *bufPtr,unsigned int bufSize, 8658c2ecf20Sopenharmony_ci int *mskp,int *valp) 8668c2ecf20Sopenharmony_ci{ 8678c2ecf20Sopenharmony_ci v4l2_std_id id; 8688c2ecf20Sopenharmony_ci if (!pvr2_std_str_to_id(&id, bufPtr, bufSize)) 8698c2ecf20Sopenharmony_ci return -EINVAL; 8708c2ecf20Sopenharmony_ci if (mskp) *mskp = id; 8718c2ecf20Sopenharmony_ci if (valp) *valp = id; 8728c2ecf20Sopenharmony_ci return 0; 8738c2ecf20Sopenharmony_ci} 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_cistatic int ctrl_stdcur_get(struct pvr2_ctrl *cptr,int *vp) 8768c2ecf20Sopenharmony_ci{ 8778c2ecf20Sopenharmony_ci *vp = cptr->hdw->std_mask_cur; 8788c2ecf20Sopenharmony_ci return 0; 8798c2ecf20Sopenharmony_ci} 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_cistatic int ctrl_stdcur_set(struct pvr2_ctrl *cptr,int m,int v) 8828c2ecf20Sopenharmony_ci{ 8838c2ecf20Sopenharmony_ci struct pvr2_hdw *hdw = cptr->hdw; 8848c2ecf20Sopenharmony_ci v4l2_std_id ns; 8858c2ecf20Sopenharmony_ci ns = hdw->std_mask_cur; 8868c2ecf20Sopenharmony_ci ns = (ns & ~m) | (v & m); 8878c2ecf20Sopenharmony_ci if (ns == hdw->std_mask_cur) return 0; 8888c2ecf20Sopenharmony_ci hdw->std_mask_cur = ns; 8898c2ecf20Sopenharmony_ci hdw->std_dirty = !0; 8908c2ecf20Sopenharmony_ci return 0; 8918c2ecf20Sopenharmony_ci} 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_cistatic int ctrl_stdcur_is_dirty(struct pvr2_ctrl *cptr) 8948c2ecf20Sopenharmony_ci{ 8958c2ecf20Sopenharmony_ci return cptr->hdw->std_dirty != 0; 8968c2ecf20Sopenharmony_ci} 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_cistatic void ctrl_stdcur_clear_dirty(struct pvr2_ctrl *cptr) 8998c2ecf20Sopenharmony_ci{ 9008c2ecf20Sopenharmony_ci cptr->hdw->std_dirty = 0; 9018c2ecf20Sopenharmony_ci} 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_cistatic int ctrl_signal_get(struct pvr2_ctrl *cptr,int *vp) 9048c2ecf20Sopenharmony_ci{ 9058c2ecf20Sopenharmony_ci struct pvr2_hdw *hdw = cptr->hdw; 9068c2ecf20Sopenharmony_ci pvr2_hdw_status_poll(hdw); 9078c2ecf20Sopenharmony_ci *vp = hdw->tuner_signal_info.signal; 9088c2ecf20Sopenharmony_ci return 0; 9098c2ecf20Sopenharmony_ci} 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_cistatic int ctrl_audio_modes_present_get(struct pvr2_ctrl *cptr,int *vp) 9128c2ecf20Sopenharmony_ci{ 9138c2ecf20Sopenharmony_ci int val = 0; 9148c2ecf20Sopenharmony_ci unsigned int subchan; 9158c2ecf20Sopenharmony_ci struct pvr2_hdw *hdw = cptr->hdw; 9168c2ecf20Sopenharmony_ci pvr2_hdw_status_poll(hdw); 9178c2ecf20Sopenharmony_ci subchan = hdw->tuner_signal_info.rxsubchans; 9188c2ecf20Sopenharmony_ci if (subchan & V4L2_TUNER_SUB_MONO) { 9198c2ecf20Sopenharmony_ci val |= (1 << V4L2_TUNER_MODE_MONO); 9208c2ecf20Sopenharmony_ci } 9218c2ecf20Sopenharmony_ci if (subchan & V4L2_TUNER_SUB_STEREO) { 9228c2ecf20Sopenharmony_ci val |= (1 << V4L2_TUNER_MODE_STEREO); 9238c2ecf20Sopenharmony_ci } 9248c2ecf20Sopenharmony_ci if (subchan & V4L2_TUNER_SUB_LANG1) { 9258c2ecf20Sopenharmony_ci val |= (1 << V4L2_TUNER_MODE_LANG1); 9268c2ecf20Sopenharmony_ci } 9278c2ecf20Sopenharmony_ci if (subchan & V4L2_TUNER_SUB_LANG2) { 9288c2ecf20Sopenharmony_ci val |= (1 << V4L2_TUNER_MODE_LANG2); 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci *vp = val; 9318c2ecf20Sopenharmony_ci return 0; 9328c2ecf20Sopenharmony_ci} 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci#define DEFINT(vmin,vmax) \ 9368c2ecf20Sopenharmony_ci .type = pvr2_ctl_int, \ 9378c2ecf20Sopenharmony_ci .def.type_int.min_value = vmin, \ 9388c2ecf20Sopenharmony_ci .def.type_int.max_value = vmax 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci#define DEFENUM(tab) \ 9418c2ecf20Sopenharmony_ci .type = pvr2_ctl_enum, \ 9428c2ecf20Sopenharmony_ci .def.type_enum.count = ARRAY_SIZE(tab), \ 9438c2ecf20Sopenharmony_ci .def.type_enum.value_names = tab 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci#define DEFBOOL \ 9468c2ecf20Sopenharmony_ci .type = pvr2_ctl_bool 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci#define DEFMASK(msk,tab) \ 9498c2ecf20Sopenharmony_ci .type = pvr2_ctl_bitmask, \ 9508c2ecf20Sopenharmony_ci .def.type_bitmask.valid_bits = msk, \ 9518c2ecf20Sopenharmony_ci .def.type_bitmask.bit_names = tab 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci#define DEFREF(vname) \ 9548c2ecf20Sopenharmony_ci .set_value = ctrl_set_##vname, \ 9558c2ecf20Sopenharmony_ci .get_value = ctrl_get_##vname, \ 9568c2ecf20Sopenharmony_ci .is_dirty = ctrl_isdirty_##vname, \ 9578c2ecf20Sopenharmony_ci .clear_dirty = ctrl_cleardirty_##vname 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci#define VCREATE_FUNCS(vname) \ 9618c2ecf20Sopenharmony_cistatic int ctrl_get_##vname(struct pvr2_ctrl *cptr,int *vp) \ 9628c2ecf20Sopenharmony_ci{*vp = cptr->hdw->vname##_val; return 0;} \ 9638c2ecf20Sopenharmony_cistatic int ctrl_set_##vname(struct pvr2_ctrl *cptr,int m,int v) \ 9648c2ecf20Sopenharmony_ci{cptr->hdw->vname##_val = v; cptr->hdw->vname##_dirty = !0; return 0;} \ 9658c2ecf20Sopenharmony_cistatic int ctrl_isdirty_##vname(struct pvr2_ctrl *cptr) \ 9668c2ecf20Sopenharmony_ci{return cptr->hdw->vname##_dirty != 0;} \ 9678c2ecf20Sopenharmony_cistatic void ctrl_cleardirty_##vname(struct pvr2_ctrl *cptr) \ 9688c2ecf20Sopenharmony_ci{cptr->hdw->vname##_dirty = 0;} 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ciVCREATE_FUNCS(brightness) 9718c2ecf20Sopenharmony_ciVCREATE_FUNCS(contrast) 9728c2ecf20Sopenharmony_ciVCREATE_FUNCS(saturation) 9738c2ecf20Sopenharmony_ciVCREATE_FUNCS(hue) 9748c2ecf20Sopenharmony_ciVCREATE_FUNCS(volume) 9758c2ecf20Sopenharmony_ciVCREATE_FUNCS(balance) 9768c2ecf20Sopenharmony_ciVCREATE_FUNCS(bass) 9778c2ecf20Sopenharmony_ciVCREATE_FUNCS(treble) 9788c2ecf20Sopenharmony_ciVCREATE_FUNCS(mute) 9798c2ecf20Sopenharmony_ciVCREATE_FUNCS(cropl) 9808c2ecf20Sopenharmony_ciVCREATE_FUNCS(cropt) 9818c2ecf20Sopenharmony_ciVCREATE_FUNCS(cropw) 9828c2ecf20Sopenharmony_ciVCREATE_FUNCS(croph) 9838c2ecf20Sopenharmony_ciVCREATE_FUNCS(audiomode) 9848c2ecf20Sopenharmony_ciVCREATE_FUNCS(res_hor) 9858c2ecf20Sopenharmony_ciVCREATE_FUNCS(res_ver) 9868c2ecf20Sopenharmony_ciVCREATE_FUNCS(srate) 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci/* Table definition of all controls which can be manipulated */ 9898c2ecf20Sopenharmony_cistatic const struct pvr2_ctl_info control_defs[] = { 9908c2ecf20Sopenharmony_ci { 9918c2ecf20Sopenharmony_ci .v4l_id = V4L2_CID_BRIGHTNESS, 9928c2ecf20Sopenharmony_ci .desc = "Brightness", 9938c2ecf20Sopenharmony_ci .name = "brightness", 9948c2ecf20Sopenharmony_ci .default_value = 128, 9958c2ecf20Sopenharmony_ci DEFREF(brightness), 9968c2ecf20Sopenharmony_ci DEFINT(0,255), 9978c2ecf20Sopenharmony_ci },{ 9988c2ecf20Sopenharmony_ci .v4l_id = V4L2_CID_CONTRAST, 9998c2ecf20Sopenharmony_ci .desc = "Contrast", 10008c2ecf20Sopenharmony_ci .name = "contrast", 10018c2ecf20Sopenharmony_ci .default_value = 68, 10028c2ecf20Sopenharmony_ci DEFREF(contrast), 10038c2ecf20Sopenharmony_ci DEFINT(0,127), 10048c2ecf20Sopenharmony_ci },{ 10058c2ecf20Sopenharmony_ci .v4l_id = V4L2_CID_SATURATION, 10068c2ecf20Sopenharmony_ci .desc = "Saturation", 10078c2ecf20Sopenharmony_ci .name = "saturation", 10088c2ecf20Sopenharmony_ci .default_value = 64, 10098c2ecf20Sopenharmony_ci DEFREF(saturation), 10108c2ecf20Sopenharmony_ci DEFINT(0,127), 10118c2ecf20Sopenharmony_ci },{ 10128c2ecf20Sopenharmony_ci .v4l_id = V4L2_CID_HUE, 10138c2ecf20Sopenharmony_ci .desc = "Hue", 10148c2ecf20Sopenharmony_ci .name = "hue", 10158c2ecf20Sopenharmony_ci .default_value = 0, 10168c2ecf20Sopenharmony_ci DEFREF(hue), 10178c2ecf20Sopenharmony_ci DEFINT(-128,127), 10188c2ecf20Sopenharmony_ci },{ 10198c2ecf20Sopenharmony_ci .v4l_id = V4L2_CID_AUDIO_VOLUME, 10208c2ecf20Sopenharmony_ci .desc = "Volume", 10218c2ecf20Sopenharmony_ci .name = "volume", 10228c2ecf20Sopenharmony_ci .default_value = 62000, 10238c2ecf20Sopenharmony_ci DEFREF(volume), 10248c2ecf20Sopenharmony_ci DEFINT(0,65535), 10258c2ecf20Sopenharmony_ci },{ 10268c2ecf20Sopenharmony_ci .v4l_id = V4L2_CID_AUDIO_BALANCE, 10278c2ecf20Sopenharmony_ci .desc = "Balance", 10288c2ecf20Sopenharmony_ci .name = "balance", 10298c2ecf20Sopenharmony_ci .default_value = 0, 10308c2ecf20Sopenharmony_ci DEFREF(balance), 10318c2ecf20Sopenharmony_ci DEFINT(-32768,32767), 10328c2ecf20Sopenharmony_ci },{ 10338c2ecf20Sopenharmony_ci .v4l_id = V4L2_CID_AUDIO_BASS, 10348c2ecf20Sopenharmony_ci .desc = "Bass", 10358c2ecf20Sopenharmony_ci .name = "bass", 10368c2ecf20Sopenharmony_ci .default_value = 0, 10378c2ecf20Sopenharmony_ci DEFREF(bass), 10388c2ecf20Sopenharmony_ci DEFINT(-32768,32767), 10398c2ecf20Sopenharmony_ci },{ 10408c2ecf20Sopenharmony_ci .v4l_id = V4L2_CID_AUDIO_TREBLE, 10418c2ecf20Sopenharmony_ci .desc = "Treble", 10428c2ecf20Sopenharmony_ci .name = "treble", 10438c2ecf20Sopenharmony_ci .default_value = 0, 10448c2ecf20Sopenharmony_ci DEFREF(treble), 10458c2ecf20Sopenharmony_ci DEFINT(-32768,32767), 10468c2ecf20Sopenharmony_ci },{ 10478c2ecf20Sopenharmony_ci .v4l_id = V4L2_CID_AUDIO_MUTE, 10488c2ecf20Sopenharmony_ci .desc = "Mute", 10498c2ecf20Sopenharmony_ci .name = "mute", 10508c2ecf20Sopenharmony_ci .default_value = 0, 10518c2ecf20Sopenharmony_ci DEFREF(mute), 10528c2ecf20Sopenharmony_ci DEFBOOL, 10538c2ecf20Sopenharmony_ci }, { 10548c2ecf20Sopenharmony_ci .desc = "Capture crop left margin", 10558c2ecf20Sopenharmony_ci .name = "crop_left", 10568c2ecf20Sopenharmony_ci .internal_id = PVR2_CID_CROPL, 10578c2ecf20Sopenharmony_ci .default_value = 0, 10588c2ecf20Sopenharmony_ci DEFREF(cropl), 10598c2ecf20Sopenharmony_ci DEFINT(-129, 340), 10608c2ecf20Sopenharmony_ci .get_min_value = ctrl_cropl_min_get, 10618c2ecf20Sopenharmony_ci .get_max_value = ctrl_cropl_max_get, 10628c2ecf20Sopenharmony_ci .get_def_value = ctrl_get_cropcapdl, 10638c2ecf20Sopenharmony_ci }, { 10648c2ecf20Sopenharmony_ci .desc = "Capture crop top margin", 10658c2ecf20Sopenharmony_ci .name = "crop_top", 10668c2ecf20Sopenharmony_ci .internal_id = PVR2_CID_CROPT, 10678c2ecf20Sopenharmony_ci .default_value = 0, 10688c2ecf20Sopenharmony_ci DEFREF(cropt), 10698c2ecf20Sopenharmony_ci DEFINT(-35, 544), 10708c2ecf20Sopenharmony_ci .get_min_value = ctrl_cropt_min_get, 10718c2ecf20Sopenharmony_ci .get_max_value = ctrl_cropt_max_get, 10728c2ecf20Sopenharmony_ci .get_def_value = ctrl_get_cropcapdt, 10738c2ecf20Sopenharmony_ci }, { 10748c2ecf20Sopenharmony_ci .desc = "Capture crop width", 10758c2ecf20Sopenharmony_ci .name = "crop_width", 10768c2ecf20Sopenharmony_ci .internal_id = PVR2_CID_CROPW, 10778c2ecf20Sopenharmony_ci .default_value = 720, 10788c2ecf20Sopenharmony_ci DEFREF(cropw), 10798c2ecf20Sopenharmony_ci DEFINT(0, 864), 10808c2ecf20Sopenharmony_ci .get_max_value = ctrl_cropw_max_get, 10818c2ecf20Sopenharmony_ci .get_def_value = ctrl_get_cropcapdw, 10828c2ecf20Sopenharmony_ci }, { 10838c2ecf20Sopenharmony_ci .desc = "Capture crop height", 10848c2ecf20Sopenharmony_ci .name = "crop_height", 10858c2ecf20Sopenharmony_ci .internal_id = PVR2_CID_CROPH, 10868c2ecf20Sopenharmony_ci .default_value = 480, 10878c2ecf20Sopenharmony_ci DEFREF(croph), 10888c2ecf20Sopenharmony_ci DEFINT(0, 576), 10898c2ecf20Sopenharmony_ci .get_max_value = ctrl_croph_max_get, 10908c2ecf20Sopenharmony_ci .get_def_value = ctrl_get_cropcapdh, 10918c2ecf20Sopenharmony_ci }, { 10928c2ecf20Sopenharmony_ci .desc = "Capture capability pixel aspect numerator", 10938c2ecf20Sopenharmony_ci .name = "cropcap_pixel_numerator", 10948c2ecf20Sopenharmony_ci .internal_id = PVR2_CID_CROPCAPPAN, 10958c2ecf20Sopenharmony_ci .get_value = ctrl_get_cropcappan, 10968c2ecf20Sopenharmony_ci }, { 10978c2ecf20Sopenharmony_ci .desc = "Capture capability pixel aspect denominator", 10988c2ecf20Sopenharmony_ci .name = "cropcap_pixel_denominator", 10998c2ecf20Sopenharmony_ci .internal_id = PVR2_CID_CROPCAPPAD, 11008c2ecf20Sopenharmony_ci .get_value = ctrl_get_cropcappad, 11018c2ecf20Sopenharmony_ci }, { 11028c2ecf20Sopenharmony_ci .desc = "Capture capability bounds top", 11038c2ecf20Sopenharmony_ci .name = "cropcap_bounds_top", 11048c2ecf20Sopenharmony_ci .internal_id = PVR2_CID_CROPCAPBT, 11058c2ecf20Sopenharmony_ci .get_value = ctrl_get_cropcapbt, 11068c2ecf20Sopenharmony_ci }, { 11078c2ecf20Sopenharmony_ci .desc = "Capture capability bounds left", 11088c2ecf20Sopenharmony_ci .name = "cropcap_bounds_left", 11098c2ecf20Sopenharmony_ci .internal_id = PVR2_CID_CROPCAPBL, 11108c2ecf20Sopenharmony_ci .get_value = ctrl_get_cropcapbl, 11118c2ecf20Sopenharmony_ci }, { 11128c2ecf20Sopenharmony_ci .desc = "Capture capability bounds width", 11138c2ecf20Sopenharmony_ci .name = "cropcap_bounds_width", 11148c2ecf20Sopenharmony_ci .internal_id = PVR2_CID_CROPCAPBW, 11158c2ecf20Sopenharmony_ci .get_value = ctrl_get_cropcapbw, 11168c2ecf20Sopenharmony_ci }, { 11178c2ecf20Sopenharmony_ci .desc = "Capture capability bounds height", 11188c2ecf20Sopenharmony_ci .name = "cropcap_bounds_height", 11198c2ecf20Sopenharmony_ci .internal_id = PVR2_CID_CROPCAPBH, 11208c2ecf20Sopenharmony_ci .get_value = ctrl_get_cropcapbh, 11218c2ecf20Sopenharmony_ci },{ 11228c2ecf20Sopenharmony_ci .desc = "Video Source", 11238c2ecf20Sopenharmony_ci .name = "input", 11248c2ecf20Sopenharmony_ci .internal_id = PVR2_CID_INPUT, 11258c2ecf20Sopenharmony_ci .default_value = PVR2_CVAL_INPUT_TV, 11268c2ecf20Sopenharmony_ci .check_value = ctrl_check_input, 11278c2ecf20Sopenharmony_ci DEFREF(input), 11288c2ecf20Sopenharmony_ci DEFENUM(control_values_input), 11298c2ecf20Sopenharmony_ci },{ 11308c2ecf20Sopenharmony_ci .desc = "Audio Mode", 11318c2ecf20Sopenharmony_ci .name = "audio_mode", 11328c2ecf20Sopenharmony_ci .internal_id = PVR2_CID_AUDIOMODE, 11338c2ecf20Sopenharmony_ci .default_value = V4L2_TUNER_MODE_STEREO, 11348c2ecf20Sopenharmony_ci DEFREF(audiomode), 11358c2ecf20Sopenharmony_ci DEFENUM(control_values_audiomode), 11368c2ecf20Sopenharmony_ci },{ 11378c2ecf20Sopenharmony_ci .desc = "Horizontal capture resolution", 11388c2ecf20Sopenharmony_ci .name = "resolution_hor", 11398c2ecf20Sopenharmony_ci .internal_id = PVR2_CID_HRES, 11408c2ecf20Sopenharmony_ci .default_value = 720, 11418c2ecf20Sopenharmony_ci DEFREF(res_hor), 11428c2ecf20Sopenharmony_ci DEFINT(19,720), 11438c2ecf20Sopenharmony_ci },{ 11448c2ecf20Sopenharmony_ci .desc = "Vertical capture resolution", 11458c2ecf20Sopenharmony_ci .name = "resolution_ver", 11468c2ecf20Sopenharmony_ci .internal_id = PVR2_CID_VRES, 11478c2ecf20Sopenharmony_ci .default_value = 480, 11488c2ecf20Sopenharmony_ci DEFREF(res_ver), 11498c2ecf20Sopenharmony_ci DEFINT(17,576), 11508c2ecf20Sopenharmony_ci /* Hook in check for video standard and adjust maximum 11518c2ecf20Sopenharmony_ci depending on the standard. */ 11528c2ecf20Sopenharmony_ci .get_max_value = ctrl_vres_max_get, 11538c2ecf20Sopenharmony_ci .get_min_value = ctrl_vres_min_get, 11548c2ecf20Sopenharmony_ci },{ 11558c2ecf20Sopenharmony_ci .v4l_id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ, 11568c2ecf20Sopenharmony_ci .default_value = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, 11578c2ecf20Sopenharmony_ci .desc = "Audio Sampling Frequency", 11588c2ecf20Sopenharmony_ci .name = "srate", 11598c2ecf20Sopenharmony_ci DEFREF(srate), 11608c2ecf20Sopenharmony_ci DEFENUM(control_values_srate), 11618c2ecf20Sopenharmony_ci },{ 11628c2ecf20Sopenharmony_ci .desc = "Tuner Frequency (Hz)", 11638c2ecf20Sopenharmony_ci .name = "frequency", 11648c2ecf20Sopenharmony_ci .internal_id = PVR2_CID_FREQUENCY, 11658c2ecf20Sopenharmony_ci .default_value = 0, 11668c2ecf20Sopenharmony_ci .set_value = ctrl_freq_set, 11678c2ecf20Sopenharmony_ci .get_value = ctrl_freq_get, 11688c2ecf20Sopenharmony_ci .is_dirty = ctrl_freq_is_dirty, 11698c2ecf20Sopenharmony_ci .clear_dirty = ctrl_freq_clear_dirty, 11708c2ecf20Sopenharmony_ci DEFINT(0,0), 11718c2ecf20Sopenharmony_ci /* Hook in check for input value (tv/radio) and adjust 11728c2ecf20Sopenharmony_ci max/min values accordingly */ 11738c2ecf20Sopenharmony_ci .get_max_value = ctrl_freq_max_get, 11748c2ecf20Sopenharmony_ci .get_min_value = ctrl_freq_min_get, 11758c2ecf20Sopenharmony_ci },{ 11768c2ecf20Sopenharmony_ci .desc = "Channel", 11778c2ecf20Sopenharmony_ci .name = "channel", 11788c2ecf20Sopenharmony_ci .set_value = ctrl_channel_set, 11798c2ecf20Sopenharmony_ci .get_value = ctrl_channel_get, 11808c2ecf20Sopenharmony_ci DEFINT(0,FREQTABLE_SIZE), 11818c2ecf20Sopenharmony_ci },{ 11828c2ecf20Sopenharmony_ci .desc = "Channel Program Frequency", 11838c2ecf20Sopenharmony_ci .name = "freq_table_value", 11848c2ecf20Sopenharmony_ci .set_value = ctrl_channelfreq_set, 11858c2ecf20Sopenharmony_ci .get_value = ctrl_channelfreq_get, 11868c2ecf20Sopenharmony_ci DEFINT(0,0), 11878c2ecf20Sopenharmony_ci /* Hook in check for input value (tv/radio) and adjust 11888c2ecf20Sopenharmony_ci max/min values accordingly */ 11898c2ecf20Sopenharmony_ci .get_max_value = ctrl_freq_max_get, 11908c2ecf20Sopenharmony_ci .get_min_value = ctrl_freq_min_get, 11918c2ecf20Sopenharmony_ci },{ 11928c2ecf20Sopenharmony_ci .desc = "Channel Program ID", 11938c2ecf20Sopenharmony_ci .name = "freq_table_channel", 11948c2ecf20Sopenharmony_ci .set_value = ctrl_channelprog_set, 11958c2ecf20Sopenharmony_ci .get_value = ctrl_channelprog_get, 11968c2ecf20Sopenharmony_ci DEFINT(0,FREQTABLE_SIZE), 11978c2ecf20Sopenharmony_ci },{ 11988c2ecf20Sopenharmony_ci .desc = "Streaming Enabled", 11998c2ecf20Sopenharmony_ci .name = "streaming_enabled", 12008c2ecf20Sopenharmony_ci .get_value = ctrl_streamingenabled_get, 12018c2ecf20Sopenharmony_ci DEFBOOL, 12028c2ecf20Sopenharmony_ci },{ 12038c2ecf20Sopenharmony_ci .desc = "USB Speed", 12048c2ecf20Sopenharmony_ci .name = "usb_speed", 12058c2ecf20Sopenharmony_ci .get_value = ctrl_hsm_get, 12068c2ecf20Sopenharmony_ci DEFENUM(control_values_hsm), 12078c2ecf20Sopenharmony_ci },{ 12088c2ecf20Sopenharmony_ci .desc = "Master State", 12098c2ecf20Sopenharmony_ci .name = "master_state", 12108c2ecf20Sopenharmony_ci .get_value = ctrl_masterstate_get, 12118c2ecf20Sopenharmony_ci DEFENUM(pvr2_state_names), 12128c2ecf20Sopenharmony_ci },{ 12138c2ecf20Sopenharmony_ci .desc = "Signal Present", 12148c2ecf20Sopenharmony_ci .name = "signal_present", 12158c2ecf20Sopenharmony_ci .get_value = ctrl_signal_get, 12168c2ecf20Sopenharmony_ci DEFINT(0,65535), 12178c2ecf20Sopenharmony_ci },{ 12188c2ecf20Sopenharmony_ci .desc = "Audio Modes Present", 12198c2ecf20Sopenharmony_ci .name = "audio_modes_present", 12208c2ecf20Sopenharmony_ci .get_value = ctrl_audio_modes_present_get, 12218c2ecf20Sopenharmony_ci /* For this type we "borrow" the V4L2_TUNER_MODE enum from 12228c2ecf20Sopenharmony_ci v4l. Nothing outside of this module cares about this, 12238c2ecf20Sopenharmony_ci but I reuse it in order to also reuse the 12248c2ecf20Sopenharmony_ci control_values_audiomode string table. */ 12258c2ecf20Sopenharmony_ci DEFMASK(((1 << V4L2_TUNER_MODE_MONO)| 12268c2ecf20Sopenharmony_ci (1 << V4L2_TUNER_MODE_STEREO)| 12278c2ecf20Sopenharmony_ci (1 << V4L2_TUNER_MODE_LANG1)| 12288c2ecf20Sopenharmony_ci (1 << V4L2_TUNER_MODE_LANG2)), 12298c2ecf20Sopenharmony_ci control_values_audiomode), 12308c2ecf20Sopenharmony_ci },{ 12318c2ecf20Sopenharmony_ci .desc = "Video Standards Available Mask", 12328c2ecf20Sopenharmony_ci .name = "video_standard_mask_available", 12338c2ecf20Sopenharmony_ci .internal_id = PVR2_CID_STDAVAIL, 12348c2ecf20Sopenharmony_ci .skip_init = !0, 12358c2ecf20Sopenharmony_ci .get_value = ctrl_stdavail_get, 12368c2ecf20Sopenharmony_ci .set_value = ctrl_stdavail_set, 12378c2ecf20Sopenharmony_ci .val_to_sym = ctrl_std_val_to_sym, 12388c2ecf20Sopenharmony_ci .sym_to_val = ctrl_std_sym_to_val, 12398c2ecf20Sopenharmony_ci .type = pvr2_ctl_bitmask, 12408c2ecf20Sopenharmony_ci },{ 12418c2ecf20Sopenharmony_ci .desc = "Video Standards In Use Mask", 12428c2ecf20Sopenharmony_ci .name = "video_standard_mask_active", 12438c2ecf20Sopenharmony_ci .internal_id = PVR2_CID_STDCUR, 12448c2ecf20Sopenharmony_ci .skip_init = !0, 12458c2ecf20Sopenharmony_ci .get_value = ctrl_stdcur_get, 12468c2ecf20Sopenharmony_ci .set_value = ctrl_stdcur_set, 12478c2ecf20Sopenharmony_ci .is_dirty = ctrl_stdcur_is_dirty, 12488c2ecf20Sopenharmony_ci .clear_dirty = ctrl_stdcur_clear_dirty, 12498c2ecf20Sopenharmony_ci .val_to_sym = ctrl_std_val_to_sym, 12508c2ecf20Sopenharmony_ci .sym_to_val = ctrl_std_sym_to_val, 12518c2ecf20Sopenharmony_ci .type = pvr2_ctl_bitmask, 12528c2ecf20Sopenharmony_ci },{ 12538c2ecf20Sopenharmony_ci .desc = "Video Standards Detected Mask", 12548c2ecf20Sopenharmony_ci .name = "video_standard_mask_detected", 12558c2ecf20Sopenharmony_ci .internal_id = PVR2_CID_STDDETECT, 12568c2ecf20Sopenharmony_ci .skip_init = !0, 12578c2ecf20Sopenharmony_ci .get_value = ctrl_stddetect_get, 12588c2ecf20Sopenharmony_ci .val_to_sym = ctrl_std_val_to_sym, 12598c2ecf20Sopenharmony_ci .sym_to_val = ctrl_std_sym_to_val, 12608c2ecf20Sopenharmony_ci .type = pvr2_ctl_bitmask, 12618c2ecf20Sopenharmony_ci } 12628c2ecf20Sopenharmony_ci}; 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci#define CTRLDEF_COUNT ARRAY_SIZE(control_defs) 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ciconst char *pvr2_config_get_name(enum pvr2_config cfg) 12688c2ecf20Sopenharmony_ci{ 12698c2ecf20Sopenharmony_ci switch (cfg) { 12708c2ecf20Sopenharmony_ci case pvr2_config_empty: return "empty"; 12718c2ecf20Sopenharmony_ci case pvr2_config_mpeg: return "mpeg"; 12728c2ecf20Sopenharmony_ci case pvr2_config_vbi: return "vbi"; 12738c2ecf20Sopenharmony_ci case pvr2_config_pcm: return "pcm"; 12748c2ecf20Sopenharmony_ci case pvr2_config_rawvideo: return "raw video"; 12758c2ecf20Sopenharmony_ci } 12768c2ecf20Sopenharmony_ci return "<unknown>"; 12778c2ecf20Sopenharmony_ci} 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_cistruct usb_device *pvr2_hdw_get_dev(struct pvr2_hdw *hdw) 12818c2ecf20Sopenharmony_ci{ 12828c2ecf20Sopenharmony_ci return hdw->usb_dev; 12838c2ecf20Sopenharmony_ci} 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ciunsigned long pvr2_hdw_get_sn(struct pvr2_hdw *hdw) 12878c2ecf20Sopenharmony_ci{ 12888c2ecf20Sopenharmony_ci return hdw->serial_number; 12898c2ecf20Sopenharmony_ci} 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ciconst char *pvr2_hdw_get_bus_info(struct pvr2_hdw *hdw) 12938c2ecf20Sopenharmony_ci{ 12948c2ecf20Sopenharmony_ci return hdw->bus_info; 12958c2ecf20Sopenharmony_ci} 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ciconst char *pvr2_hdw_get_device_identifier(struct pvr2_hdw *hdw) 12998c2ecf20Sopenharmony_ci{ 13008c2ecf20Sopenharmony_ci return hdw->identifier; 13018c2ecf20Sopenharmony_ci} 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ciunsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *hdw) 13058c2ecf20Sopenharmony_ci{ 13068c2ecf20Sopenharmony_ci return hdw->freqSelector ? hdw->freqValTelevision : hdw->freqValRadio; 13078c2ecf20Sopenharmony_ci} 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci/* Set the currently tuned frequency and account for all possible 13108c2ecf20Sopenharmony_ci driver-core side effects of this action. */ 13118c2ecf20Sopenharmony_cistatic void pvr2_hdw_set_cur_freq(struct pvr2_hdw *hdw,unsigned long val) 13128c2ecf20Sopenharmony_ci{ 13138c2ecf20Sopenharmony_ci if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) { 13148c2ecf20Sopenharmony_ci if (hdw->freqSelector) { 13158c2ecf20Sopenharmony_ci /* Swing over to radio frequency selection */ 13168c2ecf20Sopenharmony_ci hdw->freqSelector = 0; 13178c2ecf20Sopenharmony_ci hdw->freqDirty = !0; 13188c2ecf20Sopenharmony_ci } 13198c2ecf20Sopenharmony_ci if (hdw->freqValRadio != val) { 13208c2ecf20Sopenharmony_ci hdw->freqValRadio = val; 13218c2ecf20Sopenharmony_ci hdw->freqSlotRadio = 0; 13228c2ecf20Sopenharmony_ci hdw->freqDirty = !0; 13238c2ecf20Sopenharmony_ci } 13248c2ecf20Sopenharmony_ci } else { 13258c2ecf20Sopenharmony_ci if (!(hdw->freqSelector)) { 13268c2ecf20Sopenharmony_ci /* Swing over to television frequency selection */ 13278c2ecf20Sopenharmony_ci hdw->freqSelector = 1; 13288c2ecf20Sopenharmony_ci hdw->freqDirty = !0; 13298c2ecf20Sopenharmony_ci } 13308c2ecf20Sopenharmony_ci if (hdw->freqValTelevision != val) { 13318c2ecf20Sopenharmony_ci hdw->freqValTelevision = val; 13328c2ecf20Sopenharmony_ci hdw->freqSlotTelevision = 0; 13338c2ecf20Sopenharmony_ci hdw->freqDirty = !0; 13348c2ecf20Sopenharmony_ci } 13358c2ecf20Sopenharmony_ci } 13368c2ecf20Sopenharmony_ci} 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ciint pvr2_hdw_get_unit_number(struct pvr2_hdw *hdw) 13398c2ecf20Sopenharmony_ci{ 13408c2ecf20Sopenharmony_ci return hdw->unit_number; 13418c2ecf20Sopenharmony_ci} 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci/* Attempt to locate one of the given set of files. Messages are logged 13458c2ecf20Sopenharmony_ci appropriate to what has been found. The return value will be 0 or 13468c2ecf20Sopenharmony_ci greater on success (it will be the index of the file name found) and 13478c2ecf20Sopenharmony_ci fw_entry will be filled in. Otherwise a negative error is returned on 13488c2ecf20Sopenharmony_ci failure. If the return value is -ENOENT then no viable firmware file 13498c2ecf20Sopenharmony_ci could be located. */ 13508c2ecf20Sopenharmony_cistatic int pvr2_locate_firmware(struct pvr2_hdw *hdw, 13518c2ecf20Sopenharmony_ci const struct firmware **fw_entry, 13528c2ecf20Sopenharmony_ci const char *fwtypename, 13538c2ecf20Sopenharmony_ci unsigned int fwcount, 13548c2ecf20Sopenharmony_ci const char *fwnames[]) 13558c2ecf20Sopenharmony_ci{ 13568c2ecf20Sopenharmony_ci unsigned int idx; 13578c2ecf20Sopenharmony_ci int ret = -EINVAL; 13588c2ecf20Sopenharmony_ci for (idx = 0; idx < fwcount; idx++) { 13598c2ecf20Sopenharmony_ci ret = request_firmware(fw_entry, 13608c2ecf20Sopenharmony_ci fwnames[idx], 13618c2ecf20Sopenharmony_ci &hdw->usb_dev->dev); 13628c2ecf20Sopenharmony_ci if (!ret) { 13638c2ecf20Sopenharmony_ci trace_firmware("Located %s firmware: %s; uploading...", 13648c2ecf20Sopenharmony_ci fwtypename, 13658c2ecf20Sopenharmony_ci fwnames[idx]); 13668c2ecf20Sopenharmony_ci return idx; 13678c2ecf20Sopenharmony_ci } 13688c2ecf20Sopenharmony_ci if (ret == -ENOENT) continue; 13698c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 13708c2ecf20Sopenharmony_ci "request_firmware fatal error with code=%d",ret); 13718c2ecf20Sopenharmony_ci return ret; 13728c2ecf20Sopenharmony_ci } 13738c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 13748c2ecf20Sopenharmony_ci "***WARNING*** Device %s firmware seems to be missing.", 13758c2ecf20Sopenharmony_ci fwtypename); 13768c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 13778c2ecf20Sopenharmony_ci "Did you install the pvrusb2 firmware files in their proper location?"); 13788c2ecf20Sopenharmony_ci if (fwcount == 1) { 13798c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 13808c2ecf20Sopenharmony_ci "request_firmware unable to locate %s file %s", 13818c2ecf20Sopenharmony_ci fwtypename,fwnames[0]); 13828c2ecf20Sopenharmony_ci } else { 13838c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 13848c2ecf20Sopenharmony_ci "request_firmware unable to locate one of the following %s files:", 13858c2ecf20Sopenharmony_ci fwtypename); 13868c2ecf20Sopenharmony_ci for (idx = 0; idx < fwcount; idx++) { 13878c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 13888c2ecf20Sopenharmony_ci "request_firmware: Failed to find %s", 13898c2ecf20Sopenharmony_ci fwnames[idx]); 13908c2ecf20Sopenharmony_ci } 13918c2ecf20Sopenharmony_ci } 13928c2ecf20Sopenharmony_ci return ret; 13938c2ecf20Sopenharmony_ci} 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci/* 13978c2ecf20Sopenharmony_ci * pvr2_upload_firmware1(). 13988c2ecf20Sopenharmony_ci * 13998c2ecf20Sopenharmony_ci * Send the 8051 firmware to the device. After the upload, arrange for 14008c2ecf20Sopenharmony_ci * device to re-enumerate. 14018c2ecf20Sopenharmony_ci * 14028c2ecf20Sopenharmony_ci * NOTE : the pointer to the firmware data given by request_firmware() 14038c2ecf20Sopenharmony_ci * is not suitable for an usb transaction. 14048c2ecf20Sopenharmony_ci * 14058c2ecf20Sopenharmony_ci */ 14068c2ecf20Sopenharmony_cistatic int pvr2_upload_firmware1(struct pvr2_hdw *hdw) 14078c2ecf20Sopenharmony_ci{ 14088c2ecf20Sopenharmony_ci const struct firmware *fw_entry = NULL; 14098c2ecf20Sopenharmony_ci void *fw_ptr; 14108c2ecf20Sopenharmony_ci unsigned int pipe; 14118c2ecf20Sopenharmony_ci unsigned int fwsize; 14128c2ecf20Sopenharmony_ci int ret; 14138c2ecf20Sopenharmony_ci u16 address; 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci if (!hdw->hdw_desc->fx2_firmware.cnt) { 14168c2ecf20Sopenharmony_ci hdw->fw1_state = FW1_STATE_OK; 14178c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 14188c2ecf20Sopenharmony_ci "Connected device type defines no firmware to upload; ignoring firmware"); 14198c2ecf20Sopenharmony_ci return -ENOTTY; 14208c2ecf20Sopenharmony_ci } 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci hdw->fw1_state = FW1_STATE_FAILED; // default result 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci trace_firmware("pvr2_upload_firmware1"); 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci ret = pvr2_locate_firmware(hdw,&fw_entry,"fx2 controller", 14278c2ecf20Sopenharmony_ci hdw->hdw_desc->fx2_firmware.cnt, 14288c2ecf20Sopenharmony_ci hdw->hdw_desc->fx2_firmware.lst); 14298c2ecf20Sopenharmony_ci if (ret < 0) { 14308c2ecf20Sopenharmony_ci if (ret == -ENOENT) hdw->fw1_state = FW1_STATE_MISSING; 14318c2ecf20Sopenharmony_ci return ret; 14328c2ecf20Sopenharmony_ci } 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci usb_clear_halt(hdw->usb_dev, usb_sndbulkpipe(hdw->usb_dev, 0 & 0x7f)); 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci pipe = usb_sndctrlpipe(hdw->usb_dev, 0); 14378c2ecf20Sopenharmony_ci fwsize = fw_entry->size; 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci if ((fwsize != 0x2000) && 14408c2ecf20Sopenharmony_ci (!(hdw->hdw_desc->flag_fx2_16kb && (fwsize == 0x4000)))) { 14418c2ecf20Sopenharmony_ci if (hdw->hdw_desc->flag_fx2_16kb) { 14428c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 14438c2ecf20Sopenharmony_ci "Wrong fx2 firmware size (expected 8192 or 16384, got %u)", 14448c2ecf20Sopenharmony_ci fwsize); 14458c2ecf20Sopenharmony_ci } else { 14468c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 14478c2ecf20Sopenharmony_ci "Wrong fx2 firmware size (expected 8192, got %u)", 14488c2ecf20Sopenharmony_ci fwsize); 14498c2ecf20Sopenharmony_ci } 14508c2ecf20Sopenharmony_ci release_firmware(fw_entry); 14518c2ecf20Sopenharmony_ci return -ENOMEM; 14528c2ecf20Sopenharmony_ci } 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci fw_ptr = kmalloc(0x800, GFP_KERNEL); 14558c2ecf20Sopenharmony_ci if (fw_ptr == NULL){ 14568c2ecf20Sopenharmony_ci release_firmware(fw_entry); 14578c2ecf20Sopenharmony_ci return -ENOMEM; 14588c2ecf20Sopenharmony_ci } 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci /* We have to hold the CPU during firmware upload. */ 14618c2ecf20Sopenharmony_ci pvr2_hdw_cpureset_assert(hdw,1); 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci /* upload the firmware to address 0000-1fff in 2048 (=0x800) bytes 14648c2ecf20Sopenharmony_ci chunk. */ 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci ret = 0; 14678c2ecf20Sopenharmony_ci for (address = 0; address < fwsize; address += 0x800) { 14688c2ecf20Sopenharmony_ci memcpy(fw_ptr, fw_entry->data + address, 0x800); 14698c2ecf20Sopenharmony_ci ret += usb_control_msg(hdw->usb_dev, pipe, 0xa0, 0x40, address, 14708c2ecf20Sopenharmony_ci 0, fw_ptr, 0x800, 1000); 14718c2ecf20Sopenharmony_ci } 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci trace_firmware("Upload done, releasing device's CPU"); 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci /* Now release the CPU. It will disconnect and reconnect later. */ 14768c2ecf20Sopenharmony_ci pvr2_hdw_cpureset_assert(hdw,0); 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci kfree(fw_ptr); 14798c2ecf20Sopenharmony_ci release_firmware(fw_entry); 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci trace_firmware("Upload done (%d bytes sent)",ret); 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci /* We should have written fwsize bytes */ 14848c2ecf20Sopenharmony_ci if (ret == fwsize) { 14858c2ecf20Sopenharmony_ci hdw->fw1_state = FW1_STATE_RELOAD; 14868c2ecf20Sopenharmony_ci return 0; 14878c2ecf20Sopenharmony_ci } 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci return -EIO; 14908c2ecf20Sopenharmony_ci} 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci/* 14948c2ecf20Sopenharmony_ci * pvr2_upload_firmware2() 14958c2ecf20Sopenharmony_ci * 14968c2ecf20Sopenharmony_ci * This uploads encoder firmware on endpoint 2. 14978c2ecf20Sopenharmony_ci * 14988c2ecf20Sopenharmony_ci */ 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ciint pvr2_upload_firmware2(struct pvr2_hdw *hdw) 15018c2ecf20Sopenharmony_ci{ 15028c2ecf20Sopenharmony_ci const struct firmware *fw_entry = NULL; 15038c2ecf20Sopenharmony_ci void *fw_ptr; 15048c2ecf20Sopenharmony_ci unsigned int pipe, fw_len, fw_done, bcnt, icnt; 15058c2ecf20Sopenharmony_ci int actual_length; 15068c2ecf20Sopenharmony_ci int ret = 0; 15078c2ecf20Sopenharmony_ci int fwidx; 15088c2ecf20Sopenharmony_ci static const char *fw_files[] = { 15098c2ecf20Sopenharmony_ci CX2341X_FIRM_ENC_FILENAME, 15108c2ecf20Sopenharmony_ci }; 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci if (hdw->hdw_desc->flag_skip_cx23416_firmware) { 15138c2ecf20Sopenharmony_ci return 0; 15148c2ecf20Sopenharmony_ci } 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci trace_firmware("pvr2_upload_firmware2"); 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci ret = pvr2_locate_firmware(hdw,&fw_entry,"encoder", 15198c2ecf20Sopenharmony_ci ARRAY_SIZE(fw_files), fw_files); 15208c2ecf20Sopenharmony_ci if (ret < 0) return ret; 15218c2ecf20Sopenharmony_ci fwidx = ret; 15228c2ecf20Sopenharmony_ci ret = 0; 15238c2ecf20Sopenharmony_ci /* Since we're about to completely reinitialize the encoder, 15248c2ecf20Sopenharmony_ci invalidate our cached copy of its configuration state. Next 15258c2ecf20Sopenharmony_ci time we configure the encoder, then we'll fully configure it. */ 15268c2ecf20Sopenharmony_ci hdw->enc_cur_valid = 0; 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci /* Encoder is about to be reset so note that as far as we're 15298c2ecf20Sopenharmony_ci concerned now, the encoder has never been run. */ 15308c2ecf20Sopenharmony_ci del_timer_sync(&hdw->encoder_run_timer); 15318c2ecf20Sopenharmony_ci if (hdw->state_encoder_runok) { 15328c2ecf20Sopenharmony_ci hdw->state_encoder_runok = 0; 15338c2ecf20Sopenharmony_ci trace_stbit("state_encoder_runok",hdw->state_encoder_runok); 15348c2ecf20Sopenharmony_ci } 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci /* First prepare firmware loading */ 15378c2ecf20Sopenharmony_ci ret |= pvr2_write_register(hdw, 0x0048, 0xffffffff); /*interrupt mask*/ 15388c2ecf20Sopenharmony_ci ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000088); /*gpio dir*/ 15398c2ecf20Sopenharmony_ci ret |= pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000008); /*gpio output state*/ 15408c2ecf20Sopenharmony_ci ret |= pvr2_hdw_cmd_deep_reset(hdw); 15418c2ecf20Sopenharmony_ci ret |= pvr2_write_register(hdw, 0xa064, 0x00000000); /*APU command*/ 15428c2ecf20Sopenharmony_ci ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000408); /*gpio dir*/ 15438c2ecf20Sopenharmony_ci ret |= pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000008); /*gpio output state*/ 15448c2ecf20Sopenharmony_ci ret |= pvr2_write_register(hdw, 0x9058, 0xffffffed); /*VPU ctrl*/ 15458c2ecf20Sopenharmony_ci ret |= pvr2_write_register(hdw, 0x9054, 0xfffffffd); /*reset hw blocks*/ 15468c2ecf20Sopenharmony_ci ret |= pvr2_write_register(hdw, 0x07f8, 0x80000800); /*encoder SDRAM refresh*/ 15478c2ecf20Sopenharmony_ci ret |= pvr2_write_register(hdw, 0x07fc, 0x0000001a); /*encoder SDRAM pre-charge*/ 15488c2ecf20Sopenharmony_ci ret |= pvr2_write_register(hdw, 0x0700, 0x00000000); /*I2C clock*/ 15498c2ecf20Sopenharmony_ci ret |= pvr2_write_register(hdw, 0xaa00, 0x00000000); /*unknown*/ 15508c2ecf20Sopenharmony_ci ret |= pvr2_write_register(hdw, 0xaa04, 0x00057810); /*unknown*/ 15518c2ecf20Sopenharmony_ci ret |= pvr2_write_register(hdw, 0xaa10, 0x00148500); /*unknown*/ 15528c2ecf20Sopenharmony_ci ret |= pvr2_write_register(hdw, 0xaa18, 0x00840000); /*unknown*/ 15538c2ecf20Sopenharmony_ci ret |= pvr2_issue_simple_cmd(hdw,FX2CMD_FWPOST1); 15548c2ecf20Sopenharmony_ci ret |= pvr2_issue_simple_cmd(hdw,FX2CMD_MEMSEL | (1 << 8) | (0 << 16)); 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci if (ret) { 15578c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 15588c2ecf20Sopenharmony_ci "firmware2 upload prep failed, ret=%d",ret); 15598c2ecf20Sopenharmony_ci release_firmware(fw_entry); 15608c2ecf20Sopenharmony_ci goto done; 15618c2ecf20Sopenharmony_ci } 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci /* Now send firmware */ 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci fw_len = fw_entry->size; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci if (fw_len % sizeof(u32)) { 15688c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 15698c2ecf20Sopenharmony_ci "size of %s firmware must be a multiple of %zu bytes", 15708c2ecf20Sopenharmony_ci fw_files[fwidx],sizeof(u32)); 15718c2ecf20Sopenharmony_ci release_firmware(fw_entry); 15728c2ecf20Sopenharmony_ci ret = -EINVAL; 15738c2ecf20Sopenharmony_ci goto done; 15748c2ecf20Sopenharmony_ci } 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci fw_ptr = kmalloc(FIRMWARE_CHUNK_SIZE, GFP_KERNEL); 15778c2ecf20Sopenharmony_ci if (fw_ptr == NULL){ 15788c2ecf20Sopenharmony_ci release_firmware(fw_entry); 15798c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 15808c2ecf20Sopenharmony_ci "failed to allocate memory for firmware2 upload"); 15818c2ecf20Sopenharmony_ci ret = -ENOMEM; 15828c2ecf20Sopenharmony_ci goto done; 15838c2ecf20Sopenharmony_ci } 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci pipe = usb_sndbulkpipe(hdw->usb_dev, PVR2_FIRMWARE_ENDPOINT); 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci fw_done = 0; 15888c2ecf20Sopenharmony_ci for (fw_done = 0; fw_done < fw_len;) { 15898c2ecf20Sopenharmony_ci bcnt = fw_len - fw_done; 15908c2ecf20Sopenharmony_ci if (bcnt > FIRMWARE_CHUNK_SIZE) bcnt = FIRMWARE_CHUNK_SIZE; 15918c2ecf20Sopenharmony_ci memcpy(fw_ptr, fw_entry->data + fw_done, bcnt); 15928c2ecf20Sopenharmony_ci /* Usbsnoop log shows that we must swap bytes... */ 15938c2ecf20Sopenharmony_ci /* Some background info: The data being swapped here is a 15948c2ecf20Sopenharmony_ci firmware image destined for the mpeg encoder chip that 15958c2ecf20Sopenharmony_ci lives at the other end of a USB endpoint. The encoder 15968c2ecf20Sopenharmony_ci chip always talks in 32 bit chunks and its storage is 15978c2ecf20Sopenharmony_ci organized into 32 bit words. However from the file 15988c2ecf20Sopenharmony_ci system to the encoder chip everything is purely a byte 15998c2ecf20Sopenharmony_ci stream. The firmware file's contents are always 32 bit 16008c2ecf20Sopenharmony_ci swapped from what the encoder expects. Thus the need 16018c2ecf20Sopenharmony_ci always exists to swap the bytes regardless of the endian 16028c2ecf20Sopenharmony_ci type of the host processor and therefore swab32() makes 16038c2ecf20Sopenharmony_ci the most sense. */ 16048c2ecf20Sopenharmony_ci for (icnt = 0; icnt < bcnt/4 ; icnt++) 16058c2ecf20Sopenharmony_ci ((u32 *)fw_ptr)[icnt] = swab32(((u32 *)fw_ptr)[icnt]); 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci ret |= usb_bulk_msg(hdw->usb_dev, pipe, fw_ptr,bcnt, 16088c2ecf20Sopenharmony_ci &actual_length, 1000); 16098c2ecf20Sopenharmony_ci ret |= (actual_length != bcnt); 16108c2ecf20Sopenharmony_ci if (ret) break; 16118c2ecf20Sopenharmony_ci fw_done += bcnt; 16128c2ecf20Sopenharmony_ci } 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci trace_firmware("upload of %s : %i / %i ", 16158c2ecf20Sopenharmony_ci fw_files[fwidx],fw_done,fw_len); 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci kfree(fw_ptr); 16188c2ecf20Sopenharmony_ci release_firmware(fw_entry); 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci if (ret) { 16218c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 16228c2ecf20Sopenharmony_ci "firmware2 upload transfer failure"); 16238c2ecf20Sopenharmony_ci goto done; 16248c2ecf20Sopenharmony_ci } 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci /* Finish upload */ 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci ret |= pvr2_write_register(hdw, 0x9054, 0xffffffff); /*reset hw blocks*/ 16298c2ecf20Sopenharmony_ci ret |= pvr2_write_register(hdw, 0x9058, 0xffffffe8); /*VPU ctrl*/ 16308c2ecf20Sopenharmony_ci ret |= pvr2_issue_simple_cmd(hdw,FX2CMD_MEMSEL | (1 << 8) | (0 << 16)); 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci if (ret) { 16338c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 16348c2ecf20Sopenharmony_ci "firmware2 upload post-proc failure"); 16358c2ecf20Sopenharmony_ci } 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci done: 16388c2ecf20Sopenharmony_ci if (hdw->hdw_desc->signal_routing_scheme == 16398c2ecf20Sopenharmony_ci PVR2_ROUTING_SCHEME_GOTVIEW) { 16408c2ecf20Sopenharmony_ci /* Ensure that GPIO 11 is set to output for GOTVIEW 16418c2ecf20Sopenharmony_ci hardware. */ 16428c2ecf20Sopenharmony_ci pvr2_hdw_gpio_chg_dir(hdw,(1 << 11),~0); 16438c2ecf20Sopenharmony_ci } 16448c2ecf20Sopenharmony_ci return ret; 16458c2ecf20Sopenharmony_ci} 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_cistatic const char *pvr2_get_state_name(unsigned int st) 16498c2ecf20Sopenharmony_ci{ 16508c2ecf20Sopenharmony_ci if (st < ARRAY_SIZE(pvr2_state_names)) { 16518c2ecf20Sopenharmony_ci return pvr2_state_names[st]; 16528c2ecf20Sopenharmony_ci } 16538c2ecf20Sopenharmony_ci return "???"; 16548c2ecf20Sopenharmony_ci} 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_cistatic int pvr2_decoder_enable(struct pvr2_hdw *hdw,int enablefl) 16578c2ecf20Sopenharmony_ci{ 16588c2ecf20Sopenharmony_ci /* Even though we really only care about the video decoder chip at 16598c2ecf20Sopenharmony_ci this point, we'll broadcast stream on/off to all sub-devices 16608c2ecf20Sopenharmony_ci anyway, just in case somebody else wants to hear the 16618c2ecf20Sopenharmony_ci command... */ 16628c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 stream=%s", 16638c2ecf20Sopenharmony_ci (enablefl ? "on" : "off")); 16648c2ecf20Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, 0, video, s_stream, enablefl); 16658c2ecf20Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, 0, audio, s_stream, enablefl); 16668c2ecf20Sopenharmony_ci if (hdw->decoder_client_id) { 16678c2ecf20Sopenharmony_ci /* We get here if the encoder has been noticed. Otherwise 16688c2ecf20Sopenharmony_ci we'll issue a warning to the user (which should 16698c2ecf20Sopenharmony_ci normally never happen). */ 16708c2ecf20Sopenharmony_ci return 0; 16718c2ecf20Sopenharmony_ci } 16728c2ecf20Sopenharmony_ci if (!hdw->flag_decoder_missed) { 16738c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 16748c2ecf20Sopenharmony_ci "***WARNING*** No decoder present"); 16758c2ecf20Sopenharmony_ci hdw->flag_decoder_missed = !0; 16768c2ecf20Sopenharmony_ci trace_stbit("flag_decoder_missed", 16778c2ecf20Sopenharmony_ci hdw->flag_decoder_missed); 16788c2ecf20Sopenharmony_ci } 16798c2ecf20Sopenharmony_ci return -EIO; 16808c2ecf20Sopenharmony_ci} 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ciint pvr2_hdw_get_state(struct pvr2_hdw *hdw) 16848c2ecf20Sopenharmony_ci{ 16858c2ecf20Sopenharmony_ci return hdw->master_state; 16868c2ecf20Sopenharmony_ci} 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_cistatic int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *hdw) 16908c2ecf20Sopenharmony_ci{ 16918c2ecf20Sopenharmony_ci if (!hdw->flag_tripped) return 0; 16928c2ecf20Sopenharmony_ci hdw->flag_tripped = 0; 16938c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 16948c2ecf20Sopenharmony_ci "Clearing driver error status"); 16958c2ecf20Sopenharmony_ci return !0; 16968c2ecf20Sopenharmony_ci} 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ciint pvr2_hdw_untrip(struct pvr2_hdw *hdw) 17008c2ecf20Sopenharmony_ci{ 17018c2ecf20Sopenharmony_ci int fl; 17028c2ecf20Sopenharmony_ci LOCK_TAKE(hdw->big_lock); do { 17038c2ecf20Sopenharmony_ci fl = pvr2_hdw_untrip_unlocked(hdw); 17048c2ecf20Sopenharmony_ci } while (0); LOCK_GIVE(hdw->big_lock); 17058c2ecf20Sopenharmony_ci if (fl) pvr2_hdw_state_sched(hdw); 17068c2ecf20Sopenharmony_ci return 0; 17078c2ecf20Sopenharmony_ci} 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ciint pvr2_hdw_get_streaming(struct pvr2_hdw *hdw) 17138c2ecf20Sopenharmony_ci{ 17148c2ecf20Sopenharmony_ci return hdw->state_pipeline_req != 0; 17158c2ecf20Sopenharmony_ci} 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ciint pvr2_hdw_set_streaming(struct pvr2_hdw *hdw,int enable_flag) 17198c2ecf20Sopenharmony_ci{ 17208c2ecf20Sopenharmony_ci int ret,st; 17218c2ecf20Sopenharmony_ci LOCK_TAKE(hdw->big_lock); do { 17228c2ecf20Sopenharmony_ci pvr2_hdw_untrip_unlocked(hdw); 17238c2ecf20Sopenharmony_ci if ((!enable_flag) != !(hdw->state_pipeline_req)) { 17248c2ecf20Sopenharmony_ci hdw->state_pipeline_req = enable_flag != 0; 17258c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_START_STOP, 17268c2ecf20Sopenharmony_ci "/*--TRACE_STREAM--*/ %s", 17278c2ecf20Sopenharmony_ci enable_flag ? "enable" : "disable"); 17288c2ecf20Sopenharmony_ci } 17298c2ecf20Sopenharmony_ci pvr2_hdw_state_sched(hdw); 17308c2ecf20Sopenharmony_ci } while (0); LOCK_GIVE(hdw->big_lock); 17318c2ecf20Sopenharmony_ci if ((ret = pvr2_hdw_wait(hdw,0)) < 0) return ret; 17328c2ecf20Sopenharmony_ci if (enable_flag) { 17338c2ecf20Sopenharmony_ci while ((st = hdw->master_state) != PVR2_STATE_RUN) { 17348c2ecf20Sopenharmony_ci if (st != PVR2_STATE_READY) return -EIO; 17358c2ecf20Sopenharmony_ci if ((ret = pvr2_hdw_wait(hdw,st)) < 0) return ret; 17368c2ecf20Sopenharmony_ci } 17378c2ecf20Sopenharmony_ci } 17388c2ecf20Sopenharmony_ci return 0; 17398c2ecf20Sopenharmony_ci} 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ciint pvr2_hdw_set_stream_type(struct pvr2_hdw *hdw,enum pvr2_config config) 17438c2ecf20Sopenharmony_ci{ 17448c2ecf20Sopenharmony_ci int fl; 17458c2ecf20Sopenharmony_ci LOCK_TAKE(hdw->big_lock); 17468c2ecf20Sopenharmony_ci if ((fl = (hdw->desired_stream_type != config)) != 0) { 17478c2ecf20Sopenharmony_ci hdw->desired_stream_type = config; 17488c2ecf20Sopenharmony_ci hdw->state_pipeline_config = 0; 17498c2ecf20Sopenharmony_ci trace_stbit("state_pipeline_config", 17508c2ecf20Sopenharmony_ci hdw->state_pipeline_config); 17518c2ecf20Sopenharmony_ci pvr2_hdw_state_sched(hdw); 17528c2ecf20Sopenharmony_ci } 17538c2ecf20Sopenharmony_ci LOCK_GIVE(hdw->big_lock); 17548c2ecf20Sopenharmony_ci if (fl) return 0; 17558c2ecf20Sopenharmony_ci return pvr2_hdw_wait(hdw,0); 17568c2ecf20Sopenharmony_ci} 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_cistatic int get_default_tuner_type(struct pvr2_hdw *hdw) 17608c2ecf20Sopenharmony_ci{ 17618c2ecf20Sopenharmony_ci int unit_number = hdw->unit_number; 17628c2ecf20Sopenharmony_ci int tp = -1; 17638c2ecf20Sopenharmony_ci if ((unit_number >= 0) && (unit_number < PVR_NUM)) { 17648c2ecf20Sopenharmony_ci tp = tuner[unit_number]; 17658c2ecf20Sopenharmony_ci } 17668c2ecf20Sopenharmony_ci if (tp < 0) return -EINVAL; 17678c2ecf20Sopenharmony_ci hdw->tuner_type = tp; 17688c2ecf20Sopenharmony_ci hdw->tuner_updated = !0; 17698c2ecf20Sopenharmony_ci return 0; 17708c2ecf20Sopenharmony_ci} 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_cistatic v4l2_std_id get_default_standard(struct pvr2_hdw *hdw) 17748c2ecf20Sopenharmony_ci{ 17758c2ecf20Sopenharmony_ci int unit_number = hdw->unit_number; 17768c2ecf20Sopenharmony_ci int tp = 0; 17778c2ecf20Sopenharmony_ci if ((unit_number >= 0) && (unit_number < PVR_NUM)) { 17788c2ecf20Sopenharmony_ci tp = video_std[unit_number]; 17798c2ecf20Sopenharmony_ci if (tp) return tp; 17808c2ecf20Sopenharmony_ci } 17818c2ecf20Sopenharmony_ci return 0; 17828c2ecf20Sopenharmony_ci} 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_cistatic unsigned int get_default_error_tolerance(struct pvr2_hdw *hdw) 17868c2ecf20Sopenharmony_ci{ 17878c2ecf20Sopenharmony_ci int unit_number = hdw->unit_number; 17888c2ecf20Sopenharmony_ci int tp = 0; 17898c2ecf20Sopenharmony_ci if ((unit_number >= 0) && (unit_number < PVR_NUM)) { 17908c2ecf20Sopenharmony_ci tp = tolerance[unit_number]; 17918c2ecf20Sopenharmony_ci } 17928c2ecf20Sopenharmony_ci return tp; 17938c2ecf20Sopenharmony_ci} 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_cistatic int pvr2_hdw_check_firmware(struct pvr2_hdw *hdw) 17978c2ecf20Sopenharmony_ci{ 17988c2ecf20Sopenharmony_ci /* Try a harmless request to fetch the eeprom's address over 17998c2ecf20Sopenharmony_ci endpoint 1. See what happens. Only the full FX2 image can 18008c2ecf20Sopenharmony_ci respond to this. If this probe fails then likely the FX2 18018c2ecf20Sopenharmony_ci firmware needs be loaded. */ 18028c2ecf20Sopenharmony_ci int result; 18038c2ecf20Sopenharmony_ci LOCK_TAKE(hdw->ctl_lock); do { 18048c2ecf20Sopenharmony_ci hdw->cmd_buffer[0] = FX2CMD_GET_EEPROM_ADDR; 18058c2ecf20Sopenharmony_ci result = pvr2_send_request_ex(hdw,HZ*1,!0, 18068c2ecf20Sopenharmony_ci hdw->cmd_buffer,1, 18078c2ecf20Sopenharmony_ci hdw->cmd_buffer,1); 18088c2ecf20Sopenharmony_ci if (result < 0) break; 18098c2ecf20Sopenharmony_ci } while(0); LOCK_GIVE(hdw->ctl_lock); 18108c2ecf20Sopenharmony_ci if (result) { 18118c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 18128c2ecf20Sopenharmony_ci "Probe of device endpoint 1 result status %d", 18138c2ecf20Sopenharmony_ci result); 18148c2ecf20Sopenharmony_ci } else { 18158c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 18168c2ecf20Sopenharmony_ci "Probe of device endpoint 1 succeeded"); 18178c2ecf20Sopenharmony_ci } 18188c2ecf20Sopenharmony_ci return result == 0; 18198c2ecf20Sopenharmony_ci} 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_cistruct pvr2_std_hack { 18228c2ecf20Sopenharmony_ci v4l2_std_id pat; /* Pattern to match */ 18238c2ecf20Sopenharmony_ci v4l2_std_id msk; /* Which bits we care about */ 18248c2ecf20Sopenharmony_ci v4l2_std_id std; /* What additional standards or default to set */ 18258c2ecf20Sopenharmony_ci}; 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci/* This data structure labels specific combinations of standards from 18288c2ecf20Sopenharmony_ci tveeprom that we'll try to recognize. If we recognize one, then assume 18298c2ecf20Sopenharmony_ci a specified default standard to use. This is here because tveeprom only 18308c2ecf20Sopenharmony_ci tells us about available standards not the intended default standard (if 18318c2ecf20Sopenharmony_ci any) for the device in question. We guess the default based on what has 18328c2ecf20Sopenharmony_ci been reported as available. Note that this is only for guessing a 18338c2ecf20Sopenharmony_ci default - which can always be overridden explicitly - and if the user 18348c2ecf20Sopenharmony_ci has otherwise named a default then that default will always be used in 18358c2ecf20Sopenharmony_ci place of this table. */ 18368c2ecf20Sopenharmony_cistatic const struct pvr2_std_hack std_eeprom_maps[] = { 18378c2ecf20Sopenharmony_ci { /* PAL(B/G) */ 18388c2ecf20Sopenharmony_ci .pat = V4L2_STD_B|V4L2_STD_GH, 18398c2ecf20Sopenharmony_ci .std = V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_PAL_G, 18408c2ecf20Sopenharmony_ci }, 18418c2ecf20Sopenharmony_ci { /* NTSC(M) */ 18428c2ecf20Sopenharmony_ci .pat = V4L2_STD_MN, 18438c2ecf20Sopenharmony_ci .std = V4L2_STD_NTSC_M, 18448c2ecf20Sopenharmony_ci }, 18458c2ecf20Sopenharmony_ci { /* PAL(I) */ 18468c2ecf20Sopenharmony_ci .pat = V4L2_STD_PAL_I, 18478c2ecf20Sopenharmony_ci .std = V4L2_STD_PAL_I, 18488c2ecf20Sopenharmony_ci }, 18498c2ecf20Sopenharmony_ci { /* SECAM(L/L') */ 18508c2ecf20Sopenharmony_ci .pat = V4L2_STD_SECAM_L|V4L2_STD_SECAM_LC, 18518c2ecf20Sopenharmony_ci .std = V4L2_STD_SECAM_L|V4L2_STD_SECAM_LC, 18528c2ecf20Sopenharmony_ci }, 18538c2ecf20Sopenharmony_ci { /* PAL(D/D1/K) */ 18548c2ecf20Sopenharmony_ci .pat = V4L2_STD_DK, 18558c2ecf20Sopenharmony_ci .std = V4L2_STD_PAL_D|V4L2_STD_PAL_D1|V4L2_STD_PAL_K, 18568c2ecf20Sopenharmony_ci }, 18578c2ecf20Sopenharmony_ci}; 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_cistatic void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) 18608c2ecf20Sopenharmony_ci{ 18618c2ecf20Sopenharmony_ci char buf[40]; 18628c2ecf20Sopenharmony_ci unsigned int bcnt; 18638c2ecf20Sopenharmony_ci v4l2_std_id std1,std2,std3; 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci std1 = get_default_standard(hdw); 18668c2ecf20Sopenharmony_ci std3 = std1 ? 0 : hdw->hdw_desc->default_std_mask; 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci bcnt = pvr2_std_id_to_str(buf,sizeof(buf),hdw->std_mask_eeprom); 18698c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_STD, 18708c2ecf20Sopenharmony_ci "Supported video standard(s) reported available in hardware: %.*s", 18718c2ecf20Sopenharmony_ci bcnt,buf); 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci hdw->std_mask_avail = hdw->std_mask_eeprom; 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci std2 = (std1|std3) & ~hdw->std_mask_avail; 18768c2ecf20Sopenharmony_ci if (std2) { 18778c2ecf20Sopenharmony_ci bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std2); 18788c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_STD, 18798c2ecf20Sopenharmony_ci "Expanding supported video standards to include: %.*s", 18808c2ecf20Sopenharmony_ci bcnt,buf); 18818c2ecf20Sopenharmony_ci hdw->std_mask_avail |= std2; 18828c2ecf20Sopenharmony_ci } 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_ci hdw->std_info_cur.def.type_bitmask.valid_bits = hdw->std_mask_avail; 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci if (std1) { 18878c2ecf20Sopenharmony_ci bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std1); 18888c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_STD, 18898c2ecf20Sopenharmony_ci "Initial video standard forced to %.*s", 18908c2ecf20Sopenharmony_ci bcnt,buf); 18918c2ecf20Sopenharmony_ci hdw->std_mask_cur = std1; 18928c2ecf20Sopenharmony_ci hdw->std_dirty = !0; 18938c2ecf20Sopenharmony_ci return; 18948c2ecf20Sopenharmony_ci } 18958c2ecf20Sopenharmony_ci if (std3) { 18968c2ecf20Sopenharmony_ci bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std3); 18978c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_STD, 18988c2ecf20Sopenharmony_ci "Initial video standard (determined by device type): %.*s", 18998c2ecf20Sopenharmony_ci bcnt, buf); 19008c2ecf20Sopenharmony_ci hdw->std_mask_cur = std3; 19018c2ecf20Sopenharmony_ci hdw->std_dirty = !0; 19028c2ecf20Sopenharmony_ci return; 19038c2ecf20Sopenharmony_ci } 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci { 19068c2ecf20Sopenharmony_ci unsigned int idx; 19078c2ecf20Sopenharmony_ci for (idx = 0; idx < ARRAY_SIZE(std_eeprom_maps); idx++) { 19088c2ecf20Sopenharmony_ci if (std_eeprom_maps[idx].msk ? 19098c2ecf20Sopenharmony_ci ((std_eeprom_maps[idx].pat ^ 19108c2ecf20Sopenharmony_ci hdw->std_mask_eeprom) & 19118c2ecf20Sopenharmony_ci std_eeprom_maps[idx].msk) : 19128c2ecf20Sopenharmony_ci (std_eeprom_maps[idx].pat != 19138c2ecf20Sopenharmony_ci hdw->std_mask_eeprom)) continue; 19148c2ecf20Sopenharmony_ci bcnt = pvr2_std_id_to_str(buf,sizeof(buf), 19158c2ecf20Sopenharmony_ci std_eeprom_maps[idx].std); 19168c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_STD, 19178c2ecf20Sopenharmony_ci "Initial video standard guessed as %.*s", 19188c2ecf20Sopenharmony_ci bcnt,buf); 19198c2ecf20Sopenharmony_ci hdw->std_mask_cur = std_eeprom_maps[idx].std; 19208c2ecf20Sopenharmony_ci hdw->std_dirty = !0; 19218c2ecf20Sopenharmony_ci return; 19228c2ecf20Sopenharmony_ci } 19238c2ecf20Sopenharmony_ci } 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci} 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_cistatic unsigned int pvr2_copy_i2c_addr_list( 19298c2ecf20Sopenharmony_ci unsigned short *dst, const unsigned char *src, 19308c2ecf20Sopenharmony_ci unsigned int dst_max) 19318c2ecf20Sopenharmony_ci{ 19328c2ecf20Sopenharmony_ci unsigned int cnt = 0; 19338c2ecf20Sopenharmony_ci if (!src) return 0; 19348c2ecf20Sopenharmony_ci while (src[cnt] && (cnt + 1) < dst_max) { 19358c2ecf20Sopenharmony_ci dst[cnt] = src[cnt]; 19368c2ecf20Sopenharmony_ci cnt++; 19378c2ecf20Sopenharmony_ci } 19388c2ecf20Sopenharmony_ci dst[cnt] = I2C_CLIENT_END; 19398c2ecf20Sopenharmony_ci return cnt; 19408c2ecf20Sopenharmony_ci} 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_cistatic void pvr2_hdw_cx25840_vbi_hack(struct pvr2_hdw *hdw) 19448c2ecf20Sopenharmony_ci{ 19458c2ecf20Sopenharmony_ci /* 19468c2ecf20Sopenharmony_ci Mike Isely <isely@pobox.com> 19-Nov-2006 - This bit of nuttiness 19478c2ecf20Sopenharmony_ci for cx25840 causes that module to correctly set up its video 19488c2ecf20Sopenharmony_ci scaling. This is really a problem in the cx25840 module itself, 19498c2ecf20Sopenharmony_ci but we work around it here. The problem has not been seen in 19508c2ecf20Sopenharmony_ci ivtv because there VBI is supported and set up. We don't do VBI 19518c2ecf20Sopenharmony_ci here (at least not yet) and thus we never attempted to even set 19528c2ecf20Sopenharmony_ci it up. 19538c2ecf20Sopenharmony_ci */ 19548c2ecf20Sopenharmony_ci struct v4l2_format fmt; 19558c2ecf20Sopenharmony_ci if (hdw->decoder_client_id != PVR2_CLIENT_ID_CX25840) { 19568c2ecf20Sopenharmony_ci /* We're not using a cx25840 so don't enable the hack */ 19578c2ecf20Sopenharmony_ci return; 19588c2ecf20Sopenharmony_ci } 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 19618c2ecf20Sopenharmony_ci "Module ID %u: Executing cx25840 VBI hack", 19628c2ecf20Sopenharmony_ci hdw->decoder_client_id); 19638c2ecf20Sopenharmony_ci memset(&fmt, 0, sizeof(fmt)); 19648c2ecf20Sopenharmony_ci fmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; 19658c2ecf20Sopenharmony_ci fmt.fmt.sliced.service_lines[0][21] = V4L2_SLICED_CAPTION_525; 19668c2ecf20Sopenharmony_ci fmt.fmt.sliced.service_lines[1][21] = V4L2_SLICED_CAPTION_525; 19678c2ecf20Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, hdw->decoder_client_id, 19688c2ecf20Sopenharmony_ci vbi, s_sliced_fmt, &fmt.fmt.sliced); 19698c2ecf20Sopenharmony_ci} 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_cistatic int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw, 19738c2ecf20Sopenharmony_ci const struct pvr2_device_client_desc *cd) 19748c2ecf20Sopenharmony_ci{ 19758c2ecf20Sopenharmony_ci const char *fname; 19768c2ecf20Sopenharmony_ci unsigned char mid; 19778c2ecf20Sopenharmony_ci struct v4l2_subdev *sd; 19788c2ecf20Sopenharmony_ci unsigned int i2ccnt; 19798c2ecf20Sopenharmony_ci const unsigned char *p; 19808c2ecf20Sopenharmony_ci /* Arbitrary count - max # i2c addresses we will probe */ 19818c2ecf20Sopenharmony_ci unsigned short i2caddr[25]; 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_ci mid = cd->module_id; 19848c2ecf20Sopenharmony_ci fname = (mid < ARRAY_SIZE(module_names)) ? module_names[mid] : NULL; 19858c2ecf20Sopenharmony_ci if (!fname) { 19868c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 19878c2ecf20Sopenharmony_ci "Module ID %u for device %s has no name? The driver might have a configuration problem.", 19888c2ecf20Sopenharmony_ci mid, 19898c2ecf20Sopenharmony_ci hdw->hdw_desc->description); 19908c2ecf20Sopenharmony_ci return -EINVAL; 19918c2ecf20Sopenharmony_ci } 19928c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 19938c2ecf20Sopenharmony_ci "Module ID %u (%s) for device %s being loaded...", 19948c2ecf20Sopenharmony_ci mid, fname, 19958c2ecf20Sopenharmony_ci hdw->hdw_desc->description); 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci i2ccnt = pvr2_copy_i2c_addr_list(i2caddr, cd->i2c_address_list, 19988c2ecf20Sopenharmony_ci ARRAY_SIZE(i2caddr)); 19998c2ecf20Sopenharmony_ci if (!i2ccnt && ((p = (mid < ARRAY_SIZE(module_i2c_addresses)) ? 20008c2ecf20Sopenharmony_ci module_i2c_addresses[mid] : NULL) != NULL)) { 20018c2ecf20Sopenharmony_ci /* Second chance: Try default i2c address list */ 20028c2ecf20Sopenharmony_ci i2ccnt = pvr2_copy_i2c_addr_list(i2caddr, p, 20038c2ecf20Sopenharmony_ci ARRAY_SIZE(i2caddr)); 20048c2ecf20Sopenharmony_ci if (i2ccnt) { 20058c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 20068c2ecf20Sopenharmony_ci "Module ID %u: Using default i2c address list", 20078c2ecf20Sopenharmony_ci mid); 20088c2ecf20Sopenharmony_ci } 20098c2ecf20Sopenharmony_ci } 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci if (!i2ccnt) { 20128c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 20138c2ecf20Sopenharmony_ci "Module ID %u (%s) for device %s: No i2c addresses. The driver might have a configuration problem.", 20148c2ecf20Sopenharmony_ci mid, fname, hdw->hdw_desc->description); 20158c2ecf20Sopenharmony_ci return -EINVAL; 20168c2ecf20Sopenharmony_ci } 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci if (i2ccnt == 1) { 20198c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 20208c2ecf20Sopenharmony_ci "Module ID %u: Setting up with specified i2c address 0x%x", 20218c2ecf20Sopenharmony_ci mid, i2caddr[0]); 20228c2ecf20Sopenharmony_ci sd = v4l2_i2c_new_subdev(&hdw->v4l2_dev, &hdw->i2c_adap, 20238c2ecf20Sopenharmony_ci fname, i2caddr[0], NULL); 20248c2ecf20Sopenharmony_ci } else { 20258c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 20268c2ecf20Sopenharmony_ci "Module ID %u: Setting up with address probe list", 20278c2ecf20Sopenharmony_ci mid); 20288c2ecf20Sopenharmony_ci sd = v4l2_i2c_new_subdev(&hdw->v4l2_dev, &hdw->i2c_adap, 20298c2ecf20Sopenharmony_ci fname, 0, i2caddr); 20308c2ecf20Sopenharmony_ci } 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci if (!sd) { 20338c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 20348c2ecf20Sopenharmony_ci "Module ID %u (%s) for device %s failed to load. Possible missing sub-device kernel module or initialization failure within module.", 20358c2ecf20Sopenharmony_ci mid, fname, hdw->hdw_desc->description); 20368c2ecf20Sopenharmony_ci return -EIO; 20378c2ecf20Sopenharmony_ci } 20388c2ecf20Sopenharmony_ci 20398c2ecf20Sopenharmony_ci /* Tag this sub-device instance with the module ID we know about. 20408c2ecf20Sopenharmony_ci In other places we'll use that tag to determine if the instance 20418c2ecf20Sopenharmony_ci requires special handling. */ 20428c2ecf20Sopenharmony_ci sd->grp_id = mid; 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INFO, "Attached sub-driver %s", fname); 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci /* client-specific setup... */ 20488c2ecf20Sopenharmony_ci switch (mid) { 20498c2ecf20Sopenharmony_ci case PVR2_CLIENT_ID_CX25840: 20508c2ecf20Sopenharmony_ci case PVR2_CLIENT_ID_SAA7115: 20518c2ecf20Sopenharmony_ci hdw->decoder_client_id = mid; 20528c2ecf20Sopenharmony_ci break; 20538c2ecf20Sopenharmony_ci default: break; 20548c2ecf20Sopenharmony_ci } 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci return 0; 20578c2ecf20Sopenharmony_ci} 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_cistatic void pvr2_hdw_load_modules(struct pvr2_hdw *hdw) 20618c2ecf20Sopenharmony_ci{ 20628c2ecf20Sopenharmony_ci unsigned int idx; 20638c2ecf20Sopenharmony_ci const struct pvr2_string_table *cm; 20648c2ecf20Sopenharmony_ci const struct pvr2_device_client_table *ct; 20658c2ecf20Sopenharmony_ci int okFl = !0; 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci cm = &hdw->hdw_desc->client_modules; 20688c2ecf20Sopenharmony_ci for (idx = 0; idx < cm->cnt; idx++) { 20698c2ecf20Sopenharmony_ci request_module(cm->lst[idx]); 20708c2ecf20Sopenharmony_ci } 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci ct = &hdw->hdw_desc->client_table; 20738c2ecf20Sopenharmony_ci for (idx = 0; idx < ct->cnt; idx++) { 20748c2ecf20Sopenharmony_ci if (pvr2_hdw_load_subdev(hdw, &ct->lst[idx]) < 0) okFl = 0; 20758c2ecf20Sopenharmony_ci } 20768c2ecf20Sopenharmony_ci if (!okFl) { 20778c2ecf20Sopenharmony_ci hdw->flag_modulefail = !0; 20788c2ecf20Sopenharmony_ci pvr2_hdw_render_useless(hdw); 20798c2ecf20Sopenharmony_ci } 20808c2ecf20Sopenharmony_ci} 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_cistatic void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) 20848c2ecf20Sopenharmony_ci{ 20858c2ecf20Sopenharmony_ci int ret; 20868c2ecf20Sopenharmony_ci unsigned int idx; 20878c2ecf20Sopenharmony_ci struct pvr2_ctrl *cptr; 20888c2ecf20Sopenharmony_ci int reloadFl = 0; 20898c2ecf20Sopenharmony_ci if (hdw->hdw_desc->fx2_firmware.cnt) { 20908c2ecf20Sopenharmony_ci if (!reloadFl) { 20918c2ecf20Sopenharmony_ci reloadFl = 20928c2ecf20Sopenharmony_ci (hdw->usb_intf->cur_altsetting->desc.bNumEndpoints 20938c2ecf20Sopenharmony_ci == 0); 20948c2ecf20Sopenharmony_ci if (reloadFl) { 20958c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 20968c2ecf20Sopenharmony_ci "USB endpoint config looks strange; possibly firmware needs to be loaded"); 20978c2ecf20Sopenharmony_ci } 20988c2ecf20Sopenharmony_ci } 20998c2ecf20Sopenharmony_ci if (!reloadFl) { 21008c2ecf20Sopenharmony_ci reloadFl = !pvr2_hdw_check_firmware(hdw); 21018c2ecf20Sopenharmony_ci if (reloadFl) { 21028c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 21038c2ecf20Sopenharmony_ci "Check for FX2 firmware failed; possibly firmware needs to be loaded"); 21048c2ecf20Sopenharmony_ci } 21058c2ecf20Sopenharmony_ci } 21068c2ecf20Sopenharmony_ci if (reloadFl) { 21078c2ecf20Sopenharmony_ci if (pvr2_upload_firmware1(hdw) != 0) { 21088c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 21098c2ecf20Sopenharmony_ci "Failure uploading firmware1"); 21108c2ecf20Sopenharmony_ci } 21118c2ecf20Sopenharmony_ci return; 21128c2ecf20Sopenharmony_ci } 21138c2ecf20Sopenharmony_ci } 21148c2ecf20Sopenharmony_ci hdw->fw1_state = FW1_STATE_OK; 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci if (!pvr2_hdw_dev_ok(hdw)) return; 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci hdw->force_dirty = !0; 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci if (!hdw->hdw_desc->flag_no_powerup) { 21218c2ecf20Sopenharmony_ci pvr2_hdw_cmd_powerup(hdw); 21228c2ecf20Sopenharmony_ci if (!pvr2_hdw_dev_ok(hdw)) return; 21238c2ecf20Sopenharmony_ci } 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci /* Take the IR chip out of reset, if appropriate */ 21268c2ecf20Sopenharmony_ci if (hdw->ir_scheme_active == PVR2_IR_SCHEME_ZILOG) { 21278c2ecf20Sopenharmony_ci pvr2_issue_simple_cmd(hdw, 21288c2ecf20Sopenharmony_ci FX2CMD_HCW_ZILOG_RESET | 21298c2ecf20Sopenharmony_ci (1 << 8) | 21308c2ecf20Sopenharmony_ci ((0) << 16)); 21318c2ecf20Sopenharmony_ci } 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci /* This step MUST happen after the earlier powerup step */ 21348c2ecf20Sopenharmony_ci pvr2_i2c_core_init(hdw); 21358c2ecf20Sopenharmony_ci if (!pvr2_hdw_dev_ok(hdw)) return; 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci /* Reset demod only on Hauppauge 160xxx platform */ 21388c2ecf20Sopenharmony_ci if (le16_to_cpu(hdw->usb_dev->descriptor.idVendor) == 0x2040 && 21398c2ecf20Sopenharmony_ci (le16_to_cpu(hdw->usb_dev->descriptor.idProduct) == 0x7502 || 21408c2ecf20Sopenharmony_ci le16_to_cpu(hdw->usb_dev->descriptor.idProduct) == 0x7510)) { 21418c2ecf20Sopenharmony_ci pr_info("%s(): resetting 160xxx demod\n", __func__); 21428c2ecf20Sopenharmony_ci /* TODO: not sure this is proper place to reset once only */ 21438c2ecf20Sopenharmony_ci pvr2_issue_simple_cmd(hdw, 21448c2ecf20Sopenharmony_ci FX2CMD_HCW_DEMOD_RESET_PIN | 21458c2ecf20Sopenharmony_ci (1 << 8) | 21468c2ecf20Sopenharmony_ci ((0) << 16)); 21478c2ecf20Sopenharmony_ci usleep_range(10000, 10500); 21488c2ecf20Sopenharmony_ci pvr2_issue_simple_cmd(hdw, 21498c2ecf20Sopenharmony_ci FX2CMD_HCW_DEMOD_RESET_PIN | 21508c2ecf20Sopenharmony_ci (1 << 8) | 21518c2ecf20Sopenharmony_ci ((1) << 16)); 21528c2ecf20Sopenharmony_ci usleep_range(10000, 10500); 21538c2ecf20Sopenharmony_ci } 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_ci pvr2_hdw_load_modules(hdw); 21568c2ecf20Sopenharmony_ci if (!pvr2_hdw_dev_ok(hdw)) return; 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, 0, core, load_fw); 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci for (idx = 0; idx < CTRLDEF_COUNT; idx++) { 21618c2ecf20Sopenharmony_ci cptr = hdw->controls + idx; 21628c2ecf20Sopenharmony_ci if (cptr->info->skip_init) continue; 21638c2ecf20Sopenharmony_ci if (!cptr->info->set_value) continue; 21648c2ecf20Sopenharmony_ci cptr->info->set_value(cptr,~0,cptr->info->default_value); 21658c2ecf20Sopenharmony_ci } 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci pvr2_hdw_cx25840_vbi_hack(hdw); 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci /* Set up special default values for the television and radio 21708c2ecf20Sopenharmony_ci frequencies here. It's not really important what these defaults 21718c2ecf20Sopenharmony_ci are, but I set them to something usable in the Chicago area just 21728c2ecf20Sopenharmony_ci to make driver testing a little easier. */ 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci hdw->freqValTelevision = default_tv_freq; 21758c2ecf20Sopenharmony_ci hdw->freqValRadio = default_radio_freq; 21768c2ecf20Sopenharmony_ci 21778c2ecf20Sopenharmony_ci // Do not use pvr2_reset_ctl_endpoints() here. It is not 21788c2ecf20Sopenharmony_ci // thread-safe against the normal pvr2_send_request() mechanism. 21798c2ecf20Sopenharmony_ci // (We should make it thread safe). 21808c2ecf20Sopenharmony_ci 21818c2ecf20Sopenharmony_ci if (hdw->hdw_desc->flag_has_hauppauge_rom) { 21828c2ecf20Sopenharmony_ci ret = pvr2_hdw_get_eeprom_addr(hdw); 21838c2ecf20Sopenharmony_ci if (!pvr2_hdw_dev_ok(hdw)) return; 21848c2ecf20Sopenharmony_ci if (ret < 0) { 21858c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 21868c2ecf20Sopenharmony_ci "Unable to determine location of eeprom, skipping"); 21878c2ecf20Sopenharmony_ci } else { 21888c2ecf20Sopenharmony_ci hdw->eeprom_addr = ret; 21898c2ecf20Sopenharmony_ci pvr2_eeprom_analyze(hdw); 21908c2ecf20Sopenharmony_ci if (!pvr2_hdw_dev_ok(hdw)) return; 21918c2ecf20Sopenharmony_ci } 21928c2ecf20Sopenharmony_ci } else { 21938c2ecf20Sopenharmony_ci hdw->tuner_type = hdw->hdw_desc->default_tuner_type; 21948c2ecf20Sopenharmony_ci hdw->tuner_updated = !0; 21958c2ecf20Sopenharmony_ci hdw->std_mask_eeprom = V4L2_STD_ALL; 21968c2ecf20Sopenharmony_ci } 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci if (hdw->serial_number) { 21998c2ecf20Sopenharmony_ci idx = scnprintf(hdw->identifier, sizeof(hdw->identifier) - 1, 22008c2ecf20Sopenharmony_ci "sn-%lu", hdw->serial_number); 22018c2ecf20Sopenharmony_ci } else if (hdw->unit_number >= 0) { 22028c2ecf20Sopenharmony_ci idx = scnprintf(hdw->identifier, sizeof(hdw->identifier) - 1, 22038c2ecf20Sopenharmony_ci "unit-%c", 22048c2ecf20Sopenharmony_ci hdw->unit_number + 'a'); 22058c2ecf20Sopenharmony_ci } else { 22068c2ecf20Sopenharmony_ci idx = scnprintf(hdw->identifier, sizeof(hdw->identifier) - 1, 22078c2ecf20Sopenharmony_ci "unit-??"); 22088c2ecf20Sopenharmony_ci } 22098c2ecf20Sopenharmony_ci hdw->identifier[idx] = 0; 22108c2ecf20Sopenharmony_ci 22118c2ecf20Sopenharmony_ci pvr2_hdw_setup_std(hdw); 22128c2ecf20Sopenharmony_ci 22138c2ecf20Sopenharmony_ci if (!get_default_tuner_type(hdw)) { 22148c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 22158c2ecf20Sopenharmony_ci "pvr2_hdw_setup: Tuner type overridden to %d", 22168c2ecf20Sopenharmony_ci hdw->tuner_type); 22178c2ecf20Sopenharmony_ci } 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_ci 22208c2ecf20Sopenharmony_ci if (!pvr2_hdw_dev_ok(hdw)) return; 22218c2ecf20Sopenharmony_ci 22228c2ecf20Sopenharmony_ci if (hdw->hdw_desc->signal_routing_scheme == 22238c2ecf20Sopenharmony_ci PVR2_ROUTING_SCHEME_GOTVIEW) { 22248c2ecf20Sopenharmony_ci /* Ensure that GPIO 11 is set to output for GOTVIEW 22258c2ecf20Sopenharmony_ci hardware. */ 22268c2ecf20Sopenharmony_ci pvr2_hdw_gpio_chg_dir(hdw,(1 << 11),~0); 22278c2ecf20Sopenharmony_ci } 22288c2ecf20Sopenharmony_ci 22298c2ecf20Sopenharmony_ci pvr2_hdw_commit_setup(hdw); 22308c2ecf20Sopenharmony_ci 22318c2ecf20Sopenharmony_ci hdw->vid_stream = pvr2_stream_create(); 22328c2ecf20Sopenharmony_ci if (!pvr2_hdw_dev_ok(hdw)) return; 22338c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 22348c2ecf20Sopenharmony_ci "pvr2_hdw_setup: video stream is %p",hdw->vid_stream); 22358c2ecf20Sopenharmony_ci if (hdw->vid_stream) { 22368c2ecf20Sopenharmony_ci idx = get_default_error_tolerance(hdw); 22378c2ecf20Sopenharmony_ci if (idx) { 22388c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 22398c2ecf20Sopenharmony_ci "pvr2_hdw_setup: video stream %p setting tolerance %u", 22408c2ecf20Sopenharmony_ci hdw->vid_stream,idx); 22418c2ecf20Sopenharmony_ci } 22428c2ecf20Sopenharmony_ci pvr2_stream_setup(hdw->vid_stream,hdw->usb_dev, 22438c2ecf20Sopenharmony_ci PVR2_VID_ENDPOINT,idx); 22448c2ecf20Sopenharmony_ci } 22458c2ecf20Sopenharmony_ci 22468c2ecf20Sopenharmony_ci if (!pvr2_hdw_dev_ok(hdw)) return; 22478c2ecf20Sopenharmony_ci 22488c2ecf20Sopenharmony_ci hdw->flag_init_ok = !0; 22498c2ecf20Sopenharmony_ci 22508c2ecf20Sopenharmony_ci pvr2_hdw_state_sched(hdw); 22518c2ecf20Sopenharmony_ci} 22528c2ecf20Sopenharmony_ci 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci/* Set up the structure and attempt to put the device into a usable state. 22558c2ecf20Sopenharmony_ci This can be a time-consuming operation, which is why it is not done 22568c2ecf20Sopenharmony_ci internally as part of the create() step. */ 22578c2ecf20Sopenharmony_cistatic void pvr2_hdw_setup(struct pvr2_hdw *hdw) 22588c2ecf20Sopenharmony_ci{ 22598c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) begin",hdw); 22608c2ecf20Sopenharmony_ci do { 22618c2ecf20Sopenharmony_ci pvr2_hdw_setup_low(hdw); 22628c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 22638c2ecf20Sopenharmony_ci "pvr2_hdw_setup(hdw=%p) done, ok=%d init_ok=%d", 22648c2ecf20Sopenharmony_ci hdw,pvr2_hdw_dev_ok(hdw),hdw->flag_init_ok); 22658c2ecf20Sopenharmony_ci if (pvr2_hdw_dev_ok(hdw)) { 22668c2ecf20Sopenharmony_ci if (hdw->flag_init_ok) { 22678c2ecf20Sopenharmony_ci pvr2_trace( 22688c2ecf20Sopenharmony_ci PVR2_TRACE_INFO, 22698c2ecf20Sopenharmony_ci "Device initialization completed successfully."); 22708c2ecf20Sopenharmony_ci break; 22718c2ecf20Sopenharmony_ci } 22728c2ecf20Sopenharmony_ci if (hdw->fw1_state == FW1_STATE_RELOAD) { 22738c2ecf20Sopenharmony_ci pvr2_trace( 22748c2ecf20Sopenharmony_ci PVR2_TRACE_INFO, 22758c2ecf20Sopenharmony_ci "Device microcontroller firmware (re)loaded; it should now reset and reconnect."); 22768c2ecf20Sopenharmony_ci break; 22778c2ecf20Sopenharmony_ci } 22788c2ecf20Sopenharmony_ci pvr2_trace( 22798c2ecf20Sopenharmony_ci PVR2_TRACE_ERROR_LEGS, 22808c2ecf20Sopenharmony_ci "Device initialization was not successful."); 22818c2ecf20Sopenharmony_ci if (hdw->fw1_state == FW1_STATE_MISSING) { 22828c2ecf20Sopenharmony_ci pvr2_trace( 22838c2ecf20Sopenharmony_ci PVR2_TRACE_ERROR_LEGS, 22848c2ecf20Sopenharmony_ci "Giving up since device microcontroller firmware appears to be missing."); 22858c2ecf20Sopenharmony_ci break; 22868c2ecf20Sopenharmony_ci } 22878c2ecf20Sopenharmony_ci } 22888c2ecf20Sopenharmony_ci if (hdw->flag_modulefail) { 22898c2ecf20Sopenharmony_ci pvr2_trace( 22908c2ecf20Sopenharmony_ci PVR2_TRACE_ERROR_LEGS, 22918c2ecf20Sopenharmony_ci "***WARNING*** pvrusb2 driver initialization failed due to the failure of one or more sub-device kernel modules."); 22928c2ecf20Sopenharmony_ci pvr2_trace( 22938c2ecf20Sopenharmony_ci PVR2_TRACE_ERROR_LEGS, 22948c2ecf20Sopenharmony_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."); 22958c2ecf20Sopenharmony_ci break; 22968c2ecf20Sopenharmony_ci } 22978c2ecf20Sopenharmony_ci if (procreload) { 22988c2ecf20Sopenharmony_ci pvr2_trace( 22998c2ecf20Sopenharmony_ci PVR2_TRACE_ERROR_LEGS, 23008c2ecf20Sopenharmony_ci "Attempting pvrusb2 recovery by reloading primary firmware."); 23018c2ecf20Sopenharmony_ci pvr2_trace( 23028c2ecf20Sopenharmony_ci PVR2_TRACE_ERROR_LEGS, 23038c2ecf20Sopenharmony_ci "If this works, device should disconnect and reconnect in a sane state."); 23048c2ecf20Sopenharmony_ci hdw->fw1_state = FW1_STATE_UNKNOWN; 23058c2ecf20Sopenharmony_ci pvr2_upload_firmware1(hdw); 23068c2ecf20Sopenharmony_ci } else { 23078c2ecf20Sopenharmony_ci pvr2_trace( 23088c2ecf20Sopenharmony_ci PVR2_TRACE_ERROR_LEGS, 23098c2ecf20Sopenharmony_ci "***WARNING*** pvrusb2 device hardware appears to be jammed and I can't clear it."); 23108c2ecf20Sopenharmony_ci pvr2_trace( 23118c2ecf20Sopenharmony_ci PVR2_TRACE_ERROR_LEGS, 23128c2ecf20Sopenharmony_ci "You might need to power cycle the pvrusb2 device in order to recover."); 23138c2ecf20Sopenharmony_ci } 23148c2ecf20Sopenharmony_ci } while (0); 23158c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) end",hdw); 23168c2ecf20Sopenharmony_ci} 23178c2ecf20Sopenharmony_ci 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ci/* Perform second stage initialization. Set callback pointer first so that 23208c2ecf20Sopenharmony_ci we can avoid a possible initialization race (if the kernel thread runs 23218c2ecf20Sopenharmony_ci before the callback has been set). */ 23228c2ecf20Sopenharmony_ciint pvr2_hdw_initialize(struct pvr2_hdw *hdw, 23238c2ecf20Sopenharmony_ci void (*callback_func)(void *), 23248c2ecf20Sopenharmony_ci void *callback_data) 23258c2ecf20Sopenharmony_ci{ 23268c2ecf20Sopenharmony_ci LOCK_TAKE(hdw->big_lock); do { 23278c2ecf20Sopenharmony_ci if (hdw->flag_disconnected) { 23288c2ecf20Sopenharmony_ci /* Handle a race here: If we're already 23298c2ecf20Sopenharmony_ci disconnected by this point, then give up. If we 23308c2ecf20Sopenharmony_ci get past this then we'll remain connected for 23318c2ecf20Sopenharmony_ci the duration of initialization since the entire 23328c2ecf20Sopenharmony_ci initialization sequence is now protected by the 23338c2ecf20Sopenharmony_ci big_lock. */ 23348c2ecf20Sopenharmony_ci break; 23358c2ecf20Sopenharmony_ci } 23368c2ecf20Sopenharmony_ci hdw->state_data = callback_data; 23378c2ecf20Sopenharmony_ci hdw->state_func = callback_func; 23388c2ecf20Sopenharmony_ci pvr2_hdw_setup(hdw); 23398c2ecf20Sopenharmony_ci } while (0); LOCK_GIVE(hdw->big_lock); 23408c2ecf20Sopenharmony_ci return hdw->flag_init_ok; 23418c2ecf20Sopenharmony_ci} 23428c2ecf20Sopenharmony_ci 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci/* Create, set up, and return a structure for interacting with the 23458c2ecf20Sopenharmony_ci underlying hardware. */ 23468c2ecf20Sopenharmony_cistruct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, 23478c2ecf20Sopenharmony_ci const struct usb_device_id *devid) 23488c2ecf20Sopenharmony_ci{ 23498c2ecf20Sopenharmony_ci unsigned int idx,cnt1,cnt2,m; 23508c2ecf20Sopenharmony_ci struct pvr2_hdw *hdw = NULL; 23518c2ecf20Sopenharmony_ci int valid_std_mask; 23528c2ecf20Sopenharmony_ci struct pvr2_ctrl *cptr; 23538c2ecf20Sopenharmony_ci struct usb_device *usb_dev; 23548c2ecf20Sopenharmony_ci const struct pvr2_device_desc *hdw_desc; 23558c2ecf20Sopenharmony_ci __u8 ifnum; 23568c2ecf20Sopenharmony_ci struct v4l2_queryctrl qctrl; 23578c2ecf20Sopenharmony_ci struct pvr2_ctl_info *ciptr; 23588c2ecf20Sopenharmony_ci 23598c2ecf20Sopenharmony_ci usb_dev = interface_to_usbdev(intf); 23608c2ecf20Sopenharmony_ci 23618c2ecf20Sopenharmony_ci hdw_desc = (const struct pvr2_device_desc *)(devid->driver_info); 23628c2ecf20Sopenharmony_ci 23638c2ecf20Sopenharmony_ci if (hdw_desc == NULL) { 23648c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, "pvr2_hdw_create: No device description pointer, unable to continue."); 23658c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 23668c2ecf20Sopenharmony_ci "If you have a new device type, please contact Mike Isely <isely@pobox.com> to get it included in the driver"); 23678c2ecf20Sopenharmony_ci goto fail; 23688c2ecf20Sopenharmony_ci } 23698c2ecf20Sopenharmony_ci 23708c2ecf20Sopenharmony_ci hdw = kzalloc(sizeof(*hdw),GFP_KERNEL); 23718c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"", 23728c2ecf20Sopenharmony_ci hdw,hdw_desc->description); 23738c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INFO, "Hardware description: %s", 23748c2ecf20Sopenharmony_ci hdw_desc->description); 23758c2ecf20Sopenharmony_ci if (hdw_desc->flag_is_experimental) { 23768c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INFO, "**********"); 23778c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INFO, 23788c2ecf20Sopenharmony_ci "***WARNING*** Support for this device (%s) is experimental.", 23798c2ecf20Sopenharmony_ci hdw_desc->description); 23808c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INFO, 23818c2ecf20Sopenharmony_ci "Important functionality might not be entirely working."); 23828c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INFO, 23838c2ecf20Sopenharmony_ci "Please consider contacting the driver author to help with further stabilization of the driver."); 23848c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INFO, "**********"); 23858c2ecf20Sopenharmony_ci } 23868c2ecf20Sopenharmony_ci if (!hdw) goto fail; 23878c2ecf20Sopenharmony_ci 23888c2ecf20Sopenharmony_ci timer_setup(&hdw->quiescent_timer, pvr2_hdw_quiescent_timeout, 0); 23898c2ecf20Sopenharmony_ci 23908c2ecf20Sopenharmony_ci timer_setup(&hdw->decoder_stabilization_timer, 23918c2ecf20Sopenharmony_ci pvr2_hdw_decoder_stabilization_timeout, 0); 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_ci timer_setup(&hdw->encoder_wait_timer, pvr2_hdw_encoder_wait_timeout, 23948c2ecf20Sopenharmony_ci 0); 23958c2ecf20Sopenharmony_ci 23968c2ecf20Sopenharmony_ci timer_setup(&hdw->encoder_run_timer, pvr2_hdw_encoder_run_timeout, 0); 23978c2ecf20Sopenharmony_ci 23988c2ecf20Sopenharmony_ci hdw->master_state = PVR2_STATE_DEAD; 23998c2ecf20Sopenharmony_ci 24008c2ecf20Sopenharmony_ci init_waitqueue_head(&hdw->state_wait_data); 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_ci hdw->tuner_signal_stale = !0; 24038c2ecf20Sopenharmony_ci cx2341x_fill_defaults(&hdw->enc_ctl_state); 24048c2ecf20Sopenharmony_ci 24058c2ecf20Sopenharmony_ci /* Calculate which inputs are OK */ 24068c2ecf20Sopenharmony_ci m = 0; 24078c2ecf20Sopenharmony_ci if (hdw_desc->flag_has_analogtuner) m |= 1 << PVR2_CVAL_INPUT_TV; 24088c2ecf20Sopenharmony_ci if (hdw_desc->digital_control_scheme != PVR2_DIGITAL_SCHEME_NONE) { 24098c2ecf20Sopenharmony_ci m |= 1 << PVR2_CVAL_INPUT_DTV; 24108c2ecf20Sopenharmony_ci } 24118c2ecf20Sopenharmony_ci if (hdw_desc->flag_has_svideo) m |= 1 << PVR2_CVAL_INPUT_SVIDEO; 24128c2ecf20Sopenharmony_ci if (hdw_desc->flag_has_composite) m |= 1 << PVR2_CVAL_INPUT_COMPOSITE; 24138c2ecf20Sopenharmony_ci if (hdw_desc->flag_has_fmradio) m |= 1 << PVR2_CVAL_INPUT_RADIO; 24148c2ecf20Sopenharmony_ci hdw->input_avail_mask = m; 24158c2ecf20Sopenharmony_ci hdw->input_allowed_mask = hdw->input_avail_mask; 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_ci /* If not a hybrid device, pathway_state never changes. So 24188c2ecf20Sopenharmony_ci initialize it here to what it should forever be. */ 24198c2ecf20Sopenharmony_ci if (!(hdw->input_avail_mask & (1 << PVR2_CVAL_INPUT_DTV))) { 24208c2ecf20Sopenharmony_ci hdw->pathway_state = PVR2_PATHWAY_ANALOG; 24218c2ecf20Sopenharmony_ci } else if (!(hdw->input_avail_mask & (1 << PVR2_CVAL_INPUT_TV))) { 24228c2ecf20Sopenharmony_ci hdw->pathway_state = PVR2_PATHWAY_DIGITAL; 24238c2ecf20Sopenharmony_ci } 24248c2ecf20Sopenharmony_ci 24258c2ecf20Sopenharmony_ci hdw->control_cnt = CTRLDEF_COUNT; 24268c2ecf20Sopenharmony_ci hdw->control_cnt += MPEGDEF_COUNT; 24278c2ecf20Sopenharmony_ci hdw->controls = kcalloc(hdw->control_cnt, sizeof(struct pvr2_ctrl), 24288c2ecf20Sopenharmony_ci GFP_KERNEL); 24298c2ecf20Sopenharmony_ci if (!hdw->controls) goto fail; 24308c2ecf20Sopenharmony_ci hdw->hdw_desc = hdw_desc; 24318c2ecf20Sopenharmony_ci hdw->ir_scheme_active = hdw->hdw_desc->ir_scheme; 24328c2ecf20Sopenharmony_ci for (idx = 0; idx < hdw->control_cnt; idx++) { 24338c2ecf20Sopenharmony_ci cptr = hdw->controls + idx; 24348c2ecf20Sopenharmony_ci cptr->hdw = hdw; 24358c2ecf20Sopenharmony_ci } 24368c2ecf20Sopenharmony_ci for (idx = 0; idx < 32; idx++) { 24378c2ecf20Sopenharmony_ci hdw->std_mask_ptrs[idx] = hdw->std_mask_names[idx]; 24388c2ecf20Sopenharmony_ci } 24398c2ecf20Sopenharmony_ci for (idx = 0; idx < CTRLDEF_COUNT; idx++) { 24408c2ecf20Sopenharmony_ci cptr = hdw->controls + idx; 24418c2ecf20Sopenharmony_ci cptr->info = control_defs+idx; 24428c2ecf20Sopenharmony_ci } 24438c2ecf20Sopenharmony_ci 24448c2ecf20Sopenharmony_ci /* Ensure that default input choice is a valid one. */ 24458c2ecf20Sopenharmony_ci m = hdw->input_avail_mask; 24468c2ecf20Sopenharmony_ci if (m) for (idx = 0; idx < (sizeof(m) << 3); idx++) { 24478c2ecf20Sopenharmony_ci if (!((1UL << idx) & m)) continue; 24488c2ecf20Sopenharmony_ci hdw->input_val = idx; 24498c2ecf20Sopenharmony_ci break; 24508c2ecf20Sopenharmony_ci } 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_ci /* Define and configure additional controls from cx2341x module. */ 24538c2ecf20Sopenharmony_ci hdw->mpeg_ctrl_info = kcalloc(MPEGDEF_COUNT, 24548c2ecf20Sopenharmony_ci sizeof(*(hdw->mpeg_ctrl_info)), 24558c2ecf20Sopenharmony_ci GFP_KERNEL); 24568c2ecf20Sopenharmony_ci if (!hdw->mpeg_ctrl_info) goto fail; 24578c2ecf20Sopenharmony_ci for (idx = 0; idx < MPEGDEF_COUNT; idx++) { 24588c2ecf20Sopenharmony_ci cptr = hdw->controls + idx + CTRLDEF_COUNT; 24598c2ecf20Sopenharmony_ci ciptr = &(hdw->mpeg_ctrl_info[idx].info); 24608c2ecf20Sopenharmony_ci ciptr->desc = hdw->mpeg_ctrl_info[idx].desc; 24618c2ecf20Sopenharmony_ci ciptr->name = mpeg_ids[idx].strid; 24628c2ecf20Sopenharmony_ci ciptr->v4l_id = mpeg_ids[idx].id; 24638c2ecf20Sopenharmony_ci ciptr->skip_init = !0; 24648c2ecf20Sopenharmony_ci ciptr->get_value = ctrl_cx2341x_get; 24658c2ecf20Sopenharmony_ci ciptr->get_v4lflags = ctrl_cx2341x_getv4lflags; 24668c2ecf20Sopenharmony_ci ciptr->is_dirty = ctrl_cx2341x_is_dirty; 24678c2ecf20Sopenharmony_ci if (!idx) ciptr->clear_dirty = ctrl_cx2341x_clear_dirty; 24688c2ecf20Sopenharmony_ci qctrl.id = ciptr->v4l_id; 24698c2ecf20Sopenharmony_ci cx2341x_ctrl_query(&hdw->enc_ctl_state,&qctrl); 24708c2ecf20Sopenharmony_ci if (!(qctrl.flags & V4L2_CTRL_FLAG_READ_ONLY)) { 24718c2ecf20Sopenharmony_ci ciptr->set_value = ctrl_cx2341x_set; 24728c2ecf20Sopenharmony_ci } 24738c2ecf20Sopenharmony_ci strscpy(hdw->mpeg_ctrl_info[idx].desc, qctrl.name, 24748c2ecf20Sopenharmony_ci sizeof(hdw->mpeg_ctrl_info[idx].desc)); 24758c2ecf20Sopenharmony_ci ciptr->default_value = qctrl.default_value; 24768c2ecf20Sopenharmony_ci switch (qctrl.type) { 24778c2ecf20Sopenharmony_ci default: 24788c2ecf20Sopenharmony_ci case V4L2_CTRL_TYPE_INTEGER: 24798c2ecf20Sopenharmony_ci ciptr->type = pvr2_ctl_int; 24808c2ecf20Sopenharmony_ci ciptr->def.type_int.min_value = qctrl.minimum; 24818c2ecf20Sopenharmony_ci ciptr->def.type_int.max_value = qctrl.maximum; 24828c2ecf20Sopenharmony_ci break; 24838c2ecf20Sopenharmony_ci case V4L2_CTRL_TYPE_BOOLEAN: 24848c2ecf20Sopenharmony_ci ciptr->type = pvr2_ctl_bool; 24858c2ecf20Sopenharmony_ci break; 24868c2ecf20Sopenharmony_ci case V4L2_CTRL_TYPE_MENU: 24878c2ecf20Sopenharmony_ci ciptr->type = pvr2_ctl_enum; 24888c2ecf20Sopenharmony_ci ciptr->def.type_enum.value_names = 24898c2ecf20Sopenharmony_ci cx2341x_ctrl_get_menu(&hdw->enc_ctl_state, 24908c2ecf20Sopenharmony_ci ciptr->v4l_id); 24918c2ecf20Sopenharmony_ci for (cnt1 = 0; 24928c2ecf20Sopenharmony_ci ciptr->def.type_enum.value_names[cnt1] != NULL; 24938c2ecf20Sopenharmony_ci cnt1++) { } 24948c2ecf20Sopenharmony_ci ciptr->def.type_enum.count = cnt1; 24958c2ecf20Sopenharmony_ci break; 24968c2ecf20Sopenharmony_ci } 24978c2ecf20Sopenharmony_ci cptr->info = ciptr; 24988c2ecf20Sopenharmony_ci } 24998c2ecf20Sopenharmony_ci 25008c2ecf20Sopenharmony_ci // Initialize control data regarding video standard masks 25018c2ecf20Sopenharmony_ci valid_std_mask = pvr2_std_get_usable(); 25028c2ecf20Sopenharmony_ci for (idx = 0; idx < 32; idx++) { 25038c2ecf20Sopenharmony_ci if (!(valid_std_mask & (1UL << idx))) continue; 25048c2ecf20Sopenharmony_ci cnt1 = pvr2_std_id_to_str( 25058c2ecf20Sopenharmony_ci hdw->std_mask_names[idx], 25068c2ecf20Sopenharmony_ci sizeof(hdw->std_mask_names[idx])-1, 25078c2ecf20Sopenharmony_ci 1UL << idx); 25088c2ecf20Sopenharmony_ci hdw->std_mask_names[idx][cnt1] = 0; 25098c2ecf20Sopenharmony_ci } 25108c2ecf20Sopenharmony_ci cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDAVAIL); 25118c2ecf20Sopenharmony_ci if (cptr) { 25128c2ecf20Sopenharmony_ci memcpy(&hdw->std_info_avail,cptr->info, 25138c2ecf20Sopenharmony_ci sizeof(hdw->std_info_avail)); 25148c2ecf20Sopenharmony_ci cptr->info = &hdw->std_info_avail; 25158c2ecf20Sopenharmony_ci hdw->std_info_avail.def.type_bitmask.bit_names = 25168c2ecf20Sopenharmony_ci hdw->std_mask_ptrs; 25178c2ecf20Sopenharmony_ci hdw->std_info_avail.def.type_bitmask.valid_bits = 25188c2ecf20Sopenharmony_ci valid_std_mask; 25198c2ecf20Sopenharmony_ci } 25208c2ecf20Sopenharmony_ci cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR); 25218c2ecf20Sopenharmony_ci if (cptr) { 25228c2ecf20Sopenharmony_ci memcpy(&hdw->std_info_cur,cptr->info, 25238c2ecf20Sopenharmony_ci sizeof(hdw->std_info_cur)); 25248c2ecf20Sopenharmony_ci cptr->info = &hdw->std_info_cur; 25258c2ecf20Sopenharmony_ci hdw->std_info_cur.def.type_bitmask.bit_names = 25268c2ecf20Sopenharmony_ci hdw->std_mask_ptrs; 25278c2ecf20Sopenharmony_ci hdw->std_info_cur.def.type_bitmask.valid_bits = 25288c2ecf20Sopenharmony_ci valid_std_mask; 25298c2ecf20Sopenharmony_ci } 25308c2ecf20Sopenharmony_ci cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDDETECT); 25318c2ecf20Sopenharmony_ci if (cptr) { 25328c2ecf20Sopenharmony_ci memcpy(&hdw->std_info_detect,cptr->info, 25338c2ecf20Sopenharmony_ci sizeof(hdw->std_info_detect)); 25348c2ecf20Sopenharmony_ci cptr->info = &hdw->std_info_detect; 25358c2ecf20Sopenharmony_ci hdw->std_info_detect.def.type_bitmask.bit_names = 25368c2ecf20Sopenharmony_ci hdw->std_mask_ptrs; 25378c2ecf20Sopenharmony_ci hdw->std_info_detect.def.type_bitmask.valid_bits = 25388c2ecf20Sopenharmony_ci valid_std_mask; 25398c2ecf20Sopenharmony_ci } 25408c2ecf20Sopenharmony_ci 25418c2ecf20Sopenharmony_ci hdw->cropcap_stale = !0; 25428c2ecf20Sopenharmony_ci hdw->eeprom_addr = -1; 25438c2ecf20Sopenharmony_ci hdw->unit_number = -1; 25448c2ecf20Sopenharmony_ci hdw->v4l_minor_number_video = -1; 25458c2ecf20Sopenharmony_ci hdw->v4l_minor_number_vbi = -1; 25468c2ecf20Sopenharmony_ci hdw->v4l_minor_number_radio = -1; 25478c2ecf20Sopenharmony_ci hdw->ctl_write_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL); 25488c2ecf20Sopenharmony_ci if (!hdw->ctl_write_buffer) goto fail; 25498c2ecf20Sopenharmony_ci hdw->ctl_read_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL); 25508c2ecf20Sopenharmony_ci if (!hdw->ctl_read_buffer) goto fail; 25518c2ecf20Sopenharmony_ci hdw->ctl_write_urb = usb_alloc_urb(0,GFP_KERNEL); 25528c2ecf20Sopenharmony_ci if (!hdw->ctl_write_urb) goto fail; 25538c2ecf20Sopenharmony_ci hdw->ctl_read_urb = usb_alloc_urb(0,GFP_KERNEL); 25548c2ecf20Sopenharmony_ci if (!hdw->ctl_read_urb) goto fail; 25558c2ecf20Sopenharmony_ci 25568c2ecf20Sopenharmony_ci if (v4l2_device_register(&intf->dev, &hdw->v4l2_dev) != 0) { 25578c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 25588c2ecf20Sopenharmony_ci "Error registering with v4l core, giving up"); 25598c2ecf20Sopenharmony_ci goto fail; 25608c2ecf20Sopenharmony_ci } 25618c2ecf20Sopenharmony_ci mutex_lock(&pvr2_unit_mtx); 25628c2ecf20Sopenharmony_ci do { 25638c2ecf20Sopenharmony_ci for (idx = 0; idx < PVR_NUM; idx++) { 25648c2ecf20Sopenharmony_ci if (unit_pointers[idx]) continue; 25658c2ecf20Sopenharmony_ci hdw->unit_number = idx; 25668c2ecf20Sopenharmony_ci unit_pointers[idx] = hdw; 25678c2ecf20Sopenharmony_ci break; 25688c2ecf20Sopenharmony_ci } 25698c2ecf20Sopenharmony_ci } while (0); 25708c2ecf20Sopenharmony_ci mutex_unlock(&pvr2_unit_mtx); 25718c2ecf20Sopenharmony_ci 25728c2ecf20Sopenharmony_ci INIT_WORK(&hdw->workpoll, pvr2_hdw_worker_poll); 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_ci if (hdw->unit_number == -1) 25758c2ecf20Sopenharmony_ci goto fail; 25768c2ecf20Sopenharmony_ci 25778c2ecf20Sopenharmony_ci cnt1 = 0; 25788c2ecf20Sopenharmony_ci cnt2 = scnprintf(hdw->name+cnt1,sizeof(hdw->name)-cnt1,"pvrusb2"); 25798c2ecf20Sopenharmony_ci cnt1 += cnt2; 25808c2ecf20Sopenharmony_ci if (hdw->unit_number >= 0) { 25818c2ecf20Sopenharmony_ci cnt2 = scnprintf(hdw->name+cnt1,sizeof(hdw->name)-cnt1,"_%c", 25828c2ecf20Sopenharmony_ci ('a' + hdw->unit_number)); 25838c2ecf20Sopenharmony_ci cnt1 += cnt2; 25848c2ecf20Sopenharmony_ci } 25858c2ecf20Sopenharmony_ci if (cnt1 >= sizeof(hdw->name)) cnt1 = sizeof(hdw->name)-1; 25868c2ecf20Sopenharmony_ci hdw->name[cnt1] = 0; 25878c2ecf20Sopenharmony_ci 25888c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s", 25898c2ecf20Sopenharmony_ci hdw->unit_number,hdw->name); 25908c2ecf20Sopenharmony_ci 25918c2ecf20Sopenharmony_ci hdw->tuner_type = -1; 25928c2ecf20Sopenharmony_ci hdw->flag_ok = !0; 25938c2ecf20Sopenharmony_ci 25948c2ecf20Sopenharmony_ci hdw->usb_intf = intf; 25958c2ecf20Sopenharmony_ci hdw->usb_dev = usb_dev; 25968c2ecf20Sopenharmony_ci 25978c2ecf20Sopenharmony_ci usb_make_path(hdw->usb_dev, hdw->bus_info, sizeof(hdw->bus_info)); 25988c2ecf20Sopenharmony_ci 25998c2ecf20Sopenharmony_ci ifnum = hdw->usb_intf->cur_altsetting->desc.bInterfaceNumber; 26008c2ecf20Sopenharmony_ci usb_set_interface(hdw->usb_dev,ifnum,0); 26018c2ecf20Sopenharmony_ci 26028c2ecf20Sopenharmony_ci mutex_init(&hdw->ctl_lock_mutex); 26038c2ecf20Sopenharmony_ci mutex_init(&hdw->big_lock_mutex); 26048c2ecf20Sopenharmony_ci 26058c2ecf20Sopenharmony_ci return hdw; 26068c2ecf20Sopenharmony_ci fail: 26078c2ecf20Sopenharmony_ci if (hdw) { 26088c2ecf20Sopenharmony_ci del_timer_sync(&hdw->quiescent_timer); 26098c2ecf20Sopenharmony_ci del_timer_sync(&hdw->decoder_stabilization_timer); 26108c2ecf20Sopenharmony_ci del_timer_sync(&hdw->encoder_run_timer); 26118c2ecf20Sopenharmony_ci del_timer_sync(&hdw->encoder_wait_timer); 26128c2ecf20Sopenharmony_ci flush_work(&hdw->workpoll); 26138c2ecf20Sopenharmony_ci v4l2_device_unregister(&hdw->v4l2_dev); 26148c2ecf20Sopenharmony_ci usb_free_urb(hdw->ctl_read_urb); 26158c2ecf20Sopenharmony_ci usb_free_urb(hdw->ctl_write_urb); 26168c2ecf20Sopenharmony_ci kfree(hdw->ctl_read_buffer); 26178c2ecf20Sopenharmony_ci kfree(hdw->ctl_write_buffer); 26188c2ecf20Sopenharmony_ci kfree(hdw->controls); 26198c2ecf20Sopenharmony_ci kfree(hdw->mpeg_ctrl_info); 26208c2ecf20Sopenharmony_ci kfree(hdw); 26218c2ecf20Sopenharmony_ci } 26228c2ecf20Sopenharmony_ci return NULL; 26238c2ecf20Sopenharmony_ci} 26248c2ecf20Sopenharmony_ci 26258c2ecf20Sopenharmony_ci 26268c2ecf20Sopenharmony_ci/* Remove _all_ associations between this driver and the underlying USB 26278c2ecf20Sopenharmony_ci layer. */ 26288c2ecf20Sopenharmony_cistatic void pvr2_hdw_remove_usb_stuff(struct pvr2_hdw *hdw) 26298c2ecf20Sopenharmony_ci{ 26308c2ecf20Sopenharmony_ci if (hdw->flag_disconnected) return; 26318c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_remove_usb_stuff: hdw=%p",hdw); 26328c2ecf20Sopenharmony_ci if (hdw->ctl_read_urb) { 26338c2ecf20Sopenharmony_ci usb_kill_urb(hdw->ctl_read_urb); 26348c2ecf20Sopenharmony_ci usb_free_urb(hdw->ctl_read_urb); 26358c2ecf20Sopenharmony_ci hdw->ctl_read_urb = NULL; 26368c2ecf20Sopenharmony_ci } 26378c2ecf20Sopenharmony_ci if (hdw->ctl_write_urb) { 26388c2ecf20Sopenharmony_ci usb_kill_urb(hdw->ctl_write_urb); 26398c2ecf20Sopenharmony_ci usb_free_urb(hdw->ctl_write_urb); 26408c2ecf20Sopenharmony_ci hdw->ctl_write_urb = NULL; 26418c2ecf20Sopenharmony_ci } 26428c2ecf20Sopenharmony_ci if (hdw->ctl_read_buffer) { 26438c2ecf20Sopenharmony_ci kfree(hdw->ctl_read_buffer); 26448c2ecf20Sopenharmony_ci hdw->ctl_read_buffer = NULL; 26458c2ecf20Sopenharmony_ci } 26468c2ecf20Sopenharmony_ci if (hdw->ctl_write_buffer) { 26478c2ecf20Sopenharmony_ci kfree(hdw->ctl_write_buffer); 26488c2ecf20Sopenharmony_ci hdw->ctl_write_buffer = NULL; 26498c2ecf20Sopenharmony_ci } 26508c2ecf20Sopenharmony_ci hdw->flag_disconnected = !0; 26518c2ecf20Sopenharmony_ci /* If we don't do this, then there will be a dangling struct device 26528c2ecf20Sopenharmony_ci reference to our disappearing device persisting inside the V4L 26538c2ecf20Sopenharmony_ci core... */ 26548c2ecf20Sopenharmony_ci v4l2_device_disconnect(&hdw->v4l2_dev); 26558c2ecf20Sopenharmony_ci hdw->usb_dev = NULL; 26568c2ecf20Sopenharmony_ci hdw->usb_intf = NULL; 26578c2ecf20Sopenharmony_ci pvr2_hdw_render_useless(hdw); 26588c2ecf20Sopenharmony_ci} 26598c2ecf20Sopenharmony_ci 26608c2ecf20Sopenharmony_civoid pvr2_hdw_set_v4l2_dev(struct pvr2_hdw *hdw, struct video_device *vdev) 26618c2ecf20Sopenharmony_ci{ 26628c2ecf20Sopenharmony_ci vdev->v4l2_dev = &hdw->v4l2_dev; 26638c2ecf20Sopenharmony_ci} 26648c2ecf20Sopenharmony_ci 26658c2ecf20Sopenharmony_ci/* Destroy hardware interaction structure */ 26668c2ecf20Sopenharmony_civoid pvr2_hdw_destroy(struct pvr2_hdw *hdw) 26678c2ecf20Sopenharmony_ci{ 26688c2ecf20Sopenharmony_ci if (!hdw) return; 26698c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_destroy: hdw=%p",hdw); 26708c2ecf20Sopenharmony_ci flush_work(&hdw->workpoll); 26718c2ecf20Sopenharmony_ci del_timer_sync(&hdw->quiescent_timer); 26728c2ecf20Sopenharmony_ci del_timer_sync(&hdw->decoder_stabilization_timer); 26738c2ecf20Sopenharmony_ci del_timer_sync(&hdw->encoder_run_timer); 26748c2ecf20Sopenharmony_ci del_timer_sync(&hdw->encoder_wait_timer); 26758c2ecf20Sopenharmony_ci if (hdw->fw_buffer) { 26768c2ecf20Sopenharmony_ci kfree(hdw->fw_buffer); 26778c2ecf20Sopenharmony_ci hdw->fw_buffer = NULL; 26788c2ecf20Sopenharmony_ci } 26798c2ecf20Sopenharmony_ci if (hdw->vid_stream) { 26808c2ecf20Sopenharmony_ci pvr2_stream_destroy(hdw->vid_stream); 26818c2ecf20Sopenharmony_ci hdw->vid_stream = NULL; 26828c2ecf20Sopenharmony_ci } 26838c2ecf20Sopenharmony_ci v4l2_device_unregister(&hdw->v4l2_dev); 26848c2ecf20Sopenharmony_ci pvr2_hdw_disconnect(hdw); 26858c2ecf20Sopenharmony_ci mutex_lock(&pvr2_unit_mtx); 26868c2ecf20Sopenharmony_ci do { 26878c2ecf20Sopenharmony_ci if ((hdw->unit_number >= 0) && 26888c2ecf20Sopenharmony_ci (hdw->unit_number < PVR_NUM) && 26898c2ecf20Sopenharmony_ci (unit_pointers[hdw->unit_number] == hdw)) { 26908c2ecf20Sopenharmony_ci unit_pointers[hdw->unit_number] = NULL; 26918c2ecf20Sopenharmony_ci } 26928c2ecf20Sopenharmony_ci } while (0); 26938c2ecf20Sopenharmony_ci mutex_unlock(&pvr2_unit_mtx); 26948c2ecf20Sopenharmony_ci kfree(hdw->controls); 26958c2ecf20Sopenharmony_ci kfree(hdw->mpeg_ctrl_info); 26968c2ecf20Sopenharmony_ci kfree(hdw); 26978c2ecf20Sopenharmony_ci} 26988c2ecf20Sopenharmony_ci 26998c2ecf20Sopenharmony_ci 27008c2ecf20Sopenharmony_ciint pvr2_hdw_dev_ok(struct pvr2_hdw *hdw) 27018c2ecf20Sopenharmony_ci{ 27028c2ecf20Sopenharmony_ci return (hdw && hdw->flag_ok); 27038c2ecf20Sopenharmony_ci} 27048c2ecf20Sopenharmony_ci 27058c2ecf20Sopenharmony_ci 27068c2ecf20Sopenharmony_ci/* Called when hardware has been unplugged */ 27078c2ecf20Sopenharmony_civoid pvr2_hdw_disconnect(struct pvr2_hdw *hdw) 27088c2ecf20Sopenharmony_ci{ 27098c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_disconnect(hdw=%p)",hdw); 27108c2ecf20Sopenharmony_ci LOCK_TAKE(hdw->big_lock); 27118c2ecf20Sopenharmony_ci pvr2_i2c_core_done(hdw); 27128c2ecf20Sopenharmony_ci LOCK_TAKE(hdw->ctl_lock); 27138c2ecf20Sopenharmony_ci pvr2_hdw_remove_usb_stuff(hdw); 27148c2ecf20Sopenharmony_ci LOCK_GIVE(hdw->ctl_lock); 27158c2ecf20Sopenharmony_ci LOCK_GIVE(hdw->big_lock); 27168c2ecf20Sopenharmony_ci} 27178c2ecf20Sopenharmony_ci 27188c2ecf20Sopenharmony_ci 27198c2ecf20Sopenharmony_ci/* Get the number of defined controls */ 27208c2ecf20Sopenharmony_ciunsigned int pvr2_hdw_get_ctrl_count(struct pvr2_hdw *hdw) 27218c2ecf20Sopenharmony_ci{ 27228c2ecf20Sopenharmony_ci return hdw->control_cnt; 27238c2ecf20Sopenharmony_ci} 27248c2ecf20Sopenharmony_ci 27258c2ecf20Sopenharmony_ci 27268c2ecf20Sopenharmony_ci/* Retrieve a control handle given its index (0..count-1) */ 27278c2ecf20Sopenharmony_cistruct pvr2_ctrl *pvr2_hdw_get_ctrl_by_index(struct pvr2_hdw *hdw, 27288c2ecf20Sopenharmony_ci unsigned int idx) 27298c2ecf20Sopenharmony_ci{ 27308c2ecf20Sopenharmony_ci if (idx >= hdw->control_cnt) return NULL; 27318c2ecf20Sopenharmony_ci return hdw->controls + idx; 27328c2ecf20Sopenharmony_ci} 27338c2ecf20Sopenharmony_ci 27348c2ecf20Sopenharmony_ci 27358c2ecf20Sopenharmony_ci/* Retrieve a control handle given its index (0..count-1) */ 27368c2ecf20Sopenharmony_cistruct pvr2_ctrl *pvr2_hdw_get_ctrl_by_id(struct pvr2_hdw *hdw, 27378c2ecf20Sopenharmony_ci unsigned int ctl_id) 27388c2ecf20Sopenharmony_ci{ 27398c2ecf20Sopenharmony_ci struct pvr2_ctrl *cptr; 27408c2ecf20Sopenharmony_ci unsigned int idx; 27418c2ecf20Sopenharmony_ci int i; 27428c2ecf20Sopenharmony_ci 27438c2ecf20Sopenharmony_ci /* This could be made a lot more efficient, but for now... */ 27448c2ecf20Sopenharmony_ci for (idx = 0; idx < hdw->control_cnt; idx++) { 27458c2ecf20Sopenharmony_ci cptr = hdw->controls + idx; 27468c2ecf20Sopenharmony_ci i = cptr->info->internal_id; 27478c2ecf20Sopenharmony_ci if (i && (i == ctl_id)) return cptr; 27488c2ecf20Sopenharmony_ci } 27498c2ecf20Sopenharmony_ci return NULL; 27508c2ecf20Sopenharmony_ci} 27518c2ecf20Sopenharmony_ci 27528c2ecf20Sopenharmony_ci 27538c2ecf20Sopenharmony_ci/* Given a V4L ID, retrieve the control structure associated with it. */ 27548c2ecf20Sopenharmony_cistruct pvr2_ctrl *pvr2_hdw_get_ctrl_v4l(struct pvr2_hdw *hdw,unsigned int ctl_id) 27558c2ecf20Sopenharmony_ci{ 27568c2ecf20Sopenharmony_ci struct pvr2_ctrl *cptr; 27578c2ecf20Sopenharmony_ci unsigned int idx; 27588c2ecf20Sopenharmony_ci int i; 27598c2ecf20Sopenharmony_ci 27608c2ecf20Sopenharmony_ci /* This could be made a lot more efficient, but for now... */ 27618c2ecf20Sopenharmony_ci for (idx = 0; idx < hdw->control_cnt; idx++) { 27628c2ecf20Sopenharmony_ci cptr = hdw->controls + idx; 27638c2ecf20Sopenharmony_ci i = cptr->info->v4l_id; 27648c2ecf20Sopenharmony_ci if (i && (i == ctl_id)) return cptr; 27658c2ecf20Sopenharmony_ci } 27668c2ecf20Sopenharmony_ci return NULL; 27678c2ecf20Sopenharmony_ci} 27688c2ecf20Sopenharmony_ci 27698c2ecf20Sopenharmony_ci 27708c2ecf20Sopenharmony_ci/* Given a V4L ID for its immediate predecessor, retrieve the control 27718c2ecf20Sopenharmony_ci structure associated with it. */ 27728c2ecf20Sopenharmony_cistruct pvr2_ctrl *pvr2_hdw_get_ctrl_nextv4l(struct pvr2_hdw *hdw, 27738c2ecf20Sopenharmony_ci unsigned int ctl_id) 27748c2ecf20Sopenharmony_ci{ 27758c2ecf20Sopenharmony_ci struct pvr2_ctrl *cptr,*cp2; 27768c2ecf20Sopenharmony_ci unsigned int idx; 27778c2ecf20Sopenharmony_ci int i; 27788c2ecf20Sopenharmony_ci 27798c2ecf20Sopenharmony_ci /* This could be made a lot more efficient, but for now... */ 27808c2ecf20Sopenharmony_ci cp2 = NULL; 27818c2ecf20Sopenharmony_ci for (idx = 0; idx < hdw->control_cnt; idx++) { 27828c2ecf20Sopenharmony_ci cptr = hdw->controls + idx; 27838c2ecf20Sopenharmony_ci i = cptr->info->v4l_id; 27848c2ecf20Sopenharmony_ci if (!i) continue; 27858c2ecf20Sopenharmony_ci if (i <= ctl_id) continue; 27868c2ecf20Sopenharmony_ci if (cp2 && (cp2->info->v4l_id < i)) continue; 27878c2ecf20Sopenharmony_ci cp2 = cptr; 27888c2ecf20Sopenharmony_ci } 27898c2ecf20Sopenharmony_ci return cp2; 27908c2ecf20Sopenharmony_ci return NULL; 27918c2ecf20Sopenharmony_ci} 27928c2ecf20Sopenharmony_ci 27938c2ecf20Sopenharmony_ci 27948c2ecf20Sopenharmony_cistatic const char *get_ctrl_typename(enum pvr2_ctl_type tp) 27958c2ecf20Sopenharmony_ci{ 27968c2ecf20Sopenharmony_ci switch (tp) { 27978c2ecf20Sopenharmony_ci case pvr2_ctl_int: return "integer"; 27988c2ecf20Sopenharmony_ci case pvr2_ctl_enum: return "enum"; 27998c2ecf20Sopenharmony_ci case pvr2_ctl_bool: return "boolean"; 28008c2ecf20Sopenharmony_ci case pvr2_ctl_bitmask: return "bitmask"; 28018c2ecf20Sopenharmony_ci } 28028c2ecf20Sopenharmony_ci return ""; 28038c2ecf20Sopenharmony_ci} 28048c2ecf20Sopenharmony_ci 28058c2ecf20Sopenharmony_ci 28068c2ecf20Sopenharmony_cistatic void pvr2_subdev_set_control(struct pvr2_hdw *hdw, int id, 28078c2ecf20Sopenharmony_ci const char *name, int val) 28088c2ecf20Sopenharmony_ci{ 28098c2ecf20Sopenharmony_ci struct v4l2_control ctrl; 28108c2ecf20Sopenharmony_ci struct v4l2_subdev *sd; 28118c2ecf20Sopenharmony_ci 28128c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 %s=%d", name, val); 28138c2ecf20Sopenharmony_ci memset(&ctrl, 0, sizeof(ctrl)); 28148c2ecf20Sopenharmony_ci ctrl.id = id; 28158c2ecf20Sopenharmony_ci ctrl.value = val; 28168c2ecf20Sopenharmony_ci 28178c2ecf20Sopenharmony_ci v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) 28188c2ecf20Sopenharmony_ci v4l2_s_ctrl(NULL, sd->ctrl_handler, &ctrl); 28198c2ecf20Sopenharmony_ci} 28208c2ecf20Sopenharmony_ci 28218c2ecf20Sopenharmony_ci#define PVR2_SUBDEV_SET_CONTROL(hdw, id, lab) \ 28228c2ecf20Sopenharmony_ci if ((hdw)->lab##_dirty || (hdw)->force_dirty) { \ 28238c2ecf20Sopenharmony_ci pvr2_subdev_set_control(hdw, id, #lab, (hdw)->lab##_val); \ 28248c2ecf20Sopenharmony_ci } 28258c2ecf20Sopenharmony_ci 28268c2ecf20Sopenharmony_cistatic v4l2_std_id pvr2_hdw_get_detected_std(struct pvr2_hdw *hdw) 28278c2ecf20Sopenharmony_ci{ 28288c2ecf20Sopenharmony_ci v4l2_std_id std; 28298c2ecf20Sopenharmony_ci std = (v4l2_std_id)hdw->std_mask_avail; 28308c2ecf20Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, 0, 28318c2ecf20Sopenharmony_ci video, querystd, &std); 28328c2ecf20Sopenharmony_ci return std; 28338c2ecf20Sopenharmony_ci} 28348c2ecf20Sopenharmony_ci 28358c2ecf20Sopenharmony_ci/* Execute whatever commands are required to update the state of all the 28368c2ecf20Sopenharmony_ci sub-devices so that they match our current control values. */ 28378c2ecf20Sopenharmony_cistatic void pvr2_subdev_update(struct pvr2_hdw *hdw) 28388c2ecf20Sopenharmony_ci{ 28398c2ecf20Sopenharmony_ci struct v4l2_subdev *sd; 28408c2ecf20Sopenharmony_ci unsigned int id; 28418c2ecf20Sopenharmony_ci pvr2_subdev_update_func fp; 28428c2ecf20Sopenharmony_ci 28438c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_CHIPS, "subdev update..."); 28448c2ecf20Sopenharmony_ci 28458c2ecf20Sopenharmony_ci if (hdw->tuner_updated || hdw->force_dirty) { 28468c2ecf20Sopenharmony_ci struct tuner_setup setup; 28478c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_CHIPS, "subdev tuner set_type(%d)", 28488c2ecf20Sopenharmony_ci hdw->tuner_type); 28498c2ecf20Sopenharmony_ci if (((int)(hdw->tuner_type)) >= 0) { 28508c2ecf20Sopenharmony_ci memset(&setup, 0, sizeof(setup)); 28518c2ecf20Sopenharmony_ci setup.addr = ADDR_UNSET; 28528c2ecf20Sopenharmony_ci setup.type = hdw->tuner_type; 28538c2ecf20Sopenharmony_ci setup.mode_mask = T_RADIO | T_ANALOG_TV; 28548c2ecf20Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, 0, 28558c2ecf20Sopenharmony_ci tuner, s_type_addr, &setup); 28568c2ecf20Sopenharmony_ci } 28578c2ecf20Sopenharmony_ci } 28588c2ecf20Sopenharmony_ci 28598c2ecf20Sopenharmony_ci if (hdw->input_dirty || hdw->std_dirty || hdw->force_dirty) { 28608c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_standard"); 28618c2ecf20Sopenharmony_ci if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) { 28628c2ecf20Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, 0, 28638c2ecf20Sopenharmony_ci tuner, s_radio); 28648c2ecf20Sopenharmony_ci } else { 28658c2ecf20Sopenharmony_ci v4l2_std_id vs; 28668c2ecf20Sopenharmony_ci vs = hdw->std_mask_cur; 28678c2ecf20Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, 0, 28688c2ecf20Sopenharmony_ci video, s_std, vs); 28698c2ecf20Sopenharmony_ci pvr2_hdw_cx25840_vbi_hack(hdw); 28708c2ecf20Sopenharmony_ci } 28718c2ecf20Sopenharmony_ci hdw->tuner_signal_stale = !0; 28728c2ecf20Sopenharmony_ci hdw->cropcap_stale = !0; 28738c2ecf20Sopenharmony_ci } 28748c2ecf20Sopenharmony_ci 28758c2ecf20Sopenharmony_ci PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_BRIGHTNESS, brightness); 28768c2ecf20Sopenharmony_ci PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_CONTRAST, contrast); 28778c2ecf20Sopenharmony_ci PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_SATURATION, saturation); 28788c2ecf20Sopenharmony_ci PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_HUE, hue); 28798c2ecf20Sopenharmony_ci PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_MUTE, mute); 28808c2ecf20Sopenharmony_ci PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_VOLUME, volume); 28818c2ecf20Sopenharmony_ci PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_BALANCE, balance); 28828c2ecf20Sopenharmony_ci PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_BASS, bass); 28838c2ecf20Sopenharmony_ci PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_TREBLE, treble); 28848c2ecf20Sopenharmony_ci 28858c2ecf20Sopenharmony_ci if (hdw->input_dirty || hdw->audiomode_dirty || hdw->force_dirty) { 28868c2ecf20Sopenharmony_ci struct v4l2_tuner vt; 28878c2ecf20Sopenharmony_ci memset(&vt, 0, sizeof(vt)); 28888c2ecf20Sopenharmony_ci vt.type = (hdw->input_val == PVR2_CVAL_INPUT_RADIO) ? 28898c2ecf20Sopenharmony_ci V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; 28908c2ecf20Sopenharmony_ci vt.audmode = hdw->audiomode_val; 28918c2ecf20Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner, s_tuner, &vt); 28928c2ecf20Sopenharmony_ci } 28938c2ecf20Sopenharmony_ci 28948c2ecf20Sopenharmony_ci if (hdw->freqDirty || hdw->force_dirty) { 28958c2ecf20Sopenharmony_ci unsigned long fv; 28968c2ecf20Sopenharmony_ci struct v4l2_frequency freq; 28978c2ecf20Sopenharmony_ci fv = pvr2_hdw_get_cur_freq(hdw); 28988c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_freq(%lu)", fv); 28998c2ecf20Sopenharmony_ci if (hdw->tuner_signal_stale) pvr2_hdw_status_poll(hdw); 29008c2ecf20Sopenharmony_ci memset(&freq, 0, sizeof(freq)); 29018c2ecf20Sopenharmony_ci if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) { 29028c2ecf20Sopenharmony_ci /* ((fv * 1000) / 62500) */ 29038c2ecf20Sopenharmony_ci freq.frequency = (fv * 2) / 125; 29048c2ecf20Sopenharmony_ci } else { 29058c2ecf20Sopenharmony_ci freq.frequency = fv / 62500; 29068c2ecf20Sopenharmony_ci } 29078c2ecf20Sopenharmony_ci /* tuner-core currently doesn't seem to care about this, but 29088c2ecf20Sopenharmony_ci let's set it anyway for completeness. */ 29098c2ecf20Sopenharmony_ci if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) { 29108c2ecf20Sopenharmony_ci freq.type = V4L2_TUNER_RADIO; 29118c2ecf20Sopenharmony_ci } else { 29128c2ecf20Sopenharmony_ci freq.type = V4L2_TUNER_ANALOG_TV; 29138c2ecf20Sopenharmony_ci } 29148c2ecf20Sopenharmony_ci freq.tuner = 0; 29158c2ecf20Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner, 29168c2ecf20Sopenharmony_ci s_frequency, &freq); 29178c2ecf20Sopenharmony_ci } 29188c2ecf20Sopenharmony_ci 29198c2ecf20Sopenharmony_ci if (hdw->res_hor_dirty || hdw->res_ver_dirty || hdw->force_dirty) { 29208c2ecf20Sopenharmony_ci struct v4l2_subdev_format format = { 29218c2ecf20Sopenharmony_ci .which = V4L2_SUBDEV_FORMAT_ACTIVE, 29228c2ecf20Sopenharmony_ci }; 29238c2ecf20Sopenharmony_ci 29248c2ecf20Sopenharmony_ci format.format.width = hdw->res_hor_val; 29258c2ecf20Sopenharmony_ci format.format.height = hdw->res_ver_val; 29268c2ecf20Sopenharmony_ci format.format.code = MEDIA_BUS_FMT_FIXED; 29278c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_size(%dx%d)", 29288c2ecf20Sopenharmony_ci format.format.width, format.format.height); 29298c2ecf20Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, 0, pad, set_fmt, 29308c2ecf20Sopenharmony_ci NULL, &format); 29318c2ecf20Sopenharmony_ci } 29328c2ecf20Sopenharmony_ci 29338c2ecf20Sopenharmony_ci if (hdw->srate_dirty || hdw->force_dirty) { 29348c2ecf20Sopenharmony_ci u32 val; 29358c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_audio %d", 29368c2ecf20Sopenharmony_ci hdw->srate_val); 29378c2ecf20Sopenharmony_ci switch (hdw->srate_val) { 29388c2ecf20Sopenharmony_ci default: 29398c2ecf20Sopenharmony_ci case V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000: 29408c2ecf20Sopenharmony_ci val = 48000; 29418c2ecf20Sopenharmony_ci break; 29428c2ecf20Sopenharmony_ci case V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100: 29438c2ecf20Sopenharmony_ci val = 44100; 29448c2ecf20Sopenharmony_ci break; 29458c2ecf20Sopenharmony_ci case V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000: 29468c2ecf20Sopenharmony_ci val = 32000; 29478c2ecf20Sopenharmony_ci break; 29488c2ecf20Sopenharmony_ci } 29498c2ecf20Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, 0, 29508c2ecf20Sopenharmony_ci audio, s_clock_freq, val); 29518c2ecf20Sopenharmony_ci } 29528c2ecf20Sopenharmony_ci 29538c2ecf20Sopenharmony_ci /* Unable to set crop parameters; there is apparently no equivalent 29548c2ecf20Sopenharmony_ci for VIDIOC_S_CROP */ 29558c2ecf20Sopenharmony_ci 29568c2ecf20Sopenharmony_ci v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) { 29578c2ecf20Sopenharmony_ci id = sd->grp_id; 29588c2ecf20Sopenharmony_ci if (id >= ARRAY_SIZE(pvr2_module_update_functions)) continue; 29598c2ecf20Sopenharmony_ci fp = pvr2_module_update_functions[id]; 29608c2ecf20Sopenharmony_ci if (!fp) continue; 29618c2ecf20Sopenharmony_ci (*fp)(hdw, sd); 29628c2ecf20Sopenharmony_ci } 29638c2ecf20Sopenharmony_ci 29648c2ecf20Sopenharmony_ci if (hdw->tuner_signal_stale || hdw->cropcap_stale) { 29658c2ecf20Sopenharmony_ci pvr2_hdw_status_poll(hdw); 29668c2ecf20Sopenharmony_ci } 29678c2ecf20Sopenharmony_ci} 29688c2ecf20Sopenharmony_ci 29698c2ecf20Sopenharmony_ci 29708c2ecf20Sopenharmony_ci/* Figure out if we need to commit control changes. If so, mark internal 29718c2ecf20Sopenharmony_ci state flags to indicate this fact and return true. Otherwise do nothing 29728c2ecf20Sopenharmony_ci else and return false. */ 29738c2ecf20Sopenharmony_cistatic int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw) 29748c2ecf20Sopenharmony_ci{ 29758c2ecf20Sopenharmony_ci unsigned int idx; 29768c2ecf20Sopenharmony_ci struct pvr2_ctrl *cptr; 29778c2ecf20Sopenharmony_ci int value; 29788c2ecf20Sopenharmony_ci int commit_flag = hdw->force_dirty; 29798c2ecf20Sopenharmony_ci char buf[100]; 29808c2ecf20Sopenharmony_ci unsigned int bcnt,ccnt; 29818c2ecf20Sopenharmony_ci 29828c2ecf20Sopenharmony_ci for (idx = 0; idx < hdw->control_cnt; idx++) { 29838c2ecf20Sopenharmony_ci cptr = hdw->controls + idx; 29848c2ecf20Sopenharmony_ci if (!cptr->info->is_dirty) continue; 29858c2ecf20Sopenharmony_ci if (!cptr->info->is_dirty(cptr)) continue; 29868c2ecf20Sopenharmony_ci commit_flag = !0; 29878c2ecf20Sopenharmony_ci 29888c2ecf20Sopenharmony_ci if (!(pvrusb2_debug & PVR2_TRACE_CTL)) continue; 29898c2ecf20Sopenharmony_ci bcnt = scnprintf(buf,sizeof(buf),"\"%s\" <-- ", 29908c2ecf20Sopenharmony_ci cptr->info->name); 29918c2ecf20Sopenharmony_ci value = 0; 29928c2ecf20Sopenharmony_ci cptr->info->get_value(cptr,&value); 29938c2ecf20Sopenharmony_ci pvr2_ctrl_value_to_sym_internal(cptr,~0,value, 29948c2ecf20Sopenharmony_ci buf+bcnt, 29958c2ecf20Sopenharmony_ci sizeof(buf)-bcnt,&ccnt); 29968c2ecf20Sopenharmony_ci bcnt += ccnt; 29978c2ecf20Sopenharmony_ci bcnt += scnprintf(buf+bcnt,sizeof(buf)-bcnt," <%s>", 29988c2ecf20Sopenharmony_ci get_ctrl_typename(cptr->info->type)); 29998c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_CTL, 30008c2ecf20Sopenharmony_ci "/*--TRACE_COMMIT--*/ %.*s", 30018c2ecf20Sopenharmony_ci bcnt,buf); 30028c2ecf20Sopenharmony_ci } 30038c2ecf20Sopenharmony_ci 30048c2ecf20Sopenharmony_ci if (!commit_flag) { 30058c2ecf20Sopenharmony_ci /* Nothing has changed */ 30068c2ecf20Sopenharmony_ci return 0; 30078c2ecf20Sopenharmony_ci } 30088c2ecf20Sopenharmony_ci 30098c2ecf20Sopenharmony_ci hdw->state_pipeline_config = 0; 30108c2ecf20Sopenharmony_ci trace_stbit("state_pipeline_config",hdw->state_pipeline_config); 30118c2ecf20Sopenharmony_ci pvr2_hdw_state_sched(hdw); 30128c2ecf20Sopenharmony_ci 30138c2ecf20Sopenharmony_ci return !0; 30148c2ecf20Sopenharmony_ci} 30158c2ecf20Sopenharmony_ci 30168c2ecf20Sopenharmony_ci 30178c2ecf20Sopenharmony_ci/* Perform all operations needed to commit all control changes. This must 30188c2ecf20Sopenharmony_ci be performed in synchronization with the pipeline state and is thus 30198c2ecf20Sopenharmony_ci expected to be called as part of the driver's worker thread. Return 30208c2ecf20Sopenharmony_ci true if commit successful, otherwise return false to indicate that 30218c2ecf20Sopenharmony_ci commit isn't possible at this time. */ 30228c2ecf20Sopenharmony_cistatic int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw) 30238c2ecf20Sopenharmony_ci{ 30248c2ecf20Sopenharmony_ci unsigned int idx; 30258c2ecf20Sopenharmony_ci struct pvr2_ctrl *cptr; 30268c2ecf20Sopenharmony_ci int disruptive_change; 30278c2ecf20Sopenharmony_ci 30288c2ecf20Sopenharmony_ci if (hdw->input_dirty && hdw->state_pathway_ok && 30298c2ecf20Sopenharmony_ci (((hdw->input_val == PVR2_CVAL_INPUT_DTV) ? 30308c2ecf20Sopenharmony_ci PVR2_PATHWAY_DIGITAL : PVR2_PATHWAY_ANALOG) != 30318c2ecf20Sopenharmony_ci hdw->pathway_state)) { 30328c2ecf20Sopenharmony_ci /* Change of mode being asked for... */ 30338c2ecf20Sopenharmony_ci hdw->state_pathway_ok = 0; 30348c2ecf20Sopenharmony_ci trace_stbit("state_pathway_ok", hdw->state_pathway_ok); 30358c2ecf20Sopenharmony_ci } 30368c2ecf20Sopenharmony_ci if (!hdw->state_pathway_ok) { 30378c2ecf20Sopenharmony_ci /* Can't commit anything until pathway is ok. */ 30388c2ecf20Sopenharmony_ci return 0; 30398c2ecf20Sopenharmony_ci } 30408c2ecf20Sopenharmony_ci 30418c2ecf20Sopenharmony_ci /* Handle some required side effects when the video standard is 30428c2ecf20Sopenharmony_ci changed.... */ 30438c2ecf20Sopenharmony_ci if (hdw->std_dirty) { 30448c2ecf20Sopenharmony_ci int nvres; 30458c2ecf20Sopenharmony_ci int gop_size; 30468c2ecf20Sopenharmony_ci if (hdw->std_mask_cur & V4L2_STD_525_60) { 30478c2ecf20Sopenharmony_ci nvres = 480; 30488c2ecf20Sopenharmony_ci gop_size = 15; 30498c2ecf20Sopenharmony_ci } else { 30508c2ecf20Sopenharmony_ci nvres = 576; 30518c2ecf20Sopenharmony_ci gop_size = 12; 30528c2ecf20Sopenharmony_ci } 30538c2ecf20Sopenharmony_ci /* Rewrite the vertical resolution to be appropriate to the 30548c2ecf20Sopenharmony_ci video standard that has been selected. */ 30558c2ecf20Sopenharmony_ci if (nvres != hdw->res_ver_val) { 30568c2ecf20Sopenharmony_ci hdw->res_ver_val = nvres; 30578c2ecf20Sopenharmony_ci hdw->res_ver_dirty = !0; 30588c2ecf20Sopenharmony_ci } 30598c2ecf20Sopenharmony_ci /* Rewrite the GOP size to be appropriate to the video 30608c2ecf20Sopenharmony_ci standard that has been selected. */ 30618c2ecf20Sopenharmony_ci if (gop_size != hdw->enc_ctl_state.video_gop_size) { 30628c2ecf20Sopenharmony_ci struct v4l2_ext_controls cs; 30638c2ecf20Sopenharmony_ci struct v4l2_ext_control c1; 30648c2ecf20Sopenharmony_ci memset(&cs, 0, sizeof(cs)); 30658c2ecf20Sopenharmony_ci memset(&c1, 0, sizeof(c1)); 30668c2ecf20Sopenharmony_ci cs.controls = &c1; 30678c2ecf20Sopenharmony_ci cs.count = 1; 30688c2ecf20Sopenharmony_ci c1.id = V4L2_CID_MPEG_VIDEO_GOP_SIZE; 30698c2ecf20Sopenharmony_ci c1.value = gop_size; 30708c2ecf20Sopenharmony_ci cx2341x_ext_ctrls(&hdw->enc_ctl_state, 0, &cs, 30718c2ecf20Sopenharmony_ci VIDIOC_S_EXT_CTRLS); 30728c2ecf20Sopenharmony_ci } 30738c2ecf20Sopenharmony_ci } 30748c2ecf20Sopenharmony_ci 30758c2ecf20Sopenharmony_ci /* The broadcast decoder can only scale down, so if 30768c2ecf20Sopenharmony_ci * res_*_dirty && crop window < output format ==> enlarge crop. 30778c2ecf20Sopenharmony_ci * 30788c2ecf20Sopenharmony_ci * The mpeg encoder receives fields of res_hor_val dots and 30798c2ecf20Sopenharmony_ci * res_ver_val halflines. Limits: hor<=720, ver<=576. 30808c2ecf20Sopenharmony_ci */ 30818c2ecf20Sopenharmony_ci if (hdw->res_hor_dirty && hdw->cropw_val < hdw->res_hor_val) { 30828c2ecf20Sopenharmony_ci hdw->cropw_val = hdw->res_hor_val; 30838c2ecf20Sopenharmony_ci hdw->cropw_dirty = !0; 30848c2ecf20Sopenharmony_ci } else if (hdw->cropw_dirty) { 30858c2ecf20Sopenharmony_ci hdw->res_hor_dirty = !0; /* must rescale */ 30868c2ecf20Sopenharmony_ci hdw->res_hor_val = min(720, hdw->cropw_val); 30878c2ecf20Sopenharmony_ci } 30888c2ecf20Sopenharmony_ci if (hdw->res_ver_dirty && hdw->croph_val < hdw->res_ver_val) { 30898c2ecf20Sopenharmony_ci hdw->croph_val = hdw->res_ver_val; 30908c2ecf20Sopenharmony_ci hdw->croph_dirty = !0; 30918c2ecf20Sopenharmony_ci } else if (hdw->croph_dirty) { 30928c2ecf20Sopenharmony_ci int nvres = hdw->std_mask_cur & V4L2_STD_525_60 ? 480 : 576; 30938c2ecf20Sopenharmony_ci hdw->res_ver_dirty = !0; 30948c2ecf20Sopenharmony_ci hdw->res_ver_val = min(nvres, hdw->croph_val); 30958c2ecf20Sopenharmony_ci } 30968c2ecf20Sopenharmony_ci 30978c2ecf20Sopenharmony_ci /* If any of the below has changed, then we can't do the update 30988c2ecf20Sopenharmony_ci while the pipeline is running. Pipeline must be paused first 30998c2ecf20Sopenharmony_ci and decoder -> encoder connection be made quiescent before we 31008c2ecf20Sopenharmony_ci can proceed. */ 31018c2ecf20Sopenharmony_ci disruptive_change = 31028c2ecf20Sopenharmony_ci (hdw->std_dirty || 31038c2ecf20Sopenharmony_ci hdw->enc_unsafe_stale || 31048c2ecf20Sopenharmony_ci hdw->srate_dirty || 31058c2ecf20Sopenharmony_ci hdw->res_ver_dirty || 31068c2ecf20Sopenharmony_ci hdw->res_hor_dirty || 31078c2ecf20Sopenharmony_ci hdw->cropw_dirty || 31088c2ecf20Sopenharmony_ci hdw->croph_dirty || 31098c2ecf20Sopenharmony_ci hdw->input_dirty || 31108c2ecf20Sopenharmony_ci (hdw->active_stream_type != hdw->desired_stream_type)); 31118c2ecf20Sopenharmony_ci if (disruptive_change && !hdw->state_pipeline_idle) { 31128c2ecf20Sopenharmony_ci /* Pipeline is not idle; we can't proceed. Arrange to 31138c2ecf20Sopenharmony_ci cause pipeline to stop so that we can try this again 31148c2ecf20Sopenharmony_ci later.... */ 31158c2ecf20Sopenharmony_ci hdw->state_pipeline_pause = !0; 31168c2ecf20Sopenharmony_ci return 0; 31178c2ecf20Sopenharmony_ci } 31188c2ecf20Sopenharmony_ci 31198c2ecf20Sopenharmony_ci if (hdw->srate_dirty) { 31208c2ecf20Sopenharmony_ci /* Write new sample rate into control structure since 31218c2ecf20Sopenharmony_ci * the master copy is stale. We must track srate 31228c2ecf20Sopenharmony_ci * separate from the mpeg control structure because 31238c2ecf20Sopenharmony_ci * other logic also uses this value. */ 31248c2ecf20Sopenharmony_ci struct v4l2_ext_controls cs; 31258c2ecf20Sopenharmony_ci struct v4l2_ext_control c1; 31268c2ecf20Sopenharmony_ci memset(&cs,0,sizeof(cs)); 31278c2ecf20Sopenharmony_ci memset(&c1,0,sizeof(c1)); 31288c2ecf20Sopenharmony_ci cs.controls = &c1; 31298c2ecf20Sopenharmony_ci cs.count = 1; 31308c2ecf20Sopenharmony_ci c1.id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ; 31318c2ecf20Sopenharmony_ci c1.value = hdw->srate_val; 31328c2ecf20Sopenharmony_ci cx2341x_ext_ctrls(&hdw->enc_ctl_state, 0, &cs,VIDIOC_S_EXT_CTRLS); 31338c2ecf20Sopenharmony_ci } 31348c2ecf20Sopenharmony_ci 31358c2ecf20Sopenharmony_ci if (hdw->active_stream_type != hdw->desired_stream_type) { 31368c2ecf20Sopenharmony_ci /* Handle any side effects of stream config here */ 31378c2ecf20Sopenharmony_ci hdw->active_stream_type = hdw->desired_stream_type; 31388c2ecf20Sopenharmony_ci } 31398c2ecf20Sopenharmony_ci 31408c2ecf20Sopenharmony_ci if (hdw->hdw_desc->signal_routing_scheme == 31418c2ecf20Sopenharmony_ci PVR2_ROUTING_SCHEME_GOTVIEW) { 31428c2ecf20Sopenharmony_ci u32 b; 31438c2ecf20Sopenharmony_ci /* Handle GOTVIEW audio switching */ 31448c2ecf20Sopenharmony_ci pvr2_hdw_gpio_get_out(hdw,&b); 31458c2ecf20Sopenharmony_ci if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) { 31468c2ecf20Sopenharmony_ci /* Set GPIO 11 */ 31478c2ecf20Sopenharmony_ci pvr2_hdw_gpio_chg_out(hdw,(1 << 11),~0); 31488c2ecf20Sopenharmony_ci } else { 31498c2ecf20Sopenharmony_ci /* Clear GPIO 11 */ 31508c2ecf20Sopenharmony_ci pvr2_hdw_gpio_chg_out(hdw,(1 << 11),0); 31518c2ecf20Sopenharmony_ci } 31528c2ecf20Sopenharmony_ci } 31538c2ecf20Sopenharmony_ci 31548c2ecf20Sopenharmony_ci /* Check and update state for all sub-devices. */ 31558c2ecf20Sopenharmony_ci pvr2_subdev_update(hdw); 31568c2ecf20Sopenharmony_ci 31578c2ecf20Sopenharmony_ci hdw->tuner_updated = 0; 31588c2ecf20Sopenharmony_ci hdw->force_dirty = 0; 31598c2ecf20Sopenharmony_ci for (idx = 0; idx < hdw->control_cnt; idx++) { 31608c2ecf20Sopenharmony_ci cptr = hdw->controls + idx; 31618c2ecf20Sopenharmony_ci if (!cptr->info->clear_dirty) continue; 31628c2ecf20Sopenharmony_ci cptr->info->clear_dirty(cptr); 31638c2ecf20Sopenharmony_ci } 31648c2ecf20Sopenharmony_ci 31658c2ecf20Sopenharmony_ci if ((hdw->pathway_state == PVR2_PATHWAY_ANALOG) && 31668c2ecf20Sopenharmony_ci hdw->state_encoder_run) { 31678c2ecf20Sopenharmony_ci /* If encoder isn't running or it can't be touched, then 31688c2ecf20Sopenharmony_ci this will get worked out later when we start the 31698c2ecf20Sopenharmony_ci encoder. */ 31708c2ecf20Sopenharmony_ci if (pvr2_encoder_adjust(hdw) < 0) return !0; 31718c2ecf20Sopenharmony_ci } 31728c2ecf20Sopenharmony_ci 31738c2ecf20Sopenharmony_ci hdw->state_pipeline_config = !0; 31748c2ecf20Sopenharmony_ci /* Hardware state may have changed in a way to cause the cropping 31758c2ecf20Sopenharmony_ci capabilities to have changed. So mark it stale, which will 31768c2ecf20Sopenharmony_ci cause a later re-fetch. */ 31778c2ecf20Sopenharmony_ci trace_stbit("state_pipeline_config",hdw->state_pipeline_config); 31788c2ecf20Sopenharmony_ci return !0; 31798c2ecf20Sopenharmony_ci} 31808c2ecf20Sopenharmony_ci 31818c2ecf20Sopenharmony_ci 31828c2ecf20Sopenharmony_ciint pvr2_hdw_commit_ctl(struct pvr2_hdw *hdw) 31838c2ecf20Sopenharmony_ci{ 31848c2ecf20Sopenharmony_ci int fl; 31858c2ecf20Sopenharmony_ci LOCK_TAKE(hdw->big_lock); 31868c2ecf20Sopenharmony_ci fl = pvr2_hdw_commit_setup(hdw); 31878c2ecf20Sopenharmony_ci LOCK_GIVE(hdw->big_lock); 31888c2ecf20Sopenharmony_ci if (!fl) return 0; 31898c2ecf20Sopenharmony_ci return pvr2_hdw_wait(hdw,0); 31908c2ecf20Sopenharmony_ci} 31918c2ecf20Sopenharmony_ci 31928c2ecf20Sopenharmony_ci 31938c2ecf20Sopenharmony_cistatic void pvr2_hdw_worker_poll(struct work_struct *work) 31948c2ecf20Sopenharmony_ci{ 31958c2ecf20Sopenharmony_ci int fl = 0; 31968c2ecf20Sopenharmony_ci struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,workpoll); 31978c2ecf20Sopenharmony_ci LOCK_TAKE(hdw->big_lock); do { 31988c2ecf20Sopenharmony_ci fl = pvr2_hdw_state_eval(hdw); 31998c2ecf20Sopenharmony_ci } while (0); LOCK_GIVE(hdw->big_lock); 32008c2ecf20Sopenharmony_ci if (fl && hdw->state_func) { 32018c2ecf20Sopenharmony_ci hdw->state_func(hdw->state_data); 32028c2ecf20Sopenharmony_ci } 32038c2ecf20Sopenharmony_ci} 32048c2ecf20Sopenharmony_ci 32058c2ecf20Sopenharmony_ci 32068c2ecf20Sopenharmony_cistatic int pvr2_hdw_wait(struct pvr2_hdw *hdw,int state) 32078c2ecf20Sopenharmony_ci{ 32088c2ecf20Sopenharmony_ci return wait_event_interruptible( 32098c2ecf20Sopenharmony_ci hdw->state_wait_data, 32108c2ecf20Sopenharmony_ci (hdw->state_stale == 0) && 32118c2ecf20Sopenharmony_ci (!state || (hdw->master_state != state))); 32128c2ecf20Sopenharmony_ci} 32138c2ecf20Sopenharmony_ci 32148c2ecf20Sopenharmony_ci 32158c2ecf20Sopenharmony_ci/* Return name for this driver instance */ 32168c2ecf20Sopenharmony_ciconst char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw) 32178c2ecf20Sopenharmony_ci{ 32188c2ecf20Sopenharmony_ci return hdw->name; 32198c2ecf20Sopenharmony_ci} 32208c2ecf20Sopenharmony_ci 32218c2ecf20Sopenharmony_ci 32228c2ecf20Sopenharmony_ciconst char *pvr2_hdw_get_desc(struct pvr2_hdw *hdw) 32238c2ecf20Sopenharmony_ci{ 32248c2ecf20Sopenharmony_ci return hdw->hdw_desc->description; 32258c2ecf20Sopenharmony_ci} 32268c2ecf20Sopenharmony_ci 32278c2ecf20Sopenharmony_ci 32288c2ecf20Sopenharmony_ciconst char *pvr2_hdw_get_type(struct pvr2_hdw *hdw) 32298c2ecf20Sopenharmony_ci{ 32308c2ecf20Sopenharmony_ci return hdw->hdw_desc->shortname; 32318c2ecf20Sopenharmony_ci} 32328c2ecf20Sopenharmony_ci 32338c2ecf20Sopenharmony_ci 32348c2ecf20Sopenharmony_ciint pvr2_hdw_is_hsm(struct pvr2_hdw *hdw) 32358c2ecf20Sopenharmony_ci{ 32368c2ecf20Sopenharmony_ci int result; 32378c2ecf20Sopenharmony_ci LOCK_TAKE(hdw->ctl_lock); do { 32388c2ecf20Sopenharmony_ci hdw->cmd_buffer[0] = FX2CMD_GET_USB_SPEED; 32398c2ecf20Sopenharmony_ci result = pvr2_send_request(hdw, 32408c2ecf20Sopenharmony_ci hdw->cmd_buffer,1, 32418c2ecf20Sopenharmony_ci hdw->cmd_buffer,1); 32428c2ecf20Sopenharmony_ci if (result < 0) break; 32438c2ecf20Sopenharmony_ci result = (hdw->cmd_buffer[0] != 0); 32448c2ecf20Sopenharmony_ci } while(0); LOCK_GIVE(hdw->ctl_lock); 32458c2ecf20Sopenharmony_ci return result; 32468c2ecf20Sopenharmony_ci} 32478c2ecf20Sopenharmony_ci 32488c2ecf20Sopenharmony_ci 32498c2ecf20Sopenharmony_ci/* Execute poll of tuner status */ 32508c2ecf20Sopenharmony_civoid pvr2_hdw_execute_tuner_poll(struct pvr2_hdw *hdw) 32518c2ecf20Sopenharmony_ci{ 32528c2ecf20Sopenharmony_ci LOCK_TAKE(hdw->big_lock); do { 32538c2ecf20Sopenharmony_ci pvr2_hdw_status_poll(hdw); 32548c2ecf20Sopenharmony_ci } while (0); LOCK_GIVE(hdw->big_lock); 32558c2ecf20Sopenharmony_ci} 32568c2ecf20Sopenharmony_ci 32578c2ecf20Sopenharmony_ci 32588c2ecf20Sopenharmony_cistatic int pvr2_hdw_check_cropcap(struct pvr2_hdw *hdw) 32598c2ecf20Sopenharmony_ci{ 32608c2ecf20Sopenharmony_ci if (!hdw->cropcap_stale) { 32618c2ecf20Sopenharmony_ci return 0; 32628c2ecf20Sopenharmony_ci } 32638c2ecf20Sopenharmony_ci pvr2_hdw_status_poll(hdw); 32648c2ecf20Sopenharmony_ci if (hdw->cropcap_stale) { 32658c2ecf20Sopenharmony_ci return -EIO; 32668c2ecf20Sopenharmony_ci } 32678c2ecf20Sopenharmony_ci return 0; 32688c2ecf20Sopenharmony_ci} 32698c2ecf20Sopenharmony_ci 32708c2ecf20Sopenharmony_ci 32718c2ecf20Sopenharmony_ci/* Return information about cropping capabilities */ 32728c2ecf20Sopenharmony_ciint pvr2_hdw_get_cropcap(struct pvr2_hdw *hdw, struct v4l2_cropcap *pp) 32738c2ecf20Sopenharmony_ci{ 32748c2ecf20Sopenharmony_ci int stat = 0; 32758c2ecf20Sopenharmony_ci LOCK_TAKE(hdw->big_lock); 32768c2ecf20Sopenharmony_ci stat = pvr2_hdw_check_cropcap(hdw); 32778c2ecf20Sopenharmony_ci if (!stat) { 32788c2ecf20Sopenharmony_ci memcpy(pp, &hdw->cropcap_info, sizeof(hdw->cropcap_info)); 32798c2ecf20Sopenharmony_ci } 32808c2ecf20Sopenharmony_ci LOCK_GIVE(hdw->big_lock); 32818c2ecf20Sopenharmony_ci return stat; 32828c2ecf20Sopenharmony_ci} 32838c2ecf20Sopenharmony_ci 32848c2ecf20Sopenharmony_ci 32858c2ecf20Sopenharmony_ci/* Return information about the tuner */ 32868c2ecf20Sopenharmony_ciint pvr2_hdw_get_tuner_status(struct pvr2_hdw *hdw,struct v4l2_tuner *vtp) 32878c2ecf20Sopenharmony_ci{ 32888c2ecf20Sopenharmony_ci LOCK_TAKE(hdw->big_lock); do { 32898c2ecf20Sopenharmony_ci if (hdw->tuner_signal_stale) { 32908c2ecf20Sopenharmony_ci pvr2_hdw_status_poll(hdw); 32918c2ecf20Sopenharmony_ci } 32928c2ecf20Sopenharmony_ci memcpy(vtp,&hdw->tuner_signal_info,sizeof(struct v4l2_tuner)); 32938c2ecf20Sopenharmony_ci } while (0); LOCK_GIVE(hdw->big_lock); 32948c2ecf20Sopenharmony_ci return 0; 32958c2ecf20Sopenharmony_ci} 32968c2ecf20Sopenharmony_ci 32978c2ecf20Sopenharmony_ci 32988c2ecf20Sopenharmony_ci/* Get handle to video output stream */ 32998c2ecf20Sopenharmony_cistruct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *hp) 33008c2ecf20Sopenharmony_ci{ 33018c2ecf20Sopenharmony_ci return hp->vid_stream; 33028c2ecf20Sopenharmony_ci} 33038c2ecf20Sopenharmony_ci 33048c2ecf20Sopenharmony_ci 33058c2ecf20Sopenharmony_civoid pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw) 33068c2ecf20Sopenharmony_ci{ 33078c2ecf20Sopenharmony_ci int nr = pvr2_hdw_get_unit_number(hdw); 33088c2ecf20Sopenharmony_ci LOCK_TAKE(hdw->big_lock); 33098c2ecf20Sopenharmony_ci do { 33108c2ecf20Sopenharmony_ci pr_info("pvrusb2: ================= START STATUS CARD #%d =================\n", nr); 33118c2ecf20Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, 0, core, log_status); 33128c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INFO,"cx2341x config:"); 33138c2ecf20Sopenharmony_ci cx2341x_log_status(&hdw->enc_ctl_state, "pvrusb2"); 33148c2ecf20Sopenharmony_ci pvr2_hdw_state_log_state(hdw); 33158c2ecf20Sopenharmony_ci pr_info("pvrusb2: ================== END STATUS CARD #%d ==================\n", nr); 33168c2ecf20Sopenharmony_ci } while (0); 33178c2ecf20Sopenharmony_ci LOCK_GIVE(hdw->big_lock); 33188c2ecf20Sopenharmony_ci} 33198c2ecf20Sopenharmony_ci 33208c2ecf20Sopenharmony_ci 33218c2ecf20Sopenharmony_ci/* Grab EEPROM contents, needed for direct method. */ 33228c2ecf20Sopenharmony_ci#define EEPROM_SIZE 8192 33238c2ecf20Sopenharmony_ci#define trace_eeprom(...) pvr2_trace(PVR2_TRACE_EEPROM,__VA_ARGS__) 33248c2ecf20Sopenharmony_cistatic u8 *pvr2_full_eeprom_fetch(struct pvr2_hdw *hdw) 33258c2ecf20Sopenharmony_ci{ 33268c2ecf20Sopenharmony_ci struct i2c_msg msg[2]; 33278c2ecf20Sopenharmony_ci u8 *eeprom; 33288c2ecf20Sopenharmony_ci u8 iadd[2]; 33298c2ecf20Sopenharmony_ci u8 addr; 33308c2ecf20Sopenharmony_ci u16 eepromSize; 33318c2ecf20Sopenharmony_ci unsigned int offs; 33328c2ecf20Sopenharmony_ci int ret; 33338c2ecf20Sopenharmony_ci int mode16 = 0; 33348c2ecf20Sopenharmony_ci unsigned pcnt,tcnt; 33358c2ecf20Sopenharmony_ci eeprom = kzalloc(EEPROM_SIZE, GFP_KERNEL); 33368c2ecf20Sopenharmony_ci if (!eeprom) { 33378c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 33388c2ecf20Sopenharmony_ci "Failed to allocate memory required to read eeprom"); 33398c2ecf20Sopenharmony_ci return NULL; 33408c2ecf20Sopenharmony_ci } 33418c2ecf20Sopenharmony_ci 33428c2ecf20Sopenharmony_ci trace_eeprom("Value for eeprom addr from controller was 0x%x", 33438c2ecf20Sopenharmony_ci hdw->eeprom_addr); 33448c2ecf20Sopenharmony_ci addr = hdw->eeprom_addr; 33458c2ecf20Sopenharmony_ci /* Seems that if the high bit is set, then the *real* eeprom 33468c2ecf20Sopenharmony_ci address is shifted right now bit position (noticed this in 33478c2ecf20Sopenharmony_ci newer PVR USB2 hardware) */ 33488c2ecf20Sopenharmony_ci if (addr & 0x80) addr >>= 1; 33498c2ecf20Sopenharmony_ci 33508c2ecf20Sopenharmony_ci /* FX2 documentation states that a 16bit-addressed eeprom is 33518c2ecf20Sopenharmony_ci expected if the I2C address is an odd number (yeah, this is 33528c2ecf20Sopenharmony_ci strange but it's what they do) */ 33538c2ecf20Sopenharmony_ci mode16 = (addr & 1); 33548c2ecf20Sopenharmony_ci eepromSize = (mode16 ? EEPROM_SIZE : 256); 33558c2ecf20Sopenharmony_ci trace_eeprom("Examining %d byte eeprom at location 0x%x using %d bit addressing", 33568c2ecf20Sopenharmony_ci eepromSize, addr, 33578c2ecf20Sopenharmony_ci mode16 ? 16 : 8); 33588c2ecf20Sopenharmony_ci 33598c2ecf20Sopenharmony_ci msg[0].addr = addr; 33608c2ecf20Sopenharmony_ci msg[0].flags = 0; 33618c2ecf20Sopenharmony_ci msg[0].len = mode16 ? 2 : 1; 33628c2ecf20Sopenharmony_ci msg[0].buf = iadd; 33638c2ecf20Sopenharmony_ci msg[1].addr = addr; 33648c2ecf20Sopenharmony_ci msg[1].flags = I2C_M_RD; 33658c2ecf20Sopenharmony_ci 33668c2ecf20Sopenharmony_ci /* We have to do the actual eeprom data fetch ourselves, because 33678c2ecf20Sopenharmony_ci (1) we're only fetching part of the eeprom, and (2) if we were 33688c2ecf20Sopenharmony_ci getting the whole thing our I2C driver can't grab it in one 33698c2ecf20Sopenharmony_ci pass - which is what tveeprom is otherwise going to attempt */ 33708c2ecf20Sopenharmony_ci for (tcnt = 0; tcnt < EEPROM_SIZE; tcnt += pcnt) { 33718c2ecf20Sopenharmony_ci pcnt = 16; 33728c2ecf20Sopenharmony_ci if (pcnt + tcnt > EEPROM_SIZE) pcnt = EEPROM_SIZE-tcnt; 33738c2ecf20Sopenharmony_ci offs = tcnt + (eepromSize - EEPROM_SIZE); 33748c2ecf20Sopenharmony_ci if (mode16) { 33758c2ecf20Sopenharmony_ci iadd[0] = offs >> 8; 33768c2ecf20Sopenharmony_ci iadd[1] = offs; 33778c2ecf20Sopenharmony_ci } else { 33788c2ecf20Sopenharmony_ci iadd[0] = offs; 33798c2ecf20Sopenharmony_ci } 33808c2ecf20Sopenharmony_ci msg[1].len = pcnt; 33818c2ecf20Sopenharmony_ci msg[1].buf = eeprom+tcnt; 33828c2ecf20Sopenharmony_ci if ((ret = i2c_transfer(&hdw->i2c_adap, 33838c2ecf20Sopenharmony_ci msg,ARRAY_SIZE(msg))) != 2) { 33848c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 33858c2ecf20Sopenharmony_ci "eeprom fetch set offs err=%d",ret); 33868c2ecf20Sopenharmony_ci kfree(eeprom); 33878c2ecf20Sopenharmony_ci return NULL; 33888c2ecf20Sopenharmony_ci } 33898c2ecf20Sopenharmony_ci } 33908c2ecf20Sopenharmony_ci return eeprom; 33918c2ecf20Sopenharmony_ci} 33928c2ecf20Sopenharmony_ci 33938c2ecf20Sopenharmony_ci 33948c2ecf20Sopenharmony_civoid pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, 33958c2ecf20Sopenharmony_ci int mode, 33968c2ecf20Sopenharmony_ci int enable_flag) 33978c2ecf20Sopenharmony_ci{ 33988c2ecf20Sopenharmony_ci int ret; 33998c2ecf20Sopenharmony_ci u16 address; 34008c2ecf20Sopenharmony_ci unsigned int pipe; 34018c2ecf20Sopenharmony_ci LOCK_TAKE(hdw->big_lock); do { 34028c2ecf20Sopenharmony_ci if ((hdw->fw_buffer == NULL) == !enable_flag) break; 34038c2ecf20Sopenharmony_ci 34048c2ecf20Sopenharmony_ci if (!enable_flag) { 34058c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_FIRMWARE, 34068c2ecf20Sopenharmony_ci "Cleaning up after CPU firmware fetch"); 34078c2ecf20Sopenharmony_ci kfree(hdw->fw_buffer); 34088c2ecf20Sopenharmony_ci hdw->fw_buffer = NULL; 34098c2ecf20Sopenharmony_ci hdw->fw_size = 0; 34108c2ecf20Sopenharmony_ci if (hdw->fw_cpu_flag) { 34118c2ecf20Sopenharmony_ci /* Now release the CPU. It will disconnect 34128c2ecf20Sopenharmony_ci and reconnect later. */ 34138c2ecf20Sopenharmony_ci pvr2_hdw_cpureset_assert(hdw,0); 34148c2ecf20Sopenharmony_ci } 34158c2ecf20Sopenharmony_ci break; 34168c2ecf20Sopenharmony_ci } 34178c2ecf20Sopenharmony_ci 34188c2ecf20Sopenharmony_ci hdw->fw_cpu_flag = (mode != 2); 34198c2ecf20Sopenharmony_ci if (hdw->fw_cpu_flag) { 34208c2ecf20Sopenharmony_ci hdw->fw_size = (mode == 1) ? 0x4000 : 0x2000; 34218c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_FIRMWARE, 34228c2ecf20Sopenharmony_ci "Preparing to suck out CPU firmware (size=%u)", 34238c2ecf20Sopenharmony_ci hdw->fw_size); 34248c2ecf20Sopenharmony_ci hdw->fw_buffer = kzalloc(hdw->fw_size,GFP_KERNEL); 34258c2ecf20Sopenharmony_ci if (!hdw->fw_buffer) { 34268c2ecf20Sopenharmony_ci hdw->fw_size = 0; 34278c2ecf20Sopenharmony_ci break; 34288c2ecf20Sopenharmony_ci } 34298c2ecf20Sopenharmony_ci 34308c2ecf20Sopenharmony_ci /* We have to hold the CPU during firmware upload. */ 34318c2ecf20Sopenharmony_ci pvr2_hdw_cpureset_assert(hdw,1); 34328c2ecf20Sopenharmony_ci 34338c2ecf20Sopenharmony_ci /* download the firmware from address 0000-1fff in 2048 34348c2ecf20Sopenharmony_ci (=0x800) bytes chunk. */ 34358c2ecf20Sopenharmony_ci 34368c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_FIRMWARE, 34378c2ecf20Sopenharmony_ci "Grabbing CPU firmware"); 34388c2ecf20Sopenharmony_ci pipe = usb_rcvctrlpipe(hdw->usb_dev, 0); 34398c2ecf20Sopenharmony_ci for(address = 0; address < hdw->fw_size; 34408c2ecf20Sopenharmony_ci address += 0x800) { 34418c2ecf20Sopenharmony_ci ret = usb_control_msg(hdw->usb_dev,pipe, 34428c2ecf20Sopenharmony_ci 0xa0,0xc0, 34438c2ecf20Sopenharmony_ci address,0, 34448c2ecf20Sopenharmony_ci hdw->fw_buffer+address, 34458c2ecf20Sopenharmony_ci 0x800,1000); 34468c2ecf20Sopenharmony_ci if (ret < 0) break; 34478c2ecf20Sopenharmony_ci } 34488c2ecf20Sopenharmony_ci 34498c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_FIRMWARE, 34508c2ecf20Sopenharmony_ci "Done grabbing CPU firmware"); 34518c2ecf20Sopenharmony_ci } else { 34528c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_FIRMWARE, 34538c2ecf20Sopenharmony_ci "Sucking down EEPROM contents"); 34548c2ecf20Sopenharmony_ci hdw->fw_buffer = pvr2_full_eeprom_fetch(hdw); 34558c2ecf20Sopenharmony_ci if (!hdw->fw_buffer) { 34568c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_FIRMWARE, 34578c2ecf20Sopenharmony_ci "EEPROM content suck failed."); 34588c2ecf20Sopenharmony_ci break; 34598c2ecf20Sopenharmony_ci } 34608c2ecf20Sopenharmony_ci hdw->fw_size = EEPROM_SIZE; 34618c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_FIRMWARE, 34628c2ecf20Sopenharmony_ci "Done sucking down EEPROM contents"); 34638c2ecf20Sopenharmony_ci } 34648c2ecf20Sopenharmony_ci 34658c2ecf20Sopenharmony_ci } while (0); LOCK_GIVE(hdw->big_lock); 34668c2ecf20Sopenharmony_ci} 34678c2ecf20Sopenharmony_ci 34688c2ecf20Sopenharmony_ci 34698c2ecf20Sopenharmony_ci/* Return true if we're in a mode for retrieval CPU firmware */ 34708c2ecf20Sopenharmony_ciint pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *hdw) 34718c2ecf20Sopenharmony_ci{ 34728c2ecf20Sopenharmony_ci return hdw->fw_buffer != NULL; 34738c2ecf20Sopenharmony_ci} 34748c2ecf20Sopenharmony_ci 34758c2ecf20Sopenharmony_ci 34768c2ecf20Sopenharmony_ciint pvr2_hdw_cpufw_get(struct pvr2_hdw *hdw,unsigned int offs, 34778c2ecf20Sopenharmony_ci char *buf,unsigned int cnt) 34788c2ecf20Sopenharmony_ci{ 34798c2ecf20Sopenharmony_ci int ret = -EINVAL; 34808c2ecf20Sopenharmony_ci LOCK_TAKE(hdw->big_lock); do { 34818c2ecf20Sopenharmony_ci if (!buf) break; 34828c2ecf20Sopenharmony_ci if (!cnt) break; 34838c2ecf20Sopenharmony_ci 34848c2ecf20Sopenharmony_ci if (!hdw->fw_buffer) { 34858c2ecf20Sopenharmony_ci ret = -EIO; 34868c2ecf20Sopenharmony_ci break; 34878c2ecf20Sopenharmony_ci } 34888c2ecf20Sopenharmony_ci 34898c2ecf20Sopenharmony_ci if (offs >= hdw->fw_size) { 34908c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_FIRMWARE, 34918c2ecf20Sopenharmony_ci "Read firmware data offs=%d EOF", 34928c2ecf20Sopenharmony_ci offs); 34938c2ecf20Sopenharmony_ci ret = 0; 34948c2ecf20Sopenharmony_ci break; 34958c2ecf20Sopenharmony_ci } 34968c2ecf20Sopenharmony_ci 34978c2ecf20Sopenharmony_ci if (offs + cnt > hdw->fw_size) cnt = hdw->fw_size - offs; 34988c2ecf20Sopenharmony_ci 34998c2ecf20Sopenharmony_ci memcpy(buf,hdw->fw_buffer+offs,cnt); 35008c2ecf20Sopenharmony_ci 35018c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_FIRMWARE, 35028c2ecf20Sopenharmony_ci "Read firmware data offs=%d cnt=%d", 35038c2ecf20Sopenharmony_ci offs,cnt); 35048c2ecf20Sopenharmony_ci ret = cnt; 35058c2ecf20Sopenharmony_ci } while (0); LOCK_GIVE(hdw->big_lock); 35068c2ecf20Sopenharmony_ci 35078c2ecf20Sopenharmony_ci return ret; 35088c2ecf20Sopenharmony_ci} 35098c2ecf20Sopenharmony_ci 35108c2ecf20Sopenharmony_ci 35118c2ecf20Sopenharmony_ciint pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *hdw, 35128c2ecf20Sopenharmony_ci enum pvr2_v4l_type index) 35138c2ecf20Sopenharmony_ci{ 35148c2ecf20Sopenharmony_ci switch (index) { 35158c2ecf20Sopenharmony_ci case pvr2_v4l_type_video: return hdw->v4l_minor_number_video; 35168c2ecf20Sopenharmony_ci case pvr2_v4l_type_vbi: return hdw->v4l_minor_number_vbi; 35178c2ecf20Sopenharmony_ci case pvr2_v4l_type_radio: return hdw->v4l_minor_number_radio; 35188c2ecf20Sopenharmony_ci default: return -1; 35198c2ecf20Sopenharmony_ci } 35208c2ecf20Sopenharmony_ci} 35218c2ecf20Sopenharmony_ci 35228c2ecf20Sopenharmony_ci 35238c2ecf20Sopenharmony_ci/* Store a v4l minor device number */ 35248c2ecf20Sopenharmony_civoid pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *hdw, 35258c2ecf20Sopenharmony_ci enum pvr2_v4l_type index,int v) 35268c2ecf20Sopenharmony_ci{ 35278c2ecf20Sopenharmony_ci switch (index) { 35288c2ecf20Sopenharmony_ci case pvr2_v4l_type_video: hdw->v4l_minor_number_video = v;break; 35298c2ecf20Sopenharmony_ci case pvr2_v4l_type_vbi: hdw->v4l_minor_number_vbi = v;break; 35308c2ecf20Sopenharmony_ci case pvr2_v4l_type_radio: hdw->v4l_minor_number_radio = v;break; 35318c2ecf20Sopenharmony_ci default: break; 35328c2ecf20Sopenharmony_ci } 35338c2ecf20Sopenharmony_ci} 35348c2ecf20Sopenharmony_ci 35358c2ecf20Sopenharmony_ci 35368c2ecf20Sopenharmony_cistatic void pvr2_ctl_write_complete(struct urb *urb) 35378c2ecf20Sopenharmony_ci{ 35388c2ecf20Sopenharmony_ci struct pvr2_hdw *hdw = urb->context; 35398c2ecf20Sopenharmony_ci hdw->ctl_write_pend_flag = 0; 35408c2ecf20Sopenharmony_ci if (hdw->ctl_read_pend_flag) return; 35418c2ecf20Sopenharmony_ci complete(&hdw->ctl_done); 35428c2ecf20Sopenharmony_ci} 35438c2ecf20Sopenharmony_ci 35448c2ecf20Sopenharmony_ci 35458c2ecf20Sopenharmony_cistatic void pvr2_ctl_read_complete(struct urb *urb) 35468c2ecf20Sopenharmony_ci{ 35478c2ecf20Sopenharmony_ci struct pvr2_hdw *hdw = urb->context; 35488c2ecf20Sopenharmony_ci hdw->ctl_read_pend_flag = 0; 35498c2ecf20Sopenharmony_ci if (hdw->ctl_write_pend_flag) return; 35508c2ecf20Sopenharmony_ci complete(&hdw->ctl_done); 35518c2ecf20Sopenharmony_ci} 35528c2ecf20Sopenharmony_ci 35538c2ecf20Sopenharmony_cistruct hdw_timer { 35548c2ecf20Sopenharmony_ci struct timer_list timer; 35558c2ecf20Sopenharmony_ci struct pvr2_hdw *hdw; 35568c2ecf20Sopenharmony_ci}; 35578c2ecf20Sopenharmony_ci 35588c2ecf20Sopenharmony_cistatic void pvr2_ctl_timeout(struct timer_list *t) 35598c2ecf20Sopenharmony_ci{ 35608c2ecf20Sopenharmony_ci struct hdw_timer *timer = from_timer(timer, t, timer); 35618c2ecf20Sopenharmony_ci struct pvr2_hdw *hdw = timer->hdw; 35628c2ecf20Sopenharmony_ci 35638c2ecf20Sopenharmony_ci if (hdw->ctl_write_pend_flag || hdw->ctl_read_pend_flag) { 35648c2ecf20Sopenharmony_ci hdw->ctl_timeout_flag = !0; 35658c2ecf20Sopenharmony_ci if (hdw->ctl_write_pend_flag) 35668c2ecf20Sopenharmony_ci usb_unlink_urb(hdw->ctl_write_urb); 35678c2ecf20Sopenharmony_ci if (hdw->ctl_read_pend_flag) 35688c2ecf20Sopenharmony_ci usb_unlink_urb(hdw->ctl_read_urb); 35698c2ecf20Sopenharmony_ci } 35708c2ecf20Sopenharmony_ci} 35718c2ecf20Sopenharmony_ci 35728c2ecf20Sopenharmony_ci 35738c2ecf20Sopenharmony_ci/* Issue a command and get a response from the device. This extended 35748c2ecf20Sopenharmony_ci version includes a probe flag (which if set means that device errors 35758c2ecf20Sopenharmony_ci should not be logged or treated as fatal) and a timeout in jiffies. 35768c2ecf20Sopenharmony_ci This can be used to non-lethally probe the health of endpoint 1. */ 35778c2ecf20Sopenharmony_cistatic int pvr2_send_request_ex(struct pvr2_hdw *hdw, 35788c2ecf20Sopenharmony_ci unsigned int timeout,int probe_fl, 35798c2ecf20Sopenharmony_ci void *write_data,unsigned int write_len, 35808c2ecf20Sopenharmony_ci void *read_data,unsigned int read_len) 35818c2ecf20Sopenharmony_ci{ 35828c2ecf20Sopenharmony_ci unsigned int idx; 35838c2ecf20Sopenharmony_ci int status = 0; 35848c2ecf20Sopenharmony_ci struct hdw_timer timer = { 35858c2ecf20Sopenharmony_ci .hdw = hdw, 35868c2ecf20Sopenharmony_ci }; 35878c2ecf20Sopenharmony_ci 35888c2ecf20Sopenharmony_ci if (!hdw->ctl_lock_held) { 35898c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 35908c2ecf20Sopenharmony_ci "Attempted to execute control transfer without lock!!"); 35918c2ecf20Sopenharmony_ci return -EDEADLK; 35928c2ecf20Sopenharmony_ci } 35938c2ecf20Sopenharmony_ci if (!hdw->flag_ok && !probe_fl) { 35948c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 35958c2ecf20Sopenharmony_ci "Attempted to execute control transfer when device not ok"); 35968c2ecf20Sopenharmony_ci return -EIO; 35978c2ecf20Sopenharmony_ci } 35988c2ecf20Sopenharmony_ci if (!(hdw->ctl_read_urb && hdw->ctl_write_urb)) { 35998c2ecf20Sopenharmony_ci if (!probe_fl) { 36008c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 36018c2ecf20Sopenharmony_ci "Attempted to execute control transfer when USB is disconnected"); 36028c2ecf20Sopenharmony_ci } 36038c2ecf20Sopenharmony_ci return -ENOTTY; 36048c2ecf20Sopenharmony_ci } 36058c2ecf20Sopenharmony_ci 36068c2ecf20Sopenharmony_ci /* Ensure that we have sane parameters */ 36078c2ecf20Sopenharmony_ci if (!write_data) write_len = 0; 36088c2ecf20Sopenharmony_ci if (!read_data) read_len = 0; 36098c2ecf20Sopenharmony_ci if (write_len > PVR2_CTL_BUFFSIZE) { 36108c2ecf20Sopenharmony_ci pvr2_trace( 36118c2ecf20Sopenharmony_ci PVR2_TRACE_ERROR_LEGS, 36128c2ecf20Sopenharmony_ci "Attempted to execute %d byte control-write transfer (limit=%d)", 36138c2ecf20Sopenharmony_ci write_len,PVR2_CTL_BUFFSIZE); 36148c2ecf20Sopenharmony_ci return -EINVAL; 36158c2ecf20Sopenharmony_ci } 36168c2ecf20Sopenharmony_ci if (read_len > PVR2_CTL_BUFFSIZE) { 36178c2ecf20Sopenharmony_ci pvr2_trace( 36188c2ecf20Sopenharmony_ci PVR2_TRACE_ERROR_LEGS, 36198c2ecf20Sopenharmony_ci "Attempted to execute %d byte control-read transfer (limit=%d)", 36208c2ecf20Sopenharmony_ci write_len,PVR2_CTL_BUFFSIZE); 36218c2ecf20Sopenharmony_ci return -EINVAL; 36228c2ecf20Sopenharmony_ci } 36238c2ecf20Sopenharmony_ci if ((!write_len) && (!read_len)) { 36248c2ecf20Sopenharmony_ci pvr2_trace( 36258c2ecf20Sopenharmony_ci PVR2_TRACE_ERROR_LEGS, 36268c2ecf20Sopenharmony_ci "Attempted to execute null control transfer?"); 36278c2ecf20Sopenharmony_ci return -EINVAL; 36288c2ecf20Sopenharmony_ci } 36298c2ecf20Sopenharmony_ci 36308c2ecf20Sopenharmony_ci 36318c2ecf20Sopenharmony_ci hdw->cmd_debug_state = 1; 36328c2ecf20Sopenharmony_ci if (write_len && write_data) 36338c2ecf20Sopenharmony_ci hdw->cmd_debug_code = ((unsigned char *)write_data)[0]; 36348c2ecf20Sopenharmony_ci else 36358c2ecf20Sopenharmony_ci hdw->cmd_debug_code = 0; 36368c2ecf20Sopenharmony_ci hdw->cmd_debug_write_len = write_len; 36378c2ecf20Sopenharmony_ci hdw->cmd_debug_read_len = read_len; 36388c2ecf20Sopenharmony_ci 36398c2ecf20Sopenharmony_ci /* Initialize common stuff */ 36408c2ecf20Sopenharmony_ci init_completion(&hdw->ctl_done); 36418c2ecf20Sopenharmony_ci hdw->ctl_timeout_flag = 0; 36428c2ecf20Sopenharmony_ci hdw->ctl_write_pend_flag = 0; 36438c2ecf20Sopenharmony_ci hdw->ctl_read_pend_flag = 0; 36448c2ecf20Sopenharmony_ci timer_setup_on_stack(&timer.timer, pvr2_ctl_timeout, 0); 36458c2ecf20Sopenharmony_ci timer.timer.expires = jiffies + timeout; 36468c2ecf20Sopenharmony_ci 36478c2ecf20Sopenharmony_ci if (write_len && write_data) { 36488c2ecf20Sopenharmony_ci hdw->cmd_debug_state = 2; 36498c2ecf20Sopenharmony_ci /* Transfer write data to internal buffer */ 36508c2ecf20Sopenharmony_ci for (idx = 0; idx < write_len; idx++) { 36518c2ecf20Sopenharmony_ci hdw->ctl_write_buffer[idx] = 36528c2ecf20Sopenharmony_ci ((unsigned char *)write_data)[idx]; 36538c2ecf20Sopenharmony_ci } 36548c2ecf20Sopenharmony_ci /* Initiate a write request */ 36558c2ecf20Sopenharmony_ci usb_fill_bulk_urb(hdw->ctl_write_urb, 36568c2ecf20Sopenharmony_ci hdw->usb_dev, 36578c2ecf20Sopenharmony_ci usb_sndbulkpipe(hdw->usb_dev, 36588c2ecf20Sopenharmony_ci PVR2_CTL_WRITE_ENDPOINT), 36598c2ecf20Sopenharmony_ci hdw->ctl_write_buffer, 36608c2ecf20Sopenharmony_ci write_len, 36618c2ecf20Sopenharmony_ci pvr2_ctl_write_complete, 36628c2ecf20Sopenharmony_ci hdw); 36638c2ecf20Sopenharmony_ci hdw->ctl_write_urb->actual_length = 0; 36648c2ecf20Sopenharmony_ci hdw->ctl_write_pend_flag = !0; 36658c2ecf20Sopenharmony_ci if (usb_urb_ep_type_check(hdw->ctl_write_urb)) { 36668c2ecf20Sopenharmony_ci pvr2_trace( 36678c2ecf20Sopenharmony_ci PVR2_TRACE_ERROR_LEGS, 36688c2ecf20Sopenharmony_ci "Invalid write control endpoint"); 36698c2ecf20Sopenharmony_ci return -EINVAL; 36708c2ecf20Sopenharmony_ci } 36718c2ecf20Sopenharmony_ci status = usb_submit_urb(hdw->ctl_write_urb,GFP_KERNEL); 36728c2ecf20Sopenharmony_ci if (status < 0) { 36738c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 36748c2ecf20Sopenharmony_ci "Failed to submit write-control URB status=%d", 36758c2ecf20Sopenharmony_cistatus); 36768c2ecf20Sopenharmony_ci hdw->ctl_write_pend_flag = 0; 36778c2ecf20Sopenharmony_ci goto done; 36788c2ecf20Sopenharmony_ci } 36798c2ecf20Sopenharmony_ci } 36808c2ecf20Sopenharmony_ci 36818c2ecf20Sopenharmony_ci if (read_len) { 36828c2ecf20Sopenharmony_ci hdw->cmd_debug_state = 3; 36838c2ecf20Sopenharmony_ci memset(hdw->ctl_read_buffer,0x43,read_len); 36848c2ecf20Sopenharmony_ci /* Initiate a read request */ 36858c2ecf20Sopenharmony_ci usb_fill_bulk_urb(hdw->ctl_read_urb, 36868c2ecf20Sopenharmony_ci hdw->usb_dev, 36878c2ecf20Sopenharmony_ci usb_rcvbulkpipe(hdw->usb_dev, 36888c2ecf20Sopenharmony_ci PVR2_CTL_READ_ENDPOINT), 36898c2ecf20Sopenharmony_ci hdw->ctl_read_buffer, 36908c2ecf20Sopenharmony_ci read_len, 36918c2ecf20Sopenharmony_ci pvr2_ctl_read_complete, 36928c2ecf20Sopenharmony_ci hdw); 36938c2ecf20Sopenharmony_ci hdw->ctl_read_urb->actual_length = 0; 36948c2ecf20Sopenharmony_ci hdw->ctl_read_pend_flag = !0; 36958c2ecf20Sopenharmony_ci if (usb_urb_ep_type_check(hdw->ctl_read_urb)) { 36968c2ecf20Sopenharmony_ci pvr2_trace( 36978c2ecf20Sopenharmony_ci PVR2_TRACE_ERROR_LEGS, 36988c2ecf20Sopenharmony_ci "Invalid read control endpoint"); 36998c2ecf20Sopenharmony_ci return -EINVAL; 37008c2ecf20Sopenharmony_ci } 37018c2ecf20Sopenharmony_ci status = usb_submit_urb(hdw->ctl_read_urb,GFP_KERNEL); 37028c2ecf20Sopenharmony_ci if (status < 0) { 37038c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 37048c2ecf20Sopenharmony_ci "Failed to submit read-control URB status=%d", 37058c2ecf20Sopenharmony_cistatus); 37068c2ecf20Sopenharmony_ci hdw->ctl_read_pend_flag = 0; 37078c2ecf20Sopenharmony_ci goto done; 37088c2ecf20Sopenharmony_ci } 37098c2ecf20Sopenharmony_ci } 37108c2ecf20Sopenharmony_ci 37118c2ecf20Sopenharmony_ci /* Start timer */ 37128c2ecf20Sopenharmony_ci add_timer(&timer.timer); 37138c2ecf20Sopenharmony_ci 37148c2ecf20Sopenharmony_ci /* Now wait for all I/O to complete */ 37158c2ecf20Sopenharmony_ci hdw->cmd_debug_state = 4; 37168c2ecf20Sopenharmony_ci while (hdw->ctl_write_pend_flag || hdw->ctl_read_pend_flag) { 37178c2ecf20Sopenharmony_ci wait_for_completion(&hdw->ctl_done); 37188c2ecf20Sopenharmony_ci } 37198c2ecf20Sopenharmony_ci hdw->cmd_debug_state = 5; 37208c2ecf20Sopenharmony_ci 37218c2ecf20Sopenharmony_ci /* Stop timer */ 37228c2ecf20Sopenharmony_ci del_timer_sync(&timer.timer); 37238c2ecf20Sopenharmony_ci 37248c2ecf20Sopenharmony_ci hdw->cmd_debug_state = 6; 37258c2ecf20Sopenharmony_ci status = 0; 37268c2ecf20Sopenharmony_ci 37278c2ecf20Sopenharmony_ci if (hdw->ctl_timeout_flag) { 37288c2ecf20Sopenharmony_ci status = -ETIMEDOUT; 37298c2ecf20Sopenharmony_ci if (!probe_fl) { 37308c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 37318c2ecf20Sopenharmony_ci "Timed out control-write"); 37328c2ecf20Sopenharmony_ci } 37338c2ecf20Sopenharmony_ci goto done; 37348c2ecf20Sopenharmony_ci } 37358c2ecf20Sopenharmony_ci 37368c2ecf20Sopenharmony_ci if (write_len) { 37378c2ecf20Sopenharmony_ci /* Validate results of write request */ 37388c2ecf20Sopenharmony_ci if ((hdw->ctl_write_urb->status != 0) && 37398c2ecf20Sopenharmony_ci (hdw->ctl_write_urb->status != -ENOENT) && 37408c2ecf20Sopenharmony_ci (hdw->ctl_write_urb->status != -ESHUTDOWN) && 37418c2ecf20Sopenharmony_ci (hdw->ctl_write_urb->status != -ECONNRESET)) { 37428c2ecf20Sopenharmony_ci /* USB subsystem is reporting some kind of failure 37438c2ecf20Sopenharmony_ci on the write */ 37448c2ecf20Sopenharmony_ci status = hdw->ctl_write_urb->status; 37458c2ecf20Sopenharmony_ci if (!probe_fl) { 37468c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 37478c2ecf20Sopenharmony_ci "control-write URB failure, status=%d", 37488c2ecf20Sopenharmony_ci status); 37498c2ecf20Sopenharmony_ci } 37508c2ecf20Sopenharmony_ci goto done; 37518c2ecf20Sopenharmony_ci } 37528c2ecf20Sopenharmony_ci if (hdw->ctl_write_urb->actual_length < write_len) { 37538c2ecf20Sopenharmony_ci /* Failed to write enough data */ 37548c2ecf20Sopenharmony_ci status = -EIO; 37558c2ecf20Sopenharmony_ci if (!probe_fl) { 37568c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 37578c2ecf20Sopenharmony_ci "control-write URB short, expected=%d got=%d", 37588c2ecf20Sopenharmony_ci write_len, 37598c2ecf20Sopenharmony_ci hdw->ctl_write_urb->actual_length); 37608c2ecf20Sopenharmony_ci } 37618c2ecf20Sopenharmony_ci goto done; 37628c2ecf20Sopenharmony_ci } 37638c2ecf20Sopenharmony_ci } 37648c2ecf20Sopenharmony_ci if (read_len && read_data) { 37658c2ecf20Sopenharmony_ci /* Validate results of read request */ 37668c2ecf20Sopenharmony_ci if ((hdw->ctl_read_urb->status != 0) && 37678c2ecf20Sopenharmony_ci (hdw->ctl_read_urb->status != -ENOENT) && 37688c2ecf20Sopenharmony_ci (hdw->ctl_read_urb->status != -ESHUTDOWN) && 37698c2ecf20Sopenharmony_ci (hdw->ctl_read_urb->status != -ECONNRESET)) { 37708c2ecf20Sopenharmony_ci /* USB subsystem is reporting some kind of failure 37718c2ecf20Sopenharmony_ci on the read */ 37728c2ecf20Sopenharmony_ci status = hdw->ctl_read_urb->status; 37738c2ecf20Sopenharmony_ci if (!probe_fl) { 37748c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 37758c2ecf20Sopenharmony_ci "control-read URB failure, status=%d", 37768c2ecf20Sopenharmony_ci status); 37778c2ecf20Sopenharmony_ci } 37788c2ecf20Sopenharmony_ci goto done; 37798c2ecf20Sopenharmony_ci } 37808c2ecf20Sopenharmony_ci if (hdw->ctl_read_urb->actual_length < read_len) { 37818c2ecf20Sopenharmony_ci /* Failed to read enough data */ 37828c2ecf20Sopenharmony_ci status = -EIO; 37838c2ecf20Sopenharmony_ci if (!probe_fl) { 37848c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 37858c2ecf20Sopenharmony_ci "control-read URB short, expected=%d got=%d", 37868c2ecf20Sopenharmony_ci read_len, 37878c2ecf20Sopenharmony_ci hdw->ctl_read_urb->actual_length); 37888c2ecf20Sopenharmony_ci } 37898c2ecf20Sopenharmony_ci goto done; 37908c2ecf20Sopenharmony_ci } 37918c2ecf20Sopenharmony_ci /* Transfer retrieved data out from internal buffer */ 37928c2ecf20Sopenharmony_ci for (idx = 0; idx < read_len; idx++) { 37938c2ecf20Sopenharmony_ci ((unsigned char *)read_data)[idx] = 37948c2ecf20Sopenharmony_ci hdw->ctl_read_buffer[idx]; 37958c2ecf20Sopenharmony_ci } 37968c2ecf20Sopenharmony_ci } 37978c2ecf20Sopenharmony_ci 37988c2ecf20Sopenharmony_ci done: 37998c2ecf20Sopenharmony_ci 38008c2ecf20Sopenharmony_ci hdw->cmd_debug_state = 0; 38018c2ecf20Sopenharmony_ci if ((status < 0) && (!probe_fl)) { 38028c2ecf20Sopenharmony_ci pvr2_hdw_render_useless(hdw); 38038c2ecf20Sopenharmony_ci } 38048c2ecf20Sopenharmony_ci destroy_timer_on_stack(&timer.timer); 38058c2ecf20Sopenharmony_ci 38068c2ecf20Sopenharmony_ci return status; 38078c2ecf20Sopenharmony_ci} 38088c2ecf20Sopenharmony_ci 38098c2ecf20Sopenharmony_ci 38108c2ecf20Sopenharmony_ciint pvr2_send_request(struct pvr2_hdw *hdw, 38118c2ecf20Sopenharmony_ci void *write_data,unsigned int write_len, 38128c2ecf20Sopenharmony_ci void *read_data,unsigned int read_len) 38138c2ecf20Sopenharmony_ci{ 38148c2ecf20Sopenharmony_ci return pvr2_send_request_ex(hdw,HZ*4,0, 38158c2ecf20Sopenharmony_ci write_data,write_len, 38168c2ecf20Sopenharmony_ci read_data,read_len); 38178c2ecf20Sopenharmony_ci} 38188c2ecf20Sopenharmony_ci 38198c2ecf20Sopenharmony_ci 38208c2ecf20Sopenharmony_cistatic int pvr2_issue_simple_cmd(struct pvr2_hdw *hdw,u32 cmdcode) 38218c2ecf20Sopenharmony_ci{ 38228c2ecf20Sopenharmony_ci int ret; 38238c2ecf20Sopenharmony_ci unsigned int cnt = 1; 38248c2ecf20Sopenharmony_ci unsigned int args = 0; 38258c2ecf20Sopenharmony_ci LOCK_TAKE(hdw->ctl_lock); 38268c2ecf20Sopenharmony_ci hdw->cmd_buffer[0] = cmdcode & 0xffu; 38278c2ecf20Sopenharmony_ci args = (cmdcode >> 8) & 0xffu; 38288c2ecf20Sopenharmony_ci args = (args > 2) ? 2 : args; 38298c2ecf20Sopenharmony_ci if (args) { 38308c2ecf20Sopenharmony_ci cnt += args; 38318c2ecf20Sopenharmony_ci hdw->cmd_buffer[1] = (cmdcode >> 16) & 0xffu; 38328c2ecf20Sopenharmony_ci if (args > 1) { 38338c2ecf20Sopenharmony_ci hdw->cmd_buffer[2] = (cmdcode >> 24) & 0xffu; 38348c2ecf20Sopenharmony_ci } 38358c2ecf20Sopenharmony_ci } 38368c2ecf20Sopenharmony_ci if (pvrusb2_debug & PVR2_TRACE_INIT) { 38378c2ecf20Sopenharmony_ci unsigned int idx; 38388c2ecf20Sopenharmony_ci unsigned int ccnt,bcnt; 38398c2ecf20Sopenharmony_ci char tbuf[50]; 38408c2ecf20Sopenharmony_ci cmdcode &= 0xffu; 38418c2ecf20Sopenharmony_ci bcnt = 0; 38428c2ecf20Sopenharmony_ci ccnt = scnprintf(tbuf+bcnt, 38438c2ecf20Sopenharmony_ci sizeof(tbuf)-bcnt, 38448c2ecf20Sopenharmony_ci "Sending FX2 command 0x%x",cmdcode); 38458c2ecf20Sopenharmony_ci bcnt += ccnt; 38468c2ecf20Sopenharmony_ci for (idx = 0; idx < ARRAY_SIZE(pvr2_fx2cmd_desc); idx++) { 38478c2ecf20Sopenharmony_ci if (pvr2_fx2cmd_desc[idx].id == cmdcode) { 38488c2ecf20Sopenharmony_ci ccnt = scnprintf(tbuf+bcnt, 38498c2ecf20Sopenharmony_ci sizeof(tbuf)-bcnt, 38508c2ecf20Sopenharmony_ci " \"%s\"", 38518c2ecf20Sopenharmony_ci pvr2_fx2cmd_desc[idx].desc); 38528c2ecf20Sopenharmony_ci bcnt += ccnt; 38538c2ecf20Sopenharmony_ci break; 38548c2ecf20Sopenharmony_ci } 38558c2ecf20Sopenharmony_ci } 38568c2ecf20Sopenharmony_ci if (args) { 38578c2ecf20Sopenharmony_ci ccnt = scnprintf(tbuf+bcnt, 38588c2ecf20Sopenharmony_ci sizeof(tbuf)-bcnt, 38598c2ecf20Sopenharmony_ci " (%u",hdw->cmd_buffer[1]); 38608c2ecf20Sopenharmony_ci bcnt += ccnt; 38618c2ecf20Sopenharmony_ci if (args > 1) { 38628c2ecf20Sopenharmony_ci ccnt = scnprintf(tbuf+bcnt, 38638c2ecf20Sopenharmony_ci sizeof(tbuf)-bcnt, 38648c2ecf20Sopenharmony_ci ",%u",hdw->cmd_buffer[2]); 38658c2ecf20Sopenharmony_ci bcnt += ccnt; 38668c2ecf20Sopenharmony_ci } 38678c2ecf20Sopenharmony_ci ccnt = scnprintf(tbuf+bcnt, 38688c2ecf20Sopenharmony_ci sizeof(tbuf)-bcnt, 38698c2ecf20Sopenharmony_ci ")"); 38708c2ecf20Sopenharmony_ci bcnt += ccnt; 38718c2ecf20Sopenharmony_ci } 38728c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT,"%.*s",bcnt,tbuf); 38738c2ecf20Sopenharmony_ci } 38748c2ecf20Sopenharmony_ci ret = pvr2_send_request(hdw,hdw->cmd_buffer,cnt,NULL,0); 38758c2ecf20Sopenharmony_ci LOCK_GIVE(hdw->ctl_lock); 38768c2ecf20Sopenharmony_ci return ret; 38778c2ecf20Sopenharmony_ci} 38788c2ecf20Sopenharmony_ci 38798c2ecf20Sopenharmony_ci 38808c2ecf20Sopenharmony_ciint pvr2_write_register(struct pvr2_hdw *hdw, u16 reg, u32 data) 38818c2ecf20Sopenharmony_ci{ 38828c2ecf20Sopenharmony_ci int ret; 38838c2ecf20Sopenharmony_ci 38848c2ecf20Sopenharmony_ci LOCK_TAKE(hdw->ctl_lock); 38858c2ecf20Sopenharmony_ci 38868c2ecf20Sopenharmony_ci hdw->cmd_buffer[0] = FX2CMD_REG_WRITE; /* write register prefix */ 38878c2ecf20Sopenharmony_ci PVR2_DECOMPOSE_LE(hdw->cmd_buffer,1,data); 38888c2ecf20Sopenharmony_ci hdw->cmd_buffer[5] = 0; 38898c2ecf20Sopenharmony_ci hdw->cmd_buffer[6] = (reg >> 8) & 0xff; 38908c2ecf20Sopenharmony_ci hdw->cmd_buffer[7] = reg & 0xff; 38918c2ecf20Sopenharmony_ci 38928c2ecf20Sopenharmony_ci 38938c2ecf20Sopenharmony_ci ret = pvr2_send_request(hdw, hdw->cmd_buffer, 8, hdw->cmd_buffer, 0); 38948c2ecf20Sopenharmony_ci 38958c2ecf20Sopenharmony_ci LOCK_GIVE(hdw->ctl_lock); 38968c2ecf20Sopenharmony_ci 38978c2ecf20Sopenharmony_ci return ret; 38988c2ecf20Sopenharmony_ci} 38998c2ecf20Sopenharmony_ci 39008c2ecf20Sopenharmony_ci 39018c2ecf20Sopenharmony_cistatic int pvr2_read_register(struct pvr2_hdw *hdw, u16 reg, u32 *data) 39028c2ecf20Sopenharmony_ci{ 39038c2ecf20Sopenharmony_ci int ret = 0; 39048c2ecf20Sopenharmony_ci 39058c2ecf20Sopenharmony_ci LOCK_TAKE(hdw->ctl_lock); 39068c2ecf20Sopenharmony_ci 39078c2ecf20Sopenharmony_ci hdw->cmd_buffer[0] = FX2CMD_REG_READ; /* read register prefix */ 39088c2ecf20Sopenharmony_ci hdw->cmd_buffer[1] = 0; 39098c2ecf20Sopenharmony_ci hdw->cmd_buffer[2] = 0; 39108c2ecf20Sopenharmony_ci hdw->cmd_buffer[3] = 0; 39118c2ecf20Sopenharmony_ci hdw->cmd_buffer[4] = 0; 39128c2ecf20Sopenharmony_ci hdw->cmd_buffer[5] = 0; 39138c2ecf20Sopenharmony_ci hdw->cmd_buffer[6] = (reg >> 8) & 0xff; 39148c2ecf20Sopenharmony_ci hdw->cmd_buffer[7] = reg & 0xff; 39158c2ecf20Sopenharmony_ci 39168c2ecf20Sopenharmony_ci ret |= pvr2_send_request(hdw, hdw->cmd_buffer, 8, hdw->cmd_buffer, 4); 39178c2ecf20Sopenharmony_ci *data = PVR2_COMPOSE_LE(hdw->cmd_buffer,0); 39188c2ecf20Sopenharmony_ci 39198c2ecf20Sopenharmony_ci LOCK_GIVE(hdw->ctl_lock); 39208c2ecf20Sopenharmony_ci 39218c2ecf20Sopenharmony_ci return ret; 39228c2ecf20Sopenharmony_ci} 39238c2ecf20Sopenharmony_ci 39248c2ecf20Sopenharmony_ci 39258c2ecf20Sopenharmony_civoid pvr2_hdw_render_useless(struct pvr2_hdw *hdw) 39268c2ecf20Sopenharmony_ci{ 39278c2ecf20Sopenharmony_ci if (!hdw->flag_ok) return; 39288c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 39298c2ecf20Sopenharmony_ci "Device being rendered inoperable"); 39308c2ecf20Sopenharmony_ci if (hdw->vid_stream) { 39318c2ecf20Sopenharmony_ci pvr2_stream_setup(hdw->vid_stream,NULL,0,0); 39328c2ecf20Sopenharmony_ci } 39338c2ecf20Sopenharmony_ci hdw->flag_ok = 0; 39348c2ecf20Sopenharmony_ci trace_stbit("flag_ok",hdw->flag_ok); 39358c2ecf20Sopenharmony_ci pvr2_hdw_state_sched(hdw); 39368c2ecf20Sopenharmony_ci} 39378c2ecf20Sopenharmony_ci 39388c2ecf20Sopenharmony_ci 39398c2ecf20Sopenharmony_civoid pvr2_hdw_device_reset(struct pvr2_hdw *hdw) 39408c2ecf20Sopenharmony_ci{ 39418c2ecf20Sopenharmony_ci int ret; 39428c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT,"Performing a device reset..."); 39438c2ecf20Sopenharmony_ci ret = usb_lock_device_for_reset(hdw->usb_dev,NULL); 39448c2ecf20Sopenharmony_ci if (ret == 0) { 39458c2ecf20Sopenharmony_ci ret = usb_reset_device(hdw->usb_dev); 39468c2ecf20Sopenharmony_ci usb_unlock_device(hdw->usb_dev); 39478c2ecf20Sopenharmony_ci } else { 39488c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 39498c2ecf20Sopenharmony_ci "Failed to lock USB device ret=%d",ret); 39508c2ecf20Sopenharmony_ci } 39518c2ecf20Sopenharmony_ci if (init_pause_msec) { 39528c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INFO, 39538c2ecf20Sopenharmony_ci "Waiting %u msec for hardware to settle", 39548c2ecf20Sopenharmony_ci init_pause_msec); 39558c2ecf20Sopenharmony_ci msleep(init_pause_msec); 39568c2ecf20Sopenharmony_ci } 39578c2ecf20Sopenharmony_ci 39588c2ecf20Sopenharmony_ci} 39598c2ecf20Sopenharmony_ci 39608c2ecf20Sopenharmony_ci 39618c2ecf20Sopenharmony_civoid pvr2_hdw_cpureset_assert(struct pvr2_hdw *hdw,int val) 39628c2ecf20Sopenharmony_ci{ 39638c2ecf20Sopenharmony_ci char *da; 39648c2ecf20Sopenharmony_ci unsigned int pipe; 39658c2ecf20Sopenharmony_ci int ret; 39668c2ecf20Sopenharmony_ci 39678c2ecf20Sopenharmony_ci if (!hdw->usb_dev) return; 39688c2ecf20Sopenharmony_ci 39698c2ecf20Sopenharmony_ci da = kmalloc(16, GFP_KERNEL); 39708c2ecf20Sopenharmony_ci 39718c2ecf20Sopenharmony_ci if (da == NULL) { 39728c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 39738c2ecf20Sopenharmony_ci "Unable to allocate memory to control CPU reset"); 39748c2ecf20Sopenharmony_ci return; 39758c2ecf20Sopenharmony_ci } 39768c2ecf20Sopenharmony_ci 39778c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT,"cpureset_assert(%d)",val); 39788c2ecf20Sopenharmony_ci 39798c2ecf20Sopenharmony_ci da[0] = val ? 0x01 : 0x00; 39808c2ecf20Sopenharmony_ci 39818c2ecf20Sopenharmony_ci /* Write the CPUCS register on the 8051. The lsb of the register 39828c2ecf20Sopenharmony_ci is the reset bit; a 1 asserts reset while a 0 clears it. */ 39838c2ecf20Sopenharmony_ci pipe = usb_sndctrlpipe(hdw->usb_dev, 0); 39848c2ecf20Sopenharmony_ci ret = usb_control_msg(hdw->usb_dev,pipe,0xa0,0x40,0xe600,0,da,1,1000); 39858c2ecf20Sopenharmony_ci if (ret < 0) { 39868c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 39878c2ecf20Sopenharmony_ci "cpureset_assert(%d) error=%d",val,ret); 39888c2ecf20Sopenharmony_ci pvr2_hdw_render_useless(hdw); 39898c2ecf20Sopenharmony_ci } 39908c2ecf20Sopenharmony_ci 39918c2ecf20Sopenharmony_ci kfree(da); 39928c2ecf20Sopenharmony_ci} 39938c2ecf20Sopenharmony_ci 39948c2ecf20Sopenharmony_ci 39958c2ecf20Sopenharmony_ciint pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *hdw) 39968c2ecf20Sopenharmony_ci{ 39978c2ecf20Sopenharmony_ci return pvr2_issue_simple_cmd(hdw,FX2CMD_DEEP_RESET); 39988c2ecf20Sopenharmony_ci} 39998c2ecf20Sopenharmony_ci 40008c2ecf20Sopenharmony_ci 40018c2ecf20Sopenharmony_ciint pvr2_hdw_cmd_powerup(struct pvr2_hdw *hdw) 40028c2ecf20Sopenharmony_ci{ 40038c2ecf20Sopenharmony_ci return pvr2_issue_simple_cmd(hdw,FX2CMD_POWER_ON); 40048c2ecf20Sopenharmony_ci} 40058c2ecf20Sopenharmony_ci 40068c2ecf20Sopenharmony_ci 40078c2ecf20Sopenharmony_ci 40088c2ecf20Sopenharmony_ciint pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *hdw) 40098c2ecf20Sopenharmony_ci{ 40108c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 40118c2ecf20Sopenharmony_ci "Requesting decoder reset"); 40128c2ecf20Sopenharmony_ci if (hdw->decoder_client_id) { 40138c2ecf20Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, hdw->decoder_client_id, 40148c2ecf20Sopenharmony_ci core, reset, 0); 40158c2ecf20Sopenharmony_ci pvr2_hdw_cx25840_vbi_hack(hdw); 40168c2ecf20Sopenharmony_ci return 0; 40178c2ecf20Sopenharmony_ci } 40188c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, 40198c2ecf20Sopenharmony_ci "Unable to reset decoder: nothing attached"); 40208c2ecf20Sopenharmony_ci return -ENOTTY; 40218c2ecf20Sopenharmony_ci} 40228c2ecf20Sopenharmony_ci 40238c2ecf20Sopenharmony_ci 40248c2ecf20Sopenharmony_cistatic int pvr2_hdw_cmd_hcw_demod_reset(struct pvr2_hdw *hdw, int onoff) 40258c2ecf20Sopenharmony_ci{ 40268c2ecf20Sopenharmony_ci hdw->flag_ok = !0; 40278c2ecf20Sopenharmony_ci 40288c2ecf20Sopenharmony_ci /* Use this for Hauppauge 160xxx only */ 40298c2ecf20Sopenharmony_ci if (le16_to_cpu(hdw->usb_dev->descriptor.idVendor) == 0x2040 && 40308c2ecf20Sopenharmony_ci (le16_to_cpu(hdw->usb_dev->descriptor.idProduct) == 0x7502 || 40318c2ecf20Sopenharmony_ci le16_to_cpu(hdw->usb_dev->descriptor.idProduct) == 0x7510)) { 40328c2ecf20Sopenharmony_ci pr_debug("%s(): resetting demod on Hauppauge 160xxx platform skipped\n", 40338c2ecf20Sopenharmony_ci __func__); 40348c2ecf20Sopenharmony_ci /* Can't reset 160xxx or it will trash Demod tristate */ 40358c2ecf20Sopenharmony_ci return pvr2_issue_simple_cmd(hdw, 40368c2ecf20Sopenharmony_ci FX2CMD_HCW_MAKO_SLEEP_PIN | 40378c2ecf20Sopenharmony_ci (1 << 8) | 40388c2ecf20Sopenharmony_ci ((onoff ? 1 : 0) << 16)); 40398c2ecf20Sopenharmony_ci } 40408c2ecf20Sopenharmony_ci 40418c2ecf20Sopenharmony_ci return pvr2_issue_simple_cmd(hdw, 40428c2ecf20Sopenharmony_ci FX2CMD_HCW_DEMOD_RESETIN | 40438c2ecf20Sopenharmony_ci (1 << 8) | 40448c2ecf20Sopenharmony_ci ((onoff ? 1 : 0) << 16)); 40458c2ecf20Sopenharmony_ci} 40468c2ecf20Sopenharmony_ci 40478c2ecf20Sopenharmony_ci 40488c2ecf20Sopenharmony_cistatic int pvr2_hdw_cmd_onair_fe_power_ctrl(struct pvr2_hdw *hdw, int onoff) 40498c2ecf20Sopenharmony_ci{ 40508c2ecf20Sopenharmony_ci hdw->flag_ok = !0; 40518c2ecf20Sopenharmony_ci return pvr2_issue_simple_cmd(hdw,(onoff ? 40528c2ecf20Sopenharmony_ci FX2CMD_ONAIR_DTV_POWER_ON : 40538c2ecf20Sopenharmony_ci FX2CMD_ONAIR_DTV_POWER_OFF)); 40548c2ecf20Sopenharmony_ci} 40558c2ecf20Sopenharmony_ci 40568c2ecf20Sopenharmony_ci 40578c2ecf20Sopenharmony_cistatic int pvr2_hdw_cmd_onair_digital_path_ctrl(struct pvr2_hdw *hdw, 40588c2ecf20Sopenharmony_ci int onoff) 40598c2ecf20Sopenharmony_ci{ 40608c2ecf20Sopenharmony_ci return pvr2_issue_simple_cmd(hdw,(onoff ? 40618c2ecf20Sopenharmony_ci FX2CMD_ONAIR_DTV_STREAMING_ON : 40628c2ecf20Sopenharmony_ci FX2CMD_ONAIR_DTV_STREAMING_OFF)); 40638c2ecf20Sopenharmony_ci} 40648c2ecf20Sopenharmony_ci 40658c2ecf20Sopenharmony_ci 40668c2ecf20Sopenharmony_cistatic void pvr2_hdw_cmd_modeswitch(struct pvr2_hdw *hdw,int digitalFl) 40678c2ecf20Sopenharmony_ci{ 40688c2ecf20Sopenharmony_ci int cmode; 40698c2ecf20Sopenharmony_ci /* Compare digital/analog desired setting with current setting. If 40708c2ecf20Sopenharmony_ci they don't match, fix it... */ 40718c2ecf20Sopenharmony_ci cmode = (digitalFl ? PVR2_PATHWAY_DIGITAL : PVR2_PATHWAY_ANALOG); 40728c2ecf20Sopenharmony_ci if (cmode == hdw->pathway_state) { 40738c2ecf20Sopenharmony_ci /* They match; nothing to do */ 40748c2ecf20Sopenharmony_ci return; 40758c2ecf20Sopenharmony_ci } 40768c2ecf20Sopenharmony_ci 40778c2ecf20Sopenharmony_ci switch (hdw->hdw_desc->digital_control_scheme) { 40788c2ecf20Sopenharmony_ci case PVR2_DIGITAL_SCHEME_HAUPPAUGE: 40798c2ecf20Sopenharmony_ci pvr2_hdw_cmd_hcw_demod_reset(hdw,digitalFl); 40808c2ecf20Sopenharmony_ci if (cmode == PVR2_PATHWAY_ANALOG) { 40818c2ecf20Sopenharmony_ci /* If moving to analog mode, also force the decoder 40828c2ecf20Sopenharmony_ci to reset. If no decoder is attached, then it's 40838c2ecf20Sopenharmony_ci ok to ignore this because if/when the decoder 40848c2ecf20Sopenharmony_ci attaches, it will reset itself at that time. */ 40858c2ecf20Sopenharmony_ci pvr2_hdw_cmd_decoder_reset(hdw); 40868c2ecf20Sopenharmony_ci } 40878c2ecf20Sopenharmony_ci break; 40888c2ecf20Sopenharmony_ci case PVR2_DIGITAL_SCHEME_ONAIR: 40898c2ecf20Sopenharmony_ci /* Supposedly we should always have the power on whether in 40908c2ecf20Sopenharmony_ci digital or analog mode. But for now do what appears to 40918c2ecf20Sopenharmony_ci work... */ 40928c2ecf20Sopenharmony_ci pvr2_hdw_cmd_onair_fe_power_ctrl(hdw,digitalFl); 40938c2ecf20Sopenharmony_ci break; 40948c2ecf20Sopenharmony_ci default: break; 40958c2ecf20Sopenharmony_ci } 40968c2ecf20Sopenharmony_ci 40978c2ecf20Sopenharmony_ci pvr2_hdw_untrip_unlocked(hdw); 40988c2ecf20Sopenharmony_ci hdw->pathway_state = cmode; 40998c2ecf20Sopenharmony_ci} 41008c2ecf20Sopenharmony_ci 41018c2ecf20Sopenharmony_ci 41028c2ecf20Sopenharmony_cistatic void pvr2_led_ctrl_hauppauge(struct pvr2_hdw *hdw, int onoff) 41038c2ecf20Sopenharmony_ci{ 41048c2ecf20Sopenharmony_ci /* change some GPIO data 41058c2ecf20Sopenharmony_ci * 41068c2ecf20Sopenharmony_ci * note: bit d7 of dir appears to control the LED, 41078c2ecf20Sopenharmony_ci * so we shut it off here. 41088c2ecf20Sopenharmony_ci * 41098c2ecf20Sopenharmony_ci */ 41108c2ecf20Sopenharmony_ci if (onoff) { 41118c2ecf20Sopenharmony_ci pvr2_hdw_gpio_chg_dir(hdw, 0xffffffff, 0x00000481); 41128c2ecf20Sopenharmony_ci } else { 41138c2ecf20Sopenharmony_ci pvr2_hdw_gpio_chg_dir(hdw, 0xffffffff, 0x00000401); 41148c2ecf20Sopenharmony_ci } 41158c2ecf20Sopenharmony_ci pvr2_hdw_gpio_chg_out(hdw, 0xffffffff, 0x00000000); 41168c2ecf20Sopenharmony_ci} 41178c2ecf20Sopenharmony_ci 41188c2ecf20Sopenharmony_ci 41198c2ecf20Sopenharmony_citypedef void (*led_method_func)(struct pvr2_hdw *,int); 41208c2ecf20Sopenharmony_ci 41218c2ecf20Sopenharmony_cistatic led_method_func led_methods[] = { 41228c2ecf20Sopenharmony_ci [PVR2_LED_SCHEME_HAUPPAUGE] = pvr2_led_ctrl_hauppauge, 41238c2ecf20Sopenharmony_ci}; 41248c2ecf20Sopenharmony_ci 41258c2ecf20Sopenharmony_ci 41268c2ecf20Sopenharmony_ci/* Toggle LED */ 41278c2ecf20Sopenharmony_cistatic void pvr2_led_ctrl(struct pvr2_hdw *hdw,int onoff) 41288c2ecf20Sopenharmony_ci{ 41298c2ecf20Sopenharmony_ci unsigned int scheme_id; 41308c2ecf20Sopenharmony_ci led_method_func fp; 41318c2ecf20Sopenharmony_ci 41328c2ecf20Sopenharmony_ci if ((!onoff) == (!hdw->led_on)) return; 41338c2ecf20Sopenharmony_ci 41348c2ecf20Sopenharmony_ci hdw->led_on = onoff != 0; 41358c2ecf20Sopenharmony_ci 41368c2ecf20Sopenharmony_ci scheme_id = hdw->hdw_desc->led_scheme; 41378c2ecf20Sopenharmony_ci if (scheme_id < ARRAY_SIZE(led_methods)) { 41388c2ecf20Sopenharmony_ci fp = led_methods[scheme_id]; 41398c2ecf20Sopenharmony_ci } else { 41408c2ecf20Sopenharmony_ci fp = NULL; 41418c2ecf20Sopenharmony_ci } 41428c2ecf20Sopenharmony_ci 41438c2ecf20Sopenharmony_ci if (fp) (*fp)(hdw,onoff); 41448c2ecf20Sopenharmony_ci} 41458c2ecf20Sopenharmony_ci 41468c2ecf20Sopenharmony_ci 41478c2ecf20Sopenharmony_ci/* Stop / start video stream transport */ 41488c2ecf20Sopenharmony_cistatic int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl) 41498c2ecf20Sopenharmony_ci{ 41508c2ecf20Sopenharmony_ci int ret; 41518c2ecf20Sopenharmony_ci 41528c2ecf20Sopenharmony_ci /* If we're in analog mode, then just issue the usual analog 41538c2ecf20Sopenharmony_ci command. */ 41548c2ecf20Sopenharmony_ci if (hdw->pathway_state == PVR2_PATHWAY_ANALOG) { 41558c2ecf20Sopenharmony_ci return pvr2_issue_simple_cmd(hdw, 41568c2ecf20Sopenharmony_ci (runFl ? 41578c2ecf20Sopenharmony_ci FX2CMD_STREAMING_ON : 41588c2ecf20Sopenharmony_ci FX2CMD_STREAMING_OFF)); 41598c2ecf20Sopenharmony_ci /*Note: Not reached */ 41608c2ecf20Sopenharmony_ci } 41618c2ecf20Sopenharmony_ci 41628c2ecf20Sopenharmony_ci if (hdw->pathway_state != PVR2_PATHWAY_DIGITAL) { 41638c2ecf20Sopenharmony_ci /* Whoops, we don't know what mode we're in... */ 41648c2ecf20Sopenharmony_ci return -EINVAL; 41658c2ecf20Sopenharmony_ci } 41668c2ecf20Sopenharmony_ci 41678c2ecf20Sopenharmony_ci /* To get here we have to be in digital mode. The mechanism here 41688c2ecf20Sopenharmony_ci is unfortunately different for different vendors. So we switch 41698c2ecf20Sopenharmony_ci on the device's digital scheme attribute in order to figure out 41708c2ecf20Sopenharmony_ci what to do. */ 41718c2ecf20Sopenharmony_ci switch (hdw->hdw_desc->digital_control_scheme) { 41728c2ecf20Sopenharmony_ci case PVR2_DIGITAL_SCHEME_HAUPPAUGE: 41738c2ecf20Sopenharmony_ci return pvr2_issue_simple_cmd(hdw, 41748c2ecf20Sopenharmony_ci (runFl ? 41758c2ecf20Sopenharmony_ci FX2CMD_HCW_DTV_STREAMING_ON : 41768c2ecf20Sopenharmony_ci FX2CMD_HCW_DTV_STREAMING_OFF)); 41778c2ecf20Sopenharmony_ci case PVR2_DIGITAL_SCHEME_ONAIR: 41788c2ecf20Sopenharmony_ci ret = pvr2_issue_simple_cmd(hdw, 41798c2ecf20Sopenharmony_ci (runFl ? 41808c2ecf20Sopenharmony_ci FX2CMD_STREAMING_ON : 41818c2ecf20Sopenharmony_ci FX2CMD_STREAMING_OFF)); 41828c2ecf20Sopenharmony_ci if (ret) return ret; 41838c2ecf20Sopenharmony_ci return pvr2_hdw_cmd_onair_digital_path_ctrl(hdw,runFl); 41848c2ecf20Sopenharmony_ci default: 41858c2ecf20Sopenharmony_ci return -EINVAL; 41868c2ecf20Sopenharmony_ci } 41878c2ecf20Sopenharmony_ci} 41888c2ecf20Sopenharmony_ci 41898c2ecf20Sopenharmony_ci 41908c2ecf20Sopenharmony_ci/* Evaluate whether or not state_pathway_ok can change */ 41918c2ecf20Sopenharmony_cistatic int state_eval_pathway_ok(struct pvr2_hdw *hdw) 41928c2ecf20Sopenharmony_ci{ 41938c2ecf20Sopenharmony_ci if (hdw->state_pathway_ok) { 41948c2ecf20Sopenharmony_ci /* Nothing to do if pathway is already ok */ 41958c2ecf20Sopenharmony_ci return 0; 41968c2ecf20Sopenharmony_ci } 41978c2ecf20Sopenharmony_ci if (!hdw->state_pipeline_idle) { 41988c2ecf20Sopenharmony_ci /* Not allowed to change anything if pipeline is not idle */ 41998c2ecf20Sopenharmony_ci return 0; 42008c2ecf20Sopenharmony_ci } 42018c2ecf20Sopenharmony_ci pvr2_hdw_cmd_modeswitch(hdw,hdw->input_val == PVR2_CVAL_INPUT_DTV); 42028c2ecf20Sopenharmony_ci hdw->state_pathway_ok = !0; 42038c2ecf20Sopenharmony_ci trace_stbit("state_pathway_ok",hdw->state_pathway_ok); 42048c2ecf20Sopenharmony_ci return !0; 42058c2ecf20Sopenharmony_ci} 42068c2ecf20Sopenharmony_ci 42078c2ecf20Sopenharmony_ci 42088c2ecf20Sopenharmony_ci/* Evaluate whether or not state_encoder_ok can change */ 42098c2ecf20Sopenharmony_cistatic int state_eval_encoder_ok(struct pvr2_hdw *hdw) 42108c2ecf20Sopenharmony_ci{ 42118c2ecf20Sopenharmony_ci if (hdw->state_encoder_ok) return 0; 42128c2ecf20Sopenharmony_ci if (hdw->flag_tripped) return 0; 42138c2ecf20Sopenharmony_ci if (hdw->state_encoder_run) return 0; 42148c2ecf20Sopenharmony_ci if (hdw->state_encoder_config) return 0; 42158c2ecf20Sopenharmony_ci if (hdw->state_decoder_run) return 0; 42168c2ecf20Sopenharmony_ci if (hdw->state_usbstream_run) return 0; 42178c2ecf20Sopenharmony_ci if (hdw->pathway_state == PVR2_PATHWAY_DIGITAL) { 42188c2ecf20Sopenharmony_ci if (!hdw->hdw_desc->flag_digital_requires_cx23416) return 0; 42198c2ecf20Sopenharmony_ci } else if (hdw->pathway_state != PVR2_PATHWAY_ANALOG) { 42208c2ecf20Sopenharmony_ci return 0; 42218c2ecf20Sopenharmony_ci } 42228c2ecf20Sopenharmony_ci 42238c2ecf20Sopenharmony_ci if (pvr2_upload_firmware2(hdw) < 0) { 42248c2ecf20Sopenharmony_ci hdw->flag_tripped = !0; 42258c2ecf20Sopenharmony_ci trace_stbit("flag_tripped",hdw->flag_tripped); 42268c2ecf20Sopenharmony_ci return !0; 42278c2ecf20Sopenharmony_ci } 42288c2ecf20Sopenharmony_ci hdw->state_encoder_ok = !0; 42298c2ecf20Sopenharmony_ci trace_stbit("state_encoder_ok",hdw->state_encoder_ok); 42308c2ecf20Sopenharmony_ci return !0; 42318c2ecf20Sopenharmony_ci} 42328c2ecf20Sopenharmony_ci 42338c2ecf20Sopenharmony_ci 42348c2ecf20Sopenharmony_ci/* Evaluate whether or not state_encoder_config can change */ 42358c2ecf20Sopenharmony_cistatic int state_eval_encoder_config(struct pvr2_hdw *hdw) 42368c2ecf20Sopenharmony_ci{ 42378c2ecf20Sopenharmony_ci if (hdw->state_encoder_config) { 42388c2ecf20Sopenharmony_ci if (hdw->state_encoder_ok) { 42398c2ecf20Sopenharmony_ci if (hdw->state_pipeline_req && 42408c2ecf20Sopenharmony_ci !hdw->state_pipeline_pause) return 0; 42418c2ecf20Sopenharmony_ci } 42428c2ecf20Sopenharmony_ci hdw->state_encoder_config = 0; 42438c2ecf20Sopenharmony_ci hdw->state_encoder_waitok = 0; 42448c2ecf20Sopenharmony_ci trace_stbit("state_encoder_waitok",hdw->state_encoder_waitok); 42458c2ecf20Sopenharmony_ci /* paranoia - solve race if timer just completed */ 42468c2ecf20Sopenharmony_ci del_timer_sync(&hdw->encoder_wait_timer); 42478c2ecf20Sopenharmony_ci } else { 42488c2ecf20Sopenharmony_ci if (!hdw->state_pathway_ok || 42498c2ecf20Sopenharmony_ci (hdw->pathway_state != PVR2_PATHWAY_ANALOG) || 42508c2ecf20Sopenharmony_ci !hdw->state_encoder_ok || 42518c2ecf20Sopenharmony_ci !hdw->state_pipeline_idle || 42528c2ecf20Sopenharmony_ci hdw->state_pipeline_pause || 42538c2ecf20Sopenharmony_ci !hdw->state_pipeline_req || 42548c2ecf20Sopenharmony_ci !hdw->state_pipeline_config) { 42558c2ecf20Sopenharmony_ci /* We must reset the enforced wait interval if 42568c2ecf20Sopenharmony_ci anything has happened that might have disturbed 42578c2ecf20Sopenharmony_ci the encoder. This should be a rare case. */ 42588c2ecf20Sopenharmony_ci if (timer_pending(&hdw->encoder_wait_timer)) { 42598c2ecf20Sopenharmony_ci del_timer_sync(&hdw->encoder_wait_timer); 42608c2ecf20Sopenharmony_ci } 42618c2ecf20Sopenharmony_ci if (hdw->state_encoder_waitok) { 42628c2ecf20Sopenharmony_ci /* Must clear the state - therefore we did 42638c2ecf20Sopenharmony_ci something to a state bit and must also 42648c2ecf20Sopenharmony_ci return true. */ 42658c2ecf20Sopenharmony_ci hdw->state_encoder_waitok = 0; 42668c2ecf20Sopenharmony_ci trace_stbit("state_encoder_waitok", 42678c2ecf20Sopenharmony_ci hdw->state_encoder_waitok); 42688c2ecf20Sopenharmony_ci return !0; 42698c2ecf20Sopenharmony_ci } 42708c2ecf20Sopenharmony_ci return 0; 42718c2ecf20Sopenharmony_ci } 42728c2ecf20Sopenharmony_ci if (!hdw->state_encoder_waitok) { 42738c2ecf20Sopenharmony_ci if (!timer_pending(&hdw->encoder_wait_timer)) { 42748c2ecf20Sopenharmony_ci /* waitok flag wasn't set and timer isn't 42758c2ecf20Sopenharmony_ci running. Check flag once more to avoid 42768c2ecf20Sopenharmony_ci a race then start the timer. This is 42778c2ecf20Sopenharmony_ci the point when we measure out a minimal 42788c2ecf20Sopenharmony_ci quiet interval before doing something to 42798c2ecf20Sopenharmony_ci the encoder. */ 42808c2ecf20Sopenharmony_ci if (!hdw->state_encoder_waitok) { 42818c2ecf20Sopenharmony_ci hdw->encoder_wait_timer.expires = 42828c2ecf20Sopenharmony_ci jiffies + msecs_to_jiffies( 42838c2ecf20Sopenharmony_ci TIME_MSEC_ENCODER_WAIT); 42848c2ecf20Sopenharmony_ci add_timer(&hdw->encoder_wait_timer); 42858c2ecf20Sopenharmony_ci } 42868c2ecf20Sopenharmony_ci } 42878c2ecf20Sopenharmony_ci /* We can't continue until we know we have been 42888c2ecf20Sopenharmony_ci quiet for the interval measured by this 42898c2ecf20Sopenharmony_ci timer. */ 42908c2ecf20Sopenharmony_ci return 0; 42918c2ecf20Sopenharmony_ci } 42928c2ecf20Sopenharmony_ci pvr2_encoder_configure(hdw); 42938c2ecf20Sopenharmony_ci if (hdw->state_encoder_ok) hdw->state_encoder_config = !0; 42948c2ecf20Sopenharmony_ci } 42958c2ecf20Sopenharmony_ci trace_stbit("state_encoder_config",hdw->state_encoder_config); 42968c2ecf20Sopenharmony_ci return !0; 42978c2ecf20Sopenharmony_ci} 42988c2ecf20Sopenharmony_ci 42998c2ecf20Sopenharmony_ci 43008c2ecf20Sopenharmony_ci/* Return true if the encoder should not be running. */ 43018c2ecf20Sopenharmony_cistatic int state_check_disable_encoder_run(struct pvr2_hdw *hdw) 43028c2ecf20Sopenharmony_ci{ 43038c2ecf20Sopenharmony_ci if (!hdw->state_encoder_ok) { 43048c2ecf20Sopenharmony_ci /* Encoder isn't healthy at the moment, so stop it. */ 43058c2ecf20Sopenharmony_ci return !0; 43068c2ecf20Sopenharmony_ci } 43078c2ecf20Sopenharmony_ci if (!hdw->state_pathway_ok) { 43088c2ecf20Sopenharmony_ci /* Mode is not understood at the moment (i.e. it wants to 43098c2ecf20Sopenharmony_ci change), so encoder must be stopped. */ 43108c2ecf20Sopenharmony_ci return !0; 43118c2ecf20Sopenharmony_ci } 43128c2ecf20Sopenharmony_ci 43138c2ecf20Sopenharmony_ci switch (hdw->pathway_state) { 43148c2ecf20Sopenharmony_ci case PVR2_PATHWAY_ANALOG: 43158c2ecf20Sopenharmony_ci if (!hdw->state_decoder_run) { 43168c2ecf20Sopenharmony_ci /* We're in analog mode and the decoder is not 43178c2ecf20Sopenharmony_ci running; thus the encoder should be stopped as 43188c2ecf20Sopenharmony_ci well. */ 43198c2ecf20Sopenharmony_ci return !0; 43208c2ecf20Sopenharmony_ci } 43218c2ecf20Sopenharmony_ci break; 43228c2ecf20Sopenharmony_ci case PVR2_PATHWAY_DIGITAL: 43238c2ecf20Sopenharmony_ci if (hdw->state_encoder_runok) { 43248c2ecf20Sopenharmony_ci /* This is a funny case. We're in digital mode so 43258c2ecf20Sopenharmony_ci really the encoder should be stopped. However 43268c2ecf20Sopenharmony_ci if it really is running, only kill it after 43278c2ecf20Sopenharmony_ci runok has been set. This gives a chance for the 43288c2ecf20Sopenharmony_ci onair quirk to function (encoder must run 43298c2ecf20Sopenharmony_ci briefly first, at least once, before onair 43308c2ecf20Sopenharmony_ci digital streaming can work). */ 43318c2ecf20Sopenharmony_ci return !0; 43328c2ecf20Sopenharmony_ci } 43338c2ecf20Sopenharmony_ci break; 43348c2ecf20Sopenharmony_ci default: 43358c2ecf20Sopenharmony_ci /* Unknown mode; so encoder should be stopped. */ 43368c2ecf20Sopenharmony_ci return !0; 43378c2ecf20Sopenharmony_ci } 43388c2ecf20Sopenharmony_ci 43398c2ecf20Sopenharmony_ci /* If we get here, we haven't found a reason to stop the 43408c2ecf20Sopenharmony_ci encoder. */ 43418c2ecf20Sopenharmony_ci return 0; 43428c2ecf20Sopenharmony_ci} 43438c2ecf20Sopenharmony_ci 43448c2ecf20Sopenharmony_ci 43458c2ecf20Sopenharmony_ci/* Return true if the encoder should be running. */ 43468c2ecf20Sopenharmony_cistatic int state_check_enable_encoder_run(struct pvr2_hdw *hdw) 43478c2ecf20Sopenharmony_ci{ 43488c2ecf20Sopenharmony_ci if (!hdw->state_encoder_ok) { 43498c2ecf20Sopenharmony_ci /* Don't run the encoder if it isn't healthy... */ 43508c2ecf20Sopenharmony_ci return 0; 43518c2ecf20Sopenharmony_ci } 43528c2ecf20Sopenharmony_ci if (!hdw->state_pathway_ok) { 43538c2ecf20Sopenharmony_ci /* Don't run the encoder if we don't (yet) know what mode 43548c2ecf20Sopenharmony_ci we need to be in... */ 43558c2ecf20Sopenharmony_ci return 0; 43568c2ecf20Sopenharmony_ci } 43578c2ecf20Sopenharmony_ci 43588c2ecf20Sopenharmony_ci switch (hdw->pathway_state) { 43598c2ecf20Sopenharmony_ci case PVR2_PATHWAY_ANALOG: 43608c2ecf20Sopenharmony_ci if (hdw->state_decoder_run && hdw->state_decoder_ready) { 43618c2ecf20Sopenharmony_ci /* In analog mode, if the decoder is running, then 43628c2ecf20Sopenharmony_ci run the encoder. */ 43638c2ecf20Sopenharmony_ci return !0; 43648c2ecf20Sopenharmony_ci } 43658c2ecf20Sopenharmony_ci break; 43668c2ecf20Sopenharmony_ci case PVR2_PATHWAY_DIGITAL: 43678c2ecf20Sopenharmony_ci if ((hdw->hdw_desc->digital_control_scheme == 43688c2ecf20Sopenharmony_ci PVR2_DIGITAL_SCHEME_ONAIR) && 43698c2ecf20Sopenharmony_ci !hdw->state_encoder_runok) { 43708c2ecf20Sopenharmony_ci /* This is a quirk. OnAir hardware won't stream 43718c2ecf20Sopenharmony_ci digital until the encoder has been run at least 43728c2ecf20Sopenharmony_ci once, for a minimal period of time (empiricially 43738c2ecf20Sopenharmony_ci measured to be 1/4 second). So if we're on 43748c2ecf20Sopenharmony_ci OnAir hardware and the encoder has never been 43758c2ecf20Sopenharmony_ci run at all, then start the encoder. Normal 43768c2ecf20Sopenharmony_ci state machine logic in the driver will 43778c2ecf20Sopenharmony_ci automatically handle the remaining bits. */ 43788c2ecf20Sopenharmony_ci return !0; 43798c2ecf20Sopenharmony_ci } 43808c2ecf20Sopenharmony_ci break; 43818c2ecf20Sopenharmony_ci default: 43828c2ecf20Sopenharmony_ci /* For completeness (unknown mode; encoder won't run ever) */ 43838c2ecf20Sopenharmony_ci break; 43848c2ecf20Sopenharmony_ci } 43858c2ecf20Sopenharmony_ci /* If we get here, then we haven't found any reason to run the 43868c2ecf20Sopenharmony_ci encoder, so don't run it. */ 43878c2ecf20Sopenharmony_ci return 0; 43888c2ecf20Sopenharmony_ci} 43898c2ecf20Sopenharmony_ci 43908c2ecf20Sopenharmony_ci 43918c2ecf20Sopenharmony_ci/* Evaluate whether or not state_encoder_run can change */ 43928c2ecf20Sopenharmony_cistatic int state_eval_encoder_run(struct pvr2_hdw *hdw) 43938c2ecf20Sopenharmony_ci{ 43948c2ecf20Sopenharmony_ci if (hdw->state_encoder_run) { 43958c2ecf20Sopenharmony_ci if (!state_check_disable_encoder_run(hdw)) return 0; 43968c2ecf20Sopenharmony_ci if (hdw->state_encoder_ok) { 43978c2ecf20Sopenharmony_ci del_timer_sync(&hdw->encoder_run_timer); 43988c2ecf20Sopenharmony_ci if (pvr2_encoder_stop(hdw) < 0) return !0; 43998c2ecf20Sopenharmony_ci } 44008c2ecf20Sopenharmony_ci hdw->state_encoder_run = 0; 44018c2ecf20Sopenharmony_ci } else { 44028c2ecf20Sopenharmony_ci if (!state_check_enable_encoder_run(hdw)) return 0; 44038c2ecf20Sopenharmony_ci if (pvr2_encoder_start(hdw) < 0) return !0; 44048c2ecf20Sopenharmony_ci hdw->state_encoder_run = !0; 44058c2ecf20Sopenharmony_ci if (!hdw->state_encoder_runok) { 44068c2ecf20Sopenharmony_ci hdw->encoder_run_timer.expires = jiffies + 44078c2ecf20Sopenharmony_ci msecs_to_jiffies(TIME_MSEC_ENCODER_OK); 44088c2ecf20Sopenharmony_ci add_timer(&hdw->encoder_run_timer); 44098c2ecf20Sopenharmony_ci } 44108c2ecf20Sopenharmony_ci } 44118c2ecf20Sopenharmony_ci trace_stbit("state_encoder_run",hdw->state_encoder_run); 44128c2ecf20Sopenharmony_ci return !0; 44138c2ecf20Sopenharmony_ci} 44148c2ecf20Sopenharmony_ci 44158c2ecf20Sopenharmony_ci 44168c2ecf20Sopenharmony_ci/* Timeout function for quiescent timer. */ 44178c2ecf20Sopenharmony_cistatic void pvr2_hdw_quiescent_timeout(struct timer_list *t) 44188c2ecf20Sopenharmony_ci{ 44198c2ecf20Sopenharmony_ci struct pvr2_hdw *hdw = from_timer(hdw, t, quiescent_timer); 44208c2ecf20Sopenharmony_ci hdw->state_decoder_quiescent = !0; 44218c2ecf20Sopenharmony_ci trace_stbit("state_decoder_quiescent",hdw->state_decoder_quiescent); 44228c2ecf20Sopenharmony_ci hdw->state_stale = !0; 44238c2ecf20Sopenharmony_ci schedule_work(&hdw->workpoll); 44248c2ecf20Sopenharmony_ci} 44258c2ecf20Sopenharmony_ci 44268c2ecf20Sopenharmony_ci 44278c2ecf20Sopenharmony_ci/* Timeout function for decoder stabilization timer. */ 44288c2ecf20Sopenharmony_cistatic void pvr2_hdw_decoder_stabilization_timeout(struct timer_list *t) 44298c2ecf20Sopenharmony_ci{ 44308c2ecf20Sopenharmony_ci struct pvr2_hdw *hdw = from_timer(hdw, t, decoder_stabilization_timer); 44318c2ecf20Sopenharmony_ci hdw->state_decoder_ready = !0; 44328c2ecf20Sopenharmony_ci trace_stbit("state_decoder_ready", hdw->state_decoder_ready); 44338c2ecf20Sopenharmony_ci hdw->state_stale = !0; 44348c2ecf20Sopenharmony_ci schedule_work(&hdw->workpoll); 44358c2ecf20Sopenharmony_ci} 44368c2ecf20Sopenharmony_ci 44378c2ecf20Sopenharmony_ci 44388c2ecf20Sopenharmony_ci/* Timeout function for encoder wait timer. */ 44398c2ecf20Sopenharmony_cistatic void pvr2_hdw_encoder_wait_timeout(struct timer_list *t) 44408c2ecf20Sopenharmony_ci{ 44418c2ecf20Sopenharmony_ci struct pvr2_hdw *hdw = from_timer(hdw, t, encoder_wait_timer); 44428c2ecf20Sopenharmony_ci hdw->state_encoder_waitok = !0; 44438c2ecf20Sopenharmony_ci trace_stbit("state_encoder_waitok",hdw->state_encoder_waitok); 44448c2ecf20Sopenharmony_ci hdw->state_stale = !0; 44458c2ecf20Sopenharmony_ci schedule_work(&hdw->workpoll); 44468c2ecf20Sopenharmony_ci} 44478c2ecf20Sopenharmony_ci 44488c2ecf20Sopenharmony_ci 44498c2ecf20Sopenharmony_ci/* Timeout function for encoder run timer. */ 44508c2ecf20Sopenharmony_cistatic void pvr2_hdw_encoder_run_timeout(struct timer_list *t) 44518c2ecf20Sopenharmony_ci{ 44528c2ecf20Sopenharmony_ci struct pvr2_hdw *hdw = from_timer(hdw, t, encoder_run_timer); 44538c2ecf20Sopenharmony_ci if (!hdw->state_encoder_runok) { 44548c2ecf20Sopenharmony_ci hdw->state_encoder_runok = !0; 44558c2ecf20Sopenharmony_ci trace_stbit("state_encoder_runok",hdw->state_encoder_runok); 44568c2ecf20Sopenharmony_ci hdw->state_stale = !0; 44578c2ecf20Sopenharmony_ci schedule_work(&hdw->workpoll); 44588c2ecf20Sopenharmony_ci } 44598c2ecf20Sopenharmony_ci} 44608c2ecf20Sopenharmony_ci 44618c2ecf20Sopenharmony_ci 44628c2ecf20Sopenharmony_ci/* Evaluate whether or not state_decoder_run can change */ 44638c2ecf20Sopenharmony_cistatic int state_eval_decoder_run(struct pvr2_hdw *hdw) 44648c2ecf20Sopenharmony_ci{ 44658c2ecf20Sopenharmony_ci if (hdw->state_decoder_run) { 44668c2ecf20Sopenharmony_ci if (hdw->state_encoder_ok) { 44678c2ecf20Sopenharmony_ci if (hdw->state_pipeline_req && 44688c2ecf20Sopenharmony_ci !hdw->state_pipeline_pause && 44698c2ecf20Sopenharmony_ci hdw->state_pathway_ok) return 0; 44708c2ecf20Sopenharmony_ci } 44718c2ecf20Sopenharmony_ci if (!hdw->flag_decoder_missed) { 44728c2ecf20Sopenharmony_ci pvr2_decoder_enable(hdw,0); 44738c2ecf20Sopenharmony_ci } 44748c2ecf20Sopenharmony_ci hdw->state_decoder_quiescent = 0; 44758c2ecf20Sopenharmony_ci hdw->state_decoder_run = 0; 44768c2ecf20Sopenharmony_ci /* paranoia - solve race if timer(s) just completed */ 44778c2ecf20Sopenharmony_ci del_timer_sync(&hdw->quiescent_timer); 44788c2ecf20Sopenharmony_ci /* Kill the stabilization timer, in case we're killing the 44798c2ecf20Sopenharmony_ci encoder before the previous stabilization interval has 44808c2ecf20Sopenharmony_ci been properly timed. */ 44818c2ecf20Sopenharmony_ci del_timer_sync(&hdw->decoder_stabilization_timer); 44828c2ecf20Sopenharmony_ci hdw->state_decoder_ready = 0; 44838c2ecf20Sopenharmony_ci } else { 44848c2ecf20Sopenharmony_ci if (!hdw->state_decoder_quiescent) { 44858c2ecf20Sopenharmony_ci if (!timer_pending(&hdw->quiescent_timer)) { 44868c2ecf20Sopenharmony_ci /* We don't do something about the 44878c2ecf20Sopenharmony_ci quiescent timer until right here because 44888c2ecf20Sopenharmony_ci we also want to catch cases where the 44898c2ecf20Sopenharmony_ci decoder was already not running (like 44908c2ecf20Sopenharmony_ci after initialization) as opposed to 44918c2ecf20Sopenharmony_ci knowing that we had just stopped it. 44928c2ecf20Sopenharmony_ci The second flag check is here to cover a 44938c2ecf20Sopenharmony_ci race - the timer could have run and set 44948c2ecf20Sopenharmony_ci this flag just after the previous check 44958c2ecf20Sopenharmony_ci but before we did the pending check. */ 44968c2ecf20Sopenharmony_ci if (!hdw->state_decoder_quiescent) { 44978c2ecf20Sopenharmony_ci hdw->quiescent_timer.expires = 44988c2ecf20Sopenharmony_ci jiffies + msecs_to_jiffies( 44998c2ecf20Sopenharmony_ci TIME_MSEC_DECODER_WAIT); 45008c2ecf20Sopenharmony_ci add_timer(&hdw->quiescent_timer); 45018c2ecf20Sopenharmony_ci } 45028c2ecf20Sopenharmony_ci } 45038c2ecf20Sopenharmony_ci /* Don't allow decoder to start again until it has 45048c2ecf20Sopenharmony_ci been quiesced first. This little detail should 45058c2ecf20Sopenharmony_ci hopefully further stabilize the encoder. */ 45068c2ecf20Sopenharmony_ci return 0; 45078c2ecf20Sopenharmony_ci } 45088c2ecf20Sopenharmony_ci if (!hdw->state_pathway_ok || 45098c2ecf20Sopenharmony_ci (hdw->pathway_state != PVR2_PATHWAY_ANALOG) || 45108c2ecf20Sopenharmony_ci !hdw->state_pipeline_req || 45118c2ecf20Sopenharmony_ci hdw->state_pipeline_pause || 45128c2ecf20Sopenharmony_ci !hdw->state_pipeline_config || 45138c2ecf20Sopenharmony_ci !hdw->state_encoder_config || 45148c2ecf20Sopenharmony_ci !hdw->state_encoder_ok) return 0; 45158c2ecf20Sopenharmony_ci del_timer_sync(&hdw->quiescent_timer); 45168c2ecf20Sopenharmony_ci if (hdw->flag_decoder_missed) return 0; 45178c2ecf20Sopenharmony_ci if (pvr2_decoder_enable(hdw,!0) < 0) return 0; 45188c2ecf20Sopenharmony_ci hdw->state_decoder_quiescent = 0; 45198c2ecf20Sopenharmony_ci hdw->state_decoder_ready = 0; 45208c2ecf20Sopenharmony_ci hdw->state_decoder_run = !0; 45218c2ecf20Sopenharmony_ci if (hdw->decoder_client_id == PVR2_CLIENT_ID_SAA7115) { 45228c2ecf20Sopenharmony_ci hdw->decoder_stabilization_timer.expires = 45238c2ecf20Sopenharmony_ci jiffies + msecs_to_jiffies( 45248c2ecf20Sopenharmony_ci TIME_MSEC_DECODER_STABILIZATION_WAIT); 45258c2ecf20Sopenharmony_ci add_timer(&hdw->decoder_stabilization_timer); 45268c2ecf20Sopenharmony_ci } else { 45278c2ecf20Sopenharmony_ci hdw->state_decoder_ready = !0; 45288c2ecf20Sopenharmony_ci } 45298c2ecf20Sopenharmony_ci } 45308c2ecf20Sopenharmony_ci trace_stbit("state_decoder_quiescent",hdw->state_decoder_quiescent); 45318c2ecf20Sopenharmony_ci trace_stbit("state_decoder_run",hdw->state_decoder_run); 45328c2ecf20Sopenharmony_ci trace_stbit("state_decoder_ready", hdw->state_decoder_ready); 45338c2ecf20Sopenharmony_ci return !0; 45348c2ecf20Sopenharmony_ci} 45358c2ecf20Sopenharmony_ci 45368c2ecf20Sopenharmony_ci 45378c2ecf20Sopenharmony_ci/* Evaluate whether or not state_usbstream_run can change */ 45388c2ecf20Sopenharmony_cistatic int state_eval_usbstream_run(struct pvr2_hdw *hdw) 45398c2ecf20Sopenharmony_ci{ 45408c2ecf20Sopenharmony_ci if (hdw->state_usbstream_run) { 45418c2ecf20Sopenharmony_ci int fl = !0; 45428c2ecf20Sopenharmony_ci if (hdw->pathway_state == PVR2_PATHWAY_ANALOG) { 45438c2ecf20Sopenharmony_ci fl = (hdw->state_encoder_ok && 45448c2ecf20Sopenharmony_ci hdw->state_encoder_run); 45458c2ecf20Sopenharmony_ci } else if ((hdw->pathway_state == PVR2_PATHWAY_DIGITAL) && 45468c2ecf20Sopenharmony_ci (hdw->hdw_desc->flag_digital_requires_cx23416)) { 45478c2ecf20Sopenharmony_ci fl = hdw->state_encoder_ok; 45488c2ecf20Sopenharmony_ci } 45498c2ecf20Sopenharmony_ci if (fl && 45508c2ecf20Sopenharmony_ci hdw->state_pipeline_req && 45518c2ecf20Sopenharmony_ci !hdw->state_pipeline_pause && 45528c2ecf20Sopenharmony_ci hdw->state_pathway_ok) { 45538c2ecf20Sopenharmony_ci return 0; 45548c2ecf20Sopenharmony_ci } 45558c2ecf20Sopenharmony_ci pvr2_hdw_cmd_usbstream(hdw,0); 45568c2ecf20Sopenharmony_ci hdw->state_usbstream_run = 0; 45578c2ecf20Sopenharmony_ci } else { 45588c2ecf20Sopenharmony_ci if (!hdw->state_pipeline_req || 45598c2ecf20Sopenharmony_ci hdw->state_pipeline_pause || 45608c2ecf20Sopenharmony_ci !hdw->state_pathway_ok) return 0; 45618c2ecf20Sopenharmony_ci if (hdw->pathway_state == PVR2_PATHWAY_ANALOG) { 45628c2ecf20Sopenharmony_ci if (!hdw->state_encoder_ok || 45638c2ecf20Sopenharmony_ci !hdw->state_encoder_run) return 0; 45648c2ecf20Sopenharmony_ci } else if ((hdw->pathway_state == PVR2_PATHWAY_DIGITAL) && 45658c2ecf20Sopenharmony_ci (hdw->hdw_desc->flag_digital_requires_cx23416)) { 45668c2ecf20Sopenharmony_ci if (!hdw->state_encoder_ok) return 0; 45678c2ecf20Sopenharmony_ci if (hdw->state_encoder_run) return 0; 45688c2ecf20Sopenharmony_ci if (hdw->hdw_desc->digital_control_scheme == 45698c2ecf20Sopenharmony_ci PVR2_DIGITAL_SCHEME_ONAIR) { 45708c2ecf20Sopenharmony_ci /* OnAir digital receivers won't stream 45718c2ecf20Sopenharmony_ci unless the analog encoder has run first. 45728c2ecf20Sopenharmony_ci Why? I have no idea. But don't even 45738c2ecf20Sopenharmony_ci try until we know the analog side is 45748c2ecf20Sopenharmony_ci known to have run. */ 45758c2ecf20Sopenharmony_ci if (!hdw->state_encoder_runok) return 0; 45768c2ecf20Sopenharmony_ci } 45778c2ecf20Sopenharmony_ci } 45788c2ecf20Sopenharmony_ci if (pvr2_hdw_cmd_usbstream(hdw,!0) < 0) return 0; 45798c2ecf20Sopenharmony_ci hdw->state_usbstream_run = !0; 45808c2ecf20Sopenharmony_ci } 45818c2ecf20Sopenharmony_ci trace_stbit("state_usbstream_run",hdw->state_usbstream_run); 45828c2ecf20Sopenharmony_ci return !0; 45838c2ecf20Sopenharmony_ci} 45848c2ecf20Sopenharmony_ci 45858c2ecf20Sopenharmony_ci 45868c2ecf20Sopenharmony_ci/* Attempt to configure pipeline, if needed */ 45878c2ecf20Sopenharmony_cistatic int state_eval_pipeline_config(struct pvr2_hdw *hdw) 45888c2ecf20Sopenharmony_ci{ 45898c2ecf20Sopenharmony_ci if (hdw->state_pipeline_config || 45908c2ecf20Sopenharmony_ci hdw->state_pipeline_pause) return 0; 45918c2ecf20Sopenharmony_ci pvr2_hdw_commit_execute(hdw); 45928c2ecf20Sopenharmony_ci return !0; 45938c2ecf20Sopenharmony_ci} 45948c2ecf20Sopenharmony_ci 45958c2ecf20Sopenharmony_ci 45968c2ecf20Sopenharmony_ci/* Update pipeline idle and pipeline pause tracking states based on other 45978c2ecf20Sopenharmony_ci inputs. This must be called whenever the other relevant inputs have 45988c2ecf20Sopenharmony_ci changed. */ 45998c2ecf20Sopenharmony_cistatic int state_update_pipeline_state(struct pvr2_hdw *hdw) 46008c2ecf20Sopenharmony_ci{ 46018c2ecf20Sopenharmony_ci unsigned int st; 46028c2ecf20Sopenharmony_ci int updatedFl = 0; 46038c2ecf20Sopenharmony_ci /* Update pipeline state */ 46048c2ecf20Sopenharmony_ci st = !(hdw->state_encoder_run || 46058c2ecf20Sopenharmony_ci hdw->state_decoder_run || 46068c2ecf20Sopenharmony_ci hdw->state_usbstream_run || 46078c2ecf20Sopenharmony_ci (!hdw->state_decoder_quiescent)); 46088c2ecf20Sopenharmony_ci if (!st != !hdw->state_pipeline_idle) { 46098c2ecf20Sopenharmony_ci hdw->state_pipeline_idle = st; 46108c2ecf20Sopenharmony_ci updatedFl = !0; 46118c2ecf20Sopenharmony_ci } 46128c2ecf20Sopenharmony_ci if (hdw->state_pipeline_idle && hdw->state_pipeline_pause) { 46138c2ecf20Sopenharmony_ci hdw->state_pipeline_pause = 0; 46148c2ecf20Sopenharmony_ci updatedFl = !0; 46158c2ecf20Sopenharmony_ci } 46168c2ecf20Sopenharmony_ci return updatedFl; 46178c2ecf20Sopenharmony_ci} 46188c2ecf20Sopenharmony_ci 46198c2ecf20Sopenharmony_ci 46208c2ecf20Sopenharmony_citypedef int (*state_eval_func)(struct pvr2_hdw *); 46218c2ecf20Sopenharmony_ci 46228c2ecf20Sopenharmony_ci/* Set of functions to be run to evaluate various states in the driver. */ 46238c2ecf20Sopenharmony_cistatic const state_eval_func eval_funcs[] = { 46248c2ecf20Sopenharmony_ci state_eval_pathway_ok, 46258c2ecf20Sopenharmony_ci state_eval_pipeline_config, 46268c2ecf20Sopenharmony_ci state_eval_encoder_ok, 46278c2ecf20Sopenharmony_ci state_eval_encoder_config, 46288c2ecf20Sopenharmony_ci state_eval_decoder_run, 46298c2ecf20Sopenharmony_ci state_eval_encoder_run, 46308c2ecf20Sopenharmony_ci state_eval_usbstream_run, 46318c2ecf20Sopenharmony_ci}; 46328c2ecf20Sopenharmony_ci 46338c2ecf20Sopenharmony_ci 46348c2ecf20Sopenharmony_ci/* Process various states and return true if we did anything interesting. */ 46358c2ecf20Sopenharmony_cistatic int pvr2_hdw_state_update(struct pvr2_hdw *hdw) 46368c2ecf20Sopenharmony_ci{ 46378c2ecf20Sopenharmony_ci unsigned int i; 46388c2ecf20Sopenharmony_ci int state_updated = 0; 46398c2ecf20Sopenharmony_ci int check_flag; 46408c2ecf20Sopenharmony_ci 46418c2ecf20Sopenharmony_ci if (!hdw->state_stale) return 0; 46428c2ecf20Sopenharmony_ci if ((hdw->fw1_state != FW1_STATE_OK) || 46438c2ecf20Sopenharmony_ci !hdw->flag_ok) { 46448c2ecf20Sopenharmony_ci hdw->state_stale = 0; 46458c2ecf20Sopenharmony_ci return !0; 46468c2ecf20Sopenharmony_ci } 46478c2ecf20Sopenharmony_ci /* This loop is the heart of the entire driver. It keeps trying to 46488c2ecf20Sopenharmony_ci evaluate various bits of driver state until nothing changes for 46498c2ecf20Sopenharmony_ci one full iteration. Each "bit of state" tracks some global 46508c2ecf20Sopenharmony_ci aspect of the driver, e.g. whether decoder should run, if 46518c2ecf20Sopenharmony_ci pipeline is configured, usb streaming is on, etc. We separately 46528c2ecf20Sopenharmony_ci evaluate each of those questions based on other driver state to 46538c2ecf20Sopenharmony_ci arrive at the correct running configuration. */ 46548c2ecf20Sopenharmony_ci do { 46558c2ecf20Sopenharmony_ci check_flag = 0; 46568c2ecf20Sopenharmony_ci state_update_pipeline_state(hdw); 46578c2ecf20Sopenharmony_ci /* Iterate over each bit of state */ 46588c2ecf20Sopenharmony_ci for (i = 0; (i<ARRAY_SIZE(eval_funcs)) && hdw->flag_ok; i++) { 46598c2ecf20Sopenharmony_ci if ((*eval_funcs[i])(hdw)) { 46608c2ecf20Sopenharmony_ci check_flag = !0; 46618c2ecf20Sopenharmony_ci state_updated = !0; 46628c2ecf20Sopenharmony_ci state_update_pipeline_state(hdw); 46638c2ecf20Sopenharmony_ci } 46648c2ecf20Sopenharmony_ci } 46658c2ecf20Sopenharmony_ci } while (check_flag && hdw->flag_ok); 46668c2ecf20Sopenharmony_ci hdw->state_stale = 0; 46678c2ecf20Sopenharmony_ci trace_stbit("state_stale",hdw->state_stale); 46688c2ecf20Sopenharmony_ci return state_updated; 46698c2ecf20Sopenharmony_ci} 46708c2ecf20Sopenharmony_ci 46718c2ecf20Sopenharmony_ci 46728c2ecf20Sopenharmony_cistatic unsigned int print_input_mask(unsigned int msk, 46738c2ecf20Sopenharmony_ci char *buf,unsigned int acnt) 46748c2ecf20Sopenharmony_ci{ 46758c2ecf20Sopenharmony_ci unsigned int idx,ccnt; 46768c2ecf20Sopenharmony_ci unsigned int tcnt = 0; 46778c2ecf20Sopenharmony_ci for (idx = 0; idx < ARRAY_SIZE(control_values_input); idx++) { 46788c2ecf20Sopenharmony_ci if (!((1UL << idx) & msk)) continue; 46798c2ecf20Sopenharmony_ci ccnt = scnprintf(buf+tcnt, 46808c2ecf20Sopenharmony_ci acnt-tcnt, 46818c2ecf20Sopenharmony_ci "%s%s", 46828c2ecf20Sopenharmony_ci (tcnt ? ", " : ""), 46838c2ecf20Sopenharmony_ci control_values_input[idx]); 46848c2ecf20Sopenharmony_ci tcnt += ccnt; 46858c2ecf20Sopenharmony_ci } 46868c2ecf20Sopenharmony_ci return tcnt; 46878c2ecf20Sopenharmony_ci} 46888c2ecf20Sopenharmony_ci 46898c2ecf20Sopenharmony_ci 46908c2ecf20Sopenharmony_cistatic const char *pvr2_pathway_state_name(int id) 46918c2ecf20Sopenharmony_ci{ 46928c2ecf20Sopenharmony_ci switch (id) { 46938c2ecf20Sopenharmony_ci case PVR2_PATHWAY_ANALOG: return "analog"; 46948c2ecf20Sopenharmony_ci case PVR2_PATHWAY_DIGITAL: return "digital"; 46958c2ecf20Sopenharmony_ci default: return "unknown"; 46968c2ecf20Sopenharmony_ci } 46978c2ecf20Sopenharmony_ci} 46988c2ecf20Sopenharmony_ci 46998c2ecf20Sopenharmony_ci 47008c2ecf20Sopenharmony_cistatic unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which, 47018c2ecf20Sopenharmony_ci char *buf,unsigned int acnt) 47028c2ecf20Sopenharmony_ci{ 47038c2ecf20Sopenharmony_ci switch (which) { 47048c2ecf20Sopenharmony_ci case 0: 47058c2ecf20Sopenharmony_ci return scnprintf( 47068c2ecf20Sopenharmony_ci buf,acnt, 47078c2ecf20Sopenharmony_ci "driver:%s%s%s%s%s <mode=%s>", 47088c2ecf20Sopenharmony_ci (hdw->flag_ok ? " <ok>" : " <fail>"), 47098c2ecf20Sopenharmony_ci (hdw->flag_init_ok ? " <init>" : " <uninitialized>"), 47108c2ecf20Sopenharmony_ci (hdw->flag_disconnected ? " <disconnected>" : 47118c2ecf20Sopenharmony_ci " <connected>"), 47128c2ecf20Sopenharmony_ci (hdw->flag_tripped ? " <tripped>" : ""), 47138c2ecf20Sopenharmony_ci (hdw->flag_decoder_missed ? " <no decoder>" : ""), 47148c2ecf20Sopenharmony_ci pvr2_pathway_state_name(hdw->pathway_state)); 47158c2ecf20Sopenharmony_ci 47168c2ecf20Sopenharmony_ci case 1: 47178c2ecf20Sopenharmony_ci return scnprintf( 47188c2ecf20Sopenharmony_ci buf,acnt, 47198c2ecf20Sopenharmony_ci "pipeline:%s%s%s%s", 47208c2ecf20Sopenharmony_ci (hdw->state_pipeline_idle ? " <idle>" : ""), 47218c2ecf20Sopenharmony_ci (hdw->state_pipeline_config ? 47228c2ecf20Sopenharmony_ci " <configok>" : " <stale>"), 47238c2ecf20Sopenharmony_ci (hdw->state_pipeline_req ? " <req>" : ""), 47248c2ecf20Sopenharmony_ci (hdw->state_pipeline_pause ? " <pause>" : "")); 47258c2ecf20Sopenharmony_ci case 2: 47268c2ecf20Sopenharmony_ci return scnprintf( 47278c2ecf20Sopenharmony_ci buf,acnt, 47288c2ecf20Sopenharmony_ci "worker:%s%s%s%s%s%s%s", 47298c2ecf20Sopenharmony_ci (hdw->state_decoder_run ? 47308c2ecf20Sopenharmony_ci (hdw->state_decoder_ready ? 47318c2ecf20Sopenharmony_ci "<decode:run>" : " <decode:start>") : 47328c2ecf20Sopenharmony_ci (hdw->state_decoder_quiescent ? 47338c2ecf20Sopenharmony_ci "" : " <decode:stop>")), 47348c2ecf20Sopenharmony_ci (hdw->state_decoder_quiescent ? 47358c2ecf20Sopenharmony_ci " <decode:quiescent>" : ""), 47368c2ecf20Sopenharmony_ci (hdw->state_encoder_ok ? 47378c2ecf20Sopenharmony_ci "" : " <encode:init>"), 47388c2ecf20Sopenharmony_ci (hdw->state_encoder_run ? 47398c2ecf20Sopenharmony_ci (hdw->state_encoder_runok ? 47408c2ecf20Sopenharmony_ci " <encode:run>" : 47418c2ecf20Sopenharmony_ci " <encode:firstrun>") : 47428c2ecf20Sopenharmony_ci (hdw->state_encoder_runok ? 47438c2ecf20Sopenharmony_ci " <encode:stop>" : 47448c2ecf20Sopenharmony_ci " <encode:virgin>")), 47458c2ecf20Sopenharmony_ci (hdw->state_encoder_config ? 47468c2ecf20Sopenharmony_ci " <encode:configok>" : 47478c2ecf20Sopenharmony_ci (hdw->state_encoder_waitok ? 47488c2ecf20Sopenharmony_ci "" : " <encode:waitok>")), 47498c2ecf20Sopenharmony_ci (hdw->state_usbstream_run ? 47508c2ecf20Sopenharmony_ci " <usb:run>" : " <usb:stop>"), 47518c2ecf20Sopenharmony_ci (hdw->state_pathway_ok ? 47528c2ecf20Sopenharmony_ci " <pathway:ok>" : "")); 47538c2ecf20Sopenharmony_ci case 3: 47548c2ecf20Sopenharmony_ci return scnprintf( 47558c2ecf20Sopenharmony_ci buf,acnt, 47568c2ecf20Sopenharmony_ci "state: %s", 47578c2ecf20Sopenharmony_ci pvr2_get_state_name(hdw->master_state)); 47588c2ecf20Sopenharmony_ci case 4: { 47598c2ecf20Sopenharmony_ci unsigned int tcnt = 0; 47608c2ecf20Sopenharmony_ci unsigned int ccnt; 47618c2ecf20Sopenharmony_ci 47628c2ecf20Sopenharmony_ci ccnt = scnprintf(buf, 47638c2ecf20Sopenharmony_ci acnt, 47648c2ecf20Sopenharmony_ci "Hardware supported inputs: "); 47658c2ecf20Sopenharmony_ci tcnt += ccnt; 47668c2ecf20Sopenharmony_ci tcnt += print_input_mask(hdw->input_avail_mask, 47678c2ecf20Sopenharmony_ci buf+tcnt, 47688c2ecf20Sopenharmony_ci acnt-tcnt); 47698c2ecf20Sopenharmony_ci if (hdw->input_avail_mask != hdw->input_allowed_mask) { 47708c2ecf20Sopenharmony_ci ccnt = scnprintf(buf+tcnt, 47718c2ecf20Sopenharmony_ci acnt-tcnt, 47728c2ecf20Sopenharmony_ci "; allowed inputs: "); 47738c2ecf20Sopenharmony_ci tcnt += ccnt; 47748c2ecf20Sopenharmony_ci tcnt += print_input_mask(hdw->input_allowed_mask, 47758c2ecf20Sopenharmony_ci buf+tcnt, 47768c2ecf20Sopenharmony_ci acnt-tcnt); 47778c2ecf20Sopenharmony_ci } 47788c2ecf20Sopenharmony_ci return tcnt; 47798c2ecf20Sopenharmony_ci } 47808c2ecf20Sopenharmony_ci case 5: { 47818c2ecf20Sopenharmony_ci struct pvr2_stream_stats stats; 47828c2ecf20Sopenharmony_ci if (!hdw->vid_stream) break; 47838c2ecf20Sopenharmony_ci pvr2_stream_get_stats(hdw->vid_stream, 47848c2ecf20Sopenharmony_ci &stats, 47858c2ecf20Sopenharmony_ci 0); 47868c2ecf20Sopenharmony_ci return scnprintf( 47878c2ecf20Sopenharmony_ci buf,acnt, 47888c2ecf20Sopenharmony_ci "Bytes streamed=%u URBs: queued=%u idle=%u ready=%u processed=%u failed=%u", 47898c2ecf20Sopenharmony_ci stats.bytes_processed, 47908c2ecf20Sopenharmony_ci stats.buffers_in_queue, 47918c2ecf20Sopenharmony_ci stats.buffers_in_idle, 47928c2ecf20Sopenharmony_ci stats.buffers_in_ready, 47938c2ecf20Sopenharmony_ci stats.buffers_processed, 47948c2ecf20Sopenharmony_ci stats.buffers_failed); 47958c2ecf20Sopenharmony_ci } 47968c2ecf20Sopenharmony_ci case 6: { 47978c2ecf20Sopenharmony_ci unsigned int id = hdw->ir_scheme_active; 47988c2ecf20Sopenharmony_ci return scnprintf(buf, acnt, "ir scheme: id=%d %s", id, 47998c2ecf20Sopenharmony_ci (id >= ARRAY_SIZE(ir_scheme_names) ? 48008c2ecf20Sopenharmony_ci "?" : ir_scheme_names[id])); 48018c2ecf20Sopenharmony_ci } 48028c2ecf20Sopenharmony_ci default: break; 48038c2ecf20Sopenharmony_ci } 48048c2ecf20Sopenharmony_ci return 0; 48058c2ecf20Sopenharmony_ci} 48068c2ecf20Sopenharmony_ci 48078c2ecf20Sopenharmony_ci 48088c2ecf20Sopenharmony_ci/* Generate report containing info about attached sub-devices and attached 48098c2ecf20Sopenharmony_ci i2c clients, including an indication of which attached i2c clients are 48108c2ecf20Sopenharmony_ci actually sub-devices. */ 48118c2ecf20Sopenharmony_cistatic unsigned int pvr2_hdw_report_clients(struct pvr2_hdw *hdw, 48128c2ecf20Sopenharmony_ci char *buf, unsigned int acnt) 48138c2ecf20Sopenharmony_ci{ 48148c2ecf20Sopenharmony_ci struct v4l2_subdev *sd; 48158c2ecf20Sopenharmony_ci unsigned int tcnt = 0; 48168c2ecf20Sopenharmony_ci unsigned int ccnt; 48178c2ecf20Sopenharmony_ci struct i2c_client *client; 48188c2ecf20Sopenharmony_ci const char *p; 48198c2ecf20Sopenharmony_ci unsigned int id; 48208c2ecf20Sopenharmony_ci 48218c2ecf20Sopenharmony_ci ccnt = scnprintf(buf, acnt, "Associated v4l2-subdev drivers and I2C clients:\n"); 48228c2ecf20Sopenharmony_ci tcnt += ccnt; 48238c2ecf20Sopenharmony_ci v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) { 48248c2ecf20Sopenharmony_ci id = sd->grp_id; 48258c2ecf20Sopenharmony_ci p = NULL; 48268c2ecf20Sopenharmony_ci if (id < ARRAY_SIZE(module_names)) p = module_names[id]; 48278c2ecf20Sopenharmony_ci if (p) { 48288c2ecf20Sopenharmony_ci ccnt = scnprintf(buf + tcnt, acnt - tcnt, " %s:", p); 48298c2ecf20Sopenharmony_ci tcnt += ccnt; 48308c2ecf20Sopenharmony_ci } else { 48318c2ecf20Sopenharmony_ci ccnt = scnprintf(buf + tcnt, acnt - tcnt, 48328c2ecf20Sopenharmony_ci " (unknown id=%u):", id); 48338c2ecf20Sopenharmony_ci tcnt += ccnt; 48348c2ecf20Sopenharmony_ci } 48358c2ecf20Sopenharmony_ci client = v4l2_get_subdevdata(sd); 48368c2ecf20Sopenharmony_ci if (client) { 48378c2ecf20Sopenharmony_ci ccnt = scnprintf(buf + tcnt, acnt - tcnt, 48388c2ecf20Sopenharmony_ci " %s @ %02x\n", client->name, 48398c2ecf20Sopenharmony_ci client->addr); 48408c2ecf20Sopenharmony_ci tcnt += ccnt; 48418c2ecf20Sopenharmony_ci } else { 48428c2ecf20Sopenharmony_ci ccnt = scnprintf(buf + tcnt, acnt - tcnt, 48438c2ecf20Sopenharmony_ci " no i2c client\n"); 48448c2ecf20Sopenharmony_ci tcnt += ccnt; 48458c2ecf20Sopenharmony_ci } 48468c2ecf20Sopenharmony_ci } 48478c2ecf20Sopenharmony_ci return tcnt; 48488c2ecf20Sopenharmony_ci} 48498c2ecf20Sopenharmony_ci 48508c2ecf20Sopenharmony_ci 48518c2ecf20Sopenharmony_ciunsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw, 48528c2ecf20Sopenharmony_ci char *buf,unsigned int acnt) 48538c2ecf20Sopenharmony_ci{ 48548c2ecf20Sopenharmony_ci unsigned int bcnt,ccnt,idx; 48558c2ecf20Sopenharmony_ci bcnt = 0; 48568c2ecf20Sopenharmony_ci LOCK_TAKE(hdw->big_lock); 48578c2ecf20Sopenharmony_ci for (idx = 0; ; idx++) { 48588c2ecf20Sopenharmony_ci ccnt = pvr2_hdw_report_unlocked(hdw,idx,buf,acnt); 48598c2ecf20Sopenharmony_ci if (!ccnt) break; 48608c2ecf20Sopenharmony_ci bcnt += ccnt; acnt -= ccnt; buf += ccnt; 48618c2ecf20Sopenharmony_ci if (!acnt) break; 48628c2ecf20Sopenharmony_ci buf[0] = '\n'; ccnt = 1; 48638c2ecf20Sopenharmony_ci bcnt += ccnt; acnt -= ccnt; buf += ccnt; 48648c2ecf20Sopenharmony_ci } 48658c2ecf20Sopenharmony_ci ccnt = pvr2_hdw_report_clients(hdw, buf, acnt); 48668c2ecf20Sopenharmony_ci bcnt += ccnt; acnt -= ccnt; buf += ccnt; 48678c2ecf20Sopenharmony_ci LOCK_GIVE(hdw->big_lock); 48688c2ecf20Sopenharmony_ci return bcnt; 48698c2ecf20Sopenharmony_ci} 48708c2ecf20Sopenharmony_ci 48718c2ecf20Sopenharmony_ci 48728c2ecf20Sopenharmony_cistatic void pvr2_hdw_state_log_state(struct pvr2_hdw *hdw) 48738c2ecf20Sopenharmony_ci{ 48748c2ecf20Sopenharmony_ci char buf[256]; 48758c2ecf20Sopenharmony_ci unsigned int idx, ccnt; 48768c2ecf20Sopenharmony_ci unsigned int lcnt, ucnt; 48778c2ecf20Sopenharmony_ci 48788c2ecf20Sopenharmony_ci for (idx = 0; ; idx++) { 48798c2ecf20Sopenharmony_ci ccnt = pvr2_hdw_report_unlocked(hdw,idx,buf,sizeof(buf)); 48808c2ecf20Sopenharmony_ci if (!ccnt) break; 48818c2ecf20Sopenharmony_ci pr_info("%s %.*s\n", hdw->name, ccnt, buf); 48828c2ecf20Sopenharmony_ci } 48838c2ecf20Sopenharmony_ci ccnt = pvr2_hdw_report_clients(hdw, buf, sizeof(buf)); 48848c2ecf20Sopenharmony_ci if (ccnt >= sizeof(buf)) 48858c2ecf20Sopenharmony_ci ccnt = sizeof(buf); 48868c2ecf20Sopenharmony_ci 48878c2ecf20Sopenharmony_ci ucnt = 0; 48888c2ecf20Sopenharmony_ci while (ucnt < ccnt) { 48898c2ecf20Sopenharmony_ci lcnt = 0; 48908c2ecf20Sopenharmony_ci while ((lcnt + ucnt < ccnt) && (buf[lcnt + ucnt] != '\n')) { 48918c2ecf20Sopenharmony_ci lcnt++; 48928c2ecf20Sopenharmony_ci } 48938c2ecf20Sopenharmony_ci pr_info("%s %.*s\n", hdw->name, lcnt, buf + ucnt); 48948c2ecf20Sopenharmony_ci ucnt += lcnt + 1; 48958c2ecf20Sopenharmony_ci } 48968c2ecf20Sopenharmony_ci} 48978c2ecf20Sopenharmony_ci 48988c2ecf20Sopenharmony_ci 48998c2ecf20Sopenharmony_ci/* Evaluate and update the driver's current state, taking various actions 49008c2ecf20Sopenharmony_ci as appropriate for the update. */ 49018c2ecf20Sopenharmony_cistatic int pvr2_hdw_state_eval(struct pvr2_hdw *hdw) 49028c2ecf20Sopenharmony_ci{ 49038c2ecf20Sopenharmony_ci unsigned int st; 49048c2ecf20Sopenharmony_ci int state_updated = 0; 49058c2ecf20Sopenharmony_ci int callback_flag = 0; 49068c2ecf20Sopenharmony_ci int analog_mode; 49078c2ecf20Sopenharmony_ci 49088c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_STBITS, 49098c2ecf20Sopenharmony_ci "Drive state check START"); 49108c2ecf20Sopenharmony_ci if (pvrusb2_debug & PVR2_TRACE_STBITS) { 49118c2ecf20Sopenharmony_ci pvr2_hdw_state_log_state(hdw); 49128c2ecf20Sopenharmony_ci } 49138c2ecf20Sopenharmony_ci 49148c2ecf20Sopenharmony_ci /* Process all state and get back over disposition */ 49158c2ecf20Sopenharmony_ci state_updated = pvr2_hdw_state_update(hdw); 49168c2ecf20Sopenharmony_ci 49178c2ecf20Sopenharmony_ci analog_mode = (hdw->pathway_state != PVR2_PATHWAY_DIGITAL); 49188c2ecf20Sopenharmony_ci 49198c2ecf20Sopenharmony_ci /* Update master state based upon all other states. */ 49208c2ecf20Sopenharmony_ci if (!hdw->flag_ok) { 49218c2ecf20Sopenharmony_ci st = PVR2_STATE_DEAD; 49228c2ecf20Sopenharmony_ci } else if (hdw->fw1_state != FW1_STATE_OK) { 49238c2ecf20Sopenharmony_ci st = PVR2_STATE_COLD; 49248c2ecf20Sopenharmony_ci } else if ((analog_mode || 49258c2ecf20Sopenharmony_ci hdw->hdw_desc->flag_digital_requires_cx23416) && 49268c2ecf20Sopenharmony_ci !hdw->state_encoder_ok) { 49278c2ecf20Sopenharmony_ci st = PVR2_STATE_WARM; 49288c2ecf20Sopenharmony_ci } else if (hdw->flag_tripped || 49298c2ecf20Sopenharmony_ci (analog_mode && hdw->flag_decoder_missed)) { 49308c2ecf20Sopenharmony_ci st = PVR2_STATE_ERROR; 49318c2ecf20Sopenharmony_ci } else if (hdw->state_usbstream_run && 49328c2ecf20Sopenharmony_ci (!analog_mode || 49338c2ecf20Sopenharmony_ci (hdw->state_encoder_run && hdw->state_decoder_run))) { 49348c2ecf20Sopenharmony_ci st = PVR2_STATE_RUN; 49358c2ecf20Sopenharmony_ci } else { 49368c2ecf20Sopenharmony_ci st = PVR2_STATE_READY; 49378c2ecf20Sopenharmony_ci } 49388c2ecf20Sopenharmony_ci if (hdw->master_state != st) { 49398c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_STATE, 49408c2ecf20Sopenharmony_ci "Device state change from %s to %s", 49418c2ecf20Sopenharmony_ci pvr2_get_state_name(hdw->master_state), 49428c2ecf20Sopenharmony_ci pvr2_get_state_name(st)); 49438c2ecf20Sopenharmony_ci pvr2_led_ctrl(hdw,st == PVR2_STATE_RUN); 49448c2ecf20Sopenharmony_ci hdw->master_state = st; 49458c2ecf20Sopenharmony_ci state_updated = !0; 49468c2ecf20Sopenharmony_ci callback_flag = !0; 49478c2ecf20Sopenharmony_ci } 49488c2ecf20Sopenharmony_ci if (state_updated) { 49498c2ecf20Sopenharmony_ci /* Trigger anyone waiting on any state changes here. */ 49508c2ecf20Sopenharmony_ci wake_up(&hdw->state_wait_data); 49518c2ecf20Sopenharmony_ci } 49528c2ecf20Sopenharmony_ci 49538c2ecf20Sopenharmony_ci if (pvrusb2_debug & PVR2_TRACE_STBITS) { 49548c2ecf20Sopenharmony_ci pvr2_hdw_state_log_state(hdw); 49558c2ecf20Sopenharmony_ci } 49568c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_STBITS, 49578c2ecf20Sopenharmony_ci "Drive state check DONE callback=%d",callback_flag); 49588c2ecf20Sopenharmony_ci 49598c2ecf20Sopenharmony_ci return callback_flag; 49608c2ecf20Sopenharmony_ci} 49618c2ecf20Sopenharmony_ci 49628c2ecf20Sopenharmony_ci 49638c2ecf20Sopenharmony_ci/* Cause kernel thread to check / update driver state */ 49648c2ecf20Sopenharmony_cistatic void pvr2_hdw_state_sched(struct pvr2_hdw *hdw) 49658c2ecf20Sopenharmony_ci{ 49668c2ecf20Sopenharmony_ci if (hdw->state_stale) return; 49678c2ecf20Sopenharmony_ci hdw->state_stale = !0; 49688c2ecf20Sopenharmony_ci trace_stbit("state_stale",hdw->state_stale); 49698c2ecf20Sopenharmony_ci schedule_work(&hdw->workpoll); 49708c2ecf20Sopenharmony_ci} 49718c2ecf20Sopenharmony_ci 49728c2ecf20Sopenharmony_ci 49738c2ecf20Sopenharmony_ciint pvr2_hdw_gpio_get_dir(struct pvr2_hdw *hdw,u32 *dp) 49748c2ecf20Sopenharmony_ci{ 49758c2ecf20Sopenharmony_ci return pvr2_read_register(hdw,PVR2_GPIO_DIR,dp); 49768c2ecf20Sopenharmony_ci} 49778c2ecf20Sopenharmony_ci 49788c2ecf20Sopenharmony_ci 49798c2ecf20Sopenharmony_ciint pvr2_hdw_gpio_get_out(struct pvr2_hdw *hdw,u32 *dp) 49808c2ecf20Sopenharmony_ci{ 49818c2ecf20Sopenharmony_ci return pvr2_read_register(hdw,PVR2_GPIO_OUT,dp); 49828c2ecf20Sopenharmony_ci} 49838c2ecf20Sopenharmony_ci 49848c2ecf20Sopenharmony_ci 49858c2ecf20Sopenharmony_ciint pvr2_hdw_gpio_get_in(struct pvr2_hdw *hdw,u32 *dp) 49868c2ecf20Sopenharmony_ci{ 49878c2ecf20Sopenharmony_ci return pvr2_read_register(hdw,PVR2_GPIO_IN,dp); 49888c2ecf20Sopenharmony_ci} 49898c2ecf20Sopenharmony_ci 49908c2ecf20Sopenharmony_ci 49918c2ecf20Sopenharmony_ciint pvr2_hdw_gpio_chg_dir(struct pvr2_hdw *hdw,u32 msk,u32 val) 49928c2ecf20Sopenharmony_ci{ 49938c2ecf20Sopenharmony_ci u32 cval,nval; 49948c2ecf20Sopenharmony_ci int ret; 49958c2ecf20Sopenharmony_ci if (~msk) { 49968c2ecf20Sopenharmony_ci ret = pvr2_read_register(hdw,PVR2_GPIO_DIR,&cval); 49978c2ecf20Sopenharmony_ci if (ret) return ret; 49988c2ecf20Sopenharmony_ci nval = (cval & ~msk) | (val & msk); 49998c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_GPIO, 50008c2ecf20Sopenharmony_ci "GPIO direction changing 0x%x:0x%x from 0x%x to 0x%x", 50018c2ecf20Sopenharmony_ci msk,val,cval,nval); 50028c2ecf20Sopenharmony_ci } else { 50038c2ecf20Sopenharmony_ci nval = val; 50048c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_GPIO, 50058c2ecf20Sopenharmony_ci "GPIO direction changing to 0x%x",nval); 50068c2ecf20Sopenharmony_ci } 50078c2ecf20Sopenharmony_ci return pvr2_write_register(hdw,PVR2_GPIO_DIR,nval); 50088c2ecf20Sopenharmony_ci} 50098c2ecf20Sopenharmony_ci 50108c2ecf20Sopenharmony_ci 50118c2ecf20Sopenharmony_ciint pvr2_hdw_gpio_chg_out(struct pvr2_hdw *hdw,u32 msk,u32 val) 50128c2ecf20Sopenharmony_ci{ 50138c2ecf20Sopenharmony_ci u32 cval,nval; 50148c2ecf20Sopenharmony_ci int ret; 50158c2ecf20Sopenharmony_ci if (~msk) { 50168c2ecf20Sopenharmony_ci ret = pvr2_read_register(hdw,PVR2_GPIO_OUT,&cval); 50178c2ecf20Sopenharmony_ci if (ret) return ret; 50188c2ecf20Sopenharmony_ci nval = (cval & ~msk) | (val & msk); 50198c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_GPIO, 50208c2ecf20Sopenharmony_ci "GPIO output changing 0x%x:0x%x from 0x%x to 0x%x", 50218c2ecf20Sopenharmony_ci msk,val,cval,nval); 50228c2ecf20Sopenharmony_ci } else { 50238c2ecf20Sopenharmony_ci nval = val; 50248c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_GPIO, 50258c2ecf20Sopenharmony_ci "GPIO output changing to 0x%x",nval); 50268c2ecf20Sopenharmony_ci } 50278c2ecf20Sopenharmony_ci return pvr2_write_register(hdw,PVR2_GPIO_OUT,nval); 50288c2ecf20Sopenharmony_ci} 50298c2ecf20Sopenharmony_ci 50308c2ecf20Sopenharmony_ci 50318c2ecf20Sopenharmony_civoid pvr2_hdw_status_poll(struct pvr2_hdw *hdw) 50328c2ecf20Sopenharmony_ci{ 50338c2ecf20Sopenharmony_ci struct v4l2_tuner *vtp = &hdw->tuner_signal_info; 50348c2ecf20Sopenharmony_ci memset(vtp, 0, sizeof(*vtp)); 50358c2ecf20Sopenharmony_ci vtp->type = (hdw->input_val == PVR2_CVAL_INPUT_RADIO) ? 50368c2ecf20Sopenharmony_ci V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; 50378c2ecf20Sopenharmony_ci hdw->tuner_signal_stale = 0; 50388c2ecf20Sopenharmony_ci /* Note: There apparently is no replacement for VIDIOC_CROPCAP 50398c2ecf20Sopenharmony_ci using v4l2-subdev - therefore we can't support that AT ALL right 50408c2ecf20Sopenharmony_ci now. (Of course, no sub-drivers seem to implement it either. 50418c2ecf20Sopenharmony_ci But now it's a a chicken and egg problem...) */ 50428c2ecf20Sopenharmony_ci v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner, g_tuner, vtp); 50438c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_CHIPS, "subdev status poll type=%u strength=%u audio=0x%x cap=0x%x low=%u hi=%u", 50448c2ecf20Sopenharmony_ci vtp->type, 50458c2ecf20Sopenharmony_ci vtp->signal, vtp->rxsubchans, vtp->capability, 50468c2ecf20Sopenharmony_ci vtp->rangelow, vtp->rangehigh); 50478c2ecf20Sopenharmony_ci 50488c2ecf20Sopenharmony_ci /* We have to do this to avoid getting into constant polling if 50498c2ecf20Sopenharmony_ci there's nobody to answer a poll of cropcap info. */ 50508c2ecf20Sopenharmony_ci hdw->cropcap_stale = 0; 50518c2ecf20Sopenharmony_ci} 50528c2ecf20Sopenharmony_ci 50538c2ecf20Sopenharmony_ci 50548c2ecf20Sopenharmony_ciunsigned int pvr2_hdw_get_input_available(struct pvr2_hdw *hdw) 50558c2ecf20Sopenharmony_ci{ 50568c2ecf20Sopenharmony_ci return hdw->input_avail_mask; 50578c2ecf20Sopenharmony_ci} 50588c2ecf20Sopenharmony_ci 50598c2ecf20Sopenharmony_ci 50608c2ecf20Sopenharmony_ciunsigned int pvr2_hdw_get_input_allowed(struct pvr2_hdw *hdw) 50618c2ecf20Sopenharmony_ci{ 50628c2ecf20Sopenharmony_ci return hdw->input_allowed_mask; 50638c2ecf20Sopenharmony_ci} 50648c2ecf20Sopenharmony_ci 50658c2ecf20Sopenharmony_ci 50668c2ecf20Sopenharmony_cistatic int pvr2_hdw_set_input(struct pvr2_hdw *hdw,int v) 50678c2ecf20Sopenharmony_ci{ 50688c2ecf20Sopenharmony_ci if (hdw->input_val != v) { 50698c2ecf20Sopenharmony_ci hdw->input_val = v; 50708c2ecf20Sopenharmony_ci hdw->input_dirty = !0; 50718c2ecf20Sopenharmony_ci } 50728c2ecf20Sopenharmony_ci 50738c2ecf20Sopenharmony_ci /* Handle side effects - if we switch to a mode that needs the RF 50748c2ecf20Sopenharmony_ci tuner, then select the right frequency choice as well and mark 50758c2ecf20Sopenharmony_ci it dirty. */ 50768c2ecf20Sopenharmony_ci if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) { 50778c2ecf20Sopenharmony_ci hdw->freqSelector = 0; 50788c2ecf20Sopenharmony_ci hdw->freqDirty = !0; 50798c2ecf20Sopenharmony_ci } else if ((hdw->input_val == PVR2_CVAL_INPUT_TV) || 50808c2ecf20Sopenharmony_ci (hdw->input_val == PVR2_CVAL_INPUT_DTV)) { 50818c2ecf20Sopenharmony_ci hdw->freqSelector = 1; 50828c2ecf20Sopenharmony_ci hdw->freqDirty = !0; 50838c2ecf20Sopenharmony_ci } 50848c2ecf20Sopenharmony_ci return 0; 50858c2ecf20Sopenharmony_ci} 50868c2ecf20Sopenharmony_ci 50878c2ecf20Sopenharmony_ci 50888c2ecf20Sopenharmony_ciint pvr2_hdw_set_input_allowed(struct pvr2_hdw *hdw, 50898c2ecf20Sopenharmony_ci unsigned int change_mask, 50908c2ecf20Sopenharmony_ci unsigned int change_val) 50918c2ecf20Sopenharmony_ci{ 50928c2ecf20Sopenharmony_ci int ret = 0; 50938c2ecf20Sopenharmony_ci unsigned int nv,m,idx; 50948c2ecf20Sopenharmony_ci LOCK_TAKE(hdw->big_lock); 50958c2ecf20Sopenharmony_ci do { 50968c2ecf20Sopenharmony_ci nv = hdw->input_allowed_mask & ~change_mask; 50978c2ecf20Sopenharmony_ci nv |= (change_val & change_mask); 50988c2ecf20Sopenharmony_ci nv &= hdw->input_avail_mask; 50998c2ecf20Sopenharmony_ci if (!nv) { 51008c2ecf20Sopenharmony_ci /* No legal modes left; return error instead. */ 51018c2ecf20Sopenharmony_ci ret = -EPERM; 51028c2ecf20Sopenharmony_ci break; 51038c2ecf20Sopenharmony_ci } 51048c2ecf20Sopenharmony_ci hdw->input_allowed_mask = nv; 51058c2ecf20Sopenharmony_ci if ((1UL << hdw->input_val) & hdw->input_allowed_mask) { 51068c2ecf20Sopenharmony_ci /* Current mode is still in the allowed mask, so 51078c2ecf20Sopenharmony_ci we're done. */ 51088c2ecf20Sopenharmony_ci break; 51098c2ecf20Sopenharmony_ci } 51108c2ecf20Sopenharmony_ci /* Select and switch to a mode that is still in the allowed 51118c2ecf20Sopenharmony_ci mask */ 51128c2ecf20Sopenharmony_ci if (!hdw->input_allowed_mask) { 51138c2ecf20Sopenharmony_ci /* Nothing legal; give up */ 51148c2ecf20Sopenharmony_ci break; 51158c2ecf20Sopenharmony_ci } 51168c2ecf20Sopenharmony_ci m = hdw->input_allowed_mask; 51178c2ecf20Sopenharmony_ci for (idx = 0; idx < (sizeof(m) << 3); idx++) { 51188c2ecf20Sopenharmony_ci if (!((1UL << idx) & m)) continue; 51198c2ecf20Sopenharmony_ci pvr2_hdw_set_input(hdw,idx); 51208c2ecf20Sopenharmony_ci break; 51218c2ecf20Sopenharmony_ci } 51228c2ecf20Sopenharmony_ci } while (0); 51238c2ecf20Sopenharmony_ci LOCK_GIVE(hdw->big_lock); 51248c2ecf20Sopenharmony_ci return ret; 51258c2ecf20Sopenharmony_ci} 51268c2ecf20Sopenharmony_ci 51278c2ecf20Sopenharmony_ci 51288c2ecf20Sopenharmony_ci/* Find I2C address of eeprom */ 51298c2ecf20Sopenharmony_cistatic int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw) 51308c2ecf20Sopenharmony_ci{ 51318c2ecf20Sopenharmony_ci int result; 51328c2ecf20Sopenharmony_ci LOCK_TAKE(hdw->ctl_lock); do { 51338c2ecf20Sopenharmony_ci hdw->cmd_buffer[0] = FX2CMD_GET_EEPROM_ADDR; 51348c2ecf20Sopenharmony_ci result = pvr2_send_request(hdw, 51358c2ecf20Sopenharmony_ci hdw->cmd_buffer,1, 51368c2ecf20Sopenharmony_ci hdw->cmd_buffer,1); 51378c2ecf20Sopenharmony_ci if (result < 0) break; 51388c2ecf20Sopenharmony_ci result = hdw->cmd_buffer[0]; 51398c2ecf20Sopenharmony_ci } while(0); LOCK_GIVE(hdw->ctl_lock); 51408c2ecf20Sopenharmony_ci return result; 51418c2ecf20Sopenharmony_ci} 5142