您的位置:首页 > 运维架构 > Linux

linux 驱动之led子系统(一)

2015-09-25 11:29 639 查看
linux系统基于3.4

平台msm8x26

android 4.4.2

linux 中存在众多的子系统,包括led子系统,input子系统等等,那么就先从最简单的led子系统开始分析了。这次要尽量分析彻底。

在andorid中的led系统是在\kernel\drivers\leds,在经常分析代码的过程中,首先需要看的是Kconfig和makefile文件,那好先看Kconfig

menuconfig NEW_LEDS
bool "LED Support"
help
Say Y to enable Linux LED support.  This allows control of supported
LEDs from both userspace and optionally, by kernel events (triggers).

This is not related to standard keyboard LEDs which are controlled
via the input system.
if NEW_LEDS

config LEDS_CLASS
tristate "LED Class Support"
help
 This option enables the led sysfs class in /sys/class/leds.  You'll
 need this to do anything useful with LEDs.  If unsure, say N.


这类似于在linux系统执行make menuconfig,首先是NEW_LEDS,看注释就是说必须使能LED Support,才能有所谓的平台的led的支持。这些一般是支持的,而且一般的平台也是会使能的,高通平台上有Msm_defconfig (arch\arm\configs),看出来支持新增led以及led的class的。

CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
看到这些的话,应该看出msm平台是支持led的(想想也支持)接下来就是看makefile了

# LED Core
obj-$(CONFIG_NEW_LEDS)			+= led-core.o
obj-$(CONFIG_LEDS_CLASS)		+= led-class.o
obj-$(CONFIG_LEDS_TRIGGERS)		+= led-triggers.o
以上的是和平台无关的,而且从我查找的这些个obj-$(tmp),以上的文件都是会编译的。即led-core.c,led-class.c,led-triggers.c。这三个文件是led子系统的3个重要的文件,配合平台相关的led驱动,构成了一个完整的led子系统。

好,先看led-core.c

在led-core.c中导出了两个接口,一个是用来控制led的闪烁的,以及闪烁的时间,一个接口是用来直接设置led的亮灭的。

void led_blink_set(struct led_classdev *led_cdev,
unsigned long *delay_on,
unsigned long *delay_off)
void led_brightness_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
再看led-class.c,再看这个文件的时候我们再看一下led-class.txt

If you're reading this and thinking about keyboard leds, these are handled by the input subsystem and the led class is *not* needed.
好,说键盘灯是属于input的子系统的,不为led-class所控制。

In its simplest form, the LED class just allows control of LEDs from userspace. LEDs appear in /sys/class/leds/. The maximum brightness of the LED is defined in max_brightness file. The brightness file will set the brightness of the LED (taking a value 0-max_brightness). Most LEDs don't have hardware brightness support so will just be turned on for non-zero brightness settings.
说led-class仅能从用户空间的 /sys/class/leds/控制,而且可以控制最大的亮度,但是一般平台没有硬件控制,所以只能非0控制亮,0控制不亮。

The class also introduces the optional concept of an LED trigger. A trigger is a kernel based source of led events. Triggers can either be simple or complex. A simple trigger isn't configurable and is designed to slot into existing subsystems with minimal additional code. Examples are the ide-disk, nand-disk and sharpsl-charge triggers. With led triggers disabled, the code optimises away.
led子系统还导入了一个LED-trigger的概念,当需要的时候我们需要使能CONFIG_LEDS_TRIGGERS = y,否则不支持。

Complex triggers whilst available to all LEDs have LED specific parameters and work on a per LED basis. The timer trigger is an example. The timer trigger will periodically change the LED brightness between LED_OFF and the current brightness setting. The "on" and "off" time can be specified via /sys/class/leds/<device>/delay_{on,off} in milliseconds. You can change the brightness value of a LED independently of the timer trigger. However, if you set the brightness value to LED_OFF it will also disable the timer trigger.
复杂的led-trigger例如可以更改灭和当前设置的led的亮度之间切换,时间可以通过 /sys/class/leds/<device>/delay_{on,off}接口来控制时间(ms级别)。

You can change triggers in a similar manner to the way an IO scheduler is chosen (via /sys/class/leds/<device>/trigger). Trigger specific parameters can appear in /sys/class/leds/<device> once a given trigger is selected.
可以通过 via /sys/class/leds/<device>/trigger的接口来使用led-trigger。

2.led-class.c 分析

static int __init leds_init(void)
{
leds_class = class_create(THIS_MODULE, "leds");
if (IS_ERR(leds_class))
return PTR_ERR(leds_class);
leds_class->suspend = led_suspend;
leds_class->resume = led_resume;
leds_class->dev_attrs = led_class_attrs;
return 0;
}

static void __exit leds_exit(void)
{
class_destroy(leds_class);
}
led_class 被定义为 static struct class *leds_class;这个类显示在/sys/class/ 下,当调用 class_create(owner, name)函数的时候会在/sys/class/下创建name的目录,这里创建的是leds,同时将led-class中的suspend的指针以及resume的指针初始化了,一般来说是当系统休眠的时候系统上层会层层通知各个设备进入睡眠状态,那么负责这个设备的驱动则实际执行睡眠,例如手机的休眠键位,唤醒时调用的是resume,恢复设备的运行状态,这也是为了省电。即电源管理。其中将dev_attrs初始化为led_class_attrs,其中led_class_attrs为
static struct device_attribute led_class_attrs[] = {
__ATTR(brightness, 0644, led_brightness_show, led_brightness_store),
__ATTR(max_brightness, 0644, led_max_brightness_show,
led_max_brightness_store),
#ifdef CONFIG_LEDS_TRIGGERS
__ATTR(trigger, 0644, led_trigger_show, led_trigger_store),
#endif
__ATTR_NULL,
};
这个作用是在每个设备下创建brightness,max_brightness,trigger(当然得定义CONFIG_LEDS_TRIGGERS)的属性文件,权限是0644,读文件是调用show,写文件时调用store函数。注意最后要加上NULL。

接着分析:在led-class中还导出了几个接口:

int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
当led类设备驱动注册时调用

void led_classdev_unregister(struct led_classdev *led_cdev)
当led类设备驱动注销时调用

void led_classdev_resume(struct led_classdev *led_cdev)
led类设备唤醒时调用

void led_classdev_suspend(struct led_classdev *led_cdev)
led类设备挂起时调用

还有几个关于对设备的属性文件的读写函数的实现。

3.led-trigger.c

这个文件中大部分是接口,用来注册一个trigger,

void led_trigger_register_simple(const char *name, struct led_trigger **tp)
注销一个trigger

void led_trigger_unregister_simple(struct led_trigger *trigger)

led触发闪烁,实际调用的是led-core.c中的led_blink_set函数

void led_trigger_blink(struct led_trigger *trigger,
unsigned long *delay_on,
unsigned long *delay_off)
led出触发亮灭,实际调用的是led-core.c中的led_set_brightness函数

void led_trigger_event(struct led_trigger *trigger,
enum led_brightness brightness)
以上的全是基于led-trigger的简单的接口,就像前面说的txt中。

接下说较为复杂的

涉及使用led-class的时候使用

当对驱动的trigger的属性进行写时调用的接口。

ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
对驱动的trigger的属性进行读的时候调用的接口

ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
char *buf)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: