Linux下的LED子系统
最簡單的led驅(qū)動就是從端口輸出0或1來關(guān)閉或點亮燈。而我們這里講的led子系統(tǒng),主要是對led事件進行了分裝和優(yōu)化,這里我們主要講的是可以實現(xiàn)跨平臺的led驅(qū)動。不管你是使用三星的平臺,還是Atmel的平臺,你只要知道如何在你的BSP中添加平臺數(shù)據(jù),并且知道如何在應(yīng)用程序中使用這個驅(qū)動,那么你就不用因為新的平臺而再次編寫led驅(qū)動。
按鍵驅(qū)動屬于input子系統(tǒng),源碼路徑在/driver/leds下,我們的跨平臺按鍵驅(qū)動文件是/driver/leds/leds-gpio.c,關(guān)于led子系統(tǒng)的核心文件是Led-class.c和Led-core.c
查看/driver/leds/Makefile
obj-$(CONFIG_LEDS_GPIO)??????????????????? += leds-gpio.o
查看/driver/leds/Konfig
config LEDS_GPIO
?????? tristate"LED Support for GPIO connected LEDs"
?????? dependson LEDS_CLASS && GENERIC_GPIO
其中
config LEDS_CLASS
?????? tristate"LED Class Support"
所以配置內(nèi)核makemenuconfig 時,需要選中這兩項。
?
現(xiàn)在先來看如何移植,比如我們現(xiàn)在要給mini2440開發(fā)板上的led1到key4編寫led驅(qū)動,根據(jù)資料知道,led1到led4用的是GPB5-GPB8端口。下面就看移植代碼了,在mach-mini2440.c這個mini2440開發(fā)板的BSP中添加如下代碼
static struct gpio_led s3c_gpio_leds[] = {
?????? {
????????????? .name??????????????????? = "led1",
????????????? .gpio???????????????????? = S3C2410_GPB(5),
????????????? .active_low= 1,
?????? },
?????? {
????????????? .name??????????????????? = "led2",
????????????? .gpio???????????????????? = S3C2410_GPB(6),
????????????? .active_low= 1,
?????? },
?????? {
????????????? .name??????????????????? = "led3",
????????????? .gpio???????????????????? = S3C2410_GPB(7),
????????????? .active_low= 1,
?????? },
?????? {
????????????? .name??????????????????? = "led4",
????????????? .gpio???????????????????? = S3C2410_GPB(8),
????????????? .active_low= 1,
?????? },
};
?
static struct gpio_led_platform_datas3c_gpio_led_data = {
?????? .leds??????? = s3c_gpio_leds,
?????? .num_leds?????? = ARRAY_SIZE(s3c_gpio_leds),
};
?
static struct platform_device s3c_leds_gpio= {
?????? .name????? = "leds-gpio",
?????? .id??? = -1,
?????? .dev = {
????????????? .platform_data = &s3c_gpio_led_data,
?????? },
};
然后把這個s3c_leds_gpio加入到mini2440_devices數(shù)組
static struct platform_device*mini2440_devices[] __initdata = {
?????? ……
?????? &s3c_leds_gpio, //添加
};
最后添加頭文件
#include <linux/leds.h>
這樣配置完后,進行makezImage生成zImage內(nèi)核鏡像。
?
下面大致說說/driver/leds/leds-gpio.c
直接看平臺驅(qū)動定義
static struct platform_drivergpio_led_driver = {
?????? .probe??????????? = gpio_led_probe,? //探測
?????? .remove????????? = __devexit_p(gpio_led_remove),
?????? .driver??????????? = {
????????????? .name????? = "leds-gpio",? //驅(qū)動名
????????????? .owner??? = THIS_MODULE,
?????? },
};
下面看probe探測函數(shù)
static int __devinit gpio_led_probe(structplatform_device *pdev)
{
?????? structgpio_led_platform_data *pdata = pdev->dev.platform_data;
?????? structgpio_led_data *leds_data;
?????? inti, ret = 0;
?????? if(!pdata)
????????????? return-EBUSY;
?????? leds_data= kzalloc(sizeof(struct gpio_led_data) * pdata->num_leds,? //分配空間
??????????????????????????? GFP_KERNEL);
?????? if(!leds_data)
????????????? return-ENOMEM;
?????? for(i = 0; i < pdata->num_leds; i++) {
????????????? ret= create_gpio_led(&pdata->leds[i], &leds_data[i],
??????????????????????????? ????? &pdev->dev,pdata->gpio_blink_set);? //創(chuàng)建led設(shè)備
????????????? if(ret < 0)
???????????????????? gotoerr;
?????? }
?????? platform_set_drvdata(pdev,leds_data);
?????? return0;
err:
?????? for(i = i - 1; i >= 0; i--)
????????????? delete_gpio_led(&leds_data[i]);
?????? kfree(leds_data);
?????? returnret;
}
繼續(xù)跟蹤probe中的create_gpio_led函數(shù)
static int __devinit create_gpio_led(conststruct gpio_led *template,
?????? structgpio_led_data *led_dat, struct device *parent,
?????? int(*blink_set)(unsigned, unsigned long *, unsigned long *))
{
?????? intret, state;
?????? led_dat->gpio= -1;
?????? if(!gpio_is_valid(template->gpio)) {
????????????? printk(KERN_INFO"Skipping unavailable LED gpio %d (%s)\n",
??????????????????????????? template->gpio,template->name);
????????????? return0;
?????? }
?????? ret= gpio_request(template->gpio, template->name);
?????? if(ret < 0)
????????????? returnret;
?????? led_dat->cdev.name= template->name;
?????? led_dat->cdev.default_trigger= template->default_trigger;
?????? led_dat->gpio= template->gpio;
?????? led_dat->can_sleep= gpio_cansleep(template->gpio);
?????? led_dat->active_low= template->active_low;
?????? if(blink_set) {
????????????? led_dat->platform_gpio_blink_set= blink_set;
????????????? led_dat->cdev.blink_set= gpio_blink_set;?? //定義函數(shù)
?????? }
?????? led_dat->cdev.brightness_set= gpio_led_set;? //定義函數(shù)
?????? if(template->default_state == LEDS_GPIO_DEFSTATE_KEEP)
????????????? state= !!gpio_get_value(led_dat->gpio) ^ led_dat->active_low;
?????? else
????????????? state= (template->default_state == LEDS_GPIO_DEFSTATE_ON);
?????? led_dat->cdev.brightness= state ? LED_FULL : LED_OFF;
?????? if(!template->retain_state_suspended)
????????????? led_dat->cdev.flags|= LED_CORE_SUSPENDRESUME;
?????? ret= gpio_direction_output(led_dat->gpio, led_dat->active_low ^ state);
?????? if(ret < 0)
????????????? gotoerr;
?????? INIT_WORK(&led_dat->work,gpio_led_work);? //初始化工作隊列
?????? ret= led_classdev_register(parent, &led_dat->cdev);? //向leds類中注冊設(shè)備
?????? if(ret < 0)
????????????? gotoerr;
?????? return0;
err:
?????? gpio_free(led_dat->gpio);
?????? returnret;
}
?
講到這,讓我們恍然明白,這個leds子系統(tǒng)跟之前分析過的backlight背光子系統(tǒng)是非常類似的。backlight背光子系統(tǒng)在核心層定義了一套device_attribute機制,并且定義了操作backlight背光的操作函數(shù)集的接口,同時在device_attribute的show和store屬性中會調(diào)用backlight背光的操作函數(shù)集。然后我們使用這個backlight背光子系統(tǒng)核心層,編寫自己的驅(qū)動時,只需要向backlight背光子系統(tǒng)注冊設(shè)備,并填充backlight背光的操作函數(shù)集即可。用戶層只需要通過echo向brightness中寫數(shù)字觸發(fā)store屬性,或者通過cat向brightness中讀數(shù)字觸發(fā)show屬性。
再回過頭來看看我們這個leds子系統(tǒng),在create_gpio_led函數(shù)中有這樣一行代碼led_dat->cdev.brightness_set= gpio_led_set;其中的函數(shù)gpio_led_set是設(shè)置燈亮滅的函數(shù),這就是相當(dāng)于我們給led子系統(tǒng)的操作函數(shù)賦值,跟蹤led_classdev_register函數(shù),你會發(fā)現(xiàn)在那里會看到定義了leds類屬性,并創(chuàng)建了device_attribute機制,同時同時在device_attribute的store屬性中會調(diào)用我們這里定義的的操作函數(shù)gpio_led_set。
所以,leds子系統(tǒng)的源碼我就分析到這里了,我在學(xué)習(xí)backlight子系統(tǒng)的時候,就細(xì)細(xì)分析過這樣一個類里包含設(shè)備屬性,以及設(shè)備操作函數(shù),這跟leds-gpio.c代碼原理類似,如果需要可以參考。
?
LED驅(qū)動測試
用戶可以先通過cd/sys/class/leds打開led子系統(tǒng)下的設(shè)備
然后應(yīng)用層通過訪問/sys/class/leds/led1來設(shè)置等的亮滅
點亮led1:
echo 1 > /sys/class/leds/led1
關(guān)閉led1:
echo 0 > /sys/class/leds/led1
總結(jié)
以上是生活随笔為你收集整理的Linux下的LED子系统的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于EXPORT_SYMBOL
- 下一篇: 关于__init、__initdata和