Linux内核之LED子系统(二)

LEDs

379人已加入

描述

这里说一说LED子系统的一些核心源代码文件,是如何实现LED子系统。

LINUX内核

这里重点关注内核部分的实现:

对于内核中需要重点关注的几个文件如下:

driver/leds/led-class.c
driver/leds/led-core.c
driver/leds/led-triggers.c
include/linux/leds.h

1. LED设备管理

driver/leds/led-class.c

LED设备的注册和注销实现都在该函数,这里看看里面的重要结构体

struct led_classdev {
        const char              *name;
        enum led_brightness      brightness;
        enum led_brightness      max_brightness;
        int                      flags;


        /* Lower 16 bits reflect status */
#define LED_SUSPENDED           BIT(0)
#define LED_UNREGISTERING       BIT(1)
        /* Upper 16 bits reflect control information */
#define LED_CORE_SUSPENDRESUME  BIT(16)
#define LED_SYSFS_DISABLE       BIT(17)
#define LED_DEV_CAP_FLASH       BIT(18)
#define LED_HW_PLUGGABLE        BIT(19)
#define LED_PANIC_INDICATOR     BIT(20)
#define LED_BRIGHT_HW_CHANGED   BIT(21)
#define LED_RETAIN_AT_SHUTDOWN  BIT(22)
#define LED_INIT_DEFAULT_TRIGGER BIT(23)


        /* set_brightness_work / blink_timer flags, atomic, private. */
        unsigned long           work_flags;


#define LED_BLINK_SW                    0
#define LED_BLINK_ONESHOT               1
#define LED_BLINK_ONESHOT_STOP          2
#define LED_BLINK_INVERT                3
#define LED_BLINK_BRIGHTNESS_CHANGE     4
#define LED_BLINK_DISABLE               5


        /* Set LED brightness level
         * Must not sleep. Use brightness_set_blocking for drivers
         * that can sleep while setting brightness.
         */
        void            (*brightness_set)(struct led_classdev *led_cdev,
                                          enum led_brightness brightness);
        /*
         * Set LED brightness level immediately - it can block the caller for
         * the time required for accessing a LED device register.
         */
        int (*brightness_set_blocking)(struct led_classdev *led_cdev,
                                       enum led_brightness brightness);
        /* Get LED brightness level */
        enum led_brightness (*brightness_get)(struct led_classdev *led_cdev);


        /*
         * Activate hardware accelerated blink, delays are in milliseconds
         * and if both are zero then a sensible default should be chosen.


         * and if both are zero then a sensible default should be chosen.
         * The call should adjust the timings in that case and if it can't
         * match the values specified exactly.
         * Deactivate blinking again when the brightness is set to LED_OFF
         * via the brightness_set() callback.
         */
        int             (*blink_set)(struct led_classdev *led_cdev,
                                     unsigned long *delay_on,
                                     unsigned long *delay_off);


        int (*pattern_set)(struct led_classdev *led_cdev,
                           struct led_pattern *pattern, u32 len, int repeat);
        int (*pattern_clear)(struct led_classdev *led_cdev);


        struct device           *dev;
        const struct attribute_group    **groups;


        struct list_head         node;                  /* LED Device list */
        const char              *default_trigger;       /* Trigger to use */


        unsigned long            blink_delay_on, blink_delay_off;
        struct timer_list        blink_timer;
        int                      blink_brightness;
        int                      new_blink_brightness;
        void                    (*flash_resume)(struct led_classdev *led_cdev);


        struct work_struct      set_brightness_work;
        int                     delayed_set_value;


#ifdef CONFIG_LEDS_TRIGGERS
        /* Protects the trigger data below */
        struct rw_semaphore      trigger_lock;


        struct led_trigger      *trigger;
        struct list_head         trig_list;
        void                    *trigger_data;
        /* true if activated - deactivate routine uses it to do cleanup */
        bool                    activated;


        /* LEDs that have private triggers have this set */
        struct led_hw_trigger_type      *trigger_type;
#endif


#ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED
        int                      brightness_hw_changed;
        struct kernfs_node      *brightness_hw_changed_kn;
#endif


        /* Ensures consistent access to the LED Flash Class device */
        struct mutex            led_access;
};

从结构里面可以看到已经定义了LED设备的属性和操作函数,包括设备的名称,LED的亮度,max 等,设置与获取亮度函数;

重要字段:

  • name:设备名称,用于在/sys/class/leds/目录下创建设备子目录。
  • brightness:表示LED设备的亮度,可以通过读写
    /sys/class/leds//brightness文件进行控制。
  • max_brightness:LED设备的最大亮度值。
  • trigger:表示LED设备当前的触发器名称,可以通过读写
    /sys/class/leds//trigger文件进行控制。
  • triggers:指向LED设备可用触发器的链表。

LED框架初始化

static int __init leds_init(void){
        leds_class = class_create(THIS_MODULE, "leds");
        if (IS_ERR(leds_class))
            return PTR_ERR(leds_class);
        leds_class- >pm = &leds_class_dev_pm_ops;
        leds_class- >dev_groups = led_groups;
        return 0;
}

它创建了一个名为"leds"的设备类,并设置了与电源管理相关的操作函数和设备属性组。通过这个初始化过程,LED设备驱动程序可以注册到该设备类,并与LED子系统进行交互。

LED 设备注册和注销

int led_classdev_register_ext(struct device *parent,
                              struct led_classdev *led_cdev,
                              struct led_init_data *init_data)

这个函数在将可以提供外部其他文件使用

led_classdev_unregister()函数用于注销一个已注册的LED设备

2. LED核心功能

driver/leds/led-core.c

LED 设备注册和管理:led-core.c 提供了函数和数据结构,用于注册和管理 LED 设备。它定义了 struct led_classdev 结构体,用于表示一个 LED 设备的属性和操作函数。通过使用 led_classdev_register() 函数,可以将一个 LED 设备注册到 LED 子系统,并将其添加到 sysfs 文件系统中的 /sys/class/leds/ 目录下。

触发器管理:led-core.c 还实现了 LED 触发器的注册和管理。触发器是一种机制,根据不同的条件或事件改变 LED 的状态。通过使用 led_trigger_register() 函数,可以将一个 LED 触发器注册到 LED 子系统,并将其添加到 sysfs 文件系统中的 /sys/class/leds/ 目录下的触发器文件中。

电源管理:LED 子系统还提供了电源管理的支持。led-core.c 定义了与电源管理相关的操作函数,并将这些操作函数与设备类结构体中的 pm 字段关联起来。通过使用 led_classdev_register() 函数时,可以将 pm 字段设置为相应的电源管理操作函数,以实现对 LED 设备的电源管理。

属性和操作的支持:led-core.c 提供了用于处理 LED 设备属性和操作的函数。例如,它实现了与 LED 亮度相关的操作函数,以便从用户空间调整 LED 的亮度。

3. LED触发器管理

driver/leds/led-trigger.c

触发器注册和管理:led-trigger.c 提供了函数和数据结构,用于注册和管理 LED 触发器。它定义了 struct led_trigger 结构体,用于表示一个 LED 触发器的属性和操作函数。通过使用 led_trigger_register() 函数,可以将一个 LED 触发器注册到 LED 子系统,并将其添加到 sysfs 文件系统中的 /sys/class/leds/ 目录下的触发器文件中。

触发器操作:led-trigger.c 实现了与 LED 触发器相关的操作函数。这些操作函数包括触发器的启用、禁用、触发等操作。通过这些操作函数,用户可以与 LED 触发器进行交互,并控制触发器的行为。

内置触发器:led-trigger.c 还实现了一些内置的 LED 触发器。这些触发器根据不同的条件或事件改变 LED 的状态。例如,timer 触发器以指定的时间间隔来闪烁。

struct led_trigger {
          /* Trigger Properties */
          const char       *name;
          int             (*activate)(struct led_classdev *led_cdev);
          void            (*deactivate)(struct led_classdev *led_cdev);


          /* LED-private triggers have this set */
          struct led_hw_trigger_type *trigger_type;


          /* LEDs under control by this trigger (for simple triggers) */
          rwlock_t          leddev_list_lock;
          struct list_head  led_cdevs;


          /* Link to next registered trigger */
          struct list_head  next_trig;


          const struct attribute_group **groups;
};

trigger 等于是led处于某种模式,可以闪烁,可以实现具体的一个什么实物的LED,比如呼吸道,音频LED等等;

4. 总结

LINUX内核

LINUX内核

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分