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硬盘,也能够是系统心跳等事件。