最简单的led驱动就是从端口输出0或1来关闭或点亮灯。而我们这里讲的led子系统,主要是对led事件进行了分装和优化,这里我们主要讲的是可 以实现跨平台的led驱动。不管你是使用三星的平台,还是Atmel的平台,你只要知道如何在你的BSP中添加平台数据,并且知道如何在应用程序中使用这 个驱动,那么你就不用因为新的平台而再次编写led驱动。

按键驱动属于input子系统,源码路径在/driver/leds下,我们的跨平台按键驱动文件是/driver/leds/leds-gpio.c,关于led子系统的核心文件是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"

所以配置内核makemenuconfig 时,需要选中这两项。

现在先来看如何移植,比如我们现在要给mini2440开发板上的led1到key4编写led驱动,根据资料知道,led1到led4用的是 GPB5-GPB8端口。下面就看移植代码了,在mach-mini2440.c这个mini2440开发板的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数组

static struct platform_device*mini2440_devices[] __initdata = {

……

&s3c_leds_gpio, //添加

};

最后添加头文件

#include <linux/leds.h>

这样配置完后,进行makezImage生成zImage内核镜像。

下面大致说说/driver/leds/leds-gpio.c

直接看平台驱动定义

static struct platform_drivergpio_led_driver = {

.probe            = gpio_led_probe,  //探测

.remove          = __devexit_p(gpio_led_remove),

.driver            = {

.name      = "leds-gpio",  //驱动名

.owner    = THIS_MODULE,

},

};

下面看probe探测函数

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);  //创建led设备

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;

}

继续跟踪probe中的create_gpio_led函数

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;   //定义函数

}

led_dat->cdev.brightness_set= gpio_led_set;  //定义函数

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类中注册设备

if(ret < 0)

gotoerr;

return0;

err:

gpio_free(led_dat->gpio);

returnret;

}

讲到这,让我们恍然明白,这个leds子系统跟之前分析过的backlight背光子系统是非常类似的。backlight背光子系统在核心层定义 了一套device_attribute机制,并且定义了操作backlight背光的操作函数集的接口,同时在device_attribute的 show和store属性中会调用backlight背光的操作函数集。然后我们使用这个backlight背光子系统核心层,编写自己的驱动时,只需要 向backlight背光子系统注册设备,并填充backlight背光的操作函数集即可。用户层只需要通过echo向brightness中写数字触发 store属性,或者通过cat向brightness中读数字触发show属性。

再回过头来看看我们这个leds子系统,在create_gpio_led函数中有这样一行代码 led_dat->cdev.brightness_set= gpio_led_set;其中的函数gpio_led_set是设置灯亮灭的函数,这就是相当于我们给led子系统的操作函数赋值,跟踪 led_classdev_register函数,你会发现在那里会看到定义了leds类属性,并创建了device_attribute机制,同时同时 在device_attribute的store属性中会调用我们这里定义的的操作函数gpio_led_set。

所以,leds子系统的源码我就分析到这里了,我在学习backlight子系统的时候,就细细分析过这样一个类里包含设备属性,以及设备操作函数,这跟leds-gpio.c代码原理类似,如果需要可以参考。

LED驱动测试

用户可以先通过cd/sys/class/leds打开led子系统下的设备

然后应用层通过访问/sys/class/leds/led1来设置等的亮灭

点亮led1:

echo 1 > /sys/class/leds/led1

关闭led1:

echo 0 > /sys/class/leds/led1

led子系统的更多相关文章

  1. LED子系统剖析

    写之前,先看一张图: 上次说了LED驱动程序,Linux自身也携带了LED驱动,且是脱离平台的,即LED子系统.操作起来十分简单.但是它的实质却不是那么容易,研究了一个晚上,终于明白了其中一个文件的功 ...

  2. 初探linux子系统集之led子系统(三)

    世界杯结束了,德国战车夺得了大力神杯,阿根廷最终还是失败了.也许3年,5年,或者10年后,人们就不知道巴西世界杯的亚军是谁,但是总是会记得冠军是谁.就像什么考试,比赛,第一永远会被人们所记住,所以我们 ...

  3. 初探linux子系统集之led子系统(二)

    巴西世界杯,德国7比1东道主,那个惨不忍睹啊,早上起来看新闻,第一眼看到7:1还以为点球也能踢成这样,后来想想,点球对多嘛6比1啊,接着就是各种新闻铺天盖地的来了.其实失败并没有什么,人生若是能够成功 ...

  4. 初探linux子系统集之led子系统(一)

    就像学编程第一个范例helloworld一样,学嵌入式,单片机.fpga之类的第一个范例就是点亮一盏灯.对于庞大的linux系统,当然可以编写一个字符设备驱动来实现我们需要的led灯,也可以直接利用g ...

  5. arm Linux 驱动LED子系统 测试

    Linux内核在3.0以上引入了设备树概念(具体哪个版本不清楚)在编译内核后需要将与之对应的dtb文件也下载人板子上才能使内核与硬件关联起来. dtb文件是有dts文件编译后生成的:例如 /* * C ...

  6. linux led子系统(二)

    对于led子系统中,有那么多得trigger,下面就来简单了解下. 1.default-on static void defon_trig_activate(struct led_classdev * ...

  7. linux led子系统(一)

    就像学编程第一个范例helloworld一样,学嵌入式,单片机.fpga之类的第一个范例就是点亮一盏灯.对于庞大的linux系统,当然可以编写一个字符设备驱动来实现我们需要的led灯,也可以直接利用g ...

  8. 初探linux子系统集之led子系统(三)【转】

    本文转载自:http://blog.csdn.net/eastmoon502136/article/details/37822837 世界杯结束了,德国战车夺得了大力神杯,阿根廷最终还是失败了.也许3 ...

  9. 初探linux子系统集之led子系统(二)【转】

    本文转载自:http://blog.csdn.net/eastmoon502136/article/details/37606487 巴西世界杯,德国7比1东道主,那个惨不忍睹啊,早上起来看新闻,第一 ...

随机推荐

  1. [转]IDEA 导出自己的jar包 并且在另一个工程中引用

    1.导出jar包 1.1 idea导出jar包不如eclipse方便,但是熟练了也很容易操作 1.2 File -> Project Settings -> Artifacts(艺术品) ...

  2. Jmeter录制HTTPS

    Jmeter有录制功能,录制HTTPs需要增加一个证书配置,录制步骤如下: 1.打开jmeter,添加线程组.线程组右键,逻辑控制器>录制控制器 工作台 右键 非测试元件 >HTTP代理服 ...

  3. 【转】WARNING! File system needs to be upgraded. You have version null and I want version 7. Run the '${HBASE_HOME}/bin/hbase migrate' script. 的解决办法

    前段时间集群出问题,hadoop和hbase启动不了了. 后来hadoop回复了,hbase死活master无法启动.打开日志发现报了以下错误: WARNING! File system needs ...

  4. windows 环境使用 kafka

    近来学习 kafka,网上搜的教程好多不好用.在此开一贴记录一下学习过程.推荐官网,是最好的教程 http://kafka.apache.org/quickstart 官网上是linux 环境,我用的 ...

  5. 对 /sbin/nologin 的理解

    对 /sbin/nologin 的理解 系统账号的shell使用 /sbin/nologin ,此时无法登陆系统,即使给了密码也不行.   所谓“无法登陆”指的仅是这个用户无法使用bash或其他she ...

  6. 程序包org.junit不存在和编码GBK的不可映射字符问题解决

    maven项目在打包编译时提示: 解决办法: 将pom中junit依赖中的scope给注释掉 <dependency> <groupId>junit</groupId&g ...

  7. 怎么设置Linux swap分区?方法教程

    如何设置Linux swap分区 看到不少朋友问linux下swap分区的问题,收集到一篇 不错的文章 ,分享下. 什么是Swap?Swap,即交换区,除了安装Linux的时候,有多少人关心过它呢?其 ...

  8. 解决 slf4j + log4j 在云服务上打印乱码

    由于云服务器的环境是纯英文的 虽然在eclipse中可以打印日志显示中文,但是实用putty的时候查看却是乱码,下载日志也同样是乱码 那么只要设置utf-8即可

  9. nginx configure fastdfs + SSL

    ./configure \ --prefix=/usr/local/nginx \ --with-http_stub_status_module \ --with-http_ssl_module \ ...

  10. 【Unity】3.5 导入音频文件

    分类:Unity.C#.VS2015 创建日期:2016-04-05 一.简介 音频文件 (Audio File) 资源的选择原则应该以无故障地流畅运行为宗旨.下面列出了常用的音频文件. .AIFF ...