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工程代码