上篇写了I2C驱动如何来编写,但是驱动里并没有交代如何具体的跟设备通信,现在我们在hal层实现这部分逻辑代码。
HAL全称Hardware Abstract Layer,硬件抽象层,它向下屏蔽了硬件的实现细节,向上提供了抽象接口,HAL是底层硬件和上层框架直接的接口,框架层通过HAL可以操作硬件设备,HAL的实现在用户空间。
上篇我们讲了驱动的节点为/sys/class/memc/memc/cmd,所以hal层代码说白了就是对这个节点进行write read 操作。
下面代码为hal层一个模板,基本上都可以套用,移植的时候换上自己的操作函数即可。
首先在/hardware/libhardware/include/hardware下增加memc.h文件,代码如下,在.h中定义memc_module_t 、memc_device_t等结构体,并定义对外调用的函数 _memc_open。
#ifndef __MEMC_H_
#define __MEMC_H_
#include
#include
#include
#include
#define MEMC_HARDWARE_MODULE_ID "memc"
#define MEMC_MODULE_API_VERSION_1_0 HARDWARE_MODULE_API_VERSION(0, 1)
#define HARDWARE_MEMC "memc"
typedef struct memc_module {
struct hw_module_t common;
} memc_module_t;
typedef struct memc_device {
struct hw_device_t common;
int (*setMemcLevel)(int level);
int (*getMemcLevel)();
int (*setPanelIndex)(int index);
int (*getPanelIndex)();
int (* setPanelMemcDemoValue)(int value);
int (* getPanelMemcDemoValue)();
int (*setDeviceReset)();
char * (*getSwVersion)();
char * (*getBuildTime)();
} memc_device_t;
static inline int _memc_open(const struct hw_module_t *module,
memc_device_t **device) {
return module->methods->open(module, HARDWARE_MEMC,
(struct hw_device_t **) device);
}
#endif
接下来在hardware/libhardware/modules增加memc.c文件,实现memc_device_t 中定义的函数指针。
#include
#include
#include
//#include
#include
#include
#include "MemcControl.h"
#include "MemcCommon.h"
#ifdef __cplusplus
extern "C" {
#endif
MemcControl *mMemcControl = NULL;
static int setPanelMemcDemoValue(int value)
{
mMemcControl->setPanelMemcDemoValue(value);
return MEMC_SUCCESS;
}
static int getPanelMemcDemoValue()
{
return mMemcControl->getPanelMemcDemoValue();
}
static int setDeviceReset()
{
mMemcControl->setDeviceReset();
return MEMC_SUCCESS;
}
static int setPanelIndex(int index)
{
mMemcControl->setPanelIndex(index);
return MEMC_SUCCESS;
}
static int getPanelIndex()
{
return mMemcControl->getPanelIndex();
}
static int setMemcLevel(int level)
{
mMemcControl->setPanelMemcLevel(level);
return MEMC_SUCCESS;
}
static int getMemcLevel()
{
return mMemcControl->getPanelMemcLevel();
}
static char * getSwVersion()
{
return mMemcControl->getSwVersion();
}
static char * getBuildTime()
{
return mMemcControl->getBuildTime();
}
static int memc_close(hw_device_t *dev)
{
if (dev) {
free(dev);
return 0;
} else {
return -1;
}
}
static int memc_open(const hw_module_t* module,const char __unused *id,
hw_device_t** device)
{
if (device == NULL) {
ALOGE("NULL device on open");
return -1;
}
memc_device_t *dev = (memc_device_t *)malloc(sizeof(memc_device_t));
memset(dev, 0, sizeof(memc_device_t));
dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = MEMC_MODULE_API_VERSION_1_0;
dev->common.module = (struct hw_module_t*) module;
dev->common.close = memc_close;
dev->setMemcLevel= setMemcLevel;
dev->getMemcLevel = getMemcLevel;
dev->setPanelIndex = setPanelIndex;
dev->getPanelIndex = getPanelIndex;
dev->getSwVersion = getSwVersion;
dev->getBuildTime = getBuildTime;
dev->setPanelMemcDemoValue = setPanelMemcDemoValue;
dev->getPanelMemcDemoValue = getPanelMemcDemoValue;
dev->setDeviceReset = setDeviceReset;
mMemcControl = new MemcControl();
*device = &(dev->common);
ALOGE(" Max Memc open\n");
return 0;
}
static struct hw_module_methods_t memc_module_methods = {
.open = memc_open,
};
memc_module_t HAL_MODULE_INFO_SYM = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.module_api_version = MEMC_MODULE_API_VERSION_1_0,
.hal_api_version = HARDWARE_HAL_API_VERSION,
.id = MEMC_HARDWARE_MODULE_ID,
.name = "MEMC HAL",
.author = "[email protected]",
.methods = &memc_module_methods,
},
};
#ifdef __cplusplus
}
#endif
其中MemcControl 类中定义了对节点操作的具体代码。如果去掉MemcControl内容,到此一个hal的框架就搭建完成了。
上篇驱动中,我们有讲驱动中节点,将字符串转成byte然后通过I2C一个字节一个字节的发送与接收,那么我们hal中用到的write read函数 传进去的也是字符串,所以hal中为了方便传输数据的直观性,我们以byte定义要传输的数据,然后转成字符串传给write read 函数。
以上面setMemcLevel 为例详解 ,MemcControl 中定义如下。
int MemcControl::setPanelMemcLevel(int level)
{
char data[7] = {0x00,0x1b,0x00,0x00,0x00,0x00,0x00};
data[2] = level;
data[0] = ((((data[1]+data[2]+data[3]+data[4]+data[5]+data[6]) & 0x000F) << 4) | 0x02);
mMemcCommon->writeMemcCmd(data,7,0);
return MEMC_SUCCESS;
}
data 为要传输的数据
int MemcCommon::writeMemcCmd(char * data,int data_size_write,int data_size_read)
{
char buff[NODE_BUF_MAX] ;
toMemcCmdString(buff,data,data_size_write,data_size_read);
return sysfsWrite(SYS_MEMC_CMD,buff);;
}
toMemcCmdString函数将data 转换成字符串
int MemcCommon::toMemcCmdString(char * buf,char * data,int data_size,int data_size_r)
{
int pos = 0, i;
int w_num,r_num;
if (data_size_r>0)
w_num = 0;
else
w_num = data_size;
//r_num = 0;// no support read
r_num = data_size_r;
pos += snprintf(buf + pos, NODE_BUF_MAX - pos,"%d %d ",w_num,r_num);
for(i = 0; i < data_size; i++){
pos += snprintf(buf + pos, NODE_BUF_MAX - pos,"0x%02x ",data[i]);
}
//delete end space
buf[pos-1] = '\0';
//LOGD("%s -> number = %d, buf: %s \n",__FUNCTION__,pos,buf);
return pos;
}
sysfsWrite 将字符串数据write 到节点中,即完成了hal层与驱动的交互。
int MemcCommon::sysfsWrite(const char * path,char * buf)
{
char err_buf[ERR_BUF_MAX];
int size;
int fd;
fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0644);
if (fd < 0) {
strerror_r(errno, err_buf, sizeof(err_buf));
ALOGE("Error open %s: %s\n", path, err_buf);
return -1 ;
}
//LOGE(" %s -> buf = %s ",__FUNCTION__,buf);
size = write(fd, buf, strlen(buf));
if (size < 0) {
strerror_r(errno, err_buf, sizeof(err_buf));
ALOGE("Error write %s: %s\n", path, err_buf);
}
close(fd);
return size;
}
最后在hardware/libhardware/modules下编写Android.bp文件
cc_library_shared {
name: "memc.default",
relative_install_path: "hw",
proprietary: true,
header_libs: ["libhardware_headers"],
shared_libs: [
"libcutils",
"liblog",
],
srcs: ["memc.cpp",
"MemcControl.cpp",
"MemcCommon.cpp"],
cflags: ["-Wall", "-Werror"],
}
mmm hardware/libhardware/modules/memc 后在vendor/lib/hw下生成memc.default.so。编译后,将此so push到板卡里对应的位置即可。
下面我们再写个测试程序来检测下我们的hal层是否工作正常。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(){
memc_device_t* memc_device = NULL;
const memc_module_t * module = NULL;
int ret = hw_get_module(MEMC_HARDWARE_MODULE_ID,(const struct hw_module_t**)&module);
if (!ret) {
ret = _memc_open((const struct hw_module_t*)module,&memc_device);
}else{
printf("get hw_get_module-hal failed.......\n");
return -1;
}
if (ret < 0) {
printf("get memc-hal failed.......\n");
return -1;
}
printf("success start memc-hal.==%d\n",memc_device->getMemcLevel());
printf("getSwVersion===%s\n",memc_device->getSwVersion());
printf("getBuildTime===%s\n",memc_device->getBuildTime());
return 0;
}
Andorid.bp文件
cc_binary {
name: "memc_test",
vendor: true,
srcs: ["memcTest.cpp"],
shared_libs: [
"liblog",
"libhardware",
],
}
编译完成后 在vendor/bin下生成memc_test 文件,最后push到板卡对应位置即可。
执行后结果如下。
最后看一下整个hal的目录结构。
代码链接