当前位置: 首页 > news >正文

Linux内核4.14版本——drm框架分析(2)——connector分析

目录

1. drm_connector结构体

1.1 struct list_head head

1.2 struct drm_mode_object base

1.3 base.properties

1.4 uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER]

1.5 struct drm_encoder *encoder

1.6 struct list_head probed_modes

1.7 struct list_head modes

1.8 const struct drm_connector_helper_funcs *helper_private

1.9 const struct drm_connector_funcs *funcs

2. connector的相关API

2.1 drm_connector_init

2.1.1 (1)拿到drm_mode_config结构体

2.1.2 (2)创建struct drm_mode_object base结构体

2.1.3 (3)得到properties,后面填充

2.1.4 (4)生成drm_mode_config的connector_ida并作为该connector的index索引

2.1.5 (5)生成该connector的type的connector_ida

2.1.6 (6)初始化一些变量

2.1.7 (7)调用drm_connector_get_cmdline_mode

2.1.8 (8)把改connector放到drm_mode_config的connector_list链表中。

2.1.9 (9)~(12)attach property

2.2 drm_mode_connector_attach_encoder

2.3 drm_connector_register

2.4 drm_connector_helper_add

2.5 drm_mode_getconnector


        本文主要分析connector的初始化和配置。

1. drm_connector结构体


/*** struct drm_connector - central DRM connector control structure* @dev: parent DRM device* @kdev: kernel device for sysfs attributes* @attr: sysfs attributes* @head: list management* @base: base KMS object* @name: human readable name, can be overwritten by the driver* @connector_type: one of the DRM_MODE_CONNECTOR_<foo> types from drm_mode.h* @connector_type_id: index into connector type enum* @interlace_allowed: can this connector handle interlaced modes?* @doublescan_allowed: can this connector handle doublescan?* @stereo_allowed: can this connector handle stereo modes?* @funcs: connector control functions* @edid_blob_ptr: DRM property containing EDID if present* @properties: property tracking for this connector* @dpms: current dpms state* @helper_private: mid-layer private data* @cmdline_mode: mode line parsed from the kernel cmdline for this connector* @force: a DRM_FORCE_<foo> state for forced mode sets* @override_edid: has the EDID been overwritten through debugfs for testing?* @encoder_ids: valid encoders for this connector* @encoder: encoder driving this connector, if any* @eld: EDID-like data, if present* @latency_present: AV delay info from ELD, if found* @video_latency: video latency info from ELD, if found* @audio_latency: audio latency info from ELD, if found* @null_edid_counter: track sinks that give us all zeros for the EDID* @bad_edid_counter: track sinks that give us an EDID with invalid checksum* @edid_corrupt: indicates whether the last read EDID was corrupt* @debugfs_entry: debugfs directory for this connector* @has_tile: is this connector connected to a tiled monitor* @tile_group: tile group for the connected monitor* @tile_is_single_monitor: whether the tile is one monitor housing* @num_h_tile: number of horizontal tiles in the tile group* @num_v_tile: number of vertical tiles in the tile group* @tile_h_loc: horizontal location of this tile* @tile_v_loc: vertical location of this tile* @tile_h_size: horizontal size of this tile.* @tile_v_size: vertical size of this tile.* @scaling_mode_property:  Optional atomic property to control the upscaling.** Each connector may be connected to one or more CRTCs, or may be clonable by* another connector if they can share a CRTC.  Each connector also has a specific* position in the broader display (referred to as a 'screen' though it could* span multiple monitors).*/
struct drm_connector {struct drm_device *dev;struct device *kdev;struct device_attribute *attr;struct list_head head;struct drm_mode_object base;char *name;/*** @mutex: Lock for general connector state, but currently only protects* @registered. Most of the connector state is still protected by* &drm_mode_config.mutex.*/struct mutex mutex;/*** @index: Compacted connector index, which matches the position inside* the mode_config.list for drivers not supporting hot-add/removing. Can* be used as an array index. It is invariant over the lifetime of the* connector.*/unsigned index;int connector_type;int connector_type_id;bool interlace_allowed;bool doublescan_allowed;bool stereo_allowed;/*** @ycbcr_420_allowed : This bool indicates if this connector is* capable of handling YCBCR 420 output. While parsing the EDID* blocks, its very helpful to know, if the source is capable of* handling YCBCR 420 outputs.*/bool ycbcr_420_allowed;/*** @registered: Is this connector exposed (registered) with userspace?* Protected by @mutex.*/bool registered;/*** @modes:* Modes available on this connector (from fill_modes() + user).* Protected by &drm_mode_config.mutex.*/struct list_head modes;/*** @status:* One of the drm_connector_status enums (connected, not, or unknown).* Protected by &drm_mode_config.mutex.*/enum drm_connector_status status;/*** @probed_modes:* These are modes added by probing with DDC or the BIOS, before* filtering is applied. Used by the probe helpers. Protected by* &drm_mode_config.mutex.*/struct list_head probed_modes;/*** @display_info: Display information is filled from EDID information* when a display is detected. For non hot-pluggable displays such as* flat panels in embedded systems, the driver should initialize the* &drm_display_info.width_mm and &drm_display_info.height_mm fields* with the physical size of the display.** Protected by &drm_mode_config.mutex.*/struct drm_display_info display_info;const struct drm_connector_funcs *funcs;struct drm_property_blob *edid_blob_ptr;struct drm_object_properties properties;struct drm_property *scaling_mode_property;/*** @path_blob_ptr:** DRM blob property data for the DP MST path property.*/struct drm_property_blob *path_blob_ptr;/*** @tile_blob_ptr:** DRM blob property data for the tile property (used mostly by DP MST).* This is meant for screens which are driven through separate display* pipelines represented by &drm_crtc, which might not be running with* genlocked clocks. For tiled panels which are genlocked, like* dual-link LVDS or dual-link DSI, the driver should try to not expose* the tiling and virtualize both &drm_crtc and &drm_plane if needed.*/struct drm_property_blob *tile_blob_ptr;/* should we poll this connector for connects and disconnects */
/* hot plug detectable */
#define DRM_CONNECTOR_POLL_HPD (1 << 0)
/* poll for connections */
#define DRM_CONNECTOR_POLL_CONNECT (1 << 1)
/* can cleanly poll for disconnections without flickering the screen */
/* DACs should rarely do this without a lot of testing */
#define DRM_CONNECTOR_POLL_DISCONNECT (1 << 2)/*** @polled:** Connector polling mode, a combination of** DRM_CONNECTOR_POLL_HPD*     The connector generates hotplug events and doesn't need to be*     periodically polled. The CONNECT and DISCONNECT flags must not*     be set together with the HPD flag.** DRM_CONNECTOR_POLL_CONNECT*     Periodically poll the connector for connection.** DRM_CONNECTOR_POLL_DISCONNECT*     Periodically poll the connector for disconnection.** Set to 0 for connectors that don't support connection status* discovery.*/uint8_t polled;/* requested DPMS state */int dpms;const struct drm_connector_helper_funcs *helper_private;/* forced on connector */struct drm_cmdline_mode cmdline_mode;enum drm_connector_force force;bool override_edid;#define DRM_CONNECTOR_MAX_ENCODER 3uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER];struct drm_encoder *encoder; /* currently active encoder */#define MAX_ELD_BYTES	128/* EDID bits */uint8_t eld[MAX_ELD_BYTES];bool latency_present[2];int video_latency[2];	/* [0]: progressive, [1]: interlaced */int audio_latency[2];int null_edid_counter; /* needed to workaround some HW bugs where we get all 0s */unsigned bad_edid_counter;/* Flag for raw EDID header corruption - used in Displayport* compliance testing - * Displayport Link CTS Core 1.2 rev1.1 4.2.2.6*/bool edid_corrupt;struct dentry *debugfs_entry;/*** @state:** Current atomic state for this connector.** This is protected by @drm_mode_config.connection_mutex. Note that* nonblocking atomic commits access the current connector state without* taking locks. Either by going through the &struct drm_atomic_state* pointers, see for_each_connector_in_state(),* for_each_oldnew_connector_in_state(),* for_each_old_connector_in_state() and* for_each_new_connector_in_state(). Or through careful ordering of* atomic commit operations as implemented in the atomic helpers, see* &struct drm_crtc_commit.*/struct drm_connector_state *state;/* DisplayID bits */bool has_tile;struct drm_tile_group *tile_group;bool tile_is_single_monitor;uint8_t num_h_tile, num_v_tile;uint8_t tile_h_loc, tile_v_loc;uint16_t tile_h_size, tile_v_size;
};

        drm_connector的主要初始化接口为drm_connector_init,可以在下面的API中看到,下面我们分析一些参数。

1.1 struct list_head head

        connecotr实例初始化完成后,通过head挂在drm_device.mode_config.connector_list上。

drm_connector_initlist_add_tail(&connector->head, &config->connector_list)config->num_connector++

        注意每个drm_device设备只有一个mode_config成员,因此可以通过mode_config.connector_list遍历出这个设备的所有connector实例,也可以通过如下方式访问。

drm_connector_list_iter_begin(dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter);// ... use connector to process
drm_connector_list_iter_end(&conn_iter);

1.2 struct drm_mode_object base

        通过__drm_mode_object_add向dev->mode_config.object_idr申请id(base.id=id, base.type=DRM_MODE_OBJECT_CONNECTOR)

drm_connector_initret=__drm_mode_object_add(dev, &connector->base,DRM_MODE_OBJECT_CONNECTOR, false, drm_connector_free);ret=idr_alloc(&dev->mode_config.object_idr, register_obj ? obj : NULL,1, 0, GFP_KERNEL);0bj->id = ret;obj->type = obj_typereturn ret;

        注意, connector->base.id会在用户态接口drmModeGetResource调用时, 作为connector_id返回给用户态,后续用户态可以通过connector_id,调用drmModeGetConnector找到drm_connector,并获取其相关参数。

        用户态获取connector_id逻辑如下:

//用户态
drmModeGetResourcesdrmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)//res.crtc_id_ptr指向设备的所有crtc_id
//内核态
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, 0)drm_mode_getresourcesdrm_connector_list_iter_begin(dev, &conn_iter);drm_for_each_connector_iter(connector, &conn_iter); //递归获取connectorput_user(connector->base.id, connector_id+count); //拷贝id到用户态drm_connector_list_iter_end(&conn_iter);

        用户态根据connector_id获取drm_connector的逻辑如下:

//用户态
drmModeGetConnector()conn.connector_id = connector_id;drmIoctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn)
//内核态
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, 0)drm_mode_getconnectorconnector = drm_connector_lookup(dev, file_priv, out_resp->connector_id)//根据用户态传进来的id, 和type(DRM_MODE_OBJECT_CONNECTOR查找drm mode obj类型)mo = drm_mode_object_find(dev, file_priv, id, DRM_MODE_OBJECT_CONNECTOR);return obj_to_connector(mo)

1.3 base.properties

        记录connector的属性(如CRTC_ID/EDID/DPMS/link-status/non-desktop/TITLE等),这些属性首先在drm_mode_create_standard_properties创建初始化并保存在dev->mode_config中,如下:

//以'CRTC_ID'属性为例
drm_mode_config_initdrmm_mode_config_initdrm_mode_create_standard_properties//创建名称为“CRTC_ID”的属性prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC, "CRTC_ID", DRM_MODE_OBJECT_CRTTC);//创建属性drm_property_create//将该property保存在mode_config的property_list链表找list_add_tail(&property->head, &dev->mode_config.property_list)//保存到mode_config.prop_crtc_id中dev->mode_config.prop_crtc_id = prop

        在drm_connector_init中会将初始化的属性attach到base.properties

drm_connector_initconnector->base.properties = &connector->propertiesdrm_object_attach_property(&connector->base,config->dpms_property)drm_object_attach_property(&connector->base,config->link_status_property)drm_object_attach_property(&connector->base, config->prop_crtc_id,0)......

properties的获取:

//用户态
drmModeObjectGetProperties//通过connector_id以及DM_MODE_OBJECT_CONNECTOR获取其所有属性drmIoctl(fd, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, &properties)
//内核态DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl,0)//根据obj_id(connector_id),和obj_type(DRM_MODE_OBJECT_CONNECTOR)获取connector的drm_mode_object实例objobj = drm_mode_object_find(dev, file_priv, arg->obj_id, arg->obj_type)//遍历connector->base.properties并拷贝到用户态,//这里仅拷贝了properties的id和value,并没有拷贝名称drm_mode_object_get_properties(obj, file_priv->atomic,arg->props_ptr, arg->prop_values_ptr, ...);//上述获取的是connector的所有属性id、value,如果要获取特定名称的属性,还需要如下操作:
//用户态
drmModeGetProperty//根据prop_id获取属性实例对象drmIoctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop) 
//内核态DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getProperty_ioctl,0)//根据prop_id获取属性实例并拷贝到用户态      

1.4 uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER]

        标识其连接的encoders,在drm设备的connector和encoder初始化结束后,调用drm_connector_attach_encoder绑定。

1.5 struct drm_encoder *encoder

         当前使用的encoder。

1.6 struct list_head probed_modes

        通过DDC或者BIOS等获取的探测出来的drm_display_mode类型实例mode,通过drm_mode_probed_add,接口添加到connector->probed_modes链表,其常用的调用有三种如下:

1. drm_add_modes_noedidmode = drm_mode_duplicate(dev, ptr);drm_mode_probed_add(connector, mode);list_add_tail(&mode->head, &connector->probed_modes);
2. drm_add_edid_modesadd_standard_modes.....
3.drm_helper_probe_add_cmdline_modemode = drm_mode_create_from_cmdline_mode(connector->dev, cmdline_mode);drm_mode_probed_add(connector,mode)

1.7 struct list_head modes

       connector有效的drm_display_mode类型实例mode链表,该链表的更新,目前仅找到一处,如下:

connector->funcs->fill_modes在drm_mode_getconnector中调用
.fill_modes = drm_helper_probe_single_connector_modes    //从probed_modes链表中的modes 添加到connector->modes链表中drm_connector_list_update

        connector->modes链表中的mode实例会在drm_mode_getconnector中拷贝到用户态,用户态根据获取的modes的宽高信息创建fb。

//用户态
drmModeGetConnector()conn.connector_id = connector_id;drmIoctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn)
//内核态
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, 0)drm_mode_getconnectorconnector = drm_connector_lookup(dev, file_priv, out_resp->connector_id)//根据用户态传进来的id, 和type(DRM_MODE_OBJECT_CONNECTOR查找drm mode obj类型)list_for_each_entry(mode, &connector->modes, head)//用户态是drm_mode_modeinfo类型对象, 内核态是drm_display_mode类型对象//这里需要做转换drm_mode_convert_to_umode(&u_mode, mode); 

1.8 const struct drm_connector_helper_funcs *helper_private

        connector->func在drm_connector_init时初始化, func都是一些标准的helper函数,其内部会最终通过connector->helper_private调用drm驱动自定的接口,以下为例(drivers\gpu\drm\bridge\synopsys\dw-hdmi.c)。

static const struct drm_connector_funcs dw_hdmi_connector_funcs = {.fill_modes = drm_helper_probe_single_connector_modes,.detect = dw_hdmi_connector_detect,.destroy = drm_connector_cleanup,.force = dw_hdmi_connector_force,.reset = drm_atomic_helper_connector_reset,.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};drm_connector_init(bridge->dev, connector, &dw_hdmi_connector_funcs,DRM_MODE_CONNECTOR_HDMIA);

1.9 const struct drm_connector_funcs *funcs

static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {.get_modes = dw_hdmi_connector_get_modes,.best_encoder = drm_atomic_helper_best_encoder,
};drm_connector_helper_add(connector, &dw_hdmi_connector_helper_funcs);

2. connector的相关API

2.1 drm_connector_init

        已下面的调用分析改函数:

	drm_connector_init(bridge->dev, connector, &dw_hdmi_connector_funcs,DRM_MODE_CONNECTOR_HDMIA);
/** Connector and encoder types.*/
static struct drm_conn_prop_enum_list drm_connector_enum_list[] = {{ DRM_MODE_CONNECTOR_Unknown, "Unknown" },{ DRM_MODE_CONNECTOR_VGA, "VGA" },{ DRM_MODE_CONNECTOR_DVII, "DVI-I" },{ DRM_MODE_CONNECTOR_DVID, "DVI-D" },{ DRM_MODE_CONNECTOR_DVIA, "DVI-A" },{ DRM_MODE_CONNECTOR_Composite, "Composite" },{ DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" },{ DRM_MODE_CONNECTOR_LVDS, "LVDS" },{ DRM_MODE_CONNECTOR_Component, "Component" },{ DRM_MODE_CONNECTOR_9PinDIN, "DIN" },{ DRM_MODE_CONNECTOR_DisplayPort, "DP" },{ DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },{ DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },{ DRM_MODE_CONNECTOR_TV, "TV" },{ DRM_MODE_CONNECTOR_eDP, "eDP" },{ DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" },{ DRM_MODE_CONNECTOR_DSI, "DSI" },{ DRM_MODE_CONNECTOR_DPI, "DPI" },
};/*** drm_connector_init - Init a preallocated connector* @dev: DRM device* @connector: the connector to init* @funcs: callbacks for this connector* @connector_type: user visible type of the connector** Initialises a preallocated connector. Connectors should be* subclassed as part of driver connector objects.** Returns:* Zero on success, error code on failure.*/
int drm_connector_init(struct drm_device *dev,struct drm_connector *connector,const struct drm_connector_funcs *funcs,int connector_type)
{struct drm_mode_config *config = &dev->mode_config;   // (1)int ret;struct ida *connector_ida =&drm_connector_enum_list[connector_type].ida;ret = __drm_mode_object_add(dev, &connector->base,    // (2)DRM_MODE_OBJECT_CONNECTOR,false, drm_connector_free);if (ret)return ret;connector->base.properties = &connector->properties;  // (3)connector->dev = dev;connector->funcs = funcs;ret = ida_simple_get(&config->connector_ida, 0, 0, GFP_KERNEL); // (4)if (ret < 0)goto out_put;connector->index = ret;ret = 0;connector->connector_type = connector_type;           // (5)           connector->connector_type_id =ida_simple_get(connector_ida, 1, 0, GFP_KERNEL);if (connector->connector_type_id < 0) {ret = connector->connector_type_id;goto out_put_id;}connector->name =                                     // (6)   kasprintf(GFP_KERNEL, "%s-%d",drm_connector_enum_list[connector_type].name,connector->connector_type_id);if (!connector->name) {ret = -ENOMEM;goto out_put_type_id;}INIT_LIST_HEAD(&connector->probed_modes);INIT_LIST_HEAD(&connector->modes);mutex_init(&connector->mutex);connector->edid_blob_ptr = NULL;connector->status = connector_status_unknown;drm_connector_get_cmdline_mode(connector);            // (7)   /* We should add connectors at the end to avoid upsetting the connector* index too much. */spin_lock_irq(&config->connector_list_lock);          // (8)list_add_tail(&connector->head, &config->connector_list);config->num_connector++;spin_unlock_irq(&config->connector_list_lock);if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL)      // (9)drm_object_attach_property(&connector->base,config->edid_property,0);drm_object_attach_property(&connector->base,          // (10)config->dpms_property, 0);drm_object_attach_property(&connector->base,          // (11)config->link_status_property,0);if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {     // (12)drm_object_attach_property(&connector->base, config->prop_crtc_id, 0);}connector->debugfs_entry = NULL;
out_put_type_id:if (ret)ida_simple_remove(connector_ida, connector->connector_type_id);
out_put_id:if (ret)ida_simple_remove(&config->connector_ida, connector->index);
out_put:if (ret)drm_mode_object_unregister(dev, &connector->base);return ret;
}

2.1.1 (1)拿到drm_mode_config结构体

	struct drm_mode_config *config = &dev->mode_config;   // (1)int ret;struct ida *connector_ida =&drm_connector_enum_list[connector_type].ida;

      (1.1)一个drm设备只有一个struct drm_mode_config结构体,里面配置了一些参数,后面会讲。

      (1.2)拿到struct ida *connector_ida,后面会分配。

2.1.2 (2)创建struct drm_mode_object base结构体

	ret = __drm_mode_object_add(dev, &connector->base,    // (2)DRM_MODE_OBJECT_CONNECTOR,false, drm_connector_free);

      (2.1)生成一个类型为DRM_MODE_OBJECT_CONNECTOR的struct drm_mode_object结构体,这个在1.2节中已经提到过。

2.1.3 (3)得到properties,后面填充

	connector->base.properties = &connector->properties;  // (3)connector->dev = dev;connector->funcs = funcs;

2.1.4 (4)生成drm_mode_config的connector_ida并作为该connector的index索引

	ret = ida_simple_get(&config->connector_ida, 0, 0, GFP_KERNEL); // (4)if (ret < 0)goto out_put;connector->index = ret;ret = 0;

2.1.5 (5)生成该connector的type的connector_ida

	connector->connector_type = connector_type;           // (5)           connector->connector_type_id =ida_simple_get(connector_ida, 1, 0, GFP_KERNEL);if (connector->connector_type_id < 0) {ret = connector->connector_type_id;goto out_put_id;}

       生成该connector的type的connector_ida,后面该connector命名会用到。

2.1.6 (6)初始化一些变量

	connector->name =                                     // (6)   kasprintf(GFP_KERNEL, "%s-%d",drm_connector_enum_list[connector_type].name,connector->connector_type_id);if (!connector->name) {ret = -ENOMEM;goto out_put_type_id;}INIT_LIST_HEAD(&connector->probed_modes);INIT_LIST_HEAD(&connector->modes);mutex_init(&connector->mutex);connector->edid_blob_ptr = NULL;connector->status = connector_status_unknown;

2.1.7 (7)调用drm_connector_get_cmdline_mode

	drm_connector_get_cmdline_mode(connector);            // (7)   

2.1.8 (8)把改connector放到drm_mode_config的connector_list链表中。

	spin_lock_irq(&config->connector_list_lock);          // (8)list_add_tail(&connector->head, &config->connector_list);config->num_connector++;spin_unlock_irq(&config->connector_list_lock);

2.1.9 (9)~(12)attach property

	if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL)      // (9)drm_object_attach_property(&connector->base,config->edid_property,0);drm_object_attach_property(&connector->base,          // (10)config->dpms_property, 0);drm_object_attach_property(&connector->base,          // (11)config->link_status_property,0);if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {     // (12)drm_object_attach_property(&connector->base, config->prop_crtc_id, 0);

2.2 drm_mode_connector_attach_encoder

/*** drm_mode_connector_attach_encoder - attach a connector to an encoder* @connector: connector to attach* @encoder: encoder to attach @connector to** This function links up a connector to an encoder. Note that the routing* restrictions between encoders and crtcs are exposed to userspace through the* possible_clones and possible_crtcs bitmasks.** Returns:* Zero on success, negative errno on failure.*/
int drm_mode_connector_attach_encoder(struct drm_connector *connector,struct drm_encoder *encoder)
{int i;/** In the past, drivers have attempted to model the static association* of connector to encoder in simple connector/encoder devices using a* direct assignment of connector->encoder = encoder. This connection* is a logical one and the responsibility of the core, so drivers are* expected not to mess with this.** Note that the error return should've been enough here, but a large* majority of drivers ignores the return value, so add in a big WARN* to get people's attention.*/if (WARN_ON(connector->encoder))return -EINVAL;for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {if (connector->encoder_ids[i] == 0) {connector->encoder_ids[i] = encoder->base.id;return 0;}}return -ENOMEM;
}

      该connector attach一个encoder。

2.3 drm_connector_register

/*** drm_connector_register - register a connector* @connector: the connector to register** Register userspace interfaces for a connector** Returns:* Zero on success, error code on failure.*/
int drm_connector_register(struct drm_connector *connector)
{int ret = 0;if (!connector->dev->registered)return 0;mutex_lock(&connector->mutex);if (connector->registered)goto unlock;ret = drm_sysfs_connector_add(connector);if (ret)goto unlock;ret = drm_debugfs_connector_add(connector);if (ret) {goto err_sysfs;}if (connector->funcs->late_register) {ret = connector->funcs->late_register(connector);if (ret)goto err_debugfs;}drm_mode_object_register(connector->dev, &connector->base);connector->registered = true;goto unlock;err_debugfs:drm_debugfs_connector_remove(connector);
err_sysfs:drm_sysfs_connector_remove(connector);
unlock:mutex_unlock(&connector->mutex);return ret;
}

2.4 drm_connector_helper_add

/*** drm_connector_helper_add - sets the helper vtable for a connector* @connector: DRM connector* @funcs: helper vtable to set for @connector*/
static inline void drm_connector_helper_add(struct drm_connector *connector,const struct drm_connector_helper_funcs *funcs)
{connector->helper_private = funcs;
}

2.5 drm_mode_getconnector

int drm_mode_getconnector(struct drm_device *dev, void *data,struct drm_file *file_priv)
{struct drm_mode_get_connector *out_resp = data;struct drm_connector *connector;struct drm_encoder *encoder;struct drm_display_mode *mode;int mode_count = 0;int encoders_count = 0;int ret = 0;int copied = 0;int i;struct drm_mode_modeinfo u_mode;struct drm_mode_modeinfo __user *mode_ptr;uint32_t __user *encoder_ptr;if (!drm_core_check_feature(dev, DRIVER_MODESET))return -EINVAL;memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo));connector = drm_connector_lookup(dev, out_resp->connector_id);     // (1)if (!connector)return -ENOENT;for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++)                    // (2)if (connector->encoder_ids[i] != 0)encoders_count++;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],               // (3)encoder_ptr + copied)) {ret = -EFAULT;goto out;}copied++;}}}out_resp->count_encoders = encoders_count;                       // (4)out_resp->connector_id = connector->base.id;out_resp->connector_type = connector->connector_type;out_resp->connector_type_id = connector->connector_type_id;mutex_lock(&dev->mode_config.mutex);if (out_resp->count_modes == 0) {connector->funcs->fill_modes(connector,dev->mode_config.max_width,dev->mode_config.max_height);}out_resp->mm_width = connector->display_info.width_mm;          // (5)out_resp->mm_height = connector->display_info.height_mm;out_resp->subpixel = connector->display_info.subpixel_order;out_resp->connection = connector->status;/* delayed so we get modes regardless of pre-fill_modes state */list_for_each_entry(mode, &connector->modes, head)if (drm_mode_expose_to_userspace(mode, file_priv))mode_count++;/** This ioctl is called twice, once to determine how much space is* needed, and the 2nd time to fill it.*/if ((out_resp->count_modes >= mode_count) && mode_count) {    // (6)copied = 0;mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr;list_for_each_entry(mode, &connector->modes, head) {if (!drm_mode_expose_to_userspace(mode, file_priv))continue;drm_mode_convert_to_umode(&u_mode, mode);if (copy_to_user(mode_ptr + copied,&u_mode, sizeof(u_mode))) {ret = -EFAULT;mutex_unlock(&dev->mode_config.mutex);goto out;}copied++;}}out_resp->count_modes = mode_count;mutex_unlock(&dev->mode_config.mutex);drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);encoder = drm_connector_get_encoder(connector);            // (7)if (encoder)out_resp->encoder_id = encoder->base.id;elseout_resp->encoder_id = 0;/* Only grab properties after probing, to make sure EDID and other* properties reflect the latest status. */              // (8)ret = drm_mode_object_get_properties(&connector->base, file_priv->atomic,(uint32_t __user *)(unsigned long)(out_resp->props_ptr),(uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr),&out_resp->count_props);drm_modeset_unlock(&dev->mode_config.connection_mutex);out:drm_connector_put(connector);return ret;
}

该函数一般用户态使用ioctl调用。

//用户态
drmModeGetConnector()conn.connector_id = connector_id;drmIoctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn)
//内核态
DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, 0)drm_mode_getconnector

        (1)通过out_resp->connector_id找到需要的connector。

        (2)计算该connector支持多少个encoder。

        (3)把该connector支持的encoder拷贝到用户态。

        (4~5)赋值一些用户态结构体一些变量

        (6)mode暂时不知道干啥的

        (7)得到该connector目前正在使用的encoder。

        (8)得到properties。

相关文章:

Linux内核4.14版本——drm框架分析(2)——connector分析

目录 1. drm_connector结构体 1.1 struct list_head head 1.2 struct drm_mode_object base 1.3 base.properties 1.4 uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER] 1.5 struct drm_encoder *encoder 1.6 struct list_head probed_modes 1.7 struct list_head mod…...

dev GridControl 按条件纵向合并单元格

dev GridControl 按条件纵向合并单元格 gridView5.OptionsView.AllowCellMerge true; gridView5.CellMerge gridView5_CellMerge; //自定义合并单元格监听事件void gridView5_CellMerge(object sender, DevExpress.XtraGrid.Views.Grid.CellMergeEventArgs e){int rowHandle1…...

aws eks 集群初始化过程中pause容器的启动逻辑

eks集群默认策略在磁盘使用量达到threshold时会清除镜像&#xff0c;其中pause镜像也可能会被清除 https://aws.amazon.com/cn/premiumsupport/knowledge-center/eks-worker-nodes-image-cache/ pause容器能够为pod创建初始的名称空间&#xff0c;pod的内的容器共享其中的网络空…...

Numpy专栏目录(长期更新)

文章目录数组基础文件与字符串多项式分布Numpy绝对可以说是支撑Python地位的最重要的包了&#xff0c;几乎所有能叫出名的Python计算库&#xff0c;都不可避免地调用了Numpy&#xff0c;Numpy官网也列出了一些&#xff0c;大致如下图这样&#xff0c;堪称科学计算领域的瑞士军刀…...

English Learning - L2 第1次小组纠音 [ɑː] [ɔː] [uː] 2023.2.25 周六

English Learning - L2 第1次小组纠音 [ɑː] [ɔː] [uː] 2023.2.25 周六共性问题分析大后元音 [ɑː]大后元音 [ɔː]后元音 [uː]我的发音问题后元音 [uː]大后元音 [ɑː] 和 [ɔː]纠音过程第一次第二次第三次共性问题分析 大后元音 [ɑː] 嘴唇过于松散&#xff0c;没…...

博客系统程序(页面设计)

咱们学习javaEE的目的就是完成一个网站.在当前学习的基础上,已经可以完成我们的博客系统的页面的设计了!!!首先我们要进行统筹规划:首先我们的博客页面将会有4个页面:1.博客列表页2.博客详情页显示一个博客的具体内容:3.登录页就是用户输入用户名和页面的地方4.博客编辑页发布新…...

【死锁的排查工具有哪些?】

死锁是指两个或多个进程&#xff08;线程&#xff09;相互等待对方持有的资源&#xff0c;导致无法继续执行的情况。在并发编程中&#xff0c;死锁是一个常见的问题&#xff0c;需要使用专门的工具来进行排查和解决。 以下是常用的死锁排查工具&#xff1a; jstack&#xff1a…...

JUC包:CyclicBarrier源码+实例讲解

1 缘起 上篇文章讲到了CountDownLatch&#xff1a;https://blog.csdn.net/Xin_101/article/details/129116170 作为同系的佼佼者&#xff0c;不得不提CyclicBarrier&#xff0c; 设计理念相似&#xff0c;都是多线程等待&#xff0c;但是&#xff0c;应用的技术以及功能不同&a…...

Trace、Metrics、Logging 选型

背景分布式追踪的起源自从微服务的兴起开始&#xff0c;整个系统架构开始变得极为庞大和复杂&#xff0c;但是服务之间的调用关系&#xff0c;调用消耗时间等等信息却依然是半黑盒的状态。为了能够将调用的链路进行串联&#xff0c;将系统的各种指标数据展示出来以使得系统的链…...

Java验证码

文章目录一、验证码概述二、Java原生验证码1、随机数字验证码2、随机数字和字母验证码3、运算验证码三、引入三方验证码一、验证码概述 验证码&#xff08;CAPTCHA&#xff09;是“Completely Automated Public Turing test to tell Computers and Humans Apart”&#xff08;全…...

5天带你读完《Effective Java》(四)

《Effective Java》是Java开发领域无可争议的经典之作&#xff0c;连Java之父James Gosling都说&#xff1a; “如果说我需要一本Java编程的书&#xff0c;那就是它了”。它为Java程序员提供了90个富有价值的编程准则&#xff0c;适合对Java开发有一定经验想要继续深入的程序员…...

探索密码学的未来:SM1、SM2、SM3、SM4、同态加密、密态计算、隐私计算和安全多方计算

密码算法在现代通信与信息安全中发挥着至关重要的作用&#xff0c;SM1、SM2、SM3、SM4、同态加密、密态计算、隐私计算和安全多方计算等密码算法被广泛应用于各种信息安全领域。本篇博客将会为大家介绍这些密码算法&#xff0c;以及它们在信息安全中的作用和应用。 一、SM1、SM…...

【教程】去水印开源工具Lama Cleaner在Windows的安装和使用

一、Lama Cleaner是什么&#xff1f; Lama Cleaner是一款开源且免费的人工学习图片去水印程序&#xff08;个人主要学习用途&#xff09;&#xff0c;没有图片分辨率限制&#xff08;个人使用暂未发现&#xff09;&#xff0c;并且保存的图片质量很高&#xff08;个人觉得跟原…...

驾考笔记_2023

科目一1> 扣分制度1.1> 超速1.2> 超载1.3> 车牌1.4> 速记口诀2> 满分学习2.1> 消分学习2.2> 满分重考&#xff1b;3> 罚款 / 判刑3.1> 考证3.2> 审验教育3.3> 酒驾3.4> 200&#xffe5;3.5> 500&#xffe5;3.6> 2000&#xffe5…...

【架构师】跟我一起学架构——调用链

博客昵称&#xff1a;架构师Cool 最喜欢的座右铭&#xff1a;一以贯之的努力&#xff0c;不得懈怠的人生。 作者简介&#xff1a;一名Coder&#xff0c;软件设计师/鸿蒙高级工程师认证&#xff0c;在备战高级架构师/系统分析师&#xff0c;欢迎关注小弟&#xff01; 博主小留言…...

[神经网络]Swin Transformer网络

一、概述 Swin Transformer是一个用了移动窗口的层级式Vision Transformer。 在图像领域&#xff0c;Transformer需要解决如下两个问题&#xff1a; ①尺度问题&#xff1a;同一语义的物体在图像中有不一样的尺度。(大小不同) ②Resolution过大&#xff1a;若以像素点作为单位&…...

【分布式】什么是分布式,分布式和集群的区别又是什么?答案在正文。

文章目录1. 什么是分布式 ?2. 分布式与集群的区别 ?3.用一个请求串起来4.一个简化的架构图5.分布式环境的特点6.分布式环境下面临的问题7.总结1. 什么是分布式 ? 分布式系统一定是由多个节点组成的系统。 其中&#xff0c;节点指的是计算机服务器&#xff0c;而且这些节点一…...

MyBatis框架的入门案例

MyBatis框架的入门案例 资源地址&#xff1a;https://download.csdn.net/download/weixin_41957626/87531373 1.MyBatis的配置 环境&#xff1a;基于maven的结构 1.1目录结构 1.2依赖包 <dependencies><!--mybatis--><dependency><groupId>org.mybatis…...

红黑树-随记

文章目录1.为什么hashmap用红黑树不用二叉树和平衡二叉树1.1 二叉树&#xff08;Binary Search Tree&#xff09;1.2 红黑树&#xff08;Red Black Tree&#xff09;1.3 平衡二叉树&#xff08;Balence Binary Tree&#xff09;也称AVT2.为什么mysql用b数&#xff0c;不用B数或…...

Python异常处理更新,正常和不正常的都在这里

嗨害大家好鸭&#xff01;我是小熊猫~ 异常处理篇嗨害大家好鸭&#xff01;我是小熊猫~Python标准异常&#x1f4a8;什么是异常&#xff1f;不正常异常处理&#x1f4a8;使用except而不带任何异常类型使用except而带多种异常类型try-finally 语句异常的参数触发异常用户自定义异…...

[数据结构]:10-二叉排序树(无头结点)(C语言实现)

目录 前言 已完成内容 二叉排序树实现 01-开发环境 02-文件布局 03-代码 01-主函数 02-头文件 03-BinarySearchTreeCommon.cpp 04-BinarySearchTreeFunction.cpp 结语 前言 此专栏包含408考研数据结构全部内容&#xff0c;除其中使用到C引用外&#xff0c;全为C语言…...

openstack浅析

** OpenStack是一个由多个组件组成的开源云计算平台&#xff0c;每个组件都有不同的功能和用途。 ** 组件构成 以下是OpenStack中一些常见的组件及其功能&#xff1a; Nova&#xff1a;用于管理虚拟机的组件&#xff0c;提供了虚拟机的创建、销毁、管理等功能。 Neutron&am…...

华为OD机试Golang解题 - 特异性双端队列 | 含思路

华为Od必看系列 华为OD机试 全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典文章目录 华为Od必看系列使用说明本期题目…...

代码随想录中:回溯算法的基础

回溯算法是一种暴力的搜索方式&#xff1b;回溯法一般与递归同时存在。 回溯法&#xff0c;一般可以解决如下几种问题&#xff1a; 组合问题&#xff1a;N个数里面按一定规则找出k个数的集合切割问题&#xff1a;一个字符串按一定规则有几种切割方式子集问题&#xff1a;一个…...

Android kotlin 系列讲解(进阶篇)Jetpack系列之LiveData

<<返回总目录 文章目录 一、LiveData是什么二、LiveData测试一、LiveData是什么 LiveData是Jetpack提供的一种响应式编程组件,它可以包括任何类型的数据,并在数据发生变化的时候通知给观察者。LiveData特别适合与ViewModel结合在一起使用,虽然它也可以单独在别的地方…...

如何判断有向无环图:构造有向无环图

拓扑序列&#xff1a;可以用来判断一个有向图是否有环&#xff01; 拓扑排序可以判断有向图是否存在环。我们可以对任意有向图执行上述过程&#xff0c;在完成后检查A序列的长度。 若A序列的长度小于图中点的数量&#xff0c;则说明某些节点未被遍历&#xff0c;进而说明图中存…...

【2022.1.3】手脱压缩壳练习(含练习exe)

【2022.1.3】手脱压缩壳练习&#xff08;含练习exe&#xff09; 文章目录【2022.1.3】手脱压缩壳练习&#xff08;含练习exe&#xff09;0、简介1、单步跟踪法&#xff08;#&#xff09;方法介绍&#xff08;0&#xff09;练习exe下载&#xff08;1&#xff09;、查看源程序&am…...

【异或哈希】CF855 div3 F

感觉这道题跟之前有一题特别像&#xff0c;都是异或哈希感觉这种题应该很典&#xff0c;记录一下(66条消息) Codeforces Round #841 (Div. 2) and Divide by Zero【异或差分动态map维护】 2022 C. Even Subarrays_lamentropetion的博客-CSDN博客Problem - F - Codeforces题意&a…...

深度学习|改进两阶段鲁棒优化算法i-ccg

目录 1 主要内容 2 改进算法 2.1 CC&G算法的优势 2.2 i-CCG算法简介 3 结果对比 1 主要内容 自从2013年的求解两阶段鲁棒优化模型的列和约束生成算法&#xff08;CC&G&#xff09;被提出之后&#xff0c;基本没有实质性的创新&#xff0c;都是围绕该算法在各个领…...

C++11轻松打印本地时间

C11之前&#xff0c;想要获取时间并对其打印是有些困难的&#xff0c;因为C并没有标准时间库。想要对时间进行统计就需要调用C库&#xff0c;并且我们要考虑这样的调用是否能很好的封装到我们的类中。 C11之后&#xff0c;STL提供了 chrono 库&#xff0c;其让对时间的操作更加…...