传统 Hal 开发笔记4----实现 Hal 模块

目录

|---------------|
| 实现 Hal 模块 |

一、代码编写

接下来就来为上节实现的驱动写一个简单的 HAL 模块。

在 hardware/libhardware/include/hardware 目录下添加 hello_hal.h

c 复制代码
#ifndef _HARDWARE_HELLO_HAL_H
#define _HARDWARE_HELLO_HAL_H

#include <hardware/hardware.h>

__BEGIN_DECLS

#define HELLO_HAL_API_VERSION HARDWARE_MODULE_API_VERSION(1,0)

#define HELLO_HAL_HARDWARE_MODULE_ID "hello_hal"

#define HELLO_HAL_DEVICE_ID_MAIN "main_hello_hal"

struct hello_hal_device_t;

typedef struct hello_hal_device_t {
    struct hw_device_t common;

    int fd;  // 存储/dev/hello的文件描

    int (*hello_hal_open)(struct hello_hal_device_t* hello_hal_dev);

    int (*hello_hal_read)(struct hello_hal_device_t* hello_hal_dev, char* str);

    int (*hello_hal_write)(struct hello_hal_device_t* hello_hal_dev,const char* str);
} hello_hal_device_t;

static inline int hello_hal_methods_open(const struct hw_module_t* module, hello_hal_device_t** device)
{
    return module->methods->open(module, HELLO_HAL_DEVICE_ID_MAIN, (struct hw_device_t**)device);
}

__END_DECLS

#endif  // _HARDWARE_HELLO_HAL_H

这里的核心是:

  • 实现一个 hello_hal_device_t 结构体,这个结构体用于操作具体的硬件
  • 实现 hello_hal_methods_open 函数,这个函数用于从 hw_module_t 中找到 hello_hal_device_t 结构体实例
    接着在 hardware/libhardware/modules/ 目录下添加 hello_hal 目录,并在 hello_hal 目录下添加源码文件 hello_hal.c
c 复制代码
#include <hardware/hello_hal.h>
#include <hardware/hardware.h>

#include <cutils/log.h>

#include <malloc.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>


int hello_open (struct hello_hal_device_t* hello_hal_dev __unused) {
    // 打开/dev/hello,fd存入设备结构体
    hello_hal_dev->fd = open("/dev/hello", O_RDWR);
    if (hello_hal_dev->fd == -1) {
        ALOGE("hello_hal: can not open file /dev/hello, errno=%d", errno); // 用ALOGE打印日志
        return -1;
    }
    return 0;
}


int hello_close (struct hw_device_t* dev) {
    hello_hal_device_t* hello_hal_dev = (hello_hal_device_t*)dev;
    if (hello_hal_dev->fd >= 0) {
        close(hello_hal_dev->fd); // 关闭结构体中的fd
    }
    free(hello_hal_dev); // 释放设备结构体内存
    return 0;
}


int hello_read (struct hello_hal_device_t* hello_hal_dev __unused, char* str) {
    char buf[1024] = {0}; // 初始化缓冲区,避免脏数据
    int len = read(hello_hal_dev->fd, buf, sizeof(buf)-1);
    if (len > 0) {
        buf[len] = '\0';
        strcpy(str, buf);
        return len;
    } else if (len == 0) {
        ALOGW("hello_hal: read 0 bytes from /dev/hello");
        return 0;
    } else {
        ALOGE("hello_hal: read failed, errno=%d", errno);
        return -1;
    }
}

int hello_write (struct hello_hal_device_t* hello_hal_dev __unused, const char* str) {
    if (!str) { // 空指针校验
        ALOGE("hello_hal: write str is NULL");
        return -EINVAL;
    }
    int len = strlen(str) + 1;
    len = len < 1024 ? len : 1024;
    int ret = write(hello_hal_dev->fd, str, len);
    if (ret < 0) {
        ALOGE("hello_hal: write failed, errno=%d", errno);
        return -1;
    }
    return ret;
}

// HAL模块的open函数(创建设备实例)
static int hello_hal_open(const hw_module_t* module, const char* id __unused,
                          hw_device_t** device) {
    // 分配设备结构体内存(calloc自动初始化0)
    hello_hal_device_t *hello_hal_dev = calloc(1, sizeof(hello_hal_device_t));
    if (!hello_hal_dev) {
        ALOGE("hello_hal: Can not allocate memory for hello hal device");
        return -ENOMEM;
    }

    // 初始化hw_device_t(HAL框架要求)
    hello_hal_dev->common.tag = HARDWARE_DEVICE_TAG;
    hello_hal_dev->common.module = (hw_module_t *)module;
    hello_hal_dev->common.version = HARDWARE_DEVICE_API_VERSION(1,0);
    hello_hal_dev->common.close = hello_close; // 现在类型匹配

    // 绑定自定义函数指针
    hello_hal_dev->hello_hal_open = hello_open;
    hello_hal_dev->hello_hal_write = hello_write;
    hello_hal_dev->hello_hal_read = hello_read;

    // 输出设备指针给上层
    *device = (hw_device_t *)hello_hal_dev;

    return 0;
}

// HAL模块方法结构体
static struct hw_module_methods_t hello_hal_module_methods = {
    .open = hello_hal_open,
};

// HAL模块入口(必须命名为HAL_MODULE_INFO_SYM)
struct hw_module_t HAL_MODULE_INFO_SYM = {
    .tag = HARDWARE_MODULE_TAG,
    .module_api_version = HELLO_HAL_API_VERSION,
    .hal_api_version = HARDWARE_HAL_API_VERSION,
    .id = HELLO_HAL_HARDWARE_MODULE_ID,
    .name = "Default Hello HAL",
    .author = "sixian",
    .methods = &hello_hal_module_methods,
};
  • 声明一个 hw_module_t 结构体实例
  • 声明一个 hw_module_methods_t 结构体实例,其中 open 函数指针指向hello_hal_open
  • hello_hal_open> 会构建一个 hello_hal_device_t 结构体实例,对其成员赋值,核心的成员主要是 hello_hal_open 、hello_hal_write、 hello_hal_read 三个函数指针

二、编译系统配置

接着在 hardware/libhardware/modules/hello_hal 目录下添加 Android.mk

c 复制代码
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := hello_hal.default

# HAL module implementation stored in
# hw/<VIBRATOR_HARDWARE_MODULE_ID>.default.so
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_C_INCLUDES := hardware/libhardware
LOCAL_SRC_FILES := hello_hal.c
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_MODULE_TAGS := optional

include $(BUILD_SHARED_LIBRARY)

接着在 hardware/libhardware/modules/Android.mk 中添加 hello_hal ,这样编译系统才会去编译 hello_hal 模块。

c 复制代码
hardware_modules := \
    camera \
    gralloc \
    sensors \
    hello_hal
include $(call all-named-subdir-makefiles,$(hardware_modules))

接着在 product 配置文件 device/xxxx/xxxx/device.mk 中添加 hello_hal.default so库:

c 复制代码
PRODUCT_PACKAGES := \
    audio.primary.goldfish \
    vibrator.goldfish \
    hello_hal.default \

至此,hal 层任务完工

相关推荐
Android出海2 小时前
Google Play正式出手整治后台耗电应用
android·新媒体运营·产品运营·流量运营·用户运营
Winter_Sun灬2 小时前
CentOS7 交叉编译 ACE+TAO-6.5.13 安卓 arm64-v8a 静态库
android·ace
Digitally2 小时前
4种有效方法:如何将音乐从Mac传输到Android
android
CheungChunChiu2 小时前
Android 多媒体体系完整总结
android
晓13133 小时前
SQL篇——【MySQL篇:运维】高可用架构搭建(主从、读写分离、分库分表)
android·数据库·mysql
阳光的科技狗3 小时前
Android、谷歌、高通的前世今生
android·谷歌·高通
xunyan62343 小时前
面向对象(下)-接口应用:代理模式 && 工厂模式
android·java·学习
_李小白4 小时前
【Android FrameWork】第二十九天:MediaPlayer和MediaRecorder
android
casual_clover4 小时前
【Android】通过 Paint 获取文本宽度、高度及行间距信息
android·文本字体宽高