videodev.c

来自「linux 内核源代码」· C语言 代码 · 共 1,829 行 · 第 1/3 页

C
1,829
字号
		ret=vfd->vidioc_enumaudout(file, fh, p);		if (!ret)			dbgarg2("index=%d, name=%s, capability=%d, "					"mode=%d\n", p->index, p->name,					p->capability,p->mode);		break;	}	case VIDIOC_G_AUDOUT:	{		struct v4l2_audioout *p=arg;		if (!vfd->vidioc_g_audout)			break;		dbgarg(cmd, "Enum for index=%d\n", p->index);		ret=vfd->vidioc_g_audout(file, fh, p);		if (!ret)			dbgarg2("index=%d, name=%s, capability=%d, "					"mode=%d\n", p->index, p->name,					p->capability,p->mode);		break;	}	case VIDIOC_S_AUDOUT:	{		struct v4l2_audioout *p=arg;		if (!vfd->vidioc_s_audout)			break;		dbgarg(cmd, "index=%d, name=%s, capability=%d, "					"mode=%d\n", p->index, p->name,					p->capability,p->mode);		ret=vfd->vidioc_s_audout(file, fh, p);		break;	}	case VIDIOC_G_MODULATOR:	{		struct v4l2_modulator *p=arg;		if (!vfd->vidioc_g_modulator)			break;		ret=vfd->vidioc_g_modulator(file, fh, p);		if (!ret)			dbgarg(cmd, "index=%d, name=%s, "					"capability=%d, rangelow=%d,"					" rangehigh=%d, txsubchans=%d\n",					p->index, p->name,p->capability,					p->rangelow, p->rangehigh,					p->txsubchans);		break;	}	case VIDIOC_S_MODULATOR:	{		struct v4l2_modulator *p=arg;		if (!vfd->vidioc_s_modulator)			break;		dbgarg(cmd, "index=%d, name=%s, capability=%d, "				"rangelow=%d, rangehigh=%d, txsubchans=%d\n",				p->index, p->name,p->capability,p->rangelow,				p->rangehigh,p->txsubchans);			ret=vfd->vidioc_s_modulator(file, fh, p);		break;	}	case VIDIOC_G_CROP:	{		struct v4l2_crop *p=arg;		if (!vfd->vidioc_g_crop)			break;		ret=vfd->vidioc_g_crop(file, fh, p);		if (!ret) {			dbgarg(cmd, "type=%d\n", p->type);			dbgrect(vfd, "", &p->c);		}		break;	}	case VIDIOC_S_CROP:	{		struct v4l2_crop *p=arg;		if (!vfd->vidioc_s_crop)			break;		dbgarg(cmd, "type=%d\n", p->type);		dbgrect(vfd, "", &p->c);		ret=vfd->vidioc_s_crop(file, fh, p);		break;	}	case VIDIOC_CROPCAP:	{		struct v4l2_cropcap *p=arg;		/*FIXME: Should also show v4l2_fract pixelaspect */		if (!vfd->vidioc_cropcap)			break;		dbgarg(cmd, "type=%d\n", p->type);		dbgrect(vfd, "bounds ", &p->bounds);		dbgrect(vfd, "defrect ", &p->defrect);		ret=vfd->vidioc_cropcap(file, fh, p);		break;	}	case VIDIOC_G_JPEGCOMP:	{		struct v4l2_jpegcompression *p=arg;		if (!vfd->vidioc_g_jpegcomp)			break;		ret=vfd->vidioc_g_jpegcomp(file, fh, p);		if (!ret)			dbgarg (cmd, "quality=%d, APPn=%d, "						"APP_len=%d, COM_len=%d, "						"jpeg_markers=%d\n",						p->quality,p->APPn,p->APP_len,						p->COM_len,p->jpeg_markers);		break;	}	case VIDIOC_S_JPEGCOMP:	{		struct v4l2_jpegcompression *p=arg;		if (!vfd->vidioc_g_jpegcomp)			break;		dbgarg (cmd, "quality=%d, APPn=%d, APP_len=%d, "					"COM_len=%d, jpeg_markers=%d\n",					p->quality,p->APPn,p->APP_len,					p->COM_len,p->jpeg_markers);			ret=vfd->vidioc_s_jpegcomp(file, fh, p);		break;	}	case VIDIOC_G_ENC_INDEX:	{		struct v4l2_enc_idx *p=arg;		if (!vfd->vidioc_g_enc_index)			break;		ret=vfd->vidioc_g_enc_index(file, fh, p);		if (!ret)			dbgarg (cmd, "entries=%d, entries_cap=%d\n",					p->entries,p->entries_cap);		break;	}	case VIDIOC_ENCODER_CMD:	{		struct v4l2_encoder_cmd *p=arg;		if (!vfd->vidioc_encoder_cmd)			break;		ret=vfd->vidioc_encoder_cmd(file, fh, p);		if (!ret)			dbgarg (cmd, "cmd=%d, flags=%d\n",					p->cmd,p->flags);		break;	}	case VIDIOC_TRY_ENCODER_CMD:	{		struct v4l2_encoder_cmd *p=arg;		if (!vfd->vidioc_try_encoder_cmd)			break;		ret=vfd->vidioc_try_encoder_cmd(file, fh, p);		if (!ret)			dbgarg (cmd, "cmd=%d, flags=%d\n",					p->cmd,p->flags);		break;	}	case VIDIOC_G_PARM:	{		struct v4l2_streamparm *p=arg;		__u32 type=p->type;		memset(p,0,sizeof(*p));		p->type=type;		if (vfd->vidioc_g_parm) {			ret=vfd->vidioc_g_parm(file, fh, p);		} else {			struct v4l2_standard s;			if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)				return -EINVAL;			v4l2_video_std_construct(&s, vfd->current_norm,						 v4l2_norm_to_name(vfd->current_norm));			p->parm.capture.timeperframe = s.frameperiod;			ret=0;		}		dbgarg (cmd, "type=%d\n", p->type);		break;	}	case VIDIOC_S_PARM:	{		struct v4l2_streamparm *p=arg;		if (!vfd->vidioc_s_parm)			break;		dbgarg (cmd, "type=%d\n", p->type);		ret=vfd->vidioc_s_parm(file, fh, p);		break;	}	case VIDIOC_G_TUNER:	{		struct v4l2_tuner *p=arg;		__u32 index=p->index;		if (!vfd->vidioc_g_tuner)			break;		memset(p,0,sizeof(*p));		p->index=index;		ret=vfd->vidioc_g_tuner(file, fh, p);		if (!ret)			dbgarg (cmd, "index=%d, name=%s, type=%d, "					"capability=%d, rangelow=%d, "					"rangehigh=%d, signal=%d, afc=%d, "					"rxsubchans=%d, audmode=%d\n",					p->index, p->name, p->type,					p->capability, p->rangelow,					p->rangehigh, p->rxsubchans,					p->audmode, p->signal, p->afc);		break;	}	case VIDIOC_S_TUNER:	{		struct v4l2_tuner *p=arg;		if (!vfd->vidioc_s_tuner)			break;		dbgarg (cmd, "index=%d, name=%s, type=%d, "				"capability=%d, rangelow=%d, rangehigh=%d, "				"signal=%d, afc=%d, rxsubchans=%d, "				"audmode=%d\n",p->index, p->name, p->type,				p->capability, p->rangelow,p->rangehigh,				p->rxsubchans, p->audmode, p->signal,				p->afc);		ret=vfd->vidioc_s_tuner(file, fh, p);		break;	}	case VIDIOC_G_FREQUENCY:	{		struct v4l2_frequency *p=arg;		if (!vfd->vidioc_g_frequency)			break;		memset(p,0,sizeof(*p));		ret=vfd->vidioc_g_frequency(file, fh, p);		if (!ret)			dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n",						p->tuner,p->type,p->frequency);		break;	}	case VIDIOC_S_FREQUENCY:	{		struct v4l2_frequency *p=arg;		if (!vfd->vidioc_s_frequency)			break;		dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n",				p->tuner,p->type,p->frequency);		ret=vfd->vidioc_s_frequency(file, fh, p);		break;	}	case VIDIOC_G_SLICED_VBI_CAP:	{		struct v4l2_sliced_vbi_cap *p=arg;		if (!vfd->vidioc_g_sliced_vbi_cap)			break;		ret=vfd->vidioc_g_sliced_vbi_cap(file, fh, p);		if (!ret)			dbgarg (cmd, "service_set=%d\n", p->service_set);		break;	}	case VIDIOC_LOG_STATUS:	{		if (!vfd->vidioc_log_status)			break;		ret=vfd->vidioc_log_status(file, fh);		break;	}#ifdef CONFIG_VIDEO_ADV_DEBUG	case VIDIOC_DBG_G_REGISTER:	{		struct v4l2_register *p=arg;		if (!capable(CAP_SYS_ADMIN))			ret=-EPERM;		else if (vfd->vidioc_g_register)			ret=vfd->vidioc_g_register(file, fh, p);		break;	}	case VIDIOC_DBG_S_REGISTER:	{		struct v4l2_register *p=arg;		if (!capable(CAP_SYS_ADMIN))			ret=-EPERM;		else if (vfd->vidioc_s_register)			ret=vfd->vidioc_s_register(file, fh, p);		break;	}#endif	case VIDIOC_G_CHIP_IDENT:	{		struct v4l2_chip_ident *p=arg;		if (!vfd->vidioc_g_chip_ident)			break;		ret=vfd->vidioc_g_chip_ident(file, fh, p);		if (!ret)			dbgarg (cmd, "chip_ident=%u, revision=0x%x\n", p->ident, p->revision);		break;	}	} /* switch */	if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {		if (ret<0) {			printk ("%s: err:\n", vfd->name);			v4l_print_ioctl(vfd->name, cmd);		}	}	return ret;}int video_ioctl2 (struct inode *inode, struct file *file,	       unsigned int cmd, unsigned long arg){	char	sbuf[128];	void    *mbuf = NULL;	void	*parg = NULL;	int	err  = -EINVAL;	int     is_ext_ctrl;	size_t  ctrls_size = 0;	void __user *user_ptr = NULL;#ifdef __OLD_VIDIOC_	cmd = video_fix_command(cmd);#endif	is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||		       cmd == VIDIOC_TRY_EXT_CTRLS);	/*  Copy arguments into temp kernel buffer  */	switch (_IOC_DIR(cmd)) {	case _IOC_NONE:		parg = NULL;		break;	case _IOC_READ:	case _IOC_WRITE:	case (_IOC_WRITE | _IOC_READ):		if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {			parg = sbuf;		} else {			/* too big to allocate from stack */			mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);			if (NULL == mbuf)				return -ENOMEM;			parg = mbuf;		}		err = -EFAULT;		if (_IOC_DIR(cmd) & _IOC_WRITE)			if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))				goto out;		break;	}	if (is_ext_ctrl) {		struct v4l2_ext_controls *p = parg;		/* In case of an error, tell the caller that it wasn't		   a specific control that caused it. */		p->error_idx = p->count;		user_ptr = (void __user *)p->controls;		if (p->count) {			ctrls_size = sizeof(struct v4l2_ext_control) * p->count;			/* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */			mbuf = kmalloc(ctrls_size, GFP_KERNEL);			err = -ENOMEM;			if (NULL == mbuf)				goto out_ext_ctrl;			err = -EFAULT;			if (copy_from_user(mbuf, user_ptr, ctrls_size))				goto out_ext_ctrl;			p->controls = mbuf;		}	}	/* Handles IOCTL */	err = __video_do_ioctl(inode, file, cmd, parg);	if (err == -ENOIOCTLCMD)		err = -EINVAL;	if (is_ext_ctrl) {		struct v4l2_ext_controls *p = parg;		p->controls = (void *)user_ptr;		if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))			err = -EFAULT;		goto out_ext_ctrl;	}	if (err < 0)		goto out;out_ext_ctrl:	/*  Copy results into user buffer  */	switch (_IOC_DIR(cmd))	{	case _IOC_READ:	case (_IOC_WRITE | _IOC_READ):		if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))			err = -EFAULT;		break;	}out:	kfree(mbuf);	return err;}static const struct file_operations video_fops;/** *	video_register_device - register video4linux devices *	@vfd:  video device structure we want to register *	@type: type of device to register *	@nr:   which device number (0 == /dev/video0, 1 == /dev/video1, ... *             -1 == first free) * *	The registration code assigns minor numbers based on the type *	requested. -ENFILE is returned in all the device slots for this *	category are full. If not then the minor field is set and the *	driver initialize function is called (if non %NULL). * *	Zero is returned on success. * *	Valid types are * *	%VFL_TYPE_GRABBER - A frame grabber * *	%VFL_TYPE_VTX - A teletext device * *	%VFL_TYPE_VBI - Vertical blank data (undecoded) * *	%VFL_TYPE_RADIO - A radio card */int video_register_device(struct video_device *vfd, int type, int nr){	int i=0;	int base;	int end;	int ret;	char *name_base;	switch(type)	{		case VFL_TYPE_GRABBER:			base=MINOR_VFL_TYPE_GRABBER_MIN;			end=MINOR_VFL_TYPE_GRABBER_MAX+1;			name_base = "video";			break;		case VFL_TYPE_VTX:			base=MINOR_VFL_TYPE_VTX_MIN;			end=MINOR_VFL_TYPE_VTX_MAX+1;			name_base = "vtx";			break;		case VFL_TYPE_VBI:			base=MINOR_VFL_TYPE_VBI_MIN;			end=MINOR_VFL_TYPE_VBI_MAX+1;			name_base = "vbi";			break;		case VFL_TYPE_RADIO:			base=MINOR_VFL_TYPE_RADIO_MIN;			end=MINOR_VFL_TYPE_RADIO_MAX+1;			name_base = "radio";			break;		default:			printk(KERN_ERR "%s called with unknown type: %d\n",			       __FUNCTION__, type);			return -1;	}	/* pick a minor number */	mutex_lock(&videodev_lock);	if (nr >= 0  &&  nr < end-base) {		/* use the one the driver asked for */		i = base+nr;		if (NULL != video_device[i]) {			mutex_unlock(&videodev_lock);			return -ENFILE;		}	} else {		/* use first free */		for(i=base;i<end;i++)			if (NULL == video_device[i])				break;		if (i == end) {			mutex_unlock(&videodev_lock);			return -ENFILE;		}	}	video_device[i]=vfd;	vfd->minor=i;	mutex_unlock(&videodev_lock);	mutex_init(&vfd->lock);	/* sysfs class */	memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev));	if (vfd->dev)		vfd->class_dev.parent = vfd->dev;	vfd->class_dev.class       = &video_class;	vfd->class_dev.devt        = MKDEV(VIDEO_MAJOR, vfd->minor);	sprintf(vfd->class_dev.bus_id, "%s%d", name_base, i - base);	ret = device_register(&vfd->class_dev);	if (ret < 0) {		printk(KERN_ERR "%s: device_register failed\n",		       __FUNCTION__);		goto fail_minor;	}#if 1	/* needed until all drivers are fixed */	if (!vfd->release)		printk(KERN_WARNING "videodev: \"%s\" has no release callback. "		       "Please fix your driver for proper sysfs support, see "		       "http://lwn.net/Articles/36850/\n", vfd->name);#endif	return 0;fail_minor:	mutex_lock(&videodev_lock);	video_device[vfd->minor] = NULL;	vfd->minor = -1;	mutex_unlock(&videodev_lock);	return ret;}/** *	video_unregister_device - unregister a video4linux device *	@vfd: the device to unregister * *	This unregisters the passed device and deassigns the minor *	number. Future open calls will be met with errors. */void video_unregister_device(struct video_device *vfd){	mutex_lock(&videodev_lock);	if(video_device[vfd->minor]!=vfd)		panic("videodev: bad unregister");	video_device[vfd->minor]=NULL;	device_unregister(&vfd->class_dev);	mutex_unlock(&videodev_lock);}/* * Video fs operations */static const struct file_operations video_fops={	.owner		= THIS_MODULE,	.llseek		= no_llseek,	.open		= video_open,};/* *	Initialise video for linux */static int __init videodev_init(void){	int ret;	printk(KERN_INFO "Linux video capture interface: v2.00\n");	if (register_chrdev(VIDEO_MAJOR, VIDEO_NAME, &video_fops)) {		printk(KERN_WARNING "video_dev: unable to get major %d\n", VIDEO_MAJOR);		return -EIO;	}	ret = class_register(&video_class);	if (ret < 0) {		unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME);		printk(KERN_WARNING "video_dev: class_register failed\n");		return -EIO;	}	return 0;}static void __exit videodev_exit(void){	class_unregister(&video_class);	unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME);}module_init(videodev_init)module_exit(videodev_exit)EXPORT_SYMBOL(video_register_device);EXPORT_SYMBOL(video_unregister_device);EXPORT_SYMBOL(video_devdata);EXPORT_SYMBOL(video_usercopy);EXPORT_SYMBOL(video_exclusive_open);EXPORT_SYMBOL(video_exclusive_release);EXPORT_SYMBOL(video_ioctl2);EXPORT_SYMBOL(video_device_alloc);EXPORT_SYMBOL(video_device_release);MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org>");MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2");MODULE_LICENSE("GPL");/* * Local variables: * c-basic-offset: 8 * End: */

⌨️ 快捷键说明

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