Linux led子系统分析2

Linux led子系统分析2(基于Linux6.6)---软件架构介绍


一、led子系统实现说明

针对 Linux LED 子系统,其实现确实主要分为以下三大部分:led-triggerled-classled-core。每部分负责不同的功能和作用,下面是这三部分的详细说明:

1. led-trigger (LED 触发器)

LED 触发器(led-trigger)是 LED 子系统中负责控制 LED 状态变化的机制。它可以根据不同的系统事件自动触发 LED 的状态改变。常见的触发器包括 CPU 活跃度、网络流量、输入事件等。

功能:

  • 事件触发:通过特定的事件或条件(如 CPU 使用率、网络活动等),自动调整 LED 的状态(点亮、闪烁或关闭)。
  • 触发器配置:通过 sysfs 接口,用户可以配置不同的触发器。

触发器类型:

  • none:没有触发器,LED 手动控制。
  • cpu:基于 CPU 使用率变化触发。
  • netdev:基于网络接口的活动(如传输数据)触发。
  • heartbeat:定时闪烁,用于表示系统健康。
  • input:基于输入设备事件(例如按键输入)触发。

例子:

  • 将 LED 配置为在网络活动时闪烁:
  • echo netdev > /sys/class/leds/my_led/trigger
    

2. led-class (LED 类)

led-class 是 LED 子系统的核心模块,它提供了对 LED 设备的统一管理和控制接口。在 Linux 中,每个 LED 设备都由一个 led_classdev 结构表示,该结构包含 LED 的属性、状态以及操作回调函数等。

功能:

  • 设备注册与注销led-class 负责注册和注销 LED 设备,管理 LED 设备的生命周期。
  • 统一接口:提供对 LED 的统一访问接口,包括设置亮度、控制闪烁等。
  • Sysfs 接口:通过 led-class 提供的 sysfs 接口,用户空间可以对 LED 进行控制,例如设置亮度或触发器。

主要结构:

  • led_classdev:每个 LED 设备对应一个 led_classdev 结构,包含 LED 的名称、亮度设置、闪烁配置、触发器设置等。
  • 设备注册:使用 led_classdev_register() 函数注册 LED 设备,使用 led_classdev_unregister() 注销设备。

例子:

  • 设置 LED 亮度:
  • echo 255 > /sys/class/leds/my_led/brightness
    

3. led-core (LED 核心)

led-core 是 LED 子系统的底层实现,负责对 LED 设备的核心功能进行处理,包括亮度控制、闪烁控制等。它通过 led_classdev 与硬件接口进行交互。

功能:

  • 控制 LED 亮度led-core 处理对 LED 亮度的设置,控制 LED 的点亮和熄灭。
  • 闪烁控制:负责处理闪烁周期和频率的设置,通过定时器或 PWM 控制 LED 的闪烁模式。
  • 硬件交互led-core 通过硬件接口(如 GPIO、PWM 等)实现对硬件 LED 的控制。

关键操作:

  • 亮度设置:根据用户或触发器的设置,调整 LED 的亮度值。
  • 闪烁管理:通过定时器或硬件计时器,周期性地改变 LED 的状态(点亮或熄灭)。
  • 硬件控制:通过调用硬件驱动接口(如 GPIO 控制、PWM 信号等),将控制信号传递给硬件。

例子:

  • 控制 LED 闪烁:
echo "1000" > /sys/class/leds/my_led/delay_on
echo "1000" > /sys/class/leds/my_led/delay_off

二、led子系统相关数据结构说明

其实针对led子系统而言,其本身实现的功能也比较简单,目标就是控制led的亮(包括亮度调节)、灭以及闪烁这三种情况,而针对led亮、灭、闪烁的控制策略依据业务会有所不同,因此基于这些要求,led子系统抽象了两个数据结构:struct led_classdev、struct led-trigger。下面我们首先从需求入手,分析所需要实现的功能,然后再和led子系统针对数据结构的定义进行比较。

led设备需要实现的功能:

  1. 需要提供亮度设置的接口,以便对led进行亮度设置;
  2. 需要支持led闪烁的功能;
  3. 能够针对具体的功能模块,提供相应的亮度调节等(以上两条是通用需求,而第三条则是可扩展的需求,以便让led实现不同的功能)。

led触发器所需要实现的功能:

  1. 提供一个led控制策略接口,该接口可实现对led功能的控制(如呼吸灯策略、backlight等)

而led子系统中关于struct led_classdev、struct led-trigger也就是实现上述的功能,下面我们分析一下。

2.1、struct led_classdev

如下即为led_classdev,所包含的内容:

  1. led亮度设置值以及最大亮度值
  2. led亮度设置与获取当前亮度的接口;
  3. 该led自行实现的闪烁接口;
  4. 为该led提供一个定时器,通过定时器实现通用的led闪烁功能(若该led不需要该定时器实现闪烁,则只需要实现上述3中所说的接口即可);
  5. 该led所需要绑定的led-trigger,即为该led绑定一个led控制方法;
  6. 该led定义了一个struct device类型的变量,用于将该led与led相关的class关联,并为应用程序提供了一个访问led-device的方式(通过向sysfs中创建文件,应用程序访问这些文件即可实现与led-device的交互)。

include/linux/leds.h 

struct led_classdev {
	const char		*name;
	unsigned int brightness;
	unsigned int max_brightness;
	unsigned int color;
	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
	/* Brightness off also disables hw-blinking so it is a separate action */
#define LED_SET_BRIGHTNESS_OFF		6
#define LED_SET_BRIGHTNESS		7
#define LED_SET_BLINK			8

	/* 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.
	 * 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.
	 * For led_blink_set_nosleep() the LED core assumes that blink_set
	 * implementations, of drivers which do not use brightness_set_blocking,
	 * will not sleep. Therefor if brightness_set_blocking is not set
	 * this function must not sleep!
	 */
	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;
	unsigned long		delayed_delay_on;
	unsigned long		delayed_delay_off;

#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;

	/* Unique trigger name supported by LED set in hw control mode */
	const char		*hw_control_trigger;
	/*
	 * Check if the LED driver supports the requested mode provided by the
	 * defined supported trigger to setup the LED to hw control mode.
	 *
	 * Return 0 on success. Return -EOPNOTSUPP when the passed flags are not
	 * supported and software fallback needs to be used.
	 * Return a negative error number on any other case  for check fail due
	 * to various reason like device not ready or timeouts.
	 */
	int			(*hw_control_is_supported)(struct led_classdev *led_cdev,
							   unsigned long flags);
	/*
	 * Activate hardware control, LED driver will use the provided flags
	 * from the supported trigger and setup the LED to be driven by hardware
	 * following the requested mode from the trigger flags.
	 * Deactivate hardware blink control by setting brightness to LED_OFF via
	 * the brightness_set() callback.
	 *
	 * Return 0 on success, a negative error number on flags apply fail.
	 */
	int			(*hw_control_set)(struct led_classdev *led_cdev,
						  unsigned long flags);
	/*
	 * Get from the LED driver the current mode that the LED is set in hw
	 * control mode and put them in flags.
	 * Trigger can use this to get the initial state of a LED already set in
	 * hardware blink control.
	 *
	 * Return 0 on success, a negative error number on failing parsing the
	 * initial mode. Error from this function is NOT FATAL as the device
	 * may be in a not supported initial state by the attached LED trigger.
	 */
	int			(*hw_control_get)(struct led_classdev *led_cdev,
						  unsigned long *flags);
	/*
	 * Get the device this LED blinks in response to.
	 * e.g. for a PHY LED, it is the network device. If the LED is
	 * not yet associated to a device, return NULL.
	 */
	struct device		*(*hw_control_get_device)(struct led_classdev *led_cdev);
#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;
};

2.2、struct led-trigger

该数据结构的定义如下:

  1. 调用activate接口(当led-dev与led-trigger完成绑定时,即调用该接口),使能该led的控制策略;
  2. 调用deactivate接口(当led-dev与led-trigger解除绑定时,即调用该接口),关闭该led的控制策略;

 include/linux/leds.h

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) */
	spinlock_t	  leddev_list_lock;
	struct list_head  led_cdevs;

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

	const struct attribute_group **groups;
};

   除了上述的数据结构之外,led子系统还提供了led-dev的注册与注销接口、led亮度设置接口、定时器实现的led闪烁接口、led-trigger的注册与注销接口等对外接口。

以上即是led_classdev、led_trigger以及led子系统提供接口的关联图,主要说明如下:

  1. 所有注册的led_classdev均会链接到leds_list;
  2. 所有注册的led_trigger均会链接到链表trigger_list上;
  3. 一个led_trigger可以与多个led_classdev关联,而一个led_classdev只能绑定一个led_trigger,即一个led只能同时使用一种led控制策略(这也符合我们的需求)。
  4. 每一个led_classdev均会提供一个定时器,用于实现led闪烁功能,但是否启用该软件定时器由绑定的led-trigger决定(当然也与led-trigger所要实现的功能关联,如ledtrigger-timer,则就是借助该软件定时器实现闪烁的(前提是该led-classdev未实现自己的闪烁接口))。

在 Linux 内核中,LED 子系统的设计和实现通过多个组件协作来控制 LED 设备的行为。led_classdevled_trigger 和 LED 子系统的其他接口密切配合。以下是各个组件的关联图示,帮助理解它们之间的关系。

LED 子系统组件及其接口

                                 +------------------+
                                 |   User Space     |
                                 |                  |
                                 |  /sys/class/leds/ |
                                 |                  |
                                 +------------------+
                                         |
                         +------------------------------+
                         | Sysfs Interface (User Control)|
                         +------------------------------+
                                         |
            +-------------------------------------------------------+
            |                     LED Class Core                   |
            | +-----------------------------------------------+      |
            | | led_classdev structure                       |      |
            | | (per-LED device structure)                    |      |
            | +-----------------------------------------------+      |
            |     |                                                    |
            |     | Register LED Device                                |
            |     v                                                    |
            | +-----------------------------------------------+      |
            | | led_classdev_register() & led_classdev_unregister()|     |
            | +-----------------------------------------------+      |
            |     |                                                    |
            |     v                                                    |
            |   +-------------------------------------------+           |
            |   | LED Control: Brightness, Blink, etc.     |           |
            |   | led_set_brightness(), led_blink(),       |           |
            |   | led_trigger_set(), etc.                  |           |
            |   +-------------------------------------------+           |
            +-------------------------------------------------------+
                             |
                             v
             +--------------------------------------+
             |      LED Trigger Mechanism          |
             |    (led_trigger)                    |
             | +--------------------------------+   |
             | | Event-driven Trigger:          |   |
             | | - CPU usage (cpu)              |   |
             | | - Network activity (netdev)    |   |
             | | - Heartbeat (heartbeat)        |   |
             | | - User-defined triggers (input)|   |
             | +--------------------------------+   |
             |      |                               |
             |      v                               |
             |  +---------------------------------+ |
             |  | Event Handling (triggers LED)    | |
             |  | led_trigger_register()           | |
             |  +---------------------------------+ |
             +--------------------------------------+
                             |
                             v
               +-----------------------------+
               |       LED Hardware Interface |
               | (GPIO, PWM, or other HW)      |
               |                               |
               +-----------------------------+
                             |
                             v
                     +-------------------+
                     | LED Hardware (LED) |
                     +-------------------+

解释:

  1. User Space (用户空间)

    • 用户空间通过 /sys/class/leds/ 路径来控制 LED。它与内核的 LED 子系统通过 sysfs 接口交互,允许用户设置 LED 的亮度、触发器以及闪烁等行为。
  2. LED Class Core (LED 类核心)

    • led_classdev 结构体:这是每个 LED 设备的核心表示,包含了 LED 的属性和操作函数。每个 LED 设备会通过 led_classdev_register() 函数注册到系统中,并通过 led_classdev_unregister() 注销。
    • 该部分的主要任务是处理 LED 的控制命令,如亮度设置 (led_set_brightness()) 和闪烁管理(通过 led_blink()),并响应触发器的变化。
  3. LED Trigger (LED 触发器)

    • LED 触发器是根据外部事件或系统状态自动控制 LED 状态的机制。常见的触发器包括:

      • CPU 触发器 (cpu): 根据 CPU 活跃度改变 LED 状态。
      • 网络活动触发器 (netdev): 当网络设备有数据传输时触发 LED 改变。
      • 心跳触发器 (heartbeat): 周期性地闪烁 LED 表示系统正常。
      • 用户定义的输入触发器 (input): 根据输入事件(如按键)来控制 LED。
    • led_trigger_register() 函数用于注册触发器,而 led_trigger_set() 则用于设置触发器的行为。当触发器事件发生时,LED 设备会相应地改变状态。

  4. LED Hardware Interface (LED 硬件接口)

    • LED 子系统通过底层的硬件接口(如 GPIO、PWM 等)控制 LED 的物理状态。具体的硬件驱动会通过 led_classdev 结构与硬件进行交互,控制 LED 的点亮、闪烁等。

关键函数和调用流程:

  1. led_classdev_register()

    • 用于将一个新的 LED 设备注册到 LED 子系统。
    • 这个函数将 LED 设备与 led_classdev 结构绑定,允许后续通过 sysfs 控制 LED 的亮度、闪烁等。
  2. led_trigger_register()

    • 注册一个 LED 触发器,使得该触发器可以根据事件自动控制 LED 的行为。
    • 触发器会根据外部事件(如网络活动或 CPU 负载)改变 LED 的状态(亮起、闪烁等)。
  3. led_set_brightness()led_blink()

    • 用于控制 LED 的亮度或闪烁模式。这些操作通常由用户通过 sysfs 或触发器控制。
  4. 硬件控制

    • 通过 GPIO 或 PWM 控制 LED 的电平,从而实现点亮、熄灭或闪烁效果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值