📄 v4l1-compat.c
字号:
/* * * Video for Linux Two * Backward Compatibility Layer * * Support subroutines for providing V4L2 drivers with backward * compatibility with applications using the old API. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Author: Bill Dirks <bill@thedirks.org> * et al. * */#include <linux/init.h>#include <linux/module.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/mm.h>#include <linux/fs.h>#include <linux/file.h>#include <linux/string.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/videodev.h>#include <media/v4l2-common.h>#include <media/v4l2-ioctl.h>#include <asm/uaccess.h>#include <asm/system.h>#include <asm/pgtable.h>#include "compat.h"static unsigned int debug;module_param(debug, int, 0644);MODULE_PARM_DESC(debug, "enable debug messages");MODULE_AUTHOR("Bill Dirks");MODULE_DESCRIPTION("v4l(1) compatibility layer for v4l2 drivers.");MODULE_LICENSE("GPL");#define dprintk(fmt, arg...) \ do { \ if (debug) \ printk(KERN_DEBUG "v4l1-compat: " fmt , ## arg);\ } while (0)/* * I O C T L T R A N S L A T I O N * * From here on down is the code for translating the numerous * ioctl commands from the old API to the new API. */static intget_v4l_control(struct file *file, int cid, v4l2_kioctl drv){ struct v4l2_queryctrl qctrl2; struct v4l2_control ctrl2; int err; qctrl2.id = cid; err = drv(file, VIDIOC_QUERYCTRL, &qctrl2); if (err < 0) dprintk("VIDIOC_QUERYCTRL: %d\n", err); if (err == 0 && !(qctrl2.flags & V4L2_CTRL_FLAG_DISABLED)) { ctrl2.id = qctrl2.id; err = drv(file, VIDIOC_G_CTRL, &ctrl2); if (err < 0) { dprintk("VIDIOC_G_CTRL: %d\n", err); return 0; } return ((ctrl2.value - qctrl2.minimum) * 65535 + (qctrl2.maximum - qctrl2.minimum) / 2) / (qctrl2.maximum - qctrl2.minimum); } return 0;}static intset_v4l_control(struct file *file, int cid, int value, v4l2_kioctl drv){ struct v4l2_queryctrl qctrl2; struct v4l2_control ctrl2; int err; qctrl2.id = cid; err = drv(file, VIDIOC_QUERYCTRL, &qctrl2); if (err < 0) dprintk("VIDIOC_QUERYCTRL: %d\n", err); if (err == 0 && !(qctrl2.flags & V4L2_CTRL_FLAG_DISABLED) && !(qctrl2.flags & V4L2_CTRL_FLAG_GRABBED)) { if (value < 0) value = 0; if (value > 65535) value = 65535; if (value && qctrl2.type == V4L2_CTRL_TYPE_BOOLEAN) value = 65535; ctrl2.id = qctrl2.id; ctrl2.value = (value * (qctrl2.maximum - qctrl2.minimum) + 32767) / 65535; ctrl2.value += qctrl2.minimum; err = drv(file, VIDIOC_S_CTRL, &ctrl2); if (err < 0) dprintk("VIDIOC_S_CTRL: %d\n", err); } return 0;}/* ----------------------------------------------------------------- */static const unsigned int palette2pixelformat[] = { [VIDEO_PALETTE_GREY] = V4L2_PIX_FMT_GREY, [VIDEO_PALETTE_RGB555] = V4L2_PIX_FMT_RGB555, [VIDEO_PALETTE_RGB565] = V4L2_PIX_FMT_RGB565, [VIDEO_PALETTE_RGB24] = V4L2_PIX_FMT_BGR24, [VIDEO_PALETTE_RGB32] = V4L2_PIX_FMT_BGR32, /* yuv packed pixel */ [VIDEO_PALETTE_YUYV] = V4L2_PIX_FMT_YUYV, [VIDEO_PALETTE_YUV422] = V4L2_PIX_FMT_YUYV, [VIDEO_PALETTE_UYVY] = V4L2_PIX_FMT_UYVY, /* yuv planar */ [VIDEO_PALETTE_YUV410P] = V4L2_PIX_FMT_YUV410, [VIDEO_PALETTE_YUV420] = V4L2_PIX_FMT_YUV420, [VIDEO_PALETTE_YUV420P] = V4L2_PIX_FMT_YUV420, [VIDEO_PALETTE_YUV411P] = V4L2_PIX_FMT_YUV411P, [VIDEO_PALETTE_YUV422P] = V4L2_PIX_FMT_YUV422P,};static unsigned int __purepalette_to_pixelformat(unsigned int palette){ if (palette < ARRAY_SIZE(palette2pixelformat)) return palette2pixelformat[palette]; else return 0;}static unsigned int __attribute_const__pixelformat_to_palette(unsigned int pixelformat){ int palette = 0; switch (pixelformat) { case V4L2_PIX_FMT_GREY: palette = VIDEO_PALETTE_GREY; break; case V4L2_PIX_FMT_RGB555: palette = VIDEO_PALETTE_RGB555; break; case V4L2_PIX_FMT_RGB565: palette = VIDEO_PALETTE_RGB565; break; case V4L2_PIX_FMT_BGR24: palette = VIDEO_PALETTE_RGB24; break; case V4L2_PIX_FMT_BGR32: palette = VIDEO_PALETTE_RGB32; break; /* yuv packed pixel */ case V4L2_PIX_FMT_YUYV: palette = VIDEO_PALETTE_YUYV; break; case V4L2_PIX_FMT_UYVY: palette = VIDEO_PALETTE_UYVY; break; /* yuv planar */ case V4L2_PIX_FMT_YUV410: palette = VIDEO_PALETTE_YUV420; break; case V4L2_PIX_FMT_YUV420: palette = VIDEO_PALETTE_YUV420; break; case V4L2_PIX_FMT_YUV411P: palette = VIDEO_PALETTE_YUV411P; break; case V4L2_PIX_FMT_YUV422P: palette = VIDEO_PALETTE_YUV422P; break; } return palette;}/* ----------------------------------------------------------------- */static int poll_one(struct file *file, struct poll_wqueues *pwq){ int retval = 1; poll_table *table; poll_initwait(pwq); table = &pwq->pt; for (;;) { int mask; set_current_state(TASK_INTERRUPTIBLE); mask = file->f_op->poll(file, table); if (mask & POLLIN) break; table = NULL; if (signal_pending(current)) { retval = -ERESTARTSYS; break; } schedule(); } set_current_state(TASK_RUNNING); poll_freewait(pwq); return retval;}static int count_inputs( struct file *file, v4l2_kioctl drv){ struct v4l2_input input2; int i; for (i = 0;; i++) { memset(&input2, 0, sizeof(input2)); input2.index = i; if (0 != drv(file, VIDIOC_ENUMINPUT, &input2)) break; } return i;}static int check_size( struct file *file, v4l2_kioctl drv, int *maxw, int *maxh){ struct v4l2_fmtdesc desc2; struct v4l2_format fmt2; memset(&desc2, 0, sizeof(desc2)); memset(&fmt2, 0, sizeof(fmt2)); desc2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (0 != drv(file, VIDIOC_ENUM_FMT, &desc2)) goto done; fmt2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt2.fmt.pix.width = 10000; fmt2.fmt.pix.height = 10000; fmt2.fmt.pix.pixelformat = desc2.pixelformat; if (0 != drv(file, VIDIOC_TRY_FMT, &fmt2)) goto done; *maxw = fmt2.fmt.pix.width; *maxh = fmt2.fmt.pix.height;done: return 0;}/* ----------------------------------------------------------------- */static noinline int v4l1_compat_get_capabilities( struct video_capability *cap, struct file *file, v4l2_kioctl drv){ int err; struct v4l2_framebuffer fbuf; struct v4l2_capability *cap2; cap2 = kzalloc(sizeof(*cap2), GFP_KERNEL); if (!cap2) { err = -ENOMEM; return err; } memset(cap, 0, sizeof(*cap)); memset(&fbuf, 0, sizeof(fbuf)); err = drv(file, VIDIOC_QUERYCAP, cap2); if (err < 0) { dprintk("VIDIOCGCAP / VIDIOC_QUERYCAP: %d\n", err); goto done; } if (cap2->capabilities & V4L2_CAP_VIDEO_OVERLAY) { err = drv(file, VIDIOC_G_FBUF, &fbuf); if (err < 0) { dprintk("VIDIOCGCAP / VIDIOC_G_FBUF: %d\n", err); memset(&fbuf, 0, sizeof(fbuf)); } err = 0; } memcpy(cap->name, cap2->card, min(sizeof(cap->name), sizeof(cap2->card))); cap->name[sizeof(cap->name) - 1] = 0; if (cap2->capabilities & V4L2_CAP_VIDEO_CAPTURE) cap->type |= VID_TYPE_CAPTURE; if (cap2->capabilities & V4L2_CAP_TUNER) cap->type |= VID_TYPE_TUNER; if (cap2->capabilities & V4L2_CAP_VBI_CAPTURE) cap->type |= VID_TYPE_TELETEXT; if (cap2->capabilities & V4L2_CAP_VIDEO_OVERLAY) cap->type |= VID_TYPE_OVERLAY; if (fbuf.capability & V4L2_FBUF_CAP_LIST_CLIPPING) cap->type |= VID_TYPE_CLIPPING; cap->channels = count_inputs(file, drv); check_size(file, drv, &cap->maxwidth, &cap->maxheight); cap->audios = 0; /* FIXME */ cap->minwidth = 48; /* FIXME */ cap->minheight = 32; /* FIXME */done: kfree(cap2); return err;}static noinline int v4l1_compat_get_frame_buffer( struct video_buffer *buffer, struct file *file, v4l2_kioctl drv){ int err; struct v4l2_framebuffer fbuf; memset(buffer, 0, sizeof(*buffer)); memset(&fbuf, 0, sizeof(fbuf)); err = drv(file, VIDIOC_G_FBUF, &fbuf); if (err < 0) { dprintk("VIDIOCGFBUF / VIDIOC_G_FBUF: %d\n", err); goto done; } buffer->base = fbuf.base; buffer->height = fbuf.fmt.height; buffer->width = fbuf.fmt.width; switch (fbuf.fmt.pixelformat) { case V4L2_PIX_FMT_RGB332: buffer->depth = 8; break; case V4L2_PIX_FMT_RGB555: buffer->depth = 15; break; case V4L2_PIX_FMT_RGB565: buffer->depth = 16; break; case V4L2_PIX_FMT_BGR24: buffer->depth = 24; break; case V4L2_PIX_FMT_BGR32: buffer->depth = 32; break; default: buffer->depth = 0; } if (fbuf.fmt.bytesperline) { buffer->bytesperline = fbuf.fmt.bytesperline; if (!buffer->depth && buffer->width) buffer->depth = ((fbuf.fmt.bytesperline<<3) + (buffer->width-1)) / buffer->width; } else { buffer->bytesperline = (buffer->width * buffer->depth + 7) & 7; buffer->bytesperline >>= 3; }done: return err;}static noinline int v4l1_compat_set_frame_buffer( struct video_buffer *buffer, struct file *file, v4l2_kioctl drv){ int err; struct v4l2_framebuffer fbuf; memset(&fbuf, 0, sizeof(fbuf)); fbuf.base = buffer->base; fbuf.fmt.height = buffer->height; fbuf.fmt.width = buffer->width; switch (buffer->depth) { case 8: fbuf.fmt.pixelformat = V4L2_PIX_FMT_RGB332; break; case 15: fbuf.fmt.pixelformat = V4L2_PIX_FMT_RGB555; break; case 16: fbuf.fmt.pixelformat = V4L2_PIX_FMT_RGB565; break; case 24: fbuf.fmt.pixelformat = V4L2_PIX_FMT_BGR24; break; case 32: fbuf.fmt.pixelformat = V4L2_PIX_FMT_BGR32; break; } fbuf.fmt.bytesperline = buffer->bytesperline; err = drv(file, VIDIOC_S_FBUF, &fbuf); if (err < 0) dprintk("VIDIOCSFBUF / VIDIOC_S_FBUF: %d\n", err); return err;}static noinline int v4l1_compat_get_win_cap_dimensions( struct video_window *win, struct file *file, v4l2_kioctl drv){ int err; struct v4l2_format *fmt; fmt = kzalloc(sizeof(*fmt), GFP_KERNEL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -