zoukankan      html  css  js  c++  java
  • linux led子系统(一)

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

             linux的led子系统的源码路径:

    1. include/Linux/leds.h    //头文件
    2. drivers/leds              //led子系统相关源码以及API
    首先看一下led子系统中的主要文件:
    1. # LED Core 
    2. obj-$(CONFIG_NEW_LEDS)                        +=led-core.o 
    3. obj-$(CONFIG_LEDS_CLASS)                 += led-class.o 
    4. obj-$(CONFIG_LEDS_TRIGGERS)              +=led-triggers.o 
    5. # LED PlatformDrivers 
    6. obj-$(CONFIG_LEDS_GPIO)                        += leds-gpio.o 
    7. # LED Triggers 
    8. obj-$(CONFIG_LEDS_TRIGGER_TIMER) +=ledtrig-timer.o 
    9. obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK)      +=ledtrig-ide-disk.o 
    10. obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) +=ledtrig-heartbeat.o 
    11. obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) +=ledtrig-backlight.o 
    12. obj-$(CONFIG_LEDS_TRIGGER_GPIO)              +=ledtrig-gpio.o 
    13. obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON)        += ledtrig-default-on.o 
    主要由leds.h、led-core.c、led-class.c、led-triggers.c,其中led-triggers又分为了timer、ide-disk、heartbeat、backlight、gpio、default-on等算法。

    例子程序是leds-gpio,接下去会主要分析这个驱动实现。

    首先简单看一下主要的文件

    leds.h

    Led的亮度,分为三等级,关、中间、最亮。

    enum led_brightness {
        LED_OFF        = 0,        //全暗
        LED_HALF    = 127,        //一半亮度
        LED_FULL    = 255,        //最大亮度
    };

    struct led_classdev {
        const char        *name;         //led名字
        int             brightness;    //当前亮度
        int             max_brightness;//参考值,最大亮度
        int             flags;            //标志,目前只支持 LED_SUSPENDED和LED_CORE_SUSPENDRESUME

        /* Lower 16 bits reflect status */
    #define LED_SUSPENDED        (1 << 0)
        /* Upper 16 bits reflect control information */
    #define LED_CORE_SUSPENDRESUME    (1 << 16)

        /* Set LED brightness level */
        /* Must not sleep, use a workqueue if needed */
        //核心回调函数,当设置/sys/class/leds/下的led接口里的brightness(亮度)属性文件时,会回调该函数
        void        (*brightness_set)(struct led_classdev *led_cdev,
                          enum led_brightness brightness); //亮度设置函数指针
        /* Get LED brightness level */
        //核心回调函数,当获得led当前亮度值时会调用
        enum led_brightness (*brightness_get)(struct led_classdev *led_cdev);//获取亮度函数指针

        /*
         * Activate hardware accelerated blink, delays are in milliseconds
         * and if both are zero then a sensible default should be chosen.
         * The call should adjust the timings in that case and if it can't
         * match the values specified exactly.
         * Deactivate blinking again when the brightness is set to a fixed
         * value via the brightness_set() callback.
         */
        /* 激活硬件加速的闪烁 */
        int        (*blink_set)(struct led_classdev *led_cdev,
                         unsigned long *delay_on,
                         unsigned long *delay_off);//闪烁时点亮和熄灭的时间设置 
        //嵌入的标准设备模型
        struct device        *dev;
        /* 所有已经注册的led_class dev使用这个节点串联起来 */
        struct list_head     node;            /* LED Device list */ //leds-list的node
        /* 默认触发器 */
        const char        *default_trigger;    /* Trigger to use */ //默认trigger的名字

        unsigned long         blink_delay_on, blink_delay_off;     //闪烁的开关时间 
        struct timer_list     blink_timer;                          //闪烁的定时器链表
        int             blink_brightness;                                //闪烁的亮度
    //如果配置内核时使能了触发器功能,才会编译下面一段
    #ifdef CONFIG_LEDS_TRIGGERS
        /* Protects the trigger data below */
        struct rw_semaphore     trigger_lock; /* 这个读写锁保护下面的触发器数据 */

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

    struct led_trigger {
        const char     *name;             //trigger名字
        void        (*activate)(struct led_classdev *led_cdev);//激活led,led_classdev和触发器建立连接时会调用这个方法。
        void        (*deactivate)(struct led_classdev *led_cdev);//取消激活。led_classdev和触发器取消连接时会调用这个方法。

        /* LEDs under control by this trigger (for simple triggers) */
         /* 本触发器控制之下的led链表 */
        rwlock_t      leddev_list_lock; //保护链表的锁
        struct list_head  led_cdevs;    //链表头

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


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

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

    /* For the leds-gpio driver */
    //平台设备相关的gpio led数据结构
    struct gpio_led {
        const char *name;                //led的名字 
        const char *default_trigger;     //默认的trigger 
        unsigned     gpio;                 //gpio口
        unsigned    active_low : 1;
        unsigned    retain_state_suspended : 1;
        unsigned    default_state : 2;
        /* default_state should be one of LEDS_GPIO_DEFSTATE_(ON|OFF|KEEP) */
    };
    #define LEDS_GPIO_DEFSTATE_OFF        0
    #define LEDS_GPIO_DEFSTATE_ON        1
    #define LEDS_GPIO_DEFSTATE_KEEP        2

    struct gpio_led_platform_data {
        int         num_leds;            //led的个数
        const struct gpio_led *leds;    //平台设备相关的gpio led数据结构

    #define GPIO_LED_NO_BLINK_LOW    0    /* No blink GPIO state low */
    #define GPIO_LED_NO_BLINK_HIGH    1    /* No blink GPIO state high */
    #define GPIO_LED_BLINK        2    /* Please, blink */
        int        (*gpio_blink_set)(unsigned gpio, int state,
                        unsigned long *delay_on,
                        unsigned long *delay_off);
    };

    led-core.c

    //主要声明led的链表和锁
    22 DECLARE_RWSEM(leds_list_lock);
    23 EXPORT_SYMBOL_GPL(leds_list_lock);
    25 LIST_HEAD(leds_list);
    26 EXPORT_SYMBOL_GPL(leds_list);
                          

    led-class.c

    1、  leds_init

    主要是创建leds_class,赋值suspend和resume以及dev_attrs。

    led_class_attrs

    84 static struct device_attribute led_class_attrs[] = {
    85     __ATTR(brightness, 0644, led_brightness_show, led_brightness_store),
    86     __ATTR(max_brightness, 0444, led_max_brightness_show, NULL),
    87 #ifdef CONFIG_LEDS_TRIGGERS
    88     __ATTR(trigger, 0644, led_trigger_show, led_trigger_store),
    89 #endif
    90     __ATTR_NULL,
    91 };

    2、led_classdev_register

             创建classdev设备,也即Leds_class类中实例化一个对象,类似于c++的new一个对象,leds有很多种,而这里是注册一个特定的led,内核中的面向对象思想也极其丰富。

             加到leds_list链表中,初始化blinktimer,指定blink_timer的function和data,设置trigger,然后一个新的led设备就注册好了,就可以使用了。

    led-triggers.c

    1、led_trigger_register

             扫描trigger链表中是否有同名的trigger,接着把当前trigger加入到链表中,如果led_classdev中有默认的trigger,那么就设置这个默认的。

    好了,简单看了下led子系统中比较重要的结构体和函数,那么接下去就可以通过leds-gpio这个驱动来进一步了解led子系统了。

  • 相关阅读:
    第四章之Hadoop I/O
    第五章之MapReduce应用开发
    数据预处理
    SQL Server Migration Assistant for MySQL!
    【转载】.NET设计模式之工厂方法模式(Factory Method)
    "lc.exe"已退出 代码为1 的解决方法
    【转载】.NET设计模式之抽象工厂模式(Abstract Factory)
    【转载】(收藏)《博客园精华集》分类索引
    【转载】.NET设计模式之观察者模式(Observer Pattern)
    【转载】使用Visual Studio 2010调试断点不起作用的问题解决办法(AutoCAD)
  • 原文地址:https://www.cnblogs.com/xuyh/p/4921334.html
Copyright © 2011-2022 走看看