(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);

註銷所作的工做和註冊相反。node

將led掛起:將led的flag設爲LED_SUSPENDED,關閉led.

void led_classdev_suspend(struct led_classdev *led_cdev)

從掛起中恢復:linux

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_showled_brightness_store分別負責顯示和設置亮度,用戶控件經過函數

/sys/class/leds/<device>/brightness查看和設置亮度就是和這兩個函數交互的。指針

led_trigger_show用於讀取當前觸發器的名字,led_trigger_store用於指定觸發器的名字,code

它會尋找全部已註冊的觸發器,找到同名的並設置爲當前led的觸發器。orm

/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硬盤,也能夠是系統心跳等事件。

相關文章
相關標籤/搜索