1.對燈光的要求
(1)亮度可調節,如背光燈
(2)顏色可變化,如電池電量指示燈
(3)能閃爍,如通知燈
2.Linux內核對led的支持
在Linux內核中已經實現了一個led class, 它里面已經實現了brightness的調節和blink,文件為:drivers/leds/led-class.c
在ledinit()中的led_class_attrs在/sys/class/leds下創建了brightness max_brightness trigger文件。
3.使用Linux內核中的led class
(1)配置內核
make menuconfig選中:
CONFIG_LEDS_CLASS
CONFIG_LEDS_TRIGGERS
CONFIG_LEDS_TRIGGER_TIMER
(2)驅動編寫流程
a.分配led_classdev結構體
b.設置
c.注冊
可以參考leds-s3c24xx.c,驅動Demo如下:

#include <linux/kernel.h> #include <linux/module.h> #include <linux/miscdevice.h> #include <linux/device.h> #include <linux/fs.h> #include <linux/types.h> #include <linux/moduleparam.h> #include <linux/slab.h> #include <linux/ioctl.h> #include <linux/cdev.h> #include <linux/delay.h> #include <linux/gpio.h> #include <mach/gpio.h> #include <plat/gpio-cfg.h> #include <linux/leds.h> struct led_desc { int gpio; char *name; }; /*三星的goio引腳根本就不需要獲取就可以直接使用*/ static struct led_desc led_gpios[] = { {EXYNOS4212_GPM4(0), "led1"}, {EXYNOS4212_GPM4(1), "led2"}, {EXYNOS4212_GPM4(2), "led3"}, {EXYNOS4212_GPM4(3), "led4"}, }; struct led_classdev_4412 { struct led_classdev cdev; /*核心結構體*/ int gpio; /*每一個led綁定的gpio*/ }; static struct led_classdev_4412 *led_devs; static void brightness_set_4412(struct led_classdev *led_cdev, enum led_brightness brightness) { struct led_classdev_4412 *dev = (struct led_classdev_4412 *)led_cdev; led_cdev->brightness = brightness; if (brightness != LED_OFF) gpio_set_value(dev->gpio, 0); /*打開led*/ else gpio_set_value(dev->gpio, 1); /*關閉led*/ } static int leds_init(void) { int i; int ret; /* 1. alloc led_classdev */ led_devs = kzalloc(sizeof(struct led_classdev_4412) * ARRAY_SIZE(led_gpios), GFP_KERNEL); if (led_devs == NULL) { printk("No memory for device\n"); return -ENOMEM; } for (i = 0; i < ARRAY_SIZE(led_gpios); i++) { s3c_gpio_cfgpin(led_gpios[i].gpio, S3C_GPIO_OUTPUT); /*默認led全部關閉*/ gpio_set_value(led_gpios[i].gpio, 1); /* 2. set 這里面哪些域需要設置由led-class.c的實現決定的*/ led_devs[i].cdev.max_brightness = LED_FULL; led_devs[i].cdev.brightness_set = brightness_set_4412; led_devs[i].cdev.flags = LED_CORE_SUSPENDRESUME; led_devs[i].cdev.brightness = LED_OFF; led_devs[i].cdev.name = led_gpios[i].name; led_devs[i].gpio = led_gpios[i].gpio; //led_devs[i].cdev.default_trigger = "timer"; //led_devs[i].cdev.blink_delay_on = 100; //led_devs[i].cdev.blink_delay_off = 900; /* 3. led_classdev_register */ ret = led_classdev_register(NULL, &led_devs[i].cdev); if (ret) { i--; while (i >= 0) { led_classdev_unregister(&led_devs[i].cdev); i--; } kfree(led_devs); return -EIO; } } return 0; } static void leds_exit(void) { int i; for (i = 0; i < ARRAY_SIZE(led_gpios); i++) { led_classdev_unregister(&led_devs[i].cdev); } kfree(led_devs); } module_init(leds_init); module_exit(leds_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mr.Sun");
重新編譯內核啟動后,會在/sys/class/leds下看到led1——led4
4.應用程序設置方法
應用程序是通過sysfs文件來控制led的。
# echo 255 > /sys/class/leds/led1/brightness 點亮
# echo 0 > /sys/class/leds/led1/brightness 熄滅
# echo timmer > /sys/class/leds/led1/trigger 此時led1就應該在以1HZ頻率閃爍了。之后此目錄下會多出delay_on/delay_off兩個文件
配置它兩個可以配置閃爍行為。
echo none > trigger 和 echo 0 > brightness 都會使led不在依附trigger。
5.也可以在驅動代碼里面設置默認的trigger,讓led一上電就開始閃動。
6.這個顯示效果還是可以借鑒一下的,由led_trigger_show()實現的,括起來的是led目前attach的trigger,其它是系統中還存在的trigger。
shell@tiny4412:/sys/class/leds/led1 # cat trigger
none mmc0 mmc1 mmc2 [timer]
7.從這里看不但可以指定class的sysfs屬性文件,還可以指定dev的!
struct class { ... struct class_attribute *class_attrs; struct device_attribute *dev_attrs; struct bin_attribute *dev_bin_attrs; ... }
class_create()時指定的屬性在每一個依此class創建的設備文件的sysfs目錄中都存在。見leds-class.c中的leds_init()。
8.device_create()只是創建設備模型,並不會在/dev/下創建設備文件
如led_classdev_register中調用了device_create但是並沒有/dev/下的設備文件。
led_cdev->dev = device_create(leds_class, parent, 0, led_cdev, "%s", led_cdev->name); //無論arg3是否為0測試都不會創建設備文件。
9.list_for_each_entry的使用
來自led_trigger_show():
trig: 空閑變量指針
trigger_list: 單鏈表的鏈表頭
next_trig: 構成鏈表的next指針成員
list_for_each_entry(trig, &trigger_list, next_trig) {use trig...}