v4l2-ioctl.c

来自「trident tm5600的linux驱动」· C语言 代码 · 共 1,872 行 · 第 1/4 页

C
1,872
字号
		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;}EXPORT_SYMBOL(video_usercopy);static void dbgbuf(unsigned int cmd, struct video_device *vfd,					struct v4l2_buffer *p){	struct v4l2_timecode *tc = &p->timecode;	dbgarg(cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, "		"bytesused=%d, flags=0x%08d, "		"field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx, length=%d\n",			p->timestamp.tv_sec / 3600,			(int)(p->timestamp.tv_sec / 60) % 60,			(int)(p->timestamp.tv_sec % 60),			(long)p->timestamp.tv_usec,			p->index,			prt_names(p->type, v4l2_type_names),			p->bytesused, p->flags,			p->field, p->sequence,			prt_names(p->memory, v4l2_memory_names),			p->m.userptr, p->length);	dbgarg2("timecode=%02d:%02d:%02d type=%d, "		"flags=0x%08d, frames=%d, userbits=0x%08x\n",			tc->hours, tc->minutes, tc->seconds,			tc->type, tc->flags, tc->frames, *(__u32 *)tc->userbits);}static inline void dbgrect(struct video_device *vfd, char *s,							struct v4l2_rect *r){	dbgarg2("%sRect start at %dx%d, size=%dx%d\n", s, r->left, r->top,						r->width, r->height);};static inline void v4l_print_pix_fmt(struct video_device *vfd,						struct v4l2_pix_format *fmt){	dbgarg2("width=%d, height=%d, format=%c%c%c%c, field=%s, "		"bytesperline=%d sizeimage=%d, colorspace=%d\n",		fmt->width, fmt->height,		(fmt->pixelformat & 0xff),		(fmt->pixelformat >>  8) & 0xff,		(fmt->pixelformat >> 16) & 0xff,		(fmt->pixelformat >> 24) & 0xff,		prt_names(fmt->field, v4l2_field_names),		fmt->bytesperline, fmt->sizeimage, fmt->colorspace);};static inline void v4l_print_ext_ctrls(unsigned int cmd,	struct video_device *vfd, struct v4l2_ext_controls *c, int show_vals){	__u32 i;	if (!(vfd->debug & V4L2_DEBUG_IOCTL_ARG))		return;	dbgarg(cmd, "");	printk(KERN_CONT "class=0x%x", c->ctrl_class);	for (i = 0; i < c->count; i++) {		if (show_vals)			printk(KERN_CONT " id/val=0x%x/0x%x",				c->controls[i].id, c->controls[i].value);		else			printk(KERN_CONT " id=0x%x", c->controls[i].id);	}	printk(KERN_CONT "\n");};static inline int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv){	__u32 i;	/* zero the reserved fields */	c->reserved[0] = c->reserved[1] = 0;	for (i = 0; i < c->count; i++) {		c->controls[i].reserved2[0] = 0;		c->controls[i].reserved2[1] = 0;	}	/* V4L2_CID_PRIVATE_BASE cannot be used as control class	   when using extended controls.	   Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL	   is it allowed for backwards compatibility.	 */	if (!allow_priv && c->ctrl_class == V4L2_CID_PRIVATE_BASE)		return 0;	/* Check that all controls are from the same control class. */	for (i = 0; i < c->count; i++) {		if (V4L2_CTRL_ID2CLASS(c->controls[i].id) != c->ctrl_class) {			c->error_idx = i;			return 0;		}	}	return 1;}static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type){	if (ops == NULL)		return -EINVAL;	switch (type) {	case V4L2_BUF_TYPE_VIDEO_CAPTURE:		if (ops->vidioc_try_fmt_vid_cap)			return 0;		break;	case V4L2_BUF_TYPE_VIDEO_OVERLAY:		if (ops->vidioc_try_fmt_vid_overlay)			return 0;		break;	case V4L2_BUF_TYPE_VIDEO_OUTPUT:		if (ops->vidioc_try_fmt_vid_out)			return 0;		break;	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:		if (ops->vidioc_try_fmt_vid_out_overlay)			return 0;		break;	case V4L2_BUF_TYPE_VBI_CAPTURE:		if (ops->vidioc_try_fmt_vbi_cap)			return 0;		break;	case V4L2_BUF_TYPE_VBI_OUTPUT:		if (ops->vidioc_try_fmt_vbi_out)			return 0;		break;	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:		if (ops->vidioc_try_fmt_sliced_vbi_cap)			return 0;		break;	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:		if (ops->vidioc_try_fmt_sliced_vbi_out)			return 0;		break;	case V4L2_BUF_TYPE_PRIVATE:		if (ops->vidioc_try_fmt_type_private)			return 0;		break;	}	return -EINVAL;}static int __video_do_ioctl(struct file *file,		unsigned int cmd, void *arg){	struct video_device *vfd = video_devdata(file);	const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;	void *fh = file->private_data;	int ret = -EINVAL;	if ((vfd->debug & V4L2_DEBUG_IOCTL) &&				!(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) {		v4l_print_ioctl(vfd->name, cmd);		printk(KERN_CONT "\n");	}	if (ops == NULL) {		printk(KERN_WARNING "videodev: \"%s\" has no ioctl_ops.\n",				vfd->name);		return -EINVAL;	}#ifdef CONFIG_VIDEO_V4L1_COMPAT	/***********************************************************	 Handles calls to the obsoleted V4L1 API	 Due to the nature of VIDIOCGMBUF, each driver that supports	 V4L1 should implement its own handler for this ioctl.	 ***********************************************************/	/* --- streaming capture ------------------------------------- */	if (cmd == VIDIOCGMBUF) {		struct video_mbuf *p = arg;		memset(p, 0, sizeof(*p));		if (!ops->vidiocgmbuf)			return ret;		ret = ops->vidiocgmbuf(file, fh, p);		if (!ret)			dbgarg(cmd, "size=%d, frames=%d, offsets=0x%08lx\n",						p->size, p->frames,						(unsigned long)p->offsets);		return ret;	}	/********************************************************	 All other V4L1 calls are handled by v4l1_compat module.	 Those calls will be translated into V4L2 calls, and	 __video_do_ioctl will be called again, with one or more	 V4L2 ioctls.	 ********************************************************/	if (_IOC_TYPE(cmd) == 'v' && _IOC_NR(cmd) < BASE_VIDIOCPRIVATE)		return v4l_compat_translate_ioctl(file, cmd, arg,						__video_do_ioctl);#endif	switch (cmd) {	/* --- capabilities ------------------------------------------ */	case VIDIOC_QUERYCAP:	{		struct v4l2_capability *cap = (struct v4l2_capability *)arg;		memset(cap, 0, sizeof(*cap));		if (!ops->vidioc_querycap)			break;		ret = ops->vidioc_querycap(file, fh, cap);		if (!ret)			dbgarg(cmd, "driver=%s, card=%s, bus=%s, "					"version=0x%08x, "					"capabilities=0x%08x\n",					cap->driver, cap->card, cap->bus_info,					cap->version,					cap->capabilities);		break;	}	/* --- priority ------------------------------------------ */	case VIDIOC_G_PRIORITY:	{		enum v4l2_priority *p = arg;		if (!ops->vidioc_g_priority)			break;		ret = ops->vidioc_g_priority(file, fh, p);		if (!ret)			dbgarg(cmd, "priority is %d\n", *p);		break;	}	case VIDIOC_S_PRIORITY:	{		enum v4l2_priority *p = arg;		if (!ops->vidioc_s_priority)			break;		dbgarg(cmd, "setting priority to %d\n", *p);		ret = ops->vidioc_s_priority(file, fh, *p);		break;	}	/* --- capture ioctls ---------------------------------------- */	case VIDIOC_ENUM_FMT:	{		struct v4l2_fmtdesc *f = arg;		enum v4l2_buf_type type;		unsigned int index;		index = f->index;		type  = f->type;		memset(f, 0, sizeof(*f));		f->index = index;		f->type  = type;		switch (type) {		case V4L2_BUF_TYPE_VIDEO_CAPTURE:			if (ops->vidioc_enum_fmt_vid_cap)				ret = ops->vidioc_enum_fmt_vid_cap(file, fh, f);			break;		case V4L2_BUF_TYPE_VIDEO_OVERLAY:			if (ops->vidioc_enum_fmt_vid_overlay)				ret = ops->vidioc_enum_fmt_vid_overlay(file,					fh, f);			break;		case V4L2_BUF_TYPE_VIDEO_OUTPUT:			if (ops->vidioc_enum_fmt_vid_out)				ret = ops->vidioc_enum_fmt_vid_out(file, fh, f);			break;		case V4L2_BUF_TYPE_PRIVATE:			if (ops->vidioc_enum_fmt_type_private)				ret = ops->vidioc_enum_fmt_type_private(file,								fh, f);			break;		default:			break;		}		if (!ret)			dbgarg(cmd, "index=%d, type=%d, flags=%d, "				"pixelformat=%c%c%c%c, description='%s'\n",				f->index, f->type, f->flags,				(f->pixelformat & 0xff),				(f->pixelformat >>  8) & 0xff,				(f->pixelformat >> 16) & 0xff,				(f->pixelformat >> 24) & 0xff,				f->description);		break;	}	case VIDIOC_G_FMT:	{		struct v4l2_format *f = (struct v4l2_format *)arg;		memset(f->fmt.raw_data, 0, sizeof(f->fmt.raw_data));		/* FIXME: Should be one dump per type */		dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names));		switch (f->type) {		case V4L2_BUF_TYPE_VIDEO_CAPTURE:			if (ops->vidioc_g_fmt_vid_cap)				ret = ops->vidioc_g_fmt_vid_cap(file, fh, f);			if (!ret)				v4l_print_pix_fmt(vfd, &f->fmt.pix);			break;		case V4L2_BUF_TYPE_VIDEO_OVERLAY:			if (ops->vidioc_g_fmt_vid_overlay)				ret = ops->vidioc_g_fmt_vid_overlay(file,								    fh, f);			break;		case V4L2_BUF_TYPE_VIDEO_OUTPUT:			if (ops->vidioc_g_fmt_vid_out)				ret = ops->vidioc_g_fmt_vid_out(file, fh, f);			if (!ret)				v4l_print_pix_fmt(vfd, &f->fmt.pix);			break;		case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:			if (ops->vidioc_g_fmt_vid_out_overlay)				ret = ops->vidioc_g_fmt_vid_out_overlay(file,				       fh, f);			break;		case V4L2_BUF_TYPE_VBI_CAPTURE:			if (ops->vidioc_g_fmt_vbi_cap)				ret = ops->vidioc_g_fmt_vbi_cap(file, fh, f);			break;		case V4L2_BUF_TYPE_VBI_OUTPUT:			if (ops->vidioc_g_fmt_vbi_out)				ret = ops->vidioc_g_fmt_vbi_out(file, fh, f);			break;		case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:			if (ops->vidioc_g_fmt_sliced_vbi_cap)				ret = ops->vidioc_g_fmt_sliced_vbi_cap(file,									fh, f);			break;		case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:			if (ops->vidioc_g_fmt_sliced_vbi_out)				ret = ops->vidioc_g_fmt_sliced_vbi_out(file,									fh, f);			break;		case V4L2_BUF_TYPE_PRIVATE:			if (ops->vidioc_g_fmt_type_private)				ret = ops->vidioc_g_fmt_type_private(file,								fh, f);			break;		}		break;	}	case VIDIOC_S_FMT:	{		struct v4l2_format *f = (struct v4l2_format *)arg;		/* FIXME: Should be one dump per type */		dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names));		switch (f->type) {		case V4L2_BUF_TYPE_VIDEO_CAPTURE:			v4l_print_pix_fmt(vfd, &f->fmt.pix);			if (ops->vidioc_s_fmt_vid_cap)				ret = ops->vidioc_s_fmt_vid_cap(file, fh, f);			break;		case V4L2_BUF_TYPE_VIDEO_OVERLAY:			if (ops->vidioc_s_fmt_vid_overlay)				ret = ops->vidioc_s_fmt_vid_overlay(file,								    fh, f);			break;		case V4L2_BUF_TYPE_VIDEO_OUTPUT:			v4l_print_pix_fmt(vfd, &f->fmt.pix);			if (ops->vidioc_s_fmt_vid_out)				ret = ops->vidioc_s_fmt_vid_out(file, fh, f);			break;		case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:			if (ops->vidioc_s_fmt_vid_out_overlay)				ret = ops->vidioc_s_fmt_vid_out_overlay(file,					fh, f);			break;		case V4L2_BUF_TYPE_VBI_CAPTURE:			if (ops->vidioc_s_fmt_vbi_cap)				ret = ops->vidioc_s_fmt_vbi_cap(file, fh, f);			break;		case V4L2_BUF_TYPE_VBI_OUTPUT:			if (ops->vidioc_s_fmt_vbi_out)				ret = ops->vidioc_s_fmt_vbi_out(file, fh, f);			break;		case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:			if (ops->vidioc_s_fmt_sliced_vbi_cap)				ret = ops->vidioc_s_fmt_sliced_vbi_cap(file,									fh, f);			break;		case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:			if (ops->vidioc_s_fmt_sliced_vbi_out)				ret = ops->vidioc_s_fmt_sliced_vbi_out(file,									fh, f);			break;		case V4L2_BUF_TYPE_PRIVATE:			if (ops->vidioc_s_fmt_type_private)				ret = ops->vidioc_s_fmt_type_private(file,								fh, f);			break;		}		break;	}	case VIDIOC_TRY_FMT:	{		struct v4l2_format *f = (struct v4l2_format *)arg;		/* FIXME: Should be one dump per type */		dbgarg(cmd, "type=%s\n", prt_names(f->type,						v4l2_type_names));		switch (f->type) {		case V4L2_BUF_TYPE_VIDEO_CAPTURE:			if (ops->vidioc_try_fmt_vid_cap)				ret = ops->vidioc_try_fmt_vid_cap(file, fh, f);			if (!ret)				v4l_print_pix_fmt(vfd, &f->fmt.pix);			break;		case V4L2_BUF_TYPE_VIDEO_OVERLAY:			if (ops->vidioc_try_fmt_vid_overlay)				ret = ops->vidioc_try_fmt_vid_overlay(file,					fh, f);			break;		case V4L2_BUF_TYPE_VIDEO_OUTPUT:			if (ops->vidioc_try_fmt_vid_out)				ret = ops->vidioc_try_fmt_vid_out(file, fh, f);			if (!ret)				v4l_print_pix_fmt(vfd, &f->fmt.pix);			break;		case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:			if (ops->vidioc_try_fmt_vid_out_overlay)				ret = ops->vidioc_try_fmt_vid_out_overlay(file,				       fh, f);			break;		case V4L2_BUF_TYPE_VBI_CAPTURE:			if (ops->vidioc_try_fmt_vbi_cap)				ret = ops->vidioc_try_fmt_vbi_cap(file, fh, f);			break;		case V4L2_BUF_TYPE_VBI_OUTPUT:			if (ops->vidioc_try_fmt_vbi_out)				ret = ops->vidioc_try_fmt_vbi_out(file, fh, f);			break;		case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:			if (ops->vidioc_try_fmt_sliced_vbi_cap)				ret = ops->vidioc_try_fmt_sliced_vbi_cap(file,								fh, f);			break;		case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:			if (ops->vidioc_try_fmt_sliced_vbi_out)				ret = ops->vidioc_try_fmt_sliced_vbi_out(file,								fh, f);			break;		case V4L2_BUF_TYPE_PRIVATE:			if (ops->vidioc_try_fmt_type_private)				ret = ops->vidioc_try_fmt_type_private(file,

⌨️ 快捷键说明

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