博客
关于我
树莓派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/

    你可能感兴趣的文章
    Netty工作笔记0014---Buffer类型化和只读
    查看>>
    Netty工作笔记0050---Netty核心模块1
    查看>>
    Netty工作笔记0084---通过自定义协议解决粘包拆包问题2
    查看>>
    Netty常见组件二
    查看>>
    netty底层源码探究:启动流程;EventLoop中的selector、线程、任务队列;监听处理accept、read事件流程;
    查看>>
    Netty核心模块组件
    查看>>
    Netty框架的服务端开发中创建EventLoopGroup对象时线程数量源码解析
    查看>>
    Netty源码—2.Reactor线程模型一
    查看>>
    Netty源码—4.客户端接入流程一
    查看>>
    Netty源码—4.客户端接入流程二
    查看>>
    Netty源码—5.Pipeline和Handler一
    查看>>
    Netty源码—6.ByteBuf原理二
    查看>>
    Netty源码—7.ByteBuf原理三
    查看>>
    Netty源码—7.ByteBuf原理四
    查看>>
    Netty源码—8.编解码原理二
    查看>>
    Netty源码解读
    查看>>
    Netty的Socket编程详解-搭建服务端与客户端并进行数据传输
    查看>>
    Netty相关
    查看>>
    Network Dissection:Quantifying Interpretability of Deep Visual Representations(深层视觉表征的量化解释)
    查看>>
    Network Sniffer and Connection Analyzer
    查看>>