From 40bad67840aa6856cb39a431510a57d940017898 Mon Sep 17 00:00:00 2001 From: Thierry MERLE Date: Mon, 4 Dec 2006 08:31:24 -0300 Subject: [PATCH] V4L/DVB (4930): Usbvision_v4l2 : mmap corrected to get all frames - 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 Signed-off-by: Mauro Carvalho Chehab --- .../media/video/usbvision/usbvision-core.c | 105 ++++++++++-------- 1 file changed, 59 insertions(+), 46 deletions(-) diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index 3833f3fbbdf..eb8f4ca3a15 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -364,8 +364,6 @@ #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; -- 2.41.0