Hal
三个重要结构体
- hw_module_t
/**
* Every hardware module must have a data structure named HAL_MODULE_INFO_SYM
* and the fields of this data structure must begin with hw_module_t
* followed by module specific information.
*/
typedef struct hw_module_t {
/** tag must be initialized to HARDWARE_MODULE_TAG */
uint32_t tag;
/** major version number for the module */
uint16_t version_major;
/** minor version number of the module */
uint16_t version_minor;
/** Identifier of module */
const char *id;
/** Name of this module */
const char *name;
/** Author/owner/implementor of the module */
const char *author;
/** Modules methods */
//模块方法列表,指向hw_module_methods_t*
struct hw_module_methods_t* methods;
/** module's dso */
void* dso;
/** padding to 128 bytes, reserved for future use */
uint32_t reserved[32-7];
} hw_module_t;
- hw_module_methods_t
typedef struct hw_module_methods_t { //硬件模块方法列表的定义,这里只定义了一个open函数
/** Open a specific device */
int (*open)(const struct hw_module_t* module, const char* id,
struct hw_device_t** device);
} hw_module_methods_t;
- hw_device_t
/**
* Every device data structure must begin with hw_device_t
* followed by module specific public methods and attributes.
*/
typedef struct hw_device_t {
/** tag must be initialized to HARDWARE_DEVICE_TAG */
uint32_t tag;
/** version number for hw_device_t */
uint32_t version;
/** reference to the module this device belongs to */
struct hw_module_t* module;
/** padding reserved for future use */
uint32_t reserved[12];
/** Close this device */
int (*close)(struct hw_device_t* device);
} hw_device_t;
定义自己的hal模块
一、在.h文件中“继承”hw_module_t、hw_device_t
//led.h
/* HAL规定不能直接使用hw_module_t结构,因此需要做这么一个继承 */
struct led_module_t {
struct hw_module_t common;
};
struct led_control_device_t {
/* 自定义的一个针对Led控制的结构,包含hw_device_t和支持的API操作 */
struct hw_device_t common;
/*可用于具体的设备描述符,如指向/dev/xxx */
int fd;
/* 在这里定义自己的控制api */
int (*set_on)(struct led_control_device_t *dev, int32_t led);
int (*set_off)(struct led_control_device_t *dev, int32_t led);
};
/* 定义一个MODULE_ID,HAL层可以根据这个ID找到我们这个HAL stub */
#define LED_HARDWARE_MODULE_ID "led"
二、.c文件中定义相关变量、实现相关函数
1、定义相关变量
由本文件第一节“三个重要的结构体”可知,hw_device_t包含hw_module_t类型指针,hw_module_t包含hw_module_methods_t类型指针,而上面.h头文件我们自定义的led_control_device_t结构体又包含hw_device_t结构体,因此这四个结构体的复用情况如下:
hw_module_methods_t <- hw_module_t <- hw_device_t <- led_control_device_t
也就是说,通过led_control_device_t我们可以找到hal三大结构体类型(变量),而上一小节的代码中也说明了我们自定义的一些控制api也是放在led_control_device_t中的。
因此自然而然,我们应该很容易想到我们应该首先定义一个led_control_device_t变量:
//led.c
static struct hw_module_methods_t led_module_methods = {
open: led_device_open
};
const struct led_module_t HAL_MODULE_INFO_SYM = {
//定义这个对象等于向系统注册了一个ID为LED_HARDWARE_MODULE_ID的stub。注意这里HAL_MODULE_INFO_SYM的名称不能改。
common: {
tag: HARDWARE_MODULE_TAG, //这里HARDWARE_MODULE_TAG也是规范中固定死的
version_major: 1,
version_minor: 0,
id: LED_HARDWARE_MODULE_ID,
name: "Sample LED Stub",
author: "The Mokoid Open Source Project",
methods: &led_module_methods, //实现了一个open的方法供jni层调用,
//从而实例化led_control_device_t
}
};
从上面可以看出,实际并不是这样的,这里并没有定义led_control_device_t变量,却定义了led_module_t变量,而这个函数仅包括了一个hw_module_methods_t类型指针,而hw_module_methods_t中却只有一个open函数,那其他接口函数是如何传给jni的呢?
其实,关键也就在于这个open函数(可以先查看下一节的led_device_open函数),正是通过这个函数将hw_device_t类型指针返回给上层jni的,而在led_control_device_t结构体中,hw_device_t类型指针是第一个变量(规范要求必须为第一个变量),如此在jni上通过将hw_device_t类型指针的强制转换为led_control_device_t类型,则完成了接口函数的传递过程。
如果对这个感兴趣的话可以参阅下这篇文章:Android中HAL如何向上层提供接口总结
2、定义相关函数
有哪些函数需要定义呢?我们先来统计一下,我们按照以下“包含”关系自底向上来进行统计:
hw_module_methods_t <- hw_module_t <- hw_device_t <- led_control_device_t
(1)hw_module_methods_t中的open函数;
(2)hw_module_t中无;
(3)hw_device_t中的close函数;
(4)led_control_device_t中自定义的api函数;
统计是准确的:
//led.c
int led_device_close(struct hw_device_t* device)
{
struct led_control_device_t* ctx = (struct led_control_device_t*)device;
if (ctx) {
free(ctx);
}
return 0;
}
int led_on(struct led_control_device_t *dev, int32_t led)
{
LOGI("LED Stub: set %d on.", led);
return 0;
}
int led_off(struct led_control_device_t *dev, int32_t led)
{
LOGI("LED Stub: set %d off.", led);
return 0;
}
static int led_device_open(const struct hw_module_t* module, const char* name,
struct hw_device_t** device)
{
struct led_control_device_t *dev;
dev = (struct led_control_device_t *)malloc(sizeof(*dev));
memset(dev, 0, sizeof(*dev));
dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = 0;
dev->common.module = module;
dev->common.close = led_device_close;
dev->set_on = led_on;
dev->set_off = led_off;
*device = &dev->common;
success:
return 0;
}
思考
为什么hal在往上传接口时要以hw_module_t类型给出,然后在jni中对指针进行强制转换,而不直接以用户定义的类型(如led_control_device_t)传出?
参考资料:
注:
本文引用的是台湾的Jollen的mokoid工程代码