驱动编写的三种方式:传统/总线/设备树

字符设备驱动程序框架:

如何编写驱动代码

① 确定主设备号,也可以让内核分配

② 定义自己的 file_operations 结构体

③ 实现对应的 drv_open/drv_read/drv_write 等函数,填入 file_operations 结构体

④ 把 file_operations 结构体告诉内核:register_chrdev

⑤ 谁来注册驱动程序啊?得有一个入口函数:安装驱动程序时,就会去调用这个入口函数

⑥ 有入口函数就应该有出口函数:卸载驱动程序时,出口函数调用 unregister_chrdev

⑦ 其他完善:提供设备信息,自动创建设备节点:class_create, device_create

 

我们需要知道什么资料或整体操作步骤是什么?

 

如何告诉驱动程序引用的是什么那个引脚(传统/总线/设备树): 

三者的区别在于如何指定硬件资源。

传统方法:

即在代码中写死,即直接将寄存器地址配置给设备。

LED: 0X......

总线模式:

包含两个文件:

led_drv.c   :注册file_operations,初始化结构体。

led_dev.c:    指定引脚

设备树模式:

led_drv.c   :注册file_operations,初始化结构体。

jz3440.dts:    指定引脚

 

三者的区别:

以点亮两个LED的案例来解释:

传统:

首先,写led_drv.c: 

分配:allc file_operations.

设置:配置相应的LED操作函数:read/write/open等

注册:

入口函数/出口函数:

但如果是配置两个LED驱动,方法是将前面注册调用的操作复制一遍,将其pin1->pin2。所以,相对编程简单,但是不容易维护,因为新的板子过来需要重新修改led.c的代码

 

总线模式:

总线将引脚抽出来,单独去配置。

led_drv.c / led_dev.c 将文件挂载在platform总线,led.drv与前面操作相同,不同在于led_dev.c用来指定资源

led_dev.c 会分配/注册一个platform_devices,通过“.resource”来指定引脚。对于不同的board,公用同一led_drc.c。

led-drv.c 分配/设置/注册 platform_driver struct。内包含“probe”, "driver_struct"

probe:分配注册file_operations

     设置/注册.....与前面相同

而引脚在platform中被指定,我们在操作GPIO即platform的硬件资源,当borad被修改后,直接修改led_dev.c 的platform中的硬件资源即可。

但是这种方式对于不同的驱动程序,需要注册不同的“resource”,造成代码的冗余,且因为dev为.c文件需要重新编译

 

设备树:

组成:led_drv.c(与总线相同),设备树文件(*.dts)执行硬件资源

kernel根据*.dts构造platform_dev,在运行时去解析dts文件,来分配/注册一个platform_dev,所以在配置时不需要重新编译,只需要拷贝dts文件即可

 

posted @ 2023-05-21 12:55  嵌入式小白—  阅读(138)  评论(0编辑  收藏  举报