基本逻辑
分析代码之前可以先想下,如果自己要写一个设备驱动的框架出来,大概要考虑的地方。
我们首先看可能的需求,opensbi作为一个支持多平台多设备的BIOS,它需要支持多个不同
的硬件平台,每个平台上会有不同的硬件设备,不同的硬件设备需要与之匹配的驱动,这里
可以看出,首先要有描述设备的软件结构和描述驱动的软件结构。设备需要有一定的发现
机制,这样才能和硬件解耦合,一个好的办法是软件检测dts中定义的设备,然后为之创建
如上的设备软件结构。设备和驱动之间需要有一定的匹配机制,这样,驱动可以和相关设备
建立关联,进而驱动设备。对于一类设备驱动,需要抽象出一个对外的公共接口层,用户
统一通过这个公共接口层访问设备,这样可以屏蔽底层硬件的差异。
如下是一个大概的示意图:
1 | +-----+ +---------------+ |
看一个例子
opensbi里用platform这个全局结构体收集特定平台上所有设备的初始化入口和特定平台的
配置参数,对于一个编译好的二进制,因为平台是确定的,这个platform结构也是唯一的。
不同类的设备要在platform里有不同的初始化入口函数,这样在opensbi的主流程里,调用
对应的初始化函数就可以初始化对应的设备。
我们具体看下串口这类设备是怎么搞的,我们具体看generic这个平台的实现。fdt_serial_init
是generic platform里的串口类设备初始化函数,这个函数扫描dts里stdout-path域段,
找见dts中的串口描述节点,然后查看opensbi fdt_serial_drivers这个表格,按照dts
compatible域段的信息和驱动做匹配,所有串口相关的驱动要静态的放到fdt_serial_drivers
这个表里,找见相匹配的驱动后,就调用驱动的init函数初始化串口设备,驱动的初始化
函数同时把具体设备注册到串口的公共接口里:sbi_console_set_device。
这里使用一个console_dev的全局变量表示当前的显示设备,显示公共接口就是直接调用
console_dev里的输入输出回调函数:
1 | sbi_getc |