这里说一说LED子系统的一些核心源代码文件,是如何实现LED子系统。
这里重点关注内核部分的实现:
对于内核中需要重点关注的几个文件如下:
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. 总结
评论
查看更多