1 // SPDX-License-Identifier: GPL-2.0
3 * media-dev-allocator.c - Media Controller Device Allocator API
5 * Copyright (c) 2019 Shuah Khan <shuah@kernel.org>
7 * Credits: Suggested by Laurent Pinchart <laurent.pinchart@ideasonboard.com>
11 * This file adds a global refcounted Media Controller Device Instance API.
12 * A system wide global media device list is managed and each media device
13 * includes a kref count. The last put on the media device releases the media
18 #include <linux/kref.h>
19 #include <linux/module.h>
20 #include <linux/slab.h>
21 #include <linux/usb.h>
23 #include <media/media-device.h>
24 #include <media/media-dev-allocator.h>
26 static LIST_HEAD(media_device_list
);
27 static DEFINE_MUTEX(media_device_lock
);
29 struct media_device_instance
{
30 struct media_device mdev
;
32 struct list_head list
;
36 static inline struct media_device_instance
*
37 to_media_device_instance(struct media_device
*mdev
)
39 return container_of(mdev
, struct media_device_instance
, mdev
);
42 static void media_device_instance_release(struct kref
*kref
)
44 struct media_device_instance
*mdi
=
45 container_of(kref
, struct media_device_instance
, refcount
);
47 dev_dbg(mdi
->mdev
.dev
, "%s: releasing Media Device\n", __func__
);
49 mutex_lock(&media_device_lock
);
51 media_device_unregister(&mdi
->mdev
);
52 media_device_cleanup(&mdi
->mdev
);
55 mutex_unlock(&media_device_lock
);
60 /* Callers should hold media_device_lock when calling this function */
61 static struct media_device
*__media_device_get(struct device
*dev
,
62 const char *module_name
,
65 struct media_device_instance
*mdi
;
67 list_for_each_entry(mdi
, &media_device_list
, list
) {
68 if (mdi
->mdev
.dev
!= dev
)
71 kref_get(&mdi
->refcount
);
73 /* get module reference for the media_device owner */
74 if (owner
!= mdi
->owner
&& !try_module_get(mdi
->owner
))
76 "%s: module %s get owner reference error\n",
77 __func__
, module_name
);
79 dev_dbg(dev
, "%s: module %s got owner reference\n",
80 __func__
, module_name
);
84 mdi
= kzalloc(sizeof(*mdi
), GFP_KERNEL
);
89 kref_init(&mdi
->refcount
);
90 list_add_tail(&mdi
->list
, &media_device_list
);
92 dev_dbg(dev
, "%s: Allocated media device for owner %s\n",
93 __func__
, module_name
);
97 struct media_device
*media_device_usb_allocate(struct usb_device
*udev
,
98 const char *module_name
,
101 struct media_device
*mdev
;
103 mutex_lock(&media_device_lock
);
104 mdev
= __media_device_get(&udev
->dev
, module_name
, owner
);
106 mutex_unlock(&media_device_lock
);
107 return ERR_PTR(-ENOMEM
);
110 /* check if media device is already initialized */
112 __media_device_usb_init(mdev
, udev
, udev
->product
,
114 mutex_unlock(&media_device_lock
);
117 EXPORT_SYMBOL_GPL(media_device_usb_allocate
);
119 void media_device_delete(struct media_device
*mdev
, const char *module_name
,
120 struct module
*owner
)
122 struct media_device_instance
*mdi
= to_media_device_instance(mdev
);
124 mutex_lock(&media_device_lock
);
125 /* put module reference for the media_device owner */
126 if (mdi
->owner
!= owner
) {
127 module_put(mdi
->owner
);
128 dev_dbg(mdi
->mdev
.dev
,
129 "%s: module %s put owner module reference\n",
130 __func__
, module_name
);
132 mutex_unlock(&media_device_lock
);
133 kref_put(&mdi
->refcount
, media_device_instance_release
);
135 EXPORT_SYMBOL_GPL(media_device_delete
);