Android开发之应用层到驱动层的接口实现(一)

应用层到驱动层的接口实现(一)

                                                   ----硬件抽象层


   

该系列的文章主要是介绍实现从应用层(app)实现对硬件驱动层的访问,也就是通过读写文件节点的方式,访问Linux内核驱动程序。

在这便文章中介绍的是第一部分:即如何在硬件抽象层中增加硬件模块来和内核驱动程序交互。主要通过android项目翻盖机如果有子屏的话对后屏(sublcd)进行驱动操作(打开关闭)。


一、添加sublcd.h文件

1.1、文件目录:

/hardware/libhardware/include/hardware/

1.2sublcd.h文件内容:

#ifndef ANDROID_SUBLCD_INTERFACE_H
#define ANDROID_SUBLCD_INTERFACE_H
#include 
__BEGIN_DECLS

/*定义模块 ID*/
#define SUBLCD_HARDWARE_MODULE_ID "sublcd"

/*硬件模块结构体*/
struct sublcd_module_t {
struct hw_module_t common;
};

/*硬件接口结构体*/
struct sublcd_device_t {
struct hw_device_t common;
int fd;
int (*set_val)(struct sublcd_device_t* dev, int val);
int (*get_val)(struct sublcd_device_t* dev, int* val);
};

__END_DECLS

#endif

1.3、代码解释:

 这里的数据结构定义完全按照Android硬件抽象层规范的要求,分别定义模块ID、模块结构体以及硬件接口结构体。在硬件接口结构体中,fd表示设备文件描述符,对应我们将要处理的设备文件节点"/sys/class/ktd20xx/ktd2026/back_light_led"set_valget_val为该HAL对上提供的函数接口。

模块ID的名字是生成的.so文件的前缀名,在framework层就是通过模块IDSUBLCD_HARDWARE_MODULE_ID)去寻找生成的.so文件。所以该ID必须和后面要介绍到的sublcd目录下的Android.mk中定义的LOCAL_MODULE名字(前缀)一致,否则会导致在framework层往下调用HAL层定义的函数接口时失败。


二、添加sublcd文件夹

2.1、文件目录:

/hardware/libhardware/modules/

2.2/sublcd/sublcd.c文件内容:

//相关头文件
#define LOG_TAG "SubLcdStub"

#include 
#include 
#include 
#include 
#include 
#include 

//相关数据结构与宏的定义及函数声明
#define DEVICE_NAME "/sys/class/ktd20xx/ktd2026/back_light_led"
#define MODULE_NAME "Sublcd"
#define MODULE_AUTHOR "[email protected]"

static int light_sublcd();
static int died_sublcd();

/*Open and close sublcd device*/
static int sublcd_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device);
static int sublcd_device_close(struct hw_device_t* device);

/*Point to Interface*/
static int sublcd_set_val(struct sublcd_device_t* dev, int val);
static int sublcd_get_val(struct sublcd_device_t* dev, int* val);

/*Table of Module*/
static struct hw_module_methods_t sublcd_module_methods = {
open: sublcd_device_open
};

struct sublcd_module_t HAL_MODULE_INFO_SYM = {
common: {
tag: HARDWARE_MODULE_TAG,
version_major: 1,
version_minor: 0,
id: SUBLCD_HARDWARE_MODULE_ID,
name: MODULE_NAME,
author: MODULE_AUTHOR,
methods: &sublcd_module_methods,
}
};

//打开和关闭文件节点方法定义(包括相关数据结构初始化)
static int sublcd_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device) 
{
	ALOGI("SublcdStub: Sublcd_device_open");
	struct sublcd_device_t* dev;
	dev = (struct sublcd_device_t*)malloc(sizeof(struct sublcd_device_t));
		if(!dev) {
			ALOGI("SublcdStub: failed to alloc space");
			return -EFAULT;
			}
	memset(dev, 0, sizeof(struct sublcd_device_t));
	dev->common.tag = HARDWARE_DEVICE_TAG;
	dev->common.version = 0;
	dev->common.module = (hw_module_t*)module;
	dev->common.close = sublcd_device_close;
	dev->set_val = sublcd_set_val;
	dev->get_val = sublcd_get_val;
		if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) {
			ALOGI("SublcdStub: failed to open /dev/graphics/fb2 -- %s.", strerror(errno));
			free(dev);
			return -EFAULT;
			}
	*device = &(dev->common);
	ALOGI("SublcdStub: open /dev/graphics/fb2 successfully.");

	return 0;
	}
static int sublcd_device_close(struct hw_device_t* device)
{
	ALOGI("SublcdStub: sublcd_device_close");
	struct sublcd_device_t* sublcd_device = (struct sublcd_device_t*)device;
	
		if(sublcd_device) {
			close(sublcd_device->fd);
			free(sublcd_device);
		}

	return 0;
}

//往上(HAL)接口函数和文件系统节点操作函数具体定义
static int sublcd_set_val(struct sublcd_device_t* dev, int val) {
	int iflight,ifsublcdTest;	
	if(iflight = light_sublcd() == -1){
		ALOGI("SublcdStub: iflight == -1");
		return -EFAULT;
	}
	return 0;
}
static int sublcd_get_val(struct sublcd_device_t* dev, int* val) {
	int ifdied_sublcd,ifsublcdTest_exit;
	if(ifdied_sublcd = died_sublcd() == -1){
		ALOGI("SublcdStub: iflight == -1");
		return -EFAULT;
	}
	return 0;
}
static int light_sublcd(){	
	char *aa = "200";
	int back_fd = -1;
    back_fd = open(DEVICE_NAME, O_RDWR);
    if (back_fd < 0) {
		ALOGI("SublcdStub: light_sublcd failed");
		return -EFAULT;
    }
    write(back_fd, aa, 3);    
    if(back_fd){
    	close(back_fd);
    }
    return 0;
}
static int died_sublcd(){	
	char *aa = "0";
	int back_fd = -1;
    back_fd = open(DEVICE_NAME, O_RDWR);
    if (back_fd < 0) {
		ALOGI("SublcdStub: died_sublcd failed");
		return -EFAULT;
    }
    write(back_fd, aa, 1);    
    if(back_fd){
    	close(back_fd);
    }
    return 0;
}

以上便是sublcd.c的全部内容,主要是定义相关方法接口供framework层调用驱动,并实现对内核驱动程序的访问。

需要注意的是:

  1. open函数直接打开的是文件系统节点,当打开失败的时候返回的值<0,可以此判断open函数是否成功。open函数的第二个参数是文件系统节点的打开方式权限定义,其中:O_RDONLY(只读)、O_WRONLY(只写)、O_RDWR(可读可写)……

  2. write函数是对文件系统节点写入需要写入的值,需要注意的是第一个参数是open函数的返回,第二个参数是需要写入的值,是字符串类型,最后一个参数是该段字符串的长度。Write函数的返回值是该函数的最后一个参数。

2.3/sublcd/Android.mk文件内容:

#android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_SRC_FILES := sublcd.c
LOCAL_MODULE := sublcd.default
include $(BUILD_SHARED_LIBRARY)

需要注意的是LOCAL_MODULE:= sublcd.defaultsublcd便是上面所提到的模块ID,需要对应。


三、修改Android.mk文件

3.1、文件目录

/hardware/libhardware/modules/Android.mk

3.2、修改内容:

hardware_modules := ……sublcd ……

说明:在hardware_modules下添加对新增文件sublcd的编译。


至此便实现了硬件抽象层的方法接口,到hardware/libhardware/modules/sublcd下执行mm编译会在out/target/product/projectName/system/lib/hw生成sublcd.default.so。可使用adbpush直接导入到手机的/system/lib/hw/下,或者执行makesnod重新打包system.img,导入手机。


附:  

问题:HelloStub: failed to open /dev/hello -- Permission denied.

 解决:解决办法是类似于Linuxudev规则,打开Android源代码工程目录下,进入到system/core/rootdir目录,里面有一个名为ueventd.rc文件,往里面添加一行:

      /dev/hello0666 root root


以上是在驱动层的接口实现,在上层(应用层)怎么去调用这边封装好的接口呢?请参加下篇Bolg介绍:

· 应用层到驱动层的接口实现(二) ---- 应用框架层&&app应用层


你可能感兴趣的:(C++/C,Android系统开发,android,abdroid接口实现,android子屏的实现,android硬件抽象层)