博客
关于我
树莓派4B Linux的底层驱动编写体验
阅读量:390 次
发布时间:2019-03-05

本文共 3132 字,大约阅读时间需要 10 分钟。

一、编写前的准备工作

在开始编写驱动程序之前,需要完成以下几项准备工作:

  • 确认内核版本一致性

    确保树莓派上的内核版本与虚拟机中的Linux内核版本保持一致。内核版本不一致将导致驱动无法正确安装。

  • 确保交叉编译工具的存在

    虚拟机中需要预先安装交叉编译工具,这些工具将用于将驱动程序编译为树莓派所需的机器码(binaries)。

  • 确定交叉编译参数

    • 对于树莓派4,交叉编译驱动模块时,使用参数KERNEL=kernel7l
    • 对于树莓派2、3代,使用参数KERNEL=kernel7
  • 二、驱动程序编写

    驱动程序的编写基于标准的Linux内核模块框架,以下是详细步骤:

    1. 构建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关键字是为了避免函数名冲突,确保在内核环境中不会出现命名冲突。
    • 每个函数都需要打印相关信息以确认驱动的功能实现。

    2. 编写初始化函数

    初始化函数负责将驱动注册到内核中,创建设备节点等。以下是初始化函数的实现示例:

    #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_createdevice_create函数分别用于创建设备类和设备节点。

    3. 编写剩余内容

    驱动程序的退出函数负责卸载设备和释放资源:

    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/
  • 在树莓派上安装驱动:

    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/

    你可能感兴趣的文章
    PHP7安装pdo_mysql扩展
    查看>>
    PHP7实战开发简单CMS内容管理系统(7) 后台登录架构 用户登录校验
    查看>>
    php7,从phpExcel升级到PhpSpreadsheet
    查看>>
    PHP8.1 + ThinkPHP实战指南:高效构建现代化网站的六大技巧
    查看>>
    PHP8中match新语句的操作方法
    查看>>
    PHP:第一章——PHP中常量和预定义常量
    查看>>
    PHP:第一章——PHP中的位运算
    查看>>
    phpcms
    查看>>
    phpcms 2008 product.php pagesize参数代码注射漏洞
    查看>>
    phpcms V9 自定义添加 全局变量{DIY_PATH}方法
    查看>>
    Redis五种核心数据结构的基本使用与应用场景
    查看>>
    Redis五种数据结构简介
    查看>>
    PHPCMS多文件上传和上传数量限制
    查看>>
    phpEnv的PHP集成环境
    查看>>
    PHPExcel一些基本设置总结
    查看>>
    phpexcel中文手册
    查看>>
    PHPExcel导入导出 若在thinkPHP3.2中使用(无论实例还是静态调用(如new classname或classname::function)都必须加反斜杠,因3.2就命名空间,如/c...
    查看>>
    phpize及其用法
    查看>>
    phpMailer发送邮件
    查看>>
    PHPMailer发送邮件
    查看>>