這里說一說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. 總結
評論
查看更多