Commit 6f78e186 authored by Thierry MERLE's avatar Thierry MERLE Committed by Mauro Carvalho Chehab

V4L/DVB (5205): Usbvision: dynamic allocation for frames

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