Linux驱动 | 如何加载驱动模块?

来源:互联网 发布:人工蜂群算法的优缺点 编辑:程序博客网 时间:2024/05/16 09:07

0x00  前期准备

主机/work/mydrv/目录下,已经写好了驱动层的C文件:mydrv.c,应用层的C文件:mytest.c,以及用来把mydrv.c生成驱动模块(.ko文件)的Makefile
本实验的目的是:把已经写好的LED的驱动程序mydrv.c编译后加载到开发板上;mytest.c编译及运行,实现通过对设备文件的操作来控制开发板上LED的亮灭。

0x01  编译出驱动模块

先进入/work/mydrv/目录查看一下
$ cd /work/mydrv
$ ls
Makefile  mydrv.c mytest.c

输入make,开始编译驱动模块

$ make

等待编译完成,再查看一下
$ ls
Makefile  Module.symvers mydrv.c mydrv.ko mydrv.mod.c mydrv.mod.o mydrv.o mytest.c

0x02  编译应用层程序

$ arm-linux-gcc mytest.c -o mytest

查看一下目录下是否生成mytest:

$ ls
Makefile  Module.symvers mydrv.c mydrv.ko mydrv.mod.c mydrv.mod.o mydrv.o mytest mytest.c

可见经过以上两步已经编译出来了驱动模块mydrv.ko和用来测试的应用层程序mytest

0x03  把驱动模块和测试程序转移到开发板上

这里,我们使用/work/nfs_root/作为网络根文件系统来,所以我们只需要把程序放到这个目录,就相当于放到开发板上面去了。

$ cp ./mydrv.ko ./mytest /work/nfs_root

$ cd /work/nfs_root

$ ls mydrv.ko mytest -l


现在,这两个文件已经放上去了,我们就可以通过串口控制开发板来使用它们了!

0x04  加载驱动

先加载驱动模块,然后查看是否已加载,命令如下:

# insmod mydrv.ko

# lsmod


通常我们还会经常使用到这样两个命令:cat /proc/devices”,以及“ls /dev/$(DRVICE) -l”,它们分别用来查看向内核注册的设备、设备下的设备文件(应用程序操作的就是 这些文件)。比如说,在这个例子中,我在mydrv.c里面就创建了一个名为“mydrv”的设备,同时创建了一个名为“Hamburger”的设备文件,所以这里的$(DRVICE)应该换为Hamburger
我们来试一下:

# cat /proc/devices


我们可以看到mydrv就在其中了,它前面的“252”这个数字表示的就是它的“主设备号”。

# ls /dev/Hamburger -l


以上就可以得知驱动模块已加载好了。

0x05  卸载驱动

卸载驱动用的是rmmod这个命令,这里先卸载后查看:

# rmmod mydrv

# lsmod


可见驱动已经卸载了。再来查看一下/proc/devices和设备文件:

# cat /proc/devices

# ls /dev/Hamburger -l




以上就可以得知驱动已经卸载成功了。 

0x06  测试驱动

现在先把驱动模块加载上去:

# insmod mydrv.ko

接着运行测试程序mytest

# ./mytest on  

可以看见开发板上面的LED点亮了

# ./mytest off

执行之后LED灭了

以上说明我们的驱动模块符合我们的预期,测试成功!

0x07  mknod

说一下mknod这个命令,它其实就是在/dev/目录下创建一个设备文件,同时指定设备类型,主设备号,次设备号,比如:

# mknod /dev/Coke c 252 1

这时我们就创建了一个名为Coke的设备文件,并指定为字符类设备,主设备号为252,次设备号为1

/dev/目录查看一下:

# ls /dev/Coke /dev/Hamburger -l


如果要删除它,就像操作普通的文件一样:
# rm -f /dev/Coke
再说一下次设备号,它其实是可以由我们任意分配的,比如说:把Coke的次设备号也设为0

# mknod /dev/Coke c 252 0

# ls /dev/Coke /dev/Hamburger -l


可见两者并不冲突。

0x08  两个问题

/dev/Hamburger这个设备文件,我们并没有使用mknod命令去创建它,那它是怎么来的呢?

是这样的,在mydrv.c的代码,有下面两行,它调用了内核的class_createclass_device_create函数,创建了一个名为“mydrv”的class,并且在这个class之下创建了一个名为“Hamburger”的class_dev

mydrv_class = class_create(THIS_MODULE, "mydrv");mydrv_class_dev = class_device_create(mydrv_class, NULL, MKDEV(major, 0), NULL, "Hamburger");

那么当mydrv_classmydrv_class_dev这两个数据结构传入到内核后,内核busyboxmdev(把它看作内核的一个工具就可以)就会自动帮我们去做“mknod /dev/Hamburger c 252 0”了!

主设备号为252,它又是怎么来的呢?
它是系统给我们分配的,同样,在驱动代码里调用了内核的register_chrdev这个函数向内核注册驱动,函数的返回值就是主设备号

major = register_chrdev(0, "mydrv", &mydrv_fops);

0x09  总结

这个例子总结的框图如下:


从中我们也可以看出嵌入式开发的特点:代码都是在Linux主机上编译的,而加载、卸载和执行都被放到了嵌入式系统(开发板)上。

 

 

原创粉丝点击