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

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
Loading
Loading
Loading
Loading
+23 −12
Original line number Diff line number Diff line
@@ -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);

+35 −22
Original line number Diff line number Diff line
@@ -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)) {
		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;

	/* 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;
+2 −1
Original line number Diff line number Diff line
@@ -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);