1 | /* SPDX-License-Identifier: GPL-2.0 or MIT */ |
2 | |
3 | #ifndef _DRM_CLIENT_H_ |
4 | #define _DRM_CLIENT_H_ |
5 | |
6 | #include <linux/iosys-map.h> |
7 | #include <linux/lockdep.h> |
8 | #include <linux/mutex.h> |
9 | #include <linux/types.h> |
10 | |
11 | #include <drm/drm_connector.h> |
12 | #include <drm/drm_crtc.h> |
13 | |
14 | struct drm_client_dev; |
15 | struct drm_device; |
16 | struct drm_file; |
17 | struct drm_framebuffer; |
18 | struct drm_gem_object; |
19 | struct drm_minor; |
20 | struct module; |
21 | |
22 | /** |
23 | * struct drm_client_funcs - DRM client callbacks |
24 | */ |
25 | struct drm_client_funcs { |
26 | /** |
27 | * @owner: The module owner |
28 | */ |
29 | struct module *owner; |
30 | |
31 | /** |
32 | * @unregister: |
33 | * |
34 | * Called when &drm_device is unregistered. The client should respond by |
35 | * releasing its resources using drm_client_release(). |
36 | * |
37 | * This callback is optional. |
38 | */ |
39 | void (*unregister)(struct drm_client_dev *client); |
40 | |
41 | /** |
42 | * @restore: |
43 | * |
44 | * Called on drm_lastclose(). The first client instance in the list that |
45 | * returns zero gets the privilege to restore and no more clients are |
46 | * called. This callback is not called after @unregister has been called. |
47 | * |
48 | * Note that the core does not guarantee exclusion against concurrent |
49 | * drm_open(). Clients need to ensure this themselves, for example by |
50 | * using drm_master_internal_acquire() and |
51 | * drm_master_internal_release(). |
52 | * |
53 | * This callback is optional. |
54 | */ |
55 | int (*restore)(struct drm_client_dev *client); |
56 | |
57 | /** |
58 | * @hotplug: |
59 | * |
60 | * Called on drm_kms_helper_hotplug_event(). |
61 | * This callback is not called after @unregister has been called. |
62 | * |
63 | * This callback is optional. |
64 | */ |
65 | int (*hotplug)(struct drm_client_dev *client); |
66 | |
67 | /** |
68 | * @suspend: |
69 | * |
70 | * Called when suspending the device. |
71 | * |
72 | * This callback is optional. |
73 | * |
74 | * FIXME: Some callers hold the console lock when invoking this |
75 | * function. This interferes with fbdev emulation, which |
76 | * also tries to acquire the lock. Push the console lock |
77 | * into the callback and remove 'holds_console_lock'. |
78 | */ |
79 | int (*suspend)(struct drm_client_dev *client, bool holds_console_lock); |
80 | |
81 | /** |
82 | * @resume: |
83 | * |
84 | * Called when resuming the device from suspend. |
85 | * |
86 | * This callback is optional. |
87 | * |
88 | * FIXME: Some callers hold the console lock when invoking this |
89 | * function. This interferes with fbdev emulation, which |
90 | * also tries to acquire the lock. Push the console lock |
91 | * into the callback and remove 'holds_console_lock'. |
92 | */ |
93 | int (*resume)(struct drm_client_dev *client, bool holds_console_lock); |
94 | }; |
95 | |
96 | /** |
97 | * struct drm_client_dev - DRM client instance |
98 | */ |
99 | struct drm_client_dev { |
100 | /** |
101 | * @dev: DRM device |
102 | */ |
103 | struct drm_device *dev; |
104 | |
105 | /** |
106 | * @name: Name of the client. |
107 | */ |
108 | const char *name; |
109 | |
110 | /** |
111 | * @list: |
112 | * |
113 | * List of all clients of a DRM device, linked into |
114 | * &drm_device.clientlist. Protected by &drm_device.clientlist_mutex. |
115 | */ |
116 | struct list_head list; |
117 | |
118 | /** |
119 | * @funcs: DRM client functions (optional) |
120 | */ |
121 | const struct drm_client_funcs *funcs; |
122 | |
123 | /** |
124 | * @file: DRM file |
125 | */ |
126 | struct drm_file *file; |
127 | |
128 | /** |
129 | * @modeset_mutex: Protects @modesets. |
130 | */ |
131 | struct mutex modeset_mutex; |
132 | |
133 | /** |
134 | * @modesets: CRTC configurations |
135 | */ |
136 | struct drm_mode_set *modesets; |
137 | |
138 | /** |
139 | * @suspended: |
140 | * |
141 | * The client has been suspended. |
142 | */ |
143 | bool suspended; |
144 | |
145 | /** |
146 | * @hotplug_pending: |
147 | * |
148 | * A hotplug event has been received while the client was suspended. |
149 | * Try again on resume. |
150 | */ |
151 | bool hotplug_pending; |
152 | |
153 | /** |
154 | * @hotplug_failed: |
155 | * |
156 | * Set by client hotplug helpers if the hotplugging failed |
157 | * before. It is usually not tried again. |
158 | */ |
159 | bool hotplug_failed; |
160 | }; |
161 | |
162 | int drm_client_init(struct drm_device *dev, struct drm_client_dev *client, |
163 | const char *name, const struct drm_client_funcs *funcs); |
164 | void drm_client_release(struct drm_client_dev *client); |
165 | void drm_client_register(struct drm_client_dev *client); |
166 | |
167 | /** |
168 | * struct drm_client_buffer - DRM client buffer |
169 | */ |
170 | struct drm_client_buffer { |
171 | /** |
172 | * @client: DRM client |
173 | */ |
174 | struct drm_client_dev *client; |
175 | |
176 | /** |
177 | * @pitch: Buffer pitch |
178 | */ |
179 | u32 pitch; |
180 | |
181 | /** |
182 | * @gem: GEM object backing this buffer |
183 | * |
184 | * FIXME: The dependency on GEM here isn't required, we could |
185 | * convert the driver handle to a dma-buf instead and use the |
186 | * backend-agnostic dma-buf vmap support instead. This would |
187 | * require that the handle2fd prime ioctl is reworked to pull the |
188 | * fd_install step out of the driver backend hooks, to make that |
189 | * final step optional for internal users. |
190 | */ |
191 | struct drm_gem_object *gem; |
192 | |
193 | /** |
194 | * @map: Virtual address for the buffer |
195 | */ |
196 | struct iosys_map map; |
197 | |
198 | /** |
199 | * @fb: DRM framebuffer |
200 | */ |
201 | struct drm_framebuffer *fb; |
202 | }; |
203 | |
204 | struct drm_client_buffer * |
205 | drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format); |
206 | void drm_client_framebuffer_delete(struct drm_client_buffer *buffer); |
207 | int drm_client_framebuffer_flush(struct drm_client_buffer *buffer, struct drm_rect *rect); |
208 | int drm_client_buffer_vmap_local(struct drm_client_buffer *buffer, |
209 | struct iosys_map *map_copy); |
210 | void drm_client_buffer_vunmap_local(struct drm_client_buffer *buffer); |
211 | int drm_client_buffer_vmap(struct drm_client_buffer *buffer, |
212 | struct iosys_map *map); |
213 | void drm_client_buffer_vunmap(struct drm_client_buffer *buffer); |
214 | |
215 | int drm_client_modeset_create(struct drm_client_dev *client); |
216 | void drm_client_modeset_free(struct drm_client_dev *client); |
217 | int drm_client_modeset_probe(struct drm_client_dev *client, unsigned int width, unsigned int height); |
218 | bool drm_client_rotation(struct drm_mode_set *modeset, unsigned int *rotation); |
219 | int drm_client_modeset_check(struct drm_client_dev *client); |
220 | int drm_client_modeset_commit_locked(struct drm_client_dev *client); |
221 | int drm_client_modeset_commit(struct drm_client_dev *client); |
222 | int drm_client_modeset_dpms(struct drm_client_dev *client, int mode); |
223 | |
224 | /** |
225 | * drm_client_for_each_modeset() - Iterate over client modesets |
226 | * @modeset: &drm_mode_set loop cursor |
227 | * @client: DRM client |
228 | */ |
229 | #define drm_client_for_each_modeset(modeset, client) \ |
230 | for (({ lockdep_assert_held(&(client)->modeset_mutex); }), \ |
231 | modeset = (client)->modesets; modeset->crtc; modeset++) |
232 | |
233 | /** |
234 | * drm_client_for_each_connector_iter - connector_list iterator macro |
235 | * @connector: &struct drm_connector pointer used as cursor |
236 | * @iter: &struct drm_connector_list_iter |
237 | * |
238 | * This iterates the connectors that are useable for internal clients (excludes |
239 | * writeback connectors). |
240 | * |
241 | * For more info see drm_for_each_connector_iter(). |
242 | */ |
243 | #define drm_client_for_each_connector_iter(connector, iter) \ |
244 | drm_for_each_connector_iter(connector, iter) \ |
245 | if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) |
246 | |
247 | #endif |
248 | |