函数的目的是判断能否保证:参数state范围内的connector都能跟自己最合适的那个encoder绑定。
其判断条件如下:
1、state范围内的不同connector的最佳绑定encoder是同一个,就返回-EINVAL;
2、如果state范围内connector的最佳encoder已经被state外的connector绑定过了,那么有两种处理方式:
a、保持冲突encoder和原来connector的绑定关系,返回-EINVAL;
b、解除冲突encoder和原来connector的绑定关系
static int handle_conflicting_encoders(struct drm_atomic_state *state,
bool disable_conflicting_encoders)
{
struct drm_connector_state *new_conn_state;
struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
struct drm_encoder *encoder;
unsigned int encoder_mask = 0;
int i, ret = 0;
/*
* First loop, find all newly assigned encoders from the connectors
* part of the state. If the same encoder is assigned to multiple
* connectors bail out.
*/
for_each_new_connector_in_state(state, connector, new_conn_state, i) {
const struct drm_connector_helper_funcs *funcs = connector->helper_private;
struct drm_encoder *new_encoder;
if (!new_conn_state->crtc)
continue;
if (funcs->atomic_best_encoder)
new_encoder = funcs->atomic_best_encoder(connector,
state);
else if (funcs->best_encoder)
new_encoder = funcs->best_encoder(connector);
else
new_encoder = drm_connector_get_single_encoder(connector);
if (new_encoder) {
if (encoder_mask & drm_encoder_mask(new_encoder)) {
DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] on [CONNECTOR:%d:%s] already assigned\n",
new_encoder->base.id, new_encoder->name,
connector->base.id, connector->name);
return -EINVAL;
}
encoder_mask |= drm_encoder_mask(new_encoder);
}
}
if (!encoder_mask)
return 0;
/*
* Second loop, iterate over all connectors not part of the state.
*
* If a conflicting encoder is found and disable_conflicting_encoders
* is not set, an error is returned. Userspace can provide a solution
* through the atomic ioctl.
*
* If the flag is set conflicting connectors are removed from the CRTC
* and the CRTC is disabled if no encoder is left. This preserves
* compatibility with the legacy set_config behavior.
*/
drm_connector_list_iter_begin(state->dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {
struct drm_crtc_state *crtc_state;
if (drm_atomic_get_new_connector_state(state, connector))
continue;
encoder = connector->state->best_encoder;
if (!encoder || !(encoder_mask & drm_encoder_mask(encoder)))
continue;
if (!disable_conflicting_encoders) {
DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] in use on [CRTC:%d:%s] by [CONNECTOR:%d:%s]\n",
encoder->base.id, encoder->name,
connector->state->crtc->base.id,
connector->state->crtc->name,
connector->base.id, connector->name);
ret = -EINVAL;
goto out;
}
new_conn_state = drm_atomic_get_connector_state(state, connector);
if (IS_ERR(new_conn_state)) {
ret = PTR_ERR(new_conn_state);
goto out;
}
DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] in use on [CRTC:%d:%s], disabling [CONNECTOR:%d:%s]\n",
encoder->base.id, encoder->name,
new_conn_state->crtc->base.id, new_conn_state->crtc->name,
connector->base.id, connector->name);
crtc_state = drm_atomic_get_new_crtc_state(state, new_conn_state->crtc);
ret = drm_atomic_set_crtc_for_connector(new_conn_state, NULL);
if (ret)
goto out;
if (!crtc_state->connector_mask) {
ret = drm_atomic_set_mode_prop_for_crtc(crtc_state,
NULL);
if (ret < 0)
goto out;
crtc_state->active = false;
}
}
out:
drm_connector_list_iter_end(&conn_iter);
return ret;
}