// SPDX-License-Identifier: GPL-2.01/*2* Media device request objects3*4* Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.5* Copyright (C) 2018 Intel Corporation6*7* Author: Hans Verkuil <[email protected]>8* Author: Sakari Ailus <[email protected]>9*/1011#ifndef MEDIA_REQUEST_H12#define MEDIA_REQUEST_H1314#include <linux/list.h>15#include <linux/slab.h>16#include <linux/spinlock.h>17#include <linux/refcount.h>1819#include <media/media-device.h>2021/**22* enum media_request_state - media request state23*24* @MEDIA_REQUEST_STATE_IDLE: Idle25* @MEDIA_REQUEST_STATE_VALIDATING: Validating the request, no state changes26* allowed27* @MEDIA_REQUEST_STATE_QUEUED: Queued28* @MEDIA_REQUEST_STATE_COMPLETE: Completed, the request is done29* @MEDIA_REQUEST_STATE_CLEANING: Cleaning, the request is being re-inited30* @MEDIA_REQUEST_STATE_UPDATING: The request is being updated, i.e.31* request objects are being added,32* modified or removed33* @NR_OF_MEDIA_REQUEST_STATE: The number of media request states, used34* internally for sanity check purposes35*/36enum media_request_state {37MEDIA_REQUEST_STATE_IDLE,38MEDIA_REQUEST_STATE_VALIDATING,39MEDIA_REQUEST_STATE_QUEUED,40MEDIA_REQUEST_STATE_COMPLETE,41MEDIA_REQUEST_STATE_CLEANING,42MEDIA_REQUEST_STATE_UPDATING,43NR_OF_MEDIA_REQUEST_STATE,44};4546struct media_request_object;4748/**49* struct media_request - Media device request50* @mdev: Media device this request belongs to51* @kref: Reference count52* @debug_str: Prefix for debug messages (process name:fd)53* @state: The state of the request54* @updating_count: count the number of request updates that are in progress55* @access_count: count the number of request accesses that are in progress56* @objects: List of @struct media_request_object request objects57* @num_incomplete_objects: The number of incomplete objects in the request58* @poll_wait: Wait queue for poll59* @lock: Serializes access to this struct60*/61struct media_request {62struct media_device *mdev;63struct kref kref;64char debug_str[TASK_COMM_LEN + 11];65enum media_request_state state;66unsigned int updating_count;67unsigned int access_count;68struct list_head objects;69unsigned int num_incomplete_objects;70wait_queue_head_t poll_wait;71spinlock_t lock;72};7374#ifdef CONFIG_MEDIA_CONTROLLER7576/**77* media_request_lock_for_access - Lock the request to access its objects78*79* @req: The media request80*81* Use before accessing a completed request. A reference to the request must82* be held during the access. This usually takes place automatically through83* a file handle. Use @media_request_unlock_for_access when done.84*/85static inline int __must_check86media_request_lock_for_access(struct media_request *req)87{88unsigned long flags;89int ret = -EBUSY;9091spin_lock_irqsave(&req->lock, flags);92if (req->state == MEDIA_REQUEST_STATE_COMPLETE) {93req->access_count++;94ret = 0;95}96spin_unlock_irqrestore(&req->lock, flags);9798return ret;99}100101/**102* media_request_unlock_for_access - Unlock a request previously locked for103* access104*105* @req: The media request106*107* Unlock a request that has previously been locked using108* @media_request_lock_for_access.109*/110static inline void media_request_unlock_for_access(struct media_request *req)111{112unsigned long flags;113114spin_lock_irqsave(&req->lock, flags);115if (!WARN_ON(!req->access_count))116req->access_count--;117spin_unlock_irqrestore(&req->lock, flags);118}119120/**121* media_request_lock_for_update - Lock the request for updating its objects122*123* @req: The media request124*125* Use before updating a request, i.e. adding, modifying or removing a request126* object in it. A reference to the request must be held during the update. This127* usually takes place automatically through a file handle. Use128* @media_request_unlock_for_update when done.129*/130static inline int __must_check131media_request_lock_for_update(struct media_request *req)132{133unsigned long flags;134int ret = 0;135136spin_lock_irqsave(&req->lock, flags);137if (req->state == MEDIA_REQUEST_STATE_IDLE ||138req->state == MEDIA_REQUEST_STATE_UPDATING) {139req->state = MEDIA_REQUEST_STATE_UPDATING;140req->updating_count++;141} else {142ret = -EBUSY;143}144spin_unlock_irqrestore(&req->lock, flags);145146return ret;147}148149/**150* media_request_unlock_for_update - Unlock a request previously locked for151* update152*153* @req: The media request154*155* Unlock a request that has previously been locked using156* @media_request_lock_for_update.157*/158static inline void media_request_unlock_for_update(struct media_request *req)159{160unsigned long flags;161162spin_lock_irqsave(&req->lock, flags);163WARN_ON(req->updating_count <= 0);164if (!--req->updating_count)165req->state = MEDIA_REQUEST_STATE_IDLE;166spin_unlock_irqrestore(&req->lock, flags);167}168169/**170* media_request_get - Get the media request171*172* @req: The media request173*174* Get the media request.175*/176static inline void media_request_get(struct media_request *req)177{178kref_get(&req->kref);179}180181/**182* media_request_put - Put the media request183*184* @req: The media request185*186* Put the media request. The media request will be released187* when the refcount reaches 0.188*/189void media_request_put(struct media_request *req);190191/**192* media_request_get_by_fd - Get a media request by fd193*194* @mdev: Media device this request belongs to195* @request_fd: The file descriptor of the request196*197* Get the request represented by @request_fd that is owned198* by the media device.199*200* Return a -EBADR error pointer if requests are not supported201* by this driver. Return -EINVAL if the request was not found.202* Return the pointer to the request if found: the caller will203* have to call @media_request_put when it finished using the204* request.205*/206struct media_request *207media_request_get_by_fd(struct media_device *mdev, int request_fd);208209/**210* media_request_alloc - Allocate the media request211*212* @mdev: Media device this request belongs to213* @alloc_fd: Store the request's file descriptor in this int214*215* Allocated the media request and put the fd in @alloc_fd.216*/217int media_request_alloc(struct media_device *mdev,218int *alloc_fd);219220#else221222static inline void media_request_get(struct media_request *req)223{224}225226static inline void media_request_put(struct media_request *req)227{228}229230static inline struct media_request *231media_request_get_by_fd(struct media_device *mdev, int request_fd)232{233return ERR_PTR(-EBADR);234}235236#endif237238/**239* struct media_request_object_ops - Media request object operations240* @prepare: Validate and prepare the request object, optional.241* @unprepare: Unprepare the request object, optional.242* @queue: Queue the request object, optional.243* @unbind: Unbind the request object, optional.244* @release: Release the request object, required.245*/246struct media_request_object_ops {247int (*prepare)(struct media_request_object *object);248void (*unprepare)(struct media_request_object *object);249void (*queue)(struct media_request_object *object);250void (*unbind)(struct media_request_object *object);251void (*release)(struct media_request_object *object);252};253254/**255* struct media_request_object - An opaque object that belongs to a media256* request257*258* @ops: object's operations259* @priv: object's priv pointer260* @req: the request this object belongs to (can be NULL)261* @list: List entry of the object for @struct media_request262* @kref: Reference count of the object, acquire before releasing req->lock263* @completed: If true, then this object was completed.264*265* An object related to the request. This struct is always embedded in266* another struct that contains the actual data for this request object.267*/268struct media_request_object {269const struct media_request_object_ops *ops;270void *priv;271struct media_request *req;272struct list_head list;273struct kref kref;274bool completed;275};276277#ifdef CONFIG_MEDIA_CONTROLLER278279/**280* media_request_object_get - Get a media request object281*282* @obj: The object283*284* Get a media request object.285*/286static inline void media_request_object_get(struct media_request_object *obj)287{288kref_get(&obj->kref);289}290291/**292* media_request_object_put - Put a media request object293*294* @obj: The object295*296* Put a media request object. Once all references are gone, the297* object's memory is released.298*/299void media_request_object_put(struct media_request_object *obj);300301/**302* media_request_object_find - Find an object in a request303*304* @req: The media request305* @ops: Find an object with this ops value306* @priv: Find an object with this priv value307*308* Both @ops and @priv must be non-NULL.309*310* Returns the object pointer or NULL if not found. The caller must311* call media_request_object_put() once it finished using the object.312*313* Since this function needs to walk the list of objects it takes314* the @req->lock spin lock to make this safe.315*/316struct media_request_object *317media_request_object_find(struct media_request *req,318const struct media_request_object_ops *ops,319void *priv);320321/**322* media_request_object_init - Initialise a media request object323*324* @obj: The object325*326* Initialise a media request object. The object will be released using the327* release callback of the ops once it has no references (this function328* initialises references to one).329*/330void media_request_object_init(struct media_request_object *obj);331332/**333* media_request_object_bind - Bind a media request object to a request334*335* @req: The media request336* @ops: The object ops for this object337* @priv: A driver-specific priv pointer associated with this object338* @is_buffer: Set to true if the object a buffer object.339* @obj: The object340*341* Bind this object to the request and set the ops and priv values of342* the object so it can be found later with media_request_object_find().343*344* Every bound object must be unbound or completed by the kernel at some345* point in time, otherwise the request will never complete. When the346* request is released all completed objects will be unbound by the347* request core code.348*349* Buffer objects will be added to the end of the request's object350* list, non-buffer objects will be added to the front of the list.351* This ensures that all buffer objects are at the end of the list352* and that all non-buffer objects that they depend on are processed353* first.354*/355int media_request_object_bind(struct media_request *req,356const struct media_request_object_ops *ops,357void *priv, bool is_buffer,358struct media_request_object *obj);359360/**361* media_request_object_unbind - Unbind a media request object362*363* @obj: The object364*365* Unbind the media request object from the request.366*/367void media_request_object_unbind(struct media_request_object *obj);368369/**370* media_request_object_complete - Mark the media request object as complete371*372* @obj: The object373*374* Mark the media request object as complete. Only bound objects can375* be completed.376*/377void media_request_object_complete(struct media_request_object *obj);378379#else380381static inline int __must_check382media_request_lock_for_access(struct media_request *req)383{384return -EINVAL;385}386387static inline void media_request_unlock_for_access(struct media_request *req)388{389}390391static inline int __must_check392media_request_lock_for_update(struct media_request *req)393{394return -EINVAL;395}396397static inline void media_request_unlock_for_update(struct media_request *req)398{399}400401static inline void media_request_object_get(struct media_request_object *obj)402{403}404405static inline void media_request_object_put(struct media_request_object *obj)406{407}408409static inline struct media_request_object *410media_request_object_find(struct media_request *req,411const struct media_request_object_ops *ops,412void *priv)413{414return NULL;415}416417static inline void media_request_object_init(struct media_request_object *obj)418{419obj->ops = NULL;420obj->req = NULL;421}422423static inline int media_request_object_bind(struct media_request *req,424const struct media_request_object_ops *ops,425void *priv, bool is_buffer,426struct media_request_object *obj)427{428return 0;429}430431static inline void media_request_object_unbind(struct media_request_object *obj)432{433}434435static inline void media_request_object_complete(struct media_request_object *obj)436{437}438439#endif440441#endif442443444