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

📄 pvrusb2-v4l2.c

📁 V4l driver for DVB HD
💻 C
📖 第 1 页 / 共 2 页
字号:
							  V4L2_CID_PVR_HRES),					vf->fmt.pix.width);				pvr2_ctrl_set_value(					pvr2_hdw_get_ctrl(hdw,							  V4L2_CID_PVR_VRES),					vf->fmt.pix.height);				pvr2_ctrl_set_value(					pvr2_hdw_get_ctrl(						hdw,V4L2_CID_PVR_INTERLACE),					vf->fmt.pix.height != hf);			}		} 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_STREAMON:	{		ret = pvr2_hdw_set_stream_type(hdw,dev_info->config);		if (ret < 0) return ret;		ret = pvr2_hdw_set_streaming(hdw,!0);		break;	}	case VIDIOC_STREAMOFF:	{		ret = pvr2_hdw_set_streaming(hdw,0);		break;	}	case VIDIOC_QUERYCTRL:	{		struct pvr2_ctrl *cptr;		struct v4l2_queryctrl *vc = (struct v4l2_queryctrl *)arg;		cptr = pvr2_hdw_get_ctrl(hdw,vc->id);		if (!pvr2_ctrl_is_valid(cptr)) {			ret = -EINVAL;			break;		}		switch (pvr2_ctrl_get_type(cptr)) {		case PVR2_CTRL_TYPE_ENUM:			vc->type = V4L2_CTRL_TYPE_MENU;			break;		case PVR2_CTRL_TYPE_INT:			vc->type = V4L2_CTRL_TYPE_INTEGER;			break;		default:			ret = -EINVAL;			break;		}		strlcpy(vc->name,pvr2_ctrl_get_desc(cptr),sizeof(vc->name));		vc->minimum = pvr2_ctrl_get_min_value(cptr);		vc->maximum = pvr2_ctrl_get_max_value(cptr);		vc->default_value = pvr2_ctrl_get_default_value(cptr);		vc->step = 1;		ret = 0;		break;	}	case VIDIOC_QUERYMENU:	{		struct pvr2_ctrl *cptr;		struct v4l2_querymenu *vm = (struct v4l2_querymenu *)arg;		const char *value_name;		cptr = pvr2_hdw_get_ctrl(hdw,vm->id);		if (!pvr2_ctrl_is_valid(cptr)) {			ret = -EINVAL;			break;		}		value_name = pvr2_ctrl_get_value_name(cptr,vm->index);		if (value_name) {			strlcpy(vm->name,value_name,sizeof(vm->name));			ret = 0;		} else {			ret = -EINVAL;		}		break;	}	case VIDIOC_G_CTRL:	{		struct pvr2_ctrl *cptr;		struct v4l2_control *vc = (struct v4l2_control *)arg;		cptr = pvr2_hdw_get_ctrl(hdw,vc->id);		if (!pvr2_ctrl_is_valid(cptr)) {			ret = -EINVAL;			break;		}		ret = 0;		vc->value = pvr2_ctrl_get_value(cptr);		break;	}	case VIDIOC_S_CTRL:	{		struct pvr2_ctrl *cptr;		struct v4l2_control *vc = (struct v4l2_control *)arg;		cptr = pvr2_hdw_get_ctrl(hdw,vc->id);		if (!pvr2_ctrl_is_valid(cptr)) {			ret = -EINVAL;			break;		}		ret = pvr2_ctrl_set_value(cptr,vc->value);		break;	}	case VIDIOC_LOG_STATUS:	{		int nr = pvr2_hdw_get_unit_number(hdw);		printk(KERN_INFO "pvrusb2: =================  START STATUS CARD #%d  =================\n", nr);		pvr2_hdw_trigger_module_log(hdw);		printk(KERN_INFO "pvrusb2: ==================  END STATUS CARD #%d  ==================\n", nr);		ret = 0;		break;	}	default :		ret = v4l_compat_translate_ioctl(inode,file,cmd,						 arg,pvr2_v4l2_do_ioctl);	}	pvr2_hdw_commit_ctl(hdw);	if (ret < 0) {		if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {			pvr2_trace(PVR2_TRACE_ERROR_LEGS,				   "pvr2_v4l2_do_ioctl failure, ret=%d",ret);		} else {			if (pvrusb2_debug & PVR2_TRACE_ERROR_LEGS) {				pvr2_trace(PVR2_TRACE_ERROR_LEGS,					   "pvr2_v4l2_do_ioctl failure, ret=%d"					   " command was:",ret);				v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),						cmd);			}		}	} else {		pvr2_trace(PVR2_TRACE_V4LIOCTL,			   "pvr2_v4l2_do_ioctl complete, ret=%d (0x%x)",			   ret,ret);	}	return ret;}static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip){	pvr2_trace(PVR2_TRACE_INIT,		   "unregistering device video%d [%s]",		   dip->vdev->minor,pvr2_config_get_name(dip->config));	video_unregister_device(dip->vdev);}static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp){	pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,-1);	pvr2_v4l2_dev_destroy(&vp->video_dev);	pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp);	pvr2_channel_done(&vp->channel);	kfree(vp);}void pvr2_v4l2_internal_check(struct pvr2_channel *chp){	struct pvr2_v4l2 *vp;	vp = container_of(chp,struct pvr2_v4l2,channel);	if (!vp->channel.mc_head->disconnect_flag) return;	if (vp->vfirst) return;	pvr2_v4l2_destroy_no_lock(vp);}int pvr2_v4l2_ioctl(struct inode *inode, struct file *file,		    unsigned int cmd, unsigned long arg){/* Temporary hack : use ivtv api until a v4l2 one is available. */#define IVTV_IOC_G_CODEC        0xFFEE7703#define IVTV_IOC_S_CODEC        0xFFEE7704	if (cmd == IVTV_IOC_G_CODEC || cmd == IVTV_IOC_S_CODEC) return 0;	return video_usercopy(inode, file, cmd, arg, pvr2_v4l2_do_ioctl);}int pvr2_v4l2_release(struct inode *inode, struct file *file){	struct pvr2_v4l2_fh *fhp = file->private_data;	struct pvr2_v4l2 *vp = fhp->vhead;	struct pvr2_context *mp = fhp->vhead->channel.mc_head;	pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_release");	if (fhp->rhp) {		struct pvr2_stream *sp;		struct pvr2_hdw *hdw;		hdw = fhp->channel.mc_head->hdw;		pvr2_hdw_set_streaming(hdw,0);		sp = pvr2_ioread_get_stream(fhp->rhp);		if (sp) pvr2_stream_set_callback(sp,0,0);		pvr2_ioread_destroy(fhp->rhp);		fhp->rhp = 0;	}	v4l2_prio_close(&vp->prio, &fhp->prio);	file->private_data = NULL;	pvr2_context_enter(mp); do {		if (fhp->vnext) {			fhp->vnext->vprev = fhp->vprev;		} else {			vp->vlast = fhp->vprev;		}		if (fhp->vprev) {			fhp->vprev->vnext = fhp->vnext;		} else {			vp->vfirst = fhp->vnext;		}		fhp->vnext = 0;		fhp->vprev = 0;		fhp->vhead = 0;		pvr2_channel_done(&fhp->channel);		pvr2_trace(PVR2_TRACE_STRUCT,			   "Destroying pvr_v4l2_fh id=%p",fhp);		kfree(fhp);		if (vp->channel.mc_head->disconnect_flag && !vp->vfirst) {			pvr2_v4l2_destroy_no_lock(vp);		}	} while (0); pvr2_context_exit(mp);	return 0;}int pvr2_v4l2_open(struct inode *inode, struct file *file){	struct video_device *vdev = video_devdata(file);	struct pvr2_v4l2_dev *dip =		(struct pvr2_v4l2_dev *)video_get_drvdata(vdev);	struct pvr2_v4l2_fh *fhp;	struct pvr2_v4l2 *vp = dip->v4lp;	struct pvr2_hdw *hdw = vp->channel.hdw;	pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_open");	if (!pvr2_hdw_dev_ok(hdw)) {		pvr2_trace(PVR2_TRACE_OPEN_CLOSE,			   "pvr2_v4l2_open: hardware not ready");		return -EIO;	}	fhp = kmalloc(sizeof(*fhp),GFP_KERNEL);	if (!fhp) {		return -ENOMEM;	}	memset(fhp,0,sizeof(*fhp));	init_waitqueue_head(&fhp->wait_data);	fhp->dev_info = dip;	pvr2_context_enter(vp->channel.mc_head); do {		pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp);		pvr2_channel_init(&fhp->channel,vp->channel.mc_head);		fhp->vnext = 0;		fhp->vprev = vp->vlast;		if (vp->vlast) {			vp->vlast->vnext = fhp;		} else {			vp->vfirst = fhp;		}		vp->vlast = fhp;		fhp->vhead = vp;	} while (0); pvr2_context_exit(vp->channel.mc_head);	fhp->file = file;	file->private_data = fhp;	v4l2_prio_open(&vp->prio,&fhp->prio);	fhp->fw_mode_flag = pvr2_hdw_cpufw_get_enabled(hdw);	return 0;}static void pvr2_v4l2_notify(struct pvr2_v4l2_fh *fhp){	wake_up(&fhp->wait_data);}static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh){	int ret;	struct pvr2_stream *sp;	struct pvr2_hdw *hdw;	if (fh->rhp) return 0;	/* First read() attempt.  Try to claim the stream and start	   it... */	if ((ret = pvr2_channel_claim_stream(&fh->channel,					     fh->dev_info->stream)) != 0) {		/* Someone else must already have it */		return ret;	}	fh->rhp = pvr2_channel_create_mpeg_stream(fh->dev_info->stream);	if (!fh->rhp) {		pvr2_channel_claim_stream(&fh->channel,0);		return -ENOMEM;	}	hdw = fh->channel.mc_head->hdw;	sp = fh->dev_info->stream->stream;	pvr2_stream_set_callback(sp,(pvr2_stream_callback)pvr2_v4l2_notify,fh);	pvr2_hdw_set_stream_type(hdw,fh->dev_info->config);	pvr2_hdw_set_streaming(hdw,!0);	ret = pvr2_ioread_set_enabled(fh->rhp,!0);	return ret;}static ssize_t pvr2_v4l2_read(struct file *file,			      char __user *buff, size_t count, loff_t *ppos){	struct pvr2_v4l2_fh *fh = file->private_data;	int ret;	if (fh->fw_mode_flag) {		struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;		char *tbuf;		int c1,c2;		int tcnt = 0;		unsigned int offs = *ppos;		tbuf = kmalloc(PAGE_SIZE,GFP_KERNEL);		if (!tbuf) return -ENOMEM;		while (count) {			c1 = count;			if (c1 > PAGE_SIZE) c1 = PAGE_SIZE;			c2 = pvr2_hdw_cpufw_get(hdw,offs,tbuf,c1);			if (c2 < 0) {				tcnt = c2;				break;			}			if (!c2) break;			if (copy_to_user(buff,tbuf,c2)) {				tcnt = -EFAULT;				break;			}			offs += c2;			tcnt += c2;			buff += c2;			count -= c2;			*ppos += c2;		}		kfree(tbuf);		return tcnt;	}	if (!fh->rhp) {		ret = pvr2_v4l2_iosetup(fh);		if (ret) {			return ret;		}	}	for (;;) {		ret = pvr2_ioread_read(fh->rhp,buff,count);		if (ret >= 0) break;		if (ret != -EAGAIN) break;		if (file->f_flags & O_NONBLOCK) break;		/* Doing blocking I/O.  Wait here. */		ret = wait_event_interruptible(			fh->wait_data,			pvr2_ioread_avail(fh->rhp) >= 0);		if (ret < 0) break;	}	return ret;}static unsigned int pvr2_v4l2_poll(struct file *file, poll_table *wait){	unsigned int mask = 0;	struct pvr2_v4l2_fh *fh = file->private_data;	int ret;	if (fh->fw_mode_flag) {		mask |= POLLIN | POLLRDNORM;		return mask;	}	if (!fh->rhp) {		ret = pvr2_v4l2_iosetup(fh);		if (ret) return POLLERR;	}	poll_wait(file,&fh->wait_data,wait);	if (pvr2_ioread_avail(fh->rhp) >= 0) {		mask |= POLLIN | POLLRDNORM;	}	return mask;}static struct file_operations vdev_fops = {	.owner      = THIS_MODULE,	.open       = pvr2_v4l2_open,	.release    = pvr2_v4l2_release,	.read       = pvr2_v4l2_read,	.ioctl      = pvr2_v4l2_ioctl,	.llseek     = no_llseek,	.poll       = pvr2_v4l2_poll,};#define VID_HARDWARE_PVRUSB2    38  /* FIXME : need a good value */static struct video_device vdev_template = {	.owner      = THIS_MODULE,	.type       = VID_TYPE_CAPTURE | VID_TYPE_TUNER,	.type2      = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE		       | V4L2_CAP_TUNER | V4L2_CAP_AUDIO		       | V4L2_CAP_READWRITE),	.hardware   = VID_HARDWARE_PVRUSB2,	.fops       = &vdev_fops,};static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,			       struct pvr2_v4l2 *vp,			       enum pvr2_config cfg){#if 0	struct usb_device *usbdev;#endif	int mindevnum;	int unit_number;	int v4l_type;	dip->v4lp = vp;	dip->config = cfg;#if 0	usbdev = pvr2_hdw_get_dev(vp->channel.mc_head->hdw);#endif	switch (cfg) {	case pvr2_config_mpeg:		v4l_type = VFL_TYPE_GRABBER;		dip->stream = &vp->channel.mc_head->video_stream;		break;	case pvr2_config_vbi:		v4l_type = VFL_TYPE_VBI;		break;	case pvr2_config_radio:		v4l_type = VFL_TYPE_RADIO;		break;	default:		/* Bail out (this should be impossible) */		err("Failed to set up pvrusb2 v4l dev"		    " due to unrecognized config");		return;	}	if (!dip->stream) {		err("Failed to set up pvrusb2 v4l dev"		    " due to missing stream instance");		return;	}	dip->vdev = video_device_alloc();	if (!dip->vdev) {		err("Alloc of pvrusb2 v4l video device failed");		return;	}	memcpy(dip->vdev,&vdev_template,sizeof(vdev_template));#if 0	/* ????? This relation may be problematic on a disconnect.  Is this	   really needed?  I can't seem to find a reason for it.  This	   can't be a required thing - what if the video device being set	   up doesn't have a real hardware device under it? */	dip->vdev->dev = &usbdev->dev;#endif	dip->vdev->release = video_device_release;	video_set_drvdata(dip->vdev,dip);	mindevnum = -1;	unit_number = pvr2_hdw_get_unit_number(vp->channel.mc_head->hdw);	if ((unit_number >= 0) && (unit_number < PVR_NUM)) {		mindevnum = video_nr[unit_number];	}	if ((video_register_device(dip->vdev, v4l_type, mindevnum) < 0) &&	    (video_register_device(dip->vdev, v4l_type, -1) < 0)) {		err("Failed to register pvrusb2 v4l video device");	} else {		pvr2_trace(PVR2_TRACE_INIT,			   "registered device video%d [%s]",			   dip->vdev->minor,pvr2_config_get_name(dip->config));	}	pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,					dip->vdev->minor);}struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp){	struct pvr2_v4l2 *vp;	vp = kmalloc(sizeof(*vp),GFP_KERNEL);	if (!vp) return vp;	memset(vp,0,sizeof(*vp));	pvr2_channel_init(&vp->channel,mnp);	pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp);	vp->channel.check_func = pvr2_v4l2_internal_check;	/* register streams */	pvr2_v4l2_dev_init(&vp->video_dev,vp,pvr2_config_mpeg);	return vp;}/*  Stuff for Emacs to see, in order to encourage consistent editing style:  *** Local Variables: ***  *** mode: c ***  *** fill-column: 75 ***  *** tab-width: 8 ***  *** c-basic-offset: 8 ***  *** End: ***  */

⌨️ 快捷键说明

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