480 lines · 13.3 KB · C
RawDownload
// 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 <hverkuil@kernel.org> * Author: Sakari Ailus <sakari.ailus@linux.intel.com> */ #ifndef MEDIA_REQUEST_H#define MEDIA_REQUEST_H #include <linux/list.h>#include <linux/slab.h>#include <linux/spinlock.h>#include <linux/refcount.h> #include <media/media-device.h> /** * 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 * @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 * @manual_completion: if true, then the request won't be marked as completed * when @num_incomplete_objects reaches 0. Call media_request_manual_complete() * to complete the request after @num_incomplete_objects == 0. * @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;	unsigned int access_count;	struct list_head objects;	unsigned int num_incomplete_objects;	bool manual_completion;	wait_queue_head_t poll_wait;	spinlock_t lock;}; #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_checkmedia_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 * * @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_checkmedia_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_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 -EBADR 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 * request. */struct media_request *media_request_get_by_fd(struct media_device *mdev, int request_fd); /** * 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); /** * media_request_mark_manual_completion - Enable manual completion * * @req: The request * * Mark that the request has to be manually completed by calling * media_request_manual_complete(). * * This function shall be called in the req_queue callback. */static inline voidmedia_request_mark_manual_completion(struct media_request *req){	req->manual_completion = true;} /** * media_request_manual_complete - Mark the request as completed * * @req: The request * * This function completes a request that was marked for manual completion by an * earlier call to media_request_mark_manual_completion(). The request's * @manual_completion field is reset to false. * * All objects contained in the request must have been completed previously. It * is an error to call this function otherwise. If such an error occurred, the * function will WARN and the object completion will be delayed until * @num_incomplete_objects is 0. */void media_request_manual_complete(struct media_request *req); #else static inline void media_request_get(struct media_request *req){} 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(-EBADR);} #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 * * @mdev: Media device this object belongs to * @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 {	struct media_device *mdev;	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_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 * * @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 is 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_checkmedia_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_checkmedia_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 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;	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

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t