不管是出于什么样地考虑,android系统终究是提供了hardware层来封装了对Linux的驱动的访问,同时为上层提供了一个统一的硬件接口和硬件形态。
一.Hardware概述
在Hardware层中的一个模块中,主要设计一下三个结构:
- struct hw_module_t
- struct hw_module_methods_t
- struct hw_device_t
这三个结构体的关系是这样的:我们在上层访问linux驱动时,需要首先获得hardware层的对应的module,使用hw_get_module()方法实现,这个函数通过给定模块的ID来寻找硬件模块的动态链接库,找到后使用load()函数打开这个库,并通过一个固定的符号:HAL_MODULE_INFO_SYM寻找hw_module_t结构体,我们会在hw_module_t结构体中会有一个methods属性,指向hw_module_methods_t结构体,这个结构体中会提供一个open方法用来打开模块,在open的参数中会传入一个hw_device_t**的数据结构,这样我们就可以把对模块的操作函数等数据保存在这个hw_device_t结构中,这样,这样用户可以通过hw_device_t来和模块交互。
具体的说,我们在上层可以这样调用HAL层的module:
xxx_module_t *module;
hw_get_module(XXXID,(struct hw_module_t **)&module);
以上两步我们就获得了对应ID的 hw_module_t结构体。
struct xxx_device_t *device;
module->methods->open(module,XXXID,(struct hw_device_t **)&device);
这样我们就获得了hw_device_t结构体,通过hw_device_t结构体我们就可以访问HAL层对应的module了。
这个思路很重要,后面我们测试我们的HAL层module的时候,就需要上面的代码。
整个过程可用一张图展示:
二.使用Android HAL规范封装对Linux驱动的访问
在hardware/libhardware/modules新建hellotest目录,添加两个文件:hellotest.c 和 Android.mk
1.hellotest.c
这个文件把对linux驱动的访问封装成了Android要求的格式。
#include <hardware/hardware.h>
#include <hardware/hellotest.h>
#include <fcntl.h>
#include <errno.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
#define DEVICE_NAME "/dev/hello"
#define MODULE_NAME "HelloTest"
#define MODULE_AUTHOR "jinwei"
#define LOG_TAG "HelloTest"
/* 定义LOG */
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO , LOG_TAG, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN , LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR , LOG_TAG, __VA_ARGS__)
/*打开和关闭设备的方法*/
static int hellotest_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device);
static int hellotest_device_close(