This is v4l1 support for em28xx split from Markus Rechberger's tree and backported to 2.6.17. This was not submitted as Markus said he will merge his tree with the main v4l tree, which will be merged into the main kernel tree at some stage. [update: a slightly modified version of this was committed on Nov 13th 2007] diff -Naru vanilla/drivers/media/video/em28xx/em28xx-video.c linux-2.6.17.i686/drivers/media/video/em28xx/em28xx-video.c --- vanilla/drivers/media/video/em28xx/em28xx-video.c 2006-06-18 02:49:35.000000000 +0100 +++ linux-2.6.17.i686/drivers/media/video/em28xx/em28xx-video.c 2006-07-28 11:54:33.000000000 +0100 @@ -538,15 +538,15 @@ if (dev->io == IO_READ) { em28xx_queue_unusedframes(dev); - poll_wait(filp, &dev->wait_frame, wait); + } + poll_wait(filp, &dev->wait_frame, wait); - if (!list_empty(&dev->outqueue)) - mask |= POLLIN | POLLRDNORM; + if (!list_empty(&dev->outqueue)) + mask |= POLLIN | POLLRDNORM; - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->fileop_lock); - return mask; - } + return mask; } mutex_unlock(&dev->fileop_lock); @@ -605,8 +605,8 @@ return -EIO; } - if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || - size != PAGE_ALIGN(dev->frame[0].buf.length)) { + if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) /*|| + size != PAGE_ALIGN(dev->frame[0].buf.length)*/) { mutex_unlock(&dev->fileop_lock); return -EINVAL; } @@ -1311,6 +1311,113 @@ case VIDIOC_S_FMT: return em28xx_set_fmt(dev, cmd, (struct v4l2_format *)arg); + /* Next 3 are obsolete v4l1 implementation, but it's still used by some applications, + * (for example VLC). It should be implemented but we don't support it + */ + case VIDIOCGMBUF: + { + struct video_mbuf *mbuf = arg; + int i; + + int gbuffers = EM28XX_NUM_READ_FRAMES; + int gbufsize = PAGE_ALIGN(dev->frame_size); /* max resolution of em28xx based devices */ + +#if 0 + if (fh->type!=V4L2_BUF_TYPE_VIDEO_CAPTURE){ + return -EINVAL; + } +#endif + + if (dev->io != IO_NONE) { + em28xx_videodbg ("method is set to read;" + " close and open the device again to" + " choose the mmap I/O method\n"); + printk("VIDEO_IO is busy!\n"); + return -EBUSY; + } + + mutex_lock_interruptible(&dev->lock); + memset(mbuf,0,sizeof(*mbuf)); + mbuf->frames = gbuffers; + + mbuf->size = gbufsize * gbuffers; + for(i=0;ioffsets[i]=i*gbufsize; + } + + /* FIXME: setting resolution using the v4l1 PICT command */ + + em28xx_empty_framequeues(dev); + + em28xx_release_buffers(dev); + + + if(!em28xx_request_buffers(dev, EM28XX_NUM_READ_FRAMES)){ + printk("em28xx-video.c: unable to map buffers\n"); + return -ENOMEM; + } + + mutex_unlock(&dev->lock); + + dev->stream = STREAM_ON; + em28xx_empty_framequeues(dev); + dev->frame_current=NULL; + dev->io=IO_MMAP; + return 0; + } + case VIDIOCMCAPTURE: + { + struct video_mmap *vm=arg; + unsigned long lock_flags; + + if(vm->format!=VIDEO_PALETTE_YUV422) + return -EINVAL; + + if(dev->frame[vm->frame].state != F_UNUSED){ + return -EAGAIN; + } + + dev->frame[vm->frame].state = F_QUEUED; + + spin_lock_irqsave(&dev->queue_lock, lock_flags); + list_add_tail(&dev->frame[vm->frame].frame, &dev->inqueue); + spin_unlock_irqrestore(&dev->queue_lock, lock_flags); + return 0; + } + case VIDIOCSYNC: + { + /* int *frame = arg; FIXME - argument not used?*/ + struct em28xx_frame_t *f; + unsigned long lock_flags; + int ret = 0; + + if(list_empty(&dev->outqueue)){ + if(dev->stream == STREAM_OFF){ + return -EINVAL; + } + if(filp->f_flags & O_NONBLOCK){ + return -EAGAIN; + } + ret = wait_event_interruptible( + dev->wait_frame, + (!list_empty(&dev->outqueue))|| + (dev->state&DEV_DISCONNECTED)); + if (ret){ + return ret; + } + if(dev->state & DEV_DISCONNECTED){ + return -ENODEV; + } + } + + spin_lock_irqsave(&dev->queue_lock, lock_flags); + f = list_entry(dev->outqueue.next, struct em28xx_frame_t, frame); + list_del(dev->outqueue.next); + spin_unlock_irqrestore(&dev->queue_lock, lock_flags); + f->state = F_UNUSED; + return 0; + } + case VIDIOC_REQBUFS: { struct v4l2_requestbuffers *rb = arg;