videodev.c
上传用户:aoeyumen
上传日期:2007-01-06
资源大小:3329k
文件大小:49k
- /*
- * Video for Linux Two
- *
- * A generic video device interface for the LINUX operating system
- * using a set of device structures/vectors for low level operations.
- *
- * This file replaces the videodev.c file that comes with the
- * regular kernel distribution.
- *
- * 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 <bdirks@pacbell.net>
- * based on code by Alan Cox, <alan@cymru.net>
- *
- * gcc -c -O2 -Wall -DMODULE videodev.c
- */
- #ifndef __KERNEL__
- #define __KERNEL__
- #endif
- #include <linux/config.h>
- #ifndef EXPORT_SYMTAB
- #define EXPORT_SYMTAB
- #endif
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
- #include <linux/sched.h>
- #include <linux/mm.h>
- #include <linux/poll.h>
- #include <linux/string.h>
- #include <linux/errno.h>
- #include <linux/videodev2.h>
- #include <linux/proc_fs.h>
- #include <asm/uaccess.h>
- #include <asm/system.h>
- #include <asm/pgtable.h>
- #include <asm/io.h>
- #ifdef CONFIG_KMOD
- #include <linux/kmod.h>
- #endif
- #ifndef min
- #define min(a,b) (((a)<(b))?(a):(b))
- #endif
- static int v4l2_major = 81;
- MODULE_PARM(v4l2_major, "i");
- #define V4L2_NUM_DEVICES 256
- /*
- * Active devices
- */
- static struct v4l2_device *v4l2_device[V4L2_NUM_DEVICES];
- static struct v4l2_clock *masterclock;
- /*
- * D E V I C E O P E R A T I O N S
- *
- */
- /*
- * Open a video device.
- */
- static int
- video_open(struct inode *inode, struct file *file)
- {
- unsigned int minor = MINOR(inode->i_rdev);
- struct v4l2_device *vfl;
- int err;
- if (minor >= V4L2_NUM_DEVICES)
- return -ENODEV;
- vfl = v4l2_device[minor];
- if (vfl == NULL)
- {
- #ifdef CONFIG_KMOD /* KMOD code by Erik Walthinsen */
- char modname[20];
- sprintf(modname, "char-major-%d-%d", v4l2_major, minor);
- request_module(modname);
- vfl = v4l2_device[minor];
- if (vfl == NULL)
- #endif
- return -ENODEV;
- }
- if (vfl->open == NULL)
- return -ENODEV;
- err = vfl->open(vfl, file->f_flags, &file->private_data);
- if (err == 0 && file->private_data == NULL)
- {
- printk(KERN_ERR"V4L2: Device returned NULL open idn");
- err = -ENODEV;
- }
- if (err == 0)
- ++vfl->busy;
- return err;
- }
- /*
- * Last close of a struct file
- */
- static int
- video_release(struct inode *inode, struct file *file)
- {
- struct v4l2_device *vfl = v4l2_device[MINOR(inode->i_rdev)];
- if (vfl->close)
- vfl->close(file->private_data);
- file->private_data = NULL;
- if (vfl->busy)
- --vfl->busy;
- return 0;
- }
- /*
- * Read from a video device
- */
- static ssize_t
- video_read(struct file *file,
- char *buf, size_t count, loff_t *ppos)
- {
- struct v4l2_device *vfl =
- v4l2_device[MINOR(file->f_dentry->d_inode->i_rdev)];
- if (vfl->read)
- return vfl->read(file->private_data, buf, count,
- file->f_flags & O_NONBLOCK);
- return -EINVAL;
- }
- /*
- * Write to a video device
- */
- static ssize_t
- video_write(struct file *file,
- const char *buf, size_t count, loff_t *ppos)
- {
- struct v4l2_device *vfl =
- v4l2_device[MINOR(file->f_dentry->d_inode->i_rdev)];
- if (vfl->write)
- return vfl->write(file->private_data, buf, count,
- file->f_flags & O_NONBLOCK);
- return 0;
- }
- /*
- * IO Control
- */
- static void
- fill_ctrl_category(struct v4l2_queryctrl *qc);
- static int
- translate_ioctl(struct file *file,
- struct v4l2_device *vfl,
- void *per_open_data,
- int cmd,
- void *arg);
- static int
- video_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
- {
- struct v4l2_device *vfl = v4l2_device[MINOR(inode->i_rdev)];
- char targ[V4L2_MAX_IOCTL_SIZE];
- void *parg = (void *)arg;
- int err = -EINVAL;
- if (vfl->ioctl == NULL)
- return -EINVAL;
- /* Copy arguments into temp kernel buffer */
- switch (_IOC_DIR(cmd))
- {
- case _IOC_NONE:
- parg = (void *)arg;
- break;
- case _IOC_WRITE:
- case (_IOC_WRITE | _IOC_READ):
- if (_IOC_SIZE(cmd) > sizeof(targ))
- {
- printk(KERN_ERR"V4L2: ioctl 0x%08x arguments are "
- "too big, > %dn", cmd, sizeof(targ));
- break;/* Arguments are too big. */
- }
- if (copy_from_user(targ, (void *)arg, _IOC_SIZE(cmd)))
- {
- printk(KERN_INFO"V4L2: Fault on write ioctl 0x%08x "
- "copying data from user buffern", cmd);
- return -EFAULT;
- }
- parg = targ;
- break;
- case _IOC_READ:
- parg = targ;
- break;
- }
- /* Fill in the category for pre-defined controls */
- if (cmd == VIDIOC_QUERYCTRL)
- fill_ctrl_category((struct v4l2_queryctrl *)parg);
- /* Try passing it to the driver first */
- err = vfl->ioctl(file->private_data, cmd, parg);
- /* If the driver doesn't recognize it and it's an old ioctl,
- pass it through the translation layer. */
- if (err == -ENOIOCTLCMD && _IOC_TYPE(cmd) == 'v')
- {
- err = translate_ioctl(file, vfl, file->private_data,
- cmd, parg);
- }
- /* Copy results into user buffer */
- switch (_IOC_DIR(cmd))
- {
- case _IOC_READ:
- case (_IOC_WRITE | _IOC_READ):
- if (parg == targ &&
- copy_to_user((void *)arg, parg, _IOC_SIZE(cmd)))
- {
- printk(KERN_INFO"V4L2: Fault on read ioctl 0x%08x "
- "copying results to user buffern", cmd);
- return -EFAULT;
- }
- break;
- }
- if (err != -ENOIOCTLCMD)
- return err;
- /* Handle ioctls not recognized by the driver */
- return -EINVAL;
- }
- /*
- * Memory mapping
- */
- static int
- video_mmap(struct file *file, struct vm_area_struct *vma)
- {
- struct v4l2_device *vfl =
- v4l2_device[MINOR(file->f_dentry->d_inode->i_rdev)];
- int err;
- if (vfl->mmap)
- {
- vma->vm_file = file;
- /* For v4l compatibility. v4l apps typically pass zero */
- /* for the offset, so replace it with the real value */
- /* saved from before */
- if (vma->vm_offset == 0 && vfl->ioctl)
- {
- struct v4l2_buffer buf;
- buf.index = 0;
- buf.type = V4L2_BUF_TYPE_CAPTURE;
- if (vfl->ioctl(file->private_data,
- VIDIOC_QUERYBUF, &buf) == 0)
- vma->vm_offset = buf.offset;
- }
- err = vfl->mmap(file->private_data, vma);
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,3)
- /* This is now done in the kernel, as it should be */
- if (err == 0 && vma->vm_file != NULL)
- ++vma->vm_file->f_count;
- #endif
- return err;
- }
- return -ENODEV;
- }
- /*
- * Poll (select()) support
- */
- static unsigned int
- video_poll(struct file *file, poll_table *table)
- {
- struct v4l2_device *vfl =
- v4l2_device[MINOR(file->f_dentry->d_inode->i_rdev)];
- if (vfl->poll)
- return vfl->poll(file->private_data, file, table);
- return POLLERR;
- }
- /*
- * Not used.
- */
- static long long
- video_lseek(struct file *file,
- long long offset, int origin)
- {
- return -ESPIPE;
- }
- /*
- * CONTROL CATEGORIES
- */
- static void
- fill_ctrl_category(struct v4l2_queryctrl *qc)
- {
- if ((qc->id >= V4L2_CID_BRIGHTNESS &&
- qc->id <= V4L2_CID_HUE) ||
- (qc->id >= V4L2_CID_BLACK_LEVEL &&
- qc->id <= V4L2_CID_LASTP1-1))
- {
- qc->category = V4L2_CTRL_CAT_VIDEO;
- strcpy(qc->catname, "Video");
- }
- if ((qc->id >= V4L2_CID_AUDIO_VOLUME &&
- qc->id <= V4L2_CID_AUDIO_LOUDNESS))
- {
- qc->category = V4L2_CTRL_CAT_AUDIO;
- strcpy(qc->catname, "Audio");
- }
- if ((qc->id >= V4L2_CID_EFFECT_BASE &&
- qc->id <= V4L2_CID_EFFECT_BASE + 10000))
- {
- qc->category = V4L2_CTRL_CAT_EFFECT;
- strcpy(qc->catname, "Effect");
- }
- strcpy(qc->catname, "Private");
- }
- /*
- * B A C K W A R D C O M P A T I B I L I T Y
- *
- * This code allows applications written for the original API to
- * work with drivers that only understand the new API.
- */
- static int
- get_v4l_control(struct v4l2_device *vfl,
- void *context,
- int cid)
- {
- struct v4l2_queryctrl qctrl2;
- struct v4l2_control ctrl2;
- int err;
- qctrl2.id = cid;
- err = vfl->ioctl(context, VIDIOC_QUERYCTRL, &qctrl2);
- if (err == 0)
- {
- ctrl2.id = qctrl2.id;
- vfl->ioctl(context, VIDIOC_G_CTRL, &ctrl2);
- return ((ctrl2.value - qctrl2.minimum) * 65535
- + (qctrl2.maximum - qctrl2.minimum) / 2)
- / (qctrl2.maximum - qctrl2.minimum);
- }
- return 0;
- }
- static int
- set_v4l_control(struct v4l2_device *vfl,
- void *context,
- int cid,
- int value)
- {
- struct v4l2_queryctrl qctrl2;
- struct v4l2_control ctrl2;
- int err;
- qctrl2.id = cid;
- err = vfl->ioctl(context, VIDIOC_QUERYCTRL, &qctrl2);
- if (err == 0)
- {
- if (value < 0)
- value = 0;
- if (value > 65535)
- value = 65535;
- ctrl2.id = qctrl2.id;
- ctrl2.value =
- (value * (qctrl2.maximum - qctrl2.minimum)
- + 32767)
- / 65535;
- vfl->ioctl(context, VIDIOC_S_CTRL, &ctrl2);
- }
- return 0;
- }
- static int
- find_tuner(struct v4l2_device *vfl,
- void *context,
- int n)
- {
- struct v4l2_input inp2;
- int i;
- int err;
- /* Find the input number of the n'th tuner */
- for (i = 0; i < 100/*arbitrary*/; ++i)
- {
- inp2.index = i;
- err = vfl->ioctl(context, VIDIOC_ENUMINPUT, &inp2);
- if (err < 0)
- break;
- if (inp2.type != V4L2_INPUT_TYPE_TUNER)
- continue;
- if (n == 0)
- break;
- --n;
- }
- if (err < 0)
- return err;
- return i;
- }
- static int
- palette_to_pixelformat(int palette)
- {
- int pixelformat = 0;
- switch (palette)
- {
- case VIDEO_PALETTE_GREY:
- pixelformat = V4L2_PIX_FMT_GREY;
- break;
- case VIDEO_PALETTE_RGB555:
- pixelformat = V4L2_PIX_FMT_RGB555;
- break;
- case VIDEO_PALETTE_RGB565:
- pixelformat = V4L2_PIX_FMT_RGB565;
- break;
- case VIDEO_PALETTE_RGB24:
- pixelformat = V4L2_PIX_FMT_BGR24;
- break;
- case VIDEO_PALETTE_RGB32:
- pixelformat = V4L2_PIX_FMT_BGR32;
- break;
- case VIDEO_PALETTE_YUYV:
- case VIDEO_PALETTE_YUV422:
- pixelformat = V4L2_PIX_FMT_YUYV;
- break;
- case VIDEO_PALETTE_UYVY:
- pixelformat = V4L2_PIX_FMT_UYVY;
- break;
- case VIDEO_PALETTE_YUV420:
- pixelformat = V4L2_PIX_FMT_YUV420;
- break;
- case VIDEO_PALETTE_YUV422P:
- pixelformat = V4L2_PIX_FMT_YVU422P;
- break;
- case VIDEO_PALETTE_YUV411P:
- pixelformat = V4L2_PIX_FMT_YVU411P;
- break;
- }
- return pixelformat;
- }
- static int
- pixelformat_to_palette(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;
- case V4L2_PIX_FMT_YUYV:
- palette = VIDEO_PALETTE_YUYV;
- break;
- case V4L2_PIX_FMT_UYVY:
- palette = VIDEO_PALETTE_UYVY;
- break;
- case V4L2_PIX_FMT_YUV420:
- palette = VIDEO_PALETTE_YUV420;
- break;
- case V4L2_PIX_FMT_YVU422P:
- palette = VIDEO_PALETTE_YUV422P;
- break;
- case V4L2_PIX_FMT_YVU411P:
- palette = VIDEO_PALETTE_YUV411P;
- break;
- }
- return palette;
- }
- /* Do an 'in' (wait for input) select on a single file descriptor */
- /* This stuff plaigarized from linux/fs/select.c */
- #define __FD_IN(fds, n) (fds->in + n)
- #define BIT(i) (1UL << ((i)&(__NFDBITS-1)))
- #define SET(i,m) (*(m) |= (i))
- #ifndef HAVE_DO_SELECT
- /* Note: This code, inside the #ifndef HAVE_DO_SELECT ... #endif,
- is copied from fs/select.c, and is only included
- here because do_select() is not exported to modules. In the future
- export do_select() to modules and delete this code down to the
- #endif. Thank you.
- */
- #include <linux/smp_lock.h>
- #include <linux/file.h>
- #define BITS(fds, n) (*__FD_IN(fds, n))
- #define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)
- #define POLLIN_SET (POLLRDNORM | POLLRDBAND | POLLIN | POLLHUP | POLLERR)
- #define ISSET(i,m) (((i)&*(m)) != 0)
- static void free_wait(poll_table * p)
- {
- struct poll_table_entry * entry;
- poll_table *old;
- while (p) {
- entry = p->entry + p->nr;
- while (p->nr > 0) {
- p->nr--;
- entry--;
- remove_wait_queue(entry->wait_address,&entry->wait);
- fput(entry->filp);
- }
- old = p;
- p = p->next;
- free_page((unsigned long) old);
- }
- }
- static int
- my_do_select(int n, fd_set_bits *fds, long *timeout)
- {
- poll_table *wait_table, *wait;
- int retval, i, off;
- long __timeout = *timeout;
- wait = wait_table = NULL;
- if (__timeout) {
- wait_table = (poll_table *) __get_free_page(GFP_KERNEL);
- if (!wait_table)
- return -ENOMEM;
- wait_table->nr = 0;
- wait_table->entry = (struct poll_table_entry *)(wait_table + 1);
- wait_table->next = NULL;
- wait = wait_table;
- }
- lock_kernel();
- // retval = max_select_fd(n, fds);
- //if (retval < 0)
- // goto out;
- //n = retval;
- retval = 0;
- for (;;) {
- current->state = TASK_INTERRUPTIBLE;
- for (i = 0 ; i < n; i++) {
- unsigned long bit = BIT(i);
- unsigned long mask;
- struct file *file;
- off = i / __NFDBITS;
- if (!(bit & BITS(fds, off)))
- continue;
- /*
- * The poll_wait routine will increment f_count if
- * the file is added to the wait table, so we don't
- * need to increment it now.
- */
- file = fcheck(i);
- mask = POLLNVAL;
- if (file) {
- mask = DEFAULT_POLLMASK;
- if (file->f_op && file->f_op->poll)
- mask = file->f_op->poll(file, wait);
- }
- if ((mask & POLLIN_SET) && ISSET(bit, __FD_IN(fds,off))) {
- retval++;
- wait = NULL;
- }
- }
- wait = NULL;
- if (retval || !__timeout || signal_pending(current))
- break;
- __timeout = schedule_timeout(__timeout);
- }
- current->state = TASK_RUNNING;
- //out:
- if (*timeout)
- free_wait(wait_table);
- /*
- * Up-to-date the caller timeout.
- */
- *timeout = __timeout;
- unlock_kernel();
- return retval;
- }
- #endif // HAVE_DO_SELECT
- static int
- simple_select(struct file *file)
- {
- fd_set_bits fds;
- char *bits;
- long timeout;
- int i, fd, n, ret, size;
- for (i = 0; i < current->files->max_fds; ++i)
- if (file == current->files->fd[i])
- break;
- if (i == current->files->max_fds)
- return -EINVAL;
- fd = i;
- n = fd + 1;
- timeout = MAX_SCHEDULE_TIMEOUT;
- /*
- * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
- * since we used fdset we need to allocate memory in units of
- * long-words.
- */
- ret = -ENOMEM;
- size = FDS_BYTES(n);
- bits = kmalloc(6 * size, GFP_KERNEL);
- if (!bits)
- goto out_nofds;
- fds.in = (unsigned long *) bits;
- fds.out = (unsigned long *) (bits + size);
- fds.ex = (unsigned long *) (bits + 2*size);
- fds.res_in = (unsigned long *) (bits + 3*size);
- fds.res_out = (unsigned long *) (bits + 4*size);
- fds.res_ex = (unsigned long *) (bits + 5*size);
- /* All zero except our one file descriptor bit, for input */
- memset(bits, 0, 6 * size);
- SET(BIT(fd), __FD_IN((&fds), fd / __NFDBITS));
- ret = my_do_select(n, &fds, &timeout);
- if (ret < 0)
- goto out;
- if (!ret) {
- ret = -ERESTARTNOHAND;
- if (signal_pending(current))
- goto out;
- ret = 0;
- }
- out:
- kfree(bits);
- out_nofds:
- return ret;
- }
- extern int make_my_day(void);
- static int
- translate_ioctl(struct file *file,
- struct v4l2_device *vfl,
- void *context,
- int cmd,
- void *arg)
- {
- int err = -ENOIOCTLCMD;
- switch (cmd)
- {
- case VIDIOCGCAP: /* capability */
- {
- struct video_capability *cap = arg;
- struct v4l2_capability cap2;
- struct v4l2_framebuffer fbuf2;
- err = vfl->ioctl(context, VIDIOC_QUERYCAP, &cap2);
- if (err < 0)
- break;
- if (cap2.flags & V4L2_FLAG_PREVIEW)
- {
- err = vfl->ioctl(context, VIDIOC_G_FBUF, &fbuf2);
- if (err < 0)
- memset(&fbuf2, 0, sizeof(fbuf2));
- err = 0;
- }
- memset(cap, 0, sizeof(cap));
- memcpy(cap->name, cap2.name,
- min(sizeof(cap->name), sizeof(cap2.name)));
- cap->name[sizeof(cap->name) - 1] = 0;
- if (cap2.type == V4L2_TYPE_CAPTURE)
- cap->type = VID_TYPE_CAPTURE;
- if (cap2.flags & V4L2_FLAG_TUNER)
- cap->type |= VID_TYPE_TUNER;
- if (cap2.flags & V4L2_FLAG_DATA_SERVICE)
- cap->type |= VID_TYPE_TELETEXT;
- if (cap2.flags & V4L2_FLAG_PREVIEW)
- cap->type |= VID_TYPE_OVERLAY;
- if (cap2.flags & V4L2_FLAG_MONOCHROME)
- cap->type |= VID_TYPE_MONOCHROME;
- if (fbuf2.flags & V4L2_FBUF_FLAG_PRIMARY)
- cap->type |= VID_TYPE_FRAMERAM;
- if (fbuf2.capability & V4L2_FBUF_CAP_CHROMAKEY)
- cap->type |= VID_TYPE_CHROMAKEY;
- if (fbuf2.capability & V4L2_FBUF_CAP_CLIPPING)
- cap->type |= VID_TYPE_CLIPPING;
- if (fbuf2.capability & V4L2_FBUF_CAP_SCALEUP ||
- fbuf2.capability & V4L2_FBUF_CAP_SCALEDOWN)
- cap->type |= VID_TYPE_SCALES;
- cap->channels = cap2.inputs;
- cap->audios = cap2.audios;
- cap->maxwidth = cap2.maxwidth;
- cap->maxheight = cap2.maxheight;
- cap->minwidth = cap2.minwidth;
- cap->minheight = cap2.minheight;
- break;
- }
- case VIDIOCGFBUF: /* get frame buffer */
- {
- struct video_buffer *buffer = arg;
- struct v4l2_framebuffer fbuf2;
- err = vfl->ioctl(context, VIDIOC_G_FBUF, &fbuf2);
- if (err < 0)
- break;
- buffer->base = fbuf2.base[0];
- buffer->height = fbuf2.fmt.height;
- buffer->width = fbuf2.fmt.width;
- buffer->depth = fbuf2.fmt.depth;
- if (fbuf2.fmt.flags & V4L2_FMT_FLAG_BYTESPERLINE)
- buffer->bytesperline = fbuf2.fmt.bytesperline;
- else
- {
- buffer->bytesperline =
- (fbuf2.fmt.width * fbuf2.fmt.depth + 7) & 7;
- buffer->bytesperline >>= 3;
- }
- if (fbuf2.fmt.pixelformat == V4L2_PIX_FMT_RGB555)
- buffer->depth = 15;
- break;
- }
- case VIDIOCSFBUF: /* set frame buffer */
- {
- struct video_buffer *buffer = arg;
- struct v4l2_framebuffer fbuf2;
- memset(&fbuf2, 0, sizeof(fbuf2));
- fbuf2.base[0] = buffer->base;
- fbuf2.fmt.height = buffer->height;
- fbuf2.fmt.width = buffer->width;
- fbuf2.fmt.depth = buffer->depth;
- switch (fbuf2.fmt.depth)
- {
- case 8:
- fbuf2.fmt.pixelformat = V4L2_PIX_FMT_RGB332;
- break;
- case 15:
- fbuf2.fmt.depth = 16;
- fbuf2.fmt.pixelformat = V4L2_PIX_FMT_RGB555;
- break;
- case 16:
- fbuf2.fmt.pixelformat = V4L2_PIX_FMT_RGB565;
- break;
- case 24:
- fbuf2.fmt.pixelformat = V4L2_PIX_FMT_BGR24;
- break;
- case 32:
- fbuf2.fmt.pixelformat = V4L2_PIX_FMT_BGR32;
- break;
- }
- fbuf2.fmt.flags |= V4L2_FMT_FLAG_BYTESPERLINE;
- fbuf2.fmt.bytesperline = buffer->bytesperline;
- fbuf2.flags = V4L2_FBUF_FLAG_PRIMARY;
- err = vfl->ioctl(context, VIDIOC_S_FBUF, &fbuf2);
- break;
- }
- case VIDIOCGWIN: /* get window or capture dimensions */
- {
- struct video_window *win = arg;
- struct v4l2_window win2;
- struct v4l2_format fmt2;
- err = vfl->ioctl(context, VIDIOC_G_WIN, &win2);
- if (err == 0)
- {
- win->x = win2.x;
- win->y = win2.y;
- win->width = win2.width;
- win->height = win2.height;
- win->chromakey = win2.chromakey;
- win->clips = NULL;
- win->clipcount = 0;
- break;
- }
- err = vfl->ioctl(context, VIDIOC_G_FMT, &fmt2);
- if (err < 0)
- break;
- win->x = 0;
- win->y = 0;
- win->width = fmt2.width;
- win->height = fmt2.height;
- win->chromakey = 0;
- win->clips = NULL;
- win->clipcount = 0;
- break;
- }
- case VIDIOCSWIN: /* set window and/or capture dimensions */
- {
- struct video_window *win = arg;
- struct v4l2_window win2;
- struct v4l2_format fmt2;
- err = vfl->ioctl(context, VIDIOC_G_FMT, &fmt2);
- if (err == 0)
- {
- fmt2.width = win->width;
- fmt2.height = win->height;
- err = vfl->ioctl(context, VIDIOC_S_FMT, &fmt2);
- win->width = fmt2.width;
- win->height = fmt2.height;
- }
- win2.x = win->x;
- win2.y = win->y;
- win2.width = win->width;
- win2.height = win->height;
- win2.chromakey = win->chromakey;
- win2.clips = (void *)win->clips;
- win2.clipcount = win->clipcount;
- vfl->ioctl(context, VIDIOC_S_WIN, &win2);
- break;
- }
- case VIDIOCCAPTURE: /* turn on/off preview */
- {
- err = vfl->ioctl(context, VIDIOC_PREVIEW, arg);
- break;
- }
- case VIDIOCGCHAN: /* get input information */
- {
- struct video_channel *chan = arg;
- struct v4l2_input input2;
- struct v4l2_standard std2;
- int sid;
- input2.index = chan->channel;
- err = vfl->ioctl(context, VIDIOC_ENUMINPUT, &input2);
- if (err < 0)
- break;
- chan->channel = input2.index;
- memcpy(chan->name, input2.name,
- min(sizeof(chan->name), sizeof(input2.name)));
- chan->name[sizeof(chan->name) - 1] = 0;
- chan->tuners = (input2.type == V4L2_INPUT_TYPE_TUNER) ? 1 : 0;
- chan->flags = (chan->tuners) ? VIDEO_VC_TUNER : 0;
- if (input2.capability & V4L2_INPUT_CAP_AUDIO)
- chan->flags |= VIDEO_VC_AUDIO;
- switch (input2.type)
- {
- case V4L2_INPUT_TYPE_TUNER:
- chan->type = VIDEO_TYPE_TV;
- break;
- default:
- case V4L2_INPUT_TYPE_CAMERA:
- chan->type = VIDEO_TYPE_CAMERA;
- break;
- }
- chan->norm = 0;
- err = vfl->ioctl(context, VIDIOC_G_STD, &std2);
- if (err == 0)
- {
- sid = v4l2_video_std_confirm(&std2);
- switch (sid)
- {
- case V4L2_STD_NTSC:
- chan->norm = VIDEO_MODE_NTSC;
- break;
- case V4L2_STD_PAL:
- chan->norm = VIDEO_MODE_PAL;
- break;
- case V4L2_STD_SECAM:
- chan->norm = VIDEO_MODE_SECAM;
- break;
- }
- }
- break;
- }
- case VIDIOCSCHAN: /* set input */
- {
- err = vfl->ioctl(context, VIDIOC_S_INPUT,
- (void *)(*(int *)arg));
- break;
- }
- case VIDIOCGPICT: /* get tone controls & partial capture format */
- {
- struct video_picture *pict = arg;
- struct v4l2_format fmt2;
- pict->brightness = get_v4l_control(vfl, context,
- V4L2_CID_BRIGHTNESS);
- pict->hue = get_v4l_control(vfl, context,
- V4L2_CID_HUE);
- pict->contrast = get_v4l_control(vfl, context,
- V4L2_CID_CONTRAST);
- pict->colour = get_v4l_control(vfl, context,
- V4L2_CID_SATURATION);
- pict->whiteness = get_v4l_control(vfl, context,
- V4L2_CID_WHITENESS);
- err = vfl->ioctl(context, VIDIOC_G_FMT, &fmt2);
- if (err < 0)
- break;
- pict->depth = fmt2.depth;
- pict->palette = pixelformat_to_palette(fmt2.pixelformat);
- if (pict->palette == VIDEO_PALETTE_RGB555)
- pict->depth = 15;
- break;
- }
- case VIDIOCSPICT: /* set tone controls & partial capture format */
- {
- struct video_picture *pict = arg;
- struct v4l2_format fmt2;
- set_v4l_control(vfl, context,
- V4L2_CID_BRIGHTNESS, pict->brightness);
- set_v4l_control(vfl, context,
- V4L2_CID_HUE, pict->hue);
- set_v4l_control(vfl, context,
- V4L2_CID_CONTRAST, pict->contrast);
- set_v4l_control(vfl, context,
- V4L2_CID_SATURATION, pict->colour);
- set_v4l_control(vfl, context,
- V4L2_CID_WHITENESS, pict->whiteness);
- err = 0;
- vfl->ioctl(context, VIDIOC_G_FMT, &fmt2);
- if (fmt2.pixelformat != palette_to_pixelformat(pict->palette))
- {
- fmt2.pixelformat = palette_to_pixelformat(
- pict->palette);
- err = vfl->ioctl(context, VIDIOC_S_FMT, &fmt2);
- }
- break;
- }
- case VIDIOCGTUNER: /* get tuner information */
- {
- struct video_tuner *tun = arg;
- struct v4l2_tuner tun2;
- int i;
- int sid;
- i = find_tuner(vfl, context, tun->tuner);
- if (i < 0)
- {
- err = i;
- break;
- }
- tun2.input = i;
- err = vfl->ioctl(context, VIDIOC_G_TUNER, &tun2);
- if (err < 0)
- break;
- memcpy(tun->name, tun2.name,
- min(sizeof(tun->name), sizeof(tun2.name)));
- tun->name[sizeof(tun->name) - 1] = 0;
- tun->rangelow = tun2.rangelow;
- tun->rangehigh = tun2.rangehigh;
- tun->flags = 0;
- tun->mode = VIDEO_MODE_AUTO;
- sid = v4l2_video_std_confirm(&tun2.std);
- switch (sid)
- {
- case V4L2_STD_NTSC:
- tun->flags = VIDEO_TUNER_NTSC;
- tun->mode = VIDEO_MODE_NTSC;
- break;
- case V4L2_STD_PAL:
- tun->flags = VIDEO_TUNER_PAL;
- tun->mode = VIDEO_MODE_PAL;
- break;
- case V4L2_STD_SECAM:
- tun->flags = VIDEO_TUNER_SECAM;
- tun->mode = VIDEO_MODE_SECAM;
- break;
- }
- if (tun2.capability & V4L2_TUNER_CAP_LOW)
- tun->flags |= VIDEO_TUNER_LOW;
- if (tun2.rxsubchans & V4L2_TUNER_SUB_STEREO)
- tun->flags |= VIDEO_TUNER_STEREO_ON;
- tun->signal = tun2.signal;
- break;
- }
- case VIDIOCSTUNER: /* select a tuner input */
- {
- int i;
- i = find_tuner(vfl, context, (int)arg);
- if (i < 0)
- {
- err = i;
- break;
- }
- err = vfl->ioctl(context, VIDIOC_S_INPUT, (void *)i);
- break;
- }
- case VIDIOCGFREQ: /* get frequency */
- {
- err = vfl->ioctl(context, VIDIOC_G_FREQ, arg);
- break;
- }
- case VIDIOCSFREQ: /* set frequency */
- {
- err = vfl->ioctl(context, VIDIOC_S_FREQ,
- (void *)(*(int *)arg));
- break;
- }
- case VIDIOCGAUDIO: /* get audio properties/controls */
- {
- struct video_audio *aud = arg;
- struct v4l2_audio aud2;
- struct v4l2_queryctrl qctrl2;
- struct v4l2_tuner tun2;
- int v;
- err = vfl->ioctl(context, VIDIOC_G_AUDIO, &aud2);
- if (err < 0)
- break;
- memcpy(aud->name, aud2.name,
- min(sizeof(aud->name), sizeof(aud2.name)));
- aud->name[sizeof(aud->name) - 1] = 0;
- aud->audio = aud2.audio;
- aud->flags = 0;
- v = get_v4l_control(vfl, context, V4L2_CID_AUDIO_VOLUME);
- if (v >= 0)
- {
- aud->volume = v;
- aud->flags |= VIDEO_AUDIO_VOLUME;
- }
- v = get_v4l_control(vfl, context, V4L2_CID_AUDIO_BASS);
- if (v >= 0)
- {
- aud->bass = v;
- aud->flags |= VIDEO_AUDIO_BASS;
- }
- v = get_v4l_control(vfl, context, V4L2_CID_AUDIO_TREBLE);
- if (v >= 0)
- {
- aud->treble = v;
- aud->flags |= VIDEO_AUDIO_TREBLE;
- }
- v = get_v4l_control(vfl, context, V4L2_CID_AUDIO_BALANCE);
- if (v >= 0)
- {
- aud->balance = v;
- aud->flags |= VIDEO_AUDIO_BALANCE;
- }
- v = get_v4l_control(vfl, context, V4L2_CID_AUDIO_MUTE);
- if (v >= 0)
- {
- if (v)
- aud->flags |= VIDEO_AUDIO_MUTE;
- aud->flags |= VIDEO_AUDIO_MUTABLE;
- }
- aud->step = 1;
- qctrl2.id = V4L2_CID_AUDIO_VOLUME;
- if (vfl->ioctl(context, VIDIOC_QUERYCTRL, &qctrl2) == 0)
- aud->step = qctrl2.step;
- aud->mode = 0;
- err = vfl->ioctl(context, VIDIOC_G_TUNER, &tun2);
- if (err < 0)
- {
- err = 0;
- break;
- }
- switch (tun2.audmode)
- {
- case V4L2_TUNER_MODE_MONO:
- aud->mode = VIDEO_SOUND_MONO;
- break;
- case V4L2_TUNER_MODE_STEREO:
- aud->mode = VIDEO_SOUND_STEREO;
- break;
- case V4L2_TUNER_MODE_LANG2:
- aud->mode = VIDEO_SOUND_LANG2;
- break;
- }
- break;
- }
- case VIDIOCSAUDIO: /* set audio controls */
- {
- struct video_audio *aud = arg;
- struct v4l2_audio aud2;
- struct v4l2_tuner tun2;
- int i;
- aud2.audio = aud2.audio;
- err = vfl->ioctl(context, VIDIOC_S_AUDIO, &aud2);
- if (err < 0)
- break;
- set_v4l_control(vfl, context, V4L2_CID_AUDIO_VOLUME,
- aud->volume);
- set_v4l_control(vfl, context, V4L2_CID_AUDIO_BASS,
- aud->bass);
- set_v4l_control(vfl, context, V4L2_CID_AUDIO_TREBLE,
- aud->treble);
- set_v4l_control(vfl, context, V4L2_CID_AUDIO_BALANCE,
- aud->balance);
- set_v4l_control(vfl, context, V4L2_CID_AUDIO_MUTE,
- !!(aud->flags & VIDEO_AUDIO_MUTE));
- err = vfl->ioctl(context, VIDIOC_G_INPUT, &i);
- if (err < 0)
- {
- err = 0;
- break;
- }
- tun2.input = i;
- err = vfl->ioctl(context, VIDIOC_G_TUNER, &tun2);
- if (err == 0)
- {
- switch (aud->mode)
- {
- default:
- case VIDEO_SOUND_MONO:
- tun2.audmode = V4L2_TUNER_MODE_MONO;
- break;
- case VIDEO_SOUND_STEREO:
- tun2.audmode = V4L2_TUNER_MODE_STEREO;
- break;
- case VIDEO_SOUND_LANG2:
- tun2.audmode = V4L2_TUNER_MODE_LANG2;
- break;
- }
- vfl->ioctl(context, VIDIOC_S_TUNER, &tun2);
- }
- err = 0;
- break;
- }
- case VIDIOCGMBUF: /* get mmap parameters */
- {
- struct video_mbuf *mbuf = arg;
- struct v4l2_requestbuffers reqbuf2;
- struct v4l2_buffer buf2;
- struct v4l2_format fmt2, fmt2o;
- struct v4l2_capability cap2;
- int i;
- /* Set the format to maximum dimensions */
- if ((err = vfl->ioctl(context, VIDIOC_QUERYCAP, &cap2)) < 0)
- break;
- if ((err = vfl->ioctl(context, VIDIOC_G_FMT, &fmt2o)) < 0)
- break;
- fmt2 = fmt2o;
- fmt2.width = cap2.maxwidth;
- fmt2.height = cap2.maxheight;
- if ((err = vfl->ioctl(context, VIDIOC_S_FMT, &fmt2)) < 0)
- break;
- reqbuf2.count = 2; /* v4l always used two buffers */
- reqbuf2.type = V4L2_BUF_TYPE_CAPTURE | V4L2_BUF_REQ_CONTIG;
- err = vfl->ioctl(context, VIDIOC_REQBUFS, &reqbuf2);
- if (err < 0 || reqbuf2.count < 2 || reqbuf2.type
- != (V4L2_BUF_TYPE_CAPTURE | V4L2_BUF_REQ_CONTIG))
- {/* Driver doesn't support v4l back-compatibility */
- vfl->ioctl(context, VIDIOC_S_FMT, &fmt2o);
- reqbuf2.count = 1;
- reqbuf2.type = V4L2_BUF_TYPE_CAPTURE;
- err = vfl->ioctl(context, VIDIOC_REQBUFS, &reqbuf2);
- if (err < 0)
- {
- err = -EINVAL;
- break;
- }
- printk(KERN_INFO"V4L2: Device "%s" doesn't support"
- " v4l memory mappingn", vfl->name);
- }
- buf2.index = 0;
- buf2.type = V4L2_BUF_TYPE_CAPTURE;
- err = vfl->ioctl(context, VIDIOC_QUERYBUF, &buf2);
- mbuf->size = buf2.length * reqbuf2.count;
- mbuf->frames = reqbuf2.count;
- memset(mbuf->offsets, 0, sizeof(mbuf->offsets));
- for (i = 0; i < mbuf->frames; ++i)
- mbuf->offsets[i] = i * buf2.length;
- break;
- }
- case VIDIOCMCAPTURE: /* capture a frame */
- {
- struct video_mmap *mm = arg;
- struct v4l2_buffer buf2;
- struct v4l2_format fmt2;
- err = vfl->ioctl(context, VIDIOC_G_FMT, &fmt2);
- if (err < 0)
- break;
- if (mm->width != fmt2.width || mm->height != fmt2.height ||
- palette_to_pixelformat(mm->format) != fmt2.pixelformat)
- {/* New capture format... */
- //vfl->ioctl(context, VIDIOC_STREAMOFF,
- // (void *)V4L2_BUF_TYPE_CAPTURE);
- fmt2.width = mm->width;
- fmt2.height = mm->height;
- fmt2.pixelformat = palette_to_pixelformat(mm->format);
- err = vfl->ioctl(context, VIDIOC_S_FMT, &fmt2);
- if (err < 0)
- break;
- }
- buf2.index = mm->frame;
- buf2.type = V4L2_BUF_TYPE_CAPTURE;
- err = vfl->ioctl(context, VIDIOC_QUERYBUF, &buf2);
- if (err < 0)
- break;
- err = vfl->ioctl(context, VIDIOC_QBUF, &buf2);
- if (err < 0)
- break;
- vfl->ioctl(context, VIDIOC_STREAMON, (void *)buf2.type);
- break;
- }
- case VIDIOCSYNC: /* wait for a frame */
- {
- int *i = arg;
- struct v4l2_buffer buf2;
- buf2.index = *i;
- buf2.type = V4L2_BUF_TYPE_CAPTURE;
- err = vfl->ioctl(context, VIDIOC_QUERYBUF, &buf2);
- if (err < 0) /* No such buffer */
- break;
- if (!(buf2.flags & V4L2_BUF_FLAG_MAPPED))
- {/* Buffer is not mapped */
- err = -EINVAL;
- break;
- }
- /* Loop as long as the buffer is queued, but not done */
- while ((buf2.flags &
- (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE))
- == V4L2_BUF_FLAG_QUEUED)
- {
- err = simple_select(file);
- if (err < 0 || /* error or sleep was interrupted */
- err == 0) /* timeout? Shouldn't occur. */
- break;
- vfl->ioctl(context, VIDIOC_QUERYBUF, &buf2);
- }
- if (!(buf2.flags & V4L2_BUF_FLAG_DONE)) /* not done */
- break;
- do
- {
- err = vfl->ioctl(context, VIDIOC_DQBUF, &buf2);
- } while (err == 0 && buf2.index != *i);
- break;
- }
- case VIDIOCGUNIT: /* get related device minors */
- /* No translation */
- break;
- case VIDIOCGCAPTURE: /* */
- /* No translation, yet... */
- printk(KERN_INFO"V4L2: VIDIOCGCAPTURE not implemented. "
- "Send patches to bdirks@pacbell.net :-)n");
- break;
- case VIDIOCSCAPTURE: /* */
- /* No translation, yet... */
- printk(KERN_INFO"V4L2: VIDIOCSCAPTURE not implemented. "
- "Send patches to bdirks@pacbell.net :-)n");
- break;
- }
- return err;
- }
- /*
- * D E V I C E R E G I S T R A T I O N
- *
- * Video for Linux Two device drivers request registration here.
- */
- int
- v4l2_register_device(struct v4l2_device *vfl)
- {
- int i = 0;
- int err;
- if (vfl == NULL)
- {
- printk(KERN_ERR"V4L2: v4l2_register_device() passed"
- " a NULL pointer!n");
- return -1;
- }
- i = vfl->minor;
- if (vfl->open == NULL)
- {
- printk(KERN_ERR "V4L2: Device %d has no open methodn", i);
- return -1;
- }
- if (i < 0 || i >= V4L2_NUM_DEVICES)
- {
- printk(KERN_ERR"V4L2: Minor value %d is out of rangen", i);
- return -1;
- }
- if (v4l2_device[i] != NULL)
- {
- printk(KERN_ERR"V4L2: %s and %s have both been assigned"
- " minor %dn", v4l2_device[i]->name,
- vfl->name, i);
- return 1;
- }
- v4l2_device[i] = vfl;
- /* The init call may sleep so we book the slot out then call */
- MOD_INC_USE_COUNT;
- err = 0;
- if (vfl->initialize)
- err = vfl->initialize(vfl);
- if (err < 0)
- {
- printk(KERN_ERR "V4L2: %s initialize method failedn",
- vfl->name);
- v4l2_device[i] = NULL;
- MOD_DEC_USE_COUNT;
- return err;
- }
- vfl->busy = 0;
- vfl->name[sizeof(vfl->name) - 1] = 0;
- printk(KERN_INFO"V4L2: Registered "%s" as char device %d, %dn",
- vfl->name, v4l2_major, vfl->minor);
- memset(vfl->v4l2_reserved, 0, sizeof(vfl->v4l2_reserved));
- vfl->v4l2_priv = NULL;
- return 0;
- }
- /*
- * Unregister an unused video for linux device
- */
- void
- v4l2_unregister_device(struct v4l2_device *vfl)
- {
- if (vfl->minor < 0 || vfl->minor >= V4L2_NUM_DEVICES ||
- v4l2_device[vfl->minor] != vfl)
- {
- printk(KERN_ERR"V4L2: bad unregistern");
- return;
- }
- v4l2_device[vfl->minor] = NULL;
- MOD_DEC_USE_COUNT;
- }
- /*
- * / p r o c / v i d e o d e v H A N D L E R
- */
- /* Original /proc file code from Erik Walthinsen */
- static char *device_types[] =
- {
- "capture", "codec", "output", "effects",
- "vbi", "vtr", "teletext", "radio",
- "undef", "undef", "undef", "undef",
- };
- static int
- video_read_proc(char *buf, char **start, off_t offset, int len, int unused)
- {
- struct v4l2_device *vfl;
- int i;
- char *t;
- len = 0;
- len += sprintf(buf, "Video for Linux Two: V%d.%d alpha."
- " Major device: %dn",
- V4L2_MAJOR_VERSION, V4L2_MINOR_VERSION,
- v4l2_major);
- //len += sprintf(buf+len,"minor: type busy namen");
- for (i = 0; i < V4L2_NUM_DEVICES; i++)
- {
- vfl = v4l2_device[i];
- if (vfl == NULL)
- continue;
- if (len > (PAGE_SIZE - 80))
- return len;
- if (vfl->type >= 0 &&
- vfl->type < sizeof(device_types)/sizeof(char*))
- t = device_types[vfl->type];
- else if (vfl->type >= V4L2_TYPE_PRIVATE)
- t = "private";
- else
- t = "undef";
- len += sprintf(buf+len, "%5d: %-9s %3d %sn",
- vfl->minor, t, vfl->busy, vfl->name);
- }
- return len;
- }
- /* proc file for /proc/videodev */
- static struct proc_dir_entry video_proc_entry =
- {
- 0, 8, "videodev", S_IFREG | S_IRUGO, 1, 0, 0, 0, NULL,
- &video_read_proc
- };
- /*
- * V I D E O F O R L I N U X T W O I N I T I A L I Z A T I O N
- */
- static struct file_operations video_fops =
- {
- video_lseek,
- video_read,
- video_write,
- NULL, /* readdir */
- video_poll,
- video_ioctl,
- video_mmap,
- video_open,
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,118)
- NULL,
- #endif
- video_release
- };
- /*
- * Initialize Video for Linux Two
- */
- int videodev_init(void)
- {
- int i;
- printk(KERN_INFO"Video for Linux Two: V%d.%d alpha."
- " Major device: %dn",
- V4L2_MAJOR_VERSION, V4L2_MINOR_VERSION, v4l2_major);
- if (register_chrdev(v4l2_major, "v4l2", &video_fops))
- {
- printk("V4L2: Unable to get major %dn", v4l2_major);
- return -EIO;
- }
- /* make sure there's a way to tell if a device is not there */
- for (i = 0; i < V4L2_NUM_DEVICES; i++)
- v4l2_device[i] = NULL;
- proc_register(&proc_root, &video_proc_entry);
- masterclock = NULL;
- return 0;
- }
- #ifdef MODULE
- int init_module(void)
- {
- return videodev_init();
- }
- void cleanup_module(void)
- {
- proc_unregister(&proc_root, video_proc_entry.low_ino);
- unregister_chrdev(v4l2_major, "v4l2");
- }
- #endif
- /*
- *
- * V 4 L 2 D R I V E R H E L P E R A P I
- *
- */
- void
- v4l2_version(int *major, int *minor)
- {
- *major = V4L2_MAJOR_VERSION;
- *minor = V4L2_MINOR_VERSION;
- }
- int
- v4l2_major_number(void)
- {
- return v4l2_major;
- }
- struct v4l2_device *
- v4l2_device_from_minor(int minor)
- {
- if (minor < 0 || minor >= V4L2_NUM_DEVICES)
- return NULL;
- return v4l2_device[minor];
- }
- struct v4l2_device *
- v4l2_device_from_file(struct file *file)
- {
- if (file == NULL)
- return NULL;
- return v4l2_device_from_minor(MINOR(file->f_dentry->d_inode->i_rdev));
- }
- void *
- v4l2_openid_from_file(struct file *file)
- {
- if (file == NULL)
- return NULL;
- return file->private_data;
- }
- static struct mm_struct *
- find_init_mm(void)
- {
- static struct mm_struct *mm;
- struct task_struct *p;
- if (mm)
- return mm;
- for (p = current; p && (p = p->next_task) != current; )
- if (p->pid == 0)
- break;
- mm = (p) ? p->mm : NULL;
- return mm;
- }
- /* Useful for using vmalloc()ed memory as DMA target */
- unsigned long
- v4l2_vmalloc_to_bus(void *virt)
- {
- pgd_t *pgd;
- pmd_t *pmd;
- pte_t *pte;
- unsigned long a = (unsigned long)virt;
- struct mm_struct *mm = find_init_mm();
- if (mm == NULL ||
- pgd_none(*(pgd = pgd_offset(mm, a))) ||
- pmd_none(*(pmd = pmd_offset(pgd, a))) ||
- pte_none(*(pte = pte_offset(pmd, a))))
- return 0;
- return virt_to_bus((void *)pte_page(*pte))
- + (a & (PAGE_SIZE - 1));
- }
- /* Useful for a nopage handler when mmap()ing vmalloc()ed memory */
- unsigned long
- v4l2_vmalloc_to_page(void *virt)
- {
- pgd_t *pgd;
- pmd_t *pmd;
- pte_t *pte;
- unsigned long a = (unsigned long)virt;
- struct mm_struct *mm = find_init_mm();
- if (mm == NULL ||
- pgd_none(*(pgd = pgd_offset(current->mm, a))) ||
- pmd_none(*(pmd = pmd_offset(pgd, a))) ||
- pte_none(*(pte = pte_offset(pmd, a))))
- return 0;
- return pte_page(*pte);
- }
- /*
- * Simple queue management
- */
- static rwlock_t rw_lock_unlocked = RW_LOCK_UNLOCKED;
- void
- v4l2_q_init(struct v4l2_queue *q)
- {
- if (q == NULL)
- return;
- q->qlock = rw_lock_unlocked;
- q->forw = (struct v4l2_q_node *)q;
- q->back = (struct v4l2_q_node *)q;
- }
- void
- v4l2_q_add_head(struct v4l2_queue *q, struct v4l2_q_node *node)
- {
- unsigned long flags;
- if (q == NULL || node == NULL)
- return;
- if (q->forw == NULL || q->back == NULL)
- v4l2_q_init(q);
- write_lock_irqsave(&(q->qlock), flags);
- node->forw = q->forw;
- node->back = (struct v4l2_q_node *)q;
- q->forw->back = node;
- q->forw = node;
- write_unlock_irqrestore(&(q->qlock), flags);
- }
- void
- v4l2_q_add_tail(struct v4l2_queue *q, struct v4l2_q_node *node)
- {
- unsigned long flags;
- if (q == NULL || node == NULL)
- return;
- if (q->forw == NULL || q->back == NULL)
- v4l2_q_init(q);
- write_lock_irqsave(&(q->qlock), flags);
- node->forw = (struct v4l2_q_node *)q;
- node->back = q->back;
- q->back->forw = node;
- q->back = node;
- write_unlock_irqrestore(&(q->qlock), flags);
- }
- void *
- v4l2_q_del_head(struct v4l2_queue *q)
- {
- unsigned long flags;
- struct v4l2_q_node *node;
- if (q == NULL)
- return NULL;
- write_lock_irqsave(&(q->qlock), flags);
- if (q->forw == NULL || q->back == NULL ||
- q->forw == (struct v4l2_q_node *)q ||
- q->back == (struct v4l2_q_node *)q)
- {
- write_unlock_irqrestore(&(q->qlock), flags);
- return NULL;
- }
- node = q->forw;
- node->forw->back = (struct v4l2_q_node *)q;
- q->forw = node->forw;
- node->forw = NULL;
- node->back = NULL;
- write_unlock_irqrestore(&(q->qlock), flags);
- return node;
- }
- void *
- v4l2_q_del_tail(struct v4l2_queue *q)
- {
- unsigned long flags;
- struct v4l2_q_node *node;
- if (q == NULL)
- return NULL;
- write_lock_irqsave(&(q->qlock), flags);
- if (q->forw == NULL || q->back == NULL ||
- q->forw == (struct v4l2_q_node *)q ||
- q->back == (struct v4l2_q_node *)q)
- {
- write_unlock_irqrestore(&(q->qlock), flags);
- return NULL;
- }
- node = q->back;
- node->back->forw = (struct v4l2_q_node *)q;
- q->back = node->back;
- node->forw = NULL;
- node->back = NULL;
- write_unlock_irqrestore(&(q->qlock), flags);
- return node;
- }
- void *
- v4l2_q_peek_head(struct v4l2_queue *q)
- {
- unsigned long flags;
- struct v4l2_q_node *node;
- read_lock_irqsave(&(q->qlock), flags);
- if (q == NULL || q->forw == NULL || q->forw == (struct v4l2_q_node *)q)
- {
- read_unlock_irqrestore(&(q->qlock), flags);
- return NULL;
- }
- node = q->forw;
- read_unlock_irqrestore(&(q->qlock), flags);
- return node;
- }
- void *
- v4l2_q_peek_tail(struct v4l2_queue *q)
- {
- unsigned long flags;
- struct v4l2_q_node *node;
- read_lock_irqsave(&(q->qlock), flags);
- if (q == NULL || q->back == NULL || q->back == (struct v4l2_q_node *)q)
- {
- read_unlock_irqrestore(&(q->qlock), flags);
- return NULL;
- }
- node = q->back;
- read_unlock_irqrestore(&(q->qlock), flags);
- return node;
- }
- void *
- v4l2_q_yank_node(struct v4l2_queue *q, struct v4l2_q_node *node)
- {
- unsigned long flags;
- struct v4l2_q_node *t;
- if (v4l2_q_peek_head(q) == NULL || node == NULL)
- return NULL;
- write_lock_irqsave(&(q->qlock), flags);
- for (t = q->forw; t != (struct v4l2_q_node *)q; t = t->forw)
- if (t == node)
- {
- node->back->forw = node->forw;
- node->forw->back = node->back;
- node->forw = NULL;
- node->back = NULL;
- write_unlock_irqrestore(&(q->qlock), flags);
- return node;
- }
- write_unlock_irqrestore(&(q->qlock), flags);
- return NULL;
- }
- /*
- * Math functions
- */
- u32
- v4l2_math_div6432(u64 a, u32 d, u32 *r)
- {
- u32 q, m;
- #ifdef __i386__
- __asm__ __volatile__ (
- " movl %2,%%eaxn"
- " movl %3,%%edxn"
- " divl %4n"
- " movl %%eax,%0n"
- " movl %%edx,%1n"
- : "=g" (q), "=g" (m)
- : "g" ((u32)a), "g" ((u32)(a >> 32)), "g" (d)
- : "eax", "edx"
- );
- #else
- q = a / d;
- m = a % d;
- #endif
- if (r) *r = m;
- return q;
- }
- void
- v4l2_timeval_delta(struct timeval *d,
- struct timeval *a,
- struct timeval *b)
- {
- if (a->tv_sec < b->tv_sec ||
- (a->tv_sec == b->tv_sec && a->tv_usec < b->tv_usec))
- {
- d->tv_sec = b->tv_sec - a->tv_sec;
- d->tv_usec = b->tv_usec - a->tv_usec;
- }
- else
- {
- d->tv_sec = a->tv_sec - b->tv_sec;
- d->tv_usec = a->tv_usec - b->tv_usec;
- }
- if (d->tv_usec < 0)
- {
- d->tv_usec += 1000000;
- d->tv_sec -= 1;
- }
- }
- unsigned long
- v4l2_timeval_divide(struct timeval *t, unsigned long p_100ns)
- {
- /* Note: 'p_100ns' is in 100ns units, and the quotient is rounded */
- u64 t_100ns;
- t_100ns = (u64)t->tv_sec * 10000000 + t->tv_usec * 10;
- return v4l2_math_div6432(t_100ns + (p_100ns >> 1), p_100ns, NULL);
- }
- /* Force the timeval to be an integer multiple of p_100ns */
- unsigned long
- v4l2_timeval_correct(struct timeval *t, unsigned long p_100ns)
- {
- unsigned long n;
- u32 m;
- n = v4l2_timeval_divide(t, p_100ns);
- t->tv_sec = v4l2_math_div6432((u64)p_100ns * n, 10000000, &m);
- t->tv_usec = m / 10;
- return n;
- }
- /*
- * Master clock and Timeval operations
- */
- int
- v4l2_masterclock_register(struct v4l2_clock *clock)
- {
- if (clock == NULL || clock->gettime == NULL)
- return -1;
- if (masterclock != NULL)
- return -1;
- masterclock = clock;
- MOD_INC_USE_COUNT;
- return 0;
- }
- void
- v4l2_masterclock_unregister(struct v4l2_clock *clock)
- {
- if (clock != masterclock)
- return;
- masterclock = NULL;
- MOD_DEC_USE_COUNT;
- }
- void
- v4l2_masterclock_gettime(struct timeval *curr)
- {
- if (masterclock)
- masterclock->gettime(curr);
- else
- do_gettimeofday(curr);
- }
- /*
- * Video Standard Operations (contributed by Michael Schimek)
- */
- /* This is the recommended method to deal with the framerate fields. More
- sophisticated drivers will access the fields directly. */
- unsigned int
- v4l2_video_std_fps(struct v4l2_standard *vs)
- {
- if (vs->framerate.numerator > 0)
- return (((vs->framerate.denominator << 8) /
- vs->framerate.numerator) +
- (1 << 7)) / (1 << 8);
- return 0;
- }
- /* Compute the time per frame in 100ns units */
- unsigned long
- v4l2_video_std_tpf(struct v4l2_standard *vs)
- {
- return v4l2_math_div6432(
- (u64)vs->framerate.numerator * 10000000
- + vs->framerate.denominator / 2,
- vs->framerate.denominator,
- NULL);
- }
- /* Used only in v4l2_video_std_confirm() */
- static void
- catc1p2e6(__u8 *s, char c, int n)
- {
- n /= 10000;
- sprintf(s + strlen(s), "%c%d.%02d", c, n / 100, n % 100);
- }
- /* Verify the validity of the parameters of a v4l2_standard structure and
- create the name and id from the other fields. It does not relieve a
- driver from examining if it can fulfill the request. Returns an
- errno < 0 if inconsistent, 0 if an unknown but maybe usable format,
- or the V4L2_STD_XXX_X value if a known standard. */
- int
- v4l2_video_std_confirm(struct v4l2_standard *vs)
- {
- unsigned int rate = 0;
- unsigned int lines = vs->framelines;
- int std = 0;
- strcpy(vs->name, "Unknown");
- if (vs->reserved1 || vs->reserved2)
- return -EINVAL;
- if (vs->framerate.numerator > 0 &&
- vs->framerate.denominator > 0)
- rate = v4l2_video_std_fps(vs);
- if (vs->framelines >= 624 && vs->framelines <= 626)
- lines = 625;
- else if (vs->framelines >= 524 && vs->framelines <= 526)
- lines = 525;
- if (rate == 0 || lines == 0 || rate > 200)
- return -EINVAL;
- switch (vs->colorstandard)
- {
- case V4L2_COLOR_STD_PAL:
- strcpy(vs->name, "PAL");
- if (rate == 25 && lines == 625)
- switch (vs->colorstandard_data.pal.colorsubcarrier)
- {
- case V4L2_COLOR_SUBC_PAL_N:
- strcpy(vs->name, "PAL-N");
- if (vs->transmission & ~V4L2_TRANSM_STD_N)
- return -EINVAL;
- return V4L2_STD_PAL_N;
- case V4L2_COLOR_SUBC_PAL:
- if (vs->transmission &
- ~(V4L2_TRANSM_STD_B | V4L2_TRANSM_STD_G |
- V4L2_TRANSM_STD_H | V4L2_TRANSM_STD_I |
- V4L2_TRANSM_STD_D))
- return -EINVAL;
- std = V4L2_STD_PAL;
- goto addtransm;
- }
- else if (rate == 30 && lines == 525)
- switch (vs->colorstandard_data.pal.colorsubcarrier)
- {
- case V4L2_COLOR_SUBC_PAL_M:
- strcpy(vs->name, "PAL-M");
- if (vs->transmission & ~V4L2_TRANSM_STD_M)
- return -EINVAL;
- return V4L2_STD_PAL_M;
- case V4L2_COLOR_SUBC_PAL:
- strcpy(vs->name, "PAL-60");
- if (vs->transmission)
- return -EINVAL;
- return V4L2_STD_PAL_60;
- }
- if (vs->transmission)
- return -EINVAL;
- catc1p2e6(vs->name, ' ',
- vs->colorstandard_data.pal.colorsubcarrier);
- break;
- case V4L2_COLOR_STD_NTSC:
- strcpy(vs->name, "NTSC");
- if (rate == 25 && lines == 625)
- switch (vs->colorstandard_data.ntsc.colorsubcarrier)
- {
- case V4L2_COLOR_SUBC_NTSC:
- strcpy(vs->name, "NTSC-N");
- if (vs->transmission & ~V4L2_TRANSM_STD_N)
- return -EINVAL;
- return V4L2_STD_NTSC_N;
- }
- else if (rate == 30 && lines == 525)
- switch (vs->colorstandard_data.ntsc.colorsubcarrier)
- {
- case V4L2_COLOR_SUBC_NTSC:
- if (vs->transmission & ~V4L2_TRANSM_STD_M)
- return -EINVAL;
- std = V4L2_STD_NTSC;
- goto addtransm;
- case V4L2_COLOR_SUBC_PAL:
- strcpy(vs->name, "NTSC-44");
- if (vs->transmission)
- return -EINVAL;
- return V4L2_STD_NTSC_44;
- }
- if (vs->transmission)
- return -EINVAL;
- catc1p2e6(vs->name, ' ',
- vs->colorstandard_data.ntsc.colorsubcarrier);
- break;
- case V4L2_COLOR_STD_SECAM:
- strcpy(vs->name, "SECAM");
- if (rate == 25 && lines == 625)
- if (vs->colorstandard_data.secam.f0b ==
- V4L2_COLOR_SUBC_SECAMB &&
- vs->colorstandard_data.secam.f0r ==
- V4L2_COLOR_SUBC_SECAMR)
- {
- if (vs->transmission &
- ~(V4L2_TRANSM_STD_B | V4L2_TRANSM_STD_D |
- V4L2_TRANSM_STD_G | V4L2_TRANSM_STD_K |
- V4L2_TRANSM_STD_K1 | V4L2_TRANSM_STD_L))
- return -EINVAL;
- std = V4L2_STD_SECAM;
- goto addtransm;
- }
- if (vs->transmission)
- return -EINVAL;
- catc1p2e6(vs->name, ' ', vs->colorstandard_data.secam.f0b);
- catc1p2e6(vs->name, '/', vs->colorstandard_data.secam.f0r);
- break;
- default:
- return -EINVAL;
- }
- sprintf(vs->name + strlen(vs->name), " %d/%d",
- vs->framelines, rate);
- return std;
- addtransm:
- if (vs->transmission) strcat(vs->name, "-");
- if (vs->transmission & V4L2_TRANSM_STD_B) strcat(vs->name, "B/");
- if (vs->transmission & V4L2_TRANSM_STD_G) strcat(vs->name, "G/");
- if (vs->transmission & V4L2_TRANSM_STD_H) strcat(vs->name, "H/");
- if (vs->transmission & V4L2_TRANSM_STD_I) strcat(vs->name, "I/");
- if (vs->transmission & V4L2_TRANSM_STD_D) strcat(vs->name, "D/");
- if (vs->transmission & V4L2_TRANSM_STD_K) strcat(vs->name, "K/");
- if (vs->transmission & V4L2_TRANSM_STD_K1) strcat(vs->name, "K1/");
- if (vs->transmission & V4L2_TRANSM_STD_L) strcat(vs->name, "L/");
- if (vs->transmission & V4L2_TRANSM_STD_M) strcat(vs->name, "M/");
- if (vs->transmission & V4L2_TRANSM_STD_N) strcat(vs->name, "N/");
- if (vs->name[strlen(vs->name) - 1] == '/')
- vs->name[strlen(vs->name) - 1] = 0;
- return std;
- }
- /* Fill in the fields of a v4l2_standard structure according to the
- 'id' and 'transmission' parameters. Returns negative on error. */
- int
- v4l2_video_std_construct(struct v4l2_standard *vs,
- int id, __u32 transmission)
- {
- memset(vs, 0, sizeof(struct v4l2_standard));
- vs->framerate.numerator = 1;
- vs->framerate.denominator = 25;
- vs->framelines = 625;
- switch (id)
- {
- case V4L2_STD_PAL_60:
- vs->framerate.numerator = 1001;
- vs->framerate.denominator = 30000;
- vs->framelines = 525;
- /* fall thru */
- case V4L2_STD_PAL:
- vs->colorstandard = V4L2_COLOR_STD_PAL;
- vs->colorstandard_data.pal.colorsubcarrier =
- V4L2_COLOR_SUBC_PAL;
- break;
- case V4L2_STD_PAL_M:
- vs->framerate.numerator = 1001;
- vs->framerate.denominator = 30000;
- vs->framelines = 525;
- vs->colorstandard = V4L2_COLOR_STD_PAL;
- vs->colorstandard_data.pal.colorsubcarrier =
- V4L2_COLOR_SUBC_PAL_M;
- break;
- case V4L2_STD_PAL_N:
- vs->colorstandard = V4L2_COLOR_STD_PAL;
- vs->colorstandard_data.pal.colorsubcarrier =
- V4L2_COLOR_SUBC_PAL_N;
- break;
- case V4L2_STD_NTSC:
- vs->framerate.numerator = 1001;
- vs->framerate.denominator = 30000;
- vs->framelines = 525;
- /* fall thru */
- case V4L2_STD_NTSC_N:
- vs->colorstandard = V4L2_COLOR_STD_NTSC;
- vs->colorstandard_data.ntsc.colorsubcarrier =
- V4L2_COLOR_SUBC_NTSC;
- break;
- case V4L2_STD_NTSC_44:
- vs->framerate.numerator = 1001;
- vs->framerate.denominator = 30000;
- vs->framelines = 525;
- vs->colorstandard = V4L2_COLOR_STD_NTSC;
- vs->colorstandard_data.ntsc.colorsubcarrier =
- V4L2_COLOR_SUBC_PAL;
- break;
- case V4L2_STD_SECAM:
- vs->colorstandard = V4L2_COLOR_STD_SECAM;
- vs->colorstandard_data.secam.f0b = V4L2_COLOR_SUBC_SECAMB;
- vs->colorstandard_data.secam.f0r = V4L2_COLOR_SUBC_SECAMR;
- break;
- default:
- return -EINVAL;
- }
- vs->transmission = transmission;
- return v4l2_video_std_confirm(vs);
- }
- /*---------------------------------------*/
- EXPORT_SYMBOL(v4l2_register_device);
- EXPORT_SYMBOL(v4l2_unregister_device);
- EXPORT_SYMBOL(v4l2_version);
- EXPORT_SYMBOL(v4l2_major_number);
- EXPORT_SYMBOL(v4l2_device_from_minor);
- EXPORT_SYMBOL(v4l2_device_from_file);
- EXPORT_SYMBOL(v4l2_openid_from_file);
- EXPORT_SYMBOL(v4l2_vmalloc_to_bus);
- EXPORT_SYMBOL(v4l2_vmalloc_to_page);
- EXPORT_SYMBOL(v4l2_q_init);
- EXPORT_SYMBOL(v4l2_q_add_head);
- EXPORT_SYMBOL(v4l2_q_add_tail);
- EXPORT_SYMBOL(v4l2_q_del_head);
- EXPORT_SYMBOL(v4l2_q_del_tail);
- EXPORT_SYMBOL(v4l2_q_peek_head);
- EXPORT_SYMBOL(v4l2_q_peek_tail);
- EXPORT_SYMBOL(v4l2_q_yank_node);
- EXPORT_SYMBOL(v4l2_math_div6432);
- EXPORT_SYMBOL(v4l2_timeval_delta);
- EXPORT_SYMBOL(v4l2_timeval_divide);
- EXPORT_SYMBOL(v4l2_timeval_correct);
- EXPORT_SYMBOL(v4l2_masterclock_register);
- EXPORT_SYMBOL(v4l2_masterclock_unregister);
- EXPORT_SYMBOL(v4l2_masterclock_gettime);
- EXPORT_SYMBOL(v4l2_video_std_fps);
- EXPORT_SYMBOL(v4l2_video_std_tpf);
- EXPORT_SYMBOL(v4l2_video_std_confirm);
- EXPORT_SYMBOL(v4l2_video_std_construct);