V4L/DVB (4930): Usbvision_v4l2 : mmap corrected to get all frames
authorThierry MERLE <thierry.merle@free.fr>
Mon, 4 Dec 2006 11:31:24 +0000 (08:31 -0300)
committerMauro Carvalho Chehab <mchehab@infradead.org>
Sun, 10 Dec 2006 11:05:48 +0000 (09:05 -0200)
- private ioctls UVIOCSREG/UVIOCGREG translated to the
VIDIOC_INT_G_REGISTER/VIDIOC_INT_S_REGISTER
- lost frame bug corrected (mmap rework)
- reset scratch buffer is no buffer is queued (prevents useless scratch
overflow management)

Signed-off-by: Thierry MERLE <thierry.merle@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
drivers/media/video/usbvision/usbvision-core.c

index 3833f3fbbdf0bb73a518849931dba839e2f818a2..eb8f4ca3a15f010e0fe973eef47cf85161fccd9a 100644 (file)
 #endif
 
 #include "usbvision.h"
-#include "usbvision_ioctl.h"
-
 
 #define DRIVER_VERSION "0.9.8.3cvs for Linux kernels 2.4.19-2.4.32 + 2.6.0-2.6.17, compiled at "__DATE__", "__TIME__
 #define EMAIL "joerg@heckenbach-aw.de"
@@ -2320,6 +2318,10 @@ static void usbvision_isocIrq(struct urb *urb, struct pt_regs *regs)
                        }
                }
        }
+       else {
+               PDEBUG(DBG_IRQ, "received data, but no one needs it");
+               scratch_reset(usbvision);
+       }
 
        usbvision->timeInIrq += jiffies - startTime;
 
@@ -3901,41 +3903,50 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
        //      if (debug & DBG_IOCTL) v4l_printk_ioctl(cmd);
 
        switch (cmd) {
-               case UVIOCSREG:
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+               /* ioctls to allow direct acces to the NT100x registers */
+               case VIDIOC_INT_G_REGISTER:
                {
-                       struct usbvision_reg *usbvision_reg = arg;
+                       struct v4l2_register *reg = arg;
                        int errCode;
 
-                       errCode = usbvision_write_reg(usbvision, usbvision_reg->addr, usbvision_reg->value);
-
+                       if (reg->i2c_id != 0)
+                               return -EINVAL;
+                       /* NT100x has a 8-bit register space */
+                       errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
                        if (errCode < 0) {
-                               err("%s: UVIOCSREG failed: error %d", __FUNCTION__, errCode);
+                               err("%s: VIDIOC_INT_G_REGISTER failed: error %d", __FUNCTION__, errCode);
                        }
                        else {
-                               PDEBUG(DBG_IOCTL, "UVIOCSREG addr=0x%02X, value=0x%02X",
-                                                       usbvision_reg->addr, usbvision_reg->value);
-                               errCode = 0;
+                               reg->val=(unsigned char)errCode;
+                               PDEBUG(DBG_IOCTL, "VIDIOC_INT_G_REGISTER reg=0x%02X, value=0x%02X",
+                                                       (unsigned int)reg->reg, reg->val);
+                               errCode = 0; // No error
                        }
                        return errCode;
                }
-               case UVIOCGREG:
+               case VIDIOC_INT_S_REGISTER:
                {
-                       struct usbvision_reg *usbvision_reg = arg;
+                       struct v4l2_register *reg = arg;
                        int errCode;
 
-                       errCode = usbvision_read_reg(usbvision, usbvision_reg->addr);
-
+                       if (reg->i2c_id != 0)
+                               return -EINVAL;
+                       if (!capable(CAP_SYS_ADMIN))
+                               return -EPERM;
+                       errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val);
                        if (errCode < 0) {
-                               err("%s: UVIOCGREG failed: error %d", __FUNCTION__, errCode);
+                               err("%s: VIDIOC_INT_S_REGISTER failed: error %d", __FUNCTION__, errCode);
                        }
                        else {
-                               usbvision_reg->value=(unsigned char)errCode;
-                               PDEBUG(DBG_IOCTL, "UVIOCGREG addr=0x%02X, value=0x%02X",
-                                                       usbvision_reg->addr, usbvision_reg->value);
-                               errCode = 0; // No error
+                               PDEBUG(DBG_IOCTL, "VIDIOC_INT_S_REGISTER reg=0x%02X, value=0x%02X",
+                                                       (unsigned int)reg->reg, reg->val);
+                               errCode = 0;
                        }
-                       return errCode;
+                       return 0;
                }
+#endif
                case VIDIOC_QUERYCAP:
                {
                        struct v4l2_capability *vc=arg;
@@ -4232,12 +4243,9 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
                        if(frame->grabstate == FrameState_Unused)
                                vb->flags |= V4L2_BUF_FLAG_MAPPED;
                        vb->memory = V4L2_MEMORY_MMAP;
-                       if(vb->index == 0) {
-                               vb->m.offset = 0;
-                       }
-                       else {
-                               vb->m.offset = MAX_FRAME_SIZE;
-                       }
+
+                       vb->m.offset = vb->index*MAX_FRAME_SIZE;
+
                        vb->memory = V4L2_MEMORY_MMAP;
                        vb->field = V4L2_FIELD_NONE;
                        vb->length = MAX_FRAME_SIZE;
@@ -4695,40 +4703,45 @@ static ssize_t usbvision_v4l2_read(struct file *file, char *buf,
 
 static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
 {
+       unsigned long size = vma->vm_end - vma->vm_start,
+               start = vma->vm_start;
+       void *pos;
+       u32 i;
+
        struct video_device *dev = video_devdata(file);
        struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
-       unsigned long start = vma->vm_start;
-       unsigned long size  = vma->vm_end-vma->vm_start;
-
-       unsigned long page, pos;
 
        if (!USBVISION_IS_OPERATIONAL(usbvision))
                return -EFAULT;
 
-       if (size > (((USBVISION_NUMFRAMES * usbvision->max_frame_size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
+       if (!(vma->vm_flags & VM_WRITE) ||
+           size != PAGE_ALIGN(usbvision->max_frame_size)) {
+               return -EINVAL;
+       }
+
+       for (i = 0; i < USBVISION_NUMFRAMES; i++) {
+               if (((usbvision->max_frame_size*i) >> PAGE_SHIFT) == vma->vm_pgoff)
+                       break;
+       }
+       if (i == USBVISION_NUMFRAMES) {
+               PDEBUG(DBG_FUNC, "mmap: user supplied mapping address is out of range");
                return -EINVAL;
+       }
 
-       pos = (unsigned long) usbvision->fbuf;
+       /* VM_IO is eventually going to replace PageReserved altogether */
+       vma->vm_flags |= VM_IO;
+       vma->vm_flags |= VM_RESERVED;   /* avoid to swap out this VMA */
+
+       pos = usbvision->frame[i].data;
        while (size > 0) {
 
-// Really ugly....
-       #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)                           //Compatibility for 2.6.10+ kernels
-               page = vmalloc_to_pfn((void *)pos);
-               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-                       return -EAGAIN;
-               }
-       #else                                                                      //Compatibility for 2.6.0 - 2.6.9 kernels
-               page = usbvision_kvirt_to_pa(pos);
-               if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
+               if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
+                       PDEBUG(DBG_FUNC, "mmap: vm_insert_page failed");
                        return -EAGAIN;
                }
-       #endif
                start += PAGE_SIZE;
                pos += PAGE_SIZE;
-               if (size > PAGE_SIZE)
-                       size -= PAGE_SIZE;
-               else
-                       size = 0;
+               size -= PAGE_SIZE;
        }
 
        return 0;