struct list_head leds_list; // 资源链表
struct list_head trigger_list; // 驱动链表
对于链表,总有创建, 添加,遍历这三个要素,下面简单看下这两个链表的三要素
driversleds/led-triggers.c
LIST_HEAD(trigger_list);
driversleds/led-triggers.c
module_init(heartbeat_trig_init);
heartbeat_trig_init // Ledtrig-heartbeat.c (drivers\leds\trigger)
led_trigger_register
list_add_tail(&trig->next_trig, &trigger_list);
driversleds/led-triggers.c
led_trigger_store
led_trigger_show
led_trigger_set_default
led_trigger_register
list_for_each_entry(_trig, &trigger_list, next_trig)
drivers/leds/led-core.c
LIST_HEAD(leds_list);
drivers/leds/led-class.c
static struct platform_driver gpio_led_driver = {
.probe = gpio_led_probe,
.shutdown = gpio_led_shutdown,
.driver = {
.name = "leds-gpio",
.of_match_table = of_gpio_leds_match,
},
};
static const struct of_device_id of_gpio_leds_match[] = {
{ .compatible = "gpio-leds", },
{},
};
module_platform_driver(gpio_led_driver); // Leds-gpio.c (drivers\leds)
gpio_led_probe
gpio_leds_create
create_gpio_led
devm_of_led_classdev_register
of_led_classdev_register
list_add_tail(&led_cdev->node, &leds_list);
drivers/leds/led-triggers.c
static struct led_trigger heartbeat_led_trigger = {
.name = "heartbeat",
.activate = heartbeat_trig_activate,
.deactivate = heartbeat_trig_deactivate,
.groups = heartbeat_trig_groups,
};
heartbeat_trig_init // driversleds/trigger/Ledtrig-heartbeat.c
led_trigger_register(&heartbeat_led_trigger);
led_trigger_unregister
list_for_each_entry(led_cdev, &leds_list, node)
先看资源,即设备树
vim arch/arm/boot/dts/exynos4412-tiny4412.dts
leds {
compatible = "gpio-leds";
led1 {
label = "led1";
gpios = <&gpm4 0 GPIO_ACTIVE_LOW>;
default-state = "off";
linux,default-trigger = "heartbeat";
};
led2 {
label = "led2";
gpios = <&gpm4 1 GPIO_ACTIVE_LOW>;
default-state = "off";
};
led3 {
label = "led3";
gpios = <&gpm4 2 GPIO_ACTIVE_LOW>;
default-state = "off";
};
led4 {
label = "led4";
gpios = <&gpm4 3 GPIO_ACTIVE_LOW>;
default-state = "off";
linux,default-trigger = "mmc0";
};
};
led1是系统heartbeat,这里主要分析它。
其驱动程序在 drivers/leds/leds-gpio.c, 匹配compatible = "gpio-leds"
static const struct of_device_id of_gpio_leds_match[] = {
{ .compatible = "gpio-leds", },
{},
};
在gpio_led_probe里面会解析设备树
gpio_led_probe
gpio_leds_create
fwnode_property_read_string(child, "label", &led.name); // label
devm_fwnode_get_gpiod_from_child(dev, NULL, child,
GPIOD_ASIS,
led.name); // name
fwnode_property_read_string(child, "linux,default-trigger",
&led.default_trigger);
fwnode_property_read_string(child, "default-state",
&state)
create_gpio_led(&led, led_dat, dev, np, NULL);
devm_of_led_classdev_register(parent, np, &led_dat->cdev);
of_led_classdev_register -->
list_add_tail(&led_cdev->node, &leds_list); // leds_list链表产生了节点
驱动
那么trigger驱动在哪里呢
在drivers/leds/led-triggers.c
module_init(heartbeat_trig_init);
heartbeat_trig_init -->
led_trigger_register -->
list_for_each_entry(led_cdev, &leds_list, node) {
down_write(&led_cdev->trigger_lock);
if (!led_cdev->trigger && led_cdev->default_trigger &&
!strcmp(led_cdev->default_trigger, trig->name))
led_trigger_set(led_cdev, trig);
up_write(&led_cdev->trigger_lock);
} // 遍历leds_list链
如果要控制LED
,需要调用函数:
static struct led_trigger heartbeat_led_trigger = {
.name = "heartbeat",
.activate = heartbeat_trig_activate,
.deactivate = heartbeat_trig_deactivate,
};
在led_trigger_set函数里面
void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
{
if (led_cdev->trigger) {
write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags);
list_del(&led_cdev->trig_list);
write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock,
flags);
cancel_work_sync(&led_cdev->set_brightness_work);
led_stop_software_blink(led_cdev);
if (led_cdev->trigger->deactivate) // deactivate
led_cdev->trigger->deactivate(led_cdev);
led_cdev->trigger = NULL;
led_set_brightness(led_cdev, LED_OFF);
}
if (trig) {
write_lock_irqsave(&trig->leddev_list_lock, flags);
list_add_tail(&led_cdev->trig_list, &trig->led_cdevs);
write_unlock_irqrestore(&trig->leddev_list_lock, flags);
led_cdev->trigger = trig;
if (trig->activate) // activate
trig->activate(led_cdev);
}
}
而在heartbeat_trig_activate里面
timer_setup(&heartbeat_data->timer, led_heartbeat_function, 0);
led_heartbeat_function(&heartbeat_data->timer);
操作
make menuconfig
Device Drivers --->
[*] LED Support --->
<*> LED Class Support
[*] LED Trigger support --->
<*> LED Heartbeat Trigger
重新烧录内核并进入文件系统后,在/sys/class/leds里面下有led0这个目录
echo 0 > brightness #停止闪烁
echo heartbeat > trigger #继续闪烁