打通驱动层到应用层--(二)HAL层

前言

本节为HAL层模块访问Linux驱动程序,通过打开上一节创建的dev/helloxjq的设备文件来连接HAL和内核驱动程序模块。

一、创建

进入到在hardware/libhardware/include/hardware目录,新建helloxjq.h文件:

#ifndef ANDROID_HELLOXJQ_H  
#define ANDROID_HELLOXJQ_H  
#include <hardware/hardware.h>  

__BEGIN_DECLS  

/*定义模块ID,用与上层程序获取该模块*/  
#define HELLOXJQ_HARDWARE_MODULE_ID "helloxjq"

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

/*硬件接口结构体*/  
struct helloxjq_device_t {  
    struct hw_device_t common;  
    int fd;  
    int (*write_string)(struct helloxjq_device_t* dev, char *str);  
    int (*read_string)(struct helloxjq_device_t* dev, char ** str);  
};  

__END_DECLS  

#endif  

进入到hardware/libhardware/modules目录,新建helloxjq目录,并添加helloxjq.c文件和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 += \
    libcutils libutils liblog
    LOCAL_LDLIBS:=  -L$(SYSROOT)/usr/lib -llog 

      LOCAL_SRC_FILES := helloxjq.c
      LOCAL_MODULE := helloxjq.default
      include $(BUILD_SHARED_LIBRARY)

helloxjq.c内容如下:

#include <hardware/hardware.h>  
#include <hardware/helloxjq.h>  
#include <fcntl.h>  
#include <errno.h>  
#include <cutils/log.h>  
#include <cutils/atomic.h>  

#define DEVICE_NAME "/dev/helloxjq" 
#define MODULE_NAME "Helloxjqxjq"  
#define MODULE_AUTHOR "xjq" 

#define LOG_TAG "Helloxjq"  

/* 定义LOG */
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__) 
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO  , LOG_TAG, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN  , LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR  , LOG_TAG, __VA_ARGS__)


/*打开和关闭设备的方法*/  
static int helloxjq_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device);  
static int helloxjq_device_close(struct hw_device_t* device);  

/*读写linux驱动的接口*/  
static int helloxjq_write_string(struct helloxjq_device_t* dev, char * str);  
static int helloxjq_read_string(struct helloxjq_device_t* dev, char **str);  

/*模块方法结构体*/  
static struct hw_module_methods_t helloxjq_module_methods = {  
    open: helloxjq_device_open  
};  

/*模块实例变量*/  
struct helloxjq_module_t HAL_MODULE_INFO_SYM = {  
    common: {  
        tag: HARDWARE_MODULE_TAG,  
        version_major: 1,  
        version_minor: 0,  
        id: HELLOXJQ_HARDWARE_MODULE_ID,  
        name: MODULE_NAME,  
        author: MODULE_AUTHOR,  
        methods: &helloxjq_module_methods,  
    }  
};  

static int helloxjq_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device) {  
    struct helloxjq_device_t* dev;
    dev = (struct helloxjq_device_t*)malloc(sizeof(struct helloxjq_device_t));  

    if(!dev) {  
        LOGE("helloxjq: failed to alloc space");  
        return -EFAULT;  
    }  

    memset(dev, 0, sizeof(struct helloxjq_device_t));  
    dev->common.tag = HARDWARE_DEVICE_TAG;  
    dev->common.version = 0;  
    dev->common.module = (hw_module_t*)module;  
    dev->common.close = helloxjq_device_close;  
    dev->write_string = helloxjq_write_string;
    dev->read_string = helloxjq_read_string;  

    if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) {  
        LOGE("helloxjq: open /dev/helloxjq fail-- %s.", strerror(errno));free(dev);  
        return -EFAULT;  
    }  

    *device = &(dev->common);  
     LOGI("helloxjq: open /dev/helloxjq successfully.");  

    return 0;  
}  
static int helloxjq_device_close(struct hw_device_t* device) {  
    struct helloxjq_device_t* hello_device = (struct helloxjq_device_t*)device;  

    if(hello_device) {  
        close(hello_device->fd);  
        free(hello_device);  
    }  

    return 0;  
}  

static int helloxjq_write_string(struct helloxjq_device_t* dev,char * str) {  
    LOGI("helloxjq:write string: %s", str);  

    write(dev->fd, str, sizeof(str));  

    return 0;  
}  

static int helloxjq_read_string(struct helloxjq_device_t* dev, char ** str) {  
    read(dev->fd, *str, sizeof(*str));  
    LOGI("helloxjq:read string: %s", *str);
    return 0;  
}  

二、修改

  1. device_create创建的设备文件默认只有root用户可读写,而hello_device_open一般是由上层APP来调用的,这些APP一般不具有root权限,这时候就导致打开设备文件失败。解决办法很简单,打开Android源代码工程目录下,进入到system/core/rootdir目录,里面有一个名为ueventd.rc文件,往里面添加一行:
    /dev/helloxjq 0666 root root

  2. 将安卓SElinux防火墙关闭,在system/core/init/init.cpp中static bool selinux_is_enforcing(void)函数中第一句之前加上return false。此方法对于公司开发来说,很不安全,如果只是测试,可以这么操作,如果想不关闭防火墙又能访问,可以搜一下相关的权限的博客,讲解的很详细,按照所讲的步骤对源码进行修改即可。

三、编译

mmm hardware/libhardware/modules/ttt/局部编译
编译完成再打包make systemimage
每次整编的时候,不会编译这个模块,所以make clean后或者修改这个模块的代码后,需要重新编译这个模块后,再整编。

四、验证

编译成功后,就可以在out/target/product/generic/system/lib/hw目录下看到helloxjq.default.so文件了,下载代码后通过ADB能在设备system/lib/hw下看到该模块。但是人不能判断该模块和上一节的驱动模块功能是否正常,因此我们写一个test测试程序验证。

在libhardware文件夹下新建tests文件夹,在tests文件夹下新建hello_testHAL,创建Android.mk文件和test.c文件,
Android.mk文件如下:

      LOCAL_PATH := $(call my-dir)

      include $(CLEAR_VARS)

      LOCAL_MODULE_TAGS := optional

      LOCAL_MODULE := my_test

    LOCAL_LDLIBS:=  -lhardware

      LOCAL_SRC_FILES := $(call all-subdir-c-files)

      include $(BUILD_EXECUTABLE)

test.c内容如下

#include <hardware/hardware.h>  
#include <hardware/helloxjq.h>  
#include <fcntl.h>
#include <stdio.h>
struct hw_module_t * module;
struct hw_device_t * device;
int main(int argc, char *argv[]){
    char *read_str;
    char *write_str="nihao";
    read_str = malloc(100);
    char *ID = argv[1];
    printf("----begin main------\n");
    if(hw_get_module(ID,(struct hw_module_t const **)&module)==0){
        printf("get module sucess\n");
    }else{
        printf("get module fail\n");
        return -1;
    }
    if(module->methods->open(module,ID,(struct hw_device_t const**)&device)==0){
        printf("open module sucess\n");
    }else{
        printf("open module error\n");
        return -2;
    }
    struct helloxjq_device_t* dev = (struct helloxjq_device_t *)device;
    dev->read_string(dev,&read_str);
    if(read_str == NULL){
        printf("read error");
    }else{
        printf("read data: %s\n",read_str);
    }

    dev->write_string(dev,write_str);
    printf("write data: %s\n",write_str);
    dev->read_string(dev,&read_str);
    if(read_str == NULL){
        printf("read error");
    }else{
        printf("read data: %s\n",read_str);
    }
    printf("----end main------\n");
return 0;
}

编译测试程序
mmm hardware/libhardware/tests/helloxjq_testHAL/
将在文件夹out/target/product/msm8937_32go/system/bin下生成my_test文件,
在该目录下打开windows终端,将该文件使用adb push到安卓设备system/app/目录下重命名为test,给test赋可执行权限,再运行test,注:运行test 第二个参数为生成的之前生成的xxx.default.so中的xxx。

adb root
adb remount
adb push my_test system/app/test
adb shell 
cd system/app
chmod 777 test
./test helloxjq 

查看输出结果,查看模块是否正常打开,读取和写入的是否正常。如果都正常,则进入下一节,否则就查看log,具体问题出现在哪儿。

介绍 STM32CubeTM是意法半导体的一项原始计划,旨在通过减少 开发工作,时间和成本。 STM32CubeTM涵盖了STM32产品组合。 STM32CubeTM版本1.x包括: STM32CubeMX,一种图形软件配置工具,允许生成C初始化 使用图形向导编写代码。 每个系列都提供了一个全面的嵌入式软件平台(例如STM32CubeF4 STM32F4系列) STM32Cube HAL是STM32抽象嵌入式软件,可确保最大化 跨STM32产品组合的可移植性 一套一致的中间件组件,例如RTOS,USB,TCP / IP,图形 所有嵌入式软件实用程序均附带全套示例。 HAL驱动程序提供了一组通用的多实例简单API(应用程序编程) 接口)与上(应用程序,库和堆栈)进行交互。它由通用组成 和扩展API。它是直接基于通用体系结构构建的,并允许构建, 例如中间件,以实现其功能,而无需深入了解如何使用 单片机这种结构提高了库代码的可重用性,并保证了在其他库上的轻松移植 设备。 HAL驱动程序包括一整套现成的API,可简化用户应用程序 实施。例如,通信外围设备包含用于初始化和配置的API 外设,以基于轮询管理数据传输,处理中断或DMA,以及管理 通讯错误。 HAL驱动程序API分为两类:提供通用和通用的通用API 所有STM32系列和扩展API的函数,其中包括特定的和自定义的函数 给定的家庭或零件号。 HAL驱动程序是面向功能的,而不是面向IP的。例如,计时器API分为 IP提供的功能包括以下几类:基本计时器,捕获,脉冲宽度调制 (PWM)等。 驱动程序源代码是在严格的ANSI-C中开发的,使它独立于 开发工具。使用CodeSonarTM静态分析工具进行检查。它是有据可查的,并且 符合MISRA-C 2004。 HAL驱动程序通过检查所有输入值来实现运行时故障检测 功能。这种动态检查有助于增强固件的鲁棒性。运行时检测 也适用于用户应用程序开发和调试。 本用户手册的结构如下: HAL驱动程序概述 每个外围设备驱动程序的详细描述:配置结构,功能以及使用方法 给定的API来构建您的应用程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值