Linux驱动学习笔记
Linux驱动分类:字符设备驱动、块设备驱动、网络设备驱动
- 字符设备驱动:LED、屏幕、麦克风…它是最常见的驱动
- 块设备驱动:存储设备如磁盘、U盘…
- 网络设备:以太网接口、WIFI模块…
如果需要通过C语言对arm中的硬件进行控制,一般做法如下:
//通过原理图找到与硬件相关的寄存器
//通过数据手册获取寄存器的基地址,例如0x11000103
//1.指针法
//定义一个无符号int类型指针来存放基地址
unsigned int * p;
p = 0x11000103;
//直接使用*p来为指针赋值
*p = 0;
*p = 1;
//2.强制转换法
*(unsigned int *)0x11000103 = 0;
Linux驱动是介于文件系统和底层硬件之间的,可以理解为嵌入到内核中的程序
Linux驱动的上层是系统和应用,中间是Linux内核(驱动依附于Linux内核),其下层则是硬件
- 上层:Linux设备驱动要给上层提供调用的接口
- 中间:Linux设备驱动要注册到Linux内核中
- 下层:Linux设备驱动要具备操作硬件的能力
最简单的Linux驱动
功能:加载驱动的时候输出“Hello World”
Linux头文件的位置
例如:#include<linux/module.h>,它的位置为Linux源码目录的include/linux/module.h
所有的Linux代码必须遵循GPL协议,否则你的模块将无法在Linux中使用
- MODULE_LICENSE(_license):添加遵循GPL协议
- MODULE_AUTHOR(_author):代码作者
#include<linux/init.h>头文件是必备的头文件,因为其包含初始化宏定以,并且驱动入口函数module_init(x)和出口函数module_exit(x)都在该文件中
最简单驱动的详细代码如下:
//mini_linux_module.c
#include <linux/init.h> //包含初始化宏定义module_init、module_exit的头文件
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL"); //添加GPL协议,Dual BSD表示没有版本限制
MODULE_AUTHOR("Wang_Wonk"); //添加作者
static int hello_init(void)
{
printk(KERN_EMERG "Hello World enter!\n"); //内核中打印信息需要使用printk
return 0;
}
static void hello_exit(void)
{
printk(KERN_EMERG "Hello World exit!\n");
}
module_init(hello_init); //初始化函数
module_exit(hello_exit); //加载函数
//Makefile
#!/bin/bash
#指明编译脚本
obj-m += mini_linux_module.o #指明中间文件
KDIR := /home/Xunwei_work/Driver/linux_source/iTop4412_Kernel_3.0
#源码目录,根据用户实际请况选择目录
PWD ?= $(shell pwd)
#当前目录
#make -C即调用执行的路径
all:
make -C $(KDIR) M=$(PWD) modules
#表示make clean命令执行的操作
clean:
rm -rf *.o
模块编译流程
测试
- insmod:加载模块命令
- lsmod:查看模块命令
- rmmod:卸载模块命令
使用U盘或nfs将文件拷贝到开发板上,进入mini_linux_module.ko所在的路径,终端输入
insmod mini_linux_module.ko
如果在实验中遇到各种问题,请参照一下链接编译相关kernel文件
https://www.bilibili.com/video/BV1vJ411d7jD?from=search&seid=10555628828748654695
如果编译好文件之后,如果在卸载驱动的时候提示
rmmod: can't change directory to '/lib/modules': No such file or director
请参照该链接操作即可解决问题
https://www.cnblogs.com/lialong1st/p/7763531.html