⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pvrusb2-hdw.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * *  $Id$ * *  Copyright (C) 2005 Mike Isely <isely@pobox.com> * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * */#include <linux/errno.h>#include <linux/string.h>#include <linux/slab.h>#include <linux/firmware.h>#include <linux/videodev2.h>#include <media/v4l2-common.h>#include <asm/semaphore.h>#include "pvrusb2.h"#include "pvrusb2-std.h"#include "pvrusb2-util.h"#include "pvrusb2-hdw.h"#include "pvrusb2-i2c-core.h"#include "pvrusb2-tuner.h"#include "pvrusb2-eeprom.h"#include "pvrusb2-hdw-internal.h"#include "pvrusb2-encoder.h"#include "pvrusb2-debug.h"#include "pvrusb2-fx2-cmd.h"#define TV_MIN_FREQ     55250000L#define TV_MAX_FREQ    850000000Lstruct usb_device_id pvr2_device_table[] = {	[PVR2_HDW_TYPE_29XXX] = { USB_DEVICE(0x2040, 0x2900) },	[PVR2_HDW_TYPE_24XXX] = { USB_DEVICE(0x2040, 0x2400) },	{ }};MODULE_DEVICE_TABLE(usb, pvr2_device_table);static const char *pvr2_device_names[] = {	[PVR2_HDW_TYPE_29XXX] = "WinTV PVR USB2 Model Category 29xxxx",	[PVR2_HDW_TYPE_24XXX] = "WinTV PVR USB2 Model Category 24xxxx",};struct pvr2_string_table {	const char **lst;	unsigned int cnt;};// Names of other client modules to request for 24xxx model hardwarestatic const char *pvr2_client_24xxx[] = {	"cx25840",	"tuner",	"wm8775",};// Names of other client modules to request for 29xxx model hardwarestatic const char *pvr2_client_29xxx[] = {	"msp3400",	"saa7115",	"tuner",};static struct pvr2_string_table pvr2_client_lists[] = {	[PVR2_HDW_TYPE_29XXX] = {		pvr2_client_29xxx, ARRAY_SIZE(pvr2_client_29xxx)	},	[PVR2_HDW_TYPE_24XXX] = {		pvr2_client_24xxx, ARRAY_SIZE(pvr2_client_24xxx)	},};static struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = NULL};static DEFINE_MUTEX(pvr2_unit_mtx);static int ctlchg = 0;static int initusbreset = 1;static int procreload = 0;static int tuner[PVR_NUM] = { [0 ... PVR_NUM-1] = -1 };static int tolerance[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 };static int video_std[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 };static int init_pause_msec = 0;module_param(ctlchg, int, S_IRUGO|S_IWUSR);MODULE_PARM_DESC(ctlchg, "0=optimize ctl change 1=always accept new ctl value");module_param(init_pause_msec, int, S_IRUGO|S_IWUSR);MODULE_PARM_DESC(init_pause_msec, "hardware initialization settling delay");module_param(initusbreset, int, S_IRUGO|S_IWUSR);MODULE_PARM_DESC(initusbreset, "Do USB reset device on probe");module_param(procreload, int, S_IRUGO|S_IWUSR);MODULE_PARM_DESC(procreload,		 "Attempt init failure recovery with firmware reload");module_param_array(tuner,    int, NULL, 0444);MODULE_PARM_DESC(tuner,"specify installed tuner type");module_param_array(video_std,    int, NULL, 0444);MODULE_PARM_DESC(video_std,"specify initial video standard");module_param_array(tolerance,    int, NULL, 0444);MODULE_PARM_DESC(tolerance,"specify stream error tolerance");#define PVR2_CTL_WRITE_ENDPOINT  0x01#define PVR2_CTL_READ_ENDPOINT   0x81#define PVR2_GPIO_IN 0x9008#define PVR2_GPIO_OUT 0x900c#define PVR2_GPIO_DIR 0x9020#define trace_firmware(...) pvr2_trace(PVR2_TRACE_FIRMWARE,__VA_ARGS__)#define PVR2_FIRMWARE_ENDPOINT   0x02/* size of a firmware chunk */#define FIRMWARE_CHUNK_SIZE 0x2000/* Define the list of additional controls we'll dynamically construct based   on query of the cx2341x module. */struct pvr2_mpeg_ids {	const char *strid;	int id;};static const struct pvr2_mpeg_ids mpeg_ids[] = {	{		.strid = "audio_layer",		.id = V4L2_CID_MPEG_AUDIO_ENCODING,	},{		.strid = "audio_bitrate",		.id = V4L2_CID_MPEG_AUDIO_L2_BITRATE,	},{		/* Already using audio_mode elsewhere :-( */		.strid = "mpeg_audio_mode",		.id = V4L2_CID_MPEG_AUDIO_MODE,	},{		.strid = "mpeg_audio_mode_extension",		.id = V4L2_CID_MPEG_AUDIO_MODE_EXTENSION,	},{		.strid = "audio_emphasis",		.id = V4L2_CID_MPEG_AUDIO_EMPHASIS,	},{		.strid = "audio_crc",		.id = V4L2_CID_MPEG_AUDIO_CRC,	},{		.strid = "video_aspect",		.id = V4L2_CID_MPEG_VIDEO_ASPECT,	},{		.strid = "video_b_frames",		.id = V4L2_CID_MPEG_VIDEO_B_FRAMES,	},{		.strid = "video_gop_size",		.id = V4L2_CID_MPEG_VIDEO_GOP_SIZE,	},{		.strid = "video_gop_closure",		.id = V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,	},{		.strid = "video_bitrate_mode",		.id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE,	},{		.strid = "video_bitrate",		.id = V4L2_CID_MPEG_VIDEO_BITRATE,	},{		.strid = "video_bitrate_peak",		.id = V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,	},{		.strid = "video_temporal_decimation",		.id = V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION,	},{		.strid = "stream_type",		.id = V4L2_CID_MPEG_STREAM_TYPE,	},{		.strid = "video_spatial_filter_mode",		.id = V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE,	},{		.strid = "video_spatial_filter",		.id = V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER,	},{		.strid = "video_luma_spatial_filter_type",		.id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE,	},{		.strid = "video_chroma_spatial_filter_type",		.id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE,	},{		.strid = "video_temporal_filter_mode",		.id = V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE,	},{		.strid = "video_temporal_filter",		.id = V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER,	},{		.strid = "video_median_filter_type",		.id = V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE,	},{		.strid = "video_luma_median_filter_top",		.id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP,	},{		.strid = "video_luma_median_filter_bottom",		.id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM,	},{		.strid = "video_chroma_median_filter_top",		.id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP,	},{		.strid = "video_chroma_median_filter_bottom",		.id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM,	}};#define MPEGDEF_COUNT ARRAY_SIZE(mpeg_ids)static const char *control_values_srate[] = {	[V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100]   = "44.1 kHz",	[V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000]   = "48 kHz",	[V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000]   = "32 kHz",};static const char *control_values_input[] = {	[PVR2_CVAL_INPUT_TV]        = "television",  /*xawtv needs this name*/	[PVR2_CVAL_INPUT_RADIO]     = "radio",	[PVR2_CVAL_INPUT_SVIDEO]    = "s-video",	[PVR2_CVAL_INPUT_COMPOSITE] = "composite",};static const char *control_values_audiomode[] = {	[V4L2_TUNER_MODE_MONO]   = "Mono",	[V4L2_TUNER_MODE_STEREO] = "Stereo",	[V4L2_TUNER_MODE_LANG1]  = "Lang1",	[V4L2_TUNER_MODE_LANG2]  = "Lang2",	[V4L2_TUNER_MODE_LANG1_LANG2] = "Lang1+Lang2",};static const char *control_values_hsm[] = {	[PVR2_CVAL_HSM_FAIL] = "Fail",	[PVR2_CVAL_HSM_HIGH] = "High",	[PVR2_CVAL_HSM_FULL] = "Full",};static const char *control_values_subsystem[] = {	[PVR2_SUBSYS_B_ENC_FIRMWARE]  = "enc_firmware",	[PVR2_SUBSYS_B_ENC_CFG] = "enc_config",	[PVR2_SUBSYS_B_DIGITIZER_RUN] = "digitizer_run",	[PVR2_SUBSYS_B_USBSTREAM_RUN] = "usbstream_run",	[PVR2_SUBSYS_B_ENC_RUN] = "enc_run",};static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long);static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl);static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw);static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw);static void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw);static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw);static void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw);static void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw,					    unsigned long msk,					    unsigned long val);static void pvr2_hdw_subsys_stream_bit_chg_no_lock(struct pvr2_hdw *hdw,						   unsigned long msk,						   unsigned long val);static int pvr2_send_request_ex(struct pvr2_hdw *hdw,				unsigned int timeout,int probe_fl,				void *write_data,unsigned int write_len,				void *read_data,unsigned int read_len);static int ctrl_channelfreq_get(struct pvr2_ctrl *cptr,int *vp){	struct pvr2_hdw *hdw = cptr->hdw;	if ((hdw->freqProgSlot > 0) && (hdw->freqProgSlot <= FREQTABLE_SIZE)) {		*vp = hdw->freqTable[hdw->freqProgSlot-1];	} else {		*vp = 0;	}	return 0;}static int ctrl_channelfreq_set(struct pvr2_ctrl *cptr,int m,int v){	struct pvr2_hdw *hdw = cptr->hdw;	unsigned int slotId = hdw->freqProgSlot;	if ((slotId > 0) && (slotId <= FREQTABLE_SIZE)) {		hdw->freqTable[slotId-1] = v;		/* Handle side effects correctly - if we're tuned to this		   slot, then forgot the slot id relation since the stored		   frequency has been changed. */		if (hdw->freqSelector) {			if (hdw->freqSlotRadio == slotId) {				hdw->freqSlotRadio = 0;			}		} else {			if (hdw->freqSlotTelevision == slotId) {				hdw->freqSlotTelevision = 0;			}		}	}	return 0;}static int ctrl_channelprog_get(struct pvr2_ctrl *cptr,int *vp){	*vp = cptr->hdw->freqProgSlot;	return 0;}static int ctrl_channelprog_set(struct pvr2_ctrl *cptr,int m,int v){	struct pvr2_hdw *hdw = cptr->hdw;	if ((v >= 0) && (v <= FREQTABLE_SIZE)) {		hdw->freqProgSlot = v;	}	return 0;}static int ctrl_channel_get(struct pvr2_ctrl *cptr,int *vp){	struct pvr2_hdw *hdw = cptr->hdw;	*vp = hdw->freqSelector ? hdw->freqSlotRadio : hdw->freqSlotTelevision;	return 0;}static int ctrl_channel_set(struct pvr2_ctrl *cptr,int m,int slotId){	unsigned freq = 0;	struct pvr2_hdw *hdw = cptr->hdw;	if ((slotId < 0) || (slotId > FREQTABLE_SIZE)) return 0;	if (slotId > 0) {		freq = hdw->freqTable[slotId-1];		if (!freq) return 0;		pvr2_hdw_set_cur_freq(hdw,freq);	}	if (hdw->freqSelector) {		hdw->freqSlotRadio = slotId;	} else {		hdw->freqSlotTelevision = slotId;	}	return 0;}static int ctrl_freq_get(struct pvr2_ctrl *cptr,int *vp){	*vp = pvr2_hdw_get_cur_freq(cptr->hdw);	return 0;}static int ctrl_freq_is_dirty(struct pvr2_ctrl *cptr){	return cptr->hdw->freqDirty != 0;}static void ctrl_freq_clear_dirty(struct pvr2_ctrl *cptr){	cptr->hdw->freqDirty = 0;}static int ctrl_freq_set(struct pvr2_ctrl *cptr,int m,int v){	pvr2_hdw_set_cur_freq(cptr->hdw,v);	return 0;}static int ctrl_vres_max_get(struct pvr2_ctrl *cptr,int *vp){	/* Actual maximum depends on the video standard in effect. */	if (cptr->hdw->std_mask_cur & V4L2_STD_525_60) {		*vp = 480;	} else {		*vp = 576;	}	return 0;}static int ctrl_vres_min_get(struct pvr2_ctrl *cptr,int *vp){	/* Actual minimum depends on device type. */	if (cptr->hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {		*vp = 75;	} else {		*vp = 17;	}	return 0;}static int ctrl_get_input(struct pvr2_ctrl *cptr,int *vp){	*vp = cptr->hdw->input_val;	return 0;}static int ctrl_set_input(struct pvr2_ctrl *cptr,int m,int v){	struct pvr2_hdw *hdw = cptr->hdw;	if (hdw->input_val != v) {		hdw->input_val = v;		hdw->input_dirty = !0;	}	/* Handle side effects - if we switch to a mode that needs the RF	   tuner, then select the right frequency choice as well and mark	   it dirty. */	if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {		hdw->freqSelector = 0;		hdw->freqDirty = !0;	} else if (hdw->input_val == PVR2_CVAL_INPUT_TV) {		hdw->freqSelector = 1;		hdw->freqDirty = !0;	}	return 0;}static int ctrl_isdirty_input(struct pvr2_ctrl *cptr){	return cptr->hdw->input_dirty != 0;}static void ctrl_cleardirty_input(struct pvr2_ctrl *cptr){	cptr->hdw->input_dirty = 0;}static int ctrl_freq_max_get(struct pvr2_ctrl *cptr, int *vp){	unsigned long fv;	struct pvr2_hdw *hdw = cptr->hdw;	if (hdw->tuner_signal_stale) {		pvr2_i2c_core_status_poll(hdw);	}	fv = hdw->tuner_signal_info.rangehigh;	if (!fv) {		/* Safety fallback */		*vp = TV_MAX_FREQ;		return 0;	}	if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) {		fv = (fv * 125) / 2;	} else {		fv = fv * 62500;	}	*vp = fv;	return 0;}static int ctrl_freq_min_get(struct pvr2_ctrl *cptr, int *vp){	unsigned long fv;	struct pvr2_hdw *hdw = cptr->hdw;	if (hdw->tuner_signal_stale) {		pvr2_i2c_core_status_poll(hdw);	}	fv = hdw->tuner_signal_info.rangelow;	if (!fv) {		/* Safety fallback */		*vp = TV_MIN_FREQ;		return 0;	}	if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) {		fv = (fv * 125) / 2;	} else {		fv = fv * 62500;	}	*vp = fv;	return 0;}static int ctrl_cx2341x_is_dirty(struct pvr2_ctrl *cptr){	return cptr->hdw->enc_stale != 0;}static void ctrl_cx2341x_clear_dirty(struct pvr2_ctrl *cptr){	cptr->hdw->enc_stale = 0;}static int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -