From: Laurent Pinchart <laurent.pinchart+renesas@xxxxxxxxxxxxxxxx> The media devnode core associates devnodes with files by storing the devnode pointer in the file structure private_data field. In order to allow tracking of per-file-handle data introduce a new media devnode file handle structure that stores the devnode pointer, and store a pointer to that structure in the file private_data field. Users of the media devnode code (the only existing user being media_device) are responsible for managing their own subclass of the media_devnode_fh structure. Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@xxxxxxxxxxxxxxxx> Prepare struct media_device_fh to be used for maintaining file handle list to avoid shuffling things here and there right after. Signed-off-by: Sakari Ailus <sakari.ailus@xxxxxxxxxxxxxxx> Acked-by: Hans Verkuil <hverkuil-cisco@xxxxxxxxx> --- drivers/media/mc/mc-device.c | 14 +++++++++++++- drivers/media/mc/mc-devnode.c | 20 +++++++++----------- include/media/media-device.h | 7 +++++++ include/media/media-devnode.h | 18 +++++++++++++++++- include/media/media-fh.h | 32 ++++++++++++++++++++++++++++++++ 5 files changed, 78 insertions(+), 13 deletions(-) create mode 100644 include/media/media-fh.h diff --git a/drivers/media/mc/mc-device.c b/drivers/media/mc/mc-device.c index f1a88edb7573..a9505ab4412d 100644 --- a/drivers/media/mc/mc-device.c +++ b/drivers/media/mc/mc-device.c @@ -22,6 +22,7 @@ #include <media/media-device.h> #include <media/media-devnode.h> #include <media/media-entity.h> +#include <media/media-fh.h> #include <media/media-request.h> #ifdef CONFIG_MEDIA_CONTROLLER @@ -35,7 +36,6 @@ #define MEDIA_ENT_SUBTYPE_MASK 0x0000ffff #define MEDIA_ENT_T_DEVNODE_UNKNOWN (MEDIA_ENT_F_OLD_BASE | \ MEDIA_ENT_SUBTYPE_MASK) - /* ----------------------------------------------------------------------------- * Userspace API */ @@ -47,11 +47,23 @@ static inline void __user *media_get_uptr(__u64 arg) static int media_device_open(struct file *filp) { + struct media_device_fh *fh; + + fh = kzalloc(sizeof(*fh), GFP_KERNEL); + if (!fh) + return -ENOMEM; + + filp->private_data = &fh->fh; + return 0; } static int media_device_close(struct file *filp) { + struct media_device_fh *fh = media_device_fh(filp); + + kfree(fh); + return 0; } diff --git a/drivers/media/mc/mc-devnode.c b/drivers/media/mc/mc-devnode.c index f27d5d288a38..26491daaba96 100644 --- a/drivers/media/mc/mc-devnode.c +++ b/drivers/media/mc/mc-devnode.c @@ -133,6 +133,7 @@ static long media_compat_ioctl(struct file *filp, unsigned int cmd, static int media_open(struct inode *inode, struct file *filp) { struct media_devnode *devnode; + struct media_devnode_fh *fh; int ret; /* Check if the media device is available. This needs to be done with @@ -153,17 +154,15 @@ static int media_open(struct inode *inode, struct file *filp) get_device(&devnode->dev); mutex_unlock(&media_devnode_lock); - filp->private_data = devnode; - - if (devnode->fops->open) { - ret = devnode->fops->open(filp); - if (ret) { - put_device(&devnode->dev); - filp->private_data = NULL; - return ret; - } + ret = devnode->fops->open(filp); + if (ret) { + put_device(&devnode->dev); + return ret; } + fh = filp->private_data; + fh->devnode = devnode; + return 0; } @@ -172,8 +171,7 @@ static int media_release(struct inode *inode, struct file *filp) { struct media_devnode *devnode = media_devnode_data(filp); - if (devnode->fops->release) - devnode->fops->release(filp); + devnode->fops->release(filp); filp->private_data = NULL; diff --git a/include/media/media-device.h b/include/media/media-device.h index fe4625f3f62b..f9f7c37e7d57 100644 --- a/include/media/media-device.h +++ b/include/media/media-device.h @@ -110,6 +110,10 @@ struct media_device_ops { * other operations that stop or start streaming. * @request_id: Used to generate unique request IDs * + * @fh_list: List of file handles in the media device + * (struct media_device_fh.mdev_list). + * @fh_list_lock: Serialise access to fh_list list. + * * This structure represents an abstract high-level media device. It allows easy * access to entities and provides basic media device-level support. The * structure can be allocated directly or embedded in a larger structure. @@ -182,6 +186,9 @@ struct media_device { struct mutex req_queue_mutex; atomic_t request_id; + + struct list_head fh_list; + spinlock_t fh_list_lock; }; /* We don't need to include usb.h here */ diff --git a/include/media/media-devnode.h b/include/media/media-devnode.h index 113c317e6a0e..e4e8552598eb 100644 --- a/include/media/media-devnode.h +++ b/include/media/media-devnode.h @@ -53,6 +53,20 @@ struct media_file_operations { int (*release) (struct file *); }; +/** + * struct media_devnode_fh - Media device node file handle + * @devnode: pointer to the media device node + * + * This structure serves as a base for per-file-handle data storage. Media + * device node users embed media_devnode_fh in their custom file handle data + * structures and store the media_devnode_fh in the file private_data in order + * to let the media device node core locate the media_devnode corresponding to a + * file handle. + */ +struct media_devnode_fh { + struct media_devnode *devnode; +}; + /** * struct media_devnode - Media device node * @fops: pointer to struct &media_file_operations with media device ops @@ -136,7 +150,9 @@ void media_devnode_unregister(struct media_devnode *devnode); */ static inline struct media_devnode *media_devnode_data(struct file *filp) { - return filp->private_data; + struct media_devnode_fh *fh = filp->private_data; + + return fh->devnode; } /** diff --git a/include/media/media-fh.h b/include/media/media-fh.h new file mode 100644 index 000000000000..6f00744b81d6 --- /dev/null +++ b/include/media/media-fh.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Media device file handle + * + * Copyright (C) 2019--2023 Intel Corporation + */ + +#ifndef MEDIA_FH_H +#define MEDIA_FH_H + +#include <linux/list.h> +#include <linux/file.h> + +#include <media/media-devnode.h> + +/** + * struct media_device_fh - File handle specific information on MC + * + * @fh: The media device file handle + * @mdev_list: This file handle in media device's list of file handles + */ +struct media_device_fh { + struct media_devnode_fh fh; + struct list_head mdev_list; +}; + +static inline struct media_device_fh *media_device_fh(struct file *filp) +{ + return container_of(filp->private_data, struct media_device_fh, fh); +} + +#endif /* MEDIA_FH_H */ -- 2.39.2