V4L/DVB (5205): Usbvision: dynamic allocation for frames
authorThierry MERLE <thierry.merle@free.fr>
Wed, 7 Feb 2007 13:13:11 +0000 (10:13 -0300)
committerMauro Carvalho Chehab <mchehab@infradead.org>
Wed, 21 Feb 2007 15:35:19 +0000 (13:35 -0200)
- fix decoder route output
- dynamic frame buffer allocation

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
drivers/media/video/usbvision/usbvision-video.c
drivers/media/video/usbvision/usbvision.h

index 42f495c9f5ff8243bd9677ec923474e278303da5..d4fcd5736ba9d7cbe8bd9f44e1ced7ce91b8861c 100644 (file)
@@ -1852,28 +1852,33 @@ int usbvision_set_output(struct usb_usbvision *usbvision, int width,
 
 /*
  * usbvision_frames_alloc
- * allocate the maximum frames this driver can manage
+ * allocate the required frames
  */
-int usbvision_frames_alloc(struct usb_usbvision *usbvision)
+int usbvision_frames_alloc(struct usb_usbvision *usbvision, int number_of_frames)
 {
        int i;
 
-       /* Allocate memory for the frame buffers */
-       usbvision->max_frame_size = MAX_FRAME_SIZE;
-       usbvision->fbuf_size = USBVISION_NUMFRAMES * usbvision->max_frame_size;
-       usbvision->fbuf = usbvision_rvmalloc(usbvision->fbuf_size);
+       /*needs to be page aligned cause the buffers can be mapped individually! */
+       usbvision->max_frame_size =  PAGE_ALIGN(usbvision->curwidth *
+                                               usbvision->curheight *
+                                               usbvision->palette.bytes_per_pixel);
 
-       if(usbvision->fbuf == NULL) {
-               err("%s: unable to allocate %d bytes for fbuf ",
-                   __FUNCTION__, usbvision->fbuf_size);
-               return -ENOMEM;
+       /* Try to do my best to allocate the frames the user want in the remaining memory */
+       usbvision->num_frames = number_of_frames;
+       while (usbvision->num_frames > 0) {
+               usbvision->fbuf_size = usbvision->num_frames * usbvision->max_frame_size;
+               if((usbvision->fbuf = usbvision_rvmalloc(usbvision->fbuf_size))) {
+                       break;
+               }
+               usbvision->num_frames--;
        }
+
        spin_lock_init(&usbvision->queue_lock);
        init_waitqueue_head(&usbvision->wait_frame);
        init_waitqueue_head(&usbvision->wait_stream);
 
        /* Allocate all buffers */
-       for (i = 0; i < USBVISION_NUMFRAMES; i++) {
+       for (i = 0; i < usbvision->num_frames; i++) {
                usbvision->frame[i].index = i;
                usbvision->frame[i].grabstate = FrameState_Unused;
                usbvision->frame[i].data = usbvision->fbuf +
@@ -1887,7 +1892,8 @@ int usbvision_frames_alloc(struct usb_usbvision *usbvision)
                usbvision->frame[i].height = usbvision->curheight;
                usbvision->frame[i].bytes_read = 0;
        }
-       return 0;
+       PDEBUG(DBG_FUNC, "allocated %d frames (%d bytes per frame)",usbvision->num_frames,usbvision->max_frame_size);
+       return usbvision->num_frames;
 }
 
 /*
@@ -1897,9 +1903,13 @@ int usbvision_frames_alloc(struct usb_usbvision *usbvision)
 void usbvision_frames_free(struct usb_usbvision *usbvision)
 {
        /* Have to free all that memory */
+       PDEBUG(DBG_FUNC, "free %d frames",usbvision->num_frames);
+
        if (usbvision->fbuf != NULL) {
                usbvision_rvfree(usbvision->fbuf, usbvision->fbuf_size);
                usbvision->fbuf = NULL;
+
+               usbvision->num_frames = 0;
        }
 }
 /*
@@ -2490,6 +2500,7 @@ int usbvision_muxsel(struct usb_usbvision *usbvision, int channel)
        RESTRICT_TO_RANGE(channel, 0, usbvision->video_inputs);
        usbvision->ctl_input = channel;
          route.input = SAA7115_COMPOSITE1;
+         route.output = 0;
          call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route);
          call_i2c_clients(usbvision, VIDIOC_S_INPUT, &usbvision->ctl_input);
 
index 6a61ebcdf130d7fdca39fa2f9201fc334caa3ec9..cfbfda47ec4fae0188b90187c457025942a43060 100644 (file)
@@ -391,19 +391,14 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
        if (usbvision->user)
                errCode = -EBUSY;
        else {
-               /* Allocate memory for the frame buffers */
-               errCode = usbvision_frames_alloc(usbvision);
-               if(!errCode) {
-                       /* Allocate memory for the scratch ring buffer */
-                       errCode = usbvision_scratch_alloc(usbvision);
-                       if ((!errCode) && (isocMode==ISOC_MODE_COMPRESS)) {
-                               /* Allocate intermediate decompression buffers only if needed */
-                               errCode = usbvision_decompress_alloc(usbvision);
-                       }
+               /* Allocate memory for the scratch ring buffer */
+               errCode = usbvision_scratch_alloc(usbvision);
+               if (isocMode==ISOC_MODE_COMPRESS) {
+                       /* Allocate intermediate decompression buffers only if needed */
+                       errCode = usbvision_decompress_alloc(usbvision);
                }
                if (errCode) {
                        /* Deallocate all buffers if trouble */
-                       usbvision_frames_free(usbvision);
                        usbvision_scratch_free(usbvision);
                        usbvision_decompress_free(usbvision);
                }
@@ -476,6 +471,7 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file)
 
        usbvision_decompress_free(usbvision);
        usbvision_frames_free(usbvision);
+       usbvision_empty_framequeues(usbvision);
        usbvision_scratch_free(usbvision);
 
        usbvision->user--;
@@ -809,7 +805,9 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
                                    return ret;
                        }
 
+                       usbvision_frames_free(usbvision);
                        usbvision_empty_framequeues(usbvision);
+                       vr->count = usbvision_frames_alloc(usbvision,vr->count);
 
                        usbvision->curFrame = NULL;
 
@@ -826,7 +824,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
                        if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
                                return -EINVAL;
                        }
-                       if(vb->index>=USBVISION_NUMFRAMES)  {
+                       if(vb->index>=usbvision->num_frames)  {
                                return -EINVAL;
                        }
                        // Updating the corresponding frame state
@@ -840,7 +838,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
                                vb->flags |= V4L2_BUF_FLAG_MAPPED;
                        vb->memory = V4L2_MEMORY_MMAP;
 
-                       vb->m.offset = vb->index*usbvision->max_frame_size;
+                       vb->m.offset = vb->index*PAGE_ALIGN(usbvision->max_frame_size);
 
                        vb->memory = V4L2_MEMORY_MMAP;
                        vb->field = V4L2_FIELD_NONE;
@@ -859,7 +857,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
                        if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
                                return -EINVAL;
                        }
-                       if(vb->index>=USBVISION_NUMFRAMES)  {
+                       if(vb->index>=usbvision->num_frames)  {
                                return -EINVAL;
                        }
 
@@ -1029,6 +1027,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
                                                if ((ret = usbvision_stream_interrupt(usbvision)))
                                                        return ret;
                                        }
+                                       usbvision_frames_free(usbvision);
                                        usbvision_empty_framequeues(usbvision);
 
                                        usbvision->curFrame = NULL;
@@ -1075,12 +1074,24 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
        if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL))
                return -EFAULT;
 
-       /* no stream is running, make it running ! */
-       usbvision->streaming = Stream_On;
-       call_i2c_clients(usbvision,VIDIOC_STREAMON , NULL);
+       /* This entry point is compatible with the mmap routines so that a user can do either
+          VIDIOC_QBUF/VIDIOC_DQBUF to get frames or call read on the device. */
+       if(!usbvision->num_frames) {
+               /* First, allocate some frames to work with if this has not been done with
+                VIDIOC_REQBUF */
+               usbvision_frames_free(usbvision);
+               usbvision_empty_framequeues(usbvision);
+               usbvision_frames_alloc(usbvision,USBVISION_NUMFRAMES);
+       }
+
+       if(usbvision->streaming != Stream_On) {
+               /* no stream is running, make it running ! */
+               usbvision->streaming = Stream_On;
+               call_i2c_clients(usbvision,VIDIOC_STREAMON , NULL);
+       }
 
-       /* First, enqueue as many frames as possible (like a user of VIDIOC_QBUF would do) */
-       for(i=0;i<USBVISION_NUMFRAMES;i++) {
+       /* Then, enqueue as many frames as possible (like a user of VIDIOC_QBUF would do) */
+       for(i=0;i<usbvision->num_frames;i++) {
                frame = &usbvision->frame[i];
                if(frame->grabstate == FrameState_Unused) {
                        /* Mark it as ready and enqueue frame */
@@ -1157,6 +1168,8 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
        struct video_device *dev = video_devdata(file);
        struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
 
+       PDEBUG(DBG_MMAP, "mmap");
+
        down(&usbvision->lock);
 
        if (!USBVISION_IS_OPERATIONAL(usbvision)) {
@@ -1165,16 +1178,16 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
        }
 
        if (!(vma->vm_flags & VM_WRITE) ||
-           size != PAGE_ALIGN(usbvision->curwidth*usbvision->curheight*usbvision->palette.bytes_per_pixel)) {
+           size != PAGE_ALIGN(usbvision->max_frame_size)) {
                up(&usbvision->lock);
                return -EINVAL;
        }
 
-       for (i = 0; i < USBVISION_NUMFRAMES; i++) {
-               if (((usbvision->max_frame_size*i) >> PAGE_SHIFT) == vma->vm_pgoff)
+       for (i = 0; i < usbvision->num_frames; i++) {
+               if (((PAGE_ALIGN(usbvision->max_frame_size)*i) >> PAGE_SHIFT) == vma->vm_pgoff)
                        break;
        }
-       if (i == USBVISION_NUMFRAMES) {
+       if (i == usbvision->num_frames) {
                PDEBUG(DBG_MMAP, "mmap: user supplied mapping address is out of range");
                up(&usbvision->lock);
                return -EINVAL;
index a316871b79a0b459e72b677a8d9c9614dcda229b..0e2b5569986097f816e8fcd5ff2b1a9e825cb33f 100644 (file)
@@ -421,6 +421,7 @@ struct usb_usbvision {
        wait_queue_head_t wait_stream;                                  /* Processes waiting */
        struct usbvision_frame *curFrame;                               // pointer to current frame, set by usbvision_find_header
        struct usbvision_frame frame[USBVISION_NUMFRAMES];              // frame buffer
+       int num_frames;                                                 // number of frames allocated
        struct usbvision_sbuf sbuf[USBVISION_NUMSBUF];                  // S buffering
        volatile int remove_pending;                                    /* If set then about to exit */
 
@@ -490,7 +491,7 @@ int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg);
 int usbvision_write_reg(struct usb_usbvision *usbvision, unsigned char reg,
                        unsigned char value);
 
-int usbvision_frames_alloc(struct usb_usbvision *usbvision);
+int usbvision_frames_alloc(struct usb_usbvision *usbvision, int number_of_frames);
 void usbvision_frames_free(struct usb_usbvision *usbvision);
 int usbvision_scratch_alloc(struct usb_usbvision *usbvision);
 void usbvision_scratch_free(struct usb_usbvision *usbvision);