Loading drivers/gpu/drm/Kconfig +7 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,13 @@ config DRM_DP_AUX_CHARDEV read and write values to arbitrary DPCD registers on the DP aux channel. config DRM_CLIENT_BOOTSPLASH bool "DRM Bootsplash" help Choose this option to enable DRM bootsplash. This option needs to be selected only if UEFI bootsplash is disabled. Choosing this option will render splash logo in display panel during boot up. config DRM_KMS_HELPER tristate depends on DRM Loading drivers/gpu/drm/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ drm-$(CONFIG_PCI) += ati_pcigart.o drm-$(CONFIG_DRM_PANEL) += drm_panel.o drm-$(CONFIG_OF) += drm_of.o drm-$(CONFIG_AGP) += drm_agpsupport.o drm-$(CONFIG_DRM_CLIENT_BOOTSPLASH) += drm_bootsplash.o drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \ drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \ Loading drivers/gpu/drm/drm_bootsplash.c 0 → 100644 +348 −0 Original line number Diff line number Diff line #include <linux/delay.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/mutex.h> #include <linux/slab.h> #include <linux/workqueue.h> #include <linux/notifier.h> #include <linux/keyboard.h> #include <linux/completion.h> #include <drm/drmP.h> #include <drm/drm_fb_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_modes.h> #include <drm/drm_client.h> #include "drm_internal.h" #include "drm_splash.h" static bool drm_bootsplash_enabled = true; module_param_named(bootsplash_enabled, drm_bootsplash_enabled, bool, 0664); static void drm_bootsplash_client_unregister(struct drm_client_dev *client); static int drm_bootsplash_client_hotplug(struct drm_client_dev *client); struct drm_bootsplash { struct drm_client_dev client; struct mutex lock; struct drm_client_display *display; struct drm_client_buffer *buffer[2]; struct work_struct worker; struct completion xref; bool started; bool stop; }; static void drm_bootsplash_buffer_delete(struct drm_bootsplash *splash) { unsigned int i; for (i = 0; i < 2; i++) { if (!IS_ERR_OR_NULL(splash->buffer[i])) drm_client_framebuffer_delete(splash->buffer[i]); splash->buffer[i] = NULL; } } static int drm_bootsplash_buffer_create( struct drm_bootsplash *splash, u32 width, u32 height) { unsigned int i; for (i = 0; i < 2; i++) { splash->buffer[i] = drm_client_framebuffer_create(&splash->client, width, height, SPLASH_IMAGE_FORMAT); if (IS_ERR(splash->buffer[i])) { drm_bootsplash_buffer_delete(splash); return PTR_ERR(splash->buffer[i]); } splash->buffer[i]->vaddr = drm_client_buffer_vmap(splash->buffer[i]); if (!(splash->buffer[i]->vaddr)) DRM_ERROR("drm_client_buffer_vmap fail\n"); } return 0; } static int drm_bootsplash_display_probe(struct drm_bootsplash *splash) { struct drm_client_dev *client = &splash->client; unsigned int width = 0, height = 0; unsigned int num_non_tiled = 0, i; unsigned int modeset_mask = 0; struct drm_mode_set *modeset; bool tiled = false; int ret; ret = drm_client_modeset_probe(client, 0, 0); if (ret) return ret; mutex_lock(&client->modeset_mutex); drm_client_for_each_modeset(modeset, client) { if (!modeset->mode) continue; if (modeset->connectors[0]->has_tile) tiled = true; else num_non_tiled++; } if (!tiled && !num_non_tiled) { drm_bootsplash_buffer_delete(splash); ret = -ENOENT; goto out; } /* Assume only one tiled monitor is possible */ if (tiled) { int hdisplay = 0, vdisplay = 0; i = 0; drm_client_for_each_modeset(modeset, client) { i++; if (!modeset->connectors[0]->has_tile) continue; if (!modeset->y) hdisplay += modeset->mode->hdisplay; if (!modeset->x) vdisplay += modeset->mode->vdisplay; modeset_mask |= BIT(i - 1); } width = hdisplay; height = vdisplay; goto trim; } /* The rest have one display per modeset, pick the largest */ i = 0; drm_client_for_each_modeset(modeset, client) { i++; if (!modeset->mode || modeset->connectors[0]->has_tile) continue; if (modeset->mode->hdisplay * modeset->mode->vdisplay > width * height) { width = modeset->mode->hdisplay; height = modeset->mode->vdisplay; modeset_mask = BIT(i - 1); } } trim: i = 0; drm_client_for_each_modeset(modeset, client) { unsigned int j; if (modeset_mask & BIT(i++)) continue; drm_mode_destroy(client->dev, modeset->mode); modeset->mode = NULL; for (j = 0; j < modeset->num_connectors; j++) { drm_connector_unreference(modeset->connectors[j]); modeset->connectors[j] = NULL; } modeset->num_connectors = 0; } if (!splash->buffer[0] || splash->buffer[0]->fb->width != width || splash->buffer[0]->fb->height != height) { drm_bootsplash_buffer_delete(splash); ret = drm_bootsplash_buffer_create(splash, width, height); } out: mutex_unlock(&client->modeset_mutex); return ret; } static int drm_bootsplash_display_commit_buffer( struct drm_bootsplash *splash, unsigned int num) { struct drm_client_dev *client = &splash->client; struct drm_mode_set *modeset; mutex_lock(&client->modeset_mutex); drm_client_for_each_modeset(modeset, client) { if (modeset->mode) modeset->fb = splash->buffer[num]->fb; } mutex_unlock(&client->modeset_mutex); return drm_client_modeset_commit(client); } /* Draw a box for copying the image */ static void drm_bootsplash_draw_box(struct drm_client_buffer *buffer) { unsigned int width = buffer->fb->width; unsigned int height = buffer->fb->height; unsigned int x, y, z; u32 *pix; pix = buffer->vaddr; pix += ((height / 2) - 50) * width; pix += (width / 2) - 50; z = 0; for (y = 0; y < SPLASH_IMAGE_HEIGHT; y++) { for (x = 0; x < SPLASH_IMAGE_WIDTH; x++) *pix++ = splash_bgr888_image[z++]; pix += width - SPLASH_IMAGE_WIDTH; } } static int drm_bootsplash_draw(struct drm_bootsplash *splash, unsigned int buffer_num) { if (!splash->buffer[buffer_num]) return -ENOENT; drm_bootsplash_draw_box(splash->buffer[buffer_num]); return drm_bootsplash_display_commit_buffer(splash, buffer_num); } static void drm_bootsplash_worker(struct work_struct *work) { struct drm_bootsplash *splash = container_of(work, struct drm_bootsplash, worker); struct drm_client_dev *client = &splash->client; struct drm_device *dev = client->dev; unsigned int buffer_num = 0; bool stop = false; int ret = 0, times = 0; while (!splash->stop) { mutex_lock(&splash->lock); stop = splash->stop; buffer_num = !buffer_num; ret = drm_bootsplash_draw(splash, buffer_num); mutex_unlock(&splash->lock); if (stop || ret == -ENOENT || ret == -EBUSY) break; if (times == 10) splash->stop = true; else times++; msleep(500); } if ((times == 10) && splash->stop) drm_lastclose(dev); drm_bootsplash_buffer_delete(splash); DRM_DEBUG("Bootsplash has stopped (start=%u, stop=%u, ret=%d).\n", splash->started, splash->stop, ret); complete(&splash->xref); } static int drm_bootsplash_client_hotplug(struct drm_client_dev *client) { struct drm_bootsplash *splash = container_of(client, struct drm_bootsplash, client); int ret = 0, retval; if (splash->stop) goto out_unlock; ret = drm_bootsplash_display_probe(splash); if (ret < 0) { if (splash->started && ret == -ENOENT) splash->stop = true; goto out_unlock; } if (!splash->started) { splash->started = true; reinit_completion(&splash->xref); schedule_work(&splash->worker); retval = wait_for_completion_interruptible(&splash->xref); if (retval < 0) DRM_ERROR("wait for bootsplash worker failed\n"); } out_unlock: return ret; } static const struct drm_client_funcs drm_bootsplash_client_funcs = { .owner = THIS_MODULE, .unregister = drm_bootsplash_client_unregister, .hotplug = drm_bootsplash_client_hotplug, }; static void drm_bootsplash_client_unregister(struct drm_client_dev *client) { struct drm_bootsplash *splash = container_of(client, struct drm_bootsplash, client); mutex_lock(&splash->lock); splash->stop = true; mutex_unlock(&splash->lock); flush_work(&splash->worker); drm_client_release(client); kfree(splash); } void drm_bootsplash_client_register(struct drm_device *dev) { struct drm_bootsplash *splash; int ret; if (!drm_bootsplash_enabled) return; splash = kzalloc(sizeof(*splash), GFP_KERNEL); if (!splash) return; ret = drm_client_init(dev, &splash->client, "bootsplash", &drm_bootsplash_client_funcs); if (ret) { DRM_DEV_ERROR(dev->dev, "Fail to create client, ret=%d\n", ret); kfree(splash); return; } /* For this simple example only allow the first */ drm_bootsplash_enabled = false; mutex_init(&splash->lock); INIT_WORK(&splash->worker, drm_bootsplash_worker); init_completion(&splash->xref); ret = drm_bootsplash_client_hotplug(&splash->client); if (ret) DRM_DEV_ERROR(dev->dev, "client hotplug ret=%d\n", ret); drm_client_register(&splash->client); } MODULE_DESCRIPTION("bootsplash"); drivers/gpu/drm/drm_client.c +64 −12 Original line number Diff line number Diff line Loading @@ -54,7 +54,6 @@ static void drm_client_close(struct drm_client_dev *client) drm_file_free(client->file); } EXPORT_SYMBOL(drm_client_close); /** * drm_client_init - Initialise a DRM client Loading Loading @@ -157,6 +156,13 @@ void drm_client_release(struct drm_client_dev *client) } EXPORT_SYMBOL(drm_client_release); void drm_client_dev_register(struct drm_device *dev) { #ifdef CONFIG_DRM_CLIENT_BOOTSPLASH drm_bootsplash_client_register(dev); #endif } void drm_client_dev_unregister(struct drm_device *dev) { struct drm_client_dev *client, *tmp; Loading @@ -176,6 +182,7 @@ void drm_client_dev_unregister(struct drm_device *dev) } mutex_unlock(&dev->clientlist_mutex); } EXPORT_SYMBOL(drm_client_dev_unregister); /** * drm_client_dev_hotplug - Send hotplug event to clients Loading Loading @@ -249,7 +256,6 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u struct drm_device *dev = client->dev; struct drm_client_buffer *buffer; struct drm_gem_object *obj; void *vaddr; int ret; buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); Loading @@ -276,6 +282,40 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u buffer->gem = obj; return buffer; err_delete: drm_client_buffer_delete(buffer); return ERR_PTR(ret); } /** * drm_client_buffer_vmap - Map DRM client buffer into address space * @buffer: DRM client buffer * * This function maps a client buffer into kernel address space. If the * buffer is already mapped, it returns the mapping's address. * * Client buffer mappings are not ref'counted. Each call to * drm_client_buffer_vmap() should be followed by a call to * drm_client_buffer_vunmap(); or the client buffer should be mapped * throughout its lifetime. The latter is the default. * * Returns: * The mapped memory's address */ void *drm_client_buffer_vmap(struct drm_client_buffer *buffer) { struct drm_device *dev = buffer->client->dev; void *vaddr; if (buffer->vaddr) return buffer->vaddr; if (!dev->driver->gem_prime_vmap) return ERR_PTR(-ENOTSUPP); /* * FIXME: The dependency on GEM here isn't required, we could * convert the driver handle to a dma-buf instead and use the Loading @@ -284,21 +324,33 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u * fd_install step out of the driver backend hooks, to make that * final step optional for internal users. */ vaddr = dev->driver->gem_prime_vmap(obj); if (!vaddr) { ret = -ENOMEM; goto err_delete; } vaddr = dev->driver->gem_prime_vmap(buffer->gem); if (IS_ERR(vaddr)) return vaddr; buffer->vaddr = vaddr; return buffer; err_delete: drm_client_buffer_delete(buffer); return vaddr; } EXPORT_SYMBOL(drm_client_buffer_vmap); /** * drm_client_buffer_vunmap - Unmap DRM client buffer * @buffer: DRM client buffer * * This function removes a client buffer's memory mapping. This * function is only required by clients that manage their buffers * by themselves. By default, DRM client buffers are mapped throughout * their entire lifetime. */ void drm_client_buffer_vunmap(struct drm_client_buffer *buffer) { struct drm_device *dev = buffer->client->dev; return ERR_PTR(ret); if (buffer->vaddr && dev->driver->gem_prime_vunmap) dev->driver->gem_prime_vunmap(buffer->gem, buffer->vaddr); buffer->vaddr = NULL; } EXPORT_SYMBOL(drm_client_buffer_vunmap); static void drm_client_buffer_rmfb(struct drm_client_buffer *buffer) { Loading drivers/gpu/drm/drm_connector.c +7 −11 Original line number Diff line number Diff line Loading @@ -1050,8 +1050,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, goto out_unlock; } for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) if (connector->encoder_ids[i] != 0) drm_connector_for_each_possible_encoder(connector, encoder, i) encoders_count++; if (out_resp->count_modes == 0) { Loading Loading @@ -1112,17 +1111,14 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, if ((out_resp->count_encoders >= encoders_count) && encoders_count) { copied = 0; encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr); for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { if (connector->encoder_ids[i] != 0) { if (put_user(connector->encoder_ids[i], encoder_ptr + copied)) { drm_connector_for_each_possible_encoder(connector, encoder, i) { if (put_user(encoder->base.id, encoder_ptr + copied)) { ret = -EFAULT; goto out; } copied++; } } } out_resp->count_encoders = encoders_count; out: Loading Loading
drivers/gpu/drm/Kconfig +7 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,13 @@ config DRM_DP_AUX_CHARDEV read and write values to arbitrary DPCD registers on the DP aux channel. config DRM_CLIENT_BOOTSPLASH bool "DRM Bootsplash" help Choose this option to enable DRM bootsplash. This option needs to be selected only if UEFI bootsplash is disabled. Choosing this option will render splash logo in display panel during boot up. config DRM_KMS_HELPER tristate depends on DRM Loading
drivers/gpu/drm/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ drm-$(CONFIG_PCI) += ati_pcigart.o drm-$(CONFIG_DRM_PANEL) += drm_panel.o drm-$(CONFIG_OF) += drm_of.o drm-$(CONFIG_AGP) += drm_agpsupport.o drm-$(CONFIG_DRM_CLIENT_BOOTSPLASH) += drm_bootsplash.o drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \ drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \ Loading
drivers/gpu/drm/drm_bootsplash.c 0 → 100644 +348 −0 Original line number Diff line number Diff line #include <linux/delay.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/mutex.h> #include <linux/slab.h> #include <linux/workqueue.h> #include <linux/notifier.h> #include <linux/keyboard.h> #include <linux/completion.h> #include <drm/drmP.h> #include <drm/drm_fb_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_modes.h> #include <drm/drm_client.h> #include "drm_internal.h" #include "drm_splash.h" static bool drm_bootsplash_enabled = true; module_param_named(bootsplash_enabled, drm_bootsplash_enabled, bool, 0664); static void drm_bootsplash_client_unregister(struct drm_client_dev *client); static int drm_bootsplash_client_hotplug(struct drm_client_dev *client); struct drm_bootsplash { struct drm_client_dev client; struct mutex lock; struct drm_client_display *display; struct drm_client_buffer *buffer[2]; struct work_struct worker; struct completion xref; bool started; bool stop; }; static void drm_bootsplash_buffer_delete(struct drm_bootsplash *splash) { unsigned int i; for (i = 0; i < 2; i++) { if (!IS_ERR_OR_NULL(splash->buffer[i])) drm_client_framebuffer_delete(splash->buffer[i]); splash->buffer[i] = NULL; } } static int drm_bootsplash_buffer_create( struct drm_bootsplash *splash, u32 width, u32 height) { unsigned int i; for (i = 0; i < 2; i++) { splash->buffer[i] = drm_client_framebuffer_create(&splash->client, width, height, SPLASH_IMAGE_FORMAT); if (IS_ERR(splash->buffer[i])) { drm_bootsplash_buffer_delete(splash); return PTR_ERR(splash->buffer[i]); } splash->buffer[i]->vaddr = drm_client_buffer_vmap(splash->buffer[i]); if (!(splash->buffer[i]->vaddr)) DRM_ERROR("drm_client_buffer_vmap fail\n"); } return 0; } static int drm_bootsplash_display_probe(struct drm_bootsplash *splash) { struct drm_client_dev *client = &splash->client; unsigned int width = 0, height = 0; unsigned int num_non_tiled = 0, i; unsigned int modeset_mask = 0; struct drm_mode_set *modeset; bool tiled = false; int ret; ret = drm_client_modeset_probe(client, 0, 0); if (ret) return ret; mutex_lock(&client->modeset_mutex); drm_client_for_each_modeset(modeset, client) { if (!modeset->mode) continue; if (modeset->connectors[0]->has_tile) tiled = true; else num_non_tiled++; } if (!tiled && !num_non_tiled) { drm_bootsplash_buffer_delete(splash); ret = -ENOENT; goto out; } /* Assume only one tiled monitor is possible */ if (tiled) { int hdisplay = 0, vdisplay = 0; i = 0; drm_client_for_each_modeset(modeset, client) { i++; if (!modeset->connectors[0]->has_tile) continue; if (!modeset->y) hdisplay += modeset->mode->hdisplay; if (!modeset->x) vdisplay += modeset->mode->vdisplay; modeset_mask |= BIT(i - 1); } width = hdisplay; height = vdisplay; goto trim; } /* The rest have one display per modeset, pick the largest */ i = 0; drm_client_for_each_modeset(modeset, client) { i++; if (!modeset->mode || modeset->connectors[0]->has_tile) continue; if (modeset->mode->hdisplay * modeset->mode->vdisplay > width * height) { width = modeset->mode->hdisplay; height = modeset->mode->vdisplay; modeset_mask = BIT(i - 1); } } trim: i = 0; drm_client_for_each_modeset(modeset, client) { unsigned int j; if (modeset_mask & BIT(i++)) continue; drm_mode_destroy(client->dev, modeset->mode); modeset->mode = NULL; for (j = 0; j < modeset->num_connectors; j++) { drm_connector_unreference(modeset->connectors[j]); modeset->connectors[j] = NULL; } modeset->num_connectors = 0; } if (!splash->buffer[0] || splash->buffer[0]->fb->width != width || splash->buffer[0]->fb->height != height) { drm_bootsplash_buffer_delete(splash); ret = drm_bootsplash_buffer_create(splash, width, height); } out: mutex_unlock(&client->modeset_mutex); return ret; } static int drm_bootsplash_display_commit_buffer( struct drm_bootsplash *splash, unsigned int num) { struct drm_client_dev *client = &splash->client; struct drm_mode_set *modeset; mutex_lock(&client->modeset_mutex); drm_client_for_each_modeset(modeset, client) { if (modeset->mode) modeset->fb = splash->buffer[num]->fb; } mutex_unlock(&client->modeset_mutex); return drm_client_modeset_commit(client); } /* Draw a box for copying the image */ static void drm_bootsplash_draw_box(struct drm_client_buffer *buffer) { unsigned int width = buffer->fb->width; unsigned int height = buffer->fb->height; unsigned int x, y, z; u32 *pix; pix = buffer->vaddr; pix += ((height / 2) - 50) * width; pix += (width / 2) - 50; z = 0; for (y = 0; y < SPLASH_IMAGE_HEIGHT; y++) { for (x = 0; x < SPLASH_IMAGE_WIDTH; x++) *pix++ = splash_bgr888_image[z++]; pix += width - SPLASH_IMAGE_WIDTH; } } static int drm_bootsplash_draw(struct drm_bootsplash *splash, unsigned int buffer_num) { if (!splash->buffer[buffer_num]) return -ENOENT; drm_bootsplash_draw_box(splash->buffer[buffer_num]); return drm_bootsplash_display_commit_buffer(splash, buffer_num); } static void drm_bootsplash_worker(struct work_struct *work) { struct drm_bootsplash *splash = container_of(work, struct drm_bootsplash, worker); struct drm_client_dev *client = &splash->client; struct drm_device *dev = client->dev; unsigned int buffer_num = 0; bool stop = false; int ret = 0, times = 0; while (!splash->stop) { mutex_lock(&splash->lock); stop = splash->stop; buffer_num = !buffer_num; ret = drm_bootsplash_draw(splash, buffer_num); mutex_unlock(&splash->lock); if (stop || ret == -ENOENT || ret == -EBUSY) break; if (times == 10) splash->stop = true; else times++; msleep(500); } if ((times == 10) && splash->stop) drm_lastclose(dev); drm_bootsplash_buffer_delete(splash); DRM_DEBUG("Bootsplash has stopped (start=%u, stop=%u, ret=%d).\n", splash->started, splash->stop, ret); complete(&splash->xref); } static int drm_bootsplash_client_hotplug(struct drm_client_dev *client) { struct drm_bootsplash *splash = container_of(client, struct drm_bootsplash, client); int ret = 0, retval; if (splash->stop) goto out_unlock; ret = drm_bootsplash_display_probe(splash); if (ret < 0) { if (splash->started && ret == -ENOENT) splash->stop = true; goto out_unlock; } if (!splash->started) { splash->started = true; reinit_completion(&splash->xref); schedule_work(&splash->worker); retval = wait_for_completion_interruptible(&splash->xref); if (retval < 0) DRM_ERROR("wait for bootsplash worker failed\n"); } out_unlock: return ret; } static const struct drm_client_funcs drm_bootsplash_client_funcs = { .owner = THIS_MODULE, .unregister = drm_bootsplash_client_unregister, .hotplug = drm_bootsplash_client_hotplug, }; static void drm_bootsplash_client_unregister(struct drm_client_dev *client) { struct drm_bootsplash *splash = container_of(client, struct drm_bootsplash, client); mutex_lock(&splash->lock); splash->stop = true; mutex_unlock(&splash->lock); flush_work(&splash->worker); drm_client_release(client); kfree(splash); } void drm_bootsplash_client_register(struct drm_device *dev) { struct drm_bootsplash *splash; int ret; if (!drm_bootsplash_enabled) return; splash = kzalloc(sizeof(*splash), GFP_KERNEL); if (!splash) return; ret = drm_client_init(dev, &splash->client, "bootsplash", &drm_bootsplash_client_funcs); if (ret) { DRM_DEV_ERROR(dev->dev, "Fail to create client, ret=%d\n", ret); kfree(splash); return; } /* For this simple example only allow the first */ drm_bootsplash_enabled = false; mutex_init(&splash->lock); INIT_WORK(&splash->worker, drm_bootsplash_worker); init_completion(&splash->xref); ret = drm_bootsplash_client_hotplug(&splash->client); if (ret) DRM_DEV_ERROR(dev->dev, "client hotplug ret=%d\n", ret); drm_client_register(&splash->client); } MODULE_DESCRIPTION("bootsplash");
drivers/gpu/drm/drm_client.c +64 −12 Original line number Diff line number Diff line Loading @@ -54,7 +54,6 @@ static void drm_client_close(struct drm_client_dev *client) drm_file_free(client->file); } EXPORT_SYMBOL(drm_client_close); /** * drm_client_init - Initialise a DRM client Loading Loading @@ -157,6 +156,13 @@ void drm_client_release(struct drm_client_dev *client) } EXPORT_SYMBOL(drm_client_release); void drm_client_dev_register(struct drm_device *dev) { #ifdef CONFIG_DRM_CLIENT_BOOTSPLASH drm_bootsplash_client_register(dev); #endif } void drm_client_dev_unregister(struct drm_device *dev) { struct drm_client_dev *client, *tmp; Loading @@ -176,6 +182,7 @@ void drm_client_dev_unregister(struct drm_device *dev) } mutex_unlock(&dev->clientlist_mutex); } EXPORT_SYMBOL(drm_client_dev_unregister); /** * drm_client_dev_hotplug - Send hotplug event to clients Loading Loading @@ -249,7 +256,6 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u struct drm_device *dev = client->dev; struct drm_client_buffer *buffer; struct drm_gem_object *obj; void *vaddr; int ret; buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); Loading @@ -276,6 +282,40 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u buffer->gem = obj; return buffer; err_delete: drm_client_buffer_delete(buffer); return ERR_PTR(ret); } /** * drm_client_buffer_vmap - Map DRM client buffer into address space * @buffer: DRM client buffer * * This function maps a client buffer into kernel address space. If the * buffer is already mapped, it returns the mapping's address. * * Client buffer mappings are not ref'counted. Each call to * drm_client_buffer_vmap() should be followed by a call to * drm_client_buffer_vunmap(); or the client buffer should be mapped * throughout its lifetime. The latter is the default. * * Returns: * The mapped memory's address */ void *drm_client_buffer_vmap(struct drm_client_buffer *buffer) { struct drm_device *dev = buffer->client->dev; void *vaddr; if (buffer->vaddr) return buffer->vaddr; if (!dev->driver->gem_prime_vmap) return ERR_PTR(-ENOTSUPP); /* * FIXME: The dependency on GEM here isn't required, we could * convert the driver handle to a dma-buf instead and use the Loading @@ -284,21 +324,33 @@ drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u * fd_install step out of the driver backend hooks, to make that * final step optional for internal users. */ vaddr = dev->driver->gem_prime_vmap(obj); if (!vaddr) { ret = -ENOMEM; goto err_delete; } vaddr = dev->driver->gem_prime_vmap(buffer->gem); if (IS_ERR(vaddr)) return vaddr; buffer->vaddr = vaddr; return buffer; err_delete: drm_client_buffer_delete(buffer); return vaddr; } EXPORT_SYMBOL(drm_client_buffer_vmap); /** * drm_client_buffer_vunmap - Unmap DRM client buffer * @buffer: DRM client buffer * * This function removes a client buffer's memory mapping. This * function is only required by clients that manage their buffers * by themselves. By default, DRM client buffers are mapped throughout * their entire lifetime. */ void drm_client_buffer_vunmap(struct drm_client_buffer *buffer) { struct drm_device *dev = buffer->client->dev; return ERR_PTR(ret); if (buffer->vaddr && dev->driver->gem_prime_vunmap) dev->driver->gem_prime_vunmap(buffer->gem, buffer->vaddr); buffer->vaddr = NULL; } EXPORT_SYMBOL(drm_client_buffer_vunmap); static void drm_client_buffer_rmfb(struct drm_client_buffer *buffer) { Loading
drivers/gpu/drm/drm_connector.c +7 −11 Original line number Diff line number Diff line Loading @@ -1050,8 +1050,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, goto out_unlock; } for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) if (connector->encoder_ids[i] != 0) drm_connector_for_each_possible_encoder(connector, encoder, i) encoders_count++; if (out_resp->count_modes == 0) { Loading Loading @@ -1112,17 +1111,14 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, if ((out_resp->count_encoders >= encoders_count) && encoders_count) { copied = 0; encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr); for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { if (connector->encoder_ids[i] != 0) { if (put_user(connector->encoder_ids[i], encoder_ptr + copied)) { drm_connector_for_each_possible_encoder(connector, encoder, i) { if (put_user(encoder->base.id, encoder_ptr + copied)) { ret = -EFAULT; goto out; } copied++; } } } out_resp->count_encoders = encoders_count; out: Loading