AOSP添加新硬件设备开发-HAL层

2023-05-16

此篇文章接上一篇hidl,我们来实现hal层

hal层官方解释系统硬件抽象层,理解为kernel的代理层,他的存在屏蔽了不同硬件设备的差异,根据提供的访问标准,就可以对不同的硬件进行操作,也为不同的厂商隐藏了驱动的核心功能,比如一些算法

抽象层命名

硬件抽象层以模块的形式来管理各个硬件访问接口。每一个硬件模块都对应有一个动态链接库文件,动态链接库文件的命名要符合一定的规范。

那么该如何命名呢?

源码中硬件抽象层模块的命名定义在aosp/hardware/libhardware/hardware.c文件中,我们可以阅读下该文件,了解下加载的过程,就能明白我们文件该如何命名了

hw_get_module()---->hw_get_module_by_class()  --→load()

hw_get_module_by_class(){

    /*  

     * Here we rely on the fact that calling dlopen multiple times on

     * the same .so will simply increment a refcount (and not load

     * a new copy of the library).

     * We also assume that dlopen() is thread-safe.

     */

    /* First try a property specific to the class and possibly instance */

    snprintf(prop_name, sizeof(prop_name), "ro.hardware.%s", name);

    if (property_get(prop_name, prop, NULL) > 0) {

        if (hw_module_exists(path, sizeof(path), name, prop) == 0) {

            goto found;

        }   

    }   
    /* Loop through the configuration variants looking for a module */

    for (i=0 ; i<HAL_VARIANT_KEYS_COUNT; i++) {

        if (property_get(variant_keys[i], prop, NULL) == 0) {

            continue;

        }   

        if (hw_module_exists(path, sizeof(path), name, prop) == 0) {

            goto found;

        }   

    }  
  /* Nothing found, try the default */

    if (hw_module_exists(path, sizeof(path), name, "default") == 0) {

        goto found;

    } 

}

static const char *variant_keys[] = {
    "ro.hardware",  /* This goes first so that it can pick up a different
                       file on the emulator. */
    "ro.product.board",
    "ro.board.platform",
    "ro.arch"
};

通读代码我们可以看出加载过程会先读取variant_keys定义的四个系统属性,并检查对应的文件是否存在,如果存在,就load这个硬件抽象模块,如果四个属性对应的文件都不存在,那么就会找含“default“文件加载,比如led.default.so(<MODULE_ID>.default.so)。硬件抽象层模块命名规范为“<MODULE_ID>.variant.so”, MODULE_ID表示模块id,一般我们取自己模块属性比较直观的名称,比如led,

模块接口

在硬件抽象层中,实现一个模块主要涉及三个定义结构:

  • struct hw_module_t
  • struct hw_module_methods_t
  • struct hw_device_t

1,hal层的模块都要自定义一个hal模块结构体,便于区分不同的模块,并且成员类型必须包含hw_module_t。例:

typedef struct bear_module {
  struct hw_module_t common;
} bear_module_t;

2.实现自定义hal模块,变量名必须为HAL_MODULE_INFO_SYM

bear_module_t HAL_MODULE_INFO_SYM={

        .common = {

                .tag                = HARDWARE_MODULE_TAG,

                .module_api_version = BEAR_MODULE_API_VERSION_1_0,

                .hal_api_version    = HARDWARE_HAL_API_VERSION,

                .id                 = BEAR_HARDWARE_MODULE_ID,

                .name               = "bear HAL module",

                .author             = "fht",

                .methods            = &bearpi_module_methods,

        },  

};

3,“HARDWARE_MODULE_TAG”用来标识一个硬件抽象层模块,结构体成员tag的值必须为HARDWARE_MODULE_TAG('H'<<24|'W'<<16|'M'<<8|'T')。

4,hw_module_t结构体成员变量methods定义了一个硬件抽象层模块的操作方法列表,类型为我们上面介绍的hw_module_methods_t。

在aosp/hardware/libhardware/include/hardware/hardware.h中介绍hw_module_methods_t结构体只有一个成员变量,如下面内容

typedef struct hw_module_methods_t {

    /** Open a specific device */

    int (*open)(const struct hw_module_t* module, const char* id,

            struct hw_device_t** device);

} hw_module_methods_t;    

open是一个函数指针,用来打开硬件抽象层模块中的控制的硬件设备,参数介绍

  • module----要打开的硬件设备所在的模块
  • id-----------要打开的硬件设备的ID
  • device-----已经打开的硬件设备

5, 硬件抽象层中的硬件设备是由所在的hw_module_methods_t提供接口打开,关闭则是hw_device_t提供接口实现,hw_device_t的成员变量close是一个函数指针,被用来关闭硬件设备。

那么硬件抽象层是怎么工作的呢?

hidl访问驱动时,首先系统使用hw_get_module方法获得hardware层对应的module,然后后通过load加载库,并通过固定符号HAL_MODULE_INFO_SYM 寻找到hw_module_t结构体,并通过结构体hw_module_methods_t绑定的open方法打开模块,并将hw_device_t变量作为参数传递,这样我们就可以操作模块间接操作硬件了,用户也就可以实现操作硬件了。

案例实现

实现一个具有事件回调功能的硬件抽象层

一,创建bearpi.h, 路径hardware/libhardware/include/hardware/bearpi.h

/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ANDROID_INCLUDE_HARDWARE_BEAR_PI_H
#define ANDROID_INCLUDE_HARDWARE_BEAR_PI_H

#include <hardware/hardware.h>
#include <hardware/hw_auth_token.h>

#define BEAR_MODULE_API_VERSION_1_0 HARDWARE_MODULE_API_VERSION(1, 0)
#define BEAR_HARDWARE_MODULE_ID "bearpi" //需要与库名称相同 bearpi.default.so,否则找不到hal

typedef enum bear_msg_type {
    BEAR_ERROR = -1,
    BEAR_ACQUIRED = 1,
} bear_msg_type_t;


/*
 * Bear acquisition info is meant as feedback for the current operation.  Anything but
 * BEAR_ACQUIRED_GOOD will be shown to the user as feedback on how to take action on the
 * current operation. For example, BEAR_ACQUIRED_IMAGER_DIRTY can be used to tell the user
 * to clean the sensor.  If this will cause the current operation to fail,
 * In general, these messages will result in a "Try again" message.
 */
typedef enum bear_acquired_info {
    BEAR_ACQUIRED_GOOD = 0,
    BEAR_ACQUIRED_PARTIAL = 1, /* sensor needs more data, i.e. longer swipe. */
    BEAR_ACQUIRED_INSUFFICIENT = 2, /* image doesn't contain enough detail for recognition*/
    BEAR_ACQUIRED_IMAGER_DIRTY = 3, /* sensor needs to be cleaned */
    BEAR_ACQUIRED_TOO_SLOW = 4, /* mostly swipe-type sensors; not enough data collected */
    BEAR_ACQUIRED_TOO_FAST = 5, /* for swipe and area sensors; tell user to slow down*/
    BEAR_ACQUIRED_DETECTED = 6, /* when the finger is first detected. Used to optimize wakeup.
                                          Should be followed by one of the above messages */
    BEAR_ACQUIRED_VENDOR_BASE = 1000 /* vendor-specific acquisition messages start here */
} bear_acquired_info_t;


typedef struct bear_acquired {
    bear_acquired_info_t acquired_info; /* information about the image */
} bear_acquired_t;


typedef struct bear_msg {
    bear_msg_type_t type;
    union {
        bear_acquired_t acquired;
    } data;
} bear_msg_t;

/* Callback function type */
typedef void (*bear_notify_t)(const bear_msg_t *msg);  ------------------声明 bear_notfify_t 类型的函数指针

/* 自定义设备结构体 */
typedef struct bear_device {
    /**
     * Common methods of the fingerprint device. This *must* be the first member
     * of fingerprint_device as users of this structure will cast a hw_device_t
     * to fingerprint_device pointer in contexts where it's known
     * the hw_device_t references a fingerprint_device.
     */
    struct hw_device_t common;

    /*
     * Client provided callback function to receive notifications.
     * Do not set by hand, use the function above instead.
     */
    bear_notify_t notify;

    /*
     * Set notification callback:
     * Registers a user function that would receive notifications from the HAL
     * The call will block if the HAL state machine is in busy state until HAL
     * leaves the busy state.
     *
     * Function return: 0 if callback function is successfuly registered
     *                  or a negative number in case of error, generally from the errno.h set.
     */
    int (*set_notify)(struct bear_device *dev, bear_notify_t notify);

    uint64_t (*test)(struct bear_device *dev);
    int (*set_val)(struct bear_device *dev, int val);

    int (*get_val)(struct bear_device *dev, int *val);

} bear_device_t;

/*自定义模块结构体*/
typedef struct bear_module {
    /**
     * Common methods of the bear module. This *must* be the first member
     * of bear_module as users of this structure will cast a hw_module_t
     * to bear_module pointer in contexts where it's known
     * the hw_module_t references a bear_module.
     */
    struct hw_module_t common;
} bear_module_t;

#endif  /* ANDROID_INCLUDE_HARDWARE_BEAR_PI_H */

二,创建bearpi module 路径hardware/libhardware/modules/, 在bearpi目录下新建bearpi.c

/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#define LOG_TAG "lemon"

#include <errno.h>
#include <malloc.h>
#include <stdint.h>
#include <string.h>
#include <log/log.h>
#include <hardware/bearpi.h>
#include <hardware/hardware.h>

#define DEVICE_NAME "/dev/bearpi"

bear_notify_t gNotify; //定义全局函数指针变量

void set_notify(bear_notify_t notify){
    gNotify = notify;
}

static int bearpi_close(hw_device_t *dev){
    struct bear_device_t* bear_device = (struct bear_device_t*) dev;
    if(bear_device){
        close(bear_device->fd);
        free(bear_device);
        return 0;
    }else{
        return -1;
    }
}

/*设备寄存器读写接口*/
static int bearpi_get_val(struct bear_device* dev, int *val){

    if(!dev){
        ALOGE("bearpi device null pointer");
        return -EFAULT;
    }

    if(!val){
        ALOGE("bearpi val null pointer");
        return -EFAULT;
    }

    read(dev->fd, val, sizeof(*val));
    ALOGD(" bearpi get value = &d", *val);
    return 0;

}

static int bearpi_set_val(struct bear_device* dev, int val){
    if(!dev){
        ALOGE("bearpi device null pointer");
        return -EFAULT;
    }

    write(dev->fd, &val, sizeof(val));
    ALOGD("bearpi set val success !");
    return 0;
}

/*由上文hidl 调用注册回调*/
static int set_notify_callback(struct bear_device __unused *dev, bear_notify_t notify){
    dev->notify=notify;
    set_notify(notify);
    ALOGD("%s",__func__ );
    return 0;
}

/*调用test 之后通过函数指针作为回调函数,通知hidl 层,事件结果*/
static  uint64_t bearpi_test(struct bear_device __unused *dev){
    ALOGD("%s:start ",__func__ );
    bear_msg_t msg;
    bear_acquired_t acquired;

    msg.type = BEAR_ACQUIRED;
    acquired.acquired_info = BEAR_ACQUIRED_PARTIAL;
    msg.data.acquired = acquired;
    gNotify(&msg);
    ALOGD("%s: end ",__func__ );
    return 0;
}

static int bearpi_open(const hw_module_t* module, const char __unused *id, hw_device_t** device){
    if(device == NULL){
        ALOGE("NULL device on open");
        return -EINVAL;
    }
    ALOGD("%s: start ",__func__ );

    bear_device_t *dev = malloc(sizeof(bear_device_t));

    if(!dev){
        ALOGE("Failed to alloc space for bearpi");
        return -EFAULT;
    }

    memset(dev, 0, sizeof(bear_device_t));

    dev->common.tag = HARDWARE_DEVICE_TAG;
    dev->common.version = BEAR_MODULE_API_VERSION_1_0;
    dev->common.module = (struct hw_module_t*) module;
    dev->common.close = bearpi_close;

    dev->test= bearpi_test;
    dev->set_notify = set_notify_callback;
    dev->notify=NULL;
    dev->set_val = bearpi_set_val;
    dev->get_val = bearpi_get_val;

    if((dev->fd = open(DEVICE_NAME, O_RDWR) == -1)){
        ALOGE("Failed to open device /dev/bearpi!!!");
        free(dev);
        return -EFAULT;
    }

    *device = (hw_device_t*) dev;
    ALOGD("%s: end",__func__ );
    return 0;
}

static struct hw_module_methods_t bearpi_module_methods = {
        .open = bearpi_open,
};

bear_module_t HAL_MODULE_INFO_SYM={
        .common = {
                .tag                = HARDWARE_MODULE_TAG,
                .module_api_version = BEAR_MODULE_API_VERSION_1_0,
                .hal_api_version    = HARDWARE_HAL_API_VERSION,
                .id                 = BEAR_HARDWARE_MODULE_ID,
                .name               = "bear HAL module",
                .author             = "lemon",
                .methods            = &bearpi_module_methods,
        },
};

三,创建Android.bp文件

cc_library_shared {

    name: "bearpi.default",

    relative_install_path: "hw",

    //compile_multilib: "64",

    proprietary: true,

    srcs: ["bearpi.c"],

    cflags: ["-Wno-unused-parameter",

            "-Wno-unused-const-variable",

            "-Wno-unused-variable"],

    header_libs: ["libhardware_headers"],

    shared_libs: ["liblog"],

}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

AOSP添加新硬件设备开发-HAL层 的相关文章

随机推荐

  • Ubuntu系统使用root远程登录

    https blog csdn net weixin 45239621 article details 115523031 Ubuntu系统使用root远程登录的操作 一般这种情况是某某云服务器或者新的Ubuntu系统 xff08 仅Ubu
  • npm 安装详细教程

    https blog csdn net Cleve baby article details 125632341 转载 xff1a http xiaoyaojones blog 163 com blog static 28370125201
  • Linux新建用户,切换后只显示$问题

    问题 xff1a linux新建用户 xff0c 切换后只显示 的问题 xff0c 而且有些命令也使用不了 xff0c 解决方法如下 1 新建用户命令 root登录 useradd d usr sam m jiang 此命令创建了一个用户j
  • DTI(dwi)使用FSL做预处理及做TBSS处理流程(fsleyes查看结果)

    预处理 刚开始我用的数据初始文件是多个dcm格式的文件 xff0c 当时我从格式转换 提取b0 波脑 涡流 计算张量下来是没有问题的 后来我用dwi的文件 xff08 包含四维的 nii gz bvec bval文件 xff09 xff0c
  • 引用的问题

    1 二者的区别 xff08 1 xff09 引用 访问一个变量是直接访问 xff0c 而指针是间接访问 xff08 2 xff09 引用 是一个变量的别名 xff0c 本身不单独分配自己的内存空间 xff0c 而指针有自己的内存空间 xff
  • Android抓取log文件的方法

    很简单 xff0c 使用命令行来就可以 xff0c 步骤如下 xff1a 1 adb devices 检查调试设备是否连接好 xff0c 没有调试设备抓不了 2 adb logcat c 3 cd Desktop 进入你要存放日志文件的目录
  • ESLint 配置入门

    大家好 xff0c 我是前端西瓜哥 xff0c 今天带大家了解 ESLint 的配置项 ESLint 是一款检查 JavaScript 程序是否符合特定的规则的工具 比如字符串用单引号还是双引号 xff0c tab 缩进用 2 个空格还是
  • linux开机自动登陆

    在超级用户的身份下 编辑vim etc gdm custom conf span class hljs number 1 span span class hljs comment GDM configuration storage span
  • Python(Web服务)全链路日志个跟踪

    1 背景 在我们的实际项目中 xff0c 尤其以Web服务为例 xff0c 经常遇到要做日志跟踪的场景 我们经常采用的方式是 xff0c 生成一个trace id 在全链路的调用中都输出这个id进行跟踪 这里需要处理的几个问题是 xff1a
  • BCLinux用yum安装报Your license is invalid.

    1 介绍 BCLinux基于 CentOS 进行定制化 xff0c 满足企业对于通用 Linux 操作系统的需求 xff0c 提供标准化 平台化的产品发布及运行环境 xff0c 该版本与红帽商业版本及社区版本完全兼容 2 步骤 安装好操作系
  • Excel表格数据如何批量乘以一个数字

    今天跟大家分享一下Excel表格数据如何批量乘以一个数字 1 打开Excel文件 xff0c 我们想要批量将数字乘以10 2 首先我们选择所有数据单元格区域 3 点击下图选项 xff08 Excel工具箱 xff0c 百度即可了解详细下载安
  • Win2003系统部署SSL证书(部署https教程)

    在windows 2003操作系统下 xff0c IIS 6 环境的服务器SSL证书安装教程 安装前 xff0c 请准备好SSL证书 部署前请退出服务器内安装的杀毒软件 xff08 360 金山 安全狗等安全软件有可能导致SSL证书部署出错
  • Android启动模式之singleinstance的坑

    Android启动模式之singleinstance的坑 前言 在实际应用中 xff0c 使用singleinstance启动模式时 xff0c 会遇到一些奇奇怪怪的问题 Android有四种启动模式 xff0c 分别是standard x
  • 关于使用iconfont图标总生成小长方形框的解决办法

    起因是在联系仿写网易的静态页面的时候 xff0c 使用iconfont小图标的时候 xff0c 引入正确 xff0c 但是在页面上一直显示的是一个长方形小框的页面 各种搜索终于找到了解决办法 主要原因是由于iconfont css中路径不对
  • Qt和MFC的效率对比

    Qt和MFC的效率对比 之前一直做mfc xff0c 昨天看了一晚上的Qt xff0c 瞬间就喜欢上它了 xff0c Qt在windows下应该没有mfc的运行效率高 xff0c 但是我想知道差多少 xff0c 不知有没有大牛做过这方面的对
  • android 移植

    from http wiki kldp org wiki php AndroidPortingOnRealTarget s 6 1 Contents 1 Introduction 2 Copyright and Acknowledgemen
  • LD3320语音识别模块+JQ8900-TF语音模块实现简单的语音交互控制

    玩这个真的要感谢头条的强大推荐 xff0c 清明节回家的大巴车上 xff0c 无聊的刷着头条 xff0c 很智能的给我推荐了一款语音识别模块 xff0c 一直很想自己试着玩一把的我 xff0c 按奈不住 xff0c 点开视频看到了介绍 xf
  • 智能配网方案 Airkiss 技术原理介绍及应用

    写在前面 站在巨人的肩膀上 xff0c 可以看得更远 一 什么是Air Kiss 可以说AirKiss 是微信硬件平台提供的一种WIFI硬件设备快速配置连接网络的技术 xff0c 是一种创新性的信息传递技术 通过该技术可以便捷的向一台具有W
  • 谈谈Android 安全策略SElinux

    不积跬步无以至千里 xff0c 补全自己的短板 xff0c 完善体系 xff0c 站在巨人的肩膀上 xff0c 看到的更远 xff0c 写这篇文章也算是对这个知识点的总结 一 xff0c 背景 SElinux出现之前 xff0c Linux
  • AOSP添加新硬件设备开发-HAL层

    此篇文章接上一篇hidl 我们来实现hal层 hal层官方解释系统硬件抽象层 xff0c 理解为kernel的代理层 xff0c 他的存在屏蔽了不同硬件设备的差异 xff0c 根据提供的访问标准 xff0c 就可以对不同的硬件进行操作 xf