基于W800的HDF驱动框架适配 原创 精华

润和软件HiHope
发布于 2022-4-21 15:48
浏览
3收藏

作者:润和软件 李璐
HDF(Hardware Driver Foundation)驱动框架,为驱动开发者提供驱动框架能力,包括驱动加载、驱动服务管理和驱动消息机制。旨在构建统一的驱动架构平台,为驱动开发者提供更精准、更高效的开发环境,力求做到一次开发,多系统部署。
驱动加载
HDF驱动加载包括按需加载和按序加载。
按需加载: HDF框架支持驱动在系统启动过程中默认加载,或者在系统启动之后动态加载。
按序加载: HDF框架支持驱动在系统启动的过程中按照驱动的优先级进行加载。
驱动服务管理
HDF框架可以集中管理驱动服务,开发者可直接通过HDF框架对外提供的能力接口获取驱动相关的服务。
驱动消息机制
HDF框架提供统一的驱动消息机制,支持用户态应用向内核态驱动发送消息,也支持内核态驱动向用户态应用发送消息。
本文基于W800适配HDF驱动框架,分析轻量系统的HDF驱动框架适配,HDF驱动适配应在内核移植Kconfig适配之后。
驱动启动流程
在系统启动时,HDF驱动框架先启动,通过解析配置文件获取到设备列表,读取".hdf.drivers"段读取到驱动程序(Driver Entry)列表,然后遍历设备列表与驱动程序列表进行匹配,并加载匹配成功的驱动。驱动框架有两大核心管理者:
· DeviceManager 负责设备的管理,包括设备加载、卸载和查询等设备相关功能。
· DeviceServiceManager 负责管理设备发布的接口服务,提供接口服务的发布、查询等功能。
驱动加载主要由 DeviceManager 主导,首先 DeviceManager 要解析配置文件中的 Host 列表,根据 Host 列表中的信息来实例化对应的 Host 对象。Host 解析配置文件获取到关联的设备列表,遍历设备列表去获取与之匹配的驱动程序名称,然后基于.hdf.driver section 获得驱动程序地址。 HDF驱动启动流程如下:
HDF框架启动
在device/soc/winnermicro/wm800/board/app/main.c文件中,DeviceManagerStart()函数为HDF框架入口函数,如下:

......
  if (DeviceManagerStart()) {                                     --- HDF初始化
      printf("[%s] No drivers need load by hdf manager!",__func__);
  }
......

获取驱动程序列表
HDF 驱动框架通过将驱动程序入口符号的地址集中存放到一个特殊的 section 来实现对驱动的索引,这个 section 的开头和末尾插入了_hdf_drivers_start、_hdf_drivers_end 两个特殊符号,用于标记这个 section 的范围,两个特殊符号之间的数据即为驱动实现指针。
在文件 device\soc\winnermicro\wm800\board\ld\w800\gcc_csky.ld中,具体实现如下:

.data : {
. = ALIGN(0x4) ;
__sdata = . ;
__data_start__ = . ;
......
. = ALIGN(4);
_hdf_drivers_start = .;
KEEP(*(.hdf.driver))
_hdf_drivers_end = .;
 
. = ALIGN(0x4) ;
__edata = .;
__data_end__ = .;
} > REGION_DATA AT > REGION_RODATA

获取设备列表

配置文本编译后会变成二进制格式的配置文件,其中设备相关信息被存放在一个用“hdf_manager”标记的 device_info 配置块中,host 的内容以块的形式在 device_info 块中依次排列,host 块中记录了 host 名称、启动优先级和设备列表信息。 设备信息中的 moduleName 字段将用于和驱动程序入口中的 moduleName 进行匹配,从而为设备匹配到正确的驱动程序。
在文件device\soc\winnermicro\wm800\hdf_config\device_info.hcs中,具体实现如下(以GPIO为例):

evice_info {                                         --- device_info 配置块
  match_attr = "hdf_manager";
    ......
    platform :: host {                               --- host 块
      hostName = "platform_host";
      priority = 50;
      device_gpio :: device {
          gpio0 :: deviceNode {
              policy = 0;
              priority = 45;
              moduleName = "WM_GPIO_MODULE_HDF";   --- moduleName 字段
              serviceName = "HDF_PLATFORM_GPIO";
              deviceMatchAttr = "gpio_config";
          }
      }
  ......

在文件drivers\adapter\platform\gpio\gpio_wm.c 中,moduleName 字段与设备信息中的 moduleName字段保持一致,如下:

/* HdfDriverEntry definitions */
struct HdfDriverEntry g_GpioDriverEntry = {
  .moduleVersion = 1,
  .moduleName = "WM_GPIO_MODULE_HDF",               --- moduleName 字段
  .Bind = GpioDriverBind,
  .Init = GpioDriverInit,
  .Release = GpioDriverRelease,
};
HDF_INIT(g_GpioDriverEntry);

驱动程序加载流程
Device Manager 遍历设备列表,当查找到对应驱动实现时,为设备创建 Device 对象实例,如果设备配置中的 policy 字段为需要对外发布的驱动接口(SERVICE_POLICY_CAPACITY),那么驱动的 Bind 接口将首先被调用,用于关联设备和服务实例。然后驱动的 Init 接口将被调用,用于完成驱动的相关初始化工作。如果驱动被卸载或者因为硬件等原因 Init 接口返回失败,Release 将被调用,用于释放驱动申请的各类配置。
HDF驱动框架适配
HDF驱动框架提供了一套应用访问硬件的统一接口,可以简化应用开发,添加HDF组件需要在//vendor/hihope/neptune_iotlink_demo/kernel_configs添加:

LOSCFG_DRIVERS_HDF=y
LOSCFG_DRIVERS_HDF_PLATFORM=y

可在kernel/liteos_m中执行make menuconfig,进入 Driver选项选择适配的外设,例如适配UART,可选中 Enable HDF platform uart driver。
驱动适配相关文件放置在drivers/adapter/platform中,对应有gpio,i2c,pwm,spi,uart,watchdog,都是通过HDF机制加载,以GPIO和UART为例进行详细说明。
GPIO适配
1.芯片驱动适配文件位于drivers/adapter/platform目录,在gpio目录增加gpio_wm.c文件,在BUILD.gn文件中,描述了W800驱动的编译适配。如下:

...
if (defined(LOSCFG_SOC_COMPANY_WINNERMICRO)) {
sources += [ "gpio_wm.c" ]
}
...

2.gpio_wm.c中GPIO驱动实现如下:

/* HdfDriverEntry definitions */
struct HdfDriverEntry g_GpioDriverEntry = {
  .moduleVersion = 1,
  .moduleName = "WM_GPIO_MODULE_HDF",
  .Bind = GpioDriverBind,
  .Init = GpioDriverInit,
  .Release = GpioDriverRelease,
};
HDF_INIT(g_GpioDriverEntry);

编写一个简单的驱动,首先需要实现驱动程序 (Driver Entry)入口中的三个主要接口:
Bind 接口:实现驱动接口实例化绑定,如果需要发布驱动接口,会在驱动加载过程中被调用,实例化该接口的驱动服务并和 DeviceObject 绑定。 Init 接口:实现驱动的初始化,返回错误将中止驱动加载流程。 Release 接口:实现驱动的卸载,在该接口中释放驱动实例的软硬件资源。
3.在文件device\soc\winnermicro\wm800\hdf_config\device_info.hcs中添加GPIO驱动配置,具体实现如下:

device_info {
  match_attr = "hdf_manager";
    ......
    platform :: host {
      hostName = "platform_host";
      priority = 50;
      device_gpio :: device {
          gpio0 :: deviceNode {
              policy = 0;
              priority = 45;
              moduleName = "WM_GPIO_MODULE_HDF";
              serviceName = "HDF_PLATFORM_GPIO";
              deviceMatchAttr = "gpio_config";
          }
      }
  ......

4.在device/board/hihope/shields/neptune100/neptune100.hcs添加gpio硬件描述信息, 添加内容如下:

root {
    platform {
     gpio_config {
         match_attr = "gpio_config";
         groupNum = 1;
         pinNum = 48;
     }
    }
}

5.在GpioDriverInit获取hcs参数进行初始化,如下:

 ...
 gpioCntlr = GpioCntlrFromHdfDev(device);        --- gpioCntlr节点变量就可以获取具体gpio配置
 if (gpioCntlr == NULL) {
     HDF_LOGE("GpioCntlrFromHdfDev fail\r\n");
     return HDF_DEV_ERR_NO_DEVICE_SERVICE;
 }
 ...

UART适配
1.芯片驱动适配文件位于drivers/adapter/platform目录,在uart目录增加uart_wm.c文件,在BUILD.gn文件中,描述了W800驱动的编译适配。如下:

...
if (defined(LOSCFG_SOC_COMPANY_WINNERMICRO)) {
  sources += [ "uart_wm.c" ]
}
...

2.uart_wm.c中UART驱动实现如下:

/* HdfDriverEntry definitions */
struct HdfDriverEntry g_UartDriverEntry = {
    .moduleVersion = 1,
    .moduleName = "W800_UART_MODULE_HDF",
    .Bind = UartDriverBind,
    .Init = UartDriverInit,
    .Release = UartDriverRelease,
};

/* Initialize HdfDriverEntry */
HDF_INIT(g_UartDriverEntry);

3.在文件device\soc\winnermicro\wm800\hdf_config\device_info.hcs中添加UART驱动配置,具体实现如下:

device_info {
    match_attr = "hdf_manager";
     ......
     platform :: host {
        hostName = "platform_host";
        priority = 50;
        device_uart :: device {
                /*uart0 :: deviceNode {
                    policy = 1;
                    priority = 40;
                    moduleName = "W800_UART_MODULE_HDF";
                    serviceName = "HDF_PLATFORM_UART_0";
                    deviceMatchAttr = "uart0_config";
                }*/
                uart1 :: deviceNode {
                    policy = 1;
                    priority = 50;
                    moduleName = "W800_UART_MODULE_HDF";
                    serviceName = "HDF_PLATFORM_UART_1";
                    deviceMatchAttr = "uart1_config";
                }
        }
    ......

4.在device/board/hihope/shields/neptune100/neptune100.hcs添加uart硬件描述信息, 添加内容如下:

root {
    platform {
     uart_config {
     /*
         uart0 {
             match_attr = "uart0_config";
             num = 0;
             baudrate = 115200;
             parity = 0;
             stopBit = 1;
             data = 8;
         }*/
         uart1 {
             match_attr = "uart1_config";
             num = 1;
             baudrate = 115200;
             parity = 0;
             stopBit = 1;
             data = 8;
         }
      }
   }
}

5.在UartDriverInit获取hcs参数进行初始化,如下:

 ...
 host = UartHostFromDevice(device);
 if (host == NULL) {
     HDF_LOGE("%s: host is NULL", __func__);
     return HDF_ERR_INVALID_OBJECT;
 }
 ...

参考链接

HDF驱动框架:https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/driver/driver-hdf-manage.md

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
标签
已于2022-4-21 15:50:15修改
4
收藏 3
回复
举报
回复
    相关推荐