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

此篇文章接上一篇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"],

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值