前言:
什么叫做驱动框架?
内核中驱动部分维护者针对每个种类的驱动设计一套成熟的、标准的、典型的驱动实现,并把不同厂家的同类硬件驱动中相同的部分抽出来自己实现好,再把不同部分留出接口给具体的驱动开发工程师来实现,这就叫驱动框架。即标准化的驱动实现,统一管理系统资源,维护系统稳定。
概述:
-
led子系统驱动框架:
-
所有led共性:
有和用户通信的设备节点
亮和灭 -
不同点:
有的led可能是接在gpio管脚上,不同的led有不同的gpio来控制
有的led可能由其他的芯片来控制(节约cpu的pin,或者为了控制led的电流等)
可以设置亮度
可以闪烁
所以Linux中led子系统驱动框架把把所有led的共性给实现了,把不同的地方留给驱动工程师去做.
-
led子系统核心文件:
-
driver/leds/led-class.c
driver/leds/led-core.c
driver/leds/led-triggers.c
include/linux/leds.h
-
辅助文件(也就是说可以根据需求来决定这部分代码是否需要)
-
driver/leds/led-triggers.c
driver/leds/trigger/led-triggers.c
driver/leds/trigger/ledtrig-oneshot.c
driver/leds/trigger/ledtrig-timer.c
driver/leds/trigger/ledtrig-heartbeat.c
代码框架分析
led-class.c(led子系统框架的入口) 和led-core.c
- 会在/sys/class/目录下创建leds类.
- 提供不同led设备往led子系统注册的接口,并在/sys/class/下创建对应的设备节点,并在节点下面创建对应的属性文件,最后提供给应用统一的访问接口(read/write).
当make menuconfig选中LED Class Support这一项(在选择这个之前需要先选择device driver中的LED Support),就会调用led-class.c中的下面的入口:
subsys_initcall(leds_init);
leds_init模块入口函数负责在/sys/class/目录下面创建一个leds类目录,并为基于leds这个类的每个设备(device)创建对应的属性文件同时将led-class中的suspend的指针以及resume的指针初始化了,一般 来说是当系统休眠的时候系统上层会层层通知各个设备进入睡眠状态,那么负责这个设备的驱动则实际执行睡眠,例如手机的休眠键位,唤醒时调用的是 resume,恢复设备的运行状态,这也是为了省电。即电源管理。
static int __init leds_init(void)
{
leds_class = class_create(THIS_MODULE, "leds");//会生成/sys/class/leds/目录
leds_class->pm = &leds_class_dev_pm_ops; //suspend的指针以及resume的指针初始化
leds_class->dev_groups = led_groups; //创建为基于这个class的所有设备创建属性
return 0;
}
brightness max_brightness等属性的创建
static const struct attribute_group *led_groups[] = {
&led_group,
#ifdef CONFIG_LEDS_TRIGGERS //只有打开这个宏,才会创建对应的trigger属性(trigger后面分析)
&led_trigger_group,
#endif
NULL,
};
static const struct attribute_group led_group = {
.attrs = led_class_attrs,
};
static const struct attribute_group led_trigger_group = {
.attrs = led_trigger_attrs,
};
其中DEVICE_ATTR属性的原型是(Documentation/driver-model/Device.txt中有对DEVICE_ATTR的详细介绍)
#define DEVICE_ATTR(_name, _mode, _show, _store) \
struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
_name表示属性的名字,即在sys中呈现的文件.
_mode表示这个属性的读写权限,如0666, 分别表示user/group/other的权限都是可读可写
_show表示的是对此属性的读函数,当cat这个属性的时候被调用,_stroe表示的是对此属性的写函数,当echo内容到这个属性的时候被调用。
当然_ATTR还有一系列的如__ATTR_RO宏只有读方法,__ATTR_RW等等
static DEVICE_ATTR(trigger, 0666, led_trigger_show, led_trigger_store);
static DEVICE_ATTR_RO(max_brightness);
static DEVICE_ATTR_RW(brightness);
static struct attribute *led_class_attrs[] = {
&dev_attr_brightness.attr, //&dev_attr_xxx中xxx必须和DEVICE_ATTR中的name一致
&dev_attr_max_brightness.attr,
NULL,
};
static struct attribute *led_trigger_attrs[] = {
&dev_attr_trigger.attr,
NULL,
};
提供register接口
led-class.c还提供了一个让驱动开发者在/sys/class/leds这个类下创建led设备的接口
/**
* led_classdev_register - register a new object of led_classdev class.
* @parent: The device to register.
* @led