一、什么是驱动框架?
数据结构,这些是驱动框架的直接表现。
Linux/init.h中。
这个宏的功能是:将其声明的函数放到一个特定的段:.initcall4.init。
(2)分析module_init宏,可以看出它将函数放到了.initcall6.init段中。
module_init
__initcall
device_initcall
__define_initcall('6',fn,6)
(3)内核在启动过程中,需要按照顺序执行很多事情。内核如何实现按照先后顺序去做很多初始化操作?
内核的解决方案就是将内核启动时要调用的所有函数归类,然后每个类按照一定的次序去调用执行。
这些分类名就叫.initcalln.init,n的值从1到8。
内核开发者在编写内核代码时只要将函数设置合适的级别,链接的时候,这些函数就会被放入特定的段,内核启动时再按照(内核链接脚本中指定的)段顺序去依次执行各个段即可。内核链接脚本(编译之后才有)在arch/arm/kernel/vmlinux.lds中。

(4)经过分析可以看出,subsys_initcall和module_init的作用是一样的,只不过前者所声明的函数要比后者在内核启动时的执行顺序更早。
3、led_class_attrs



(1)什么是attribute?
对应将来/sys/class/leds/目录里的内容,一般是文件和文件夹。
这些文件其实就是sysfs开放给应用层的一些操作接口(非常类似于/dev/目录下的那些设备文件,对这些设备文件的操作API,对应file_operations里面的函数)。
(2)attribute有什么用?
让应用程序可以通过/sys/class/leds/目录下面的属性文件来操作驱动进而操作硬件设备。
(3)attribute其实是另一条驱动实现的路线(不再有c_dev相关的函数操作),有区别于之前讲的file_operations那条线。
4、led_classdev_register设备注册函数

led_classdev_register函数创建一个属于leds这个类的一个设备,其实就是去注册一个设备。
这个函数是led驱动框架中,内核开发者提供给SoC厂家驱动开发者的一个注册驱动的接口。
当使用led驱动框架去编写驱动的时候,这个led_classdev_register函数的作用类似于之前使用file_operations方式去注册字符设备驱动时的register_chrdev函数。
之前使用file_operations方式时,在sys/class目录下创建一个类,然后再创建属于这个类的一个设备。
5、led_classdev结构体

在leds.h文件中
四、在内核中添加或去除某个驱动
1、去除九鼎移植的LED驱动
(1)九鼎移植的驱动(在应用层的接口)在/sys/devices/platform/x210-led/目录下,有led1、led2、led3、led4四个设备文件,各自管理一个led。

echo 1 > led1可以点亮其中的led1;
(2)要去掉九鼎自己移植的led驱动,要在make menucofig中去掉选择项,然后重新make得到zImage,然后重启时启动这个新的zImage即可。
新的内核启动后,如果/sys/devices/platform/目录下已经没有了x210-led这个目录,就说明我们去掉这个驱动成功了。
(3)为什么make menuconfig就能去掉这个驱动?
理解make menuconfig的功能。
2、添加led驱动框架支持
当前内核中没有LED驱动框架,要去添加它。(/sys/class目录下没有此类,因此要去添加此类)
主要是menuconfig的操作。
3、sysfs中的内容分析
4、后续展望:完成leds-x210.c
五、基于驱动框架写led驱动1
1、分析
(1)参考哪里? drivers/leds/leds-s3c24xx.c文件
(2)关键点?led_classdev_register函数
2、动手写led驱动模块
代码如下
注意设备注册函数、设备注销函数

#include
// module_init module_exit #include
// __init __exit #include
#include
#include
#include
#include
#include
#define GPJ0CON S5PV210_GPJ0CON
#define GPJ0DAT S5PV210_GPJ0DAT
static struct led_classdev mydev; // 定义结构体变量
// 这个函数就是要去完成具体的硬件读写任务的
static void s5pv210_led_set(struct led_classdev *led_cdev,enum led_brightness value)
{
printk(KERN_INFO 's5pv210_led_setn');
// 在这里根据用户设置的值来操作硬件
// 用户设置的值就是value
if (value == LED_OFF)
{
// 用户给了个0,希望LED灭
writel(0x11111111, GPJ0CON);
writel(((1<<3) | (1<<4) | (1<<5)), GPJ0DAT);
}
else
{
// 用户给的是非0,希望LED亮
writel(0x11111111, GPJ0CON);
writel(((0<<3) | (0<<4) | (0<<5)), GPJ0DAT);
}
}
static int __init s5pv210_led_init(void)
{
// 用户insmod安装驱动模块时会调用该函数
// 该函数的主要任务就是去使用led驱动框架提供的设备注册函数来注册一个设备
int ret = -1;
mydev.name = 'myled';//设备的名字
mydev.brightness = 255;
mydev.brightness_set = s5pv210_led_set;
ret = led_classdev_register(NULL, &mydev);
if (ret < 0) {
printk(KERN_ERR 'led_classdev_register failedn');
return ret;
}
return 0;
}
static void __exit s5pv210_led_exit(void)
{
led_classdev_unregister(&mydev);
}
module_init(s5pv210_led_init);
module_exit(s5pv210_led_exit);
// MODULE_xxx这种宏作用是用来添加模块描述信息
MODULE_LICENSE('GPL'); // 描述模块的许可证
MODULE_AUTHOR('aston <1264671872@qq.com>'); // 描述模块的作者
MODULE_DESCRIPTION('s5pv210 led driver'); // 描述模块的介绍信息
MODULE_ALIAS('s5pv210_led'); // 描述模块的别名信息
六、基于驱动框架写led驱动2
1、代码实践
(1)调试
(2)分析





我们写的驱动确实工作了,被加载了,/sys/class/leds/目录下确实多出来了一个表示设备的文件夹。
文件夹里面有相应的操控led硬件的2个属性brightness和max_brightness。
led-class.c中brightness方法有一个show方法和store方法,这两个方法对应用户在/sys/class/leds/myled/brightness目录下直接去读写这个文件时实际执行的代码。
当我们show brightness时,实际就会执行led_brightness_show函数。
当我们echo 1 > brightness时,实际就会执行led_brightness_store函数。
(3)show方法实际要做的就是读取LED硬件信息,然后把硬件信息返回
因此show方法和store方法会去操控硬件;
但是led-class.c文件又属于驱动框架中的文件,它本身无法直接读取具体硬件,因此在show和store方法中使用函数指针的方式调用了struct led_classdev结构体中的相应的读取/写入硬件信息的方法。
(4)struct led_classdev结构体中的实际用来读写硬件信息的函数,就是我们自己写的驱动文件leds-s5pv210.c中要提供的。
2、添加硬件操作
七、基于驱动框架写led驱动3
1、在驱动中将4个LED分开
(1)好处
驱动层实现对各个LED设备的独立访问,并向应用层展示出4个操作接口led1、led2、led3、led4,这样应用层可以完全按照自己的需要对LED进行控制。
驱动的设计理念:不要对最终需求功能进行假定(不能假定用户进行什么操作,比如是几个led一起操作还是一个操作而已?),而应该只是直接的对硬件的操作。
有一个概念就是:机制和策略的问题。在硬件操作上驱动只应该提供机制(具体实现)而不是策略(方法、主意、解决方案)。策略由应用程序来做。
(2)如何实现
#include
// module_init module_exit #include
// __init __exit #include
#include
#include
#include
#include
#include
#define GPJ0CON S5PV210_GPJ0CON
#define GPJ0DAT S5PV210_GPJ0DAT
static struct led_classdev mydev1; // 定义结构体变量
static struct led_classdev mydev2; // 定义结构体变量
static struct led_classdev mydev3; // 定义结构体变量
上一篇:tiny210V2 Uboot kernel filesystem 烧写和启动
下一篇:INPUT输入子系统——按键
推荐阅读最新更新时间:2026-03-25 11:25
- 用于 7VIN 至 16VIN、1.5V 和 1.2V 输出的 LTM4628EV DC/DC 模块稳压器的典型应用电路
- 使用 Analog Devices 的 LTC3728LIGN 的参考设计
- DER-406 - 适用于 A19 灯的 5.76 W 高 PF 非隔离降压-升压型 TRIAC 调光 LED 驱动器
- ADR5045B 5V 输出精密微功率并联模式电压基准的典型应用
- LT3970EDDB-3.42 2.5V 降压转换器的典型应用
- MC78M08BDTG 8V 电流调节器的典型应用
- LT1021DCN8-5 精密电压基准的典型应用
- DER-282 - 100W, 扁平(11 mm), LLC DC-DC转换器
- REF193 低压差开尔文连接电压基准的典型应用电路
- LT3088EM 线性稳压器用于添加软启动的典型应用



英飞凌PSoC 6 电位器控制LED闪烁状态并水墨屏显示——源码
Follow me第三季第4期任务
非常经典的关于LLC的杨波博士论文
5962-89541022A
XC6406PP60DL






京公网安备 11010802033920号