由于NanoPi Fire3使用的是linux 4.4的内核版本,所以不知道以前的linux 2.6版本的驱动程序能否兼容,所以这一章来说明linux2.6版本与4.4版本的驱动程序的区别。
这一章用到的内核源码和交叉编译工具链可以在NanoPi Fire3的wiki第7节中找到
http://wiki.friendlyarm.com/wiki/index.php/NanoPi_Fire3/zh#.E7.BC.96.E8.AF.91Linux_kernel_4.4.y
首先,我使用以前2.6版本所写的最简单的驱动程序来进行试验
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
int major; //主设备号
static struct class *hellodrv_class;
static struct class_device *hellodrv_class_dev;
static int hello_drv_open(struct inode *inode, struct file *file)
{
printk(KERN_EMERG "hello_drv_open\n");
return 0;
}
static ssize_t hello_drv_read(struct file *fd, char __user *buf, size_t count, loff_t *ppos)
{
printk(KERN_EMERG "hello_drv_read\n");
return 0;
}
static ssize_t hello_drv_write(struct file *fd, const char __user *buf, size_t count, loff_t *ppos)
{
printk(KERN_EMERG "hello_drv_write\n");
return 0;
}
static struct file_operations hello_drv_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = hello_drv_open,
.read = hello_drv_read,
.write = hello_drv_write,
};
static int hello_drv_init(void)
{
printk(KERN_EMERG "hello_drv_init...\n");
major = register_chrdev(0, "hello_drv", &hello_drv_fops); //注册,告诉内核
hellodrv_class = class_create(THIS_MODULE, "hellodrv");
hellodrv_class_dev = class_device_create(hellodrv_class, NULL, MKDEV(major, 0), NULL, "hello_drv");
return 0;
}
static void hello_drv_exit(void)
{
printk(KERN_EMERG "hello_drv_exit...\n");
unregister_chrdev(major, "hello_drv");
class_device_unregister(hellodrv_class_dev);
class_destroy(hellodrv_class);
}
module_init(hello_drv_init);
module_exit(hello_drv_exit);
MODULE_LICENSE("GPL");
MakeFile如下
KERN_DIR = /home/Linux_kernel/4.4.y/linux
all:
make -C $(KERN_DIR) M=`pwd` modules
clean:
rm -rf *.o
make -C $(KERN_DIR) M=`pwd` modules clean
obj-m += hello_driver.o
KERN_DIR根据实际源码所在文件目录位置进行修改
如果是第一次编译驱动,首先要把源码编译一遍才可以,否则会报错。
将驱动程序与Makefile放入ubuntu
然后执行make
aarch64-linux-gcc: error: unrecognized argument in option ‘-mcmodel=kernel’
aarch64-linux-gcc: note: valid arguments to ‘-mcmodel=’ are: large small tiny
aarch64-linux-gcc: error: unrecognized command line option ‘-mno-sse’; did you mean ‘-fno-ds’?
aarch64-linux-gcc: error: unrecognized command line option ‘-mno-mmx’
aarch64-linux-gcc: error: unrecognized command line option ‘-mno-sse2’; did you mean ‘-fno-dse’?
aarch64-linux-gcc: error: unrecognized command line option ‘-mno-3dnow’
aarch64-linux-gcc: error: unrecognized command line option ‘-m64’
aarch64-linux-gcc: error: unrecognized command line option ‘-mno-red-zone’; did you mean ‘-fno-regmove’?
很好,一堆错误。这时候不要急,看着错误信息一步一步查。
红框里的是错误的关键,仔细一看,居然用了x86架构下的Makefile,难怪这么多错误,我们写的是arm架构下的驱动。
那么在make的时候加入架构相关的信息
make ARCH=arm64
implicit declaration of function ‘class_create’ [-Werror=implicit-function-declaration]
implicit declaration of function ‘class_device_create’ [-Werror=implicit-function-declaration]
报错,原因是因为内核版本不一样导致的一些函数的名字不一样
增加头文件
#include <linux/device.h>
使用struct device代替struct class_device
使用device_create()代替class_device_create()
使用device_unregister()代替class_device_unregister()
再次编译试试
没有报错,生成了.ko文件,成功了
接下来写测试程序
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
int main(int argc, char **argv)
{
int fd;
int ret;
char *file_name = "/dev/hello_drv";
fd = open(file_name, O_RDWR|O_NOCTTY|O_NDELAY);
if(fd < 0)
{
printf("can't open file %s\n", file_name);
return -1;
}
close(fd);
return 0;
}
交叉编译
aarch64-linux-gcc -o hello_test hello_test.c
将生成的驱动和测试程序拷贝到ARM板上进行测试
首先,安装驱动
insmod hello_driver.ko
lsmod查看
已经安装成功
查看设备号,这里使用的是自动分配设备号的方式
cat /proc/devices
查看是否生成设备节点
ls /dev/
启动测试程序,先添加可执行属性
chmod +x hello_test
./hello_test
执行完发现没有任何打印信息,但是我们在驱动中,在初始化、退出、打开文件的地方都有打印语句,这是为什么?
原来,我使用的是SSH远程登录,而printk所打印的内核信息只会通过控制台串口进行输出,也就是ttySAC0串口,并不会打印到远程端口,那么如何查看是否有打印信息呢?
第一种方法,在命令行输入
cat kmsg
可以看到最下面就是驱动打印的信息
第二种方法,在命令行输入
dmsg
在最后也可以看到驱动的打印信息
最简单的驱动程序测试成功!
万事开头难,接下来可以继续完善复杂的驱动了。
完整的源码放在github上,有需要可以自行下载。 代码名称为190518.zip
https://github.com/ljy980330/opencv_face_sys
有任何问题可以在下面给我留言!大家一起学习!