一、内核空间和用户空间
用户空间和内核空间参数对应关系
用户空间->内核空间(write)
int copy_from_user(void *to, const void __user volatile *from, unsigned long n)
函数功能:将数据从用户空间拷贝数据到内核空间
参数: to:内核空间的首地址
from:用户空间首地址 (__user:给编译器使用,告诉编译器这是一个用户空间的地址)
n:拷贝字节的大小(单位字节)
返回值:成功返回0,
失败返回未拷贝的字节个数 错误码:EIO,找到内核中的错误码
内核空间->用户空间(read)
int copy_to_user(void __user volatile *to, const void *from, unsigned long n)
函数功能:将内核空间数据拷贝到用户空间
参数: to:用户的地址
from:内核地址 (__user:给编译器使用,告诉编译器这是一个用户空间的地址)
n:拷贝字节的大小
返回值:成功返回0,失败返回未拷贝的字节个数
二、模块
Linux内核模块分为:入口、出口、许可证
入口:资源的申请工作,在驱动安装insmod的时候执行
出口:资源释放工作,在驱动卸载rmmod的时候执行
许可证:驱动需要遵循GPL协议(开源)
三、设备模块分类:字符设备和块设备
设备管理
i) 字符设备:按照字节流来访问,并且顺序访问的设备
ii) 块设备:按照block(512字节)来访问设备,可以顺序访问,也可以无序访问
iii) 网卡设备:网卡没有设备节点,接收网络协议栈发来的数据,将这些数据向网线上收发即可,网络驱动没有设备文件 网卡设备早于Linux内核设备
四、驱动程序框架
五、错误和消息打印
应用层是使用printf来打印信息 内核中使用printk来打印信息
如何查看打印级别 以下为printk打印级别:
2、在Linux内核中将打印的信息分为8个级别,分别是0~7,数字越小级别越高,内核中这个打印级别是用于过滤信息的
3、打印格式: printk(打印级别 "打印信息\n"); 或者 printk("打印信息\n");---->使用默认的消息级别 总结:内核中的printk用法和printf用法除了打印级别之外都是一样的,这个打印级别是用来过滤打印信息
4、printk打印的内容属于消息,消息的级别在内核中一共有8种,数值越小优先级越高 消息有消息的级别,终端也有终端的级别,只有消息级别大于终端级别的时候,消息才会在终端显示
5、默认的消息打印级别: 命令查看:cat /proc/sys/kernel/printk 打印信息:4 4 1 7 终端级别 默认消息级别 终端最大级别 终端最小级别
6、如何进行修改默认消息级别 su root echo 4 3 1 7 > /proc/sys/kernel/printk 备注:sudo passwd root (更改ubuntu密码)
7、如何进入虚拟终端 如何进入虚拟终端 进入虚拟终端:ctrl+Fn+alt[F2-F7] 推出终端:ctrl+Fn+alt+F1
8、主动查看打印信息:dmesg sudo dmesg -C:直接清除打印信息 sudo dmesg -c:先回显所有的打印信息后,在清除打印信息 内核从启动到现在的时间,时间为s 。
六、模块参数
内核模块为什么需要传参?
1.编译通过传参不需要每次都给变量的值
2.有些驱动厂商不提供源代码,直接提供.ko驱动模块,驱动中具体的数据通过传参的形式更改
接收命令行参数
函数原型:module_param(name, type, perm)
功能:用于接收安装驱动时命令行传递过来参数
参数:
name:变量名
type:变量的类型
perm:修饰的是
sys目录下文件的权限(0664/0444)
对变量进行描述
MODULE_PARM_DESC(_parm, desc)
功能:对变量进行描述(modinfo命令查看)
参数:
param:被描述的变量
desc:描述字段,也就是需要描述的内容
接收向内核模块传递的数组
函数原型:module_param_array(name, type, nump, perm)
功能:接受向内核模块传递的数组
参数:
name:数组名
type:数组成员的类型
nump:变量的地址(用户获取用户传递的参数个数)
perm:权限