struct drm_display_mode { /** * @clock: * * Pixel clock in kHz. */ int clock; /* in kHz */ u16 hdisplay; u16 hsync_start; u16 hsync_end; u16 htotal; u16 hskew; u16 vdisplay; u16 vsync_start; u16 vsync_end; u16 vtotal; u16 vscan; /** * @flags: * * Sync and timing flags: * * - DRM_MODE_FLAG_PHSYNC: horizontal sync is active high. * - DRM_MODE_FLAG_NHSYNC: horizontal sync is active low. * - DRM_MODE_FLAG_PVSYNC: vertical sync is active high....
Posts
人眼对亮度的感知是非线性的,对暗处的变化比亮处的变化更敏感。如果图像没有进行 gamma correction,那么会分配了太多的比特来突出人类无法区分的亮点,并且分配了太少的比特显示阴影。因此需要 gamma correction 来校准,尽量做到线性化。 可以想象 video out 和 video in 之间的公式: $V_{out} = V_{in}^\gamma$ if gamma < 1, encoding gamma,称作 gamma compression。 if gamma > 1, decoding gamma,称作 gamma expansion。 蓝色为输入图像亮度变化曲线,红色为 gamma 值的曲线,紫色为最终显示的亮度变化曲线。 display gamma 即 lcd 运用的 gamma 变换,可以看出 gamma 的值在比如 0~255 色深中不是一个定值,通常需要 LUT 查找表来对某一范围内的亮度进行 gamma 变换。在 0~255 低位区域使用更小的 gamma,而高位区域使用更大的 gamma 值,gamma > 1。
# modetest --help usage: modetest [-acDdefMPpsCvrw] Query options: -c list connectors -e list encoders -f list framebuffers -p list CRTCs and planes (pipes) Test options: -P <plane_id>@<crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>] set a plane -s <connector_id>[,<connector_id>][@<crtc_id>]:[#<mode index>]<mode>[-<vrefresh>][@<format>] set a mode -C test hw cursor -v test vsynced page flipping -r set the preferred mode for all connectors -w <obj_id>:<prop_name>:<value> set property -a use atomic API -F pattern1,pattern2 specify fill patterns Generic options: -d drop master after mode set -M module use the given driver -D device use the given device
Aggregate Driver 实现结构体: struct component_master_ops { int (*bind)(struct device *master); void (*unbind)(struct device *master); }; 在 probe 函数中调用 component_match_add()来填充 component match list, 最后调用 component_master_add_with_match() register aggregate driver, remove 函数中调用 component_master_del() 来 unregister。 void component_match_add(struct device *parent, struct component_match **matchptr, int (*compare)(struct device*, void*), void *compare_data) int component_master_add_with_match(struct device *parent, const struct component_master_ops *ops, struct component_match *match) Components Driver 实现结构体: struct component_ops { int (*bind)(struct device *comp, struct device *master, void *master_data); void (*unbind)(struct device *comp, struct device *master, void *master_data); }; 在 probe 函数中调用 component_add() register component driver, remove 函数中调用 component_del() 来 ungister。...
概述 bus 模块的功能包括: bus 的注册和注销 本 bus 下有 device 或者 device_driver 注册到内核时的处理 本 bus 下有 device 或者 device_driver 从内核注销时的处理 device_drivers 的 probe 处理 管理 bus 下的所有 device 和 device_driver 数据结构 struct bus_type { const char *name; const char *dev_name; const struct attribute_group **bus_groups; const struct attribute_group **dev_groups; const struct attribute_group **drv_groups; int (*match)(struct device *dev, struct device_driver *drv); int (*uevent)(const struct device *dev, struct kobj_uevent_env *env); int (*probe)(struct device *dev); void (*sync_state)(struct device *dev); void (*remove)(struct device *dev); void (*shutdown)(struct device *dev); int (*online)(struct device *dev); int (*offline)(struct device *dev); int (*suspend)(struct device *dev, pm_message_t state); int (*resume)(struct device *dev); int (*num_vf)(struct device *dev); int (*dma_configure)(struct device *dev); void (*dma_cleanup)(struct device *dev); const struct dev_pm_ops *pm; bool need_parent_lock; }; name : bus 的名称....
struct device { struct kobject kobj; struct device *parent; struct device_private *p; const char *init_name; /* initial name of the device */ const struct device_type *type; const struct bus_type *bus; /* type of bus device is on */ struct device_driver *driver; /* which driver has allocated this device */ void *platform_data; /* Platform specific data, device core doesn't touch it */ void *driver_data; /* Driver data, set and get with dev_set_drvdata/dev_get_drvdata */ struct mutex mutex; /* mutex to synchronize calls to * its driver....
数据结构 Platform 设备是可以通过 CPU bus 直接寻址的设备, 内核在设备模型 bus, device 和 driver 的基础上, 进行了进一步封装, 抽象了 platform_bus, platform_device, platform_driver. platform 相关的实现在 include/linux/platform_device.h, drivers/base/platform.c中. struct platform_device { const char *name; int id; bool id_auto; struct device dev; u64 platform_dma_mask; struct device_dma_parameters dma_parms; u32 num_resources; struct resource *resource; const struct platform_device_id *id_entry; }; name: platform device 的名称. dev: 指向底层的 device. id: 可以手动设置, 也可设置为宏 PLATFORM_DEVID_NONE 表示没有 id, pdev->dev->name 直接设置为 pdev->name. 设置为宏 PLATFORM_DEVID_AUTO 表示自动生成 id. id_auto: 当 id 设置为 PLATFORM_DEVID_AUTO, id_auto 被置为 true, 在注册 platform_device 时可以自动生成 id....
概述 include/linux/kobject.h lib/kobject.c Kobject 是基本数据类型,每个 Kobject 都会在"/sys/“文件系统中以目录的形式出现。 Ktype 代表 Kobject 的属性操作集合 (由于通用性,多个 Kobject 可能共用同一个属性操作集,因此把 Ktype 独立出来了). Kset 是一个特殊的 Kobject(因此它也会在"/sys/“文件系统中以目录的形式出现),它用来集合相似的 Kobject(这些 Kobject 可以是相同属性的,也可以不同属性的)。 数据结构 kobject: struct kobject { const char *name; struct list_head entry; struct kobject *parent; struct kset *kset; const struct kobj_type *ktype; struct kernfs_node *sd; /* sysfs directory entry */ struct kref kref; unsigned int state_initialized:1; unsigned int state_in_sysfs:1; unsigned int state_add_uevent_sent:1; unsigned int state_remove_uevent_sent:1; unsigned int uevent_suppress:1; }; name: kobject 的名称, 也是在 sysfs 中的目录名....
kernel boot 过程,设备树初始化 reserved-memory 节点: early_init_fdt_scan_reserved_mem() fdt_scan_reserved_mem(); fdt_init_reserved_mem(); static int __init fdt_scan_reserved_mem(void) { int node, child; const void *fdt = initial_boot_params; node = fdt_path_offset(fdt, "/reserved-memory"); fdt_for_each_subnode(child, fdt, node) { const char *uname; int err; if (!of_fdt_device_is_available(fdt, child)) continue; uname = fdt_get_name(fdt, child, NULL); /// 存在 reg 属性的情况 err = __reserved_mem_reserve_reg(child, uname); /// 不存在 reg 属性的情况,存在 size 属性 if (err == -ENOENT && of_get_flat_dt_prop(child, "size", NULL)) fdt_reserved_mem_save_node(child, uname, 0, 0); } return 0; } /// 先预留 rmem 的 base 和 size 都为 0 void __init fdt_reserved_mem_save_node(unsigned long node, const char *uname, phys_addr_t base, phys_addr_t size) { struct reserved_mem *rmem = &reserved_mem[reserved_mem_count]; rmem->fdt_node = node; rmem->name = uname; rmem->base = base; rmem->size = size; reserved_mem_count++; return; } void __init fdt_init_reserved_mem(void) { int i; for (i = 0; i < reserved_mem_count; i++) { struct reserved_mem *rmem = &reserved_mem[i]; unsigned long node = rmem->fdt_node; int len; const __be32 *prop; int err = 0; bool nomap; nomap = of_get_flat_dt_prop(node, "no-map", NULL) !...