为Android增加硬件抽象层(HAL)模块访问Linux内核驱动程序
在Android硬件抽象层(HAL)概要介绍和学习计划一文中,我们简要介绍了在Android系统为为硬件编写驱动程序的方法。简单来说,硬件驱动程序一方面分布在Linux内核中,另一方面分布在用户空间的硬件抽象层中。接着,在Ubuntu上为Android系统编写Linux内核驱动程序一 文中举例子说明了如何在Linux内核编写驱动程序。在这一篇文章中,我们将继续介绍Android系统硬件驱动程序的另一方面实现,即如何在硬件抽象层 中增加硬件模块来和内核驱动程序交互。在这篇文章中,我们还将学习到如何在Android系统创建设备文件时用类似Linux的udev规则修改设备文件 模式的方法。
一. 参照在Ubuntu上为Android系统编写Linux内核驱动程序一 文所示,准备好示例内核驱动序。完成这个内核驱动程序后,便可以在Android系统中得到三个文件,分别是/dev/hello、/sys/class /hello/hello/val和/proc/hello。在本文中,我们将通过设备文件/dev/hello来连接硬件抽象层模块和Linux内核驱 动程序模块。
二. 进入到在hardware/libhardware/include/hardware目录,新建hello.h文件:
USER-NAME@MACHINE-NAME:~/Android$ cd hardware/libhardware/include/hardware
USER-NAME@MACHINE-NAME:~/Android/hardware/libhardware/include/hardware$ vi hello.h
hello.h文件的内容如下:
- #ifndef ANDROID_HELLO_INTERFACE_H
- #define ANDROID_HELLO_INTERFACE_H
- #include <hardware/hardware.h>
- __BEGIN_DECLS
- /*定义模块ID*/
- #define HELLO_HARDWARE_MODULE_ID "hello"
- /*硬件模块结构体*/
- struct hello_module_t {
- struct hw_module_t common;
- };
- /*硬件接口结构体*/
- struct hello_device_t {
- struct hw_device_t common;
- int fd;
- int (*set_val)(struct hello_device_t* dev, int val);
- int (*get_val)(struct hello_device_t* dev, int* val);
- };
- __END_DECLS
- #endif
这里按照Android硬件抽象层规范的要求,分别定义模块ID、模块结构体以及硬件接口结构体。在硬件接口结构体中,fd表示设备文件描述符,对应我 们将要处理的设备文件"/dev/hello",set_val和get_val为该HAL对上提供的函数接口。
三. 进入到hardware/libhardware/modules目录,新建hello目录,并添加hello.c文件。 hello.c的内容较多,我们分段来看。
首先是包含相关头文件和定义相关结构:
- #define LOG_TAG "HelloStub"
- #include <hardware/hardware.h>
- #include <hardware/hello.h>
- #include <fcntl.h>
- #include <errno.h>
- #include <cutils/log.h>
- #include <cutils/atomic.h>
- #define DEVICE_NAME "/dev/hello"
- #define MODULE_NAME "Hello"
- #define MODULE_AUTHOR "shyluo@gmail.com"
- /*设备打开和关闭接口*/
- static int hello_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device);
- static int hello_device_close(struct hw_device_t* device);
- /*设备访问接口*/
- static int hello_set_val(struct hello_device_t* dev, int val);
- static int hello_get_val(struct hello_device_t* dev, int* val);
- /*模块方法表*/
- static struct hw_module_methods_t hello_module_methods = {
- open: hello_device_open
- };
- /*模块实例变量*/
- struct hello_module_t HAL_MODULE_INFO_SYM = {
- common: {
- tag: HARDWARE_MODULE_TAG,
- version_major: 1,
- version_minor: 0,
- id: HELLO_HARDWARE_MODULE_ID,
- name: MODULE_NAME,
- author: MODULE_AUTHOR,
- methods: &hello_module_methods,
- }
- };
这里,实例变量名必须为HAL_MODULE_INFO_SYM,tag也必须为HARDWARE_MODULE_TAG,这是Android硬件抽象层规范规定的。
定义hello_device_open函数:
- static int hello_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device) {
- struct hello_device_t* dev;dev = (struct hello_device_t*)malloc(sizeof(struct hello_device_t));
- if(!dev) {
- LOGE("Hello Stub: failed to alloc space");
- return -EFAULT;
- }
- memset(dev, 0, sizeof(struct hello_device_t));
- dev->common.tag = HARDWARE_DEVICE_TAG;
- dev->common.version = 0;
- dev->common.module = (hw_module_t*)module;
- dev->common.close = hello_device_close;
- dev->set_val = hello_set_val;dev->get_val = hello_get_val;
- if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) {
- LOGE("Hello Stub: failed to open /dev/hello -- %s.", strerror(errno));free(dev);
- return -EFAULT;
- }
- *device = &(dev->common);
- LOGI("Hello Stub: open /dev/hello successfully.");
- return 0;
- }
DEVICE_NAME定义为"/dev/hello"。由于设备文件是在内核驱动里面通过device_create创建的,而 device_create创建的设备文件默认只有root用户可读写,而hello_device_open一般是由上层APP来调用的,这些APP一 般不具有root权限,这时候就导致打开设备文件失败:
- static int hello_device_close(struct hw_device_t* device) {
- struct hello_device_t* hello_device = (struct hello_device_t*)device;
- if(hello_device) {
- close(hello_device->fd);
- free(hello_device);
- }
- return 0;
- }
- static int hello_set_val(struct hello_device_t* dev, int val) {
- LOGI("Hello Stub: set value %d to device.", val);
- write(dev->fd, &val, sizeof(val));
- return 0;
- }
- static int hello_get_val(struct hello_device_t* dev, int* val) {
- if(!val) {
- LOGE("Hello Stub: error val pointer");
- return -EFAULT;
- }
- read(dev->fd, val, sizeof(*val));
- LOGI("Hello Stub: get value %d from device", *val);
- return 0;
- }
虽然我们在Android系统为我们自己的硬件增加了一个硬件抽象层模块,但是现在Java应用程序还不能访问到我们的硬件。我们还必须编写JNI方法 和在Android的Application Frameworks层增加API接口,才能让上层Application访问我们的硬件。在接下来的文章中,我们还将完成这一系统过程,使得我们能够在 Java应用程序中访问我们自己定制的硬件
为Android增加硬件抽象层(HAL)模块访问Linux内核驱动程序的更多相关文章
- 在Ubuntu上为Android增加硬件抽象层(HAL)模块访问Linux内核驱动程序(老罗学习笔记3)
简单来说,硬件驱动程序一方面分布在Linux内核中,另一方面分布在用户空间的硬件抽象层中.接着,在Ubuntu上为Android系统编写Linux内核驱动程序(老罗学习笔记1)一文中举例子说明了如何在 ...
- 在Ubuntu上为Android系统内置C可执行程序测试Linux内核驱动程序(老罗学习笔记2)
在前一篇文章中,我们介绍了如何在Ubuntu上为Android系统编写Linux内核驱动程序.在这个名为hello的Linux内核驱动程序中,创建三个不同的文件节点来供用户空间访问,分别是传统的设备文 ...
- 为Android系统内置C可执行程序测试Linux内核驱动程序
在前一篇文章中,我们介绍了如何在Ubuntu上为Android系统编写Linux内核驱动程序.在这个名为hello的Linux内核驱动程序中, 创建三个不同的文件节点来供用户空间访问,分别是传统的设备 ...
- Android架构分析之使用自定义硬件抽象层(HAL)模块
作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz Android版本:2.3.7_r1 Linux内核版本:android-goldfish-2.6.29 在上一篇博 ...
- 在Ubuntu上为Android系统编写Linux内核驱动程序(老罗学习笔记1)
这里,我们不会为真实的硬件设备编写内核驱动程序.为了方便描述为Android系统编写内核驱动程序的过程,我们使用一个虚拟的硬件设备,这个设备只有一个4字节的寄存器,它可读可写.想起我们第一次学习程序语 ...
- 在Ubuntu上为Android系统编写Linux内核驱动程序
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6568411 在智能手机时代,每个品牌的手机都有 ...
- 转: 使用 /sys 文件系统访问 Linux 内核
转一个挺不错的文章 使用 /sys 文件系统访问 Linux 内核 https://www.ibm.com/developerworks/cn/linux/l-cn-sysfs/ 如果你正在开发的设备 ...
- 转:使用 /proc 文件系统来访问 Linux 内核的内容
使用 /proc 文件系统来访问 Linux 内核的内容 https://www.ibm.com/developerworks/cn/linux/l-proc.html /proc 文件系统并不是 G ...
- 使用 /sys 文件系统访问 Linux 内核
sysfs 与 /sys sysfs 文件系统总是被挂载在 /sys 挂载点上.虽然在较早期的2.6内核系统上并没有规定 sysfs 的标准挂载位置,可以把 sysfs 挂载在任何位置,但较近的2.6 ...
随机推荐
- idea代码调试debug篇
主要看图,看图一目了然. 断点的设定和eclipse一样,只要点一下就可以,下面是我设定的几个断点,再下面的三个窗口是用来调试代码的,这个和eclipse类似 调试常用的快捷键 F9 ...
- 关于java的上转型对象
1. 定义 如果B类是A类的子类或间接子类,当用B类创建对象b并将这个对象b的引用赋给A类对象a时,如: A a;a = new B();ORA a;B b = new B();a = b; 则称A类 ...
- Gym 100553B Burrito King 无脑背包
题意就是你有n和m两个上限 吃一个东西会同时增加两个东西 m的值不能超过给定的m 问最后的n m值和每个东西吃了多少 贪心一下就好了 算一下性价比 从最大的开始吃 直到吃满了m n也一定是最大了 只是 ...
- SharePoint 2013 工作流设计之Designer 使用“可视化视图
转载自:http://www.cnblogs.com/jianyus/p/3406309.html SharePoint 2013增强了工作流功能,而Designer里面也添加了可视化设计视图,也就是 ...
- kvstore之mongodb为存储介质
配置config(连接mongo) mongo define('KVSTORE_STORAGE', 'base_kvstore_mongodb'); define('MONGODB_SERVER_CO ...
- 【strtok()】——分割字符串
对字符串进行分割: 在使用前需要先初始化例如: char * p=strtok(Str," ");/*初始化以" "(以空格字符来分割字符串),即把" ...
- ural 1355. Bald Spot Revisited(数的素因子划分)
1355. Bald Spot Revisited Time limit: 1.0 secondMemory limit: 64 MB A student dreamt that he walked ...
- 对http协议断点续传的理解
断点续传指的是下载传输文件可以中断,之后重新下载时可以接着中断的地方开始下载,而不必从头开始下载.断点续传需要客户端和服务端都支持. 原理是客户端一块一块的请求数据,最后将下载回来的数据块拼接成完整的 ...
- java启动子进程以及进程通信
1.利用进程的管道通信传输流 2.子进程没有控制台,正常测试的时候也是没办法看到子进程的输出的,需要传到主线程 3.测试主进程传参给子进程再传回来 4.父进程启动子进程只要执行runtime.exec ...
- 线程中sleep方法和wait方法有什么区别?
如果你没有接触过java的多线程,那么多对于这两个方法可能有点陌生,看名字好像这两个方法是差不多的,但是实际上面差别好大. 首先我们看一下官方的API Sleep(sleep有两个方法,另一个方法传递 ...