diff options
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | v4l2.c | 733 | ||||
| -rw-r--r-- | v4l2.h | 303 | 
3 files changed, 1037 insertions, 1 deletions
| @@ -9,7 +9,7 @@ LDFLAGS		:= -g  all: uvc-gadget -uvc-gadget: events.o uvc-gadget.o +uvc-gadget: events.o uvc-gadget.o v4l2.o  	$(CC) $(LDFLAGS) -o $@ $^  clean: @@ -0,0 +1,733 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * V4L2 Devices + * + * Copyright (C) 2018 Laurent Pinchart + * + * This file originally comes from the omap3-isp-live project + * (git://git.ideasonboard.org/omap3-isp-live.git) + * + * Copyright (C) 2010-2011 Ideas on board SPRL + * + * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com> + */ + +#include <errno.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <linux/videodev2.h> + +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/select.h> +#include <sys/time.h> + +#include "list.h" +#include "tools.h" +#include "v4l2.h" + +#ifndef V4L2_BUF_FLAG_ERROR +#define V4L2_BUF_FLAG_ERROR	0x0040 +#endif + +struct v4l2_ival_desc { +	struct v4l2_fract min; +	struct v4l2_fract max; +	struct v4l2_fract step; + +	struct list_entry list; +}; + +struct v4l2_frame_desc { +	unsigned int min_width; +	unsigned int min_height; +	unsigned int max_width; +	unsigned int max_height; +	unsigned int step_width; +	unsigned int step_height; + +	struct list_entry list; +	struct list_entry ivals; +}; + +struct v4l2_format_desc { +	unsigned int pixelformat; + +	struct list_entry list; +	struct list_entry frames; +}; + +/* ----------------------------------------------------------------------------- + * Formats enumeration + */ + +static int +v4l2_enum_frame_intervals(struct v4l2_device *dev, struct v4l2_format_desc *format, +	struct v4l2_frame_desc *frame) +{ +	struct v4l2_ival_desc *ival; +	unsigned int i; +	int ret; + +	for (i = 0; ; ++i) { +		struct v4l2_frmivalenum ivalenum; + +		memset(&ivalenum, 0, sizeof ivalenum); +		ivalenum.index = i; +		ivalenum.pixel_format = format->pixelformat; +		ivalenum.width = frame->min_width; +		ivalenum.height = frame->min_height; +		ret = ioctl(dev->fd, VIDIOC_ENUM_FRAMEINTERVALS, &ivalenum); +		if (ret < 0) +			break; + +		if (i != ivalenum.index) +			printf("Warning: driver returned wrong ival index " +				"%u.\n", ivalenum.index); +		if (format->pixelformat != ivalenum.pixel_format) +			printf("Warning: driver returned wrong ival pixel " +				"format %08x.\n", ivalenum.pixel_format); +		if (frame->min_width != ivalenum.width) +			printf("Warning: driver returned wrong ival width " +				"%u.\n", ivalenum.width); +		if (frame->min_height != ivalenum.height) +			printf("Warning: driver returned wrong ival height " +				"%u.\n", ivalenum.height); + +		ival = malloc(sizeof *ival); +		if (ival == NULL) +			return -ENOMEM; + +		memset(ival, 0, sizeof *ival); + +		switch (ivalenum.type) { +		case V4L2_FRMIVAL_TYPE_DISCRETE: +			ival->min = ivalenum.discrete; +			ival->max = ivalenum.discrete; +			ival->step.numerator = 1; +			ival->step.denominator = 1; +			break; + +		case V4L2_FRMIVAL_TYPE_STEPWISE: +			ival->min = ivalenum.stepwise.min; +			ival->max = ivalenum.stepwise.max; +			ival->step = ivalenum.stepwise.step; +			break; + +		default: +			printf("Error: driver returned invalid frame ival " +				"type %u\n", ivalenum.type); +			return -EINVAL; +		} + +		list_append(&ival->list, &frame->ivals); +	} + +	return 0; +} + +static int +v4l2_enum_frame_sizes(struct v4l2_device *dev, struct v4l2_format_desc *format) +{ +	struct v4l2_frame_desc *frame; +	unsigned int i; +	int ret; + +	for (i = 0; ; ++i) { +		struct v4l2_frmsizeenum frmenum; + +		memset(&frmenum, 0, sizeof frmenum); +		frmenum.index = i; +		frmenum.pixel_format = format->pixelformat; + +		ret = ioctl(dev->fd, VIDIOC_ENUM_FRAMESIZES, &frmenum); +		if (ret < 0) +			break; + +		if (i != frmenum.index) +			printf("Warning: driver returned wrong frame index " +				"%u.\n", frmenum.index); +		if (format->pixelformat != frmenum.pixel_format) +			printf("Warning: driver returned wrong frame pixel " +				"format %08x.\n", frmenum.pixel_format); + +		frame = malloc(sizeof *frame); +		if (frame == NULL) +			return -ENOMEM; + +		memset(frame, 0, sizeof *frame); + +		list_init(&frame->ivals); +		frame->step_width = 1; +		frame->step_height = 1; + +		switch (frmenum.type) { +		case V4L2_FRMSIZE_TYPE_DISCRETE: +			frame->min_width = frmenum.discrete.width; +			frame->min_height = frmenum.discrete.height; +			frame->max_width = frmenum.discrete.width; +			frame->max_height = frmenum.discrete.height; +			break; + +		case V4L2_FRMSIZE_TYPE_STEPWISE: +			frame->step_width = frmenum.stepwise.step_width; +			frame->step_height = frmenum.stepwise.step_height; +		case V4L2_FRMSIZE_TYPE_CONTINUOUS: +			frame->min_width = frmenum.stepwise.min_width; +			frame->min_height = frmenum.stepwise.min_height; +			frame->max_width = frmenum.stepwise.max_width; +			frame->max_height = frmenum.stepwise.max_height; +			break; + +		default: +			printf("Error: driver returned invalid frame size " +				"type %u\n", frmenum.type); +			return -EINVAL; +		} + +		list_append(&frame->list, &format->frames); + +		ret = v4l2_enum_frame_intervals(dev, format, frame); +		if (ret < 0) +			return ret; +	} + +	return 0; +} +static int v4l2_enum_formats(struct v4l2_device *dev) +{ +	struct v4l2_format_desc *format; +	unsigned int i; +	int ret; + +	for (i = 0; ; ++i) { +		struct v4l2_fmtdesc fmtenum; + +		memset(&fmtenum, 0, sizeof fmtenum); +		fmtenum.index = i; +		fmtenum.type = dev->type; + +		ret = ioctl(dev->fd, VIDIOC_ENUM_FMT, &fmtenum); +		if (ret < 0) +			break; + +		if (i != fmtenum.index) +			printf("Warning: driver returned wrong format index " +				"%u.\n", fmtenum.index); +		if (dev->type != fmtenum.type) +			printf("Warning: driver returned wrong format type " +				"%u.\n", fmtenum.type); + +		format = malloc(sizeof *format); +		if (format == NULL) +			return -ENOMEM; + +		memset(format, 0, sizeof *format); + +		list_init(&format->frames); +		format->pixelformat = fmtenum.pixelformat; + +		list_append(&format->list, &dev->formats); + +		ret = v4l2_enum_frame_sizes(dev, format); +		if (ret < 0) +			return ret; +	} + +	return 0; +} + +/* ----------------------------------------------------------------------------- + * Open/close + */ + +struct v4l2_device *v4l2_open(const char *devname) +{ +	struct v4l2_device *dev; +	struct v4l2_capability cap; +	__u32 capabilities; +	int ret; + +	dev = malloc(sizeof *dev); +	if (dev == NULL) +		return NULL; + +	memset(dev, 0, sizeof *dev); +	dev->fd = -1; +	dev->name = strdup(devname); +	list_init(&dev->formats); + +	dev->fd = open(devname, O_RDWR | O_NONBLOCK); +	if (dev->fd < 0) { +		printf("Error opening device %s: %d.\n", devname, errno); +		v4l2_close(dev); +		return NULL; +	} + +	memset(&cap, 0, sizeof cap); +	ret = ioctl(dev->fd, VIDIOC_QUERYCAP, &cap); +	if (ret < 0) { +		printf("Error opening device %s: unable to query " +			"device.\n", devname); +		v4l2_close(dev); +		return NULL; +	} + +	/*  +	 * If the device_caps field is set use it, otherwise use the older +	 * capabilities field. +	 */ +	capabilities = cap.device_caps ? : cap.capabilities; + +	if (capabilities & V4L2_CAP_VIDEO_CAPTURE) +		dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; +	else if (capabilities & V4L2_CAP_VIDEO_OUTPUT) +		dev->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; +	else { +		printf("Error opening device %s: neither video capture " +			"nor video output supported.\n", devname); +		v4l2_close(dev); +		return NULL; +	} + +	ret = v4l2_enum_formats(dev); +	if (ret < 0) { +		printf("Error opening device %s: unable to enumerate " +			"formats.\n", devname); +		v4l2_close(dev); +		return NULL; +	} + +	printf("Device %s opened: %s (%s).\n", devname, cap.card, cap.bus_info); + +	return dev; +} + +void v4l2_close(struct v4l2_device *dev) +{ +	struct v4l2_format_desc *format, *next_fmt; +	struct v4l2_frame_desc *frame, *next_frm; +	struct v4l2_ival_desc *ival, *next_ival; + +	if (dev == NULL) +		return; + +	list_for_each_entry_safe(format, next_fmt, &dev->formats, list) { +		list_for_each_entry_safe(frame, next_frm, &format->frames, list) { +			list_for_each_entry_safe(ival, next_ival, &frame->ivals, list) { +				free(ival); +			} +			free(frame); +		} +		free(format); +	} + +	free(dev->name); +	close(dev->fd); +} + +/* ----------------------------------------------------------------------------- + * Controls + */ + +int v4l2_get_control(struct v4l2_device *dev, unsigned int id, int32_t *value) +{ +	struct v4l2_control ctrl; +	int ret; + +	ctrl.id = id; + +	ret = ioctl(dev->fd, VIDIOC_G_CTRL, &ctrl); +	if (ret < 0) { +		printf("%s: unable to get control (%d).\n", dev->name, errno); +		return -errno; +	} + +	*value = ctrl.value; +	return 0; +} + +int v4l2_set_control(struct v4l2_device *dev, unsigned int id, int32_t *value) +{ +	struct v4l2_control ctrl; +	int ret; + +	ctrl.id = id; +	ctrl.value = *value; + +	ret = ioctl(dev->fd, VIDIOC_S_CTRL, &ctrl); +	if (ret < 0) { +		printf("%s: unable to set control (%d).\n", dev->name, errno); +		return -errno; +	} + +	*value = ctrl.value; +	return 0; +} + +int v4l2_get_controls(struct v4l2_device *dev, unsigned int count, +		      struct v4l2_ext_control *ctrls) +{ +	struct v4l2_ext_controls controls; +	int ret; + +	memset(&controls, 0, sizeof controls); +	controls.count = count; +	controls.controls = ctrls; + +	ret = ioctl(dev->fd, VIDIOC_G_EXT_CTRLS, &controls); +	if (ret < 0) +		printf("%s: unable to get multiple controls (%d).\n", dev->name, +		       errno); + +	return ret; +} + +int v4l2_set_controls(struct v4l2_device *dev, unsigned int count, +		      struct v4l2_ext_control *ctrls) +{ +	struct v4l2_ext_controls controls; +	int ret; + +	memset(&controls, 0, sizeof controls); +	controls.count = count; +	controls.controls = ctrls; + +	ret = ioctl(dev->fd, VIDIOC_S_EXT_CTRLS, &controls); +	if (ret < 0) +		printf("%s: unable to set multiple controls (%d).\n", dev->name, +		       errno); + +	return ret; +} + +/* ----------------------------------------------------------------------------- + * Formats and frame rates + */ + +int v4l2_get_crop(struct v4l2_device *dev, struct v4l2_rect *rect) +{ +	struct v4l2_crop crop; +	int ret; + +	memset(&crop, 0, sizeof crop); +	crop.type = dev->type; + +	ret = ioctl(dev->fd, VIDIOC_G_CROP, &crop); +	if (ret < 0) { +		printf("%s: unable to get crop rectangle (%d).\n", dev->name, +		       errno); +		return -errno; +	} + +	dev->crop = crop.c; +	*rect = crop.c; + +	return 0; +} + +int v4l2_set_crop(struct v4l2_device *dev, struct v4l2_rect *rect) +{ +	struct v4l2_crop crop; +	int ret; + +	memset(&crop, 0, sizeof crop); +	crop.type = dev->type; +	crop.c = *rect; + +	ret = ioctl(dev->fd, VIDIOC_S_CROP, &crop); +	if (ret < 0) { +		printf("%s: unable to set crop rectangle (%d).\n", dev->name, +		       errno); +		return -errno; +	} + +	dev->crop = crop.c; +	*rect = crop.c; + +	return 0; +} + +int v4l2_get_format(struct v4l2_device *dev, struct v4l2_pix_format *format) +{ +	struct v4l2_format fmt; +	int ret; + +	memset(&fmt, 0, sizeof fmt); +	fmt.type = dev->type; + +	ret = ioctl(dev->fd, VIDIOC_G_FMT, &fmt); +	if (ret < 0) { +		printf("%s: unable to get format (%d).\n", dev->name, errno); +		return -errno; +	} + +	dev->format = fmt.fmt.pix; +	*format = fmt.fmt.pix; + +	return 0; +} + +int v4l2_set_format(struct v4l2_device *dev, struct v4l2_pix_format *format) +{ +	struct v4l2_format fmt; +	int ret; + +	memset(&fmt, 0, sizeof fmt); +	fmt.type = dev->type; +	fmt.fmt.pix.width = format->width; +	fmt.fmt.pix.height = format->height; +	fmt.fmt.pix.pixelformat = format->pixelformat; +	fmt.fmt.pix.field = V4L2_FIELD_ANY; + +	ret = ioctl(dev->fd, VIDIOC_S_FMT, &fmt); +	if (ret < 0) { +		printf("%s: unable to set format (%d).\n", dev->name, errno); +		return -errno; +	} + +	dev->format = fmt.fmt.pix; +	*format = fmt.fmt.pix; + +	return 0; +} + +/* ----------------------------------------------------------------------------- + * Buffers management + */ + +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; + +	/* Request the buffers from the driver. */ +	memset(&rb, 0, sizeof rb); +	rb.count = nbufs; +	rb.type = dev->type; +	rb.memory = memtype; + +	ret = ioctl(dev->fd, VIDIOC_REQBUFS, &rb); +	if (ret < 0) { +		printf("%s: unable to request buffers (%d).\n", dev->name, +		       errno); +		ret = -errno; +		goto done; +	} + +	if (rb.count > nbufs) { +		printf("%s: driver needs more buffers (%u) than available (%u).\n", +		       dev->name, rb.count, nbufs); +		ret = -E2BIG; +		goto done; +	} + +	printf("%s: %u buffers requested.\n", dev->name, rb.count); + +	/* Allocate the buffer objects. */ +	dev->memtype = memtype; +	dev->nbufs = rb.count; + +	dev->buffers = malloc(sizeof *dev->buffers * nbufs); +	if (dev->buffers == NULL) { +		ret = -ENOMEM; +		goto done; +	} + +	memset(dev->buffers, 0, sizeof *dev->buffers * nbufs); + +	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: +	if (ret < 0) +		v4l2_free_buffers(dev); + +	return ret; +} + +int v4l2_free_buffers(struct v4l2_device *dev) +{ +	struct v4l2_requestbuffers rb; +	unsigned int i; +	int ret; + +	if (dev->nbufs == 0) +		return 0; + +	if (dev->memtype == V4L2_MEMORY_MMAP) { +		for (i = 0; i < dev->nbufs; ++i) { +			struct v4l2_video_buffer *buffer = &dev->buffers[i]; + +			if (buffer->mem == NULL) +				continue; + +			ret = munmap(buffer->mem, buffer->size); +			if (ret < 0) { +				printf("%s: unable to unmap buffer %u (%d)\n", +				       dev->name, i, errno); +				return -errno; +			} + +			buffer->mem = NULL; +			buffer->size = 0; +		} +	} + +	memset(&rb, 0, sizeof rb); +	rb.count = 0; +	rb.type = dev->type; +	rb.memory = dev->memtype; + +	ret = ioctl(dev->fd, VIDIOC_REQBUFS, &rb); +	if (ret < 0) { +		printf("%s: unable to release buffers (%d)\n", dev->name, +		       errno); +		return -errno; +	} + +	free(dev->buffers); +	dev->buffers = NULL; +	dev->nbufs = 0; + +	return 0; +} + +int v4l2_dequeue_buffer(struct v4l2_device *dev, struct v4l2_video_buffer *buffer) +{ +	struct v4l2_buffer buf; +	int ret; + +	memset(&buf, 0, sizeof buf); +	buf.type = dev->type; +	buf.memory = dev->memtype; + +	ret = ioctl(dev->fd, VIDIOC_DQBUF, &buf); +	if (ret < 0) { +		printf("%s: unable to dequeue buffer index %u/%u (%d)\n", +		       dev->name, buf.index, dev->nbufs, errno); +		return -errno; +	} + +	*buffer = dev->buffers[buf.index]; +	buffer->bytesused = buf.bytesused; +	buffer->timestamp = buf.timestamp; +	buffer->error = !!(buf.flags & V4L2_BUF_FLAG_ERROR); + +	return 0; +} + +int v4l2_queue_buffer(struct v4l2_device *dev, struct v4l2_video_buffer *buffer) +{ +	struct v4l2_buffer buf; +	int ret; + +	if (buffer->index >= dev->nbufs) +		return -EINVAL; + +	memset(&buf, 0, sizeof buf); +	buf.index = buffer->index; +	buf.type = dev->type; +	buf.memory = dev->memtype; + +	if (dev->memtype == V4L2_MEMORY_USERPTR) +		buf.m.userptr = (unsigned long)dev->buffers[buffer->index].mem; + +	buf.length = dev->buffers[buffer->index].size; + +	if (dev->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) +		buf.bytesused = buffer->bytesused; + +	ret = ioctl(dev->fd, VIDIOC_QBUF, &buf); +	if (ret < 0) { +		printf("%s: unable to queue buffer index %u/%u (%d)\n", +		       dev->name, buf.index, dev->nbufs, errno); +		return -errno; +	} + +	return 0; +} + +/* ----------------------------------------------------------------------------- + * Stream management + */ + +int v4l2_stream_on(struct v4l2_device *dev) +{ +	int type = dev->type; +	int ret; + +	ret = ioctl(dev->fd, VIDIOC_STREAMON, &type); +	if (ret < 0) +		return -errno; + +	return 0; +} + +int v4l2_stream_off(struct v4l2_device *dev) +{ +	int type = dev->type; +	int ret; + +	ret = ioctl(dev->fd, VIDIOC_STREAMOFF, &type); +	if (ret < 0) +		return -errno; + +	return 0; +} @@ -0,0 +1,303 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * V4L2 Devices + * + * Copyright (C) 2018 Laurent Pinchart + * + * This file originally comes from the omap3-isp-live project + * (git://git.ideasonboard.org/omap3-isp-live.git) + * + * Copyright (C) 2010-2011 Ideas on board SPRL + * + * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com> + */ +#ifndef __V4L2_H +#define __V4L2_H + +#include <stdbool.h> + +#include <linux/videodev2.h> + +#include <sys/time.h> + +#include "list.h" + +/* + * struct v4l2_video_buffer - Video buffer information + * @index: Zero-based buffer index, limited to the number of buffers minus one + * @size: Size of the video memory, in bytes + * @bytesused: Number of bytes used by video data, smaller or equal to @size + * @timestamp: Time stamp at which the buffer has been captured + * @error: True if an error occured while capturing video data for the buffer + * @allocated: True if memory for the buffer has been allocated + * @mem: Video data memory + * @fd: Video data dmabuf handle + */ +struct v4l2_video_buffer +{ +	unsigned int index; +	unsigned int size; +	unsigned int bytesused; +	struct timeval timestamp; +	bool error; +	bool allocated; +	void *mem; +	int fd; +}; + +struct v4l2_device +{ +	int fd; +	char *name; + +	enum v4l2_buf_type type; +	enum v4l2_memory memtype; + +	struct list_entry formats; +	struct v4l2_pix_format format; +	struct v4l2_rect crop; + +	unsigned int nbufs; +	struct v4l2_video_buffer *buffers; +}; + +/* + * v4l2_open - Open a V4L2 device + * @devname: Name (including path) of the device node + * + * Open the V4L2 device referenced by @devname for video capture or display in + * non-blocking mode. + * + * If the device can be opened, query its capabilities and enumerates frame + * formats, sizes and intervals. + * + * Return a pointer to a newly allocated v4l2_device structure instance on + * success and NULL on failure. The returned pointer must be freed with + * v4l2_close when the device isn't needed anymore. + */ +struct v4l2_device *v4l2_open(const char *devname); + +/* + * v4l2_close - Close a V4L2 device + * @dev: Device instance + * + * Close the device instance given as argument and free allocated resources. + * Access to the device instance is forbidden after this function returns. + */ +void v4l2_close(struct v4l2_device *dev); + +/* + * v4l2_get_format - Retrieve the current pixel format + * @dev: Device instance + * @format: Pixel format structure to be filled + * + * Query the device to retrieve the current pixel format and frame size and fill + * the @format structure. + * + * Return 0 on success or a negative error code on failure. + */ +int v4l2_get_format(struct v4l2_device *dev, struct v4l2_pix_format *format); + +/* + * v4l2_set_format - Set the pixel format + * @dev: Device instance + * @format: Pixel format structure to be set + * + * Set the pixel format and frame size stored in @format. The device can modify + * the requested format and size, in which case the @format structure will be + * updated to reflect the modified settings. + * + * Return 0 on success or a negative error code on failure. + */ +int v4l2_set_format(struct v4l2_device *dev, struct v4l2_pix_format *format); + +/* + * v4l2_get_crop - Retrieve the current crop rectangle + * @dev: Device instance + * @rect: Crop rectangle structure to be filled + * + * Query the device to retrieve the current crop rectangle and fill the @rect + * structure. + * + * Return 0 on success or a negative error code on failure. + */ +int v4l2_get_crop(struct v4l2_device *dev, struct v4l2_rect *rect); + +/* + * v4l2_set_crop - Set the crop rectangle + * @dev: Device instance + * @rect: Crop rectangle structure to be set + * + * Set the crop rectangle stored in @rect. The device can modify the requested + * rectangle, in which case the @rect structure will be updated to reflect the + * modified settings. + * + * Return 0 on success or a negative error code on failure. + */ +int v4l2_set_crop(struct v4l2_device *dev, struct v4l2_rect *rect); + +/* + * v4l2_alloc_buffers - Allocate buffers for video frames + * @dev: Device instance + * @memtype: Type of buffers + * @nbufs: Number of buffers to allocate + * + * Request the driver to allocate @nbufs buffers. The driver can modify the + * number of buffers depending on its needs. The number of allocated buffers + * 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. + * + * Return 0 on success or a negative error code on failure. + */ +int v4l2_alloc_buffers(struct v4l2_device *dev, enum v4l2_memory memtype, +		       unsigned int nbufs); + +/* + * v4l2_free_buffers - Free buffers + * @dev: Device instance + * + * Free buffers previously allocated by v4l2_alloc_buffers(). If the buffers + * have been allocated with the V4L2_MEMORY_USERPTR memory type only the buffer + * objects are freed, and the caller is responsible for freeing the video frames + * memory if required. + * + * When successful this function sets the @dev::nbufs field to zero. + * + * Return 0 on success or a negative error code on failure. + */ +int v4l2_free_buffers(struct v4l2_device *dev); + +/* + * v4l2_queue_buffer - Queue a buffer for video capture/output + * @dev: Device instance + * @buffer: Buffer to be queued + * + * Queue the buffer identified by @buffer for video capture or output, depending + * on the device type. + * + * The caller must initialize the @buffer::index field with the index of the + * buffer to be queued. The index is zero-based and must be lower than the + * number of allocated buffers. + * + * For V4L2_MEMORY_USERPTR buffers, the caller must initialize the @buffer::mem + * field with the address of the video frame memory, and the @buffer:length + * field with its size in bytes. For optimal performances the address and length + * should be identical between v4l2_queue_buffer() calls for a given buffer + * index. + * + * For video output, the caller must initialize the @buffer::bytesused field + * with the size of video data. The value should differ from the buffer length + * for variable-size video formats only. + * + * Upon successful return the buffer ownership is transferred to the driver. The + * caller must not touch video memory for that buffer before calling + * v4l2_dequeue_buffer(). Attempting to queue an already queued buffer will + * fail. + * + * Return 0 on success or a negative error code on failure. + */ +int v4l2_queue_buffer(struct v4l2_device *dev, struct v4l2_video_buffer *buffer); + +/* + * v4l2_dequeue_buffer - Dequeue the next buffer + * @dev: Device instance + * @buffer: Dequeued buffer data to be filled + * + * Dequeue the next buffer processed by the driver and fill all fields in + * @buffer.  + * + * This function does not block. If no buffer is ready it will return + * immediately with -EAGAIN. + * + * If an error occured during video capture or display, the @buffer::error field + * is set to true. Depending on the device the video data can be partly + * corrupted or complete garbage. + * + * Once dequeued the buffer ownership is transferred to the caller. Video memory + * for that buffer can be safely read from and written to. + * + * Return 0 on success or a negative error code on failure. An error that + * results in @buffer:error being set is not considered as a failure condition + * for the purpose of the return value. + */ +int v4l2_dequeue_buffer(struct v4l2_device *dev, struct v4l2_video_buffer *buffer); + +/* + * v4l2_stream_on - Start video streaming + * @dev: Device instance + * + * Start video capture or output on the device. For video output devices at + * least one buffer must be queued before starting the stream. + * + * Return 0 on success or a negative error code on failure. + */ +int v4l2_stream_on(struct v4l2_device *dev); + +/* + * v4l2_stream_off - Stop video streaming + * @dev: Device instance + * + * Stop video capture or output on the device. Upon successful return ownership + * of all buffers is returned to the caller. + * + * Return 0 on success or a negative error code on failure. + */ +int v4l2_stream_off(struct v4l2_device *dev); + +/* + * v4l2_get_control - Read the value of a control + * @dev: Device instance + * @id: Control ID + * @value: Control value to be filled + * + * Retrieve the current value of control @id and store it in @value. + * + * Return 0 on success or a negative error code on failure. + */ +int v4l2_get_control(struct v4l2_device *dev, unsigned int id, int32_t *value); + +/* + * v4l2_set_control - Write the value of a control + * @dev: Device instance + * @id: Control ID + * @value: Control value + * + * Set control @id to @value. The device is allowed to modify the requested + * value, in which case @value is updated to the modified value. + * + * Return 0 on success or a negative error code on failure. + */ +int v4l2_set_control(struct v4l2_device *dev, unsigned int id, int32_t *value); + +/* + * v4l2_get_controls - Read the value of multiple controls + * @dev: Device instance + * @count: Number of controls + * @ctrls: Controls to be read + * + * Retrieve the current value of controls identified by @ctrls. + * + * Return 0 on success or a negative error code on failure. + */ +int v4l2_get_controls(struct v4l2_device *dev, unsigned int count, +		      struct v4l2_ext_control *ctrls); + +/* + * v4l2_set_controls - Write the value of multiple controls + * @dev: Device instance + * @count: Number of controls + * @ctrls: Controls to be written + * + * Set controls identified by @ctrls. The device is allowed to modify the + * requested values, in which case @ctrls is updated to the modified value. + * + * Return 0 on success or a negative error code on failure. + */ +int v4l2_set_controls(struct v4l2_device *dev, unsigned int count, +		      struct v4l2_ext_control *ctrls); + +#endif | 
