一、什么是驱动框架?
1、驱动是谁写的?
(1)驱动开发工程师;
(2)内核维护者;
2、驱动编程协作要求
(1)接口标准化;
(2)内核开发者应该尽量降低驱动开发者难度;
3、到底什么是驱动框架?
(1)驱动框架
- 内核中驱动部分维护者,针对每个种类(比如LED、LCD、蜂鸣器等等)的设备,都设计有一套成熟的、标准的、典型的驱动实现;
- 它是把不同厂家的同类硬件驱动中相同的部分抽出来自己实现好,再把不同部分留出接口给具体的驱动开发工程师来实现。
- 降低了难度,也标准化。
(2)内核维护者在内核中设计了一些(统一管控系统资源的)体系
- 这些体系让内核能够(对资源在各个驱动之间的使用)统一协调和分配,保证整个内核的稳定健康运行。
- 譬如系统中所有的GPIO就属于系统资源,每个驱动模块如果要使用某个GPIO就要先调用特殊的接口先申请,申请到后使用,使用完后要释放。
- 又譬如中断号也是一种资源,驱动在使用前也必须去申请。
- 这体系也是驱动框架的组成部分。
(3)一些特定的接口函数、一些特定的数据结构,这些是驱动框架的直接表现。
二、内核驱动框架中LED的基本情况
1、相关文件
(1)drivers/leds目录
- 这个目录就是驱动框架规定的LED这种硬件的驱动应该待的地方。
(2)drivers/leds目录下有led-class.c和led-core.c
- 这两个文件加起来属于LED驱动框架的第一部分,这两个文件是内核开发者提供的,他们描述的是内核中所有厂家的不同LED硬件的相同部分的逻辑。
(3)此目录下有leds-xxxx.c
- 这个文件是LED驱动框架的第2部分,是由不同厂商的驱动工程师编写添加的;
- 厂商驱动工程师结合自己公司的硬件的不同情况来对LED进行操作,使用第一部分提供的接口来和驱动框架进行交互,最终实现驱动的功能。
2、典型的驱动开发行业现状
(1)内核开发者对驱动框架进行开发和维护、升级,对应led-class.c和led-core.c;
(2)SoC厂商的驱动工程师对设备驱动源码进行编写、调试,提供参考版本,对应leds-s3c24xx.c;
(3)做产品的厂商的驱动工程师以SoC厂商提供的驱动源码为基础,来做移植和调试;
二、内核添加led驱动框架支持
当前内核中没有LED驱动框架,要去添加它。(/sys/class目录下没有此类,因此要去添加此类)
配置内核,make menuconfig
Device Drivers --->
[*] LED Support --->
<*> LED Class Support
三、内核驱动框架中LED的接口
1、led_classdev_register设备注册函数
int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
- led_classdev_register函数创建一个属于leds这个类的一个设备,其实就是去注册一个设备。
- 这个函数是led驱动框架中,内核开发者提供给SoC厂家驱动开发者的一个注册驱动的接口。
- 当使用led驱动框架去编写驱动的时候,这个led_classdev_register函数的作用类似于之前使用file_operations方式去注册字符设备驱动时的register_chrdev函数。
- 之前使用file_operations方式时,在sys/class目录下创建一个类,然后再创建属于这个类的一个设备。
2、led_classdev结构体
看一下led_classdev中的主要成员
struct led_classdev {
const char *name; //设备名字
int brightness; //当前亮度值
int max_brightness; //最大亮度值
...
void (*brightness_set)(struct led_classdev *led_cdev, enum led_brightness brightness); /* 设置led亮度值 */
...
};
四、基于驱动框架写led驱动
#include <linux/module.h>
#include <linux/init.h>
#include <linux/leds.h>
static struct led_classdev mydev;
/* led设置接口 */
static void s5pv210_led_set(struct led_classdev *led_cdev, enum led_brightness value)
{
printk(KERN_INFO "s5pv210_led_set\n");
}
static int __init s5pv210_led_init(void)
{
int ret = -1;
mydev.name = "led";
mydev.brightness = 0;
mydev.brightness_set = s5pv210_led_set;
/* 注册led设备 */
ret = led_classdev_register(NULL, &mydev);
if (ret < 0) {
printk(KERN_ERR "led_classdev_register failed\n");
return ret;
}
return 0;
}
static void __exit s5pv210_led_exit(void)
{
/* 注销led设备 */
led_classdev_unregister(&mydev);
}
module_init(s5pv210_led_init);
module_exit(s5pv210_led_exit);
// MODULE_xxx这种宏作用是用来添加模块描述信息
MODULE_LICENSE("GPL"); // 描述模块的许可证
MODULE_AUTHOR("lsm"); // 描述模块的作者
MODULE_DESCRIPTION("s5pv210 led driver"); // 描述模块的介绍信息
MODULE_ALIAS("s5pv210_led"); // 描述模块的别名信息
五、查看led设备
安装好led驱动之后,进入/sys/class/leds/led
打印出s5pv210_led_set,表示使用led框架成功。