DRM系列九:Drm之DRM_IOCTL_MODE_ATOMIC

本系列文章基于linux 5.15
当原子模式设置都结束后,需要提交原子模式设置请求,将其配置到硬件上, 此时需要调用ioctl(fd, DRM_IOCTL_MODE_ATOMIC, &atomic)进行提交。

一、整体流程

用户层提供相应的原子模式设置,包含着各种属性和对象,然后通过ioctl(fd, DRM_IOCTL_MODE_ATOMIC, &atomic)进入kernel层,调用drm_mode_atomic_ioctl 提交的原子模式设置请求。主要步骤如下:

  • 参数验证:内核首先会验证用户空间传递的参数是否有效,包括检查对象句柄、属性 ID 等。
  • 属性更新:内核会遍历请求中的所有属性,并逐个应用到相应的 DRM 对象(如 CRTC、平面、连接器等)。
  • 提交检查:在应用属性之前,内核会进行一系列的检查,以确保新的模式设置是有效的,并且不会导致显示问题。
  • 原子提交:如果所有检查和更新都成功,内核会将这些更改原子地提交到硬件,确保显示的一致性。
  • 错误处理:如果在任何步骤中出现错误,内核会回滚所有更改,并返回相应的错误码给用户空间。

1.drm_mode_atomic_ioctl

用于处理与显示相关的原子模式设置请求。

DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATOMIC, drm_mode_atomic_ioctl, DRM_MASTER)

int drm_mode_atomic_ioctl(struct drm_device *dev,
			  void *data, struct drm_file *file_priv)
{
	struct drm_mode_atomic *arg = data;
	uint32_t __user *objs_ptr = (uint32_t __user *)(unsigned long)(arg->objs_ptr);
	uint32_t __user *count_props_ptr = (uint32_t __user *)(unsigned long)(arg->count_props_ptr);
	uint32_t __user *props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
	uint64_t __user *prop_values_ptr = (uint64_t __user *)(unsigned long)(arg->prop_values_ptr);
	unsigned int copied_objs, copied_props;
	struct drm_atomic_state *state;
	struct drm_modeset_acquire_ctx ctx;
	struct drm_out_fence_state *fence_state;
	int ret = 0;
	unsigned int i, j, num_fences;
	struct drm_printer p = drm_info_printer(dev->dev);

	/* 检查 driver_feature是否支持DRIVER_ATOMIC*/
	if (!drm_core_check_feature(dev, DRIVER_ATOMIC))
		return -EOPNOTSUPP;

	/* disallow for userspace that has not enabled atomic cap (even
	 * though this may be a bit overkill, since legacy userspace
	 * wouldn't know how to call this ioctl)
	 */
	if (!file_priv->atomic) {
		drm_dbg_atomic(dev,
			       "commit failed: atomic cap not enabled\n");
		return -EINVAL;
	}

	if (arg->flags & ~DRM_MODE_ATOMIC_FLAGS) {
		drm_dbg_atomic(dev, "commit failed: invalid flag\n");
		return -EINVAL;
	}

	if (arg->reserved) {
		drm_dbg_atomic(dev, "commit failed: reserved field set\n");
		return -EINVAL;
	}

	if (arg->flags & DRM_MODE_PAGE_FLIP_ASYNC) {
		drm_dbg_atomic(dev,
			       "commit failed: invalid flag DRM_MODE_PAGE_FLIP_ASYNC\n");
		return -EINVAL;
	}

	/* can't test and expect an event at the same time. */
	if ((arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) &&
			(arg->flags & DRM_MODE_PAGE_FLIP_EVENT)) {
		drm_dbg_atomic(dev,
			       "commit failed: page-flip event requested with test-only commit\n");
		return -EINVAL;
	}
/*用于初始化一个原子状态对象, 这里只更新了原子状态对象中crtc、plane对象的状态变化,connector对象变化不在这里*/
	state = drm_atomic_state_alloc(dev);
	if (!state)
		return -ENOMEM;

	drm_modeset_acquire_init(&ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE);
	state->acquire_ctx = &ctx;
	state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET);

retry:
	copied_objs = 0;
	copied_props = 0;
	fence_state = NULL;
	num_fences = 0;

	for (i = 0; i < arg->count_objs; i++) {
		uint32_t obj_id, count_props;
		struct drm_mode_object *obj;
	/*从用户空间安全地读取对象 ID*/
		if (get_user(obj_id, objs_ptr + copied_objs)) {
			ret = -EFAULT;
			goto out;
		}
	/*查找指定 ID 的对象*/
		obj = drm_mode_object_find(dev, file_priv, obj_id, DRM_MODE_OBJECT_ANY);
		if (!obj) {
			ret = -ENOENT;
			goto out;
		}
		if (!obj->properties) {
			drm_mode_object_put(obj);
			ret = -ENOENT;
			goto out;
		}
	/*从用户空间安全地读取当前对象的属性数量/
		if (get_user(count_props, count_props_ptr + copied_objs)) {
			drm_mode_object_put(obj);
			ret = -EFAULT;
			goto out;
		}

		copied_objs++;

		for (j = 0; j < count_props; j++) {
			uint32_t prop_id;
			uint64_t prop_value;
			struct drm_property *prop;
	/*从用户空间安全地读取当前对象属性ID*/
			if (get_user(prop_id, props_ptr + copied_props)) {
				drm_mode_object_put(obj);
				ret = -EFAULT;
				goto out;
			}
	/*查找指定 ID 的对象属性*/
			prop = drm_mode_obj_find_prop_id(obj, prop_id);
			if (!prop) {
				drm_mode_object_put(obj);
				ret = -ENOENT;
				goto out;
			}
	/*从用户空间安全地读取对象属性值*/
			if (copy_from_user(&prop_value,
					   prop_values_ptr + copied_props,
					   sizeof(prop_value))) {
				drm_mode_object_put(obj);
				ret = -EFAULT;
				goto out;
			}
	/*将属性值设置到原子状态对象中*/
			ret = drm_atomic_set_property(state, file_priv,
						      obj, prop, prop_value);
			if (ret) {
				drm_mode_object_put(obj);
				goto out;
			}

			copied_props++;
		}

		drm_mode_object_put(obj);
	}

	ret = prepare_signaling(dev, state, arg, file_priv, &fence_state,
				&num_fences);
	if (ret)
		goto out;
	/*仅测试原子操作是否可行(DRM_MODE_ATOMIC_TEST_ONLY)。
	以非阻塞方式提交原子操作(DRM_MODE_ATOMIC_NONBLOCK)。
	以阻塞方式提交原子操作(默认情况)。*/
	if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) {
		/*检查原子状态是否有效,但不会实际应用这些更改*/
		ret = drm_atomic_check_only(state);
	} else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) {
		/*调用该函数提交原子操作,但不会阻塞当前线程*/
		ret = drm_atomic_nonblocking_commit(state);
	} else {
		/*如果内核调试功能(drm_debug_enabled(DRM_UT_STATE))启用,打印原子状态的调试信息。*/
		if (drm_debug_enabled(DRM_UT_STATE))
			drm_atomic_print_new_state(state, &p);

		ret = drm_atomic_commit(state);
	}

out:
	complete_signaling(dev, state, fence_state, num_fences, !ret);

	if (ret == -EDEADLK) {
		drm_atomic_state_clear(state);
		ret = drm_modeset_backoff(&ctx);
		if (!ret)
			goto retry;
	}

	drm_atomic_state_put(state);

	drm_modeset_drop_locks(&ctx);
	drm_modeset_acquire_fini(&ctx);

	return ret;
}

1.1drm_atomic_set_property

作用是一是根据属性的类型判断是否符合属性的定义,二是根据对象的类型,获取相应的原子状态,设置属性值。

int drm_atomic_set_property(struct drm_atomic_state *state,
			    struct drm_file *file_priv,
			    struct drm_mode_object *obj,
			    struct drm_property *prop,
			    uint64_t prop_value)
{
	struct drm_mode_object *ref;
	int ret;
	/*根据属性的类型(如range、bitmask、enum等)来检查给定的值是否符合属性的定义*/
	if (!drm_property_change_valid_get(prop, prop_value, &ref))
		return -EINVAL;
	/*根据 DRM 对象的类型(CONNECTOR、CRTC、PLANE等),获取相应的原子状态,并调用特定的函数来设置属性值。*/
	switch (obj->type) {
	case DRM_MODE_OBJECT_CONNECTOR: {
		struct drm_connector *connector = obj_to_connector(obj);
		struct drm_connector_state *connector_state;
	/*根据connector->funcs->atomic_duplicate_state(厂商自定义),获取相应的原子状态,*/
		connector_state = drm_atomic_get_connector_state(state, connector);
		if (IS_ERR(connector_state)) {
			ret = PTR_ERR(connector_state);
			break;
		}
	/*设置属性值,如果是自定义property,调用connector->funcs->atomic_set_property(厂商自定义)*/
		ret = drm_atomic_connector_set_property(connector,
				connector_state, file_priv,
				prop, prop_value);
		break;
	}
	case DRM_MODE_OBJECT_CRTC: {
		struct drm_crtc *crtc = obj_to_crtc(obj);
		struct drm_crtc_state *crtc_state;
/*根据crtc->funcs->atomic_duplicate_state(厂商自定义),获取相应的原子状态,*/
		crtc_state = drm_atomic_get_crtc_state(state, crtc);
		if (IS_ERR(crtc_state)) {
			ret = PTR_ERR(crtc_state);
			break;
		}
/*设置属性值,如果是自定义property,调用crtc->funcs->atomic_set_property(厂商自定义)*/
		ret = drm_atomic_crtc_set_property(crtc,
				crtc_state, prop, prop_value);
		break;
	}
	case DRM_MODE_OBJECT_PLANE: {
		struct drm_plane *plane = obj_to_plane(obj);
		struct drm_plane_state *plane_state;
/*根据plane->funcs->atomic_duplicate_state(厂商自定义),获取相应的原子状态,*/
		plane_state = drm_atomic_get_plane_state(state, plane);
		if (IS_ERR(plane_state)) {
			ret = PTR_ERR(plane_state);
			break;
		}
/*设置属性值,如果是自定义property,调用plane->funcs->atomic_set_property(厂商自定义)*/
		ret = drm_atomic_plane_set_property(plane,
				plane_state, file_priv,
				prop, prop_value);
		break;
	}
	default:
		ret = -EINVAL;
		break;
	}
	/*作用是根据属性的类型,正确地释放对应的引用对象,以避免内存泄漏或资源未正确释放*/
	drm_property_change_valid_put(prop, ref);
	return ret;
}
1.1.1.1drm_property_change_valid_get

根据属性的类型(如range、bitmask、enum等)来检查给定的值是否符合属性的定义,并且可以选择性地返回一个引用对象(如 Blob 或其他对象)。

bool drm_property_change_valid_get(struct drm_property *property,
				   uint64_t value, struct drm_mode_object **ref)
{
	int i;

	if (property->flags & DRM_MODE_PROP_IMMUTABLE)
		return false;

	*ref = NULL;

	if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) {
		if (value < property->values[0] || value > property->values[1])
			return false;
		return true;
	} else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) {
		int64_t svalue = U642I64(value);

		if (svalue < U642I64(property->values[0]) ||
				svalue > U642I64(property->values[1]))
			return false;
		return true;
	} else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
		uint64_t valid_mask = 0;

		for (i = 0; i < property->num_values; i++)
			valid_mask |= (1ULL << property->values[i]);
		return !(value & ~valid_mask);
	} else if (drm_property_type_is(property, DRM_MODE_PROP_BLOB)) {
		struct drm_property_blob *blob;

		if (value == 0)
			return true;

		blob = drm_property_lookup_blob(property->dev, value);
		if (blob) {
			*ref = &blob->base;
			return true;
		} else {
			return false;
		}
	} else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
		/* a zero value for an object property translates to null: */
		if (value == 0)
			return true;

		*ref = __drm_mode_object_find(property->dev, NULL, value,
					      property->values[0]);
		return *ref != NULL;
	}

	for (i = 0; i < property->num_values; i++)
		if (property->values[i] == value)
			return true;
	return false;
}

1.2prepare_signaling

处理与原子操作相关的事件(如页面翻转事件)和同步原语(如 DMA 围栏)。

static int prepare_signaling(struct drm_device *dev,
				  struct drm_atomic_state *state,
				  struct drm_mode_atomic *arg,
				  struct drm_file *file_priv,
				  struct drm_out_fence_state **fence_state,
				  unsigned int *num_fences)
{
	struct drm_crtc *crtc;
	struct drm_crtc_state *crtc_state;
	struct drm_connector *conn;
	struct drm_connector_state *conn_state;
	int i, c = 0, ret;
	/*设置了 DRM_MODE_ATOMIC_TEST_ONLY 标志,表示仅测试原子操作是否可行,不实际提交*/
	if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY)
		return 0;
	/*处理 CRTC 事件和同步原语(fence)*/
	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
		s32 __user *fence_ptr;

		fence_ptr = get_out_fence_for_crtc(crtc_state->state, crtc);
	/*如果设置了 DRM_MODE_PAGE_FLIP_EVENT 标志或存在同步原语(fence)指针,则需要创建事件*/
		if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT || fence_ptr) {
			struct drm_pending_vblank_event *e;
	/*创建一个与垂直消隐(vblank)相关的事件结构体,并将其初始化为页面翻转完成事件。
	该事件可以用于通知用户空间应用程序某个 CRTC 上的页面翻转操作已经完成。*/
			e = create_vblank_event(crtc, arg->user_data);
			if (!e)
				return -ENOMEM;

			crtc_state->event = e;
		}

		if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
			struct drm_pending_vblank_event *e = crtc_state->event;

			if (!file_priv)
				continue;

			ret = drm_event_reserve_init(dev, file_priv, &e->base,
						     &e->event.base);
			if (ret) {
				kfree(e);
				crtc_state->event = NULL;
				return ret;
			}
		}

		if (fence_ptr) {
			struct dma_fence *fence;
			struct drm_out_fence_state *f;

			f = krealloc(*fence_state, sizeof(**fence_state) *
				     (*num_fences + 1), GFP_KERNEL);
			if (!f)
				return -ENOMEM;

			memset(&f[*num_fences], 0, sizeof(*f));

			f[*num_fences].out_fence_ptr = fence_ptr;
			*fence_state = f;
	/*创建一个同步原语*/
			fence = drm_crtc_create_fence(crtc);
			if (!fence)
				return -ENOMEM;
	/*设置同步原语*/
			ret = setup_out_fence(&f[(*num_fences)++], fence);
			if (ret) {
				dma_fence_put(fence);
				return ret;
			}
	/*将同步原语与 CRTC 的事件关联起来*/
			crtc_state->event->base.fence = fence;
		}

		c++;
	}
	/*处理 CRTC 事件和同步原语(fence)*/
	for_each_new_connector_in_state(state, conn, conn_state, i) {
		struct drm_writeback_connector *wb_conn;
		struct drm_out_fence_state *f;
		struct dma_fence *fence;
		s32 __user *fence_ptr;

		if (!conn_state->writeback_job)
			continue;

		fence_ptr = get_out_fence_for_connector(state, conn);
		if (!fence_ptr)
			continue;

		f = krealloc(*fence_state, sizeof(**fence_state) *
			     (*num_fences + 1), GFP_KERNEL);
		if (!f)
			return -ENOMEM;

		memset(&f[*num_fences], 0, sizeof(*f));

		f[*num_fences].out_fence_ptr = fence_ptr;
		*fence_state = f;

		wb_conn = drm_connector_to_writeback(conn);
		fence = drm_writeback_get_out_fence(wb_conn);
		if (!fence)
			return -ENOMEM;

		ret = setup_out_fence(&f[(*num_fences)++], fence);
		if (ret) {
			dma_fence_put(fence);
			return ret;
		}

		conn_state->writeback_job->out_fence = fence;
	}

	/*如果没有 CRTC 需要处理事件,但设置了 DRM_MODE_PAGE_FLIP_EVENT 标志*/
	if (c == 0 && (arg->flags & DRM_MODE_PAGE_FLIP_EVENT))
		return -EINVAL;

	return 0;
}

1.3drm_atomic_commit

用于提交原子状态对象(drm_atomic_state)并实际应用这些状态更改。在提交之前会有check,只有check之后才会正式提交,这里比较复杂,后续再讲。

int drm_atomic_commit(struct drm_atomic_state *state)
{
	struct drm_mode_config *config = &state->dev->mode_config;
	int ret;
	/*检查原子状态的有效性*/
	ret = drm_atomic_check_only(state);
	if (ret)
		return ret;

	DRM_DEBUG_ATOMIC("committing %p\n", state);
/*调用驱动程序提供的 atomic_commit 回调函数来提交原子状态。*/
	return config->funcs->atomic_commit(state->dev, state, false);
}
<think>好的,我现在需要帮助用户了解如何追踪`drm_atomic_crtc_set_property`这个用户API函数的调用流程。首先,我得确认自己对这个问题有足够的理解。用户提到这是一个提供给用户的API函数,所以应该属于DRM(Direct Rendering Manager)子系统的一部分,用于设置CRTC(阴极射线管控制器,在现代GPU中通常指显示控制器)的原子属性。 首先,我应该回忆一下DRM框架的基本结构。DRM在内核中负责处理图形渲染和显示输出,支持原子更新,允许用户空间程序通过ioctl调用来修改显示相关的属性,比如分辨率、色彩模式等。原子更新意味着所有的更改在一次操作中提交,避免中间状态导致的闪烁或不一致。 接下来,`drm_atomic_crtc_set_property`这个函数的作用可能是在原子提交过程中设置CRTC的属性。用户想知道如何追踪这个函数的调用流程,也就是从用户空间发起调用,经过内核的各个层次,直到这个函数被执行的过程。 为了追踪这个调用流程,我需要考虑以下几个方面: 1. **用户空间的API**:用户程序如何调用这个函数。通常DRM的用户空间接口是通过libdrm库提供的,而libdrm会通过ioctl系统调用与内核交互。因此,可能需要检查libdrm中相关的函数,比如`drmModeObjectSetProperty`。 2. **内核中的ioctl处理**:DRM驱动会注册一系列ioctl处理函数,对应的命令可能是`DRM_IOCTL_MODE_ATOMIC`。当用户空间发起ioctl调用时,内核的DRM子系统会解析请求,并调用相应的处理函数。 3. **原子提交流程**:在原子模式下,用户空间会准备一个原子请求(drm_mode_atomic),其中包含多个属性的更改。内核会遍历这些属性,并针对每个对象(如CRTC、Plane、Connector)调用对应的set_property函数,这里就是`drm_atomic_crtc_set_property`。 4. **属性定义和操作**:每个CRTC属性在驱动中应该有对应的定义,包括属性ID、类型以及如何设置的回调函数。`drm_atomic_crtc_set_property`可能需要根据属性ID来调用不同的处理逻辑,或者将值传递给底层的硬件驱动。 现在,我需要将这些步骤具体化,并给出用户可以用来追踪调用的方法。可能需要使用调试工具,如ftrace、printk,或者动态调试(dynamic_debug)来在内核代码中添加日志,观察函数调用的路径。另外,查看内核源码中相关函数的调用关系也是必要的。 可能的步骤包括: - **查找用户空间调用路径**:确定用户程序如何通过libdrm发起设置属性的请求,比如使用`drmModeAtomicAddProperty`函数,然后提交原子请求。 - **分析内核ioctl处理**:在内核中,`drm_mode_atomic_ioctl`函数处理用户空间的原子提交请求。该函数会解析用户传递的drm_mode_atomic结构,逐个处理每个属性更新。 - **跟踪属性处理流程**:在原子提交过程中,对于每个CRTC的属性,内核会调用`drm_atomic_crtc_set_property`函数。这个函数可能进一步调用驱动特定的回调函数,比如`atomic_set_property`。 - **使用调试工具**:在关键函数中添加printk语句,或者启用DRM的调试输出(如启用动态调试开关`CONFIG_DRM_DEBUG_SELFTEST`),或者使用ftrace来跟踪函数调用图。 另外,需要考虑到不同内核版本之间的差异,函数名或流程可能有所变化。因此,用户需要根据自己使用的内核版本来调整追踪的方法。 可能遇到的问题包括: - 如何确定用户空间的调用对应到内核的哪个ioctl? 这需要了解libdrm和内核之间的接口定义,通常libdrm的`xf86drmMode.h`中定义了相关的函数和结构体,而内核的`drm/drm_mode.h`定义了对应的ioctl命令和数据结构。 - 如何确认`drm_atomic_crtc_set_property`是否被正确调用? 在函数内部添加调试输出,或者使用kprobes来动态跟踪函数的执行。 - 如果驱动没有正确实现该函数,或者属性未正确注册,应该如何排查? 需要检查驱动代码中CRTC的初始化部分,确认属性是否通过`drm_object_attach_property`或类似函数注册,并且确认`atomic_set_property`回调是否被正确设置。 总结来说,追踪`drm_atomic_crtc_set_property`的调用流程需要结合用户空间的库函数、内核的ioctl处理、原子提交逻辑以及驱动中的具体实现。通过代码分析、调试工具和日志输出,可以逐步理清整个调用链。</think>要追踪`drm_atomic_crtc_set_property`函数的调用流程,可以按照以下步骤逐步分析: --- ### **1. 用户空间调用路径** 用户程序通过 **libdrm** 提供的接口发起属性修改请求: - **关键函数**:`drmModeAtomicAddProperty`(添加属性到原子请求)和`drmModeAtomicCommit`(提交请求)。 - **触发流程**: ```c drmModeAtomicAddProperty(atomic_req, crtc_id, property_id, value); drmModeAtomicCommit(fd, atomic_req, flags, NULL); ``` 提交后会触发`DRM_IOCTL_MODE_ATOMIC`的ioctl调用。 --- ### **2. 内核ioctl处理** 内核中处理原子提交的入口是`drm_mode_atomic_ioctl`函数: - **代码路径**:`drivers/gpu/drm/drm_atomic_uapi.c` - **关键操作**: - 解析用户传递的`drm_mode_atomic`结构。 - 遍历每个属性对象(CRTC、Plane、Connector等),调用对应的`set_property`函数。 - 对于CRTC属性,最终调用`drm_atomic_crtc_set_property`。 --- ### **3. 属性设置流程** 在`drm_atomic_crtc_set_property`中: - **代码路径**:`drivers/gpu/drm/drm_atomic.c` - **关键逻辑**: - 根据`property_id`匹配CRTC的属性列表。 - 将用户空间传递的`value`写入CRTC的原子状态(`drm_crtc_state`)。 - 可能触发驱动实现的回调(如`.atomic_set_property`)。 --- ### **4. 调试与追踪方法** #### **(1) 内核日志(printk)** 在关键函数中添加调试输出: ```c // 在drm_atomic_crtc_set_property中添加printk int drm_atomic_crtc_set_property(struct drm_crtc *crtc, struct drm_crtc_state *state, struct drm_property *property, uint64_t val) { printk(KERN_DEBUG "Setting CRTC%d property %s to %llu\n", crtc->base.id, property->name, val); // ...原有逻辑... } ``` 重新编译内核并查看`dmesg`输出。 #### **(2) 动态调试(Dynamic Debug)** 启用DRM子系统的动态调试: ```bash echo 'file drm_atomic* +p' > /sys/kernel/debug/dynamic_debug/control ``` 这会打印`drm_atomic`相关函数的调用信息。 #### **(3) Ftrace函数追踪** 使用ftrace追踪调用链: ```bash # 启用函数追踪 echo function > /sys/kernel/debug/tracing/current_tracer # 过滤DRM相关函数 echo "drm_atomic_*" > /sys/kernel/debug/tracing/set_ftrace_filter # 开始追踪 echo 1 > /sys/kernel/debug/tracing/tracing_on # 执行用户程序触发调用 cat /sys/kernel/debug/tracing/trace ``` #### **(4) 代码分析工具** 使用`cscope`或`ctags`在Linux内核源码中查找调用关系: ```bash # 在源码根目录生成索引 make cscope # 搜索drm_atomic_crtc_set_property的调用者 cscope -d -L3 drm_atomic_crtc_set_property ``` --- ### **5. 驱动实现示例** 检查驱动中CRTC属性的注册和回调: ```c // 驱动初始化时注册CRTC属性 static const struct drm_prop_enum_list prop_list[] = { {DRM_MODE_PROP_CRTC_MODE_ID, "MODE_ID"}, // ...其他属性... }; void my_crtc_init(struct drm_device *dev, struct drm_crtc *crtc) { // 创建属性 struct drm_property *prop = drm_property_create_range(dev, 0, "my_prop", 0, 100); // 将属性附加到CRTC drm_object_attach_property(&crtc->base, prop, 0); } // 实现atomic_set_property回调 static int my_crtc_atomic_set_property(struct drm_crtc *crtc, struct drm_crtc_state *state, struct drm_property *property, uint64_t val) { if (property == my_prop) { state->custom_value = val; // 保存到状态 return 0; } return -EINVAL; } ``` --- ### **常见问题排查** - **属性未生效**:检查驱动是否注册了对应属性,且`drm_atomic_crtc_set_property`是否正确处理了`property_id`。 - **内核崩溃**:确认传递的`value`范围合法,驱动回调未访问无效内存。 - **无调试输出**:检查内核配置是否启用`CONFIG_DRM_DEBUG`或动态调试未正确启用。 通过以上步骤,可以系统性地追踪`drm_atomic_crtc_set_property`的调用流程,定位问题根源。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值