diff options
| author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2018-05-22 11:42:47 +0300 | 
|---|---|---|
| committer | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2018-05-22 11:42:47 +0300 | 
| commit | 117cd47e08db4e31d2f966cb4b22987d3e5d6bb7 (patch) | |
| tree | 4fb5396cd3c3d063aec59ef1e9e1066325f33a71 | |
| parent | ab92702a44f8521d5deef3e2ac9f35514bbe7c9a (diff) | |
v4l2: Split buffer allocation and mapping
Not all use cases of V4L2_MEMORY_MMAP require mapping buffers to
userspace. Separate the allocation and mapping to allow usage of
unmapped buffers.
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
| -rw-r--r-- | uvc-gadget.c | 12 | ||||
| -rw-r--r-- | v4l2.c | 92 | ||||
| -rw-r--r-- | v4l2.h | 25 | 
3 files changed, 78 insertions, 51 deletions
| diff --git a/uvc-gadget.c b/uvc-gadget.c index a0d8004..df9d80a 100644 --- a/uvc-gadget.c +++ b/uvc-gadget.c @@ -163,6 +163,12 @@ uvc_video_stream(struct uvc_device *dev, int enable)  		return ret;  	} +	ret = v4l2_mmap_buffers(dev->vdev); +	if (ret < 0) { +		printf("Failed to mmap buffers.\n"); +		goto error; +	} +  	for (i = 0; i < dev->vdev->nbufs; ++i) {  		struct v4l2_video_buffer *buf = &dev->vdev->buffers[i]; @@ -170,13 +176,17 @@ uvc_video_stream(struct uvc_device *dev, int enable)  		ret = v4l2_queue_buffer(dev->vdev, buf);  		if (ret < 0) -			return ret; +			goto error;  	}  	v4l2_stream_on(dev->vdev);  	events_watch_fd(&dev->events, dev->vdev->fd, EVENT_WRITE,  			uvc_video_process, dev); +	return 0; + +error: +	v4l2_free_buffers(dev->vdev);  	return ret;  } @@ -506,13 +506,15 @@ int v4l2_alloc_buffers(struct v4l2_device *dev, enum v4l2_memory memtype,  		       unsigned int nbufs)  {  	struct v4l2_requestbuffers rb; -	struct v4l2_buffer buf;  	unsigned int i;  	int ret;  	if (dev->nbufs != 0)  		return -EBUSY; +	if (memtype != V4L2_MEMORY_MMAP && memtype != V4L2_MEMORY_USERPTR) +		return -EINVAL; +  	/* Request the buffers from the driver. */  	memset(&rb, 0, sizeof rb);  	rb.count = nbufs; @@ -551,52 +553,6 @@ int v4l2_alloc_buffers(struct v4l2_device *dev, enum v4l2_memory memtype,  	for (i = 0; i < dev->nbufs; ++i)  		dev->buffers[i].index = i; -	/* Map the buffers. */ -	for (i = 0; i < rb.count; ++i) { -		memset(&buf, 0, sizeof buf); -		buf.index = i; -		buf.type = dev->type; -		buf.memory = memtype; -		ret = ioctl(dev->fd, VIDIOC_QUERYBUF, &buf); -		if (ret < 0) { -			printf("%s: unable to query buffer %u (%d).\n", -			       dev->name, i, errno); -			ret = -errno; -			goto done; -		} - -		switch (memtype) { -		case V4L2_MEMORY_MMAP: -			dev->buffers[i].mem = mmap(0, buf.length, PROT_READ | PROT_WRITE, -					      MAP_SHARED, dev->fd, buf.m.offset); -			if (dev->buffers[i].mem == MAP_FAILED) { -				printf("%s: unable to map buffer %u (%d)\n", -				       dev->name, i, errno); -				ret = -errno; -				goto done; -			} -			dev->buffers[i].size = buf.length; -			printf("%s: buffer %u mapped at address %p.\n", -			       dev->name, i, dev->buffers[i].mem); -			break; - -		case V4L2_MEMORY_USERPTR: -			if (dev->buffers[i].size < buf.length) { -				printf("%s: buffer %u too small (%u bytes required, " -				       "%u bytes available.\n", dev->name, i, -				       buf.length, dev->buffers[i].size); -				ret = -EINVAL; -				goto done; -			} - -			printf("%s: buffer %u valid.\n", dev->name, i); -			break; - -		default: -			break; -		} -	} -  	ret = 0;  done: @@ -653,6 +609,48 @@ int v4l2_free_buffers(struct v4l2_device *dev)  	return 0;  } +int v4l2_mmap_buffers(struct v4l2_device *dev) +{ +	unsigned int i; +	int ret; + +	if (dev->memtype != V4L2_MEMORY_MMAP) +		return -EINVAL; + +	for (i = 0; i < dev->nbufs; ++i) { +		struct v4l2_video_buffer *buffer = &dev->buffers[i]; +		struct v4l2_buffer buf = { +			.index = i, +			.type = dev->type, +			.memory = dev->memtype, +		}; +		void *mem; + +		ret = ioctl(dev->fd, VIDIOC_QUERYBUF, &buf); +		if (ret < 0) { +			printf("%s: unable to query buffer %u (%d).\n", +			       dev->name, i, errno); +			return -errno; +		} + +		mem = mmap(0, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, +			   dev->fd, buf.m.offset); +		if (mem == MAP_FAILED) { +			printf("%s: unable to map buffer %u (%d)\n", +			       dev->name, i, errno); +			return -errno; +		} + +		buffer->mem = mem; +		buffer->size = buf.length; + +		printf("%s: buffer %u mapped at address %p.\n", dev->name, i, +		       mem); +	} + +	return 0; +} +  int v4l2_dequeue_buffer(struct v4l2_device *dev, struct v4l2_video_buffer *buffer)  {  	struct v4l2_buffer buf; @@ -147,9 +147,10 @@ int v4l2_set_crop(struct v4l2_device *dev, struct v4l2_rect *rect);   * will be stored in the @dev::nbufs field.   *   * When @memtype is set to V4L2_MEMORY_MMAP the buffers are allocated by the - * driver and mapped to userspace. When @memtype is set to V4L2_MEMORY_USERPTR - * the driver only allocates buffer objects and relies on the application to - * provide memory storage for video frames. + * driver. They can then be mapped to userspace by calling v4l2_mmap_buffers(). + * When @memtype is set to V4L2_MEMORY_USERPTR the driver only allocates buffer + * objects and relies on the application to provide memory storage for video + * frames.   *   * Return 0 on success or a negative error code on failure.   */ @@ -172,6 +173,24 @@ int v4l2_alloc_buffers(struct v4l2_device *dev, enum v4l2_memory memtype,  int v4l2_free_buffers(struct v4l2_device *dev);  /* + * v4l2_mmap_buffers - Map buffers to application memory space + * @dev: Device instance + * + * Map all the buffers previously allocated by v4l2_alloc_buffers() to the + * application memory space. The buffer memory can be accessed through the mem + * field of each entry in the @dev::buffers array. + * + * Buffers will be automatically unmapped when freed with v4l2_free_buffers(). + * + * This function can only be called when buffers have been allocated with the + * memory type set to V4L2_MEMORY_MMAP. If the memory type is different, or if + * no buffers have been allocated, it will return -EINVAL. + * + * Return 0 on success or a negative error code on failure. + */ +int v4l2_mmap_buffers(struct v4l2_device *dev); + +/*   * v4l2_queue_buffer - Queue a buffer for video capture/output   * @dev: Device instance   * @buffer: Buffer to be queued | 
