(linux)LED子系统
数据结构(/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_SUSPENDE
#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硬盘,也可以是系统心跳等事件。
(linux)LED子系统的更多相关文章
- linux led子系统(二)
对于led子系统中,有那么多得trigger,下面就来简单了解下. 1.default-on static void defon_trig_activate(struct led_classdev * ...
- linux led子系统(一)
就像学编程第一个范例helloworld一样,学嵌入式,单片机.fpga之类的第一个范例就是点亮一盏灯.对于庞大的linux系统,当然可以编写一个字符设备驱动来实现我们需要的led灯,也可以直接利用g ...
- 初探linux子系统集之led子系统(二)
巴西世界杯,德国7比1东道主,那个惨不忍睹啊,早上起来看新闻,第一眼看到7:1还以为点球也能踢成这样,后来想想,点球对多嘛6比1啊,接着就是各种新闻铺天盖地的来了.其实失败并没有什么,人生若是能够成功 ...
- 初探linux子系统集之led子系统(一)
就像学编程第一个范例helloworld一样,学嵌入式,单片机.fpga之类的第一个范例就是点亮一盏灯.对于庞大的linux系统,当然可以编写一个字符设备驱动来实现我们需要的led灯,也可以直接利用g ...
- arm Linux 驱动LED子系统 测试
Linux内核在3.0以上引入了设备树概念(具体哪个版本不清楚)在编译内核后需要将与之对应的dtb文件也下载人板子上才能使内核与硬件关联起来. dtb文件是有dts文件编译后生成的:例如 /* * C ...
- 初探linux子系统集之led子系统(二)【转】
本文转载自:http://blog.csdn.net/eastmoon502136/article/details/37606487 巴西世界杯,德国7比1东道主,那个惨不忍睹啊,早上起来看新闻,第一 ...
- 初探linux子系统集之led子系统(一)【转】
本文转载自:http://blog.csdn.net/eastmoon502136/article/details/37569789 就像学编程第一个范例helloworld一样,学嵌入式,单片机.f ...
- 【linux】led子系统
目录 前言 linux子系统 led子系统 led子系统实战-系统调用-ARM平台 前言 接下来记录的是 led子系统 目前不涉及驱动源码 linux子系统 在 Linux 系统中 绝大多数硬件设备都 ...
- 初探linux子系统集之led子系统(三)
世界杯结束了,德国战车夺得了大力神杯,阿根廷最终还是失败了.也许3年,5年,或者10年后,人们就不知道巴西世界杯的亚军是谁,但是总是会记得冠军是谁.就像什么考试,比赛,第一永远会被人们所记住,所以我们 ...
随机推荐
- MFC中 编辑框输入换行功能
首先修改编辑框的属性: Multiline 设为true , Auto HScroll 设为true , Auto VScroll 设为 true . 然后响应PreTranslateMessage( ...
- python+tesseract验证码识别的一点小心得
由于公司需要,最近开始学习验证码的识别 我选用的是tesseract-ocr进行识别,据说以前是惠普公司开发的排名前三的,现在开源了.到目前为止已经出到3.0.2了 当然了,前期我们还是需要对验证码进 ...
- iOS开发--从TQRichTextViewDemo中学会分析project
下载地址: http://code4app.com/ios/TQRichTextView/5244fe9c6803fa0862000000 1.首先找到AppDelegate类.不管一个project ...
- git错误解决 -- 小结
1.今天 当我 执行 Git add somefile 的时候,出现 如下 错误: If no other git process is currently running, this prob ...
- Android性能优化Google课程翻译一:Render----OverDraw实战
Context 近期实战了下OverDraw,加深了下理解.在上篇文章里Android性能优化Google课程翻译一:Render----OverDraw 写过详细方法. OverDraw解决方法离不 ...
- 【小程序】微信小程序开发实践
帐号相关流程 注册范围 企业 政府 媒体 其他组织 换句话讲就是不让个人开发者注册. :) 填写企业信息 不能使用和之前的公众号账户相同的邮箱,也就是说小程序是和微信公众号一个层级的. 填写公司机构信 ...
- sql执行顺序图
http://www.16aspx.com/cmsimages/20130325/664845013.png
- 如何将数据导入到hive中
可以通过多种方式将数据导入hive表 1.通过外部表导入 用户在hive上建external表,建表的同时指定hdfs路径,在数据拷贝到指定hdfs路径的同时,也同时完成数据插入external表. ...
- HTTP状态码中301与302的区别
301 Moved Permanently 被请求的资源已永久移动到新位置,并且将来任何对此资源的引用都应该使用本响应返回的若干个URI之一.如果可能,拥有链接编辑功能的客户端应当自动把请求的地址修改 ...
- 【Linux】 awk应用
1 统计机器上处于不同状态的所有TCP连接的个数(TCP连接是有状态连接,包含SYN_RECV, ESTABLISHED, TIME_WAIT, FIN_WAIT0, FIN_WAIT1等多种状态, ...