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

📄 pvrusb2-v4l2.c

📁 V4l driver for DVB HD
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * *  $Id$ * *  Copyright (C) 2005 Mike Isely <isely@pobox.com> *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> * *  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 "compat.h"#include <linux/kernel.h>#include <linux/videodev.h>#include "pvrusb2-context.h"#include "pvrusb2-hdw.h"#include "pvrusb2.h"#include "pvrusb2-debug.h"#include "pvrusb2-v4l2.h"#include "pvrusb2-ioread.h"#include <linux/videodev2.h>#include <media/v4l2-common.h>#define PVR_WIDTH_DVD      720#define PVR_WIDTH_SVCD     480#define PVR_WIDTH_VCD      352#define PVR_HEIGHT_PAL      480#define PVR_HEIGHT_NTSC     576struct pvr2_v4l2_dev;struct pvr2_v4l2_fh;struct pvr2_v4l2;struct pvr2_v4l2_dev {	struct pvr2_v4l2 *v4lp;	struct video_device *vdev;	struct pvr2_context_stream *stream;	enum pvr2_config config;};struct pvr2_v4l2_fh {	struct pvr2_channel channel;	struct pvr2_v4l2_dev *dev_info;	enum v4l2_priority prio;	struct pvr2_ioread *rhp;	struct file *file;	struct pvr2_v4l2 *vhead;	struct pvr2_v4l2_fh *vnext;	struct pvr2_v4l2_fh *vprev;	wait_queue_head_t wait_data;	int fw_mode_flag;};struct pvr2_v4l2 {	struct pvr2_channel channel;	struct pvr2_v4l2_fh *vfirst;	struct pvr2_v4l2_fh *vlast;	struct v4l2_prio_state prio;	/* streams */	struct pvr2_v4l2_dev video_dev;};static int video_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};module_param_array(video_nr, int, NULL, 0444);MODULE_PARM_DESC(video_nr, "Offset for device's minor");struct v4l2_capability pvr_capability ={	.driver         = "pvrusb2",	.card           = "Hauppauge WinTV pvr-usb2",	.bus_info       = "usb",	.version        = KERNEL_VERSION(0,8,0),	.capabilities   = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE |			   V4L2_CAP_TUNER | V4L2_CAP_AUDIO |			   V4L2_CAP_READWRITE),	.reserved       = {0,0,0,0}};static struct v4l2_tuner pvr_v4l2_tuners[]= {	{		.index      = 0,		.name       = "TV Tuner",		.type           = V4L2_TUNER_ANALOG_TV,		.capability     = (V4L2_TUNER_CAP_NORM |				   V4L2_TUNER_CAP_STEREO |				   V4L2_TUNER_CAP_LANG1 |				   V4L2_TUNER_CAP_LANG2),		.rangelow   = 0,		.rangehigh  = 0,		.rxsubchans     = V4L2_TUNER_SUB_STEREO,		.audmode        = V4L2_TUNER_MODE_STEREO,		.signal         = 0,		.afc            = 0,		.reserved       = {0,0,0,0}	}#if 0	{		.index    = 1,		.name   = "Radio Tuner",		.type             = V4L2_TUNER_RADIO,		.capability       = (V4L2_TUNER_CAP_STEREO),		.rangelow   = 0,		.rangehigh  = 0,		.rxsubchans       = 0,		.audmode  = V4L2_TUNER_MODE_STEREO,		.signal           = 0,		.afc              = 0,		.reserved = {0,0,0,0}	}#endif};struct v4l2_fmtdesc pvr_fmtdesc [] = {	{		.index          = 0,		.type           = V4L2_BUF_TYPE_VIDEO_CAPTURE,		.flags          = V4L2_FMT_FLAG_COMPRESSED,		.description    = "MPEG1/2",		// This should really be V4L2_PIX_FMT_MPEG, but xawtv		// breaks when I do that.		.pixelformat    = 0, // V4L2_PIX_FMT_MPEG,		.reserved       = { 0, 0, 0, 0 }	}};#define PVR_FORMAT_PIX  0#define PVR_FORMAT_VBI  1struct v4l2_format pvr_format [] = {	[PVR_FORMAT_PIX] = {		.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE,		.fmt    = {			.pix        = {				.width          = 720,				.height             = 576,				// This should really be V4L2_PIX_FMT_MPEG,				// but xawtv breaks when I do that.				.pixelformat    = 0, // V4L2_PIX_FMT_MPEG,				.field          = V4L2_FIELD_INTERLACED,				.bytesperline   = 0,  // doesn't make sense						      // here				//FIXME : Don't know what to put here...				.sizeimage          = (32*1024),				.colorspace     = 0, // doesn't make sense here				.priv           = 0			}		}	},	[PVR_FORMAT_VBI] = {		.type   = V4L2_BUF_TYPE_VBI_CAPTURE,		.fmt    = {			.vbi        = {				.sampling_rate = 27000000,				.offset = 248,				.samples_per_line = 1443,				.sample_format = V4L2_PIX_FMT_GREY,				.start = { 0, 0 },				.count = { 0, 0 },				.flags = 0,				.reserved = { 0, 0 }			}		}	}};/* * pvr_ioctl() * * This is part of Video 4 Linux API. The procedure handles ioctl() calls. * */static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,			      unsigned int cmd, void *arg){	struct pvr2_v4l2_fh *fh = file->private_data;	struct pvr2_v4l2 *vp = fh->vhead;	struct pvr2_v4l2_dev *dev_info = fh->dev_info;	struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;	int ret = -EINVAL;	if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {		v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),cmd);	}	if (!pvr2_hdw_dev_ok(hdw)) {		pvr2_trace(PVR2_TRACE_ERROR_LEGS,			   "ioctl failed - bad or no context");		return -EFAULT;	}	/* check priority */	switch (cmd) {	case VIDIOC_S_CTRL:	case VIDIOC_S_STD:	case VIDIOC_S_INPUT:	case VIDIOC_S_TUNER:	case VIDIOC_S_FREQUENCY:		ret = v4l2_prio_check(&vp->prio, &fh->prio);		if (ret)			return ret;	}	switch (cmd) {	case VIDIOC_QUERYCAP:	{		struct v4l2_capability *cap = arg;		memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));		ret = 0;		break;	}	case VIDIOC_G_PRIORITY:	{		enum v4l2_priority *p = arg;		*p = v4l2_prio_max(&vp->prio);		ret = 0;		break;	}	case VIDIOC_S_PRIORITY:	{		enum v4l2_priority *prio = arg;		ret = v4l2_prio_change(&vp->prio, &fh->prio, *prio);		break;	}	case VIDIOC_ENUMSTD:	{		struct v4l2_standard *vs = (struct v4l2_standard *)arg;		const struct v4l2_standard *src;		int idx = vs->index;		src = pvr2_hdw_get_stdenum_value(hdw,idx);		if (!src) break;		memcpy(vs, src, sizeof(struct v4l2_standard));		vs->index = idx;		ret = 0;		break;	}	case VIDIOC_G_STD:	{		struct pvr2_ctrl *cptr;		v4l2_std_id *vs = (v4l2_std_id *)arg;		cptr = pvr2_hdw_get_ctrl(hdw,V4L2_CID_PVR_STDCUR);		if (!pvr2_ctrl_is_valid(cptr)) {			ret = -EINVAL;			break;		}		*vs = pvr2_ctrl_get_value(cptr);		ret = 0;		break;	}	case VIDIOC_S_STD:	{		struct pvr2_ctrl *cptr;		v4l2_std_id *vs = (v4l2_std_id *)arg;		cptr = pvr2_hdw_get_ctrl(hdw,V4L2_CID_PVR_STDCUR);		if (!pvr2_ctrl_is_valid(cptr)) {			ret = -EINVAL;			break;		}		pvr2_ctrl_set_value(cptr,*vs);		ret = 0;		break;	}	case VIDIOC_ENUMINPUT:	{		struct pvr2_ctrl *cptr;		struct v4l2_input *vi = (struct v4l2_input *)arg;		struct v4l2_input tmp;		if ((vi->index > PVR2_CVAL_INPUT_MAX) ||		    (vi->index < PVR2_CVAL_INPUT_MIN)) {			break;		}		cptr = pvr2_hdw_get_ctrl(hdw,V4L2_CID_PVR_INPUT);		memset(&tmp,0,sizeof(tmp));		tmp.index = vi->index;		switch (vi->index) {		case PVR2_CVAL_INPUT_TV:		case PVR2_CVAL_INPUT_RADIO:			tmp.type = V4L2_INPUT_TYPE_TUNER;			break;		case PVR2_CVAL_INPUT_SVIDEO:		case PVR2_CVAL_INPUT_COMPOSITE:			tmp.type = V4L2_INPUT_TYPE_CAMERA;			break;		}		strlcpy(tmp.name,			pvr2_ctrl_get_value_name(cptr,vi->index),			sizeof(tmp.name));		/* Don't bother with audioset, since this driver currently		   always switches the audio whenever the video is		   switched. */		/* Handling std is a tougher problem.  It doesn't make		   sense in cases where a device might be multi-standard.		   We could just copy out the current value for the		   standard, but it can change over time.  For now just		   leave it zero. */		memcpy(vi, &tmp, sizeof(tmp));		ret = 0;		break;	}	case VIDIOC_G_INPUT:	{		struct pvr2_ctrl *cptr;		struct v4l2_input *vi = (struct v4l2_input *)arg;		cptr = pvr2_hdw_get_ctrl(hdw,V4L2_CID_PVR_INPUT);		if (!pvr2_ctrl_is_valid(cptr)) {			ret = -EINVAL;			break;		}		vi->index = pvr2_ctrl_get_value(cptr);		ret = 0;		break;	}	case VIDIOC_S_INPUT:	{		struct pvr2_ctrl *cptr;		struct v4l2_input *vi = (struct v4l2_input *)arg;		cptr = pvr2_hdw_get_ctrl(hdw,V4L2_CID_PVR_INPUT);		if (!pvr2_ctrl_is_valid(cptr)) {			ret = -EINVAL;			break;		}		ret = 0;		if (pvr2_ctrl_set_value(cptr,vi->index)) {			ret = -EINVAL;		}		break;	}	case VIDIOC_ENUMAUDIO:	{		ret = -EINVAL;		break;	}	case VIDIOC_G_AUDIO:	{		ret = -EINVAL;		break;	}	case VIDIOC_S_AUDIO:	{		ret = -EINVAL;		break;	}	case VIDIOC_G_TUNER:	{		struct pvr2_ctrl *cptr;		struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;		unsigned int status_mask;		if (vt->index !=0) break;		status_mask = pvr2_hdw_get_signal_status(hdw);		memcpy(vt, &pvr_v4l2_tuners[vt->index],		       sizeof(struct v4l2_tuner));		vt->signal = 0;		if (status_mask & PVR2_SIGNAL_OK) {			if (status_mask & PVR2_SIGNAL_STEREO) {				vt->rxsubchans = V4L2_TUNER_SUB_STEREO;			} else {				vt->rxsubchans = V4L2_TUNER_SUB_MONO;			}			if (status_mask & PVR2_SIGNAL_SAP) {				vt->rxsubchans |= (V4L2_TUNER_SUB_LANG1 |						   V4L2_TUNER_SUB_LANG2);			}			vt->signal = 65535;		}		cptr = pvr2_hdw_get_ctrl(hdw,V4L2_CID_PVR_AUDIOMODE);		vt->audmode = pvr2_ctrl_get_value(cptr);		ret = 0;		break;	}	case VIDIOC_S_TUNER:	{		struct pvr2_ctrl *cptr;		struct v4l2_tuner *vt=(struct v4l2_tuner *)arg;		if (vt->index != 0)			break;		cptr = pvr2_hdw_get_ctrl(hdw,V4L2_CID_PVR_AUDIOMODE);		if (!pvr2_ctrl_is_valid(cptr)) {			ret = -EINVAL;			break;		}		pvr2_ctrl_set_value(cptr,vt->audmode);		ret = 0;	}	case VIDIOC_S_FREQUENCY:	{		struct pvr2_ctrl *cptr;		const struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;		cptr = pvr2_hdw_get_ctrl(hdw,V4L2_CID_PVR_FREQUENCY);		if (!pvr2_ctrl_is_valid(cptr)) {			ret = -EINVAL;			break;		}		pvr2_ctrl_set_value(cptr,vf->frequency * 62500);		ret = 0;		break;	}	case VIDIOC_G_FREQUENCY:	{		struct pvr2_ctrl *cptr;		struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;		int val;		cptr = pvr2_hdw_get_ctrl(hdw,V4L2_CID_PVR_FREQUENCY);		if (!pvr2_ctrl_is_valid(cptr)) {			ret = -EINVAL;			break;		}		val = pvr2_ctrl_get_value(cptr);		val /= 62500;		vf->frequency = val;		ret = 0;		break;	}	case VIDIOC_ENUM_FMT:	{		struct v4l2_fmtdesc *fd = (struct v4l2_fmtdesc *)arg;		/* Only one format is supported : mpeg.*/		if (fd->index != 0)			break;		memcpy(fd, pvr_fmtdesc, sizeof(struct v4l2_fmtdesc));		ret = 0;		break;	}	case VIDIOC_G_FMT:	{		struct v4l2_format *vf = (struct v4l2_format *)arg;		switch(vf->type) {		case V4L2_BUF_TYPE_VIDEO_CAPTURE:			memcpy(vf, &pvr_format[PVR_FORMAT_PIX],			       sizeof(struct v4l2_format));			vf->fmt.pix.width =				pvr2_ctrl_get_value(					pvr2_hdw_get_ctrl(hdw,							  V4L2_CID_PVR_HRES));			if (pvr2_ctrl_get_value(				    pvr2_hdw_get_ctrl(					    hdw,V4L2_CID_PVR_INTERLACE))) {				vf->fmt.pix.width /= 2;			}			vf->fmt.pix.height =				pvr2_ctrl_get_value(					pvr2_hdw_get_ctrl(hdw,							  V4L2_CID_PVR_VRES));			ret = 0;			break;		case V4L2_BUF_TYPE_VBI_CAPTURE:			// ????? Still need to figure out to do VBI correctly			ret = -EINVAL;			break;		default:			ret = -EINVAL;			break;		}		break;	}	case VIDIOC_TRY_FMT:	case VIDIOC_S_FMT:	{		struct v4l2_format *vf = (struct v4l2_format *)arg;		ret = 0;		switch(vf->type) {		case V4L2_BUF_TYPE_VIDEO_CAPTURE: {			int h = vf->fmt.pix.height;			int w = vf->fmt.pix.width;			int vd_std, hf, hh;			vd_std = pvr2_ctrl_get_value(				pvr2_hdw_get_ctrl(hdw,V4L2_CID_PVR_STDCUR));			if (vd_std & V4L2_STD_525_60) {				hf=480;			} else {				hf=576;			}			hh = (int) (hf / 2);			memcpy(vf, &pvr_format[PVR_FORMAT_PIX],			       sizeof(struct v4l2_format));			if (w > 720)				vf->fmt.pix.width = 720;			vf->fmt.pix.width &= 0xff0;			vf->fmt.pix.height = (h > hh) ? hf : hh;			if (cmd == VIDIOC_S_FMT){				pvr2_ctrl_set_value(					pvr2_hdw_get_ctrl(hdw,

⌨️ 快捷键说明

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