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 + -
显示快捷键?