drivers/gpu/drm/display/drm_dp_aux_dev.c

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

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/display/drm_dp_aux_dev.c
Extension
.c
Size
8623 bytes
Lines
355
Domain
Driver Families
Bucket
drivers/gpu
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern 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

static const struct file_operations auxdev_fops = {
	.owner		= THIS_MODULE,
	.llseek		= auxdev_llseek,
	.read_iter	= auxdev_read_iter,
	.write_iter	= auxdev_write_iter,
	.open		= auxdev_open,
	.release	= auxdev_release,
};

#define to_auxdev(d) container_of(d, struct drm_dp_aux_dev, aux)

static struct drm_dp_aux_dev *drm_dp_aux_dev_get_by_aux(struct drm_dp_aux *aux)
{
	struct drm_dp_aux_dev *iter, *aux_dev = NULL;
	int id;

	/* don't increase kref count here because this function should only be
	 * used by drm_dp_aux_unregister_devnode. Thus, it will always have at
	 * least one reference - the one that drm_dp_aux_register_devnode
	 * created
	 */
	mutex_lock(&aux_idr_mutex);
	idr_for_each_entry(&aux_idr, iter, id) {
		if (iter->aux == aux) {
			aux_dev = iter;
			break;
		}
	}
	mutex_unlock(&aux_idr_mutex);
	return aux_dev;
}

void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux)
{
	struct drm_dp_aux_dev *aux_dev;
	unsigned int minor;

	aux_dev = drm_dp_aux_dev_get_by_aux(aux);
	if (!aux_dev) /* attach must have failed */
		return;

	/*
	 * As some AUX adapters may exist as platform devices which outlive their respective DRM
	 * devices, we clear drm_dev to ensure that we never accidentally reference a stale pointer
	 */
	aux->drm_dev = NULL;

	mutex_lock(&aux_idr_mutex);
	idr_remove(&aux_idr, aux_dev->index);
	mutex_unlock(&aux_idr_mutex);

	atomic_dec(&aux_dev->usecount);
	wait_var_event(&aux_dev->usecount, !atomic_read(&aux_dev->usecount));

	minor = aux_dev->index;
	if (aux_dev->dev)
		device_destroy(drm_dp_aux_dev_class,
			       MKDEV(drm_dev_major, minor));

	DRM_DEBUG("drm_dp_aux_dev: aux [%s] unregistering\n", aux->name);
	kref_put(&aux_dev->refcount, release_drm_dp_aux_dev);
}

int drm_dp_aux_register_devnode(struct drm_dp_aux *aux)
{
	struct drm_dp_aux_dev *aux_dev;
	int res;

	aux_dev = alloc_drm_dp_aux_dev(aux);
	if (IS_ERR(aux_dev))
		return PTR_ERR(aux_dev);

	aux_dev->dev = device_create(drm_dp_aux_dev_class, aux->dev,
				     MKDEV(drm_dev_major, aux_dev->index), NULL,
				     "drm_dp_aux%d", aux_dev->index);
	if (IS_ERR(aux_dev->dev)) {
		res = PTR_ERR(aux_dev->dev);
		aux_dev->dev = NULL;
		goto error;
	}

	DRM_DEBUG("drm_dp_aux_dev: aux [%s] registered as minor %d\n",
		  aux->name, aux_dev->index);
	return 0;
error:
	drm_dp_aux_unregister_devnode(aux);
	return res;
}

int drm_dp_aux_dev_init(void)

Annotation

Implementation Notes