Android上层与驱动交互完整篇(二)Hal层篇

Android上层与驱动交互完整篇(二)

Hal层篇

上篇写了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到板卡里对应的位置即可。
Android上层与驱动交互完整篇(二)Hal层篇_第1张图片
下面我们再写个测试程序来检测下我们的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到板卡对应位置即可。
执行后结果如下。
Android上层与驱动交互完整篇(二)Hal层篇_第2张图片
最后看一下整个hal的目录结构。
Android上层与驱动交互完整篇(二)Hal层篇_第3张图片
代码链接

你可能感兴趣的:(hal,android,c++,linux)