本文共 3132 字,大约阅读时间需要 10 分钟。
在开始编写驱动程序之前,需要完成以下几项准备工作:
确认内核版本一致性
确保树莓派上的内核版本与虚拟机中的Linux内核版本保持一致。内核版本不一致将导致驱动无法正确安装。确保交叉编译工具的存在
虚拟机中需要预先安装交叉编译工具,这些工具将用于将驱动程序编译为树莓派所需的机器码(binaries)。确定交叉编译参数
KERNEL=kernel7l。KERNEL=kernel7。驱动程序的编写基于标准的Linux内核模块框架,以下是详细步骤:
file_operations结构体驱动程序的核心是定义一个符合Linux内核规范的文件操作接口。以下是file_operations结构体的定义示例:
#include#include #include #include #include #include #include static int Test_open(struct inode *inode, struct file *file) { printk("pin4_open\n"); return 0;}static ssize_t Test_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { printk("pin4_write\n"); return 0;}static struct file_operations pin4_fops = { .owner = THIS_MODULE, .open = Test_open, .write = Test_write,};
注意事项:
static关键字是为了避免函数名冲突,确保在内核环境中不会出现命名冲突。初始化函数负责将驱动注册到内核中,创建设备节点等。以下是初始化函数的实现示例:
#include#include #include #include #include #include #include static struct class *Test_class;static struct device *Test_dev;static dev_t devno;static int major = 240; // 设备主号static int minor = 0; // 设备次号static char *module_name = "test"; // 驱动名称static int Test_open(struct inode *inode, struct file *file) { printk("Test_open\n"); return 0;}static ssize_t Test_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { printk("Test_write\n"); return 0;}static struct file_operations Test_fops = { .owner = THIS_MODULE, .open = Test_open, .write = Test_write,};int __init Test_dev_init(void) { int ret; devno = MKDEV(major, minor); ret = register_chrdev(major, module_name, &Test_fops); Test_class = class_create(THIS_MODULE, "Test_class"); Test_dev = device_create(&Test_class, NULL, devno, NULL, module_name); return 0;}
注意事项:
MKDEV宏用于创建设备号,register_chrdev函数用于将设备注册到内核中。class_create和device_create函数分别用于创建设备类和设备节点。驱动程序的退出函数负责卸载设备和释放资源:
void __exit Test_exit(void) { device_destroy(Test_class, devno); class_destroy(Test_class); unregister_chrdev(major, module_name);}module_init(Test_dev_init);module_exit(Test_exit);MODULE_LICENSE("GPL v2"); 完成驱动程序编写后,需要按照以下步骤进行编译:
将驱动文件放置在内核文件系统的/drivers/char/目录下:
cp Test.c /home/.../drivers/char/
修改Makefile文件,将驱动源文件添加到编译列表中:
obj-m += test.o
在内核文件根目录下,执行编译命令(以树莓派4为例):
ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7l make -j4 modules
编译完成后,检查并修复可能的错误(如语法错误或缺少分号等),重新编译。
将编译生成的驱动模块文件复制到树莓派上:
scp drivers/char/xxx.ko pi@ <树莓派ip地址> :/home/xxx/ 树莓派ip地址>
在树莓派上安装驱动:
sudo insmod xxx.kosudo chmod 666 /dev/xxx
注意事项:
/dev/xxx节点不存在,请检查设备号是否正确,并确保设备号唯一。编写一个简单的用户空间测试程序来验证驱动功能:
#include#include #include #include int main() { int fd; int cmd = 1; fd = open("/dev/test", O_RDWR); if (fd < 0) { perror("open failed"); return -1; } fd = write(fd, &cmd, sizeof(int)); return 0;}
测试命令:
./test_program
查看内核日志:
使用dmesg命令查看驱动安装和运行时的内核打印信息: dmesg
转载地址:http://stlwz.baihongyu.com/