1 // SPDX-License-Identifier: GPL-2.0 or MIT
3 * Copyright 2018 Noralf Trønnes
6 #include <linux/list.h>
7 #include <linux/mutex.h>
8 #include <linux/seq_file.h>
10 #include <drm/drm_client.h>
11 #include <drm/drm_client_event.h>
12 #include <drm/drm_debugfs.h>
13 #include <drm/drm_device.h>
14 #include <drm/drm_drv.h>
15 #include <drm/drm_print.h>
17 #include "drm_internal.h"
20 * drm_client_dev_unregister - Unregister clients
23 * This function releases all clients by calling each client's
24 * &drm_client_funcs.unregister callback. The callback function
25 * is responsibe for releaseing all resources including the client
28 * The helper drm_dev_unregister() calls this function. Drivers
29 * that use it don't need to call this function themselves.
31 void drm_client_dev_unregister(struct drm_device
*dev
)
33 struct drm_client_dev
*client
, *tmp
;
35 if (!drm_core_check_feature(dev
, DRIVER_MODESET
))
38 mutex_lock(&dev
->clientlist_mutex
);
39 list_for_each_entry_safe(client
, tmp
, &dev
->clientlist
, list
) {
40 list_del(&client
->list
);
41 if (client
->funcs
&& client
->funcs
->unregister
) {
42 client
->funcs
->unregister(client
);
44 drm_client_release(client
);
48 mutex_unlock(&dev
->clientlist_mutex
);
50 EXPORT_SYMBOL(drm_client_dev_unregister
);
53 * drm_client_dev_hotplug - Send hotplug event to clients
56 * This function calls the &drm_client_funcs.hotplug callback on the attached clients.
58 * drm_kms_helper_hotplug_event() calls this function, so drivers that use it
59 * don't need to call this function themselves.
61 void drm_client_dev_hotplug(struct drm_device
*dev
)
63 struct drm_client_dev
*client
;
66 if (!drm_core_check_feature(dev
, DRIVER_MODESET
))
69 if (!dev
->mode_config
.num_connector
) {
70 drm_dbg_kms(dev
, "No connectors found, will not send hotplug events!\n");
74 mutex_lock(&dev
->clientlist_mutex
);
75 list_for_each_entry(client
, &dev
->clientlist
, list
) {
76 if (!client
->funcs
|| !client
->funcs
->hotplug
)
79 if (client
->hotplug_failed
)
82 ret
= client
->funcs
->hotplug(client
);
83 drm_dbg_kms(dev
, "%s: ret=%d\n", client
->name
, ret
);
85 client
->hotplug_failed
= true;
87 mutex_unlock(&dev
->clientlist_mutex
);
89 EXPORT_SYMBOL(drm_client_dev_hotplug
);
91 void drm_client_dev_restore(struct drm_device
*dev
)
93 struct drm_client_dev
*client
;
96 if (!drm_core_check_feature(dev
, DRIVER_MODESET
))
99 mutex_lock(&dev
->clientlist_mutex
);
100 list_for_each_entry(client
, &dev
->clientlist
, list
) {
101 if (!client
->funcs
|| !client
->funcs
->restore
)
104 ret
= client
->funcs
->restore(client
);
105 drm_dbg_kms(dev
, "%s: ret=%d\n", client
->name
, ret
);
106 if (!ret
) /* The first one to return zero gets the privilege to restore */
109 mutex_unlock(&dev
->clientlist_mutex
);
112 static int drm_client_suspend(struct drm_client_dev
*client
, bool holds_console_lock
)
114 struct drm_device
*dev
= client
->dev
;
117 if (drm_WARN_ON_ONCE(dev
, client
->suspended
))
120 if (client
->funcs
&& client
->funcs
->suspend
)
121 ret
= client
->funcs
->suspend(client
, holds_console_lock
);
122 drm_dbg_kms(dev
, "%s: ret=%d\n", client
->name
, ret
);
124 client
->suspended
= true;
129 void drm_client_dev_suspend(struct drm_device
*dev
, bool holds_console_lock
)
131 struct drm_client_dev
*client
;
133 mutex_lock(&dev
->clientlist_mutex
);
134 list_for_each_entry(client
, &dev
->clientlist
, list
) {
135 if (!client
->suspended
)
136 drm_client_suspend(client
, holds_console_lock
);
138 mutex_unlock(&dev
->clientlist_mutex
);
140 EXPORT_SYMBOL(drm_client_dev_suspend
);
142 static int drm_client_resume(struct drm_client_dev
*client
, bool holds_console_lock
)
144 struct drm_device
*dev
= client
->dev
;
147 if (drm_WARN_ON_ONCE(dev
, !client
->suspended
))
150 if (client
->funcs
&& client
->funcs
->resume
)
151 ret
= client
->funcs
->resume(client
, holds_console_lock
);
152 drm_dbg_kms(dev
, "%s: ret=%d\n", client
->name
, ret
);
154 client
->suspended
= false;
159 void drm_client_dev_resume(struct drm_device
*dev
, bool holds_console_lock
)
161 struct drm_client_dev
*client
;
163 mutex_lock(&dev
->clientlist_mutex
);
164 list_for_each_entry(client
, &dev
->clientlist
, list
) {
165 if (client
->suspended
)
166 drm_client_resume(client
, holds_console_lock
);
168 mutex_unlock(&dev
->clientlist_mutex
);
170 EXPORT_SYMBOL(drm_client_dev_resume
);
172 #ifdef CONFIG_DEBUG_FS
173 static int drm_client_debugfs_internal_clients(struct seq_file
*m
, void *data
)
175 struct drm_debugfs_entry
*entry
= m
->private;
176 struct drm_device
*dev
= entry
->dev
;
177 struct drm_printer p
= drm_seq_file_printer(m
);
178 struct drm_client_dev
*client
;
180 mutex_lock(&dev
->clientlist_mutex
);
181 list_for_each_entry(client
, &dev
->clientlist
, list
)
182 drm_printf(&p
, "%s\n", client
->name
);
183 mutex_unlock(&dev
->clientlist_mutex
);
188 static const struct drm_debugfs_info drm_client_debugfs_list
[] = {
189 { "internal_clients", drm_client_debugfs_internal_clients
, 0 },
192 void drm_client_debugfs_init(struct drm_device
*dev
)
194 drm_debugfs_add_files(dev
, drm_client_debugfs_list
,
195 ARRAY_SIZE(drm_client_debugfs_list
));