linux led子系統(一)

就像學編程第一個範例helloworld同樣,學嵌入式,單片機、fpga之類的第一個範例就是點亮一盞燈。對於龐大的linux系統,固然能夠編寫一個字符設備驅動來實現咱們須要的led燈,也能夠直接利用gpio口,應用程序來拉高拉低管腳控制。不過,既然linux系統本身原本就帶有led子系統,那麼就能夠好好利用之。好處不用多說了,主要對於應用層來講,不一樣平臺都用linux的led子系統,那麼應用程序不用作任何的改變,就能夠在新的平臺上運行,可移植性好。node

         linux的led子系統的源碼路徑:linux

  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,接下去會主要分析這個驅動實現。c++

首先簡單看一下主要的文件算法

leds.h編程

Led的亮度,分爲三等級,關、中間、最亮。數據結構

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

 

 

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)this

    /* 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

一、  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 };

二、led_classdev_register

         建立classdev設備,也即Leds_class類中實例化一個對象,相似於c++的new一個對象,leds有不少種,而這裏是註冊一個特定的led,內核中的面向對象思想也極其豐富。

         加到leds_list鏈表中,初始化blinktimer,指定blink_timer的function和data,設置trigger,而後一個新的led設備就註冊好了,就可使用了。

led-triggers.c

一、led_trigger_register

         掃描trigger鏈表中是否有同名的trigger,接着把當前trigger加入到鏈表中,若是led_classdev中有默認的trigger,那麼就設置這個默認的。

好了,簡單看了下led子系統中比較重要的結構體和函數,那麼接下去就能夠經過leds-gpio這個驅動來進一步瞭解led子系統了。

相關文章
相關標籤/搜索