编写硬件抽象层模块接口分析
在阅读了“编写Android硬件抽象层相关规范说明”之后,我们应该很熟悉如何去定义和编写硬件抽象层模块接口了。下面即为本人实现的相关代码说明。
我们遵循Android源代码的相关习惯和规则,我想是有原因的;因此,我么也把编写的硬件抽象模块接口文件存放在hardware/libhardware/目录中。具体目录结构为(我的源代码放于Android文件夹中):
$Android/hardware/libhardware/
---Include
---hardware
---helloworld.h
---modules
---helloworld
---helloworld.cpp
---Android.mk
那么下面即为具体的实现代码说明。
头文件helloworld.h实现:
#ifndef ANDROID_HELLOWORLD__INTERFACE_H
#define ANDROID_HELLOWORLD_INTERFACE_H
#include <hardware/hardware.h>
___BEGIN_DECLS
//定义模块编号
#define HELLOWORLD_HARDWARE_MODULE_ID “helloworld”
//定义模块结构体
Struct helloworld_module_t {
Struct hw_modult_t common;//第一个成员变量必须为 //hw_module_t类型
};
//定义设备编号
#define HELLOWORLD_HARDWARE_DEVICE_H “helloworld”
//定义设备结构体
Struct helloworld_device_t {
Struct hw_module_t common;//第一个成员变量必须为该类型
int (*set_val)(struct helloworld_device_t* dev,int val);
Int(*get_val)(struct helloworld_device_t* dev,int* val);
Int fd;
};
__END_DECLS
#endif
这个头文件中的常量和结构体的定义都是按照Android系统的规范来定义的。宏变量HELLOWORLD_HARDWARE_MODULT_ID和HELLOWORLD_HARDWARE_DEVICE_ID分别用来描述欲编写的模块和其对应的设备编号;而结构体变量helloworld_module_t和helloworld_device_t则代表着欲编写的模块结构体和对应的设备描述结构体类型,并且这两个结构体的第一个成员变量类型必须为hw_module_t结构体类型。另外,helloworld_device_t中的其他三个变量的含义分别为:函数指针set_val和get_val用来对欲访问的设别进行写和读的操作,而fd表示打开的设备文件/dev/helloworld的描述符,借助这个描述符,我们可以知道当前打开的设备的状态。
实现文件helloworld.cpp:
#define LOG_TAG "HelloworldHALStub"
#include <hardware/hardware.h>
#include <fcntl.h>
#include <errno.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
#include <hardware/helloworld.h>
#define DEVICE_NAME "/dev/helloworld"
#define MODULE_NAME "helloworld"
#define MODULE_AUTHOR "[email protected]"
/*
*相关函数方法的定义部分
*/
static int helloworld_device_open(const struct hw_module_t* module, const char* id, struct hw_device_t** device);
static int helloworld_set_val(struct helloworld_device_t* dev, int val);
static int helloworld_get_val(struct helloworld_device_t* dev, int* val);
static int helloworld_device_close(struct hw_device_t* device);
static struct hw_module_methods_t helloworld_module_methods = {
open: helloworld_device_open
};
struct helloworld_module_t HAL_MODULE_INFO_SYM = {
common: {
tag: HARDWARE_MODULE_TAG,
version_major: 1,
version_minor: 0,
id: helloworld_HARDWARE_MODULE_ID,
name: MODULE_NAME,
author: MODULE_AUTHOR,
methods: &helloworld_module_methods,
}
};
/*
*相关实现部分
*/
/*
*打开设备方法实现
*第一个参数代表与要打开的设备对应的模块
*第二个参数代表着在抽象层中可能多个的设备的唯一标示,即区分打开那个设备
*第三个参数代表想要打开的目标设备
*/
static int helloworld_device_open(const struct hw_module_t* module, const char* id, struct hw_device_t** device) {
if(!strcmp(id, HELLOWORLD_HARDWARE_DEVICE_ID)) {
struct helloworld_device_t* dev;
//为设备文件分配物理空间大小
dev = (struct helloworld_device_t*)malloc(sizeof(struct helloworld_device_t));
if(!dev) {
LOGE("failed to alloc space for helloworld_device");
return -EFAULT;
}
memset(dev, 0, sizeof(struct helloworld_device_t));//设备驱动信号同步
dev->common.tag = HARDWARE_DEVICE_TAG;//成员变量tag必须为这个值
dev->common.version = 0;
dev->common.module = (hw_module_t*)module;
dev->common.close = helloworld_device_close;//调用设备自身函数关闭设备
//操作设备的两个方法
dev->set_val = helloworld_set_val;
dev->get_val = helloworld_get_val;
//判断当前设备是否打开
if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) {
LOGE("failed to open device file /dev/helloworld -----%s.", strerror(errno));
free(dev);
return -EFAULT;
}
*device = &(dev->common);
LOGI("open device file /dev/helloworld success.");
return 0;
}
return -EFAULT;
}
/*
*第一个参数代表欲操作的设备
*第二个参数代表为操作的设备赋予的值
*/
static int helloworld_set_val(struct helloworld_device_t* dev, int val) {
if(!dev) {
LOGE("null dev pointer.");
return -EFAULT;
}
LOGI("set value %d to device file /dev/helloworld.", val);
write(dev->fd, &val, sizeof(val));//调用系统函数,通过对应的设备文件找到欲操作设备, //并将设定的值写入设备中
return 0;
}
/*
*第一个参数代表操作的设备
*第二个参数表示从设别获取的值
*/
static int helloworld_get_val(struct helloworld_device_t* dev, int* val) {
if(!dev) {
LOGE("null dev pointer.");
return -EFAULT;
}
if(!val) {
LOGE("null val pointer.");
}
read(dev->fd, val, sizeof(*val));//调用系统函数,通过对应的设备文件找到欲操作设备, //并获取值,留给硬件访问服务读取显示
LOGI("get value %d from device file /dev/helloworld.", *val);
return 0;
}
/*
*关闭设备,这个函数有设备自身提供调用来关闭对应设备
*唯一参数则代表欲关闭的设备
*/
static int helloworld_device_close(struct hw_device_t* device) {
struct helloworld_device_t* helloworld_device = (struct helloworld_device_t*)device;
if(helloworld_device) {
close(helloworld_device->fd);
free(helloworld_device);
}
return 0;
}
编译脚本文件Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_PRELINK_MODULE := false
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_SRC_FILES := helloworld.cpp
LOCAL_MODULE := helloworld.default
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
include $(BUILD_SHARED_LIBRARY)//代表将编译的文件编译成为动态链接库文件,名 //称为helloworld.default,并保存在/out/target/product/generic/system/lib目录中。
准备好所有文件之后,使用命令:mmm ./hardware/libhardware/modules/helloworld/和make snod进行编译;最后可以得到一个位于/out/target/product/generic/system/lib目录中的helloworld.default.so文件。这时一个动态的链接库文件。
编写完硬件抽象层模块接口之后,接下来就是为这个模块接口编写一个硬件访问服务,这个硬件访问服务是位于框架层,用来为应用程序提供访问设备硬件的服务接口。敬请期待,硬件访问服务的实现!
本人刚创建了一个QQ群,目的是共同研究学习Android,期待兴趣相投的同学加入!!
群号:179914858