Linux驱动学习
强烈建议在参照这篇博客的时候,先将整篇博客通读(瞟)一下,熟悉一下目录结构,以免浪费你人生中的几个小时
第二、三章可以选择不做,运气好的话十几分钟能做完
整理一下第三次作业要求
1、第一部分
制作驱动,要求驱动能实现基本的open、write、read、close、ioctl。
其中ioctl需要实现:
输入CMD1:打印 hello ecnu;
输入CMD2:打印 ecnu hello;
输入CMD3:打印学号和姓名。
不一定非要这样,能对输入有反应就行了。
lseek和poll能实现的话更好。
第一部分在ubuntu主机或者qemu测试没有问题了,就可以准备做第二部分。
2、第二部分
静态加载,就是把驱动程序直接编译到内核里,系统启动后可以直接调用。在本篇第五、六章
这次学习会遇到很多问题:
1、gcc版本不同导致的问题
2、编译平台不同
3、我不知道什么原因的原因
4、作者是个菜鸟、希望能给大家提供一些思路
5、本文qemu测试部分基于第二次作业,ubuntu16.04,linux-5.14.14
一、需要的文件
1、驱动程序源码: 某某某.c
2、Makefile:Makefile
3、应用程序代码: 某某.c
使用 make 指令 ,按照Makefile的设置编译 驱动程序源码 生成 hello.ko等文件。hello.ko就是动态加载驱动要用到的文件
这里附上gitee地址
https://gitee.com/steveqobs/learn-linux-driver.git
使用下面指令,可将项目克隆到任意位置。
建议在/home/你的用户名/kernel/下执行。
和我的目录保持一致,会省去一些麻烦。
git clone https://gitee.com/steveqobs/learn-linux-driver.git
/learn-linux-driver/drv目录是ubuntu主机用的,
/learn-linux-driver/files/rootfs/drvqemu是后面qemu中测试用的
注意!!!项目下载到本地后,请看一遍drv和/learn-linux-driver/files/rootfs/drvqemu的app.c和hello.c,我已经把自己的英文名去掉写成"yourname",“yournumber”,改成自己的再继续操作!,drvqemu的Makefile也打开修改一下steve
1、驱动源代码hello.c
使用自动创建设备节点的方法,这章的测试不用每次mknod。
作业要求要有 insmod指令步骤,和mknod步骤,mknod在后面的qemu测试用到了。
调用了 __register_chrdev(major, 0, 256, name, fops) 函数: 这个函数不只帮我们注册了设备号,还帮我们做了cdev 的初始化以及cdev 的注册;
以下所有C语言都取消展示,因为放这了大家也没时间看代码,而且还占了几百行显得博客太长,有兴趣直接去我gitee码云下载了看代码吧
2、Makefile
drv文件的这个Makefile 是给Ubuntu主机测试驱动用的,内核目录选择了本机内核模块地址
KERN_DIR = /lib/modules/$(shell uname -r)/build
all:
make -C $(KERN_DIR) M=`pwd` modules
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order
obj-m += hello.o
3、应用程序app.c
课上演示的应用程序文件,代码写的很不错,用了while循环,打印 了功能菜单,可读取 操作对应的指令。大家有空可以实现一下… 我这文件只是流水线 一运行就是open、write、read、ioctl。 close忘加了。 就是打印的东西花里胡哨,而且还有bug(ioctl并没有采用常规方式实现,课堂上展示的代码才是正确的)。谨慎使用。
二、加载驱动(ubuntu主机)
app.c hello.c Makefile是必需的
做这步确保你的app.c和hello.c中的关键字已经修改为你的名字,然后可执行make clean 可删除我生成的文件,再继续make
1、make
先make出hello.ko文件
make
make执行成功,如下图所示
2、insmod
insmod命令功能: 用于将指定模块加载到内核中
sudo insmod hello.ko
insmod成功,输出init函数打印的东东
dmesg | tail -6
-6就是显示6行printk
我把steve删了,printk的内容你们可以随意修改
3、查看设备
查看当前有哪些设备
cat /proc/devices
可以看到字符设备已经有hello了,我这自动分配为243号
不一定每个人都是243。
ls -l /dev/hello
hello.c代码已经帮我们生成好了/dev/hello
三、执行app(ubuntu主机)
在应用层调用ioctl的时候,当传入的cmd=2时会出现错误。
ioctl返回值为-1。错误号errno:14, bad address。
需要使用_IOWR等宏来生成cmd命令,而不能自己写。
虽然自己写也可以,但很有可能和系统的其他命令冲突。
看到老师写的代码这样写,在hello.c定义了,这才是正常的
#define HELLO_SETCHANEL 0xc000fa01
#define HELLO_SET_BIT 0xc000fa02
https://mjmwired.net/kernel/Documentation/ioctl-number.txt
1、生成可执行文件
gcc -o app app.c
2、执行
sudo ./app
查看最近30条记录
dmesg | tail -30
3、卸载驱动
sudo rmmod hello.ko
四、在qemu中测试驱动(qemu)
因为第二次作业做的只是雏形,不适合在工程下使用,少了很多模块(我偷懒少了一些步骤)所以下面遇到一些问题不好解决。
后来我把文件系统完善了一下,能正常用了。
这章要用到的/learn-linux-driver/files/rootfs/drvqemu目录和drv目录基本一致,区别就是Makefile不一样
做这步确保你的app.c和hello.c中的关键字已经修改为你的名字,Makefile中的内核路径中的steve改成你的用户名
直接在files文件夹执行start.sh即可
1、生成hello.ko和app
可直接在/learn-linux-driver/files/rootfs/drvqemu/文件下执行
make
生成app应用程序
arm-linux-gnueabi-gcc -o app app.c
2、运行qemu
在files文件夹下运行start.sh
要等几秒钟,返回终端查看。
./start.sh
sudo 的指令会要求输入密码
等它输出一会 ,按enter进入
3、装载驱动
ls
cd drvqemu
insmod hello.ko
cat /proc/devices
4、mknod和运行应用程序
ls -l /dev/hello
mknod /dev/hello c 250 0
ls -l /dev/hello
./app
输入2,打印出来了。可以重新执行./app ,1、2、3都试一下
5、卸载驱动
rmmod hello.ko
关机
poweroff
五、驱动的静态加载
第五章完成make前的准备,第六章做静态加载的驱动测试
0、熟悉一下文件夹
learn-linux-driver是用git clone 下载来的文件夹,代码和文件系统在这里面,之后要用到。
linux-5.14.14是本次静态装载要用到内核文件夹,要修改的Makefile和Kconfig都在这里,hello.c也要放到这个文件夹的/drivers/char/里面。
/learn-linux-driver/files/的rootfs、tmpfs、a9rootfs.ext3是启动qemu模拟器要用到的。
start.sh脚本包含了几句指令,用./start.sh即可完成文件系统的装载和qemu的启动。
1、修改/drivers/char/Makefile
用指令或者到对应文件夹中打开这个文件
如果用指令进入文件修改。记得改steve为你的用户名
vi /home/steve/kernel/linux-5.14.14/drivers/char/Makefile
在最下面 ,加一行
obj-$(CONFIG_DRVHELLO) += hello.o
**$(CONFIG_DRVHELLO)**可以看作一个变量,默认值是y,hello.o就是要编译到内核要用到的文件名。
2、修改/drivers/tty/Kconfig
vi /home/steve/kernel/linux-5.14.14/drivers/tty/Kconfig
DRVHELLO默认值为 y
对应了本章第一节的obj-$(CONFIG_DRVHELLO)
help就是说明。
照葫芦画瓢,这些信息会出现在menuconfig图形界面。
复制下面这段,一定要把下面的中文改成别的英文,内容随便你写
config DRVHELLO
bool "这里写的会显示在menuconfig菜单项"
default y
help
这里写的会显示这一项的help(帮助、说明)中
编辑完成 按ctrl s 保存
下面这个图片 举个例子
3、make menuconfig确认驱动已配置
注意我执行的路径在/home/steve/kernel/linux-5.14.14/
make menuconfig
在内核文件夹执行make menuconfig 往下翻
选择 设备驱动 Device Drivers
select 。再往下翻,选择字符设备Character devices
可以看到 hell driver 已经被打上星号*了
这就是刚才在Konfig中输入的
可选择help查看刚才写的内容
这张截图就是作业要求之一
4、复制hello.c到/char/
只把hello.c 复制到这里
cp /home/steve/kernel/learn-linux-driver/files/rootfs/drvqemu/hello.c /home/steve/kernel/linux-5.14.14/drivers/char/hello.c
5、编译
返回到内核目录/home/steve/kernel/linux-5.14.14/
复制了第二次作业的两句代码
make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm vexpress_defconfig
make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm
在make过程中会有hello.o生成到/drivers/char目录,当然你第一次编译的话,打印的行数太多,你看不到它,如果在没有修改配置的情况下载再次编译,就可以看到这次更新了hello.o,我们启动qemu需要的Image文件也生成了。
第一次编译完成之后,就可以开始最后一步了,驱动静态装载的测试
六、静态加载的测试
1、启动qemu
这时启动的镜像已经和第四章的不一样了
./start.sh
能看到加载中执行了这
2、执行app
启动成功、测试
cd drvqemu
./app
关机…poweroff
linux4.4也完成了,测试也ok