版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第第9讲讲 硬件抽象层(硬件抽象层(HAL)讲师:李宁主要内容 什么是HAL 为什么要在Android在添加HAL 编写和测试基于HAL的LED驱动什么是HAL HAL(Hardware Abstraction Layer,硬件抽象层)是建立在Linux驱动之上的一套动态库。这套动态库并不属于Linux内核,而是属于Linux内核层之上的系统运行库层。Google为Android增加HAL的主要目的除尽量避免应用程序直接访问Linux驱动外,还有一个重要原因,那就是保护“私人财产”。对于那些既想发布基于Android的Linux驱动程序,又不想将核心业务逻辑公开的企业或个人,HAL简直就是福音
2、。为什么要在Android中加入HAL 加入HAL的主要目的l 统一硬件的调用接口。由于HAL有标准的调用接口,所以可以利用HAL屏蔽Linux驱动复杂、不统一的接口。l 解决了GPL版权问题。由于Linux内核基于GPL协议,而Android基于Apache Licence 2.0协议。因此Google玩了个“穿越”,将原本位于Linux内核中的Linux驱动的敏感代码向上移了一个层次。这样这些敏感代码就摆脱了GPL协议的束缚。那写不想开源的Linux驱动作者也就没必要开源了。l 针对一些特殊的要求。对于有些硬件,可能需要访问一些用户空间的资源,或在内核空间不方便完成的工作以及特殊需求。在这
3、种情况下,可以利用位于用户空间的HAL代码来辅助Linux驱动完成一些工作。Android HAL的旧架构 Android HAL的新架构 Android HAL程序库的路径 Android HAL的源代码存储的位置并不固定。一般会存储在/hardware目录中。其中/hardware/libhardware_legacy用于保存旧的HAL架构的源代码。新HAL架构的源代码在/hardware/libhardware目录中,当然,这些源代码可以放在/hardware或其他的目录。最终编译生成的.so文件主要放在Android系统的/system/lib/hw目录,也可以放在其他的目录。精简LE
4、D驱动 基于HAL的LED驱动去掉了所有与读写寄存器规则相关的代码,只保留了创建设备文件已经与寄存器交互的代码(不涉及到任何规则,只是将数据简单地写入指定的寄存器,或从指定的寄存器读取数据)。 LED驱动利用了设备文件的read和write函数来读写指定的寄存器。基本原理是只从指定寄存器读取或写入5个字节。第1个字节用于指定读写的动作以及寄存器。后4个字节是读写的实际的数据(因为LED驱动只涉及到操作一个int类型数据的寄存器,因此使用4个字节个来表示一个int类型的数据)。在与LED驱动交互是,只要向设备文件(/dev/s3c6410_leds_hal)读取或发送5个字节的数据,就可以读写指
5、定的寄存器。测试读写寄存器操作 由于LED驱动程序的设备文件接收的不是字符串,而是字节类型的数据(字节数组),因此需要单独做一个程序向设备文件写入字节形式的数据,或从设备文件中读取字节类型的数据。 命令行参数来传递设备文件名、字节数和要传递的字节等信息。命令行语法格式如下:rwdev byte1 byte2 . byten编译rw_dev.c程序arm-gcc -static -o /root/drivers/read_write_dev/rwdev /root/drivers/read_write_dev/rw_dev.c调用LED驱动的HAL程序库(1) 任何被系统自动调用的程序都会有一个
6、标准的接口。这个接口相当与一个约定的规则。不管任何程序,只要遵循这个规则,就可以成功被调用。例如,C语言可执行程序都会有一个main函数,系统中执行程序是都会寻找main函数来执行;Linux驱动也有多个接口,最常用的就是init和exit函数,除此之外,还有与设备文件相关的read、write、ioctl等函数。只要Linux驱动程序安装接口的要求定义和实现,就可以成功安装在Linux驱动中。调用LED驱动的HAL程序库(2) 既然HAL程序库也可以被Android系统自动调用,那么自然也拥有标准的接口。只不过这个接口不是函数,而是一个固定名称的结构体变量HAL_MODULE_INFO_SY
7、M。也就是说,所有的HAL程序都必须要有一个HAL_MODULE_INFO_SYM变量,并且初始化该结构体变量的common成员变量。调用LED驱动的HAL程序库(3) 第1步:定义结构体定义结构体和宏和宏 编写HAL程序库需要使用到3个非常重要的结构体(hw_module_t、hw_device_t和hw_module_methods_t),在第1步需要定义两个新的结构体,这两个结构体的第1个变量的类型必须是hw_module_t和hw_device_t。一般还需要为HAL模块定义一个ID。实际上在这1步就是编写leds_hal.h头文件的代码。调用LED驱动的HAL程序库(4) typed
8、ef struct hw_module_t /* 模块的Tag,值必须是HARDWARE_MODULE_TAG */ uint32_t tag; /* 模块主版本号 */ uint16_t version_major; /* 模块从版本号 */ uint16_t version_minor; /* 模块的ID,通过该ID可以找到当前模块 */ const char *id; /* 模块名称 */ const char *name; /* 模块作者 */ const char *author; /* 与模块相关的函数指针,都包含着hw_module_methods_t结构体中 */ struct
9、 hw_module_methods_t* methods; /* 模块的dso ,dlopen函数返回的HAL动态库的handler */ void* dso; /*保留的空间 */ uint32_t reserved32-7; hw_module_t;调用LED驱动的HAL程序库(5) 描述硬件设备(或称为描述硬件设备(或称为HAL设备)的结构体设备)的结构体hw_device_t。typedef struct hw_device_t /* 设备的Tag,值必须是HARDWARE_DEVICE_TAG */ uint32_t tag; /* 硬件设备的版本号 */ uint32_t ver
10、sion; /* 指向描述硬件模块的hw_module_t结构体指针 */ struct hw_module_t* module; /* 保留的内存空间 */ uint32_t reserved12; /* 关闭设备的函数指针 */ int (*close)(struct hw_device_t* device); hw_device_t;调用LED驱动的HAL程序库(6) 描述模块入口函数的结构体描述模块入口函数的结构体hw_module_methods_t。typedef struct hw_module_methods_t /* 打开设备是调用的open函数的指针 */ int (*op
11、en)(const struct hw_module_t* module, const char* id, struct hw_device_t* device); hw_module_methods_t; 在这3个结构体中,hw_module_t是最先使用到的,然后通过hw_module_t.methods找到hw_module_methods_t.open函数,并调用该函数。这个open函数相当与HAL程序库的入口函数。一般会在这个函数里打开设备文件,初始化hw_device_t结构体设置一些控制硬件设备的函数。调用LED驱动的HAL程序库(7) 在第1步先考虑hw_module_t和hw
12、_device_t两个结构体。HAL规则建议不直接使用hw_module_t和hw_device_t(直接使用这,而要新定义两个结构体,将hw_module_t和hw_device_t分别作为新结构体的第1个变量的类型。就像leds_hal.h文件中的led_module_t和led_control_device_t。那么HAL为什么要这么建议呢?调用LED驱动的HAL程序库(8) 在说明原因之前,先看一下led_device_open函数和led_control_device_t结构体。static int led_device_open(const struct hw_module_t*
13、module, const char* name, struct hw_device_t* device) struct led_control_device_t struct hw_device_t hw_device; int (*set_on)(struct led_control_device_t *dev, int32_t led); int (*set_off)(struct led_control_device_t *dev, int32_t led);调用LED驱动的HAL程序库(9) led_device_open函数将在NDK程序中被调用。该函数的最后1个参数类型是hw_d
14、evice_t*,不过在调用该函数时,传进来的却是led_control_device_t*。从这一点看。hw_device_t相当与led_control_device_t的父类(C语言中并没有类的概念,这样解释只是便于理解,也可以称为其父结构体)。在调用led_device_open函数时将led_control_device_t*强行转换成了hw_device_t*。对于C语言来说,这样的转换要满足一个条件,就是做为父结构体(hw_device_t)的结构体必须是子结构体(led_control_device_t)的第1个变量的数据类型。调用LED驱动的HAL程序库(10) 那么为什么要
15、这样做强行转换呢?主要是因为扩展的需要。因为在led_control_device_t结构体中定义了两个函数指针变量(set_on和set_off)。这两个变量的名称和参数个数、参数类型是任意指定的。但为了使HAL程序库保持独立性(可能会被多个NDK模块使用,每个NDK模块使用了不同的hw_device_t和hw_module_t的子结构体),HAL程序库在的方法只能使用hw_device_t和hw_module_t作为参数类型。而如果不使用hw_device_t和hw_module_t的父类,就意味这无法添加这种设备函数指针(set_on和set_off)等成员。那么这个HAL程序库就成了中
16、看不中用的“东西”了。光有逻辑代码,却无法向外部提供与其交互的接口。调用LED驱动的HAL程序库(11) 由于在led_module_t结构体除了hw_module变量外,没有任何其他的成员,因此,HAL_MODULE_INFO_SYM的类型可以直接定义成hw_module_t,代码如下:struct hw_module_t HAL_MODULE_INFO_SYM = tag: HARDWARE_MODULE_TAG, version_major: 1, version_minor: 0, id: LED_HARDWARE_MODULE_ID,name: Sample LED HAL Stub
17、,author: Lining,methods: &led_module_methods,;调用LED驱动的HAL程序库(12) 第第2步:编写打开设备的步:编写打开设备的open函数函数 设备的打开函数是HAL模块的入口点。在本例中是led_device_open函数。设备打开函数主要做如下3项工作。l 初始化hw_device_t的子结构体。除了设置也写必要的变量外,还需要设置操作硬件的函数指针(本例是close、set_on和set_off)。其中set_on和set_off在调用HAL模块的代码中要使用到。close有系统自动调用。在这一步与close、set_on和set_o
18、ff惯量的函数还没有定义,可以先把函数名写上,或在定义了相关函数后再设置这些函数指针。l 打开设备文件。l 初始化寄存器。调用LED驱动的HAL程序库(13) 第第3步:定义步:定义hw_module_methods_t结构体变量结构体变量HAL模块需要hw_module_methods_t结构体的open函数指针变量指定open入口函数。 第第4步:定义步:定义HAL_MODULE_INFO_SYM变量变量 所有的HAL模块都必须有一个HAL_MODULE_INFO_SYM变量。该变量的类型一般为hw_module_t或其子结构体。该变量初始化了一些变量,其中id和methods成员最重要。
19、id表示HAL模块中Android系统中的索引。使用HAL模块的程序并不是直接装载.so文件,而是通过这个id找到并装载HAL模块。methods变量的值需要设置在第3步定义的hw_module_methods_t结构体变量。当调用者通过id找到并装载HAL模块后,就会通过methods变量调用open入口函数来初始化设备。调用LED驱动的HAL程序库(14) 第第5步:编写卸载设备的步:编写卸载设备的close函数函数当HAL模块被卸载后会调用close函数。在本例中是led_device_close函数。该函数需要在第2步的led_device_open函数中赋给hw_device_t的c
20、lose成员变量。 第第6步:编写控制设备的函数步:编写控制设备的函数根据设备类型和功能的不同,这一步编写的函数也有所不同。在本例中编写了两个控制函数(led_on和led_off),分别用来控制LED的开、关。led_on和led_off函数需要在第2步编写的led_device_open函数中赋给led_control_device_t.set_on和led_control_device_t.set_off变量。编写调用HAL程序库的Service 调用HAL程序库涉及到一个非常重要的hw_get_module函数。该函数可以通过在leds_hal.h中定义的LED_HARDWARE_MO
21、DULE_ID宏(led_hal)查找LED HAL模块,并获得led_module_t结构体。然后调用led_module_t.hw_module.methods.open函数来初始化LED驱动。并通过open函数返回led_control_device_t结构体。在led_control_device_t结构体中包含了在HAL模块中定义的控制LED驱动的函数指针(set_on和set_off)。为Service建立符号链接 ln -s /root/drivers/s3c6410_leds_hal/leds_hal_jni /working/android2.3.4_src/framewor
22、ks/base/services/leds_hal_jniHAL的存放路径和命名规则(1) HAL程序库(so文件)通常存放在/system/lib/hw目录。文件名中一般都有一个default。例如,led_hal.default.so文件是LED驱动的HAL程序库。那么这个存放目录和文件名是我们的唯一选择吗?在回答这个问题之前,需要先查看一下调用HAL程序库的核心函数hw_get_module的代码,因为正是这个函数利用HAL模块的ID找到了HAL程序库的.so文件。所以一切的秘密都会在这个函数的揭开。hw_get_module函数位于hardware.c文件中。hardware.c文件的
23、完整路径如下:/working/android2.3.4_src/hardware/libhardware/hardware.cHAL的存放路径和命名规则(2) 在阅读完hardware.c文件的代码和注释后,可以得出如下结论,这些结论也恰好回到了本节开始提出的问题。l HAL模块库文件的存放路径有两个:/system/lib/hw和/vendor/lib/hw。hw_get_module函数会先从/system/lib/hw目录根据库文件命名规则寻找库文件。如果/system/lib/hw目录没有库文件,hw_get_module会按同样的规则在/vendor/lib/hw目录中寻找。l H
24、AL模块库文件的命名规则是ID.suffix.so。其中ID功过hw_get_module函数的id参数指定。suffix(后缀)通过在属性文件中指定。l hw_get_module会在Android系统的属性文件中根据variant_keys数组中定义的4个key依次查找suffix。如果未找到suffix,使用默认的suffix(default)。HAL的存放路径和命名规则(3) 在上面的几点多次提到了属性文件,那么这个属性文件到底是什么呢?实际上,Android系统的属性文件共有如下4个。l /pl /system/pl /system/defau
25、pl /data/pHAL的存放路径和命名规则(4) Android在启动时会自动装载这些属性文件。如果在多个属性文件中都定义了同一个Key和Value,那么只用第一个Key被获取。例如,在/p文件中定义了duct.board的值为abc,而在/system/p文件中定义了duct.boardd的值为xyz。那么hw_get_module函数会把/p文件中的abc作为HAL模块库文件的后缀,而不会再读取/system/p文件中的xyz。因此,HAL模块的库文件名是(假设ID是led_hal)led_hal.abc.so。HAL的存放路径和命名规则(5) 4个属性文件名在如下文件定义了4个宏。在以后的Android版本中有可能增加新的属性文件。/working/android2.3.4_src/bionic/libc/include/sys/_system_proper
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 礼仪文化传承模板
- 公开课课件民族区域自治制度适合国情的好制度
- 嘉兴新式别墅花园施工方案
- 2024年镇小家长学校工作计划学校工作计划
- 校园帮扶工作计划格式
- 小学上学期2021教学科研处工作计划新选
- 2024年乡镇法律法规学习计划教研学习计划
- 2024年校长学期工作计划要点
- 韶关市计划生育证明书
- 乡年普法工作计划
- JCT558-2007 建筑用轻钢龙骨配件
- SYT 0447-2014《 埋地钢制管道环氧煤沥青防腐层技术标准》
- 我的家乡湖南
- 玩转计算机网络-计算机网络原理智慧树知到课后章节答案2023年下青岛大学
- 仰望古老的中国文化作文900字
- NICE3000NEW全系列电气调试说明书
- 线性代数的应用论文线性代数的应用论文
- 胃食管反流病的护理课件
- 妇科手术与输尿管损伤
- 安规热力和机械部分培训课件
- 施工现场专项消防安全检查表
评论
0/150
提交评论