diff options
author | Patrick Boettcher <pb@linuxtv.org> | 2008-04-13 17:53:00 +0200 |
---|---|---|
committer | Patrick Boettcher <pb@linuxtv.org> | 2008-04-13 17:53:00 +0200 |
commit | 86faba43c8df6ebf57a1048e4077d3b00ae3f1cd (patch) | |
tree | 54485f2a2002230d056048686f22cd8f884cab7e /linux/drivers/media | |
parent | c89479a6fe0053481818f497b371c10d74ded242 (diff) | |
parent | cfff1cb68e96dcce0c0880af6db1b4461e19ba9b (diff) | |
download | mediapointer-dvb-s2-86faba43c8df6ebf57a1048e4077d3b00ae3f1cd.tar.gz mediapointer-dvb-s2-86faba43c8df6ebf57a1048e4077d3b00ae3f1cd.tar.bz2 |
merge from main
From: Patrick Boettcher <pb@linuxtv.org>
Signed-off-by: Patrick Boettcher <pb@linuxtv.org>
Diffstat (limited to 'linux/drivers/media')
-rw-r--r-- | linux/drivers/media/video/em28xx/em28xx-core.c | 484 | ||||
-rw-r--r-- | linux/drivers/media/video/em28xx/em28xx-video.c | 1151 | ||||
-rw-r--r-- | linux/drivers/media/video/em28xx/em28xx.h | 95 | ||||
-rw-r--r-- | linux/drivers/media/video/ivtv/ivtv-ioctl.c | 3 | ||||
-rw-r--r-- | linux/drivers/media/video/pwc/pwc-v4l.c | 4 | ||||
-rw-r--r-- | linux/drivers/media/video/videobuf-core.c | 73 | ||||
-rw-r--r-- | linux/drivers/media/video/videobuf-dma-sg.c | 15 | ||||
-rw-r--r-- | linux/drivers/media/video/videobuf-dvb.c | 10 | ||||
-rw-r--r-- | linux/drivers/media/video/videobuf-vmalloc.c | 206 | ||||
-rw-r--r-- | linux/drivers/media/video/videodev.c | 63 | ||||
-rw-r--r-- | linux/drivers/media/video/vivi.c | 4 |
11 files changed, 977 insertions, 1131 deletions
diff --git a/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c index effa1c7c5..97635abb9 100644 --- a/linux/drivers/media/video/em28xx/em28xx-core.c +++ b/linux/drivers/media/video/em28xx/em28xx-core.c @@ -49,138 +49,10 @@ MODULE_PARM_DESC(reg_debug,"enable debug messages [URB reg]"); printk(KERN_INFO "%s %s :"fmt, \ dev->name, __func__ , ##arg); } while (0) -static unsigned int isoc_debug; -module_param(isoc_debug,int,0644); -MODULE_PARM_DESC(isoc_debug,"enable debug messages [isoc transfers]"); - -#define em28xx_isocdbg(fmt, arg...) do {\ - if (isoc_debug) \ - printk(KERN_INFO "%s %s :"fmt, \ - dev->name, __func__ , ##arg); } while (0) - static int alt = EM28XX_PINOUT; module_param(alt, int, 0644); MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint"); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) -#include <linux/mm.h> -static void *rvmalloc(size_t size) -{ - void *mem; - unsigned long adr; - - size = PAGE_ALIGN(size); - - mem = vmalloc_32((unsigned long)size); - if (!mem) - return NULL; - - adr = (unsigned long)mem; - while (size > 0) { - SetPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - - return mem; -} - -static void rvfree(void *mem, size_t size) -{ - unsigned long adr; - - if (!mem) - return; - - size = PAGE_ALIGN(size); - - adr = (unsigned long)mem; - while (size > 0) { - ClearPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - - vfree(mem); -} -#endif - -/* - * em28xx_request_buffers() - * allocate a number of buffers - */ -u32 em28xx_request_buffers(struct em28xx *dev, u32 count) -{ - const size_t imagesize = PAGE_ALIGN(dev->frame_size); /*needs to be page aligned cause the buffers can be mapped individually! */ - void *buff = NULL; - u32 i; - em28xx_coredbg("requested %i buffers with size %zi\n", - count, imagesize); - if (count > EM28XX_NUM_FRAMES) - count = EM28XX_NUM_FRAMES; - - dev->num_frames = count; - while (dev->num_frames > 0) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) - if ((buff = rvmalloc(dev->num_frames * imagesize))) { -#else - if ((buff = vmalloc_32(dev->num_frames * imagesize))) { -#endif - memset(buff, 0, dev->num_frames * imagesize); - break; - } - dev->num_frames--; - } - - for (i = 0; i < dev->num_frames; i++) { - dev->frame[i].bufmem = buff + i * imagesize; - dev->frame[i].buf.index = i; - dev->frame[i].buf.m.offset = i * imagesize; - dev->frame[i].buf.length = dev->frame_size; - dev->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - dev->frame[i].buf.sequence = 0; - dev->frame[i].buf.field = V4L2_FIELD_NONE; - dev->frame[i].buf.memory = V4L2_MEMORY_MMAP; - dev->frame[i].buf.flags = 0; - } - return dev->num_frames; -} - -/* - * em28xx_queue_unusedframes() - * add all frames that are not currently in use to the inbuffer queue - */ -void em28xx_queue_unusedframes(struct em28xx *dev) -{ - unsigned long lock_flags; - u32 i; - - for (i = 0; i < dev->num_frames; i++) - if (dev->frame[i].state == F_UNUSED) { - dev->frame[i].state = F_QUEUED; - spin_lock_irqsave(&dev->queue_lock, lock_flags); - list_add_tail(&dev->frame[i].frame, &dev->inqueue); - spin_unlock_irqrestore(&dev->queue_lock, lock_flags); - } -} - -/* - * em28xx_release_buffers() - * free frame buffers - */ -void em28xx_release_buffers(struct em28xx *dev) -{ - if (dev->num_frames) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) - rvfree(dev->frame[0].bufmem, - dev->num_frames * PAGE_ALIGN(dev->frame[0].buf.length)); -#else - vfree(dev->frame[0].bufmem); -#endif - dev->num_frames = 0; - } -} - /* * em28xx_read_reg_req() * reads data from the usb device specifying bRequest @@ -520,369 +392,17 @@ int em28xx_resolution_set(struct em28xx *dev) return em28xx_scaler_set(dev, dev->hscale, dev->vscale); } - -/******************* isoc transfer handling ****************************/ - -#ifdef ENABLE_DEBUG_ISOC_FRAMES -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) -static void em28xx_isoc_dump(struct urb *urb, struct pt_regs *regs) -#else -static void em28xx_isoc_dump(struct urb *urb) -#endif -{ - int len = 0; - int ntrans = 0; - int i; - - printk(KERN_DEBUG "isocIrq: sf=%d np=%d ec=%x\n", - urb->start_frame, urb->number_of_packets, - urb->error_count); - for (i = 0; i < urb->number_of_packets; i++) { - unsigned char *buf = - urb->transfer_buffer + - urb->iso_frame_desc[i].offset; - int alen = urb->iso_frame_desc[i].actual_length; - if (alen > 0) { - if (buf[0] == 0x88) { - ntrans++; - len += alen; - } else if (buf[0] == 0x22) { - printk(KERN_DEBUG - "= l=%d nt=%d bpp=%d\n", - len - 4 * ntrans, ntrans, - ntrans == 0 ? 0 : len / ntrans); - ntrans = 1; - len = alen; - } else - printk(KERN_DEBUG "!\n"); - } - printk(KERN_DEBUG " n=%d s=%d al=%d %x\n", i, - urb->iso_frame_desc[i].status, - urb->iso_frame_desc[i].actual_length, - (unsigned int) - *((unsigned char *)(urb->transfer_buffer + - urb->iso_frame_desc[i]. - offset))); - } -} -#endif - -static inline int em28xx_isoc_video(struct em28xx *dev,struct em28xx_frame_t **f, - unsigned long *lock_flags, unsigned char buf) -{ - if (!(buf & 0x01)) { - if ((*f)->state == F_GRABBING) { - /*previous frame is incomplete */ - if ((*f)->fieldbytesused < dev->field_size) { - (*f)->state = F_ERROR; - em28xx_isocdbg ("dropping incomplete bottom field (%i missing bytes)", - dev->field_size-(*f)->fieldbytesused); - } else { - (*f)->state = F_DONE; - (*f)->buf.bytesused = dev->frame_size; - } - } - if ((*f)->state == F_DONE || (*f)->state == F_ERROR) { - /* move current frame to outqueue and get next free buffer from inqueue */ - spin_lock_irqsave(&dev-> queue_lock, *lock_flags); - list_move_tail(&(*f)->frame, &dev->outqueue); - if (!list_empty(&dev->inqueue)) - (*f) = list_entry(dev-> inqueue.next, - struct em28xx_frame_t,frame); - else - (*f) = NULL; - spin_unlock_irqrestore(&dev->queue_lock,*lock_flags); - } - if (!(*f)) { - em28xx_isocdbg ("new frame but no buffer is free"); - return -1; - } - do_gettimeofday(&(*f)->buf.timestamp); - (*f)->buf.sequence = ++dev->frame_count; - (*f)->buf.field = V4L2_FIELD_INTERLACED; - (*f)->state = F_GRABBING; - (*f)->buf.bytesused = 0; - (*f)->top_field = 1; - (*f)->fieldbytesused = 0; - } else { - /* acquiring bottom field */ - if ((*f)->state == F_GRABBING) { - if (!(*f)->top_field) { - (*f)->state = F_ERROR; - em28xx_isocdbg ("unexpected begin of bottom field; discarding it"); - } else if ((*f)-> fieldbytesused < dev->field_size - 172) { - (*f)->state = F_ERROR; - em28xx_isocdbg ("dropping incomplete top field (%i missing bytes)", - dev->field_size-(*f)->fieldbytesused); - } else { - (*f)->top_field = 0; - (*f)->fieldbytesused = 0; - } - } - } - return (0); -} - -static inline void em28xx_isoc_video_copy(struct em28xx *dev, - struct em28xx_frame_t **f, unsigned char *buf, int len) -{ - void *fieldstart, *startwrite, *startread; - int linesdone, currlinedone, offset, lencopy,remain; - - if(dev->frame_size != (*f)->buf.length){ - em28xx_err("frame_size %i and buf.length %i are different!!!\n",dev->frame_size,(*f)->buf.length); - return; - } - - if ((*f)->fieldbytesused + len > dev->field_size) - len =dev->field_size - (*f)->fieldbytesused; - - if (buf[0] != 0x88 && buf[0] != 0x22) { - em28xx_isocdbg("frame is not complete\n"); - startread = buf; - len+=4; - } else - startread = buf + 4; - - remain = len; - - if ((*f)->top_field) - fieldstart = (*f)->bufmem; - else - fieldstart = (*f)->bufmem + dev->bytesperline; - - linesdone = (*f)->fieldbytesused / dev->bytesperline; - currlinedone = (*f)->fieldbytesused % dev->bytesperline; - offset = linesdone * dev->bytesperline * 2 + currlinedone; - startwrite = fieldstart + offset; - lencopy = dev->bytesperline - currlinedone; - lencopy = lencopy > remain ? remain : lencopy; - - memcpy(startwrite, startread, lencopy); - remain -= lencopy; - - while (remain > 0) { - startwrite += lencopy + dev->bytesperline; - startread += lencopy; - if (dev->bytesperline > remain) - lencopy = remain; - else - lencopy = dev->bytesperline; - - memcpy(startwrite, startread, lencopy); - remain -= lencopy; - } - - (*f)->fieldbytesused += len; -} - -/* - * em28xx_isoIrq() - * handles the incoming isoc urbs and fills the frames from our inqueue - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) -static void em28xx_isocIrq(struct urb *urb, struct pt_regs *regs) -#else -static void em28xx_isocIrq(struct urb *urb) -#endif -{ - struct em28xx *dev = urb->context; - int i, status; - struct em28xx_frame_t **f; - unsigned long lock_flags; - - if (!dev) - return; -#ifdef ENABLE_DEBUG_ISOC_FRAMES - if (isoc_debug>1) -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) - em28xx_isoc_dump(urb, regs); -#else - em28xx_isoc_dump(urb); -#endif -#endif - - if (urb->status == -ENOENT) - return; - - f = &dev->frame_current; - - if (dev->stream == STREAM_INTERRUPT) { - dev->stream = STREAM_OFF; - if ((*f)) - (*f)->state = F_QUEUED; - em28xx_isocdbg("stream interrupted"); - wake_up_interruptible(&dev->wait_stream); - } - - if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) - return; - - if (dev->stream == STREAM_ON && !list_empty(&dev->inqueue)) { - if (!(*f)) - (*f) = list_entry(dev->inqueue.next, - struct em28xx_frame_t, frame); - - for (i = 0; i < urb->number_of_packets; i++) { - unsigned char *buf = urb->transfer_buffer + - urb->iso_frame_desc[i].offset; - int len = urb->iso_frame_desc[i].actual_length - 4; - - if (urb->iso_frame_desc[i].status) { - em28xx_isocdbg("data error: [%d] len=%d, status=%d", i, - urb->iso_frame_desc[i].actual_length, - urb->iso_frame_desc[i].status); - if (urb->iso_frame_desc[i].status != -EPROTO) - continue; - } - if (urb->iso_frame_desc[i].actual_length <= 0) { - em28xx_isocdbg("packet %d is empty",i); - continue; - } - if (urb->iso_frame_desc[i].actual_length > - urb->iso_frame_desc[i].length) { - em28xx_isocdbg("packet bigger than packet size"); - continue; - } - /*new frame */ - if (buf[0] == 0x22 && buf[1] == 0x5a) { - em28xx_isocdbg("Video frame, length=%i!",len); - - if (em28xx_isoc_video(dev,f,&lock_flags,buf[2])) - break; - } else if (buf[0]==0x33 && buf[1]==0x95 && buf[2]==0x00) { - em28xx_isocdbg("VBI HEADER!!!"); - } - - /* actual copying */ - if ((*f)->state == F_GRABBING) { - em28xx_isoc_video_copy(dev,f,buf, len); - } - } - } - - for (i = 0; i < urb->number_of_packets; i++) { - urb->iso_frame_desc[i].status = 0; - urb->iso_frame_desc[i].actual_length = 0; - } - - urb->status = 0; - if ((status = usb_submit_urb(urb, GFP_ATOMIC))) { - em28xx_errdev("resubmit of urb failed (error=%i)\n", status); - dev->state |= DEV_MISCONFIGURED; - } - wake_up_interruptible(&dev->wait_frame); - return; -} - -/* - * em28xx_uninit_isoc() - * deallocates the buffers and urbs allocated during em28xx_init_iosc() - */ -void em28xx_uninit_isoc(struct em28xx *dev) -{ - int i; - - for (i = 0; i < EM28XX_NUM_BUFS; i++) { - if (dev->urb[i]) { - usb_kill_urb(dev->urb[i]); - if (dev->transfer_buffer[i]) { - usb_buffer_free(dev->udev, - dev->urb[i]->transfer_buffer_length, - dev->transfer_buffer[i], - dev->urb[i]->transfer_dma); - } - usb_free_urb(dev->urb[i]); - } - dev->urb[i] = NULL; - dev->transfer_buffer[i] = NULL; - } - em28xx_capture_start(dev, 0); -} - -/* - * em28xx_init_isoc() - * allocates transfer buffers and submits the urbs for isoc transfer - */ -int em28xx_init_isoc(struct em28xx *dev) -{ - /* change interface to 3 which allows the biggest packet sizes */ - int i, errCode; - int sb_size; - - em28xx_set_alternate(dev); - sb_size = EM28XX_NUM_PACKETS * dev->max_pkt_size; - - /* reset streaming vars */ - dev->frame_current = NULL; - dev->frame_count = 0; - - /* allocate urbs */ - for (i = 0; i < EM28XX_NUM_BUFS; i++) { - struct urb *urb; - int j; - /* allocate transfer buffer */ - urb = usb_alloc_urb(EM28XX_NUM_PACKETS, GFP_KERNEL); - if (!urb){ - em28xx_errdev("cannot alloc urb %i\n", i); - em28xx_uninit_isoc(dev); - return -ENOMEM; - } - dev->transfer_buffer[i] = usb_buffer_alloc(dev->udev, sb_size, - GFP_KERNEL, - &urb->transfer_dma); - if (!dev->transfer_buffer[i]) { - em28xx_errdev - ("unable to allocate %i bytes for transfer buffer %i\n", - sb_size, i); - em28xx_uninit_isoc(dev); - usb_free_urb(urb); - return -ENOMEM; - } - memset(dev->transfer_buffer[i], 0, sb_size); - urb->dev = dev->udev; - urb->context = dev; - urb->pipe = usb_rcvisocpipe(dev->udev, 0x82); - urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; - urb->interval = 1; - urb->transfer_buffer = dev->transfer_buffer[i]; - urb->complete = em28xx_isocIrq; - urb->number_of_packets = EM28XX_NUM_PACKETS; - urb->transfer_buffer_length = sb_size; - for (j = 0; j < EM28XX_NUM_PACKETS; j++) { - urb->iso_frame_desc[j].offset = j * dev->max_pkt_size; - urb->iso_frame_desc[j].length = dev->max_pkt_size; - } - dev->urb[i] = urb; - } - - /* submit urbs */ - em28xx_coredbg("Submitting %d urbs of %d packets (%d each)\n", - EM28XX_NUM_BUFS, EM28XX_NUM_PACKETS, dev->max_pkt_size); - for (i = 0; i < EM28XX_NUM_BUFS; i++) { - errCode = usb_submit_urb(dev->urb[i], GFP_KERNEL); - if (errCode) { - em28xx_errdev("submit of urb %i failed (error=%i)\n", i, - errCode); - em28xx_uninit_isoc(dev); - return errCode; - } - } - - return 0; -} - int em28xx_set_alternate(struct em28xx *dev) { int errCode, prev_alt = dev->alt; int i; - unsigned int min_pkt_size = dev->bytesperline + 4; + unsigned int min_pkt_size = dev->width * 2 + 4; /* When image size is bigger than a certain value, the frame size should be increased, otherwise, only green screen will be received. */ - if (dev->frame_size > 720*240*2) + if (dev->width * 2 * dev->height > 720 * 240 * 2) min_pkt_size *= 2; for (i = 0; i < dev->num_alt; i++) { diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c index 45cdb4820..924f29214 100644 --- a/linux/drivers/media/video/em28xx/em28xx-video.c +++ b/linux/drivers/media/video/em28xx/em28xx-video.c @@ -59,6 +59,19 @@ printk(KERN_INFO "%s %s :"fmt, \ dev->name, __func__ , ##arg); } while (0) +static unsigned int isoc_debug; +module_param(isoc_debug, int, 0644); +MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]"); + +#define em28xx_isocdbg(fmt, arg...) do {\ + if (isoc_debug) \ + printk(KERN_INFO "%s %s :"fmt, \ + dev->name, __func__ , ##arg); } while (0) + +/* Limits minimum and default number of buffers */ +#define EM28XX_MIN_BUF 4 +#define EM28XX_DEF_BUF 8 + MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); @@ -127,6 +140,575 @@ static struct v4l2_queryctrl em28xx_qctrl[] = { static struct usb_driver em28xx_usb_driver; +/* ------------------------------------------------------------------ + DMA and thread functions + ------------------------------------------------------------------*/ + +/* + * Announces that a buffer were filled and request the next + */ +static inline void buffer_filled(struct em28xx *dev, + struct em28xx_dmaqueue *dma_q, + struct em28xx_buffer *buf) +{ + /* Advice that buffer was filled */ + em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i); + buf->vb.state = VIDEOBUF_DONE; + buf->vb.field_count++; + do_gettimeofday(&buf->vb.ts); + + dev->isoc_ctl.buf = NULL; + + list_del(&buf->vb.queue); + wake_up(&buf->vb.done); +} + +/* + * Identify the buffer header type and properly handles + */ +static void em28xx_copy_video(struct em28xx *dev, + struct em28xx_dmaqueue *dma_q, + struct em28xx_buffer *buf, + unsigned char *p, + unsigned char *outp, unsigned long len) +{ + void *fieldstart, *startwrite, *startread; + int linesdone, currlinedone, offset, lencopy, remain; + int bytesperline = dev->width << 1; + + if (dma_q->pos + len > buf->vb.size) + len = buf->vb.size - dma_q->pos; + + if (p[0] != 0x88 && p[0] != 0x22) { + em28xx_isocdbg("frame is not complete\n"); + len += 4; + } else + p += 4; + + startread = p; + remain = len; + + /* Interlaces frame */ + if (buf->top_field) + fieldstart = outp; + else + fieldstart = outp + bytesperline; + + linesdone = dma_q->pos / bytesperline; + currlinedone = dma_q->pos % bytesperline; + offset = linesdone * bytesperline * 2 + currlinedone; + startwrite = fieldstart + offset; + lencopy = bytesperline - currlinedone; + lencopy = lencopy > remain ? remain : lencopy; + + if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) { + em28xx_isocdbg("Overflow of %zi bytes past buffer end (1)\n", + ((char *)startwrite + lencopy) - + ((char *)outp + buf->vb.size)); + lencopy = remain = (char *)outp + buf->vb.size - (char *)startwrite; + } + if (lencopy <= 0) + return; + memcpy(startwrite, startread, lencopy); + + remain -= lencopy; + + while (remain > 0) { + startwrite += lencopy + bytesperline; + startread += lencopy; + if (bytesperline > remain) + lencopy = remain; + else + lencopy = bytesperline; + + if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) { + em28xx_isocdbg("Overflow of %zi bytes past buffer end (2)\n", + ((char *)startwrite + lencopy) - + ((char *)outp + buf->vb.size)); + lencopy = remain = (char *)outp + buf->vb.size - + (char *)startwrite; + } + if (lencopy <= 0) + break; + + memcpy(startwrite, startread, lencopy); + + remain -= lencopy; + } + + dma_q->pos += len; +} + +static inline void print_err_status(struct em28xx *dev, + int packet, int status) +{ + char *errmsg = "Unknown"; + + switch (status) { + case -ENOENT: + errmsg = "unlinked synchronuously"; + break; + case -ECONNRESET: + errmsg = "unlinked asynchronuously"; + break; + case -ENOSR: + errmsg = "Buffer error (overrun)"; + break; + case -EPIPE: + errmsg = "Stalled (device not responding)"; + break; + case -EOVERFLOW: + errmsg = "Babble (bad cable?)"; + break; + case -EPROTO: + errmsg = "Bit-stuff error (bad cable?)"; + break; + case -EILSEQ: + errmsg = "CRC/Timeout (could be anything)"; + break; + case -ETIME: + errmsg = "Device does not respond"; + break; + } + if (packet < 0) { + em28xx_isocdbg("URB status %d [%s].\n", status, errmsg); + } else { + em28xx_isocdbg("URB packet %d, status %d [%s].\n", + packet, status, errmsg); + } +} + +/* + * video-buf generic routine to get the next available buffer + */ +static inline void get_next_buf(struct em28xx_dmaqueue *dma_q, + struct em28xx_buffer **buf) +{ + struct em28xx *dev = container_of(dma_q, struct em28xx, vidq); +#if 1 + char *outp; +#endif + + if (list_empty(&dma_q->active)) { + em28xx_isocdbg("No active queue to serve\n"); + dev->isoc_ctl.buf = NULL; + *buf = NULL; + return; + } + + /* Get the next buffer */ + *buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue); + +#if 1 + /* Cleans up buffer - Usefull for testing for frame/URB loss */ + outp = videobuf_to_vmalloc(&(*buf)->vb); + memset(outp, 0, (*buf)->vb.size); +#endif + + dev->isoc_ctl.buf = *buf; + + return; +} + +/* + * Controls the isoc copy of each urb packet + */ +static inline int em28xx_isoc_copy(struct urb *urb) +{ + struct em28xx_buffer *buf; + struct em28xx_dmaqueue *dma_q = urb->context; + struct em28xx *dev = container_of(dma_q, struct em28xx, vidq); + unsigned char *outp = NULL; + int i, len = 0, rc = 1; + unsigned char *p; + + if (!dev) + return 0; + + if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) + return 0; + + if (urb->status < 0) { + print_err_status(dev, -1, urb->status); + if (urb->status == -ENOENT) + return 0; + } + + buf = dev->isoc_ctl.buf; + if (buf != NULL) + outp = videobuf_to_vmalloc(&buf->vb); + + for (i = 0; i < urb->number_of_packets; i++) { + int status = urb->iso_frame_desc[i].status; + + if (status < 0) { + print_err_status(dev, i, status); + if (urb->iso_frame_desc[i].status != -EPROTO) + continue; + } + + len = urb->iso_frame_desc[i].actual_length - 4; + + if (urb->iso_frame_desc[i].actual_length <= 0) { + /* em28xx_isocdbg("packet %d is empty",i); - spammy */ + continue; + } + if (urb->iso_frame_desc[i].actual_length > + dev->max_pkt_size) { + em28xx_isocdbg("packet bigger than packet size"); + continue; + } + + p = urb->transfer_buffer + urb->iso_frame_desc[i].offset; + + /* FIXME: incomplete buffer checks where removed to make + logic simpler. Impacts of those changes should be evaluated + */ + if (p[0] == 0x33 && p[1] == 0x95 && p[2] == 0x00) { + em28xx_isocdbg("VBI HEADER!!!\n"); + /* FIXME: Should add vbi copy */ + continue; + } + if (p[0] == 0x22 && p[1] == 0x5a) { + em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2], + len, (p[2] & 1)? "odd" : "even"); + + if (!(p[2] & 1)) { + if (buf != NULL) + buffer_filled(dev, dma_q, buf); + get_next_buf(dma_q, &buf); + if (buf == NULL) + outp = NULL; + else + outp = videobuf_to_vmalloc(&buf->vb); + } + + if (buf != NULL) { + if (p[2] & 1) + buf->top_field = 0; + else + buf->top_field = 1; + } + + dma_q->pos = 0; + } + if (buf != NULL) + em28xx_copy_video(dev, dma_q, buf, p, outp, len); + } + return rc; +} + +/* ------------------------------------------------------------------ + URB control + ------------------------------------------------------------------*/ + +/* + * IRQ callback, called by URB callback + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) +static void em28xx_irq_callback(struct urb *urb, struct pt_regs *regs) +#else +static void em28xx_irq_callback(struct urb *urb) +#endif +{ + struct em28xx_dmaqueue *dma_q = urb->context; + struct em28xx *dev = container_of(dma_q, struct em28xx, vidq); + int rc, i; + + /* Copy data from URB */ + spin_lock(&dev->slock); + rc = em28xx_isoc_copy(urb); + spin_unlock(&dev->slock); + + /* Reset urb buffers */ + for (i = 0; i < urb->number_of_packets; i++) { + urb->iso_frame_desc[i].status = 0; + urb->iso_frame_desc[i].actual_length = 0; + } + urb->status = 0; + + urb->status = usb_submit_urb(urb, GFP_ATOMIC); + if (urb->status) { + em28xx_err("urb resubmit failed (error=%i)\n", + urb->status); + } +} + +/* + * Stop and Deallocate URBs + */ +static void em28xx_uninit_isoc(struct em28xx *dev) +{ + struct urb *urb; + int i; + + em28xx_isocdbg("em28xx: called em28xx_uninit_isoc\n"); + + dev->isoc_ctl.nfields = -1; + for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { + urb = dev->isoc_ctl.urb[i]; + if (urb) { + usb_kill_urb(urb); + usb_unlink_urb(urb); + if (dev->isoc_ctl.transfer_buffer[i]) { + usb_buffer_free(dev->udev, + urb->transfer_buffer_length, + dev->isoc_ctl.transfer_buffer[i], + urb->transfer_dma); + } + usb_free_urb(urb); + dev->isoc_ctl.urb[i] = NULL; + } + dev->isoc_ctl.transfer_buffer[i] = NULL; + } + + kfree(dev->isoc_ctl.urb); + kfree(dev->isoc_ctl.transfer_buffer); + dev->isoc_ctl.urb = NULL; + dev->isoc_ctl.transfer_buffer = NULL; + + dev->isoc_ctl.num_bufs = 0; + + em28xx_capture_start(dev, 0); +} + +/* + * Allocate URBs and start IRQ + */ +static int em28xx_prepare_isoc(struct em28xx *dev, int max_packets, + int num_bufs) +{ + struct em28xx_dmaqueue *dma_q = &dev->vidq; + int i; + int sb_size, pipe; + struct urb *urb; + int j, k; + + em28xx_isocdbg("em28xx: called em28xx_prepare_isoc\n"); + + /* De-allocates all pending stuff */ + em28xx_uninit_isoc(dev); + + dev->isoc_ctl.num_bufs = num_bufs; + + dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL); + if (!dev->isoc_ctl.urb) { + em28xx_errdev("cannot alloc memory for usb buffers\n"); + return -ENOMEM; + } + + dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs, + GFP_KERNEL); + if (!dev->isoc_ctl.urb) { + em28xx_errdev("cannot allocate memory for usbtransfer\n"); + kfree(dev->isoc_ctl.urb); + return -ENOMEM; + } + + dev->isoc_ctl.max_pkt_size = dev->max_pkt_size; + dev->isoc_ctl.buf = NULL; + + sb_size = max_packets * dev->isoc_ctl.max_pkt_size; + + /* allocate urbs and transfer buffers */ + for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { + urb = usb_alloc_urb(max_packets, GFP_KERNEL); + if (!urb) { + em28xx_err("cannot alloc isoc_ctl.urb %i\n", i); + em28xx_uninit_isoc(dev); + return -ENOMEM; + } + dev->isoc_ctl.urb[i] = urb; + + dev->isoc_ctl.transfer_buffer[i] = usb_buffer_alloc(dev->udev, + sb_size, GFP_KERNEL, &urb->transfer_dma); + if (!dev->isoc_ctl.transfer_buffer[i]) { + em28xx_err("unable to allocate %i bytes for transfer" + " buffer %i%s\n", + sb_size, i, + in_interrupt()?" while in int":""); + em28xx_uninit_isoc(dev); + return -ENOMEM; + } + memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size); + + /* FIXME: this is a hack - should be + 'desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK' + should also be using 'desc.bInterval' + */ + pipe = usb_rcvisocpipe(dev->udev, 0x82); + usb_fill_int_urb(urb, dev->udev, pipe, + dev->isoc_ctl.transfer_buffer[i], sb_size, + em28xx_irq_callback, dma_q, 1); + + urb->number_of_packets = max_packets; + urb->transfer_flags = URB_ISO_ASAP; + + k = 0; + for (j = 0; j < max_packets; j++) { + urb->iso_frame_desc[j].offset = k; + urb->iso_frame_desc[j].length = + dev->isoc_ctl.max_pkt_size; + k += dev->isoc_ctl.max_pkt_size; + } + } + + return 0; +} + +static int em28xx_start_thread(struct em28xx_dmaqueue *dma_q) +{ + struct em28xx *dev = container_of(dma_q, struct em28xx, vidq); + int i, rc = 0; + + em28xx_videodbg("Called em28xx_start_thread\n"); + + init_waitqueue_head(&dma_q->wq); + + em28xx_capture_start(dev, 1); + + /* submit urbs and enables IRQ */ + for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { + rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC); + if (rc) { + em28xx_err("submit of urb %i failed (error=%i)\n", i, + rc); + em28xx_uninit_isoc(dev); + return rc; + } + } + + if (rc < 0) + return rc; + + return 0; +} + +/* ------------------------------------------------------------------ + Videobuf operations + ------------------------------------------------------------------*/ + +static int +buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) +{ + struct em28xx_fh *fh = vq->priv_data; + + *size = 16 * fh->dev->width * fh->dev->height >> 3; + if (0 == *count) + *count = EM28XX_DEF_BUF; + + if (*count < EM28XX_MIN_BUF) + *count = EM28XX_MIN_BUF; + + return 0; +} + +/* This is called *without* dev->slock held; please keep it that way */ +static void free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf) +{ + struct em28xx_fh *fh = vq->priv_data; + struct em28xx *dev = fh->dev; + unsigned long flags = 0; + if (in_interrupt()) + BUG(); + + /* We used to wait for the buffer to finish here, but this didn't work + because, as we were keeping the state as VIDEOBUF_QUEUED, + videobuf_queue_cancel marked it as finished for us. + (Also, it could wedge forever if the hardware was misconfigured.) + + This should be safe; by the time we get here, the buffer isn't + queued anymore. If we ever start marking the buffers as + VIDEOBUF_ACTIVE, it won't be, though. + */ + spin_lock_irqsave(&dev->slock, flags); + if (dev->isoc_ctl.buf == buf) + dev->isoc_ctl.buf = NULL; + spin_unlock_irqrestore(&dev->slock, flags); + + videobuf_vmalloc_free(&buf->vb); + buf->vb.state = VIDEOBUF_NEEDS_INIT; +} + +static int +buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct em28xx_fh *fh = vq->priv_data; + struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb); + struct em28xx *dev = fh->dev; + struct em28xx_dmaqueue *vidq = &dev->vidq; + int rc = 0, urb_init = 0; + + /* FIXME: It assumes depth = 16 */ + /* The only currently supported format is 16 bits/pixel */ + buf->vb.size = 16 * dev->width * dev->height >> 3; + + if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) + return -EINVAL; + + buf->vb.width = dev->width; + buf->vb.height = dev->height; + buf->vb.field = field; + + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + rc = videobuf_iolock(vq, &buf->vb, NULL); + if (rc < 0) + goto fail; + } + + if (!dev->isoc_ctl.num_bufs) + urb_init = 1; + + if (urb_init) { + rc = em28xx_prepare_isoc(dev, EM28XX_NUM_PACKETS, + EM28XX_NUM_BUFS); + if (rc < 0) + goto fail; + + rc = em28xx_start_thread(vidq); + if (rc < 0) + goto fail; + } + + buf->vb.state = VIDEOBUF_PREPARED; + return 0; + +fail: + free_buffer(vq, buf); + return rc; +} + +static void +buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +{ + struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb); + struct em28xx_fh *fh = vq->priv_data; + struct em28xx *dev = fh->dev; + struct em28xx_dmaqueue *vidq = &dev->vidq; + + buf->vb.state = VIDEOBUF_QUEUED; + list_add_tail(&buf->vb.queue, &vidq->active); + +} + +static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb) +{ + struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb); + struct em28xx_fh *fh = vq->priv_data; + struct em28xx *dev = (struct em28xx *)fh->dev; + + em28xx_isocdbg("em28xx: called buffer_release\n"); + + free_buffer(vq, buf); +} + +static struct videobuf_queue_ops em28xx_video_qops = { + .buf_setup = buffer_setup, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .buf_release = buffer_release, +}; /********************* v4l2 interface ******************************************/ @@ -174,23 +756,6 @@ static void em28xx_config_i2c(struct em28xx *dev) em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL); } -/* - * em28xx_empty_framequeues() - * prepare queues for incoming and outgoing frames - */ -static void em28xx_empty_framequeues(struct em28xx *dev) -{ - u32 i; - - INIT_LIST_HEAD(&dev->inqueue); - INIT_LIST_HEAD(&dev->outqueue); - - for (i = 0; i < EM28XX_NUM_FRAMES; i++) { - dev->frame[i].state = F_UNUSED; - dev->frame[i].buf.bytesused = 0; - } -} - static void video_mux(struct em28xx *dev, int index) { struct v4l2_routing route; @@ -224,15 +789,12 @@ static int res_get(struct em28xx_fh *fh) if (fh->stream_on) return rc; - mutex_lock(&dev->lock); - if (dev->stream_on) - rc = -EINVAL; - else { - dev->stream_on = 1; - fh->stream_on = 1; - } + return -EINVAL; + mutex_lock(&dev->lock); + dev->stream_on = 1; + fh->stream_on = 1; mutex_unlock(&dev->lock); return rc; } @@ -253,33 +815,6 @@ static void res_free(struct em28xx_fh *fh) } /* - * em28xx_vm_open() - */ -static void em28xx_vm_open(struct vm_area_struct *vma) -{ - struct em28xx_frame_t *f = vma->vm_private_data; - f->vma_use_count++; -} - -/* - * em28xx_vm_close() - */ -static void em28xx_vm_close(struct vm_area_struct *vma) -{ - /* NOTE: buffers are not freed here */ - struct em28xx_frame_t *f = vma->vm_private_data; - - if (f->vma_use_count) - f->vma_use_count--; -} - -static struct vm_operations_struct em28xx_vm_ops = { - .open = em28xx_vm_open, - .close = em28xx_vm_close, -}; - - -/* * em28xx_get_ctrl() * return the current saturation, brightness or contrast, mute state */ @@ -318,34 +853,6 @@ static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl) } } -/* - * em28xx_stream_interrupt() - * stops streaming - */ -static int em28xx_stream_interrupt(struct em28xx *dev) -{ - int rc = 0; - - /* stop reading from the device */ - - dev->stream = STREAM_INTERRUPT; - rc = wait_event_timeout(dev->wait_stream, - (dev->stream == STREAM_OFF) || - (dev->state & DEV_DISCONNECTED), - EM28XX_URB_TIMEOUT); - - if (rc) { - dev->state |= DEV_MISCONFIGURED; - em28xx_videodbg("device is misconfigured; close and " - "open /dev/video%d again\n", - dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN); - return rc; - } - - return 0; -} - - static int check_dev(struct em28xx *dev) { if (dev->state & DEV_DISCONNECTED) { @@ -392,8 +899,8 @@ static int vidioc_g_fmt_cap(struct file *file, void *priv, f->fmt.pix.width = dev->width; f->fmt.pix.height = dev->height; f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; - f->fmt.pix.bytesperline = dev->bytesperline; - f->fmt.pix.sizeimage = dev->frame_size; + f->fmt.pix.bytesperline = dev->width * 2; + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * dev->height; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */ @@ -469,7 +976,7 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv, { struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; - int rc, i; + int rc; rc = check_dev(dev); if (rc < 0) @@ -479,44 +986,29 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv, mutex_lock(&dev->lock); - for (i = 0; i < dev->num_frames; i++) - if (dev->frame[i].vma_use_count) { - em28xx_videodbg("VIDIOC_S_FMT failed. " - "Unmap the buffers first.\n"); - rc = -EINVAL; - goto err; - } - - /* stop io in case it is already in progress */ - if (dev->stream == STREAM_ON) { - em28xx_videodbg("VIDIOC_SET_FMT: interrupting stream\n"); - rc = em28xx_stream_interrupt(dev); - if (rc < 0) - goto err; + if (videobuf_queue_is_busy(&fh->vb_vidq)) { + em28xx_errdev("%s queue busy\n", __func__); + rc = -EBUSY; + goto out; } - em28xx_release_buffers(dev); - dev->io = IO_NONE; + if (dev->stream_on && !fh->stream_on) { + em28xx_errdev("%s device in use by another fh\n", __func__); + rc = -EBUSY; + goto out; + } /* set new image size */ dev->width = f->fmt.pix.width; dev->height = f->fmt.pix.height; - dev->frame_size = dev->width * dev->height * 2; - dev->field_size = dev->frame_size >> 1; - dev->bytesperline = dev->width * 2; get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale); - /* FIXME: This is really weird! Why capture is starting with - this ioctl ??? - */ - em28xx_uninit_isoc(dev); em28xx_set_alternate(dev); - em28xx_capture_start(dev, 1); em28xx_resolution_set(dev); - em28xx_init_isoc(dev); + rc = 0; -err: +out: mutex_unlock(&dev->lock); return rc; } @@ -546,9 +1038,6 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) /* set new image size */ dev->width = f.fmt.pix.width; dev->height = f.fmt.pix.height; - dev->frame_size = dev->width * dev->height * 2; - dev->field_size = dev->frame_size >> 1; - dev->bytesperline = dev->width * 2; get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale); em28xx_resolution_set(dev); @@ -940,23 +1429,11 @@ static int vidioc_streamon(struct file *file, void *priv, if (rc < 0) return rc; - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP) - return -EINVAL; - - if (list_empty(&dev->inqueue)) - return -EINVAL; - mutex_lock(&dev->lock); - - if (unlikely(res_get(fh) < 0)) { - mutex_unlock(&dev->lock); + if (unlikely(res_get(fh) < 0)) return -EBUSY; - } - dev->stream = STREAM_ON; /* FIXME: Start video capture here? */ - - mutex_unlock(&dev->lock); - return 0; + return (videobuf_streamon(&fh->vb_vidq)); } static int vidioc_streamoff(struct file *file, void *priv, @@ -970,23 +1447,14 @@ static int vidioc_streamoff(struct file *file, void *priv, if (rc < 0) return rc; - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP) + if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (type != fh->type) return -EINVAL; - mutex_lock(&dev->lock); - - if (dev->stream == STREAM_ON) { - em28xx_videodbg("VIDIOC_STREAMOFF: interrupting stream\n"); - rc = em28xx_stream_interrupt(dev); - if (rc < 0) { - mutex_unlock(&dev->lock); - return rc; - } - } - - em28xx_empty_framequeues(dev); + videobuf_streamoff(&fh->vb_vidq); + res_free(fh); - mutex_unlock(&dev->lock); return 0; } @@ -1117,53 +1585,13 @@ static int vidioc_reqbufs(struct file *file, void *priv, { struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; - u32 i; int rc; rc = check_dev(dev); if (rc < 0) return rc; - if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - rb->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - if (dev->io == IO_READ) { - em28xx_videodbg("method is set to read;" - " close and open the device again to" - " choose the mmap I/O method\n"); - return -EINVAL; - } - - for (i = 0; i < dev->num_frames; i++) - if (dev->frame[i].vma_use_count) { - em28xx_videodbg("VIDIOC_REQBUFS failed; " - "previous buffers are still mapped\n"); - return -EINVAL; - } - - mutex_lock(&dev->lock); - - if (dev->stream == STREAM_ON) { - em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n"); - rc = em28xx_stream_interrupt(dev); - if (rc < 0) { - mutex_unlock(&dev->lock); - return rc; - } - } - - em28xx_empty_framequeues(dev); - - em28xx_release_buffers(dev); - if (rb->count) - rb->count = em28xx_request_buffers(dev, rb->count); - - dev->frame_current = NULL; - dev->io = rb->count ? IO_MMAP : IO_NONE; - - mutex_unlock(&dev->lock); - return 0; + return (videobuf_reqbufs(&fh->vb_vidq, rb)); } static int vidioc_querybuf(struct file *file, void *priv, @@ -1177,52 +1605,20 @@ static int vidioc_querybuf(struct file *file, void *priv, if (rc < 0) return rc; - if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - b->index >= dev->num_frames || dev->io != IO_MMAP) - return -EINVAL; - - mutex_lock(&dev->lock); - - memcpy(b, &dev->frame[b->index].buf, sizeof(*b)); - - if (dev->frame[b->index].vma_use_count) - b->flags |= V4L2_BUF_FLAG_MAPPED; - - if (dev->frame[b->index].state == F_DONE) - b->flags |= V4L2_BUF_FLAG_DONE; - else if (dev->frame[b->index].state != F_UNUSED) - b->flags |= V4L2_BUF_FLAG_QUEUED; - - mutex_unlock(&dev->lock); - return 0; + return (videobuf_querybuf(&fh->vb_vidq, b)); } static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) { struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; - unsigned long lock_flags; int rc; rc = check_dev(dev); if (rc < 0) return rc; - if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP || - b->index >= dev->num_frames) - return -EINVAL; - - if (dev->frame[b->index].state != F_UNUSED) - return -EAGAIN; - - dev->frame[b->index].state = F_QUEUED; - - /* add frame to fifo */ - spin_lock_irqsave(&dev->queue_lock, lock_flags); - list_add_tail(&dev->frame[b->index].frame, &dev->inqueue); - spin_unlock_irqrestore(&dev->queue_lock, lock_flags); - - return 0; + return (videobuf_qbuf(&fh->vb_vidq, b)); } static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) @@ -1230,46 +1626,24 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; int rc; - struct em28xx_frame_t *f; - unsigned long lock_flags; rc = check_dev(dev); if (rc < 0) return rc; - if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP) - return -EINVAL; - - if (list_empty(&dev->outqueue)) { - if (dev->stream == STREAM_OFF) - return -EINVAL; - - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - - rc = wait_event_interruptible(dev->wait_frame, - (!list_empty(&dev->outqueue)) || - (dev->state & DEV_DISCONNECTED)); - if (rc) - return rc; - - 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; - memcpy(b, &f->buf, sizeof(*b)); + return (videobuf_dqbuf(&fh->vb_vidq, b, + file->f_flags & O_NONBLOCK)); +} - if (f->vma_use_count) - b->flags |= V4L2_BUF_FLAG_MAPPED; +#ifdef CONFIG_VIDEO_V4L1_COMPAT +static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) +{ + struct em28xx_fh *fh = priv; - return 0; + return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8); } +#endif + /* ----------------------------------------------------------- */ /* RADIO ESPECIFIC IOCTLS */ @@ -1377,15 +1751,16 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) int errCode = 0, radio = 0; struct em28xx *h,*dev = NULL; struct em28xx_fh *fh; + enum v4l2_buf_type fh_type = 0; list_for_each_entry(h, &em28xx_devlist, devlist) { if (h->vdev->minor == minor) { dev = h; - dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; } if (h->vbi_dev->minor == minor) { dev = h; - dev->type = V4L2_BUF_TYPE_VBI_CAPTURE; + fh_type = V4L2_BUF_TYPE_VBI_CAPTURE; } if (h->radio_dev && h->radio_dev->minor == minor) { @@ -1397,7 +1772,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) return -ENODEV; em28xx_videodbg("open minor=%d type=%s users=%d\n", - minor,v4l2_type_names[dev->type],dev->users); + minor, v4l2_type_names[fh_type], dev->users); fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL); @@ -1408,32 +1783,22 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) mutex_lock(&dev->lock); fh->dev = dev; fh->radio = radio; + fh->type = fh_type; filp->private_data = fh; - if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { dev->width = norm_maxw(dev); dev->height = norm_maxh(dev); - dev->frame_size = dev->width * dev->height * 2; - dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */ - dev->bytesperline = dev->width * 2; dev->hscale = 0; dev->vscale = 0; em28xx_set_alternate(dev); - em28xx_capture_start(dev, 1); em28xx_resolution_set(dev); #if 0 /* device needs to be initialized before isoc transfer */ video_mux(dev, 0); #endif - - /* start the transfer */ - errCode = em28xx_init_isoc(dev); - if (errCode) - goto err; - - em28xx_empty_framequeues(dev); } if (fh->radio) { em28xx_videodbg("video_open: setting radio device\n"); @@ -1445,7 +1810,10 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) dev->users++; -err: + videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops, + NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED, + sizeof(struct em28xx_buffer), fh); + mutex_unlock(&dev->lock); return errCode; } @@ -1511,9 +1879,8 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp) mutex_lock(&dev->lock); if (dev->users == 1) { - em28xx_uninit_isoc(dev); - em28xx_release_buffers(dev); - dev->io = IO_NONE; + videobuf_stop(&fh->vb_vidq); + videobuf_mmap_free(&fh->vb_vidq); /* the device is already disconnect, free the remaining resources */ @@ -1524,6 +1891,9 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp) return 0; } + /* do this before setting alternate! */ + em28xx_uninit_isoc(dev); + /* set alternate 0 */ dev->alt = 0; em28xx_videodbg("setting alternate 0\n"); @@ -1546,134 +1916,28 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp) */ static ssize_t em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, - loff_t * f_pos) + loff_t *pos) { - struct em28xx_frame_t *f, *i; - unsigned long lock_flags; - int ret = 0; struct em28xx_fh *fh = filp->private_data; struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; /* FIXME: read() is not prepared to allow changing the video resolution while streaming. Seems a bug at em28xx_set_fmt */ - if (unlikely(res_get(fh) < 0)) - return -EBUSY; - - mutex_lock(&dev->lock); - - if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - em28xx_videodbg("V4l2_Buf_type_videocapture is set\n"); + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + if (unlikely(res_get(fh))) + return -EBUSY; - if (dev->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n"); - em28xx_videodbg("not supported yet! ...\n"); - if (copy_to_user(buf, "", 1)) { - mutex_unlock(&dev->lock); - return -EFAULT; - } - mutex_unlock(&dev->lock); - return (1); - } - if (dev->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { - em28xx_videodbg("V4L2_BUF_TYPE_SLICED_VBI_CAPTURE is set\n"); - em28xx_videodbg("not supported yet! ...\n"); - if (copy_to_user(buf, "", 1)) { - mutex_unlock(&dev->lock); - return -EFAULT; - } - mutex_unlock(&dev->lock); - return (1); + return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0, + filp->f_flags & O_NONBLOCK); } - - if (dev->state & DEV_DISCONNECTED) { - em28xx_videodbg("device not present\n"); - mutex_unlock(&dev->lock); - return -ENODEV; - } - - if (dev->state & DEV_MISCONFIGURED) { - em28xx_videodbg("device misconfigured; close and open it again\n"); - mutex_unlock(&dev->lock); - return -EIO; - } - - if (dev->io == IO_MMAP) { - em28xx_videodbg ("IO method is set to mmap; close and open" - " the device again to choose the read method\n"); - mutex_unlock(&dev->lock); - return -EINVAL; - } - - if (dev->io == IO_NONE) { - if (!em28xx_request_buffers(dev, EM28XX_NUM_READ_FRAMES)) { - em28xx_errdev("read failed, not enough memory\n"); - mutex_unlock(&dev->lock); - return -ENOMEM; - } - dev->io = IO_READ; - dev->stream = STREAM_ON; - em28xx_queue_unusedframes(dev); - } - - if (!count) { - mutex_unlock(&dev->lock); - return 0; - } - - if (list_empty(&dev->outqueue)) { - if (filp->f_flags & O_NONBLOCK) { - mutex_unlock(&dev->lock); - return -EAGAIN; - } - ret = wait_event_interruptible - (dev->wait_frame, - (!list_empty(&dev->outqueue)) || - (dev->state & DEV_DISCONNECTED)); - if (ret) { - mutex_unlock(&dev->lock); - return ret; - } - if (dev->state & DEV_DISCONNECTED) { - mutex_unlock(&dev->lock); - return -ENODEV; - } - dev->video_bytesread = 0; - } - - f = list_entry(dev->outqueue.prev, struct em28xx_frame_t, frame); - - em28xx_queue_unusedframes(dev); - - if (count > f->buf.length) - count = f->buf.length; - - if ((dev->video_bytesread + count) > dev->frame_size) - count = dev->frame_size - dev->video_bytesread; - - if (copy_to_user(buf, f->bufmem+dev->video_bytesread, count)) { - em28xx_err("Error while copying to user\n"); - return -EFAULT; - } - dev->video_bytesread += count; - - if (dev->video_bytesread == dev->frame_size) { - spin_lock_irqsave(&dev->queue_lock, lock_flags); - list_for_each_entry(i, &dev->outqueue, frame) - i->state = F_UNUSED; - INIT_LIST_HEAD(&dev->outqueue); - spin_unlock_irqrestore(&dev->queue_lock, lock_flags); - - em28xx_queue_unusedframes(dev); - dev->video_bytesread = 0; - } - - *f_pos += count; - - mutex_unlock(&dev->lock); - - return count; + return 0; } /* @@ -1682,46 +1946,21 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, */ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait) { - unsigned int mask = 0; struct em28xx_fh *fh = filp->private_data; struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; if (unlikely(res_get(fh) < 0)) return POLLERR; - mutex_lock(&dev->lock); - - if (dev->state & DEV_DISCONNECTED) { - em28xx_videodbg("device not present\n"); - } else if (dev->state & DEV_MISCONFIGURED) { - em28xx_videodbg("device is misconfigured; close and open it again\n"); - } else { - if (dev->io == IO_NONE) { - if (!em28xx_request_buffers - (dev, EM28XX_NUM_READ_FRAMES)) { - em28xx_warn - ("poll() failed, not enough memory\n"); - } else { - dev->io = IO_READ; - dev->stream = STREAM_ON; - } - } - - if (dev->io == IO_READ) { - em28xx_queue_unusedframes(dev); - poll_wait(filp, &dev->wait_frame, wait); - - if (!list_empty(&dev->outqueue)) - mask |= POLLIN | POLLRDNORM; - - mutex_unlock(&dev->lock); - - return mask; - } - } + if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) + return POLLERR; - mutex_unlock(&dev->lock); - return POLLERR; + return videobuf_poll_stream(filp, &fh->vb_vidq, wait); } /* @@ -1731,69 +1970,23 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) { struct em28xx_fh *fh = filp->private_data; struct em28xx *dev = fh->dev; - unsigned long size = vma->vm_end - vma->vm_start; - unsigned long start = vma->vm_start; - void *pos; - u32 i; + int rc; if (unlikely(res_get(fh) < 0)) return -EBUSY; - mutex_lock(&dev->lock); - - if (dev->state & DEV_DISCONNECTED) { - em28xx_videodbg("mmap: device not present\n"); - mutex_unlock(&dev->lock); - return -ENODEV; - } - - if (dev->state & DEV_MISCONFIGURED) { - em28xx_videodbg ("mmap: Device is misconfigured; close and " - "open it again\n"); - mutex_unlock(&dev->lock); - return -EIO; - } - - if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE)) { - mutex_unlock(&dev->lock); - return -EINVAL; - } - - if (size > PAGE_ALIGN(dev->frame[0].buf.length)) - size = PAGE_ALIGN(dev->frame[0].buf.length); - - for (i = 0; i < dev->num_frames; i++) { - if ((dev->frame[i].buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff) - break; - } - if (i == dev->num_frames) { - em28xx_videodbg("mmap: user supplied mapping address is out of range\n"); - mutex_unlock(&dev->lock); - return -EINVAL; - } + rc = check_dev(dev); + if (rc < 0) + return rc; - /* 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 */ + rc = videobuf_mmap_mapper(&fh->vb_vidq, vma); - pos = dev->frame[i].bufmem; - while (size > 0) { /* size is page-aligned */ - if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { - em28xx_videodbg("mmap: vm_insert_page failed\n"); - mutex_unlock(&dev->lock); - return -EAGAIN; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - size -= PAGE_SIZE; - } + em28xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n", + (unsigned long)vma->vm_start, + (unsigned long)vma->vm_end-(unsigned long)vma->vm_start, + rc); - vma->vm_ops = &em28xx_vm_ops; - vma->vm_private_data = &dev->frame[i]; - - em28xx_vm_open(vma); - mutex_unlock(&dev->lock); - return 0; + return rc; } static const struct file_operations em28xx_v4l_fops = { @@ -1865,6 +2058,9 @@ static const struct video_device em28xx_video_template = { .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, #endif +#ifdef CONFIG_VIDEO_V4L1_COMPAT + .vidiocgmbuf = vidiocgmbuf, +#endif .tvnorms = V4L2_STD_ALL, .current_norm = V4L2_STD_PAL, @@ -1952,6 +2148,7 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev, vfd->release = video_device_release; #endif vfd->type = type; + vfd->debug = video_debug; snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name); @@ -1975,7 +2172,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, dev->udev = udev; mutex_init(&dev->lock); - spin_lock_init(&dev->queue_lock); + spin_lock_init(&dev->slock); init_waitqueue_head(&dev->open); init_waitqueue_head(&dev->wait_frame); init_waitqueue_head(&dev->wait_stream); @@ -2023,10 +2220,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, dev->width = maxw; dev->height = maxh; dev->interlaced = EM28XX_INTERLACED_DEFAULT; - dev->field_size = dev->width * dev->height; - dev->frame_size = - dev->interlaced ? dev->field_size << 1 : dev->field_size; - dev->bytesperline = dev->width * 2; dev->hscale = 0; dev->vscale = 0; dev->ctl_input = 2; @@ -2082,6 +2275,10 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, dev->radio_dev->minor & 0x1f); } + /* init video dma queues */ + INIT_LIST_HEAD(&dev->vidq.active); + INIT_LIST_HEAD(&dev->vidq.queued); + #if 0 video_set_drvdata(dev->vbi_dev, dev); #endif diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h index 980989f11..cf6efe070 100644 --- a/linux/drivers/media/video/em28xx/em28xx.h +++ b/linux/drivers/media/video/em28xx/em28xx.h @@ -27,14 +27,14 @@ #include "compat.h" #include <linux/videodev2.h> +#include <media/videobuf-vmalloc.h> + #include <linux/i2c.h> #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15) #include <linux/mutex.h> #endif #include <media/ir-kbd-i2c.h> -#define UNSET -1 - /* maximum number of em28xx boards */ #define EM28XX_MAXBOARDS 4 /*FIXME: should be bigger */ @@ -84,31 +84,66 @@ /* time in msecs to wait for i2c writes to finish */ #define EM2800_I2C_WRITE_TIMEOUT 20 -/* the various frame states */ -enum em28xx_frame_state { - F_UNUSED = 0, - F_QUEUED, - F_GRABBING, - F_DONE, - F_ERROR, -}; - -/* stream states */ enum em28xx_stream_state { STREAM_OFF, STREAM_INTERRUPT, STREAM_ON, }; -/* frames */ -struct em28xx_frame_t { - void *bufmem; - struct v4l2_buffer buf; - enum em28xx_frame_state state; +struct em28xx_usb_isoc_ctl { + /* max packet size of isoc transaction */ + int max_pkt_size; + + /* number of allocated urbs */ + int num_bufs; + + /* urb for isoc transfers */ + struct urb **urb; + + /* transfer buffers for isoc transfer */ + char **transfer_buffer; + + /* Last buffer command and region */ + u8 cmd; + int pos, size, pktsize; + + /* Last field: ODD or EVEN? */ + int field; + + /* Stores incomplete commands */ + u32 tmp_buf; + int tmp_buf_len; + + /* Stores already requested buffers */ + struct em28xx_buffer *buf; + + /* Stores the number of received fields */ + int nfields; +}; + +struct em28xx_fmt { + char *name; + u32 fourcc; /* v4l2 format id */ +}; + +/* buffer for one video frame */ +struct em28xx_buffer { + /* common v4l buffer stuff -- must be first */ + struct videobuf_buffer vb; + struct list_head frame; - unsigned long vma_use_count; int top_field; - int fieldbytesused; + int receiving; +}; + +struct em28xx_dmaqueue { + struct list_head active; + struct list_head queued; + + wait_queue_head_t wq; + + /* Counters to control buffer fill */ + int pos; }; /* io methods */ @@ -266,19 +301,11 @@ struct em28xx { int mute; int volume; /* frame properties */ - struct em28xx_frame_t frame[EM28XX_NUM_FRAMES]; /* list of frames */ - int num_frames; /* number of frames currently in use */ - unsigned int frame_count; /* total number of transfered frames */ - struct em28xx_frame_t *frame_current; /* the frame that is being filled */ int width; /* current frame width */ int height; /* current frame height */ - int frame_size; /* current frame size */ - int field_size; /* current field size */ - int bytesperline; int hscale; /* horizontal scale factor (see datasheet) */ int vscale; /* vertical scale factor (see datasheet) */ int interlaced; /* 1=interlace fileds, 0=just top fileds */ - int type; unsigned int video_bytesread; /* Number of bytes read */ unsigned long hash; /* eeprom hash - for boards with generic ID */ @@ -288,7 +315,6 @@ struct em28xx { /* states */ enum em28xx_dev_state state; - enum em28xx_stream_state stream; enum em28xx_io_method io; struct work_struct request_module_wk; @@ -299,7 +325,7 @@ struct em28xx { #else struct semaphore lock, fileop_lock; #endif - spinlock_t queue_lock; + /* spinlock_t queue_lock; */ struct list_head inqueue, outqueue; wait_queue_head_t open, wait_frame, wait_stream; struct video_device *vbi_dev; @@ -307,6 +333,11 @@ struct em28xx { unsigned char eedata[256]; + /* Isoc control struct */ + struct em28xx_dmaqueue vidq; + struct em28xx_usb_isoc_ctl isoc_ctl; + spinlock_t slock; + /* usb transfer */ struct usb_device *udev; /* the usb device */ int alt; /* alternate */ @@ -330,6 +361,10 @@ struct em28xx_fh { struct em28xx *dev; unsigned int stream_on:1; /* Locks streams */ int radio; + + struct videobuf_queue vb_vidq; + + enum v4l2_buf_type type; }; struct em28xx_ops { @@ -366,8 +401,6 @@ int em28xx_colorlevels_set_default(struct em28xx *dev); int em28xx_capture_start(struct em28xx *dev, int start); int em28xx_outfmt_set_yuv422(struct em28xx *dev); int em28xx_resolution_set(struct em28xx *dev); -int em28xx_init_isoc(struct em28xx *dev); -void em28xx_uninit_isoc(struct em28xx *dev); int em28xx_set_alternate(struct em28xx *dev); /* Provided by em28xx-video.c */ diff --git a/linux/drivers/media/video/ivtv/ivtv-ioctl.c b/linux/drivers/media/video/ivtv/ivtv-ioctl.c index 873296394..a5da513d6 100644 --- a/linux/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/linux/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1644,6 +1644,7 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp, if (ivtv_debug & IVTV_DBGFLG_IOCTL) { printk(KERN_INFO "ivtv%d ioctl: ", itv->num); v4l_printk_ioctl(cmd); + printk("\n"); } return ivtv_debug_ioctls(filp, cmd, arg); @@ -1687,6 +1688,7 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp, if (ivtv_debug & IVTV_DBGFLG_IOCTL) { printk(KERN_INFO "ivtv%d ioctl: ", itv->num); v4l_printk_ioctl(cmd); + printk("\n"); } return ivtv_v4l2_ioctls(itv, filp, cmd, arg); @@ -1700,6 +1702,7 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp, if (ivtv_debug & IVTV_DBGFLG_IOCTL) { printk(KERN_INFO "ivtv%d ioctl: ", itv->num); v4l_printk_ioctl(cmd); + printk("\n"); } return ivtv_control_ioctls(itv, cmd, arg); diff --git a/linux/drivers/media/video/pwc/pwc-v4l.c b/linux/drivers/media/video/pwc/pwc-v4l.c index 32fbe1ae6..174288987 100644 --- a/linux/drivers/media/video/pwc/pwc-v4l.c +++ b/linux/drivers/media/video/pwc/pwc-v4l.c @@ -351,8 +351,10 @@ int pwc_video_do_ioctl(struct inode *inode, struct file *file, return -EFAULT; #ifdef CONFIG_USB_PWC_DEBUG - if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace) + if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace) { v4l_printk_ioctl(cmd); + printk("\n"); + } #endif diff --git a/linux/drivers/media/video/videobuf-core.c b/linux/drivers/media/video/videobuf-core.c index 7138410fa..367f150a9 100644 --- a/linux/drivers/media/video/videobuf-core.c +++ b/linux/drivers/media/video/videobuf-core.c @@ -95,13 +95,14 @@ int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb, return CALL(q, iolock, q, vb, fbuf); } -/* --------------------------------------------------------------------- */ - -static int videobuf_mmap_setup_default(struct videobuf_queue *q, - struct videobuf_buffer *vb) +void *videobuf_queue_to_vmalloc (struct videobuf_queue *q, + struct videobuf_buffer *buf) { - return 0; + return CALL(q, vmalloc, buf); } +EXPORT_SYMBOL_GPL(videobuf_queue_to_vmalloc); + +/* --------------------------------------------------------------------- */ void videobuf_queue_core_init(struct videobuf_queue *q, @@ -124,9 +125,6 @@ void videobuf_queue_core_init(struct videobuf_queue *q, q->priv_data = priv; q->int_ops = int_ops; - if (!q->int_ops->mmap_setup) - q->int_ops->mmap_setup = videobuf_mmap_setup_default; - /* All buffer operations are mandatory */ BUG_ON(!q->ops->buf_setup); BUG_ON(!q->ops->buf_prepare); @@ -136,6 +134,9 @@ void videobuf_queue_core_init(struct videobuf_queue *q, /* Having implementations for abstract methods are mandatory */ BUG_ON(!q->int_ops); + /* Having irqlock is mandatory */ + BUG_ON(!q->irqlock); + mutex_init(&q->vb_lock); init_waitqueue_head(&q->wait); INIT_LIST_HEAD(&q->stream); @@ -190,8 +191,7 @@ void videobuf_queue_cancel(struct videobuf_queue *q) wake_up_interruptible_sync(&q->wait); /* remove queued buffers from list */ - if (q->irqlock) - spin_lock_irqsave(q->irqlock, flags); + spin_lock_irqsave(q->irqlock, flags); for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; @@ -201,8 +201,7 @@ void videobuf_queue_cancel(struct videobuf_queue *q) wake_up_all(&q->bufs[i]->done); } } - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock, flags); + spin_unlock_irqrestore(q->irqlock, flags); /* free all buffers + clear queue */ for (i = 0; i < VIDEO_MAX_FRAME; i++) { @@ -304,6 +303,8 @@ static int __videobuf_mmap_free(struct videobuf_queue *q) rc = CALL(q, mmap_free, q); + q->is_mmapped = 0; + if (rc < 0) return rc; @@ -355,9 +356,6 @@ static int __videobuf_mmap_setup(struct videobuf_queue *q, switch (memory) { case V4L2_MEMORY_MMAP: q->bufs[i]->boff = bsize * i; - err = q->int_ops->mmap_setup(q, q->bufs[i]); - if (err) - break; break; case V4L2_MEMORY_USERPTR: case V4L2_MEMORY_OVERLAY: @@ -559,11 +557,9 @@ int videobuf_qbuf(struct videobuf_queue *q, list_add_tail(&buf->stream, &q->stream); if (q->streaming) { - if (q->irqlock) - spin_lock_irqsave(q->irqlock, flags); + spin_lock_irqsave(q->irqlock, flags); q->ops->buf_queue(q, buf); - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock, flags); + spin_unlock_irqrestore(q->irqlock, flags); } dprintk(1, "qbuf: succeded\n"); retval = 0; @@ -700,13 +696,11 @@ int videobuf_streamon(struct videobuf_queue *q) if (q->streaming) goto done; q->streaming = 1; - if (q->irqlock) - spin_lock_irqsave(q->irqlock, flags); + spin_lock_irqsave(q->irqlock, flags); list_for_each_entry(buf, &q->stream, stream) if (buf->state == VIDEOBUF_PREPARED) q->ops->buf_queue(q, buf); - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock, flags); + spin_unlock_irqrestore(q->irqlock, flags); wake_up_interruptible_sync(&q->wait); done: @@ -762,11 +756,10 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q, goto done; /* start capture & wait */ - if (q->irqlock) - spin_lock_irqsave(q->irqlock, flags); + spin_lock_irqsave(q->irqlock, flags); q->ops->buf_queue(q, q->read_buf); - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock, flags); + spin_unlock_irqrestore(q->irqlock, flags); + retval = videobuf_waiton(q->read_buf, 0, 0); if (0 == retval) { CALL(q, sync, q, q->read_buf); @@ -827,12 +820,10 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, q->read_buf = NULL; goto done; } - if (q->irqlock) - spin_lock_irqsave(q->irqlock, flags); - + spin_lock_irqsave(q->irqlock, flags); q->ops->buf_queue(q, q->read_buf); - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock, flags); + spin_unlock_irqrestore(q->irqlock, flags); + q->read_off = 0; } @@ -898,12 +889,12 @@ static int __videobuf_read_start(struct videobuf_queue *q) return err; list_add_tail(&q->bufs[i]->stream, &q->stream); } - if (q->irqlock) - spin_lock_irqsave(q->irqlock, flags); + + spin_lock_irqsave(q->irqlock, flags); for (i = 0; i < count; i++) q->ops->buf_queue(q, q->bufs[i]); - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock, flags); + spin_unlock_irqrestore(q->irqlock, flags); + q->reading = 1; return 0; } @@ -912,7 +903,6 @@ static void __videobuf_read_stop(struct videobuf_queue *q) { int i; - videobuf_queue_cancel(q); __videobuf_mmap_free(q); INIT_LIST_HEAD(&q->stream); @@ -1016,11 +1006,11 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q, if (q->read_off == q->read_buf->size) { list_add_tail(&q->read_buf->stream, &q->stream); - if (q->irqlock) - spin_lock_irqsave(q->irqlock, flags); + + spin_lock_irqsave(q->irqlock, flags); q->ops->buf_queue(q, q->read_buf); - if (q->irqlock) - spin_unlock_irqrestore(q->irqlock, flags); + spin_unlock_irqrestore(q->irqlock, flags); + q->read_buf = NULL; } if (retval < 0) @@ -1080,6 +1070,7 @@ int videobuf_mmap_mapper(struct videobuf_queue *q, mutex_lock(&q->vb_lock); retval = CALL(q, mmap_mapper, q, vma); + q->is_mmapped = 1; mutex_unlock(&q->vb_lock); return retval; diff --git a/linux/drivers/media/video/videobuf-dma-sg.c b/linux/drivers/media/video/videobuf-dma-sg.c index 47280bf9f..7d459ed6b 100644 --- a/linux/drivers/media/video/videobuf-dma-sg.c +++ b/linux/drivers/media/video/videobuf-dma-sg.c @@ -163,9 +163,6 @@ static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma, dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n", data,size,dma->nr_pages); - dma->varea = (void *) data; - - err = get_user_pages(current,current->mm, data & PAGE_MASK, dma->nr_pages, rw == READ, 1, /* force */ @@ -305,7 +302,6 @@ int videobuf_dma_free(struct videobuf_dmabuf *dma) vfree(dma->vmalloc); dma->vmalloc = NULL; - dma->varea = NULL; if (dma->bus_addr) { dma->bus_addr = 0; @@ -482,6 +478,16 @@ static void *__videobuf_alloc(size_t size) return vb; } +static void *__videobuf_to_vmalloc (struct videobuf_buffer *buf) +{ + struct videobuf_dma_sg_memory *mem = buf->priv; + BUG_ON(!mem); + + MAGIC_CHECK(mem->magic, MAGIC_SG_MEM); + + return mem->dma.vmalloc; +} + static int __videobuf_iolock (struct videobuf_queue* q, struct videobuf_buffer *vb, struct v4l2_framebuffer *fbuf) @@ -727,6 +733,7 @@ static struct videobuf_qtype_ops sg_ops = { .mmap_mapper = __videobuf_mmap_mapper, .video_copy_to_user = __videobuf_copy_to_user, .copy_stream = __videobuf_copy_stream, + .vmalloc = __videobuf_to_vmalloc, }; void *videobuf_sg_alloc(size_t size) diff --git a/linux/drivers/media/video/videobuf-dvb.c b/linux/drivers/media/video/videobuf-dvb.c index 301d5af12..9a821371a 100644 --- a/linux/drivers/media/video/videobuf-dvb.c +++ b/linux/drivers/media/video/videobuf-dvb.c @@ -21,13 +21,14 @@ #include <linux/fs.h> #include <linux/kthread.h> #include <linux/file.h> + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) #include <linux/suspend.h> #else #include <linux/freezer.h> #endif -#include <media/videobuf-dma-sg.h> +#include <media/videobuf-core.h> #include <media/videobuf-dvb.h> #include "compat.h" @@ -51,7 +52,7 @@ static int videobuf_dvb_thread(void *data) struct videobuf_buffer *buf; unsigned long flags; int err; - struct videobuf_dmabuf *dma; + void *outp; dprintk("dvb thread started\n"); set_freezable(); @@ -72,9 +73,10 @@ static int videobuf_dvb_thread(void *data) try_to_freeze(); /* feed buffer data to demux */ - dma=videobuf_to_dma(buf); + outp = videobuf_queue_to_vmalloc (&dvb->dvbq, buf); + if (buf->state == VIDEOBUF_DONE) - dvb_dmx_swfilter(&dvb->demux, dma->vmalloc, + dvb_dmx_swfilter(&dvb->demux, outp, buf->size); /* requeue buffer */ diff --git a/linux/drivers/media/video/videobuf-vmalloc.c b/linux/drivers/media/video/videobuf-vmalloc.c index 9e6ff640e..6f487b348 100644 --- a/linux/drivers/media/video/videobuf-vmalloc.c +++ b/linux/drivers/media/video/videobuf-vmalloc.c @@ -58,20 +58,26 @@ videobuf_vm_open(struct vm_area_struct *vma) map->count++; } -static void -videobuf_vm_close(struct vm_area_struct *vma) +static void videobuf_vm_close(struct vm_area_struct *vma) { struct videobuf_mapping *map = vma->vm_private_data; struct videobuf_queue *q = map->q; int i; - dprintk(2,"vm_close %p [count=%u,vma=%08lx-%08lx]\n",map, - map->count,vma->vm_start,vma->vm_end); + dprintk(2,"vm_close %p [count=%u,vma=%08lx-%08lx]\n", map, + map->count, vma->vm_start, vma->vm_end); map->count--; if (0 == map->count) { - dprintk(1,"munmap %p q=%p\n",map,q); + struct videobuf_vmalloc_memory *mem; + + dprintk(1, "munmap %p q=%p\n", map, q); mutex_lock(&q->vb_lock); + + /* We need first to cancel streams, before unmapping */ + if (q->streaming) + videobuf_queue_cancel(q); + for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; @@ -79,12 +85,35 @@ videobuf_vm_close(struct vm_area_struct *vma) if (q->bufs[i]->map != map) continue; + mem = q->bufs[i]->priv; + if (mem) { + /* This callback is called only if kernel has + allocated memory and this memory is mmapped. + In this case, memory should be freed, + in order to do memory unmap. + */ + + MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); + + /* vfree is not atomic - can't be + called with IRQ's disabled + */ + dprintk(1, "%s: buf[%d] freeing (%p)\n", + __func__, i, mem->vmalloc); + + vfree(mem->vmalloc); + mem->vmalloc = NULL; + } + q->bufs[i]->map = NULL; q->bufs[i]->baddr = 0; } - mutex_unlock(&q->vb_lock); + kfree(map); + + mutex_unlock(&q->vb_lock); } + return; } @@ -125,53 +154,77 @@ static int __videobuf_iolock (struct videobuf_queue* q, struct videobuf_buffer *vb, struct v4l2_framebuffer *fbuf) { + struct videobuf_vmalloc_memory *mem = vb->priv; int pages; - struct videobuf_vmalloc_memory *mem=vb->priv; BUG_ON(!mem); - MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); - pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT; + switch (vb->memory) { + case V4L2_MEMORY_MMAP: + dprintk(1, "%s memory method MMAP\n", __func__); - /* Currently, doesn't support V4L2_MEMORY_OVERLAY */ - if ((vb->memory != V4L2_MEMORY_MMAP) && - (vb->memory != V4L2_MEMORY_USERPTR) ) { - printk(KERN_ERR "Method currently unsupported.\n"); - return -EINVAL; - } + /* All handling should be done by __videobuf_mmap_mapper() */ + if (!mem->vmalloc) { + printk(KERN_ERR "memory is not alloced/mmapped.\n"); + return -EINVAL; + } + break; + case V4L2_MEMORY_USERPTR: + pages = PAGE_ALIGN(vb->size); - /* FIXME: should be tested with kernel mmap mem */ - mem->vmalloc=vmalloc_user (PAGE_ALIGN(vb->size)); - if (NULL == mem->vmalloc) { - printk(KERN_ERR "vmalloc (%d pages) failed\n",pages); - return -ENOMEM; - } + dprintk(1, "%s memory method USERPTR\n", __func__); - dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n", - (unsigned long)mem->vmalloc, - pages << PAGE_SHIFT); +#if 1 /* keep */ + if (vb->baddr) { + printk(KERN_ERR "USERPTR is currently not supported\n"); + return -EINVAL; + } +#endif - return 0; -} + /* The only USERPTR currently supported is the one needed for + read() method. + */ -static int __videobuf_mmap_setup(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - int retval = 0; - BUG_ON(vb->memory != V4L2_MEMORY_MMAP); - if (vb->state == VIDEOBUF_NEEDS_INIT) { - /* bsize == size since the buffer needs to be large enough to - * hold an entire frame, not the case in the read case for - * example*/ - vb->size = vb->bsize; - retval = __videobuf_iolock(q, vb, NULL); - if (!retval) { - /* Don't IOLOCK later */ - vb->state = VIDEOBUF_IDLE; + mem->vmalloc = vmalloc_user(pages); + if (!mem->vmalloc) { + printk(KERN_ERR "vmalloc (%d pages) failed\n", pages); + return -ENOMEM; + } + dprintk(1, "vmalloc is at addr %p (%d pages)\n", + mem->vmalloc, pages); + +#if 0 /* keep */ + int rc; + /* Kernel userptr is used also by read() method. In this case, + there's no need to remap, since data will be copied to user + */ + if (!vb->baddr) + return 0; + + /* FIXME: to properly support USERPTR, remap should occur. + The code bellow won't work, since mem->vma = NULL + */ + /* Try to remap memory */ + rc = remap_vmalloc_range(mem->vma, (void *)vb->baddr, 0); + if (rc < 0) { + printk(KERN_ERR "mmap: remap failed with error %d. ", rc); + return -ENOMEM; } +#endif + + break; + case V4L2_MEMORY_OVERLAY: + default: + dprintk(1, "%s memory method OVERLAY/unknown\n", __func__); + + /* Currently, doesn't support V4L2_MEMORY_OVERLAY */ + printk(KERN_ERR "Memory method currently unsupported.\n"); + return -EINVAL; } - return retval; + + return 0; } static int __videobuf_sync(struct videobuf_queue *q, @@ -184,6 +237,7 @@ static int __videobuf_mmap_free(struct videobuf_queue *q) { unsigned int i; + dprintk(1, "%s\n", __func__); for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (q->bufs[i]) { if (q->bufs[i]->map) @@ -200,10 +254,11 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, struct videobuf_vmalloc_memory *mem; struct videobuf_mapping *map; unsigned int first; - int retval; + int retval, pages; unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - if (! (vma->vm_flags & VM_WRITE) || ! (vma->vm_flags & VM_SHARED)) + dprintk(1, "%s\n", __func__); + if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED)) return -EINVAL; /* look for first buffer to map */ @@ -223,39 +278,55 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, } /* create mapping + update buffer list */ - map = q->bufs[first]->map = kzalloc(sizeof(struct videobuf_mapping),GFP_KERNEL); + map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL); if (NULL == map) return -ENOMEM; + q->bufs[first]->map = map; map->start = vma->vm_start; map->end = vma->vm_end; map->q = q; q->bufs[first]->baddr = vma->vm_start; - vma->vm_ops = &videobuf_vm_ops; - vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; - vma->vm_private_data = map; + mem = q->bufs[first]->priv; + BUG_ON(!mem); + MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); - mem=q->bufs[first]->priv; - BUG_ON (!mem); - MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + pages = PAGE_ALIGN(vma->vm_end - vma->vm_start); + mem->vmalloc = vmalloc_user(pages); + if (!mem->vmalloc) { + printk(KERN_ERR "vmalloc (%d pages) failed\n", pages); + goto error; + } + dprintk(1, "vmalloc is at addr %p (%d pages)\n", + mem->vmalloc, pages); /* Try to remap memory */ - retval=remap_vmalloc_range(vma, mem->vmalloc,0); - if (retval<0) { - dprintk(1, "mmap: failed to remap_vmalloc_range\n"); - return -EINVAL; + retval = remap_vmalloc_range(vma, mem->vmalloc, 0); + if (retval < 0) { + printk(KERN_ERR "mmap: remap failed with error %d. ", retval); + vfree(mem->vmalloc); + goto error; } + vma->vm_ops = &videobuf_vm_ops; + vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; + vma->vm_private_data = map; + dprintk(1,"mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n", - map,q,vma->vm_start,vma->vm_end, + map, q, vma->vm_start, vma->vm_end, (long int) q->bufs[first]->bsize, - vma->vm_pgoff,first); + vma->vm_pgoff, first); videobuf_vm_open(vma); - return (0); + return 0; + +error: + mem = NULL; + kfree(map); + return -ENOMEM; } static int __videobuf_copy_to_user ( struct videobuf_queue *q, @@ -313,11 +384,11 @@ static struct videobuf_qtype_ops qops = { .alloc = __videobuf_alloc, .iolock = __videobuf_iolock, .sync = __videobuf_sync, - .mmap_setup = __videobuf_mmap_setup, .mmap_free = __videobuf_mmap_free, .mmap_mapper = __videobuf_mmap_mapper, .video_copy_to_user = __videobuf_copy_to_user, .copy_stream = __videobuf_copy_stream, + .vmalloc = videobuf_to_vmalloc, }; void videobuf_queue_vmalloc_init(struct videobuf_queue* q, @@ -347,13 +418,24 @@ EXPORT_SYMBOL_GPL(videobuf_to_vmalloc); void videobuf_vmalloc_free (struct videobuf_buffer *buf) { - struct videobuf_vmalloc_memory *mem=buf->priv; - BUG_ON (!mem); + struct videobuf_vmalloc_memory *mem = buf->priv; - MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); + /* mmapped memory can't be freed here, otherwise mmapped region + would be released, while still needed. In this case, the memory + release should happen inside videobuf_vm_close(). + So, it should free memory only if the memory were allocated for + read() operation. + */ + if ((buf->memory != V4L2_MEMORY_USERPTR) || (buf->baddr == 0)) + return; + + if (!mem) + return; + + MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); vfree(mem->vmalloc); - mem->vmalloc=NULL; + mem->vmalloc = NULL; return; } diff --git a/linux/drivers/media/video/videodev.c b/linux/drivers/media/video/videodev.c index f73f876e0..31e28a14f 100644 --- a/linux/drivers/media/video/videodev.c +++ b/linux/drivers/media/video/videodev.c @@ -18,14 +18,14 @@ #define dbgarg(cmd, fmt, arg...) \ if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { \ - printk (KERN_DEBUG "%s: ", vfd->name); \ + printk(KERN_DEBUG "%s: ", vfd->name); \ v4l_printk_ioctl(cmd); \ - printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg); \ + printk(" " fmt, ## arg); \ } #define dbgarg2(fmt, arg...) \ if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \ - printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg); + printk(KERN_DEBUG "%s: " fmt, vfd->name, ## arg); #include <linux/module.h> #include <linux/types.h> @@ -382,38 +382,45 @@ static const char *v4l2_int_ioctls[] = { external ioctl messages as well as internal V4L ioctl */ void v4l_printk_ioctl(unsigned int cmd) { - char *dir; + char *dir, *type; - switch (_IOC_DIR(cmd)) { - case _IOC_NONE: dir = "--"; break; - case _IOC_READ: dir = "r-"; break; - case _IOC_WRITE: dir = "-w"; break; - case _IOC_READ | _IOC_WRITE: dir = "rw"; break; - default: dir = "*ERR*"; break; - } switch (_IOC_TYPE(cmd)) { case 'd': - printk("v4l2_int ioctl %s, dir=%s (0x%08x)\n", - (_IOC_NR(cmd) < V4L2_INT_IOCTLS) ? - v4l2_int_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd); - break; + if (_IOC_NR(cmd) >= V4L2_INT_IOCTLS) { + type = "v4l2_int"; + break; + } + printk("%s", v4l2_int_ioctls[_IOC_NR(cmd)]); + return; #ifdef CONFIG_VIDEO_V4L1_COMPAT case 'v': - printk("v4l1 ioctl %s, dir=%s (0x%08x)\n", - (_IOC_NR(cmd) < V4L1_IOCTLS) ? - v4l1_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd); - break; + if (_IOC_NR(cmd) >= V4L1_IOCTLS) { + type = "v4l1"; + break; + } + printk("%s", v4l1_ioctls[_IOC_NR(cmd)]); + return; #endif case 'V': - printk("v4l2 ioctl %s, dir=%s (0x%08x)\n", - (_IOC_NR(cmd) < V4L2_IOCTLS) ? - v4l2_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd); - break; - + if (_IOC_NR(cmd) >= V4L2_IOCTLS) { + type = "v4l2"; + break; + } + printk("%s", v4l2_ioctls[_IOC_NR(cmd)]); + return; default: - printk("unknown ioctl '%c', dir=%s, #%d (0x%08x)\n", - _IOC_TYPE(cmd), dir, _IOC_NR(cmd), cmd); + type = "unknown"; + } + + switch (_IOC_DIR(cmd)) { + case _IOC_NONE: dir = "--"; break; + case _IOC_READ: dir = "r-"; break; + case _IOC_WRITE: dir = "-w"; break; + case _IOC_READ | _IOC_WRITE: dir = "rw"; break; + default: dir = "*ERR*"; break; } + printk("%s ioctl '%c', dir=%s, #%d (0x%08x)", + type, _IOC_TYPE(cmd), dir, _IOC_NR(cmd), cmd); } EXPORT_SYMBOL(v4l_printk_ioctl); @@ -811,6 +818,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, if ( (vfd->debug & V4L2_DEBUG_IOCTL) && !(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) { v4l_print_ioctl(vfd->name, cmd); + printk("\n"); } #ifdef CONFIG_VIDEO_V4L1_COMPAT @@ -1894,8 +1902,9 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { if (ret<0) { - printk ("%s: err:\n", vfd->name); + printk("%s: err: on ", vfd->name); v4l_print_ioctl(vfd->name, cmd); + printk("\n"); } } diff --git a/linux/drivers/media/video/vivi.c b/linux/drivers/media/video/vivi.c index 3ad428808..900a17404 100644 --- a/linux/drivers/media/video/vivi.c +++ b/linux/drivers/media/video/vivi.c @@ -603,7 +603,7 @@ static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf) BUG(); videobuf_vmalloc_free(&buf->vb); - dprintk(dev, 1, "free_buffer: freed"); + dprintk(dev, 1, "free_buffer: freed\n"); buf->vb.state = VIDEOBUF_NEEDS_INIT; } @@ -1123,7 +1123,7 @@ static const struct file_operations vivi_fops = { .poll = vivi_poll, .ioctl = video_ioctl2, /* V4L2 ioctl handler */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11) - .compat_ioctl = v4l_compat_ioctl32, + .compat_ioctl = v4l_compat_ioctl32, #endif .mmap = vivi_mmap, .llseek = no_llseek, |