首页 > 系统相关 >初探linux子系统集之led子系统(二)

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

时间:2023-01-15 15:05:15浏览次数:39  
标签:led trig trigger cdev linux heartbeat data 子系统


 

         巴西世界杯,德国7比1东道主,那个惨不忍睹啊,早上起来看新闻,第一眼看到7:1还以为点球也能踢成这样,后来想想,点球对多嘛6比1啊,接着就是各种新闻铺天盖地的来了。其实失败并没有什么,人生若是能够成功一次,那么再多的失败也是值得的,脚踏实地,失败了再次爬起来。很多时候,在一切都那么顺利的情况下,反而觉得没有啥意思,有一些挑战,一些失败,一些打击,接着,就会很努力很努力地去做,慢慢地就会被自己征服,很喜欢这种感受,废话说多了,还是接着研究led子系统吧。

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

1、default-on

<pre name="code" class="html">static voiddefon_trig_activate(struct led_classdev *led_cdev)
{
led_set_brightness(led_cdev,led_cdev->max_brightness);
}

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

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

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





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

 

2、backlight

struct bl_trig_notifier {
structled_classdev *led; //led子系统设备
intbrightness; //亮度
intold_status;
structnotifier_block notifier; //内核通知链
unsignedinvert;
};

static struct led_trigger bl_led_trigger ={
.name = "backlight",
.activate = bl_trig_activate,
.deactivate = bl_trig_deactivate
};
static void bl_trig_activate(structled_classdev *led)
{
intret;

structbl_trig_notifier *n;

n= kzalloc(sizeof(struct bl_trig_notifier), GFP_KERNEL);
led->trigger_data= n;
if(!n) {
dev_err(led->dev,"unable to allocate backlight trigger\n");
return;
}

ret= device_create_file(led->dev, &dev_attr_inverted);
if(ret)
gotoerr_invert;

n->led= led;
n->brightness= led->brightness;
n->old_status= UNBLANK;
n->notifier.notifier_call= fb_notifier_callback;

ret= fb_register_client(&n->notifier);
if(ret)
dev_err(led->dev,"unable to register backlight trigger\n");

return;

err_invert:
led->trigger_data= NULL;
kfree(n);
}



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

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

 

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

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

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

 

 

static int fb_notifier_callback(struct notifier_block *p,
unsignedlong event, void *data)
{
structbl_trig_notifier *n = container_of(p,
structbl_trig_notifier, notifier);
struct led_classdev*led = n->led;
struct fb_event*fb_event = data;
int *blank =fb_event->data;
int new_status =*blank ? BLANK : UNBLANK;

switch (event) {
case FB_EVENT_BLANK :
if(new_status == n->old_status)
break;

if((n->old_status == UNBLANK) ^ n->invert) {
n->brightness= led->brightness;
led_set_brightness(led,LED_OFF);
} else {
led_set_brightness(led,n->brightness);
}

n->old_status= new_status;

break;
}

return 0;
}


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

 

3、timer

static structled_trigger timer_led_trigger = {
.name = "timer",
.activate =timer_trig_activate,
.deactivate =timer_trig_deactivate,
};

static voidtimer_trig_activate(struct led_classdev *led_cdev)
{
int rc;

led_cdev->trigger_data= NULL;

rc =device_create_file(led_cdev->dev, &dev_attr_delay_on);
if (rc)
return;
rc =device_create_file(led_cdev->dev, &dev_attr_delay_off);
if (rc)
gotoerr_out_delayon;

led_blink_set(led_cdev,&led_cdev->blink_delay_on,
&led_cdev->blink_delay_off);

led_cdev->trigger_data= (void *)1;

return;

err_out_delayon:
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

static structled_trigger heartbeat_led_trigger = {
.name = "heartbeat",
.activate =heartbeat_trig_activate,
.deactivate = heartbeat_trig_deactivate,
};

structheartbeat_trig_data {
unsigned int phase;
unsigned int period;
struct timer_listtimer;
};

static voidheartbeat_trig_activate(struct led_classdev *led_cdev)
{
structheartbeat_trig_data *heartbeat_data;

heartbeat_data =kzalloc(sizeof(*heartbeat_data), GFP_KERNEL);
if (!heartbeat_data)
return;

led_cdev->trigger_data= heartbeat_data;
setup_timer(&heartbeat_data->timer,
led_heartbeat_function, (unsigned long)led_cdev);
heartbeat_data->phase= 0;
led_heartbeat_function(heartbeat_data->timer.data);
}



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

static voidled_heartbeat_function(unsigned long data)
{
struct led_classdev*led_cdev = (struct led_classdev *) data;
structheartbeat_trig_data *heartbeat_data = led_cdev->trigger_data;
unsigned longbrightness = LED_OFF;
unsigned long delay =0;

/* acts like anactual heart beat -- ie thump-thump-pause... */
switch(heartbeat_data->phase) {
case 0:
/*
* The hyperbolic function below modifies the
* heartbeat period length in dependency of the
* current (1min) load. It goes through thepoints
* f(0)=1260, f(1)=860, f(5)=510,f(inf)->300.
*/
heartbeat_data->period= 300 +
(6720<< FSHIFT) / (5 * avenrun[0] + (7 << FSHIFT));
heartbeat_data->period=
msecs_to_jiffies(heartbeat_data->period);
delay =msecs_to_jiffies(70);
heartbeat_data->phase++;
brightness =led_cdev->max_brightness;
break;
case 1:
delay =heartbeat_data->period / 4 - msecs_to_jiffies(70);
heartbeat_data->phase++;
break;
case 2:
delay =msecs_to_jiffies(70);
heartbeat_data->phase++;
brightness =led_cdev->max_brightness;
break;
default:
delay =heartbeat_data->period - heartbeat_data->period / 4 -
msecs_to_jiffies(70);
heartbeat_data->phase= 0;
break;
}

led_set_brightness(led_cdev,brightness);
mod_timer(&heartbeat_data->timer,jiffies + delay);
}



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

 

5、ide-disk

static voidledtrig_ide_timerfunc(unsigned long data)
{
if (ide_lastactivity!= ide_activity) {
ide_lastactivity =ide_activity;
/* INT_MAX will seteach LED to its maximum brightness */
led_trigger_event(ledtrig_ide,INT_MAX);
mod_timer(&ledtrig_ide_timer,jiffies + msecs_to_jiffies(10));
} else {
led_trigger_event(ledtrig_ide,LED_OFF);
}
}

static int __initledtrig_ide_init(void)
{
led_trigger_register_simple("ide-disk",&ledtrig_ide);
return 0;
}


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


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

标签:led,trig,trigger,cdev,linux,heartbeat,data,子系统
From: https://blog.51cto.com/u_15940062/6008704

相关文章

  • 和菜鸟一起学linux总线驱动之i2c死锁问题
        不知不觉中已经有好几个月没有写点东西了,懒了就是懒了,说是忙着想把产品做得更好,都是借口,每天花一点时间来写点东西确实很不错,自己也坚持了很久很久,只不过今年以......
  • 初探linux子系统集之led子系统(一)
         就像学编程第一个范例helloworld一样,学嵌入式,单片机、fpga之类的第一个范例就是点亮一盏灯。对于庞大的linux系统,当然可以编写一个字符设备驱动来实现我们需......
  • 和菜鸟一起学linux之initramfs方式启动
    关于initramfs       initramfs在编译内核的同时被编译并与内核连接成一个文件,它被链接到地址__initramfs_start处,与内核同时被加载到ram中。initramfs被解析处理后......
  • AndroidThings学习笔记--gpio控制Led和Button
    1.了解androidthings的框架  Androidthings框架,其实和android原生区别不是非常的大。如下图所示:  AndroidThings扩展了一些硬件相关的api,比如外设io的api,以及用户驱......
  • Linux后台运行
    title:Linux后台运行date:2022-09-0312:51:35tags:-Linuxcategories:-Linux如何后台运行脚本方法1:nohup在执行命令前面加nohup但是CTRL+C就......
  • 和菜鸟一起学linux之常见错误的解决和常用命令
    1、错误提示:make:警告:检测到时钟错误。您的创建可能是不完整的。   解决方法:当前编译目录下,命令行输入:find.-typef-exectouch{}\;2、SSH生成密钥:ssh-keygen;SSH......
  • 初探linux子系统集之写在前言
                           ......
  • 和菜鸟一起学linux内核之初始化init篇
    注:以下大部分内容摘自linux内核编程入门篇和linux内核完全注释      初始化init下只有一个main函数。      首先利用setup.s程序取得的程序参数设置系统的根......
  • CUDNN_STATUS_EXECUTION_FAILED 错误原因:显卡版本和cuda版本不匹配
    又是寄人篱下使用服务器的一天...造成错误的过程:跑实验需要装一个新的虚拟环境来使用cuda,别人的readme上面要用torh1.3,搜了一下教程,适配的cuda版本是10.1,目前显卡支持......
  • linux/windows查看端口被占用情况
    linux下查看端口被占用情况1.可以通过"~$netstat-anp"来查看哪些端口被打开。(注:加参数'-n'会将应用程序转为端口显示,即数字格式的地址,2.然后可以通过"~$lsof-i:$POR......