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

📄 pvrusb2-v4l2.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 2 页
字号:
			vc->type = V4L2_CTRL_TYPE_BOOLEAN;			vc->minimum = 0;			vc->maximum = 1;			vc->step = 1;			break;		case pvr2_ctl_int:			vc->type = V4L2_CTRL_TYPE_INTEGER;			vc->minimum = pvr2_ctrl_get_min(cptr);			vc->maximum = pvr2_ctrl_get_max(cptr);			vc->step = 1;			break;		default:			pvr2_trace(PVR2_TRACE_V4LIOCTL,				   "QUERYCTRL id=0x%x name=%s not mappable",				   vc->id,pvr2_ctrl_get_name(cptr));			ret = -EINVAL;			break;		}		break;	}	case VIDIOC_QUERYMENU:	{		struct v4l2_querymenu *vm = (struct v4l2_querymenu *)arg;		unsigned int cnt = 0;		ret = pvr2_ctrl_get_valname(pvr2_hdw_get_ctrl_v4l(hdw,vm->id),					    vm->index,					    vm->name,sizeof(vm->name)-1,					    &cnt);		vm->name[cnt] = 0;		break;	}	case VIDIOC_G_CTRL:	{		struct v4l2_control *vc = (struct v4l2_control *)arg;		int val = 0;		ret = pvr2_ctrl_get_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id),					  &val);		vc->value = val;		break;	}	case VIDIOC_S_CTRL:	{		struct v4l2_control *vc = (struct v4l2_control *)arg;		ret = pvr2_ctrl_set_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id),					  vc->value);		break;	}	case VIDIOC_G_EXT_CTRLS:	{		struct v4l2_ext_controls *ctls =			(struct v4l2_ext_controls *)arg;		struct v4l2_ext_control *ctrl;		unsigned int idx;		int val;		ret = 0;		for (idx = 0; idx < ctls->count; idx++) {			ctrl = ctls->controls + idx;			ret = pvr2_ctrl_get_value(				pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id),&val);			if (ret) {				ctls->error_idx = idx;				break;			}			/* Ensure that if read as a 64 bit value, the user			   will still get a hopefully sane value */			ctrl->value64 = 0;			ctrl->value = val;		}		break;	}	case VIDIOC_S_EXT_CTRLS:	{		struct v4l2_ext_controls *ctls =			(struct v4l2_ext_controls *)arg;		struct v4l2_ext_control *ctrl;		unsigned int idx;		ret = 0;		for (idx = 0; idx < ctls->count; idx++) {			ctrl = ctls->controls + idx;			ret = pvr2_ctrl_set_value(				pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id),				ctrl->value);			if (ret) {				ctls->error_idx = idx;				break;			}		}		break;	}	case VIDIOC_TRY_EXT_CTRLS:	{		struct v4l2_ext_controls *ctls =			(struct v4l2_ext_controls *)arg;		struct v4l2_ext_control *ctrl;		struct pvr2_ctrl *pctl;		unsigned int idx;		/* For the moment just validate that the requested control		   actually exists. */		ret = 0;		for (idx = 0; idx < ctls->count; idx++) {			ctrl = ctls->controls + idx;			pctl = pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id);			if (!pctl) {				ret = -EINVAL;				ctls->error_idx = idx;				break;			}		}		break;	}	case VIDIOC_LOG_STATUS:	{		pvr2_hdw_trigger_module_log(hdw);		ret = 0;		break;	}#ifdef CONFIG_VIDEO_ADV_DEBUG	case VIDIOC_DBG_S_REGISTER:	case VIDIOC_DBG_G_REGISTER:	{		u64 val;		struct v4l2_register *req = (struct v4l2_register *)arg;		if (cmd == VIDIOC_DBG_S_REGISTER) val = req->val;		ret = pvr2_hdw_register_access(			hdw,req->match_type,req->match_chip,req->reg,			cmd == VIDIOC_DBG_S_REGISTER,&val);		if (cmd == VIDIOC_DBG_G_REGISTER) req->val = val;		break;	}#endif	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_V4LIOCTL,				   "pvr2_v4l2_do_ioctl failure, ret=%d",ret);		} else {			if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {				pvr2_trace(PVR2_TRACE_V4LIOCTL,					   "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){	int minor_id = dip->devbase.minor;	struct pvr2_hdw *hdw = dip->v4lp->channel.mc_head->hdw;	enum pvr2_config cfg = dip->config;	int v4l_type = dip->v4l_type;	pvr2_hdw_v4l_store_minor_number(hdw,dip->minor_type,-1);	/* Paranoia */	dip->v4lp = NULL;	dip->stream = NULL;	/* Actual deallocation happens later when all internal references	   are gone. */	video_unregister_device(&dip->devbase);	printk(KERN_INFO "pvrusb2: unregistered device %s%u [%s]\n",	       get_v4l_name(v4l_type),minor_id & 0x1f,	       pvr2_config_get_name(cfg));}static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp){	if (vp->dev_video) {		pvr2_v4l2_dev_destroy(vp->dev_video);		vp->dev_video = NULL;	}	if (vp->dev_radio) {		pvr2_v4l2_dev_destroy(vp->dev_radio);		vp->dev_radio = NULL;	}	pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp);	pvr2_channel_done(&vp->channel);	kfree(vp);}static void pvr2_video_device_release(struct video_device *vdev){	struct pvr2_v4l2_dev *dev;	dev = container_of(vdev,struct pvr2_v4l2_dev,devbase);	kfree(dev);}static 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);}static 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);}static 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;	struct pvr2_hdw *hdw = fhp->channel.mc_head->hdw;	pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_release");	if (fhp->rhp) {		struct pvr2_stream *sp;		pvr2_hdw_set_streaming(hdw,0);		sp = pvr2_ioread_get_stream(fhp->rhp);		if (sp) pvr2_stream_set_callback(sp,NULL,NULL);		pvr2_ioread_destroy(fhp->rhp);		fhp->rhp = NULL;	}	v4l2_prio_close(&vp->prio, &fhp->prio);	file->private_data = NULL;	pvr2_context_enter(mp); do {		/* Restore the previous input selection, if it makes sense		   to do so. */		if (fhp->dev_info->v4l_type == VFL_TYPE_RADIO) {			struct pvr2_ctrl *cp;			int pval;			cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);			pvr2_ctrl_get_value(cp,&pval);			/* Only restore if we're still selecting the radio */			if (pval == PVR2_CVAL_INPUT_RADIO) {				pvr2_ctrl_set_value(cp,fhp->prev_input_val);				pvr2_hdw_commit_ctl(hdw);			}		}		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 = NULL;		fhp->vprev = NULL;		fhp->vhead = NULL;		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;}static int pvr2_v4l2_open(struct inode *inode, struct file *file){	struct pvr2_v4l2_dev *dip; /* Our own context pointer */	struct pvr2_v4l2_fh *fhp;	struct pvr2_v4l2 *vp;	struct pvr2_hdw *hdw;	dip = container_of(video_devdata(file),struct pvr2_v4l2_dev,devbase);	vp = dip->v4lp;	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 = kzalloc(sizeof(*fhp),GFP_KERNEL);	if (!fhp) {		return -ENOMEM;	}	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 = NULL;		fhp->vprev = vp->vlast;		if (vp->vlast) {			vp->vlast->vnext = fhp;		} else {			vp->vfirst = fhp;		}		vp->vlast = fhp;		fhp->vhead = vp;		/* Opening the /dev/radioX device implies a mode switch.		   So execute that here.  Note that you can get the		   IDENTICAL effect merely by opening the normal video		   device and setting the input appropriately. */		if (dip->v4l_type == VFL_TYPE_RADIO) {			struct pvr2_ctrl *cp;			cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);			pvr2_ctrl_get_value(cp,&fhp->prev_input_val);			pvr2_ctrl_set_value(cp,PVR2_CVAL_INPUT_RADIO);			pvr2_hdw_commit_ctl(hdw);		}	} 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;	if (!fh->dev_info->stream) {		/* No stream defined for this node.  This means that we're		   not currently allowed to stream from this node. */		return -EPERM;	}	/* 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,NULL);		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 const 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,};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),	.fops       = &vdev_fops,};static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,			       struct pvr2_v4l2 *vp,			       int v4l_type){	int mindevnum;	int unit_number;	int *nr_ptr = NULL;	dip->v4lp = vp;	dip->v4l_type = v4l_type;	switch (v4l_type) {	case VFL_TYPE_GRABBER:		dip->stream = &vp->channel.mc_head->video_stream;		dip->config = pvr2_config_mpeg;		dip->minor_type = pvr2_v4l_type_video;		nr_ptr = video_nr;		if (!dip->stream) {			err("Failed to set up pvrusb2 v4l video dev"			    " due to missing stream instance");			return;		}		break;	case VFL_TYPE_VBI:		dip->config = pvr2_config_vbi;		dip->minor_type = pvr2_v4l_type_vbi;		nr_ptr = vbi_nr;		break;	case VFL_TYPE_RADIO:		dip->stream = &vp->channel.mc_head->video_stream;		dip->config = pvr2_config_mpeg;		dip->minor_type = pvr2_v4l_type_radio;		nr_ptr = radio_nr;		break;	default:		/* Bail out (this should be impossible) */		err("Failed to set up pvrusb2 v4l dev"		    " due to unrecognized config");		return;	}	memcpy(&dip->devbase,&vdev_template,sizeof(vdev_template));	dip->devbase.release = pvr2_video_device_release;	mindevnum = -1;	unit_number = pvr2_hdw_get_unit_number(vp->channel.mc_head->hdw);	if (nr_ptr && (unit_number >= 0) && (unit_number < PVR_NUM)) {		mindevnum = nr_ptr[unit_number];	}	if ((video_register_device(&dip->devbase,				   dip->v4l_type, mindevnum) < 0) &&	    (video_register_device(&dip->devbase,				   dip->v4l_type, -1) < 0)) {		err("Failed to register pvrusb2 v4l device");	}	printk(KERN_INFO "pvrusb2: registered device %s%u [%s]\n",	       get_v4l_name(dip->v4l_type),dip->devbase.minor & 0x1f,	       pvr2_config_get_name(dip->config));	pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,					dip->minor_type,dip->devbase.minor);}struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp){	struct pvr2_v4l2 *vp;	vp = kzalloc(sizeof(*vp),GFP_KERNEL);	if (!vp) return vp;	vp->dev_video = kzalloc(sizeof(*vp->dev_video),GFP_KERNEL);	vp->dev_radio = kzalloc(sizeof(*vp->dev_radio),GFP_KERNEL);	if (!(vp->dev_video && vp->dev_radio)) {		kfree(vp->dev_video);		kfree(vp->dev_radio);		kfree(vp);		return NULL;	}	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->dev_video,vp,VFL_TYPE_GRABBER);	pvr2_v4l2_dev_init(vp->dev_radio,vp,VFL_TYPE_RADIO);	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 + -