enum led_brightness { LED_OFF = 0, LED_HALF = 127, LED_FULL = 255, };
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; };
struct led_info { const char *name; char *default_trigger; int flags; }; struct led_platform_data { int num_leds; struct led_info *leds; };
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); };
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);
void led_classdev_unregister(struct led_classdev *led_cdev);
註銷所作的工做和註冊相反。node
void led_classdev_suspend(struct led_classdev *led_cdev)
從掛起中恢復:linux
void led_classdev_resume(struct led_classdev *led_cdev)
/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_show
和led_brightness_store
分別負責顯示和設置亮度,用戶控件經過函數
/sys/class/leds/<device>/brightness
查看和設置亮度就是和這兩個函數交互的。指針
led_trigger_show
用於讀取當前觸發器的名字,led_trigger_store
用於指定觸發器的名字,code
它會尋找全部已註冊的觸發器,找到同名的並設置爲當前led的觸發器。orm
/sys/class/leds/<device>/trigger
用於用戶空間查看和設置觸發器。接口
led_classdev_register
註冊的struct led_classdev
會被加入leds_list
鏈表,這個鏈表定義在driver/leds/led-core.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);
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硬盤,也能夠是系統心跳等事件。