Linux驱动开发
本文最后更新于:2022年6月6日 晚上
主要内容:
- Linux 应用程序和底层驱动的关系
- 怎么编写Linux下的驱动
理解 驱动开发就是为了给应用程序提供操作底层设备的函数接口
Linux 驱动
Linux 设备驱动开发
- Linux 设备驱动框架(固定)
- 自己动手编写驱动
- 简单(C语言)
Linux 驱动 vs 裸机驱动
裸机驱动 (mpu6050 i2c)
直接操作控制器,让硬件工作,实现硬件功能和如何使用这些功能是在一起
Linux 驱动
因为操作系统中,同类硬件设备一般只有一个,但是想操作硬件设备的进程会很多。这就带来一个问题,应用层如何访问硬件设备以及多个人同时访问的时候,如何解决并发问题。
Linux 驱动本质是向应用层提供访问硬件设备的函数接口,也就是说驱动只是提供硬件的功能函数接口,而如何使用这些功能由应用层代码去做。
注意:Linux下的驱动提供函数接口,必须遵从设备驱动的框架,便于Linux操作系统对设备进行管理。
Linux 驱动 = Linux 驱动框架 + 裸机操作
Linux 设备分类
设备种类 | 举例 |
---|---|
字符设备 | 键盘,鼠标, … |
块设备 | u盘,emmc,硬盘,…. |
网络设备 | 网卡 |
注意 :
(1)字符设备和块设备驱动在应用层存在设备文件和驱动对应。
(2)网络设备驱动在应用层存在是网络接口 (ifconfig命令可以查看)
模块编译的过程
在 Linux 内核中添加模块代码
按照 Linux 规定模块的形式添加代码
1 |
|
模块 Makefile 编写
思想
Linux 内核源码的编译系统可以编译我们编写的模块代码
编译方式
第一种 (产品发布):
将自己编写的代码,拷贝到Linux内核源码树下,然后配置编译,编译进内核
第二种 (驱动调试):
自己编写Makefile,然后使用Linux内核的编译系统,编译自己的模块代码
Q 1: Linux内核的编译系统在哪里?
Linux内核源码下的Makefile
注意 : 你的Linux内核源码必须已经根据自己所开发的平台进行了配置
[1]修改了Makefile,指定了开发工具链
[2]已经使用Linux内核默认配置文件进行了配置ubuntu系统自带的Linux内核编译系统 (pc机,x86)
1
/lib/modules/3.13.0-32-generic/build/Makefile
Q 2:如何在自己编写的Makefile中使用Linux内核的编译系统 ?
1
make -C linux内核编译系统的路径 M=需要编译的模块代码路径 modules
make 调用当前目录下的Makefile———–切换到————>linux内核编译系统的路径Makefile
- 使用 Linux 内核编译的 Makefile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18# 标准模板
ifeq ($(KERNELRELEASE),)
KERNEL_BUILD=/lib/modules/$(shell uname -r)/build 记录Linux内核的编译系统路径
MODULE_PATH =$(shell pwd) 记录模块代码的路径
module:
$(MAKE) -C $(KERNEL_BUILD) M=$(MODULE_PATH) modules
# make -C /lib/modules/$(shell uname -r)/build M=记录模块代码的路径 modules
clean:
$(MAKE) -C $(KERNEL_BUILD) M=$(MODULE_PATH) clean
else
obj-m = hello_module.o
endif- 模块操作
1
2
3
4insmod 加载模块 ----> 模块入口函数
lsmod 查看系统中的模块
rmmod 卸载模块 ----> 模块出口函数
modinfo led-driver.ko 查看模块包含的信息注意 :
查看内核空间printk打印的信息:
dmesg,
清除 :dmesg -c
Linux 应用程序调用底层驱动
核心思想 (牢记):
Linux 驱动本质是向应用层提供访问硬件设备的函数接口
应用程序 和 底层驱动
应用层的进程如何访问底层的驱动程序
字符设备或块设备,我们可以通过设备文件(属性信息中包含的设备号)来找到底层驱动程序
驱动的标识:设备号
12bit(主设备号) + 20bit(次设备号) = 32bit
主设备号:标识一类设备
次设备号:为了区分同类型设备的不同设备
Linux内核有那么多驱动程序,如何才能确定自己需要访问的驱动程序?
通过设备文件中包含的设备号信息
Linux内核中,如何描述文件?
struct inode 描述文件属性信息
文件类型,权限,大小,修改时间,设备号[设备文件]
和设备文件共存亡,只分配一次
struct file 描述一个打开的文件(打开的方式,文件偏移量,…)
- 只要打开一次文件,就会分配一次
应用层访问底层字符设备驱动的过程?
open —-> 设备文件
—->struct inode:设备号
—–>struct cdev
它的一个成员记录操作硬件设备的函数接口
(struct file_operations)
1
2
3寻找成功之后:
struct inode --- 结构体记录struct cdev这个结构体首地址
struct file --- 结构体记录struct file_operations这个结构体首地址写字符驱动,需要做什么?
需要给自己设计的结构体分配空间
1
2
3
4
5/* struct cdev:Linux 针对字符设备的通用描述 */
struct led_device{
struct cdev cdev;/* 通用的字符设备描述 */
...
};1
pled = kmalloc(sizeof(struct led_device), GFP_KERNEL);
提供硬件设备的操作函数接口
1
cdev_init(&pled->led_cdev,&led_fops);
申请一个空闲的设备号
1
2devno = MKDEV(LED_DEVICE_MAJOR,0); //返回设备号
register_chrdev_region(devno, 1, "led-device"); //注册设备号使用设备号,将 struct cdev 这个结构体添加到系统中去
1
cdev_add(&led_cdev, devno, 1); //添加字符设备
创建设备文件
1
2
3mknod 设备文件名 设备文件类型 主设备号 次设备号
mknod /dev/led c 250 0
Linux 应用层和驱动层关系图
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!