客观题
-
Linux使用
mknod
命令创建设备节点 -
Linux使用
mkdir
命令创建目录文件 -
Linux使用
mkfifo
命令来创建管道文件(管道的本质就是队列,先进先出) -
Linux设备驱动主要分为:
字符设备
、块设备
、网络设备
(其主要的区别在于字符设备是按照字节流
来处理数据,不支持随机存取
,典型字符设备有鼠标
、键盘
等;块设备顾名思义,处理数据是按块空间来处理的,支持随机存取,也可以顺序存取
,典型的设备有磁盘
、EEPROM
等;网络设备,因其特点在于对网络协议的处理以及网络数据包的封包和拆包而归类
,典型设备:网卡
) -
Linux驱动模块的后缀名为:
.ko
-
Linux下常用系统调用名,系统调用实际也是
VFS
层提供的功能
(其调用流程就是,在我们调用open函数时,调用的是glibc的open
函数,产生SWI中断
,使得CPU进入到SVC
模式,进而调用VFS的do_sys_open
函数)
read:读取设备
open:打开设备
close:关闭设备
lseek:偏移设备
注意:fopen\fwrite不是系统调用,是标准IO,其产生的主要原因在于通过开辟一块缓冲区,使得减少系统调用,提高效率和节省资源
-
platform_driver
和platform_device
在总线匹配成功后,执行platform_driver中指定的probe函数
(platform_driver就是驱动,plateform_device就是设备,一个描述如何操作硬件设备,一个描述该硬件的属性信息(寄存器地址,引脚等等)) -
Linux通过
ioremap
(注意是宏
,不是函数)实现物理地址到虚拟地址的映射 -
设备树被内核识别后,会在
/sys
目录下为用户提供可视化操作接口 -
Linux的
miscdevice(混杂设备:就是无法归类的设备)
的主设备号为10
-
在
printk
打印内核信息时,以信息级打印应设置KERN_INFO
前缀(更改printk打印优先级echo 1 4 1 7 > /proc/sys/kernel/printk
;前缀有很多,大家自行百度) -
设备树定义节点时,定义资源的属性名是
reg
(其实最重要的资源就是寄存器物理地址
,所以我认为reg就是register) -
实现内核空间拷贝到用户空间的接口名:
copy_to_uer
(不知道与mmap的机制是否有关系,但是有机会会详细研究一下) -
内核提供
cdev
结构体描述字符设备,cdev_init是绑定设备与file_operations结构体
,cdev_add是向内核添加/注册你的驱动,主次设备好
,cdev_del是从内核移除
,因为内核总是认为我的东西在污染它,事实也确实是这样!!! -
内核模块源码可以配置为编译进进内核和以模块编译的方式(没毛病,你在对应的kconfig文件中,将你的驱动源码设置为
tristate
三态的意思,-m就是以模块的方式编译
,-y就是编译进内核
,-n就是不编译
) -
内核模块的入口函数需要通过
module_init
进行注册到内核(√) -
Linux字符设备和块设备独占主设备号(√)(其实主设备号就是用来指定使用那一套驱动程序的,而次设备号的作用是来区分同一类物品的多个东西,比如两个LED)
-
Linux设备号中主设备号为
12
位(√)(对应次设备号就是20位) -
内核模块通过
insmode
命令来实现用户空间向内核空间加载驱动; -
使用
kmalloc
函数在内核空间申请内存,使用malloc
函数在用户空间申请内存 -
内核platform总线设备是一种虚拟的设备驱动(√)(并不是真的硬件设备,只是platform_driver和platform_deivce匹配的机制像一条线两边,所以就类比到芯片上的
总线一样
,但并不是芯片中那样真实存在的总线) -
内核通过
sysfs文件系统
导出内核设备模型 -
Linux内核的虚拟内存是
3G-4G
空间 -
使用
wait_event
接口将当前访问进程设置位等待状态
主观题
驱动Makefile框架
#体系结构
ARCH :=
#编译链前缀
CROSS_COMPILE :=
# 要编译的内核目录
KERNEL_DIR ?=
#应用程序测试代码
SOURCE :=
TARGET :=
all:
make -C $(KERNEL_DIR) M=`pwd` modules
$(CROSS_COMPILE)gcc -o $(TARGET) $(SOURCE)
.PHONY:clean
clean:
make -C $(KERNEL_DIR) M=`pwd` modules clean
rm -rf $(TARGET)
# 驱动源文件
obj-m += 驱动源文件名.o
# 如果你需要多个文件生成驱动文件
# xxx-y :=yyy.o zzz.o aaa.o
# obj-m +=xxx.o
驱动程序模块相关
- 模块加载函数,通过insmod命令来加载内核,模块的加载函数会自动被内核执行,完成本模块相关的初始化工作。(用
modeprobe
也可以加载,区别就是modeprobe会解决驱动模块依赖的问题) - 模块卸载函数,通过rmmod命令来卸载某模块,被调用执行
- 模块许可证声明,使用MODULE_LICENSE配置GPL的声明
- 可选模块参数、模块导出符号表、模块作者信息等声明
编写global_memory的open函数
static int mem_open(struct inode *node, struct file *fp)
{
struct mem_dev *dev;
//通过子类找基类
dev = container_of(node->i_cdev,struct mem_dev, cdev);
//得到文件描述符,就可以操作该设备了
fp->private_data = dev;
return 0;
}
编写一个最简单的驱动
驱动程序从下网上写与看
#include <linux/module.h>
#include <linux/init.h>
static __init int hello_init(void)
{
printk("Hello world\n");
return 0; //必须返回0
}
static __exit void hello_exit(void)
{
printk("GoodBye\n");
return;
}
module_init(hello_init);
module_init(hello_exit);
MODULE_LICENSE("GPL");