文章目录
前言
为了尽量降低驱动开发者难度以及接口标准化,就出现了设备驱动框架的概念;
一、什么是驱动框架
Linux 针对每个种类的驱动设计一套成熟的、标准的、典型的驱动实现, 然后把不同厂家的同
类硬件驱动中相同的部分抽出来自己实现好,再把不同部分留出接口给具体的驱动开发工程
师来实现,这就叫驱动框架。
说白了,设备驱动框架就是对原始的驱动开发接口进行了封装,不同种类的设备有不同
的封装和实现方法,驱动开发工程师根据这些封装好的接口来编写自己的驱动程序,这就是
设备驱动框架。
内核源码 drivers/leds 目录下有两个文件 ledclass.c 和 led-core.c,它们就是 LED 驱动框架的核心文件,由内核开发工作者进行维护和升级。
二、使用步骤
1.注册LED设备
LED 驱动框架提供了 led_classdev_register 宏用于注册 LED 设备,该宏定义在内核源码 drivers/leds/leds.h 头文件中
extern int of_led_classdev_register(struct device *parent,
struct device_node *np,
struct led_classdev *led_cdev);
#define led_classdev_register(parent, led_cdev) \
of_led_classdev_register(parent, NULL, led_cdev)
parent: LED 设备的父设备, struct device 类型指针变量。
led_cdev: 需要注册的 LED 设备结构体,LED 驱动框架中使用struct led_classdev结构体来描述一个 LED设备。
返回值:成功返回 0,失败则返回一个负数
struct led_classdev 结构体的内容,该结构体定义在 drivers/leds/leds.h 头文件中
struct led_classdev {
const char *name; // 设备名字
enum led_brightness brightness; // LED 默认亮度
enum led_brightness max_brightness; // LED 的最大亮度
。。。
}
描述亮度的枚举类型:
enum led_brightness {
LED_OFF = 0,
LED_ON = 1,
LED_HALF = 127,
LED_FULL = 255,
}
2.卸载LED设备
void led_classdev_unregister(struct led_classdev *led_cdev)
led_cdev:需要卸载的 led 设备结构体, struct led_classdev 结构体类型指针变量
返回值:无
3.内核中申请内存
1.kmalloc
void *kmalloc(size_t size, gfp_t flags);
size:需要分配的内存大小。
flags:分配内存时所使用的标志位,这些 flag 定义在 include/linux/gfp.h 头文件中
主要:
GFP_ATOMIC: 分配内存的过程是一个原子过程,分配内存的过程不会被(高优先级进程或中断)打断。
GFP_KERNEL: 内核空间中正常的内存分配过程,也是用的最多的 flag。
GFP_KERNEL_ACCOUNT: GFP_KERNEL_ACCOUNT 与 GFP_KERNEL 相同,只是分配是由 kmemcg 负责。
GFP_DMA: 给 DMA 控制器分配内存,需要使用该标志( DMA 要求分配虚拟地址和物理地址连续)。
返回值:申请成功返回的就是内存的起始地址,申请失败返回 NULL
kmalloc()申请的内存位于物理内存映射区域,而且在物理上也是连续的,它们与真实的物理地址只有一个固定的偏移,因为存在较简单的转换关系,所以对申请的内存大小有限制,不能超过 128KB。 如何要释放内存可以使用 kfree 函数,函数原型如下:
void kfree(const void *addr);
2.kzalloc
kzalloc()函数与 kmalloc()非常相似,参数及返回值是一样的, kzalloc()函数除了申请内存
空间之外,还会对申请到的内存空间进行清零。同样 kzalloc()对应的内存释放函数也是 kfree()。
void *kzalloc(size_t size, gfp_t flags)
3.vmalloc
void *vmalloc(unsigned long size);
void vfree(const void *addr);
函数只有一个参数,就是需要申请的内存空间大小,