drivers/gpu/drm/drm_framebuffer.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/drm_framebuffer.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/drm_framebuffer.c
Extension
.c
Size
34616 bytes
Lines
1239
Domain
Driver Families
Bucket
drivers/gpu
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct drm_mode_rmfb_work {
	struct work_struct work;
	struct list_head fbs;
};

static void drm_mode_rmfb_work_fn(struct work_struct *w)
{
	struct drm_mode_rmfb_work *arg = container_of(w, typeof(*arg), work);

	while (!list_empty(&arg->fbs)) {
		struct drm_framebuffer *fb =
			list_first_entry(&arg->fbs, typeof(*fb), filp_head);

		drm_dbg_kms(fb->dev,
			    "Removing [FB:%d] from all active usage due to RMFB ioctl\n",
			    fb->base.id);
		list_del_init(&fb->filp_head);
		drm_framebuffer_remove(fb);
	}
}

static int drm_mode_closefb(struct drm_framebuffer *fb,
			    struct drm_file *file_priv)
{
	struct drm_framebuffer *fbl;
	bool found = false;

	mutex_lock(&file_priv->fbs_lock);
	list_for_each_entry(fbl, &file_priv->fbs, filp_head)
		if (fb == fbl)
			found = true;

	if (!found) {
		mutex_unlock(&file_priv->fbs_lock);
		return -ENOENT;
	}

	list_del_init(&fb->filp_head);
	mutex_unlock(&file_priv->fbs_lock);

	/* Drop the reference that was stored in the fbs list */
	drm_framebuffer_put(fb);

	return 0;
}

/**
 * drm_mode_rmfb - remove an FB from the configuration
 * @dev: drm device
 * @fb_id: id of framebuffer to remove
 * @file_priv: drm file
 *
 * Remove the specified FB.
 *
 * Called by the user via ioctl, or by an in-kernel client.
 *
 * Returns:
 * Zero on success, negative errno on failure.
 */
int drm_mode_rmfb(struct drm_device *dev, u32 fb_id,
		  struct drm_file *file_priv)
{
	struct drm_framebuffer *fb;
	int ret;

	if (!drm_core_check_feature(dev, DRIVER_MODESET))
		return -EOPNOTSUPP;

	fb = drm_framebuffer_lookup(dev, file_priv, fb_id);
	if (!fb)
		return -ENOENT;

	ret = drm_mode_closefb(fb, file_priv);
	if (ret != 0) {
		drm_framebuffer_put(fb);
		return ret;
	}

	/*
	 * drm_framebuffer_remove may fail with -EINTR on pending signals,
	 * so run this in a separate stack as there's no way to correctly
	 * handle this after the fb is already removed from the lookup table.
	 */
	if (drm_framebuffer_read_refcount(fb) > 1) {
		struct drm_mode_rmfb_work arg;

		INIT_WORK_ONSTACK(&arg.work, drm_mode_rmfb_work_fn);
		INIT_LIST_HEAD(&arg.fbs);
		drm_WARN_ON(dev, !list_empty(&fb->filp_head));
		list_add_tail(&fb->filp_head, &arg.fbs);

Annotation

Implementation Notes