commit 2bf3b305535fb7c3a7c9c0c0a5de9d7035b856ce
parent ccb72a37290703dbf0a433a47cbfede0d58cb456
Author: alex <alex@022568fa-442e-4ef8-a3e8-54dcafdb011a>
Date: Fri, 18 Jan 2008 02:33:48 +0000
* Added changelog entries.
* Provide working V4L1 support. \o/
git-svn-id: http://svn.mediati.org/svn/r5u870/trunk@41 022568fa-442e-4ef8-a3e8-54dcafdb011a
Diffstat:
2 files changed, 391 insertions(+), 179 deletions(-)
diff --git a/ChangeLog b/ChangeLog
@@ -1,3 +1,9 @@
+2008-01-18 Alexander Hixon <hixon.alexander@mediati.org>
+ * usbcam/usbcam_fops.c: Provide working V4L1 support. Probably needs a bit
+ of a cleanup, but works perfectly fine.
+ * r5u870.c: Added support for the 1837 UVC camera - apparently uses the
+ same firmware as the 1836 model. Awating test results from a user.
+
2008-01-17 Alexander Hixon <hixon.alexander@mediati.org>
* usbcam/usbcam.c: Remove unnecessary file - accidentially kept post-
merge.
diff --git a/usbcam/usbcam_fops.c b/usbcam/usbcam_fops.c
@@ -28,6 +28,61 @@
* - Add debug tracing to more ioctl paths
*/
+/* HELPER FOR V4L1 COMPAT OPS */
+
+const static 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 __pure
+palette_to_pixelformat(unsigned int palette)
+{
+ if (palette < ARRAY_SIZE(palette2pixelformat))
+ return palette2pixelformat[palette];
+ else
+ return 0;
+}
+
+static int poll_one(struct file *file)
+{
+ int retval = 1;
+ poll_table *table;
+ struct poll_wqueues pwq;
+
+ 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;
+}
+
/*
* V4L file_operations callout implementations
*/
@@ -184,185 +239,6 @@ static int usbcam_v4l_mmap(struct file *filp, struct vm_area_struct * vma)
return videobuf_mmap_mapper(&ufp->ufh_vbq, vma);
}
-/* Intercept calls to minidriver V4L handler thing. */
-static int usbcam_v4l_int_ioctl(struct inode *inodep, struct file *filp,
- unsigned int cmd, void *arg)
-{
- struct usbcam_fh *ufp = (struct usbcam_fh *) filp->private_data;
- struct usbcam_dev *udp = ufp->ufh_dev;
-
- if (cmd == VIDIOCGCAP) {
- struct video_capability *cap = (struct video_capability *) arg;
-
- usbcam_lock(udp);
-
- strlcpy(cap->name, udp->ud_vdev.name, sizeof(cap->name));
- cap->type = VID_TYPE_CAPTURE;
- cap->audios = 0;
- cap->channels = 1; /* only one input source, the camera */
-
- cap->maxwidth = udp->ud_format.width;
- cap->maxheight = udp->ud_format.height;
-
- /*
- * We lie, here. These values normally return 640x480, which is
- * actually the maximum, not the minimum. Minimum is usually
- * 160x120. It's sort of useful to lie since lots of software
- * just stick with the minimum - we want higher res for the
- * user where possible.
- */
-
- cap->minwidth = udp->ud_format.width;
- cap->minheight = udp->ud_format.height;
-
- usbcam_unlock(udp);
- return 0;
- }
- else if (cmd == VIDIOCGFBUF) {
- struct video_buffer *buf = (struct video_buffer *) arg;
-
- usbcam_lock(udp);
- buf->base = NULL; /* no physical frame buffer access */
- buf->height = udp->ud_format.height;
- buf->width = udp->ud_format.width;
-
- // graciously stolen from drivers/media/video/v4l1-compat.c
- // and modified slightly.
- switch (udp->ud_format.pixelformat) {
- case V4L2_PIX_FMT_RGB332:
- buf->depth = 8;
- break;
- case V4L2_PIX_FMT_RGB555:
- buf->depth = 15;
- break;
- case V4L2_PIX_FMT_RGB565:
- buf->depth = 16;
- break;
- case V4L2_PIX_FMT_BGR24:
- buf->depth = 24;
- break;
- case V4L2_PIX_FMT_BGR32:
- buf->depth = 32;
- break;
- default:
- buf->depth = 0;
- }
-
- if (udp->ud_format.bytesperline) {
- buf->bytesperline = udp->ud_format.bytesperline;
-
- /* typically comes out at 16 bit depth as non-rgb */
- if (!buf->depth && buf->width)
- buf->depth = ((udp->ud_format.bytesperline<<3)
- + (buf->width-1) )
- /buf->width;
- } else {
- buf->bytesperline =
- (buf->width * buf->depth + 7) & 7;
- buf->bytesperline >>= 3;
- }
-
- usbcam_unlock(udp);
- return 0;
- }
- else {
- usbcam_warn(udp, "usbcam_v4l_int_ioctl called without valid ioctl");
- return -ENOIOCTLCMD;
- }
-}
-
-static int usbcam_v4l_ioctl (struct inode *inodep, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- if (cmd == VIDIOCGCAP || cmd == VIDIOCGFBUF)
- {
- // run our own internal ioctl handler for these V4L compat commands.
- return video_usercopy(inodep, file, cmd, arg, usbcam_v4l_int_ioctl);
- }
-#endif
-
- /*if (cmd != VIDIOCGMBUF && _IOC_TYPE(cmd) == 'v')
- {
- // send the command off to the compat translator if it's any other v4l1
- return v4l_compat_translate_ioctl(inodep, file, cmd, arg,
- usbcam_v4l_int_ioctl);
- }
- else
- {*/
- // normal v4l2 command
- return video_ioctl2(inodep, file, cmd, arg);
- //}
-}
-
-/*
- * The template file_operations structure
- *
- * Each usbcam_minidrv_t contains its own copy of this, which
- * is associated with the video4linux device created for that
- * minidriver.
- *
- * In general, copies will differ only in the .owner field, which
- * will refer to the minidriver module, not usbcam.
- */
-
-struct file_operations usbcam_v4l_fops_template = {
- .owner = THIS_MODULE,
- .open = usbcam_v4l_open,
- .release = usbcam_v4l_release,
- .read = usbcam_v4l_read,
- .poll = usbcam_v4l_poll,
- .mmap = usbcam_v4l_mmap,
- /*.ioctl = video_ioctl2,*/
- .ioctl = usbcam_v4l_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = v4l_compat_ioctl32,
-#endif
- .llseek = no_llseek,
-};
-
-
-static void usbcam_dbg_v4l2_buffer_res(struct usbcam_dev *udp, int res,
- void *arg, const char *prefix)
-{
- struct v4l2_buffer *b __attribute__((unused)) =
- (struct v4l2_buffer *) arg;
-
- if (res) {
- usbcam_dbg(udp, IOCTL_BUF, "%s res:%d", prefix, res);
- return;
- }
-
- usbcam_dbg(udp, IOCTL_BUF, "%s out: index=%d type=%d bytesused=%d "
- "flags=0x%x field=%d memory=%d m=0x%lx length=%d",
- prefix, b->index, b->type, b->bytesused,
- b->flags, b->field, b->memory, b->m.userptr, b->length);
-}
-
-static void usbcam_dbg_v4l2_pix_format(struct usbcam_dev *udp,
- struct v4l2_pix_format *f,
- const char *prefix)
-{
- __u32 pixfmt = f->pixelformat;
- if (!pixfmt)
- pixfmt = 0x3f3f3f3f;
- usbcam_dbg(udp, IOCTL_FMT, "%s wid=%d hgt=%d fmt=%.4s field=%d "
- "bpl=%d size=%d cs=%d", prefix,
- f->width, f->height, (char *) &pixfmt, f->field,
- f->bytesperline, f->sizeimage, f->colorspace);
-}
-
-static void usbcam_dbg_v4l2_pix_format_res(struct usbcam_dev *udp, int res,
- struct v4l2_pix_format *f,
- const char *prefix)
-{
- if (res) {
- usbcam_dbg(udp, IOCTL_FMT, "%s %d", prefix, res);
- return;
- }
- usbcam_dbg_v4l2_pix_format(udp, f, prefix);
-}
-
static int usbcam_v4l_vidiocgmbuf(struct file *filp, void *fh,
struct video_mbuf *p)
{
@@ -429,6 +305,47 @@ static int usbcam_v4l_vidiocgmbuf(struct file *filp, void *fh,
return 0;
}
+static void usbcam_dbg_v4l2_buffer_res(struct usbcam_dev *udp, int res,
+ void *arg, const char *prefix)
+{
+ struct v4l2_buffer *b __attribute__((unused)) =
+ (struct v4l2_buffer *) arg;
+
+ if (res) {
+ usbcam_dbg(udp, IOCTL_BUF, "%s res:%d", prefix, res);
+ return;
+ }
+
+ usbcam_dbg(udp, IOCTL_BUF, "%s out: index=%d type=%d bytesused=%d "
+ "flags=0x%x field=%d memory=%d m=0x%lx length=%d",
+ prefix, b->index, b->type, b->bytesused,
+ b->flags, b->field, b->memory, b->m.userptr, b->length);
+}
+
+static void usbcam_dbg_v4l2_pix_format(struct usbcam_dev *udp,
+ struct v4l2_pix_format *f,
+ const char *prefix)
+{
+ __u32 pixfmt = f->pixelformat;
+ if (!pixfmt)
+ pixfmt = 0x3f3f3f3f;
+ usbcam_dbg(udp, IOCTL_FMT, "%s wid=%d hgt=%d fmt=%.4s field=%d "
+ "bpl=%d size=%d cs=%d", prefix,
+ f->width, f->height, (char *) &pixfmt, f->field,
+ f->bytesperline, f->sizeimage, f->colorspace);
+}
+
+static void usbcam_dbg_v4l2_pix_format_res(struct usbcam_dev *udp, int res,
+ struct v4l2_pix_format *f,
+ const char *prefix)
+{
+ if (res) {
+ usbcam_dbg(udp, IOCTL_FMT, "%s %d", prefix, res);
+ return;
+ }
+ usbcam_dbg_v4l2_pix_format(udp, f, prefix);
+}
+
static int usbcam_v4l_vidioc_reqbufs(struct file *filp, void *fh,
struct v4l2_requestbuffers *r)
{
@@ -955,6 +872,295 @@ static int usbcam_v4l_vidioc_s_input(struct file *filp, void *fh,
return 0;
}
+/* Intercept calls to minidriver V4L handler thing for compat calls. */
+static int usbcam_v4l_int_ioctl(struct inode *inodep, struct file *filp,
+ unsigned int cmd, void *arg)
+{
+ struct usbcam_fh *ufp = (struct usbcam_fh *) filp->private_data;
+ struct usbcam_dev *udp = ufp->ufh_dev;
+
+ struct v4l2_buffer buf2;
+ enum v4l2_buf_type captype = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ int err = 0;
+
+
+ if (cmd == VIDIOCGCAP) {
+ struct video_capability *cap = (struct video_capability *) arg;
+
+ usbcam_lock(udp);
+
+ strlcpy(cap->name, udp->ud_vdev.name, sizeof(cap->name));
+ cap->type = VID_TYPE_CAPTURE;
+ cap->audios = 0;
+ cap->channels = 1; /* only one input source, the camera */
+
+ cap->maxwidth = udp->ud_format.width;
+ cap->maxheight = udp->ud_format.height;
+
+ /*
+ * We lie, here. These values normally return 640x480, which is
+ * actually the maximum, not the minimum. Minimum is usually
+ * 160x120. It's sort of useful to lie since lots of software
+ * just stick with the minimum - we want higher res for the
+ * user where possible.
+ */
+
+ cap->minwidth = udp->ud_format.width;
+ cap->minheight = udp->ud_format.height;
+
+ usbcam_unlock(udp);
+ return 0;
+ }
+ else if (cmd == VIDIOCGCHAN) {
+ struct video_channel *chan = (struct video_channel *) arg;
+
+ usbcam_lock(udp);
+
+ chan->channel = 0;
+ strlcpy(chan->name, udp->ud_vdev.name, sizeof(chan->name));
+ chan->tuners = 0;
+ chan->type = VIDEO_TYPE_CAMERA;
+
+ usbcam_unlock(udp);
+ return 0;
+ }
+ else if (cmd == VIDIOCSCHAN) {
+ struct video_channel *chan = (struct video_channel *) arg;
+
+ if (chan->norm != 0)
+ return -EINVAL;
+ return 0;
+ }
+ else if (cmd == VIDIOCGAUDIO) {
+ return -ENOIOCTLCMD;
+ }
+ else if (cmd == VIDIOCGTUNER) {
+ return -ENOIOCTLCMD;
+ }
+ else if (cmd == VIDIOCGPICT) {
+ return -ENOIOCTLCMD;
+ }
+ else if (cmd == VIDIOCGWIN) {
+ struct video_window *win = (struct video_window *) arg;
+
+ usbcam_lock(udp);
+
+ win->x = 0;
+ win->y = 0;
+ win->width = udp->ud_format.width;
+ win->height = udp->ud_format.height;
+ win->chromakey = 0;
+ win->clips = NULL;
+ win->clipcount = 0;
+ win->flags = 0;
+
+ usbcam_unlock(udp);
+ return 0;
+ }
+ else if (cmd == VIDIOCGFBUF) {
+ struct video_buffer *buf = (struct video_buffer *) arg;
+
+ usbcam_lock(udp);
+
+ buf->base = NULL; /* no physical frame buffer access */
+ buf->height = udp->ud_format.height;
+ buf->width = udp->ud_format.width;
+
+ /*
+ * graciously stolen from drivers/media/video/v4l1-compat.c
+ * and modified slightly.
+ */
+ switch (udp->ud_format.pixelformat) {
+ case V4L2_PIX_FMT_RGB332:
+ buf->depth = 8;
+ break;
+ case V4L2_PIX_FMT_RGB555:
+ buf->depth = 15;
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ buf->depth = 16;
+ break;
+ case V4L2_PIX_FMT_BGR24:
+ buf->depth = 24;
+ break;
+ case V4L2_PIX_FMT_BGR32:
+ buf->depth = 32;
+ break;
+ default:
+ buf->depth = 0;
+ }
+
+ if (udp->ud_format.bytesperline) {
+ buf->bytesperline = udp->ud_format.bytesperline;
+
+ /* typically comes out at 16 bit depth as non-rgb */
+ if (!buf->depth && buf->width)
+ buf->depth = ((udp->ud_format.bytesperline<<3)
+ + (buf->width-1) )
+ /buf->width;
+ } else {
+ buf->bytesperline =
+ (buf->width * buf->depth + 7) & 7;
+ buf->bytesperline >>= 3;
+ }
+
+ usbcam_unlock(udp);
+ return 0;
+ }
+ else if (cmd == VIDIOCGMBUF) {
+ struct video_mbuf *mbuf = (struct video_mbuf *) arg;
+ return usbcam_v4l_vidiocgmbuf(filp, filp->private_data, mbuf);
+ }
+ else if (cmd == VIDIOCSFBUF) {
+ usbcam_warn(udp, "VIDIOCSFBUF called.");
+ return -ENOIOCTLCMD;
+ }
+ else if (cmd == VIDIOCSWIN) {
+ return -ENOIOCTLCMD;
+ }
+ else if (cmd == VIDIOCMCAPTURE) {
+ struct v4l2_format *fmt2 = NULL;
+ struct video_mmap *mm = arg;
+
+ fmt2 = kzalloc(sizeof(*fmt2),GFP_KERNEL);
+ memset(&buf2,0,sizeof(buf2));
+
+ fmt2->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ err = usbcam_v4l_vidioc_g_fmt_cap(filp, filp->private_data, fmt2);
+ if (err < 0) {
+ usbcam_dbg(udp, IOCTL_MISC, "VIDIOCMCAPTURE / VIDIOC_G_FMT: %d\n",err);
+ return err;
+ }
+ if (mm->width != fmt2->fmt.pix.width ||
+ mm->height != fmt2->fmt.pix.height ||
+ palette_to_pixelformat(mm->format) !=
+ fmt2->fmt.pix.pixelformat)
+ {/* New capture format... */
+ fmt2->fmt.pix.width = mm->width;
+ fmt2->fmt.pix.height = mm->height;
+ fmt2->fmt.pix.pixelformat =
+ palette_to_pixelformat(mm->format);
+ fmt2->fmt.pix.field = V4L2_FIELD_ANY;
+ fmt2->fmt.pix.bytesperline = 0;
+ err = usbcam_v4l_vidioc_s_fmt_cap(filp, filp->private_data, fmt2);
+ if (err < 0) {
+ usbcam_dbg(udp, IOCTL_MISC, "VIDIOCMCAPTURE / VIDIOC_S_FMT: %d\n",err);
+ return err;
+ }
+ }
+ buf2.index = mm->frame;
+ buf2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ err = usbcam_v4l_vidioc_querybuf(filp, filp->private_data, &buf2);
+ if (err < 0) {
+ usbcam_dbg(udp, IOCTL_MISC, "VIDIOCMCAPTURE / VIDIOC_QUERYBUF: %d\n",err);
+ return err;
+ }
+ err = usbcam_v4l_vidioc_qbuf(filp, filp->private_data, &buf2);
+ if (err < 0) {
+ usbcam_dbg(udp, IOCTL_MISC, "VIDIOCMCAPTURE / VIDIOC_QBUF: %d\n",err);
+ return err;
+ }
+ err = usbcam_v4l_vidioc_streamon(filp, filp->private_data, captype);
+ if (err < 0)
+ usbcam_dbg(udp, IOCTL_MISC, "VIDIOCMCAPTURE / VIDIOC_STREAMON: %d\n",err);
+ return 0;
+ }
+ else if (cmd == VIDIOCSYNC) {
+ int *i = arg;
+
+ memset(&buf2,0,sizeof(buf2));
+ buf2.index = *i;
+ buf2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ err = usbcam_v4l_vidioc_querybuf(filp, filp->private_data, &buf2);
+ if (err < 0) {
+ /* No such buffer */
+ usbcam_dbg(udp, IOCTL_MISC, "VIDIOCSYNC / VIDIOC_QUERYBUF: %d\n",err);
+ return err;
+ }
+ if (!(buf2.flags & V4L2_BUF_FLAG_MAPPED)) {
+ /* Buffer is not mapped */
+ err = -EINVAL;
+ return err;
+ }
+
+ /* make sure capture actually runs so we don't block forever */
+ err = usbcam_v4l_vidioc_streamon(filp, filp->private_data, captype);
+ if (err < 0) {
+ usbcam_dbg(udp, IOCTL_MISC, "VIDIOCSYNC / VIDIOC_STREAMON: %d\n",err);
+ return err;
+ }
+
+ /* 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 = poll_one(filp);
+ if (err < 0 || /* error or sleep was interrupted */
+ err == 0) /* timeout? Shouldn't occur. */
+ return err;
+ err = usbcam_v4l_vidioc_querybuf(filp, filp->private_data, &buf2);
+ if (err < 0)
+ usbcam_dbg(udp, IOCTL_MISC, "VIDIOCSYNC / VIDIOC_QUERYBUF: %d\n",err);
+ }
+ if (!(buf2.flags & V4L2_BUF_FLAG_DONE)) /* not done */
+ return err;
+ do {
+ err = usbcam_v4l_vidioc_dqbuf(filp, filp->private_data, &buf2);
+ if (err < 0)
+ usbcam_dbg(udp, IOCTL_MISC, "VIDIOCSYNC / VIDIOC_DQBUF: %d\n",err);
+ } while (err == 0 && buf2.index != *i);
+ return err;
+ }
+ else {
+ usbcam_warn(udp, "usbcam_v4l_int_ioctl called without valid ioctl");
+ return -ENOIOCTLCMD;
+ }
+}
+
+static int usbcam_v4l_ioctl (struct inode *inodep, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ printk("usbcam: received v4l ioctl: %d\n", cmd);
+
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+ if (_IOC_TYPE(cmd) == 'v')
+ {
+ // run our own internal ioctl handler for these V4L compat ioctl.
+ return video_usercopy(inodep, file, cmd, arg, usbcam_v4l_int_ioctl);
+ }
+#endif
+
+ return video_ioctl2(inodep, file, cmd, arg);
+}
+
+/*
+ * The template file_operations structure
+ *
+ * Each usbcam_minidrv_t contains its own copy of this, which
+ * is associated with the video4linux device created for that
+ * minidriver.
+ *
+ * In general, copies will differ only in the .owner field, which
+ * will refer to the minidriver module, not usbcam.
+ */
+
+struct file_operations usbcam_v4l_fops_template = {
+ .owner = THIS_MODULE,
+ .open = usbcam_v4l_open,
+ .release = usbcam_v4l_release,
+ .read = usbcam_v4l_read,
+ .poll = usbcam_v4l_poll,
+ .mmap = usbcam_v4l_mmap,
+ /*.ioctl = video_ioctl2,*/
+ .ioctl = usbcam_v4l_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = v4l_compat_ioctl32,
+#endif
+ .llseek = no_llseek,
+};
+
+
/*
* The template video_device structure
*