commit 8b04dd28855cb232391a87e6b03a1b5373c94404
parent bf523ae9d68ea89d532d63490fd5f45776fa6e75
Author: alex <alex@022568fa-442e-4ef8-a3e8-54dcafdb011a>
Date: Thu, 17 Jan 2008 05:43:44 +0000
Less breakage wrt driver info ioctls.
git-svn-id: http://svn.mediati.org/svn/r5u870/trunk@39 022568fa-442e-4ef8-a3e8-54dcafdb011a
Diffstat:
M | usbcam/usbcam_fops.c | | | 145 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- |
1 file changed, 143 insertions(+), 2 deletions(-)
diff --git a/usbcam/usbcam_fops.c b/usbcam/usbcam_fops.c
@@ -184,6 +184,117 @@ 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
*
@@ -202,7 +313,8 @@ struct file_operations usbcam_v4l_fops_template = {
.read = usbcam_v4l_read,
.poll = usbcam_v4l_poll,
.mmap = usbcam_v4l_mmap,
- .ioctl = video_ioctl2,
+ /*.ioctl = video_ioctl2,*/
+ .ioctl = usbcam_v4l_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
#endif
@@ -272,7 +384,34 @@ static int usbcam_v4l_vidiocgmbuf(struct file *filp, void *fh,
req.count = 2;
req.memory = V4L2_MEMORY_MMAP;
res = videobuf_reqbufs(&ufp->ufh_vbq, &req);
- if (res) {
+ if (res == -EBUSY)
+ {
+ usbcam_dbg(udp, IOCTL_BUF,
+ "VIDIOCGMBUF reqbufs failed: device was busy"
+ " - closing and trying again.");
+
+ res = videobuf_streamoff(&ufp->ufh_vbq);
+ if (res < 0)
+ {
+ usbcam_dbg(udp, IOCTL_BUF,
+ "VIDIOCGMBUF reqbufs failed:"
+ "couldn't free previous buffer.");
+ return -EBUSY;
+ }
+ else
+ {
+ // we freed previous reqbuf OK.
+ usbcam_lock(udp);
+ ufp->ufh_flags |= USBCAM_FH_USE_FIXED_FB;
+ usbcam_unlock(udp);
+
+ req.type = ufp->ufh_vbq.type;
+ req.count = 2;
+ req.memory = V4L2_MEMORY_MMAP;
+ res = videobuf_reqbufs(&ufp->ufh_vbq, &req);
+ }
+ }
+ else if (res < 0) {
usbcam_dbg(udp, IOCTL_BUF,
"VIDIOCGMBUF reqbufs failed: %d", res);
return res;
@@ -822,6 +961,8 @@ static int usbcam_v4l_vidioc_s_input(struct file *filp, void *fh,
* Each usbcam_dev contains its own copy of this. The minidriver is
* free to install its own handlers for each interface, although it
* should take care not to screw up the frame buffer handling.
+ *
+ * This gets installed via video_register_device() from usb_usbcam_probe().
*/
struct video_device usbcam_videodev_template = {