查看: 1883|回复: 0

[评测分享] 【ALINX AXU2CGB试用】LED 小灯 linux 驱动源码分析

[复制链接]
  • TA的每日心情
    开心
    2024-1-16 17:48
  • 签到天数: 592 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2021-6-1 09:55:48 | 显示全部楼层 |阅读模式
    分享到:
    本帖最后由 robe.zhang 于 2021-6-1 10:02 编辑

    【ALINXAXU2CGB试用】LED 小灯 linux 驱动源码分析


    LED linux 驱动源码位于 drivers\leds目录中,跳了核心层和部分trigger代码分析以下:
    led-core.c                           #核心层
    led-class.c                           #类注册
    led-class-flash.c           # 调用核心层实现的 led flash部分,源码用的比较少
    led-triggers.c               # triger 的 api
    uleds.c                                #用户空间部分
    trigger/                               #led 触发方式
           ledtrig-heartbeat.c              # timer phase 实现的
           ledtrig-timer.c                     # software blink 实现,timer 实现
           ledtrig-pattern.c           # timer 实现,patten保存整个数组,一个接着一个执行

    看 led-core.c 文件
    EXPORT_SYMBOL_GPL(led_compose_name);          # 打印名字,其中调用了led_parse_fwnode_props函数
    led_parse_fwnode_props(dev, fwnode, &props);             # 解析设备树
    EXPORT_SYMBOL_GPL(led_sysfs_enable);
    EXPORT_SYMBOL_GPL(led_sysfs_disable);                      #开关 sysfs
    EXPORT_SYMBOL_GPL(led_get_default_pattern);            # 解析 pattern属性
    EXPORT_SYMBOL_GPL(led_update_brightness);             # 更新 brightness值
    EXPORT_SYMBOL_GPL(led_set_brightness_sync);
    EXPORT_SYMBOL_GPL(led_set_brightness_nosleep);
    EXPORT_SYMBOL_GPL(led_set_brightness_nopm);
    EXPORT_SYMBOL_GPL(led_set_brightness);                   # 各种方式设置 brightness,这里就是具体实现,先看同步开关 LED 的代码:
    设置 brightness,调用 __led_set_brightness_blocking,继续追踪:
    1.png
    __led_set_brightness_blocking 掉用了 led_cdev 的一个函数
    2.png
    看 led_cdev 结构体第 97 行,就是这个函数开关LED 小灯的,先标记为robe_1 函数,稍后能看到这个函数的具体实现
    3.png
    EXPORT_SYMBOL_GPL(led_stop_software_blink);           # 软件实现的一个 blink功能
    EXPORT_SYMBOL_GPL(led_blink_set);
    看 software_blink 实现,设置 delay_on, delay_off 两个时间,然后使用timer 实现,详细代码稍后能看到实现,此处标记robe_2 代码
    4.png
    EXPORT_SYMBOL_GPL(led_blink_set_oneshot);              # 软实现的 oneshot功能

    EXPORT_SYMBOL_GPL(led_init_core);              # 核心初始化部分,这个函数有必要看一下
    初始化了一个 work 一个 timer
    5.png
    Work 中根据flags 实现点亮或者闪灯:
    6.png
    Timer 中检查设置 flags,设置时间,设置下一次timer,一次接着一次不停的闪闪闪就是这样实现的。这也就是 robe_2 代码的具体实现之一
    7.png
    再看led-class.c 代码:
    创建了一个类,实现了 pm 电源管理,dev_groups:
    8.png
    EXPORT_SYMBOL_GPL(devm_led_classdev_unregister);
    EXPORT_SYMBOL_GPL(devm_led_classdev_register_ext);      
    EXPORT_SYMBOL_GPL(led_classdev_unregister);
    EXPORT_SYMBOL_GPL(led_classdev_register_ext);          # 注册,注销 led_classdev
    EXPORT_SYMBOL_GPL(led_classdev_resume);
    EXPORT_SYMBOL_GPL(led_classdev_suspend);
    EXPORT_SYMBOL_GPL(led_classdev_notify_brightness_hw_changed);         # 电源管理
    dev_groups
    9.png
    看一个重点函数 led_classdev_register_ext ,273行创建led_class 类的dev,313行初始化 timer 和 delay_work,316行led_trigger_set_default,注册过程就做了这三件事。led_trigger_set_default 函数记作 robe_3 代码,看完trigger 时候具体分析看他做了什么
    10.png
    11.png

    再看 led-triggers.c 代码:
    EXPORT_SYMBOL_GPL(led_trigger_unregister_simple);
    EXPORT_SYMBOL_GPL(led_trigger_register_simple);              # 注册注销
    EXPORT_SYMBOL_GPL(led_trigger_blink_oneshot);
    EXPORT_SYMBOL_GPL(led_trigger_blink);
    EXPORT_SYMBOL_GPL(led_trigger_event);                     # blink 方式,event
    EXPORT_SYMBOL_GPL(devm_led_trigger_register);
    EXPORT_SYMBOL_GPL(led_trigger_unregister);
    EXPORT_SYMBOL_GPL(led_trigger_register);                  # 注册注销
    EXPORT_SYMBOL_GPL(led_trigger_rename_static);
    EXPORT_SYMBOL_GPL(led_trigger_set_default);
    EXPORT_SYMBOL_GPL(led_trigger_remove);
    EXPORT_SYMBOL_GPL(led_trigger_set);                         # 设置 tigger 方式
    EXPORT_SYMBOL_GPL(led_trigger_show);
    EXPORT_SYMBOL_GPL(led_trigger_store);
    看 led_trigger_register,243行添加tigger,253 行遍历led_dev 找到匹配的trigger,设置trigger
    12.png
    看 trigger 是如何设置的,led有 trigger 删掉,没有添加,调用 trig->activate(led_cdev),给系统发事件。这个trig->activate(led_cdev) 记作robe_4 代码,稍后看具体实现
    13.png
    再看 led_trigger_set_default,也就是 robe_3 代码:调用了led_trigger_set,回到了上面,不在赘述
    14.png
    看 trigger\ledtrig-timer.c  源码:
    注册 timer_led_trigger,内部的 timer_trig_activate 函数就是 robe_4 代码的具体实现:
    15.png
    看这个函数:pattern 初始化,冲刷 work,设置 blink
    16.png
    调用 led_blink_setup
    17.png
    led_blink_setup 调用 led_set_software_blink实现,上面说过。
    18.png
    最后看leds-gpio.c 源码:也就是 leds-gpio 驱动:
    19.png
    Probe代码:逐个 led 解析后创建注册led_dev 设备,详细看278行的函数
    20.png
    278行函数:84行,86行,就是 brightness_set 和 brightness_set_blocking 函数,也就是robe_1 函数。一堆初始化,然后devm_led_classdev_register 注册 led_classdev,
    22.png
    注册函数层层调用,最后调用了 led_classdev_register_ext,这个函数上面说过。
    21.png
    23.png
    Trigger active 之后,led小灯就开始blink 了.

    LED小灯驱动框架和驱动全部分析完了,led 小灯的工作过程,大概就这个情况,源码分析的比较笼统,细节可能不是很精确,但是不影响理解驱动框架,理解到这个程度能称的上骨灰级用户,碰到所有 led 小灯驱动问题都可以得心应手从容应对,稍后适配板子上的四个LED小灯

    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    手机版|小黑屋|与非网

    GMT+8, 2024-4-24 12:34 , Processed in 0.113249 second(s), 17 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.