1c349dbc7Sjsg // SPDX-License-Identifier: GPL-2.0 or MIT
2c349dbc7Sjsg /*
3c349dbc7Sjsg * Copyright 2018 Noralf Trønnes
4c349dbc7Sjsg */
5c349dbc7Sjsg
61bb76ff1Sjsg #include <linux/iosys-map.h>
7c349dbc7Sjsg #include <linux/list.h>
8c349dbc7Sjsg #include <linux/module.h>
9c349dbc7Sjsg #include <linux/mutex.h>
10c349dbc7Sjsg #include <linux/seq_file.h>
11c349dbc7Sjsg #include <linux/slab.h>
12c349dbc7Sjsg
13c349dbc7Sjsg #include <drm/drm_client.h>
14c349dbc7Sjsg #include <drm/drm_debugfs.h>
15c349dbc7Sjsg #include <drm/drm_device.h>
16c349dbc7Sjsg #include <drm/drm_drv.h>
17c349dbc7Sjsg #include <drm/drm_file.h>
18c349dbc7Sjsg #include <drm/drm_fourcc.h>
19c349dbc7Sjsg #include <drm/drm_framebuffer.h>
20c349dbc7Sjsg #include <drm/drm_gem.h>
21c349dbc7Sjsg #include <drm/drm_mode.h>
22c349dbc7Sjsg #include <drm/drm_print.h>
23c349dbc7Sjsg
24c349dbc7Sjsg #include "drm_crtc_internal.h"
25c349dbc7Sjsg #include "drm_internal.h"
26c349dbc7Sjsg
27c349dbc7Sjsg /**
28c349dbc7Sjsg * DOC: overview
29c349dbc7Sjsg *
30c349dbc7Sjsg * This library provides support for clients running in the kernel like fbdev and bootsplash.
31c349dbc7Sjsg *
32c349dbc7Sjsg * GEM drivers which provide a GEM based dumb buffer with a virtual address are supported.
33c349dbc7Sjsg */
34c349dbc7Sjsg
drm_client_open(struct drm_client_dev * client)35c349dbc7Sjsg static int drm_client_open(struct drm_client_dev *client)
36c349dbc7Sjsg {
37c349dbc7Sjsg struct drm_device *dev = client->dev;
38c349dbc7Sjsg struct drm_file *file;
39c349dbc7Sjsg
40c349dbc7Sjsg file = drm_file_alloc(dev->primary);
41c349dbc7Sjsg if (IS_ERR(file))
42c349dbc7Sjsg return PTR_ERR(file);
43c349dbc7Sjsg
44c349dbc7Sjsg mutex_lock(&dev->filelist_mutex);
45c349dbc7Sjsg list_add(&file->lhead, &dev->filelist_internal);
46c349dbc7Sjsg mutex_unlock(&dev->filelist_mutex);
47c349dbc7Sjsg
48c349dbc7Sjsg client->file = file;
49c349dbc7Sjsg
50c349dbc7Sjsg return 0;
51c349dbc7Sjsg }
52c349dbc7Sjsg
drm_client_close(struct drm_client_dev * client)53c349dbc7Sjsg static void drm_client_close(struct drm_client_dev *client)
54c349dbc7Sjsg {
55c349dbc7Sjsg struct drm_device *dev = client->dev;
56c349dbc7Sjsg
57c349dbc7Sjsg mutex_lock(&dev->filelist_mutex);
58c349dbc7Sjsg list_del(&client->file->lhead);
59c349dbc7Sjsg mutex_unlock(&dev->filelist_mutex);
60c349dbc7Sjsg
61c349dbc7Sjsg drm_file_free(client->file);
62c349dbc7Sjsg }
63c349dbc7Sjsg
64c349dbc7Sjsg /**
65c349dbc7Sjsg * drm_client_init - Initialise a DRM client
66c349dbc7Sjsg * @dev: DRM device
67c349dbc7Sjsg * @client: DRM client
68c349dbc7Sjsg * @name: Client name
69c349dbc7Sjsg * @funcs: DRM client functions (optional)
70c349dbc7Sjsg *
71c349dbc7Sjsg * This initialises the client and opens a &drm_file.
72c349dbc7Sjsg * Use drm_client_register() to complete the process.
73c349dbc7Sjsg * The caller needs to hold a reference on @dev before calling this function.
74c349dbc7Sjsg * The client is freed when the &drm_device is unregistered. See drm_client_release().
75c349dbc7Sjsg *
76c349dbc7Sjsg * Returns:
77c349dbc7Sjsg * Zero on success or negative error code on failure.
78c349dbc7Sjsg */
drm_client_init(struct drm_device * dev,struct drm_client_dev * client,const char * name,const struct drm_client_funcs * funcs)79c349dbc7Sjsg int drm_client_init(struct drm_device *dev, struct drm_client_dev *client,
80c349dbc7Sjsg const char *name, const struct drm_client_funcs *funcs)
81c349dbc7Sjsg {
82c349dbc7Sjsg int ret;
83c349dbc7Sjsg
84c349dbc7Sjsg if (!drm_core_check_feature(dev, DRIVER_MODESET) || !dev->driver->dumb_create)
85c349dbc7Sjsg return -EOPNOTSUPP;
86c349dbc7Sjsg
87c349dbc7Sjsg if (funcs && !try_module_get(funcs->owner))
88c349dbc7Sjsg return -ENODEV;
89c349dbc7Sjsg
90c349dbc7Sjsg client->dev = dev;
91c349dbc7Sjsg client->name = name;
92c349dbc7Sjsg client->funcs = funcs;
93c349dbc7Sjsg
94c349dbc7Sjsg ret = drm_client_modeset_create(client);
95c349dbc7Sjsg if (ret)
96c349dbc7Sjsg goto err_put_module;
97c349dbc7Sjsg
98c349dbc7Sjsg ret = drm_client_open(client);
99c349dbc7Sjsg if (ret)
100c349dbc7Sjsg goto err_free;
101c349dbc7Sjsg
102c349dbc7Sjsg drm_dev_get(dev);
103c349dbc7Sjsg
104c349dbc7Sjsg return 0;
105c349dbc7Sjsg
106c349dbc7Sjsg err_free:
107c349dbc7Sjsg drm_client_modeset_free(client);
108c349dbc7Sjsg err_put_module:
109c349dbc7Sjsg if (funcs)
110c349dbc7Sjsg module_put(funcs->owner);
111c349dbc7Sjsg
112c349dbc7Sjsg return ret;
113c349dbc7Sjsg }
114c349dbc7Sjsg EXPORT_SYMBOL(drm_client_init);
115c349dbc7Sjsg
116c349dbc7Sjsg /**
117c349dbc7Sjsg * drm_client_register - Register client
118c349dbc7Sjsg * @client: DRM client
119c349dbc7Sjsg *
120c349dbc7Sjsg * Add the client to the &drm_device client list to activate its callbacks.
121c349dbc7Sjsg * @client must be initialized by a call to drm_client_init(). After
122c349dbc7Sjsg * drm_client_register() it is no longer permissible to call drm_client_release()
123c349dbc7Sjsg * directly (outside the unregister callback), instead cleanup will happen
124c349dbc7Sjsg * automatically on driver unload.
125753a1a00Sjsg *
126753a1a00Sjsg * Registering a client generates a hotplug event that allows the client
127753a1a00Sjsg * to set up its display from pre-existing outputs. The client must have
128753a1a00Sjsg * initialized its state to able to handle the hotplug event successfully.
129c349dbc7Sjsg */
drm_client_register(struct drm_client_dev * client)130c349dbc7Sjsg void drm_client_register(struct drm_client_dev *client)
131c349dbc7Sjsg {
132c349dbc7Sjsg struct drm_device *dev = client->dev;
133753a1a00Sjsg int ret;
134c349dbc7Sjsg
135c349dbc7Sjsg mutex_lock(&dev->clientlist_mutex);
136c349dbc7Sjsg list_add(&client->list, &dev->clientlist);
137753a1a00Sjsg
138753a1a00Sjsg if (client->funcs && client->funcs->hotplug) {
139753a1a00Sjsg /*
140753a1a00Sjsg * Perform an initial hotplug event to pick up the
141753a1a00Sjsg * display configuration for the client. This step
142753a1a00Sjsg * has to be performed *after* registering the client
143753a1a00Sjsg * in the list of clients, or a concurrent hotplug
144753a1a00Sjsg * event might be lost; leaving the display off.
145753a1a00Sjsg *
146753a1a00Sjsg * Hold the clientlist_mutex as for a regular hotplug
147753a1a00Sjsg * event.
148753a1a00Sjsg */
149753a1a00Sjsg ret = client->funcs->hotplug(client);
150753a1a00Sjsg if (ret)
151753a1a00Sjsg drm_dbg_kms(dev, "client hotplug ret=%d\n", ret);
152753a1a00Sjsg }
153c349dbc7Sjsg mutex_unlock(&dev->clientlist_mutex);
154c349dbc7Sjsg }
155c349dbc7Sjsg EXPORT_SYMBOL(drm_client_register);
156c349dbc7Sjsg
157c349dbc7Sjsg /**
158c349dbc7Sjsg * drm_client_release - Release DRM client resources
159c349dbc7Sjsg * @client: DRM client
160c349dbc7Sjsg *
161c349dbc7Sjsg * Releases resources by closing the &drm_file that was opened by drm_client_init().
162c349dbc7Sjsg * It is called automatically if the &drm_client_funcs.unregister callback is _not_ set.
163c349dbc7Sjsg *
164c349dbc7Sjsg * This function should only be called from the unregister callback. An exception
165c349dbc7Sjsg * is fbdev which cannot free the buffer if userspace has open file descriptors.
166c349dbc7Sjsg *
167c349dbc7Sjsg * Note:
168c349dbc7Sjsg * Clients cannot initiate a release by themselves. This is done to keep the code simple.
169c349dbc7Sjsg * The driver has to be unloaded before the client can be unloaded.
170c349dbc7Sjsg */
drm_client_release(struct drm_client_dev * client)171c349dbc7Sjsg void drm_client_release(struct drm_client_dev *client)
172c349dbc7Sjsg {
173c349dbc7Sjsg struct drm_device *dev = client->dev;
174c349dbc7Sjsg
175c349dbc7Sjsg drm_dbg_kms(dev, "%s\n", client->name);
176c349dbc7Sjsg
177c349dbc7Sjsg drm_client_modeset_free(client);
178c349dbc7Sjsg drm_client_close(client);
179c349dbc7Sjsg drm_dev_put(dev);
180c349dbc7Sjsg if (client->funcs)
181c349dbc7Sjsg module_put(client->funcs->owner);
182c349dbc7Sjsg }
183c349dbc7Sjsg EXPORT_SYMBOL(drm_client_release);
184c349dbc7Sjsg
drm_client_dev_unregister(struct drm_device * dev)185c349dbc7Sjsg void drm_client_dev_unregister(struct drm_device *dev)
186c349dbc7Sjsg {
187c349dbc7Sjsg struct drm_client_dev *client, *tmp;
188c349dbc7Sjsg
189c349dbc7Sjsg if (!drm_core_check_feature(dev, DRIVER_MODESET))
190c349dbc7Sjsg return;
191c349dbc7Sjsg
192c349dbc7Sjsg mutex_lock(&dev->clientlist_mutex);
193c349dbc7Sjsg list_for_each_entry_safe(client, tmp, &dev->clientlist, list) {
194c349dbc7Sjsg list_del(&client->list);
195c349dbc7Sjsg if (client->funcs && client->funcs->unregister) {
196c349dbc7Sjsg client->funcs->unregister(client);
197c349dbc7Sjsg } else {
198c349dbc7Sjsg drm_client_release(client);
199c349dbc7Sjsg kfree(client);
200c349dbc7Sjsg }
201c349dbc7Sjsg }
202c349dbc7Sjsg mutex_unlock(&dev->clientlist_mutex);
203c349dbc7Sjsg }
204c349dbc7Sjsg
205c349dbc7Sjsg /**
206c349dbc7Sjsg * drm_client_dev_hotplug - Send hotplug event to clients
207c349dbc7Sjsg * @dev: DRM device
208c349dbc7Sjsg *
209c349dbc7Sjsg * This function calls the &drm_client_funcs.hotplug callback on the attached clients.
210c349dbc7Sjsg *
211c349dbc7Sjsg * drm_kms_helper_hotplug_event() calls this function, so drivers that use it
212c349dbc7Sjsg * don't need to call this function themselves.
213c349dbc7Sjsg */
drm_client_dev_hotplug(struct drm_device * dev)214c349dbc7Sjsg void drm_client_dev_hotplug(struct drm_device *dev)
215c349dbc7Sjsg {
216c349dbc7Sjsg struct drm_client_dev *client;
217c349dbc7Sjsg int ret;
218c349dbc7Sjsg
219c349dbc7Sjsg if (!drm_core_check_feature(dev, DRIVER_MODESET))
220c349dbc7Sjsg return;
221c349dbc7Sjsg
222*f005ef32Sjsg if (!dev->mode_config.num_connector) {
223*f005ef32Sjsg drm_dbg_kms(dev, "No connectors found, will not send hotplug events!\n");
224*f005ef32Sjsg return;
225*f005ef32Sjsg }
226*f005ef32Sjsg
227c349dbc7Sjsg mutex_lock(&dev->clientlist_mutex);
228c349dbc7Sjsg list_for_each_entry(client, &dev->clientlist, list) {
229c349dbc7Sjsg if (!client->funcs || !client->funcs->hotplug)
230c349dbc7Sjsg continue;
231c349dbc7Sjsg
232*f005ef32Sjsg if (client->hotplug_failed)
233*f005ef32Sjsg continue;
234*f005ef32Sjsg
235c349dbc7Sjsg ret = client->funcs->hotplug(client);
236c349dbc7Sjsg drm_dbg_kms(dev, "%s: ret=%d\n", client->name, ret);
237*f005ef32Sjsg if (ret)
238*f005ef32Sjsg client->hotplug_failed = true;
239c349dbc7Sjsg }
240c349dbc7Sjsg mutex_unlock(&dev->clientlist_mutex);
241c349dbc7Sjsg }
242c349dbc7Sjsg EXPORT_SYMBOL(drm_client_dev_hotplug);
243c349dbc7Sjsg
drm_client_dev_restore(struct drm_device * dev)244c349dbc7Sjsg void drm_client_dev_restore(struct drm_device *dev)
245c349dbc7Sjsg {
246c349dbc7Sjsg struct drm_client_dev *client;
247c349dbc7Sjsg int ret;
248c349dbc7Sjsg
249c349dbc7Sjsg if (!drm_core_check_feature(dev, DRIVER_MODESET))
250c349dbc7Sjsg return;
251c349dbc7Sjsg
252c349dbc7Sjsg mutex_lock(&dev->clientlist_mutex);
253c349dbc7Sjsg list_for_each_entry(client, &dev->clientlist, list) {
254c349dbc7Sjsg if (!client->funcs || !client->funcs->restore)
255c349dbc7Sjsg continue;
256c349dbc7Sjsg
257c349dbc7Sjsg ret = client->funcs->restore(client);
258c349dbc7Sjsg drm_dbg_kms(dev, "%s: ret=%d\n", client->name, ret);
259c349dbc7Sjsg if (!ret) /* The first one to return zero gets the privilege to restore */
260c349dbc7Sjsg break;
261c349dbc7Sjsg }
262c349dbc7Sjsg mutex_unlock(&dev->clientlist_mutex);
263c349dbc7Sjsg }
264c349dbc7Sjsg
drm_client_buffer_delete(struct drm_client_buffer * buffer)265c349dbc7Sjsg static void drm_client_buffer_delete(struct drm_client_buffer *buffer)
266c349dbc7Sjsg {
267*f005ef32Sjsg if (buffer->gem) {
268*f005ef32Sjsg drm_gem_vunmap_unlocked(buffer->gem, &buffer->map);
269ad8b1aafSjsg drm_gem_object_put(buffer->gem);
270*f005ef32Sjsg }
271c349dbc7Sjsg
272c349dbc7Sjsg kfree(buffer);
273c349dbc7Sjsg }
274c349dbc7Sjsg
275c349dbc7Sjsg static struct drm_client_buffer *
drm_client_buffer_create(struct drm_client_dev * client,u32 width,u32 height,u32 format,u32 * handle)276*f005ef32Sjsg drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height,
277*f005ef32Sjsg u32 format, u32 *handle)
278c349dbc7Sjsg {
279c349dbc7Sjsg const struct drm_format_info *info = drm_format_info(format);
280c349dbc7Sjsg struct drm_mode_create_dumb dumb_args = { };
281c349dbc7Sjsg struct drm_device *dev = client->dev;
282c349dbc7Sjsg struct drm_client_buffer *buffer;
283c349dbc7Sjsg struct drm_gem_object *obj;
284c349dbc7Sjsg int ret;
285c349dbc7Sjsg
286c349dbc7Sjsg buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
287c349dbc7Sjsg if (!buffer)
288c349dbc7Sjsg return ERR_PTR(-ENOMEM);
289c349dbc7Sjsg
290c349dbc7Sjsg buffer->client = client;
291c349dbc7Sjsg
292c349dbc7Sjsg dumb_args.width = width;
293c349dbc7Sjsg dumb_args.height = height;
2941bb76ff1Sjsg dumb_args.bpp = drm_format_info_bpp(info, 0);
295c349dbc7Sjsg ret = drm_mode_create_dumb(dev, &dumb_args, client->file);
296c349dbc7Sjsg if (ret)
297c349dbc7Sjsg goto err_delete;
298c349dbc7Sjsg
299c349dbc7Sjsg obj = drm_gem_object_lookup(client->file, dumb_args.handle);
300c349dbc7Sjsg if (!obj) {
301c349dbc7Sjsg ret = -ENOENT;
302c349dbc7Sjsg goto err_delete;
303c349dbc7Sjsg }
304c349dbc7Sjsg
305*f005ef32Sjsg buffer->pitch = dumb_args.pitch;
306c349dbc7Sjsg buffer->gem = obj;
307*f005ef32Sjsg *handle = dumb_args.handle;
308c349dbc7Sjsg
309c349dbc7Sjsg return buffer;
310c349dbc7Sjsg
311c349dbc7Sjsg err_delete:
312c349dbc7Sjsg drm_client_buffer_delete(buffer);
313c349dbc7Sjsg
314c349dbc7Sjsg return ERR_PTR(ret);
315c349dbc7Sjsg }
316c349dbc7Sjsg
317c349dbc7Sjsg /**
318c349dbc7Sjsg * drm_client_buffer_vmap - Map DRM client buffer into address space
319c349dbc7Sjsg * @buffer: DRM client buffer
3205ca02815Sjsg * @map_copy: Returns the mapped memory's address
321c349dbc7Sjsg *
322c349dbc7Sjsg * This function maps a client buffer into kernel address space. If the
3235ca02815Sjsg * buffer is already mapped, it returns the existing mapping's address.
324c349dbc7Sjsg *
325c349dbc7Sjsg * Client buffer mappings are not ref'counted. Each call to
326c349dbc7Sjsg * drm_client_buffer_vmap() should be followed by a call to
327c349dbc7Sjsg * drm_client_buffer_vunmap(); or the client buffer should be mapped
328c349dbc7Sjsg * throughout its lifetime.
329c349dbc7Sjsg *
3305ca02815Sjsg * The returned address is a copy of the internal value. In contrast to
3315ca02815Sjsg * other vmap interfaces, you don't need it for the client's vunmap
3325ca02815Sjsg * function. So you can modify it at will during blit and draw operations.
3335ca02815Sjsg *
334c349dbc7Sjsg * Returns:
3355ca02815Sjsg * 0 on success, or a negative errno code otherwise.
336c349dbc7Sjsg */
3375ca02815Sjsg int
drm_client_buffer_vmap(struct drm_client_buffer * buffer,struct iosys_map * map_copy)3381bb76ff1Sjsg drm_client_buffer_vmap(struct drm_client_buffer *buffer,
3391bb76ff1Sjsg struct iosys_map *map_copy)
340c349dbc7Sjsg {
3411bb76ff1Sjsg struct iosys_map *map = &buffer->map;
3425ca02815Sjsg int ret;
343c349dbc7Sjsg
344c349dbc7Sjsg /*
345c349dbc7Sjsg * FIXME: The dependency on GEM here isn't required, we could
346c349dbc7Sjsg * convert the driver handle to a dma-buf instead and use the
347c349dbc7Sjsg * backend-agnostic dma-buf vmap support instead. This would
348c349dbc7Sjsg * require that the handle2fd prime ioctl is reworked to pull the
349c349dbc7Sjsg * fd_install step out of the driver backend hooks, to make that
350c349dbc7Sjsg * final step optional for internal users.
351c349dbc7Sjsg */
352*f005ef32Sjsg ret = drm_gem_vmap_unlocked(buffer->gem, map);
3535ca02815Sjsg if (ret)
3545ca02815Sjsg return ret;
355c349dbc7Sjsg
3565ca02815Sjsg *map_copy = *map;
357c349dbc7Sjsg
3585ca02815Sjsg return 0;
359c349dbc7Sjsg }
360c349dbc7Sjsg EXPORT_SYMBOL(drm_client_buffer_vmap);
361c349dbc7Sjsg
362c349dbc7Sjsg /**
363c349dbc7Sjsg * drm_client_buffer_vunmap - Unmap DRM client buffer
364c349dbc7Sjsg * @buffer: DRM client buffer
365c349dbc7Sjsg *
366c349dbc7Sjsg * This function removes a client buffer's memory mapping. Calling this
367c349dbc7Sjsg * function is only required by clients that manage their buffer mappings
368c349dbc7Sjsg * by themselves.
369c349dbc7Sjsg */
drm_client_buffer_vunmap(struct drm_client_buffer * buffer)370c349dbc7Sjsg void drm_client_buffer_vunmap(struct drm_client_buffer *buffer)
371c349dbc7Sjsg {
3721bb76ff1Sjsg struct iosys_map *map = &buffer->map;
3735ca02815Sjsg
374*f005ef32Sjsg drm_gem_vunmap_unlocked(buffer->gem, map);
375c349dbc7Sjsg }
376c349dbc7Sjsg EXPORT_SYMBOL(drm_client_buffer_vunmap);
377c349dbc7Sjsg
drm_client_buffer_rmfb(struct drm_client_buffer * buffer)378c349dbc7Sjsg static void drm_client_buffer_rmfb(struct drm_client_buffer *buffer)
379c349dbc7Sjsg {
380c349dbc7Sjsg int ret;
381c349dbc7Sjsg
382c349dbc7Sjsg if (!buffer->fb)
383c349dbc7Sjsg return;
384c349dbc7Sjsg
385c349dbc7Sjsg ret = drm_mode_rmfb(buffer->client->dev, buffer->fb->base.id, buffer->client->file);
386c349dbc7Sjsg if (ret)
387c349dbc7Sjsg drm_err(buffer->client->dev,
388c349dbc7Sjsg "Error removing FB:%u (%d)\n", buffer->fb->base.id, ret);
389c349dbc7Sjsg
390c349dbc7Sjsg buffer->fb = NULL;
391c349dbc7Sjsg }
392c349dbc7Sjsg
drm_client_buffer_addfb(struct drm_client_buffer * buffer,u32 width,u32 height,u32 format,u32 handle)393c349dbc7Sjsg static int drm_client_buffer_addfb(struct drm_client_buffer *buffer,
394*f005ef32Sjsg u32 width, u32 height, u32 format,
395*f005ef32Sjsg u32 handle)
396c349dbc7Sjsg {
397c349dbc7Sjsg struct drm_client_dev *client = buffer->client;
398c349dbc7Sjsg struct drm_mode_fb_cmd fb_req = { };
399c349dbc7Sjsg const struct drm_format_info *info;
400c349dbc7Sjsg int ret;
401c349dbc7Sjsg
402c349dbc7Sjsg info = drm_format_info(format);
4031bb76ff1Sjsg fb_req.bpp = drm_format_info_bpp(info, 0);
404c349dbc7Sjsg fb_req.depth = info->depth;
405c349dbc7Sjsg fb_req.width = width;
406c349dbc7Sjsg fb_req.height = height;
407*f005ef32Sjsg fb_req.handle = handle;
408c349dbc7Sjsg fb_req.pitch = buffer->pitch;
409c349dbc7Sjsg
410c349dbc7Sjsg ret = drm_mode_addfb(client->dev, &fb_req, client->file);
411c349dbc7Sjsg if (ret)
412c349dbc7Sjsg return ret;
413c349dbc7Sjsg
414c349dbc7Sjsg buffer->fb = drm_framebuffer_lookup(client->dev, buffer->client->file, fb_req.fb_id);
415c349dbc7Sjsg if (WARN_ON(!buffer->fb))
416c349dbc7Sjsg return -ENOENT;
417c349dbc7Sjsg
418c349dbc7Sjsg /* drop the reference we picked up in framebuffer lookup */
419c349dbc7Sjsg drm_framebuffer_put(buffer->fb);
420c349dbc7Sjsg
421c349dbc7Sjsg strscpy(buffer->fb->comm, client->name, TASK_COMM_LEN);
422c349dbc7Sjsg
423c349dbc7Sjsg return 0;
424c349dbc7Sjsg }
425c349dbc7Sjsg
426c349dbc7Sjsg /**
427c349dbc7Sjsg * drm_client_framebuffer_create - Create a client framebuffer
428c349dbc7Sjsg * @client: DRM client
429c349dbc7Sjsg * @width: Framebuffer width
430c349dbc7Sjsg * @height: Framebuffer height
431c349dbc7Sjsg * @format: Buffer format
432c349dbc7Sjsg *
433c349dbc7Sjsg * This function creates a &drm_client_buffer which consists of a
434c349dbc7Sjsg * &drm_framebuffer backed by a dumb buffer.
435c349dbc7Sjsg * Call drm_client_framebuffer_delete() to free the buffer.
436c349dbc7Sjsg *
437c349dbc7Sjsg * Returns:
438c349dbc7Sjsg * Pointer to a client buffer or an error pointer on failure.
439c349dbc7Sjsg */
440c349dbc7Sjsg struct drm_client_buffer *
drm_client_framebuffer_create(struct drm_client_dev * client,u32 width,u32 height,u32 format)441c349dbc7Sjsg drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format)
442c349dbc7Sjsg {
443c349dbc7Sjsg struct drm_client_buffer *buffer;
444*f005ef32Sjsg u32 handle;
445c349dbc7Sjsg int ret;
446c349dbc7Sjsg
447*f005ef32Sjsg buffer = drm_client_buffer_create(client, width, height, format,
448*f005ef32Sjsg &handle);
449c349dbc7Sjsg if (IS_ERR(buffer))
450c349dbc7Sjsg return buffer;
451c349dbc7Sjsg
452*f005ef32Sjsg ret = drm_client_buffer_addfb(buffer, width, height, format, handle);
453*f005ef32Sjsg
454*f005ef32Sjsg /*
455*f005ef32Sjsg * The handle is only needed for creating the framebuffer, destroy it
456*f005ef32Sjsg * again to solve a circular dependency should anybody export the GEM
457*f005ef32Sjsg * object as DMA-buf. The framebuffer and our buffer structure are still
458*f005ef32Sjsg * holding references to the GEM object to prevent its destruction.
459*f005ef32Sjsg */
460*f005ef32Sjsg drm_mode_destroy_dumb(client->dev, handle, client->file);
461*f005ef32Sjsg
462c349dbc7Sjsg if (ret) {
463c349dbc7Sjsg drm_client_buffer_delete(buffer);
464c349dbc7Sjsg return ERR_PTR(ret);
465c349dbc7Sjsg }
466c349dbc7Sjsg
467c349dbc7Sjsg return buffer;
468c349dbc7Sjsg }
469c349dbc7Sjsg EXPORT_SYMBOL(drm_client_framebuffer_create);
470c349dbc7Sjsg
471c349dbc7Sjsg /**
472c349dbc7Sjsg * drm_client_framebuffer_delete - Delete a client framebuffer
473c349dbc7Sjsg * @buffer: DRM client buffer (can be NULL)
474c349dbc7Sjsg */
drm_client_framebuffer_delete(struct drm_client_buffer * buffer)475c349dbc7Sjsg void drm_client_framebuffer_delete(struct drm_client_buffer *buffer)
476c349dbc7Sjsg {
477c349dbc7Sjsg if (!buffer)
478c349dbc7Sjsg return;
479c349dbc7Sjsg
480c349dbc7Sjsg drm_client_buffer_rmfb(buffer);
481c349dbc7Sjsg drm_client_buffer_delete(buffer);
482c349dbc7Sjsg }
483c349dbc7Sjsg EXPORT_SYMBOL(drm_client_framebuffer_delete);
484c349dbc7Sjsg
485ad8b1aafSjsg /**
486ad8b1aafSjsg * drm_client_framebuffer_flush - Manually flush client framebuffer
487ad8b1aafSjsg * @buffer: DRM client buffer (can be NULL)
488ad8b1aafSjsg * @rect: Damage rectangle (if NULL flushes all)
489ad8b1aafSjsg *
490ad8b1aafSjsg * This calls &drm_framebuffer_funcs->dirty (if present) to flush buffer changes
491ad8b1aafSjsg * for drivers that need it.
492ad8b1aafSjsg *
493ad8b1aafSjsg * Returns:
494ad8b1aafSjsg * Zero on success or negative error code on failure.
495ad8b1aafSjsg */
drm_client_framebuffer_flush(struct drm_client_buffer * buffer,struct drm_rect * rect)496ad8b1aafSjsg int drm_client_framebuffer_flush(struct drm_client_buffer *buffer, struct drm_rect *rect)
497ad8b1aafSjsg {
498ad8b1aafSjsg if (!buffer || !buffer->fb || !buffer->fb->funcs->dirty)
499ad8b1aafSjsg return 0;
500ad8b1aafSjsg
501ad8b1aafSjsg if (rect) {
502ad8b1aafSjsg struct drm_clip_rect clip = {
503ad8b1aafSjsg .x1 = rect->x1,
504ad8b1aafSjsg .y1 = rect->y1,
505ad8b1aafSjsg .x2 = rect->x2,
506ad8b1aafSjsg .y2 = rect->y2,
507ad8b1aafSjsg };
508ad8b1aafSjsg
509ad8b1aafSjsg return buffer->fb->funcs->dirty(buffer->fb, buffer->client->file,
510ad8b1aafSjsg 0, 0, &clip, 1);
511ad8b1aafSjsg }
512ad8b1aafSjsg
513ad8b1aafSjsg return buffer->fb->funcs->dirty(buffer->fb, buffer->client->file,
514ad8b1aafSjsg 0, 0, NULL, 0);
515ad8b1aafSjsg }
516ad8b1aafSjsg EXPORT_SYMBOL(drm_client_framebuffer_flush);
517ad8b1aafSjsg
518c349dbc7Sjsg #ifdef CONFIG_DEBUG_FS
drm_client_debugfs_internal_clients(struct seq_file * m,void * data)519c349dbc7Sjsg static int drm_client_debugfs_internal_clients(struct seq_file *m, void *data)
520c349dbc7Sjsg {
521*f005ef32Sjsg struct drm_debugfs_entry *entry = m->private;
522*f005ef32Sjsg struct drm_device *dev = entry->dev;
523c349dbc7Sjsg struct drm_printer p = drm_seq_file_printer(m);
524c349dbc7Sjsg struct drm_client_dev *client;
525c349dbc7Sjsg
526c349dbc7Sjsg mutex_lock(&dev->clientlist_mutex);
527c349dbc7Sjsg list_for_each_entry(client, &dev->clientlist, list)
528c349dbc7Sjsg drm_printf(&p, "%s\n", client->name);
529c349dbc7Sjsg mutex_unlock(&dev->clientlist_mutex);
530c349dbc7Sjsg
531c349dbc7Sjsg return 0;
532c349dbc7Sjsg }
533c349dbc7Sjsg
534*f005ef32Sjsg static const struct drm_debugfs_info drm_client_debugfs_list[] = {
535c349dbc7Sjsg { "internal_clients", drm_client_debugfs_internal_clients, 0 },
536c349dbc7Sjsg };
537c349dbc7Sjsg
drm_client_debugfs_init(struct drm_minor * minor)538ad8b1aafSjsg void drm_client_debugfs_init(struct drm_minor *minor)
539c349dbc7Sjsg {
540*f005ef32Sjsg drm_debugfs_add_files(minor->dev, drm_client_debugfs_list,
541*f005ef32Sjsg ARRAY_SIZE(drm_client_debugfs_list));
542c349dbc7Sjsg }
543c349dbc7Sjsg #endif
544