From 10905d70d78841a6fa191be5ec193e3c0d63555f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 21 May 2018 04:54:27 -0400 Subject: media: media-request: implement media requests Add initial media request support: 1) Add MEDIA_IOC_REQUEST_ALLOC ioctl support to media-device.c 2) Add struct media_request to store request objects. 3) Add struct media_request_object to represent a request object. 4) Add MEDIA_REQUEST_IOC_QUEUE/REINIT ioctl support. Basic lifecycle: the application allocates a request, adds objects to it, queues the request, polls until it is completed and can then read the final values of the objects at the time of completion. When it closes the file descriptor the request memory will be freed (actually, when the last user of that request releases the request). Drivers will bind an object to a request (the 'adds objects to it' phase), when MEDIA_REQUEST_IOC_QUEUE is called the request is validated (req_validate op), then queued (the req_queue op). When done with an object it can either be unbound from the request (e.g. when the driver has finished with a vb2 buffer) or marked as completed (e.g. for controls associated with a buffer). When all objects in the request are completed (or unbound), then the request fd will signal an exception (poll). Co-developed-by: Sakari Ailus Co-developed-by: Laurent Pinchart Co-developed-by: Alexandre Courbot Signed-off-by: Hans Verkuil Signed-off-by: Sakari Ailus Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- include/media/media-device.h | 29 ++++ include/media/media-request.h | 334 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 363 insertions(+) create mode 100644 include/media/media-request.h (limited to 'include/media') diff --git a/include/media/media-device.h b/include/media/media-device.h index bcc6ec434f1f..c8ddbfe8b74c 100644 --- a/include/media/media-device.h +++ b/include/media/media-device.h @@ -27,6 +27,7 @@ struct ida; struct device; +struct media_device; /** * struct media_entity_notify - Media Entity Notify @@ -50,10 +51,32 @@ struct media_entity_notify { * struct media_device_ops - Media device operations * @link_notify: Link state change notification callback. This callback is * called with the graph_mutex held. + * @req_alloc: Allocate a request. Set this if you need to allocate a struct + * larger then struct media_request. @req_alloc and @req_free must + * either both be set or both be NULL. + * @req_free: Free a request. Set this if @req_alloc was set as well, leave + * to NULL otherwise. + * @req_validate: Validate a request, but do not queue yet. The req_queue_mutex + * lock is held when this op is called. + * @req_queue: Queue a validated request, cannot fail. If something goes + * wrong when queueing this request then it should be marked + * as such internally in the driver and any related buffers + * must eventually return to vb2 with state VB2_BUF_STATE_ERROR. + * The req_queue_mutex lock is held when this op is called. + * It is important that vb2 buffer objects are queued last after + * all other object types are queued: queueing a buffer kickstarts + * the request processing, so all other objects related to the + * request (and thus the buffer) must be available to the driver. + * And once a buffer is queued, then the driver can complete + * or delete objects from the request before req_queue exits. */ struct media_device_ops { int (*link_notify)(struct media_link *link, u32 flags, unsigned int notification); + struct media_request *(*req_alloc)(struct media_device *mdev); + void (*req_free)(struct media_request *req); + int (*req_validate)(struct media_request *req); + void (*req_queue)(struct media_request *req); }; /** @@ -88,6 +111,9 @@ struct media_device_ops { * @disable_source: Disable Source Handler function pointer * * @ops: Operation handler callbacks + * @req_queue_mutex: Serialise the MEDIA_REQUEST_IOC_QUEUE ioctl w.r.t. + * other operations that stop or start streaming. + * @request_id: Used to generate unique request IDs * * This structure represents an abstract high-level media device. It allows easy * access to entities and provides basic media device-level support. The @@ -158,6 +184,9 @@ struct media_device { void (*disable_source)(struct media_entity *entity); const struct media_device_ops *ops; + + struct mutex req_queue_mutex; + atomic_t request_id; }; /* We don't need to include pci.h or usb.h here */ diff --git a/include/media/media-request.h b/include/media/media-request.h new file mode 100644 index 000000000000..9664ebac5dc4 --- /dev/null +++ b/include/media/media-request.h @@ -0,0 +1,334 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Media device request objects + * + * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * Copyright (C) 2018 Intel Corporation + * + * Author: Hans Verkuil + * Author: Sakari Ailus + */ + +#ifndef MEDIA_REQUEST_H +#define MEDIA_REQUEST_H + +#include +#include +#include +#include + +#include + +/** + * enum media_request_state - media request state + * + * @MEDIA_REQUEST_STATE_IDLE: Idle + * @MEDIA_REQUEST_STATE_VALIDATING: Validating the request, no state changes + * allowed + * @MEDIA_REQUEST_STATE_QUEUED: Queued + * @MEDIA_REQUEST_STATE_COMPLETE: Completed, the request is done + * @MEDIA_REQUEST_STATE_CLEANING: Cleaning, the request is being re-inited + * @MEDIA_REQUEST_STATE_UPDATING: The request is being updated, i.e. + * request objects are being added, + * modified or removed + * @NR_OF_MEDIA_REQUEST_STATE: The number of media request states, used + * internally for sanity check purposes + */ +enum media_request_state { + MEDIA_REQUEST_STATE_IDLE, + MEDIA_REQUEST_STATE_VALIDATING, + MEDIA_REQUEST_STATE_QUEUED, + MEDIA_REQUEST_STATE_COMPLETE, + MEDIA_REQUEST_STATE_CLEANING, + MEDIA_REQUEST_STATE_UPDATING, + NR_OF_MEDIA_REQUEST_STATE, +}; + +struct media_request_object; + +/** + * struct media_request - Media device request + * @mdev: Media device this request belongs to + * @kref: Reference count + * @debug_str: Prefix for debug messages (process name:fd) + * @state: The state of the request + * @updating_count: count the number of request updates that are in progress + * @objects: List of @struct media_request_object request objects + * @num_incomplete_objects: The number of incomplete objects in the request + * @poll_wait: Wait queue for poll + * @lock: Serializes access to this struct + */ +struct media_request { + struct media_device *mdev; + struct kref kref; + char debug_str[TASK_COMM_LEN + 11]; + enum media_request_state state; + unsigned int updating_count; + struct list_head objects; + unsigned int num_incomplete_objects; + struct wait_queue_head poll_wait; + spinlock_t lock; +}; + +#ifdef CONFIG_MEDIA_CONTROLLER + +/** + * media_request_lock_for_update - Lock the request for updating its objects + * + * @req: The media request + * + * Use before updating a request, i.e. adding, modifying or removing a request + * object in it. A reference to the request must be held during the update. This + * usually takes place automatically through a file handle. Use + * @media_request_unlock_for_update when done. + */ +static inline int __must_check +media_request_lock_for_update(struct media_request *req) +{ + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&req->lock, flags); + if (req->state == MEDIA_REQUEST_STATE_IDLE || + req->state == MEDIA_REQUEST_STATE_UPDATING) { + req->state = MEDIA_REQUEST_STATE_UPDATING; + req->updating_count++; + } else { + ret = -EBUSY; + } + spin_unlock_irqrestore(&req->lock, flags); + + return ret; +} + +/** + * media_request_unlock_for_update - Unlock a request previously locked for + * update + * + * @req: The media request + * + * Unlock a request that has previously been locked using + * @media_request_lock_for_update. + */ +static inline void media_request_unlock_for_update(struct media_request *req) +{ + unsigned long flags; + + spin_lock_irqsave(&req->lock, flags); + WARN_ON(req->updating_count <= 0); + if (!--req->updating_count) + req->state = MEDIA_REQUEST_STATE_IDLE; + spin_unlock_irqrestore(&req->lock, flags); +} + +/** + * media_request_get - Get the media request + * + * @req: The media request + * + * Get the media request. + */ +static inline void media_request_get(struct media_request *req) +{ + kref_get(&req->kref); +} + +/** + * media_request_put - Put the media request + * + * @req: The media request + * + * Put the media request. The media request will be released + * when the refcount reaches 0. + */ +void media_request_put(struct media_request *req); + +/** + * media_request_alloc - Allocate the media request + * + * @mdev: Media device this request belongs to + * @alloc_fd: Store the request's file descriptor in this int + * + * Allocated the media request and put the fd in @alloc_fd. + */ +int media_request_alloc(struct media_device *mdev, + int *alloc_fd); + +#else + +static inline void media_request_get(struct media_request *req) +{ +} + +static inline void media_request_put(struct media_request *req) +{ +} + +#endif + +/** + * struct media_request_object_ops - Media request object operations + * @prepare: Validate and prepare the request object, optional. + * @unprepare: Unprepare the request object, optional. + * @queue: Queue the request object, optional. + * @unbind: Unbind the request object, optional. + * @release: Release the request object, required. + */ +struct media_request_object_ops { + int (*prepare)(struct media_request_object *object); + void (*unprepare)(struct media_request_object *object); + void (*queue)(struct media_request_object *object); + void (*unbind)(struct media_request_object *object); + void (*release)(struct media_request_object *object); +}; + +/** + * struct media_request_object - An opaque object that belongs to a media + * request + * + * @ops: object's operations + * @priv: object's priv pointer + * @req: the request this object belongs to (can be NULL) + * @list: List entry of the object for @struct media_request + * @kref: Reference count of the object, acquire before releasing req->lock + * @completed: If true, then this object was completed. + * + * An object related to the request. This struct is always embedded in + * another struct that contains the actual data for this request object. + */ +struct media_request_object { + const struct media_request_object_ops *ops; + void *priv; + struct media_request *req; + struct list_head list; + struct kref kref; + bool completed; +}; + +#ifdef CONFIG_MEDIA_CONTROLLER + +/** + * media_request_object_get - Get a media request object + * + * @obj: The object + * + * Get a media request object. + */ +static inline void media_request_object_get(struct media_request_object *obj) +{ + kref_get(&obj->kref); +} + +/** + * media_request_object_put - Put a media request object + * + * @obj: The object + * + * Put a media request object. Once all references are gone, the + * object's memory is released. + */ +void media_request_object_put(struct media_request_object *obj); + +/** + * media_request_object_init - Initialise a media request object + * + * @obj: The object + * + * Initialise a media request object. The object will be released using the + * release callback of the ops once it has no references (this function + * initialises references to one). + */ +void media_request_object_init(struct media_request_object *obj); + +/** + * media_request_object_bind - Bind a media request object to a request + * + * @req: The media request + * @ops: The object ops for this object + * @priv: A driver-specific priv pointer associated with this object + * @is_buffer: Set to true if the object a buffer object. + * @obj: The object + * + * Bind this object to the request and set the ops and priv values of + * the object so it can be found later with media_request_object_find(). + * + * Every bound object must be unbound or completed by the kernel at some + * point in time, otherwise the request will never complete. When the + * request is released all completed objects will be unbound by the + * request core code. + * + * Buffer objects will be added to the end of the request's object + * list, non-buffer objects will be added to the front of the list. + * This ensures that all buffer objects are at the end of the list + * and that all non-buffer objects that they depend on are processed + * first. + */ +int media_request_object_bind(struct media_request *req, + const struct media_request_object_ops *ops, + void *priv, bool is_buffer, + struct media_request_object *obj); + +/** + * media_request_object_unbind - Unbind a media request object + * + * @obj: The object + * + * Unbind the media request object from the request. + */ +void media_request_object_unbind(struct media_request_object *obj); + +/** + * media_request_object_complete - Mark the media request object as complete + * + * @obj: The object + * + * Mark the media request object as complete. Only bound objects can + * be completed. + */ +void media_request_object_complete(struct media_request_object *obj); + +#else + +static inline int __must_check +media_request_lock_for_update(struct media_request *req) +{ + return -EINVAL; +} + +static inline void media_request_unlock_for_update(struct media_request *req) +{ +} + +static inline void media_request_object_get(struct media_request_object *obj) +{ +} + +static inline void media_request_object_put(struct media_request_object *obj) +{ +} + +static inline void media_request_object_init(struct media_request_object *obj) +{ + obj->ops = NULL; + obj->req = NULL; +} + +static inline int media_request_object_bind(struct media_request *req, + const struct media_request_object_ops *ops, + void *priv, bool is_buffer, + struct media_request_object *obj) +{ + return 0; +} + +static inline void media_request_object_unbind(struct media_request_object *obj) +{ +} + +static inline void media_request_object_complete(struct media_request_object *obj) +{ +} + +#endif + +#endif -- cgit From be9d6d4b0bf9cc3644826fb95264dbddb9a6d047 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 21 May 2018 04:54:28 -0400 Subject: media: media-request: add media_request_get_by_fd Add media_request_get_by_fd() to find a request based on the file descriptor. The caller has to call media_request_put() for the returned request since this function increments the refcount. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- include/media/media-request.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'include/media') diff --git a/include/media/media-request.h b/include/media/media-request.h index 9664ebac5dc4..1c3e5d804d07 100644 --- a/include/media/media-request.h +++ b/include/media/media-request.h @@ -143,6 +143,24 @@ static inline void media_request_get(struct media_request *req) */ void media_request_put(struct media_request *req); +/** + * media_request_get_by_fd - Get a media request by fd + * + * @mdev: Media device this request belongs to + * @request_fd: The file descriptor of the request + * + * Get the request represented by @request_fd that is owned + * by the media device. + * + * Return a -EPERM error pointer if requests are not supported + * by this driver. Return -ENOENT if the request was not found. + * Return the pointer to the request if found: the caller will + * have to call @media_request_put when it finished using the + * request. + */ +struct media_request * +media_request_get_by_fd(struct media_device *mdev, int request_fd); + /** * media_request_alloc - Allocate the media request * @@ -164,6 +182,12 @@ static inline void media_request_put(struct media_request *req) { } +static inline struct media_request * +media_request_get_by_fd(struct media_device *mdev, int request_fd) +{ + return ERR_PTR(-EPERM); +} + #endif /** -- cgit From 0ca0e8442dcd5da2af5ce35e90b083a492b4cbac Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 21 May 2018 04:54:29 -0400 Subject: media: media-request: add media_request_object_find Add media_request_object_find to find a request object inside a request based on ops and priv values. Objects of the same type (vb2 buffer, control handler) will have the same ops value. And objects that refer to the same 'parent' object (e.g. the v4l2_ctrl_handler that has the current driver state) will have the same priv value. The caller has to call media_request_object_put() for the returned object since this function increments the refcount. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- include/media/media-request.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'include/media') diff --git a/include/media/media-request.h b/include/media/media-request.h index 1c3e5d804d07..ac02019c1d77 100644 --- a/include/media/media-request.h +++ b/include/media/media-request.h @@ -253,6 +253,26 @@ static inline void media_request_object_get(struct media_request_object *obj) */ void media_request_object_put(struct media_request_object *obj); +/** + * media_request_object_find - Find an object in a request + * + * @req: The media request + * @ops: Find an object with this ops value + * @priv: Find an object with this priv value + * + * Both @ops and @priv must be non-NULL. + * + * Returns the object pointer or NULL if not found. The caller must + * call media_request_object_put() once it finished using the object. + * + * Since this function needs to walk the list of objects it takes + * the @req->lock spin lock to make this safe. + */ +struct media_request_object * +media_request_object_find(struct media_request *req, + const struct media_request_object_ops *ops, + void *priv); + /** * media_request_object_init - Initialise a media request object * @@ -331,6 +351,14 @@ static inline void media_request_object_put(struct media_request_object *obj) { } +static inline struct media_request_object * +media_request_object_find(struct media_request *req, + const struct media_request_object_ops *ops, + void *priv) +{ + return NULL; +} + static inline void media_request_object_init(struct media_request_object *obj) { obj->ops = NULL; -- cgit From 93a9d9008d3c963d5d12c56460b5e1d93dad3ea8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 23 May 2018 07:11:06 -0400 Subject: media: v4l2-device.h: add v4l2_device_supports_requests() helper Add a simple helper function that tests if the driver supports the request API. Signed-off-by: Hans Verkuil Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-device.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'include/media') diff --git a/include/media/v4l2-device.h b/include/media/v4l2-device.h index b330e4a08a6b..ac7677a183ff 100644 --- a/include/media/v4l2-device.h +++ b/include/media/v4l2-device.h @@ -211,6 +211,17 @@ static inline void v4l2_subdev_notify(struct v4l2_subdev *sd, sd->v4l2_dev->notify(sd, notification, arg); } +/** + * v4l2_device_supports_requests - Test if requests are supported. + * + * @v4l2_dev: pointer to struct v4l2_device + */ +static inline bool v4l2_device_supports_requests(struct v4l2_device *v4l2_dev) +{ + return v4l2_dev->mdev && v4l2_dev->mdev->ops && + v4l2_dev->mdev->ops->req_queue; +} + /* Helper macros to iterate over all subdevs. */ /** -- cgit From da1b1aeac1aced231ac85329112a592dc14d173a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 21 May 2018 04:54:36 -0400 Subject: media: v4l2-ctrls: v4l2_ctrl_add_handler: add from_other_dev Add a 'bool from_other_dev' argument: set to true if the two handlers refer to different devices (e.g. it is true when inheriting controls from a subdev into a main v4l2 bridge driver). This will be used later when implementing support for the request API since we need to skip such controls. Signed-off-by: Hans Verkuil Signed-off-by: Alexandre Courbot Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-ctrls.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'include/media') diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index f615ba1b29dd..192e31c21faf 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -247,6 +247,8 @@ struct v4l2_ctrl { * @ctrl: The actual control information. * @helper: Pointer to helper struct. Used internally in * ``prepare_ext_ctrls`` function at ``v4l2-ctrl.c``. + * @from_other_dev: If true, then @ctrl was defined in another + * device than the &struct v4l2_ctrl_handler. * * Each control handler has a list of these refs. The list_head is used to * keep a sorted-by-control-ID list of all controls, while the next pointer @@ -257,6 +259,7 @@ struct v4l2_ctrl_ref { struct v4l2_ctrl_ref *next; struct v4l2_ctrl *ctrl; struct v4l2_ctrl_helper *helper; + bool from_other_dev; }; /** @@ -633,6 +636,8 @@ typedef bool (*v4l2_ctrl_filter)(const struct v4l2_ctrl *ctrl); * @add: The control handler whose controls you want to add to * the @hdl control handler. * @filter: This function will filter which controls should be added. + * @from_other_dev: If true, then the controls in @add were defined in another + * device than @hdl. * * Does nothing if either of the two handlers is a NULL pointer. * If @filter is NULL, then all controls are added. Otherwise only those @@ -642,7 +647,8 @@ typedef bool (*v4l2_ctrl_filter)(const struct v4l2_ctrl *ctrl); */ int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl, struct v4l2_ctrl_handler *add, - v4l2_ctrl_filter filter); + v4l2_ctrl_filter filter, + bool from_other_dev); /** * v4l2_ctrl_radio_filter() - Standard filter for radio controls. -- cgit From 52beeddb68833e02c0923bc46868b347a6ad393c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 21 May 2018 04:54:37 -0400 Subject: media: v4l2-ctrls: prepare internal structs for request API Embed and initialize a media_request_object in struct v4l2_ctrl_handler. Add a p_req field to struct v4l2_ctrl_ref that will store the request value. Signed-off-by: Hans Verkuil Signed-off-by: Alexandre Courbot Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-ctrls.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'include/media') diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index 192e31c21faf..3f4e062d4e3d 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -20,6 +20,7 @@ #include #include #include +#include /* forward references */ struct file; @@ -249,6 +250,11 @@ struct v4l2_ctrl { * ``prepare_ext_ctrls`` function at ``v4l2-ctrl.c``. * @from_other_dev: If true, then @ctrl was defined in another * device than the &struct v4l2_ctrl_handler. + * @p_req: If the control handler containing this control reference + * is bound to a media request, then this points to the + * value of the control that should be applied when the request + * is executed, or to the value of the control at the time + * that the request was completed. * * Each control handler has a list of these refs. The list_head is used to * keep a sorted-by-control-ID list of all controls, while the next pointer @@ -260,6 +266,7 @@ struct v4l2_ctrl_ref { struct v4l2_ctrl *ctrl; struct v4l2_ctrl_helper *helper; bool from_other_dev; + union v4l2_ctrl_ptr p_req; }; /** @@ -283,6 +290,8 @@ struct v4l2_ctrl_ref { * @notify_priv: Passed as argument to the v4l2_ctrl notify callback. * @nr_of_buckets: Total number of buckets in the array. * @error: The error code of the first failed control addition. + * @req_obj: The &struct media_request_object, used to link into a + * &struct media_request. This request object has a refcount. */ struct v4l2_ctrl_handler { struct mutex _lock; @@ -295,6 +304,7 @@ struct v4l2_ctrl_handler { void *notify_priv; u16 nr_of_buckets; int error; + struct media_request_object req_obj; }; /** -- cgit From 6fa6f831f0950bf46934e6c3a9766b258a9ea85f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 21 May 2018 04:54:40 -0400 Subject: media: v4l2-ctrls: add core request support Integrate the request support. This adds the v4l2_ctrl_request_complete and v4l2_ctrl_request_setup functions to complete a request and (as a helper function) to apply a request to the hardware. It takes care of queuing requests and correctly chaining control values in the request queue. Note that when a request is marked completed it will copy control values to the internal request state. This can be optimized in the future since this is sub-optimal when dealing with large compound and/or array controls. For the initial 'stateless codec' use-case the current implementation is sufficient. Signed-off-by: Hans Verkuil Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-ctrls.h | 51 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'include/media') diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index 3f4e062d4e3d..ed784e98c293 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -250,6 +250,12 @@ struct v4l2_ctrl { * ``prepare_ext_ctrls`` function at ``v4l2-ctrl.c``. * @from_other_dev: If true, then @ctrl was defined in another * device than the &struct v4l2_ctrl_handler. + * @req_done: Internal flag: if the control handler containing this control + * reference is bound to a media request, then this is set when + * the control has been applied. This prevents applying controls + * from a cluster with multiple controls twice (when the first + * control of a cluster is applied, they all are). + * @req: If set, this refers to another request that sets this control. * @p_req: If the control handler containing this control reference * is bound to a media request, then this points to the * value of the control that should be applied when the request @@ -266,6 +272,8 @@ struct v4l2_ctrl_ref { struct v4l2_ctrl *ctrl; struct v4l2_ctrl_helper *helper; bool from_other_dev; + bool req_done; + struct v4l2_ctrl_ref *req; union v4l2_ctrl_ptr p_req; }; @@ -290,6 +298,15 @@ struct v4l2_ctrl_ref { * @notify_priv: Passed as argument to the v4l2_ctrl notify callback. * @nr_of_buckets: Total number of buckets in the array. * @error: The error code of the first failed control addition. + * @request_is_queued: True if the request was queued. + * @requests: List to keep track of open control handler request objects. + * For the parent control handler (@req_obj.req == NULL) this + * is the list header. When the parent control handler is + * removed, it has to unbind and put all these requests since + * they refer to the parent. + * @requests_queued: List of the queued requests. This determines the order + * in which these controls are applied. Once the request is + * completed it is removed from this list. * @req_obj: The &struct media_request_object, used to link into a * &struct media_request. This request object has a refcount. */ @@ -304,6 +321,9 @@ struct v4l2_ctrl_handler { void *notify_priv; u16 nr_of_buckets; int error; + bool request_is_queued; + struct list_head requests; + struct list_head requests_queued; struct media_request_object req_obj; }; @@ -1062,6 +1082,37 @@ int v4l2_ctrl_subscribe_event(struct v4l2_fh *fh, */ __poll_t v4l2_ctrl_poll(struct file *file, struct poll_table_struct *wait); +/** + * v4l2_ctrl_request_setup - helper function to apply control values in a request + * + * @req: The request + * @parent: The parent control handler ('priv' in media_request_object_find()) + * + * This is a helper function to call the control handler's s_ctrl callback with + * the control values contained in the request. Do note that this approach of + * applying control values in a request is only applicable to memory-to-memory + * devices. + */ +void v4l2_ctrl_request_setup(struct media_request *req, + struct v4l2_ctrl_handler *parent); + +/** + * v4l2_ctrl_request_complete - Complete a control handler request object + * + * @req: The request + * @parent: The parent control handler ('priv' in media_request_object_find()) + * + * This function is to be called on each control handler that may have had a + * request object associated with it, i.e. control handlers of a driver that + * supports requests. + * + * The function first obtains the values of any volatile controls in the control + * handler and attach them to the request. Then, the function completes the + * request object. + */ +void v4l2_ctrl_request_complete(struct media_request *req, + struct v4l2_ctrl_handler *hdl); + /* Helpers for ioctl_ops */ /** -- cgit From c41e9cff704a06b8cbd9eeea0fdec54fb6d13825 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 21 May 2018 04:54:42 -0400 Subject: media: v4l2-ctrls: support g/s_ext_ctrls for requests The v4l2_g/s_ext_ctrls functions now support control handlers that represent requests. The v4l2_ctrls_find_req_obj() function is responsible for finding the request from the fd. Signed-off-by: Hans Verkuil Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-ctrls.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'include/media') diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index ed784e98c293..f4156544150b 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -1179,11 +1179,12 @@ int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl, * :ref:`VIDIOC_G_EXT_CTRLS ` ioctl * * @hdl: pointer to &struct v4l2_ctrl_handler + * @mdev: pointer to &struct media_device * @c: pointer to &struct v4l2_ext_controls * * If hdl == NULL then they will all return -EINVAL. */ -int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, +int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct media_device *mdev, struct v4l2_ext_controls *c); /** @@ -1191,11 +1192,13 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, * :ref:`VIDIOC_TRY_EXT_CTRLS ` ioctl * * @hdl: pointer to &struct v4l2_ctrl_handler + * @mdev: pointer to &struct media_device * @c: pointer to &struct v4l2_ext_controls * * If hdl == NULL then they will all return -EINVAL. */ int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl, + struct media_device *mdev, struct v4l2_ext_controls *c); /** @@ -1204,11 +1207,13 @@ int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl, * * @fh: pointer to &struct v4l2_fh * @hdl: pointer to &struct v4l2_ctrl_handler + * @mdev: pointer to &struct media_device * @c: pointer to &struct v4l2_ext_controls * * If hdl == NULL then they will all return -EINVAL. */ int v4l2_s_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl, + struct media_device *mdev, struct v4l2_ext_controls *c); /** -- cgit From 5f611d74c2bd89296aa045609df0e5309ff7ab41 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 10 Jul 2018 04:00:53 -0400 Subject: media: v4l2-ctrls: add v4l2_ctrl_request_hdl_find/put/ctrl_find functions If a driver needs to find/inspect the controls set in a request then it can use these functions. E.g. to check if a required control is set in a request use this in the req_validate() implementation: int res = -EINVAL; hdl = v4l2_ctrl_request_hdl_find(req, parent_hdl); if (hdl) { if (v4l2_ctrl_request_hdl_ctrl_find(hdl, ctrl_id)) res = 0; v4l2_ctrl_request_hdl_put(hdl); } return res; Signed-off-by: Hans Verkuil Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-ctrls.h | 49 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) (limited to 'include/media') diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index f4156544150b..53ca4df0c353 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -1111,7 +1111,54 @@ void v4l2_ctrl_request_setup(struct media_request *req, * request object. */ void v4l2_ctrl_request_complete(struct media_request *req, - struct v4l2_ctrl_handler *hdl); + struct v4l2_ctrl_handler *parent); + +/** + * v4l2_ctrl_request_hdl_find - Find the control handler in the request + * + * @req: The request + * @parent: The parent control handler ('priv' in media_request_object_find()) + * + * This function finds the control handler in the request. It may return + * NULL if not found. When done, you must call v4l2_ctrl_request_put_hdl() + * with the returned handler pointer. + * + * If the request is not in state VALIDATING or QUEUED, then this function + * will always return NULL. + * + * Note that in state VALIDATING the req_queue_mutex is held, so + * no objects can be added or deleted from the request. + * + * In state QUEUED it is the driver that will have to ensure this. + */ +struct v4l2_ctrl_handler *v4l2_ctrl_request_hdl_find(struct media_request *req, + struct v4l2_ctrl_handler *parent); + +/** + * v4l2_ctrl_request_hdl_put - Put the control handler + * + * @hdl: Put this control handler + * + * This function released the control handler previously obtained from' + * v4l2_ctrl_request_hdl_find(). + */ +static inline void v4l2_ctrl_request_hdl_put(struct v4l2_ctrl_handler *hdl) +{ + if (hdl) + media_request_object_put(&hdl->req_obj); +} + +/** + * v4l2_ctrl_request_ctrl_find() - Find a control with the given ID. + * + * @hdl: The control handler from the request. + * @id: The ID of the control to find. + * + * This function returns a pointer to the control if this control is + * part of the request or NULL otherwise. + */ +struct v4l2_ctrl * +v4l2_ctrl_request_hdl_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id); /* Helpers for ioctl_ops */ -- cgit From db6e8d57e2cd9fb77e6ceef8476912caecbd59b5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 21 May 2018 04:54:45 -0400 Subject: media: vb2: store userspace data in vb2_v4l2_buffer The userspace-provided plane data needs to be stored in vb2_v4l2_buffer. Currently this information is applied by __fill_vb2_buffer() which is called by the core prepare_buf and qbuf functions, but when using requests these functions aren't called yet since the buffer won't be prepared until the media request is actually queued. In the meantime this information has to be stored somewhere and vb2_v4l2_buffer is a good place for it. The __fill_vb2_buffer callback now just copies the relevant information from vb2_v4l2_buffer into the planes array. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/media/videobuf2-core.h | 3 +-- include/media/videobuf2-v4l2.h | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'include/media') diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index f6818f732f34..224c4820a044 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -417,8 +417,7 @@ struct vb2_ops { struct vb2_buf_ops { int (*verify_planes_array)(struct vb2_buffer *vb, const void *pb); void (*fill_user_buffer)(struct vb2_buffer *vb, void *pb); - int (*fill_vb2_buffer)(struct vb2_buffer *vb, const void *pb, - struct vb2_plane *planes); + int (*fill_vb2_buffer)(struct vb2_buffer *vb, struct vb2_plane *planes); void (*copy_timestamp)(struct vb2_buffer *vb, const void *pb); }; diff --git a/include/media/videobuf2-v4l2.h b/include/media/videobuf2-v4l2.h index 3d5e2d739f05..097bf3e6951d 100644 --- a/include/media/videobuf2-v4l2.h +++ b/include/media/videobuf2-v4l2.h @@ -32,6 +32,7 @@ * &enum v4l2_field. * @timecode: frame timecode. * @sequence: sequence count of this frame. + * @planes: plane information (userptr/fd, length, bytesused, data_offset). * * Should contain enough information to be able to cover all the fields * of &struct v4l2_buffer at ``videodev2.h``. @@ -43,6 +44,7 @@ struct vb2_v4l2_buffer { __u32 field; struct v4l2_timecode timecode; __u32 sequence; + struct vb2_plane planes[VB2_MAX_PLANES]; }; /* -- cgit From 55028695c3bbd8f202b969a5a702caa7d7a51675 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 3 Jun 2018 05:02:27 -0400 Subject: media: vb2: drop VB2_BUF_STATE_PREPARED, use bool prepared/synced instead The PREPARED state becomes a problem with the request API: a buffer could be PREPARED but dequeued, or PREPARED and in state IN_REQUEST. PREPARED is really not a state as such, but more a property of the buffer. So make new 'prepared' and 'synced' bools instead to remember whether the buffer is prepared and/or synced or not. V4L2_BUF_FLAG_PREPARED is only set if the buffer is both synced and prepared and in the DEQUEUED state. Signed-off-by: Hans Verkuil Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- include/media/videobuf2-core.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'include/media') diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 224c4820a044..15a14b1e5c0b 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -204,7 +204,6 @@ enum vb2_io_modes { * enum vb2_buffer_state - current video buffer state. * @VB2_BUF_STATE_DEQUEUED: buffer under userspace control. * @VB2_BUF_STATE_PREPARING: buffer is being prepared in videobuf. - * @VB2_BUF_STATE_PREPARED: buffer prepared in videobuf and by the driver. * @VB2_BUF_STATE_QUEUED: buffer queued in videobuf, but not in driver. * @VB2_BUF_STATE_REQUEUEING: re-queue a buffer to the driver. * @VB2_BUF_STATE_ACTIVE: buffer queued in driver and possibly used @@ -218,7 +217,6 @@ enum vb2_io_modes { enum vb2_buffer_state { VB2_BUF_STATE_DEQUEUED, VB2_BUF_STATE_PREPARING, - VB2_BUF_STATE_PREPARED, VB2_BUF_STATE_QUEUED, VB2_BUF_STATE_REQUEUEING, VB2_BUF_STATE_ACTIVE, @@ -250,6 +248,12 @@ struct vb2_buffer { /* private: internal use only * * state: current buffer state; do not change + * synced: this buffer has been synced for DMA, i.e. the + * 'prepare' memop was called. It is cleared again + * after the 'finish' memop is called. + * prepared: this buffer has been prepared, i.e. the + * buf_prepare op was called. It is cleared again + * after the 'buf_finish' op is called. * queued_entry: entry on the queued buffers list, which holds * all buffers queued from userspace * done_entry: entry on the list that stores all buffers ready @@ -257,6 +261,8 @@ struct vb2_buffer { * vb2_plane: per-plane information; do not change */ enum vb2_buffer_state state; + bool synced; + bool prepared; struct vb2_plane planes[VB2_MAX_PLANES]; struct list_head queued_entry; -- cgit From 8e013700bc12806d80f31ebe360916987f0e03df Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 1 Jun 2018 11:03:13 -0400 Subject: media: vb2: add init_buffer buffer op We need to initialize the request_fd field in struct vb2_v4l2_buffer to -1 instead of the default of 0. So we need to add a new op that is called when struct vb2_v4l2_buffer is allocated. Signed-off-by: Hans Verkuil Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- include/media/videobuf2-core.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/media') diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 15a14b1e5c0b..2eb24961183e 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -412,6 +412,9 @@ struct vb2_ops { * @verify_planes_array: Verify that a given user space structure contains * enough planes for the buffer. This is called * for each dequeued buffer. + * @init_buffer: given a &vb2_buffer initialize the extra data after + * struct vb2_buffer. + * For V4L2 this is a &struct vb2_v4l2_buffer. * @fill_user_buffer: given a &vb2_buffer fill in the userspace structure. * For V4L2 this is a &struct v4l2_buffer. * @fill_vb2_buffer: given a userspace structure, fill in the &vb2_buffer. @@ -422,6 +425,7 @@ struct vb2_ops { */ struct vb2_buf_ops { int (*verify_planes_array)(struct vb2_buffer *vb, const void *pb); + void (*init_buffer)(struct vb2_buffer *vb); void (*fill_user_buffer)(struct vb2_buffer *vb, void *pb); int (*fill_vb2_buffer)(struct vb2_buffer *vb, struct vb2_plane *planes); void (*copy_timestamp)(struct vb2_buffer *vb, const void *pb); -- cgit From 1cf96dcc6e79a860d2216a4d1c3edb1676a5798e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 21 May 2018 04:54:46 -0400 Subject: media: videobuf2-core: embed media_request_object Make vb2_buffer a request object. Signed-off-by: Hans Verkuil Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- include/media/videobuf2-core.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/media') diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 2eb24961183e..413b8b2dc485 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -17,6 +17,7 @@ #include #include #include +#include #define VB2_MAX_FRAME (32) #define VB2_MAX_PLANES (8) @@ -236,6 +237,8 @@ struct vb2_queue; * @num_planes: number of planes in the buffer * on an internal driver queue. * @timestamp: frame timestamp in ns. + * @req_obj: used to bind this buffer to a request. This + * request object has a refcount. */ struct vb2_buffer { struct vb2_queue *vb2_queue; @@ -244,6 +247,7 @@ struct vb2_buffer { unsigned int memory; unsigned int num_planes; u64 timestamp; + struct media_request_object req_obj; /* private: internal use only * -- cgit From fd89e0bb6ebff6481b9b8dd73729f5d62984490a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 21 May 2018 04:54:47 -0400 Subject: media: videobuf2-core: integrate with media requests Buffers can now be prepared or queued for a request. A buffer is unbound from the request at vb2_buffer_done time or when the queue is cancelled. Signed-off-by: Hans Verkuil Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- include/media/videobuf2-core.h | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'include/media') diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 413b8b2dc485..957b11c675cb 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -204,6 +204,7 @@ enum vb2_io_modes { /** * enum vb2_buffer_state - current video buffer state. * @VB2_BUF_STATE_DEQUEUED: buffer under userspace control. + * @VB2_BUF_STATE_IN_REQUEST: buffer is queued in media request. * @VB2_BUF_STATE_PREPARING: buffer is being prepared in videobuf. * @VB2_BUF_STATE_QUEUED: buffer queued in videobuf, but not in driver. * @VB2_BUF_STATE_REQUEUEING: re-queue a buffer to the driver. @@ -217,6 +218,7 @@ enum vb2_io_modes { */ enum vb2_buffer_state { VB2_BUF_STATE_DEQUEUED, + VB2_BUF_STATE_IN_REQUEST, VB2_BUF_STATE_PREPARING, VB2_BUF_STATE_QUEUED, VB2_BUF_STATE_REQUEUEING, @@ -297,6 +299,7 @@ struct vb2_buffer { u32 cnt_buf_finish; u32 cnt_buf_cleanup; u32 cnt_buf_queue; + u32 cnt_buf_request_complete; /* This counts the number of calls to vb2_buffer_done() */ u32 cnt_buf_done; @@ -390,6 +393,11 @@ struct vb2_buffer { * ioctl; might be called before @start_streaming callback * if user pre-queued buffers before calling * VIDIOC_STREAMON(). + * @buf_request_complete: a buffer that was never queued to the driver but is + * associated with a queued request was canceled. + * The driver will have to mark associated objects in the + * request as completed; required if requests are + * supported. */ struct vb2_ops { int (*queue_setup)(struct vb2_queue *q, @@ -408,6 +416,8 @@ struct vb2_ops { void (*stop_streaming)(struct vb2_queue *q); void (*buf_queue)(struct vb2_buffer *vb); + + void (*buf_request_complete)(struct vb2_buffer *vb); }; /** @@ -765,12 +775,17 @@ int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb); * @index: id number of the buffer * @pb: buffer structure passed from userspace to * v4l2_ioctl_ops->vidioc_qbuf handler in driver + * @req: pointer to &struct media_request, may be NULL. * * Videobuf2 core helper to implement VIDIOC_QBUF() operation. It is called * internally by VB2 by an API-specific handler, like ``videobuf2-v4l2.h``. * * This function: * + * #) If @req is non-NULL, then the buffer will be bound to this + * media request and it returns. The buffer will be prepared and + * queued to the driver (i.e. the next two steps) when the request + * itself is queued. * #) if necessary, calls &vb2_ops->buf_prepare callback in the driver * (if provided), in which driver-specific buffer initialization can * be performed; @@ -779,7 +794,8 @@ int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb); * * Return: returns zero on success; an error code otherwise. */ -int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb); +int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb, + struct media_request *req); /** * vb2_core_dqbuf() - Dequeue a buffer to the userspace -- cgit From 394dc588809158826e2877adb670391829f91c63 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 30 May 2018 02:46:22 -0400 Subject: media: videobuf2-v4l2: integrate with media requests This implements the V4L2 part of the request support. The main change is that vb2_qbuf and vb2_prepare_buf now have a new media_device pointer. This required changes to several drivers that did not use the vb2_ioctl_qbuf/prepare_buf helper functions. Signed-off-by: Hans Verkuil Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- include/media/videobuf2-v4l2.h | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'include/media') diff --git a/include/media/videobuf2-v4l2.h b/include/media/videobuf2-v4l2.h index 097bf3e6951d..91a2b3e1a642 100644 --- a/include/media/videobuf2-v4l2.h +++ b/include/media/videobuf2-v4l2.h @@ -32,6 +32,7 @@ * &enum v4l2_field. * @timecode: frame timecode. * @sequence: sequence count of this frame. + * @request_fd: the request_fd associated with this buffer * @planes: plane information (userptr/fd, length, bytesused, data_offset). * * Should contain enough information to be able to cover all the fields @@ -44,6 +45,7 @@ struct vb2_v4l2_buffer { __u32 field; struct v4l2_timecode timecode; __u32 sequence; + __s32 request_fd; struct vb2_plane planes[VB2_MAX_PLANES]; }; @@ -79,6 +81,7 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create); * vb2_prepare_buf() - Pass ownership of a buffer from userspace to the kernel * * @q: pointer to &struct vb2_queue with videobuf2 queue. + * @mdev: pointer to &struct media_device, may be NULL. * @b: buffer structure passed from userspace to * &v4l2_ioctl_ops->vidioc_prepare_buf handler in driver * @@ -90,15 +93,19 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create); * #) verifies the passed buffer, * #) calls &vb2_ops->buf_prepare callback in the driver (if provided), * in which driver-specific buffer initialization can be performed. + * #) if @b->request_fd is non-zero and @mdev->ops->req_queue is set, + * then bind the prepared buffer to the request. * * The return values from this function are intended to be directly returned * from &v4l2_ioctl_ops->vidioc_prepare_buf handler in driver. */ -int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b); +int vb2_prepare_buf(struct vb2_queue *q, struct media_device *mdev, + struct v4l2_buffer *b); /** * vb2_qbuf() - Queue a buffer from userspace * @q: pointer to &struct vb2_queue with videobuf2 queue. + * @mdev: pointer to &struct media_device, may be NULL. * @b: buffer structure passed from userspace to * &v4l2_ioctl_ops->vidioc_qbuf handler in driver * @@ -107,6 +114,8 @@ int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b); * This function: * * #) verifies the passed buffer; + * #) if @b->request_fd is non-zero and @mdev->ops->req_queue is set, + * then bind the buffer to the request. * #) if necessary, calls &vb2_ops->buf_prepare callback in the driver * (if provided), in which driver-specific buffer initialization can * be performed; @@ -116,7 +125,8 @@ int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b); * The return values from this function are intended to be directly returned * from &v4l2_ioctl_ops->vidioc_qbuf handler in driver. */ -int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b); +int vb2_qbuf(struct vb2_queue *q, struct media_device *mdev, + struct v4l2_buffer *b); /** * vb2_expbuf() - Export a buffer as a file descriptor -- cgit From c07aa48ec57eca649e987e8f19a336d4373b8da6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 21 May 2018 04:54:51 -0400 Subject: media: videobuf2-core: add request helper functions Add a new helper function to tell if a request object is a buffer. Add a new helper function that returns true if a media_request contains at least one buffer. Signed-off-by: Hans Verkuil Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- include/media/videobuf2-core.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'include/media') diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 957b11c675cb..a9f2a7eae49a 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -1172,4 +1172,19 @@ bool vb2_buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb); */ int vb2_verify_memory_type(struct vb2_queue *q, enum vb2_memory memory, unsigned int type); + +/** + * vb2_request_object_is_buffer() - return true if the object is a buffer + * + * @obj: the request object. + */ +bool vb2_request_object_is_buffer(struct media_request_object *obj); + +/** + * vb2_request_has_buffers() - return true if the request contains buffers + * + * @req: the request. + */ +bool vb2_request_has_buffers(struct media_request *req); + #endif /* _MEDIA_VIDEOBUF2_CORE_H */ -- cgit From 86f6bd3cf1222c62bcccd76daf1c831f22e595bf Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 21 May 2018 04:54:52 -0400 Subject: media: videobuf2-v4l2: add vb2_request_queue/validate helpers The generic vb2_request_validate helper function checks if there are buffers in the request and if so, prepares (validates) all objects in the request. The generic vb2_request_queue helper function queues all buffer objects in the validated request. Signed-off-by: Hans Verkuil Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- include/media/videobuf2-v4l2.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/media') diff --git a/include/media/videobuf2-v4l2.h b/include/media/videobuf2-v4l2.h index 91a2b3e1a642..727855463838 100644 --- a/include/media/videobuf2-v4l2.h +++ b/include/media/videobuf2-v4l2.h @@ -303,4 +303,8 @@ void vb2_ops_wait_prepare(struct vb2_queue *vq); */ void vb2_ops_wait_finish(struct vb2_queue *vq); +struct media_request; +int vb2_request_validate(struct media_request *req); +void vb2_request_queue(struct media_request *req); + #endif /* _MEDIA_VIDEOBUF2_V4L2_H */ -- cgit From 61add367dda6309ee1702d85344b5fcbd6ede9a1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 23 May 2018 07:51:25 -0400 Subject: media: videobuf2-core: add uses_requests/qbuf flags Set the first time a buffer from a request is queued to vb2 (uses_requests) or directly queued (uses_qbuf). Cleared when the queue is canceled. Signed-off-by: Hans Verkuil Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- include/media/videobuf2-core.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'include/media') diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index a9f2a7eae49a..881f53b38b26 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -472,6 +472,12 @@ struct vb2_buf_ops { * @quirk_poll_must_check_waiting_for_buffers: Return %EPOLLERR at poll when QBUF * has not been called. This is a vb1 idiom that has been adopted * also by vb2. + * @uses_qbuf: qbuf was used directly for this queue. Set to 1 the first + * time this is called. Set to 0 when the queue is canceled. + * If this is 1, then you cannot queue buffers from a request. + * @uses_requests: requests are used for this queue. Set to 1 the first time + * a request is queued. Set to 0 when the queue is canceled. + * If this is 1, then you cannot queue buffers directly. * @lock: pointer to a mutex that protects the &struct vb2_queue. The * driver can set this to a mutex to let the v4l2 core serialize * the queuing ioctls. If the driver wants to handle locking @@ -539,6 +545,8 @@ struct vb2_queue { unsigned fileio_write_immediately:1; unsigned allow_zero_bytesused:1; unsigned quirk_poll_must_check_waiting_for_buffers:1; + unsigned uses_qbuf:1; + unsigned uses_requests:1; struct mutex *lock; void *owner; -- cgit From 803a7ab758252599ddadf5fe9326acee7340d9b6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 21 May 2018 04:54:53 -0400 Subject: media: v4l2-mem2mem: add vb2_m2m_request_queue For mem2mem devices we have to make sure that v4l2_m2m_try_schedule() is called whenever a request is queued. We do that by creating a vb2_m2m_request_queue() helper that should be used instead of the 'normal' vb2_request_queue() helper. The m2m helper function will call v4l2_m2m_try_schedule() as needed. In addition we also avoid calling v4l2_m2m_try_schedule() when preparing or queueing a buffer for a request since that is no longer needed. Instead this helper function will do that when the request is actually queued. Signed-off-by: Hans Verkuil Reviewed-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-mem2mem.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/media') diff --git a/include/media/v4l2-mem2mem.h b/include/media/v4l2-mem2mem.h index d655720e16a1..58c1ecf3d648 100644 --- a/include/media/v4l2-mem2mem.h +++ b/include/media/v4l2-mem2mem.h @@ -622,6 +622,10 @@ v4l2_m2m_dst_buf_remove_by_idx(struct v4l2_m2m_ctx *m2m_ctx, unsigned int idx) return v4l2_m2m_buf_remove_by_idx(&m2m_ctx->cap_q_ctx, idx); } +/* v4l2 request helper */ + +void vb2_m2m_request_queue(struct media_request *req); + /* v4l2 ioctl helpers */ int v4l2_m2m_ioctl_reqbufs(struct file *file, void *priv, -- cgit From 34b41472465b1b5a2c6c63255431fb2c1a450af1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 23 Aug 2018 06:14:12 -0400 Subject: media: media-request: return -EINVAL for invalid request_fds Instead of returning -ENOENT when a request_fd was not found (VIDIOC_QBUF and VIDIOC_G/S/TRY_EXT_CTRLS), we now return -EINVAL. This is in line with what we do when invalid dmabuf fds are passed to e.g. VIDIOC_QBUF. Also document that EINVAL is returned for invalid m.fd values, we never documented that. Signed-off-by: Hans Verkuil Reviewed-by: Tomasz Figa Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- include/media/media-request.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/media') diff --git a/include/media/media-request.h b/include/media/media-request.h index ac02019c1d77..453a6b95c61a 100644 --- a/include/media/media-request.h +++ b/include/media/media-request.h @@ -153,7 +153,7 @@ void media_request_put(struct media_request *req); * by the media device. * * Return a -EPERM error pointer if requests are not supported - * by this driver. Return -ENOENT if the request was not found. + * by this driver. Return -EINVAL if the request was not found. * Return the pointer to the request if found: the caller will * have to call @media_request_put when it finished using the * request. -- cgit From e5079cf11373e4cc98be8b1072aece429eb2d4d2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 23 Aug 2018 10:18:35 -0400 Subject: media: vb2: set reqbufs/create_bufs capabilities Set the capabilities field of v4l2_requestbuffers and v4l2_create_buffers. The various mapping modes were easy, but for signaling the request capability a new 'supports_requests' bitfield was added to videobuf2-core.h (and set in vim2m and vivid). Drivers have to set this bitfield for any queue where requests are supported. Signed-off-by: Hans Verkuil Reviewed-by: Tomasz Figa Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- include/media/videobuf2-core.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/media') diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 881f53b38b26..6c76b9802589 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -472,6 +472,7 @@ struct vb2_buf_ops { * @quirk_poll_must_check_waiting_for_buffers: Return %EPOLLERR at poll when QBUF * has not been called. This is a vb1 idiom that has been adopted * also by vb2. + * @supports_requests: this queue supports the Request API. * @uses_qbuf: qbuf was used directly for this queue. Set to 1 the first * time this is called. Set to 0 when the queue is canceled. * If this is 1, then you cannot queue buffers from a request. @@ -545,6 +546,7 @@ struct vb2_queue { unsigned fileio_write_immediately:1; unsigned allow_zero_bytesused:1; unsigned quirk_poll_must_check_waiting_for_buffers:1; + unsigned supports_requests:1; unsigned uses_qbuf:1; unsigned uses_requests:1; -- cgit From 6736f4e948817ca8385bdc6feb5475cdf1eb1ec8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 27 Aug 2018 11:10:38 -0400 Subject: media: media-request: add media_request_(un)lock_for_access Add helper functions to prevent a completed request from being re-inited while it is being accessed. Signed-off-by: Hans Verkuil Reviewed-by: Tomasz Figa Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- include/media/media-request.h | 56 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'include/media') diff --git a/include/media/media-request.h b/include/media/media-request.h index 453a6b95c61a..f0920aa84509 100644 --- a/include/media/media-request.h +++ b/include/media/media-request.h @@ -53,6 +53,7 @@ struct media_request_object; * @debug_str: Prefix for debug messages (process name:fd) * @state: The state of the request * @updating_count: count the number of request updates that are in progress + * @access_count: count the number of request accesses that are in progress * @objects: List of @struct media_request_object request objects * @num_incomplete_objects: The number of incomplete objects in the request * @poll_wait: Wait queue for poll @@ -64,6 +65,7 @@ struct media_request { char debug_str[TASK_COMM_LEN + 11]; enum media_request_state state; unsigned int updating_count; + unsigned int access_count; struct list_head objects; unsigned int num_incomplete_objects; struct wait_queue_head poll_wait; @@ -72,6 +74,50 @@ struct media_request { #ifdef CONFIG_MEDIA_CONTROLLER +/** + * media_request_lock_for_access - Lock the request to access its objects + * + * @req: The media request + * + * Use before accessing a completed request. A reference to the request must + * be held during the access. This usually takes place automatically through + * a file handle. Use @media_request_unlock_for_access when done. + */ +static inline int __must_check +media_request_lock_for_access(struct media_request *req) +{ + unsigned long flags; + int ret = -EBUSY; + + spin_lock_irqsave(&req->lock, flags); + if (req->state == MEDIA_REQUEST_STATE_COMPLETE) { + req->access_count++; + ret = 0; + } + spin_unlock_irqrestore(&req->lock, flags); + + return ret; +} + +/** + * media_request_unlock_for_access - Unlock a request previously locked for + * access + * + * @req: The media request + * + * Unlock a request that has previously been locked using + * @media_request_lock_for_access. + */ +static inline void media_request_unlock_for_access(struct media_request *req) +{ + unsigned long flags; + + spin_lock_irqsave(&req->lock, flags); + if (!WARN_ON(!req->access_count)) + req->access_count--; + spin_unlock_irqrestore(&req->lock, flags); +} + /** * media_request_lock_for_update - Lock the request for updating its objects * @@ -333,6 +379,16 @@ void media_request_object_complete(struct media_request_object *obj); #else +static inline int __must_check +media_request_lock_for_access(struct media_request *req) +{ + return -EINVAL; +} + +static inline void media_request_unlock_for_access(struct media_request *req) +{ +} + static inline int __must_check media_request_lock_for_update(struct media_request *req) { -- cgit From 15cd442e79e2a60a725ee5501e4ffb537698c802 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 1 Sep 2018 07:29:14 -0400 Subject: media: media-request: EPERM -> EACCES/EBUSY If requests are not supported by the driver, then return EACCES, not EPERM. If you attempt to mix queueing buffers directly and using requests, then EBUSY is returned instead of EPERM: once a specific queueing mode has been chosen the queue is 'busy' if you attempt the other mode (i.e. direct queueing vs via a request). Signed-off-by: Hans Verkuil Reviewed-by: Tomasz Figa Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- include/media/media-request.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/media') diff --git a/include/media/media-request.h b/include/media/media-request.h index f0920aa84509..0ce75c35131f 100644 --- a/include/media/media-request.h +++ b/include/media/media-request.h @@ -198,7 +198,7 @@ void media_request_put(struct media_request *req); * Get the request represented by @request_fd that is owned * by the media device. * - * Return a -EPERM error pointer if requests are not supported + * Return a -EACCES error pointer if requests are not supported * by this driver. Return -EINVAL if the request was not found. * Return the pointer to the request if found: the caller will * have to call @media_request_put when it finished using the @@ -231,7 +231,7 @@ static inline void media_request_put(struct media_request *req) static inline struct media_request * media_request_get_by_fd(struct media_device *mdev, int request_fd) { - return ERR_PTR(-EPERM); + return ERR_PTR(-EACCES); } #endif -- cgit From 515c5a7333be87a7d01ab267d94626a454a7e794 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Thu, 13 Sep 2018 10:51:51 -0400 Subject: media: videobuf2-core: Rework and rename helper for request buffer count The helper indicating whether buffers are associated with the request is reworked and renamed to return the number of associated buffer objects. This is useful for drivers that need to check how many buffers are in the request to validate it. Existing users of the helper don't need particular adaptation since the meaning of zero/non-zero remains consistent. Signed-off-by: Paul Kocialkowski Signed-off-by: Maxime Ripard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/media/videobuf2-core.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/media') diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 6c76b9802589..e86981d615ae 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -1191,10 +1191,10 @@ int vb2_verify_memory_type(struct vb2_queue *q, bool vb2_request_object_is_buffer(struct media_request_object *obj); /** - * vb2_request_has_buffers() - return true if the request contains buffers + * vb2_request_buffer_cnt() - return the number of buffers in the request * * @req: the request. */ -bool vb2_request_has_buffers(struct media_request *req); +unsigned int vb2_request_buffer_cnt(struct media_request *req); #endif /* _MEDIA_VIDEOBUF2_CORE_H */ -- cgit From c27bb30e7b6d385c5bff26406089377d678f1a1d Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Thu, 13 Sep 2018 10:51:52 -0400 Subject: media: v4l: Add definitions for MPEG-2 slice format and metadata Stateless video decoding engines require both the MPEG-2 slices and associated metadata from the video stream in order to decode frames. This introduces definitions for a new pixel format, describing buffers with MPEG-2 slice data, as well as control structure sfor passing the frame metadata to drivers. This is based on work from both Florent Revest and Hugues Fruchet. Signed-off-by: Paul Kocialkowski Signed-off-by: Maxime Ripard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-ctrls.h | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'include/media') diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index 53ca4df0c353..0dae03dd5b06 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -35,13 +35,15 @@ struct poll_table_struct; /** * union v4l2_ctrl_ptr - A pointer to a control value. - * @p_s32: Pointer to a 32-bit signed value. - * @p_s64: Pointer to a 64-bit signed value. - * @p_u8: Pointer to a 8-bit unsigned value. - * @p_u16: Pointer to a 16-bit unsigned value. - * @p_u32: Pointer to a 32-bit unsigned value. - * @p_char: Pointer to a string. - * @p: Pointer to a compound value. + * @p_s32: Pointer to a 32-bit signed value. + * @p_s64: Pointer to a 64-bit signed value. + * @p_u8: Pointer to a 8-bit unsigned value. + * @p_u16: Pointer to a 16-bit unsigned value. + * @p_u32: Pointer to a 32-bit unsigned value. + * @p_char: Pointer to a string. + * @p_mpeg2_slice_params: Pointer to a MPEG2 slice parameters structure. + * @p_mpeg2_quantization: Pointer to a MPEG2 quantization data structure. + * @p: Pointer to a compound value. */ union v4l2_ctrl_ptr { s32 *p_s32; @@ -50,6 +52,8 @@ union v4l2_ctrl_ptr { u16 *p_u16; u32 *p_u32; char *p_char; + struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params; + struct v4l2_ctrl_mpeg2_quantization *p_mpeg2_quantization; void *p; }; -- cgit