linux led子系统(二)

对于led子系统中,有那么多得trigger,下面就来简单了解下。

1、default-on

static void defon_trig_activate(struct led_classdev *led_cdev)
{
    led_set_brightness(led_cdev, led_cdev->max_brightness);
}

static struct led_trigger defon_led_trigger = {
    .name     = "default-on",
    .activate = defon_trig_activate,
};

static int __init defon_trig_init(void)
{
    return led_trigger_register(&defon_led_trigger);
}

static void __exit defon_trig_exit(void)
{
    led_trigger_unregister(&defon_led_trigger);
}

Default-on主要是设置led为最大亮度。

 

2、backlight

  1. struct bl_trig_notifier { 
  2.          structled_classdev *led;       //led子系统设备 
  3.          intbrightness;               //亮度 
  4.          intold_status; 
  5.          structnotifier_block notifier;    //内核通知链 
  6.          unsignedinvert; 
  7. }; 
  8. static struct led_trigger bl_led_trigger ={ 
  9. .name                = "backlight", 
  10. .activate  = bl_trig_activate, 
  11. .deactivate       = bl_trig_deactivate
  12. }; 
  13. static void bl_trig_activate(structled_classdev *led) 
  14.          intret; 
  15.          structbl_trig_notifier *n; 
  16. n= kzalloc(sizeof(struct bl_trig_notifier), GFP_KERNEL); 
  17.          led->trigger_data= n; 
  18.          if(!n) { 
  19.                    dev_err(led->dev,"unable to allocate backlight trigger\n"); 
  20.                    return; 
  21.          } 
  22. ret= device_create_file(led->dev, &dev_attr_inverted); 
  23.          if(ret) 
  24.                    gotoerr_invert; 
  25.          n->led= led; 
  26.          n->brightness= led->brightness; 
  27.          n->old_status= UNBLANK; 
  28.          n->notifier.notifier_call= fb_notifier_callback; 
  29. ret= fb_register_client(&n->notifier); 
  30.          if(ret) 
  31.                    dev_err(led->dev,"unable to register backlight trigger\n"); 
  32.          return; 
  33. err_invert: 
  34.          led->trigger_data= NULL; 
  35.          kfree(n); 

其中fb_register_client注册到了framebuffer中的fb_notifier_list中,一旦framebuffer驱动中有事件,就会调用内核通知链中注册好的函数fb_notifier_callback。

关于内核通知链,这里就插播一曲来自网络的摘抄了:

大多数内核子系统都是相互独立的,因此某个子系统可能对其它子系统产生的事件感兴趣。为了满足这个需求,也即是让某个子系统在发生某个事件时通知其它的子系统,Linux内核提供了通知链的机制。通知链表只能够在内核的子系统之间使用,而不能够在内核与用户空间之间进行事件的通知。

通知链表是一个函数链表,链表上的每一个节点都注册了一个函数。当某个事情发生时,链表上所有节点对应的函数就会被执行。所以对于通知链表来说有一个通知方与一个接收方。在通知这个事件时所运行的函数由被通知方决定,实际上也即是被通知方注册了某个函数,在发生某个事件时这些函数就得到执行。其实和系统调用signal的思想差不多。

通知链技术可以概括为:事件的被通知者将事件发生时应该执行的操作通过函数指针方式保存在链表(通知链)中,然后当事件发生时通知者依次执行链表中每一个元素的回调函数完成通知。

  1. static int fb_notifier_callback(struct notifier_block *p, 
  2.                                      unsignedlong event, void *data) 
  3.          structbl_trig_notifier *n = container_of(p, 
  4.                                                structbl_trig_notifier, notifier); 
  5.          struct led_classdev*led = n->led; 
  6.          struct fb_event*fb_event = data; 
  7.          int *blank =fb_event->data; 
  8.          int new_status =*blank ? BLANK : UNBLANK; 
  9.          switch (event) { 
  10.          case FB_EVENT_BLANK : 
  11.                    if(new_status == n->old_status) 
  12.                             break; 
  13.                    if((n->old_status == UNBLANK) ^ n->invert) { 
  14.                             n->brightness= led->brightness; 
  15.                             led_set_brightness(led,LED_OFF); 
  16.                    } else { 
  17.                             led_set_brightness(led,n->brightness); 
  18.                    } 
  19.                    n->old_status= new_status; 
  20.                    break; 
  21.          } 
  22.          return 0; 
  23. }  

如果触发了FB_EVENT_BLANK,那么就执行相应的操作。

 

 

3、timer

  1. static structled_trigger timer_led_trigger = { 
  2. .name     = "timer", 
  3. .activate =timer_trig_activate, 
  4. .deactivate =timer_trig_deactivate, 
  5. }; 
  6. static voidtimer_trig_activate(struct led_classdev *led_cdev) 
  7.                            int rc; 
  8.                            led_cdev->trigger_data= NULL; 
  9. rc =device_create_file(led_cdev->dev, &dev_attr_delay_on); 
  10.                            if (rc) 
  11.                             return; 
  12. rc =device_create_file(led_cdev->dev, &dev_attr_delay_off); 
  13.                            if (rc) 
  14.                             gotoerr_out_delayon; 
  15.                            led_blink_set(led_cdev,&led_cdev->blink_delay_on, 
  16.                                   &led_cdev->blink_delay_off); 
  17.                            led_cdev->trigger_data= (void *)1; 
  18.                            return; 
  19. err_out_delayon: 
  20.                            device_remove_file(led_cdev->dev,&dev_attr_delay_on); 

当某个led_classdev与之连接后,这个触发器会在/sys/class/leds/<device>/下创建两个文件delay_on和delay_off。用户空间往这两个文件中写入数据后,相应的led会按照设置的高低电平的时间(ms)来闪烁。如果led_classdev注册了硬件闪烁的接口led_cdev->blink_set就是用硬件控制闪烁,否则用软件定时器来控制闪烁。

 

4、heatbeat

  1. static structled_trigger heartbeat_led_trigger = { 
  2. .name     = "heartbeat", 
  3. .activate =heartbeat_trig_activate, 
  4. .deactivate = heartbeat_trig_deactivate, 
  5. }; 
  6. structheartbeat_trig_data { 
  7.                            unsigned int phase; 
  8.                            unsigned int period; 
  9.                            struct timer_listtimer; 
  10. }; 
  11. static voidheartbeat_trig_activate(struct led_classdev *led_cdev) 
  12.                            structheartbeat_trig_data *heartbeat_data; 
  13. heartbeat_data =kzalloc(sizeof(*heartbeat_data), GFP_KERNEL); 
  14.                            if (!heartbeat_data) 
  15.                             return; 
  16.                            led_cdev->trigger_data= heartbeat_data; 
  17.                            setup_timer(&heartbeat_data->timer, 
  18.                                 led_heartbeat_function, (unsigned long)led_cdev); 
  19.                            heartbeat_data->phase= 0; 
  20.                            led_heartbeat_function(heartbeat_data->timer.data); 

设置了heartbeat_data->phase,然后调用led_heartbeat_function。

  1. static voidled_heartbeat_function(unsigned long data) 
  2.                            struct led_classdev*led_cdev = (struct led_classdev *) data; 
  3.                            structheartbeat_trig_data *heartbeat_data = led_cdev->trigger_data; 
  4.                            unsigned longbrightness = LED_OFF; 
  5.                            unsigned long delay =0; 
  6.                            /* acts like anactual heart beat -- ie thump-thump-pause... */ 
  7.                            switch(heartbeat_data->phase) { 
  8.                            case 0: 
  9.                             /* 
  10.                              * The hyperbolic function below modifies the 
  11.                              * heartbeat period length in dependency of the 
  12.                              * current (1min) load. It goes through thepoints 
  13.                              * f(0)=1260, f(1)=860, f(5)=510,f(inf)->300. 
  14.                              */ 
  15.                             heartbeat_data->period= 300 + 
  16.                                      (6720<< FSHIFT) / (5 * avenrun[0] + (7 << FSHIFT)); 
  17.                             heartbeat_data->period= 
  18. msecs_to_jiffies(heartbeat_data->period); 
  19. delay =msecs_to_jiffies(70); 
  20.                             heartbeat_data->phase++; 
  21. brightness =led_cdev->max_brightness; 
  22.                             break; 
  23.                            case 1: 
  24. delay =heartbeat_data->period / 4 - msecs_to_jiffies(70); 
  25.                             heartbeat_data->phase++; 
  26.                             break; 
  27.                            case 2: 
  28. delay =msecs_to_jiffies(70); 
  29.                             heartbeat_data->phase++; 
  30. brightness =led_cdev->max_brightness; 
  31.                             break; 
  32.                            default: 
  33. delay =heartbeat_data->period - heartbeat_data->period / 4 - 
  34.                                      msecs_to_jiffies(70); 
  35.                             heartbeat_data->phase= 0; 
  36.                             break; 
  37.                            } 
  38.                            led_set_brightness(led_cdev,brightness); 
  39.                            mod_timer(&heartbeat_data->timer,jiffies + delay); 

通过定时来实现类似于心跳的led灯。

5、ide-disk

  1. static voidledtrig_ide_timerfunc(unsigned long data) 
  2.                            if (ide_lastactivity!= ide_activity) { 
  3. ide_lastactivity =ide_activity; 
  4.                             /* INT_MAX will seteach LED to its maximum brightness */ 
  5.                             led_trigger_event(ledtrig_ide,INT_MAX); 
  6.                             mod_timer(&ledtrig_ide_timer,jiffies + msecs_to_jiffies(10)); 
  7.                            } else { 
  8.                             led_trigger_event(ledtrig_ide,LED_OFF); 
  9.                            } 
  10. static int __initledtrig_ide_init(void) 
  11.                            led_trigger_register_simple("ide-disk",&ledtrig_ide); 
  12.                            return 0; 

通过定时器实现类似于硬盘灯的指示。

     以上便是led子系统中的trigger的一些简单介绍。

时间: 2024-10-26 08:30:32

linux led子系统(二)的相关文章

linux led子系统(一)

就像学编程第一个范例helloworld一样,学嵌入式,单片机.fpga之类的第一个范例就是点亮一盏灯.对于庞大的linux系统,当然可以编写一个字符设备驱动来实现我们需要的led灯,也可以直接利用gpio口,应用程序来拉高拉低管脚控制.不过,既然linux系统自己本来就带有led子系统,那么就可以好好利用之.好处不用多说了,主要对于应用层来说,不同平台都用linux的led子系统,那么应用程序不用做任何的改变,就可以在新的平台上运行,可移植性好.          linux的led子系统的源

Linux时间子系统(二) 软件架构

一.前言 本文的主要内容是描述内核时间子系统的软件框架.首先介绍了从旧的时间子系统迁移到新的时间子系统的源由,介绍新的时间子系统的优势.第三章汇整了时间子系统的相关文件以及内核配置.最后描述各种内核配置下的时间子系统的数据流和控制流. 二.背景介绍 1.传统内核时间子系统的软件架构 让我们先回到远古的2.4内核时代,其内核的时间子系统的软件框架如下: 首先,在每个architecture相关的代码中要有实现clock event和clock source模块.这里听起来名字是高大上,实际上,这里

linux设备模型之led子系统(转载)

linux设备模型之led子系统 本文来自转载: http://www.cnblogs.com/gdt-a20 时代不同了,连led都成子系统了,针对内核提供的通用模型,分析一下,好久没写文章了也! 代码位于drivers/leds下,看一下Makefile 模型文件主要是: # LED Core obj-$(CONFIG_NEW_LEDS)            += led-core.o obj-$(CONFIG_LEDS_CLASS)        += led-class.o obj-$

arm Linux 驱动LED子系统 测试

Linux内核在3.0以上引入了设备树概念(具体哪个版本不清楚)在编译内核后需要将与之对应的dtb文件也下载人板子上才能使内核与硬件关联起来. dtb文件是有dts文件编译后生成的:例如 /* * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ * * This program is free software; you can redistribute it and/or modify * it un

Linux usb子系统(二):USB设备驱动usb-skeleton.c

usb驱动分为通过usbfs操作设备的用户空间驱动,内核空间的内核驱动.两者不能同时进行,否则容易引发对共享资源访问的问题,死锁!使用了内核驱动,就不能在usbfs里驱动该设备. 下面转载的一篇分析usb-skeleton.c文章. 初次接触与OS相关的设备驱动编写,感觉还挺有意思的,为了不至于忘掉看过的东西,笔记跟总结当然不可缺,更何况我决定为嵌入式卖命了.好,言归正传,我说一说这段时间的收获,跟大家分享一下Linux的驱动开发.但这次只先针对Linux的USB子系统作分析,因为周五研讨老板催

Linux usb子系统(一):子系统架构

摘自:http://www.360doc.com/content/15/0519/05/22854460_471598740.shtml 摘自:https://www.cnblogs.com/cslunatic/p/3726053.html Linux usb子系统(一):子系统架构 一.USB协议基础知识   前序:USB概念概述 USB1.0版本速度1.5Mbps(低速USB) USB1.1版本速度12Mbps(全速USB)  USB2.0版本速度480Mbps(高速USB). USB 分为

linux中断子系统:中断号的映射与维护

写在前沿: 好久好久没有静下心来整理一些东西了,开始工作已有一个月,脑子里想整理的东西特别多.记录是一种很好的自我学习方式,静下来多思考多总结,三年的工作目标不能发生变化,作为职场菜鸟即将进入全世界半导体第一的Intel working,是机遇更是一种挑战,困难也是可想而知.脚踏实地.仰望星空,以结果为导向,以目标为准则,争取每天进步一点点. Linux内核版本:3.4.39 一. linux中断子系统的irq_desc初始化 linux内核最初的中断初始化过程入口为start_kernel.在

20150303 IMX257 输入子系统(二)之键盘模拟

20150303 IMX257 输入子系统(二)之键盘模拟 2015-03-03 李海沿 前面我们已经详细介绍了基本的知识:地址http://www.cnblogs.com/lihaiyan/p/4309329.html 接下来,我们使用IMX257的IO引脚中断+Linux输入子系统实现一个模拟键盘按键.实现的效果是,我们使用IO模拟按键L.按键S和Enter键 这三个按键. 这次我们就不再多废话了,直接上程序,大家看代码: 实验效果图: 如图所示: 我们依次按下三个按键 第一个按键 显示的键

arm linux 启动之二:start_kernel到创建1号进程

本文介绍arm linux启动的第二部分,C语言编写,主要讲述start_kernel到1号进程的创建.主要讲述大概过程,以后再对子函数进行讲解. 一.start_kernel start_kernel位于init/main.c,主要完成linux一些子系统的初始化. 1)smp_setup_processor_id() 单CPU位为空. 2)lock_kernel() 锁CPU,linux是支持抢占的,多CPU时调用这个函数防止其他CPU抢占.3)tick_init() 时间相关初始化4)bo