本文转载自:http://blog.csdn.net/yuanlulu/article/details/6438841

版权声明:本文为博主原创文章,未经博主允许不得转载。

============================================
作者:yuanlulu
http://blog.csdn.NET/yuanlulu

版权没有,但是转载请保留此段声明
============================================

数据结构
/include/linux/leds.h
enum led_brightness {
     LED_OFF          = 0,
     LED_HALF     = 127,
     LED_FULL     = 255,
};

led_classdev代表led的实例
struct led_classdev {
     const char          *name;               //名字
     int               brightness;                   //当前亮度
     int               flags;                         //标志,目前只支持 LED_SUSPENDED

#define LED_SUSPENDED          (1 << 0)

/*设置led的亮度,不可以睡眠,有必要的话可以使用工作队列*/
     void          (*brightness_set)(struct led_classdev *led_cdev,
                           enum led_brightness brightness);
     /* 获取亮度 */
     enum led_brightness (*brightness_get)(struct led_classdev *led_cdev);

/* 激活硬件加速的闪烁 */
     int          (*blink_set)(struct led_classdev *led_cdev,
                         unsigned long *delay_on,
                         unsigned long *delay_off);

struct device          *dev;
     struct list_head     node;               /* 所有已经注册的led_classdev使用这个节点串联起来 */
     const char          *default_trigger;     /* 默认触发器 */

#ifdef CONFIG_LEDS_TRIGGERS               //如果配置内核时使能了触发器功能,才会编译下面一段
     /* 这个读写子轩锁保护下面的触发器数据 */
     struct rw_semaphore     trigger_lock;

struct led_trigger     *trigger;          //触发器指针
     struct list_head     trig_list;               //触发器使用的链表节点,用来连接同一触发器上的所有led_classdev
     void               *trigger_data;            //触发器使用的私有数据
#endif
};

 
触发器的结构体
#define TRIG_NAME_MAX 50
struct led_trigger {
     const char     *name;          //触发器名字
     void          (*activate)(struct led_classdev *led_cdev);     //激活ledled。led_classdev和触发器建立连接时会调用这个方法。
     void          (*deactivate)(struct led_classdev *led_cdev);     //取消激活。led_classdev和触发器取消连接时会调用这个方法。

/* 本触发器控制之下的led链表 */
     rwlock_t       leddev_list_lock; //保护链表的锁
     struct list_head  led_cdevs;    //链表头

/* 连接下一个已注册触发器的链表节点 ,所有已注册的触发器都会被加入一个全局链表*/
     struct list_head  next_trig;
};

 
平台设备相关的led数据结构
struct led_info {
     const char     *name;
     char          *default_trigger;
     int          flags;
};

struct led_platform_data {
     int          num_leds;
     struct led_info     *leds;
};

 
平台设备相关的gpio led数据结构
struct gpio_led {
     const char *name;
     char *default_trigger;
     unsigned      gpio;
     u8           active_low;
};

struct gpio_led_platform_data {
     int           num_leds;
     struct gpio_led *leds;
     int          (*gpio_blink_set)(unsigned gpio,
                         unsigned long *delay_on,
                         unsigned long *delay_off);
};

 

led_classdev接口分析/driver/rtc/led-class.c
 
注册struct led_classdev:
int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
{
     int rc;

     /* 创建一个struct device,他的父设备是parent,drvdata是led_cdev,名字是led_cdev->name,类别是 leds_class*/
     led_cdev->dev = device_create_drvdata(leds_class, parent, 0, led_cdev,
                               "%s", led_cdev->name);
     if (IS_ERR(led_cdev->dev))
          return PTR_ERR(led_cdev->dev);

/* register the attributes */
     rc = device_create_file(led_cdev->dev, &dev_attr_brightness);//在sys/class/rtc/下创建一个led的属性文件。
     if (rc)
          goto err_out;

/* add to the list of leds */
     down_write(&leds_list_lock);
     list_add_tail(&led_cdev->node, &leds_list);//将新的led加入链表,全局链表是leds_list
     up_write(&leds_list_lock);

led_update_brightness(led_cdev);//获取led当前的亮度更新led_cdev的brightness成员

#ifdef CONFIG_LEDS_TRIGGERS
     init_rwsem(&led_cdev->trigger_lock);//初始化led_cdev的触发器自旋锁

rc = device_create_file(led_cdev->dev, &dev_attr_trigger);//在sys/class/led中为触发器创建属性文件
     if (rc)
          goto err_out_led_list;

led_trigger_set_default(led_cdev); //为led_cdev设置默认的触发器
#endif

printk(KERN_INFO "Registered led device: %s/n",
               led_cdev->name);

return 0;

#ifdef CONFIG_LEDS_TRIGGERS
err_out_led_list:
     device_remove_file(led_cdev->dev, &dev_attr_brightness);
     list_del(&led_cdev->node);
#endif
err_out:
     device_unregister(led_cdev->dev);
     return rc;
}
EXPORT_SYMBOL_GPL(led_classdev_register);

 
注销struct led_classdev:
void led_classdev_unregister(struct led_classdev *led_cdev);
注销所做的工作和注册相反。
 
将led挂起:将led的flag设为LED_SUSPENDED,关闭led.
void led_classdev_suspend(struct led_classdev *led_cdev)
从挂起中恢复:
void led_classdev_resume(struct led_classdev *led_cdev)
 
sysfs中的属性文件
/driver/rtc/led-class.c会首先创建一个leds类,生成/sys/class/leds目录。
在led_classdev_register中生成了两个sysfs属性文件,它们使用的属性参数如下:
 
static DEVICE_ATTR(brightness, 0644, led_brightness_show, led_brightness_store);
static DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store);
 
led_brightness_show和led_brightness_store分别负责显示和设置亮度,用户控件通过
/sys/class/leds/<device>/brightness查看和设置亮度就是和这两个函数交互的。
 led_trigger_show用于读取当前触发器的名字,led_trigger_store用于指定触发器的名字,
它会寻找所有已注册的触发器,找到同名的并设置为当前led的触发器。
/sys/class/leds/<device>/trigger用于用户空间查看和设置触发器。
 
 led_classdev全局链表:
led_classdev_register注册的struct led_classdev会被加入leds_list链表,这个链表定义在driver/leds/led-core.c。
 

led_trigger接口分析/driver/leds/led-triggers.c
 
注册触发器
int led_trigger_register(struct led_trigger *trigger);
这个函数注册的trigger会被加入全局链表trigger_list,这个链表头是在/driver/leds/led-triggers.c定义的。
此外,这个函数还会遍历所有的已注册的 led_classdev,如果有哪个led_classdev的默认触发器和自己同名,则
调用led_trigger_set将自己设为那个led的触发器。
led_classdev注册的时候也会调用led_trigger_set_default来遍历所有已注册的触发器,找到和led_classdev.default_trigger同名的触发器则将它设为自己的触发器。
 
注销触发器
void led_trigger_unregister(struct led_trigger *trigger);
这个函数做和注册相反的工作,并把所有和自己建立连接的led的led_classdev.trigger设为NULL。
 
设置触发器上所有的led为某个亮度
void led_trigger_event(struct led_trigger *trigger, enum led_brightness brightness);
 
注册触发器的简单方法
指定一个名字就可以注册一个触发器,注册的触发器通过**tp返回,但是这样注册的触发器没有active和deactivede。
void led_trigger_register_simple(const char *name, struct led_trigger **tp);
相对应的注销函数为:
void led_trigger_unregister_simple(struct led_trigger *trigger);
 
触发器和led的连接
void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger);//建立连接。建立连接的时候会调用触发器的activate方法
void led_trigger_remove(struct led_classdev *led_cdev);//取消连接。取消连接的时候会调用触发器的deactivate方法
void led_trigger_set_default(struct led_classdev *led_cdev);//在所有已注册的触发器中寻找led_cdev的默认触发器并调用 led_trigger_set建立连接
 
最后总结一下led、led_classdev、led_trigger的关系:
 也就是说trigger好比是控制LED类设备的算法,这个算法决定着LED什么时候亮什么时候暗。LED trigger类设备可以是现实的硬件设备,比如IDE硬盘,也可以是系统心跳等事件。

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. led子系统

    最简单的led驱动就是从端口输出0或1来关闭或点亮灯.而我们这里讲的led子系统,主要是对led事件进行了分装和优化,这里我们主要讲的是可 以实现跨平台的led驱动.不管你是使用三星的平台,还是Atm ...

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

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

  7. linux led子系统(二)

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

  8. linux led子系统(一)

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

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

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

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

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

随机推荐

  1. luogu P1040 加分二叉树

    题目描述 设一个n个节点的二叉树tree的中序遍历为(1,2,3,-,n),其中数字1,2,3,-,n为节点编号.每个节点都有一个分数(均为正整数),记第i个节点的分数为di,tree及它的每个子树都 ...

  2. Endless Pallet(min-max容斥)

    地址:传送门 分析: 设$x_i$表示第i个点被染成黑色的时间,所求即为$E(max \left \{x_i  \right \})$ 因为$E(X)=\sum_{k=1}^{\infty}i \ti ...

  3. Maven的安装文字版(Windows/Linux/Mac)

    以下内容引用自https://ayayui.gitbooks.io/tutorialspoint-maven/content/book/maven_environment_setup.html,安装信 ...

  4. session再次理解

    1.session介绍: session主要用来存储用户的会话所需的信息(用户行为信息),当用户在同一个服务器上实现不同的操作时,session信息会以变量的形式存储在服务器的内存中,保存用户的状态信 ...

  5. Java使用QRCode.jar生成与解析二维码

    原文V:http://www.cnblogs.com/bigroc/p/7496995.html#3797682 正题:Java使用QRCode.jar生成与解析二维码demo 欢迎新手共勉,大神监督 ...

  6. C++11 并发指南一(C++11 多线程初探)(转)

    引言 C++11 自2011年发布以来已经快两年了,之前一直没怎么关注,直到最近几个月才看了一些 C++11 的新特性,今后几篇博客我都会写一些关于 C++11 的特性,算是记录一下自己学到的东西吧, ...

  7. WinDbg抓取dmp文件

    应用程序发生异常时抓取dmp: adplus.vbs -crash -pn w3wp.exe -y srv*c:\symbols*http://msdl.microsoft.com/download/ ...

  8. 递归计算战士打靶S次打了N环一共同拥有多少种可能的问题

    问题描写叙述 一个战士打了10次靶.一共打了90环,问一共同拥有多少种可能,并输出这些可能的组合. 思路 首先.嵌套10层循环进行穷举是不可取的,一是由于速度太慢,二是假设改成打20次靶就完蛋了. 事 ...

  9. 1.excel如何让一列的数都乘以固定值

     让B列等于A列乘以39.37 1.我们先选中B列中要编辑的单元: 2.再在编辑栏中输入公式:=A2*39.37   (PS:*号即表示是×号) 3.公式输入后,按下快捷键:CTRL+回车:记住一定要 ...

  10. jQuery UI Autocomplete是jQuery UI的自动完成组件

    支持的数据源 jQuery UI Autocomplete主要支持字符串Array.JSON两种数据格式. 普通的Array格式没有什么特殊的,如下: ? 1 ["cnblogs" ...