老罗的ANDROID之旅---硬件抽象层学习笔记

本文记录了在Ubuntu上学习Android硬件抽象层(HAL)的过程,涉及Linux内核驱动编写、C可执行程序测试驱动、HAL模块接入、JNI方法创建、Application Frameworks层硬件服务等,探讨了HAL对硬件支持的分层原因及其商业考量。
摘要由CSDN通过智能技术生成

下面是在学习老罗的ANDROID之旅hal过程中的笔记: 基本上都是从其COPY的

Android的硬件抽象层,简单来说,就是对Linux内核驱动程序的封装,向上提供接口,屏蔽低层的实现细节。也就是说,把对硬件的支持分成了两层,一层放在用户空间(User Space),一层放在内核空间(Kernel Space),其中,硬件抽象层运行在用户空间,而Linux内核驱动程序运行在内核空间。为什么要这样安排呢?把硬件抽象层和内核驱动整合在一起放在内核空间不可行吗?从技术实现的角度来看,是可以的,然而从商业的角度来看,把对硬件的支持逻辑都放在内核空间,可能会损害厂家的利益。我们知道,Linux内核源代码版权遵循GNU License,而Android源代码版权遵循Apache License,前者在发布产品时,必须公布源代码,而后者无须发布源代码。如果把对硬件支持的所有代码都放在Linux驱动层,那就意味着发布时要公开驱动程序的源代码,而公开源代码就意味着把硬件的相关参数和实现都公开了,在手机市场竞争激烈的今天,这对厂家来说,损害是非常大的。因此,Android才会想到把对硬件的支持分成硬件抽象层和内核驱动层,内核驱动层只提供简单的访问硬件逻辑,例如读写硬件寄存器的通道,至于从硬件中读到了什么值或者写了什么值到硬件中的逻辑,都放在硬件抽象层中去了,这样就可以把商业秘密隐藏起来了。也正是由于这个分层的原因,Android被踢出了Linux内核主线代码树中。大家想想,Android放在内核空间的驱动程序对硬件的支持是不完整的,把Linux内核移植到别的机器上去时,由于缺乏硬件抽象层的支持,硬件就完全不能用了,这也是为什么说Android是开放系统而不是开源系统的原因。

在学习Android硬件抽象层的过程中,我们将会学习如何在内核空间编写硬件驱动程序、如何在硬件抽象层中添加接口支持访问硬件、如何在系统启动时提供硬件访问服务以及 如何编写JNI使得可以通过Java接口来访问硬件,而作为中间的一个小插曲,我们还将学习一下如何在Android系统中添加一个C可执行程序来访问硬件驱动程序。


在Ubuntu上为Android系统编写Linux内核驱动程序

我的开发测试环境是ANDROID 4.2 以及 Linux3.4 ,我将相关的驱动程序放在drivers/media/video/sunxi_csi/device 下面,主要是为了测试的方便:
hello.h 
 1 #ifndef _HELLO_ANDROID_H_                                                                                                       
  2 #define _HELLO_ANDROID_H_  
  3 
  4 #include <linux/cdev.h>
  5 #include <linux/semaphore.h>
  6 
  7 #define HELLO_DEVICE_NODE_NAME  "hello"  
  8 #define HELLO_DEVICE_FILE_NAME  "hello"  
  9 #define HELLO_DEVICE_PROC_NAME  "hello"  
 10 #define HELLO_DEVICE_CLASS_NAME "hello"  
 11 
 12 struct hello_android_dev {
 13     int val;
 14     struct semaphore sem;
 15     struct cdev dev;
 16 };
 17 
 18 #endif


hello.c 
#include <linux/init.h>  
#include <linux/module.h>  
#include <linux/types.h>  
#include <linux/fs.h>  
#include <linux/proc_fs.h>  
#include <linux/device.h>  
#include <asm/uaccess.h>  
  
#include "hello.h"  
  
/*主设备和从设备号变量*/  
static int hello_major = 0;  
static int hello_minor = 0;  
  
/*设备类别和设备变量*/  
static struct class* hello_class = NULL;  
static struct hello_android_dev* hello_dev = NULL;  
  
/*传统的设备文件操作方法*/  
static int hello_open(struct inode* inode, struct file* filp);  
static int hello_release(struct inode* inode, struct file* filp);  
static ssize_t hello_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos);  
static ssize_t hello_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos);  
  
/*设备文件操作方法表*/  
static struct file_operations hello_fops = {  
    .owner = THIS_MODULE,  
    .open = hello_open,  
    .release = hello_release,  
    .read = hello_read,  
    .write = hello_write,   
};  
  
/*访问设置属性方法*/  
static ssize_t hello_val_show(struct device* dev, struct device_attribute* attr,  char* buf);  
static ssize_t hello_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count);  
  
/*定义设备属性*/  
static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, hello_val_show, hello_val_store);  

/*打开设备方法*/  
static int hello_open(struct inode* inode, struct file* filp) {  
    struct hello_android_dev* dev;          
      
    /*将自定义设备结构体保存在文件指针的私有数据域中,以便访问设备时拿来用*/  
    dev = container_of(inode->i_cdev, struct hello_android_dev, dev);  
    filp->private_data = dev;  
      
    return 0;  
}  
  
/*设备文件释放时调用,空实现*/  
static int hello_release(struct inode* inode, struct file* filp) {  
    return 0;  
}  
  
/*读取设备的寄存器val的值*/  
static ssize_t hello_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos) {  
    ssize_t err = 0;  
    struct hello_android_dev* dev = filp->private_data;          
  
    /*同步访问*/  
    if(down_interruptible(&(dev->sem))) {  
        return -ERESTARTSYS;  
    }  
  
    if(count < sizeof(dev->val)) {  
        goto out;  
    }          
  
    /*将寄存器val的值拷贝到用户提供的缓冲区*/  
    if(copy_to_user(buf, &(dev->val), sizeof(dev->val))) {  
        err = -EFAULT;  
        goto out;  
    }  
  
    err = sizeof(dev->val);  
  
out:  
    up(&(dev->sem));  
    return err;  
}  
  
/*写设备的寄存器值val*/  
static ssize_t hello_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos) {  
    struct hello_android_dev* dev = filp->private_data;  
    ssize_t err = 0;          
  
    /*同步访问*/  
    if(down_interruptible(&(dev->sem))) {  
        return -ERESTARTSYS;          
    }          
  
    if(count != sizeof(dev->val)) {  
        goto out;          
    }          
  
    /*将用户提供的缓冲区的值写到设备寄存器去*/  
    if(copy_from_user(&(dev->val), buf, count)) {  
        err = -EFAULT;  
        goto out;  
    }  
  
    err = sizeof(dev->val);  
  
out:  
    up(&(dev->sem));  
    return err;  
}  

/*读取寄存器val的值到缓冲区buf中,内部使用*/  
static ssize_t __hello_get_val(struct hello_android_dev* dev, char* buf) {  
    int val = 0;          
  
    /*同步访问*/  
    if(down_interruptible(&(dev->sem))) {                  
        return -ERESTARTSYS;          
    }          
  
    val = dev->val;          
    up(&(dev->sem));          
  
    return snprintf(buf, PAGE_SIZE, "%d\n", val);  
}  
  
/*把缓冲区buf的值写到设备寄存器val中去,内部使用*/  
static ssize_t __hello_set_val(struct hello_android_dev* dev, const char* buf, size_t count) {  
    int val = 0;          
  
    /*将字符串转换成数字*/          
    val = simple_strtol(buf, NULL, 10);          
  
    /*同步访问*/          
    if(down_interruptible(&(dev->sem))) {                  
        return -ERESTARTSYS;          
    }          
  
    dev->val = val;          
    up(&(dev->sem));  
  
    return count;  
}  
  
/*读取设备属性val*/  
static ssize_t hello_val_show(struct device* dev, struct device_attribute* attr, char* buf) {  
    struct hello_android_dev* hdev = (struct hello_android_dev*)dev_get_drvdata(dev);          
  
    return __hello_get_val(hdev, buf);  
}  
  
/*写设备属性val*/  
static ssize_t hello_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count) {   
    struct hello_android_dev* hdev = (struct hello_android_dev*)dev_get_drvdata(dev);    
      
    return __hello_set_val(hdev, buf, count);  
}  

/*读取设备寄存器val的值,保存在page缓冲区中*/  
static ssize_t hello_proc_read(char* page, char** start, off_t off, int count, int* eof, void* data) {  
    if(off > 0) {  
        *eof = 1;  
        return 0;  
    }  
  
    return __hello_get_val(hello_dev, page);  
}  
  
/*把缓冲区的值buff保存到设备寄存器val中去*/  
static ssize_t hello_proc_write(struct file* filp, const char __user *buff, unsigned long len, void* data) {  
    int err = 0;  
    char* page = NULL;  
  
    if(len > PAGE_SIZE) {  
        printk(KERN_ALERT"The buff is too large: %lu.\n", len);  
        return -EFAULT;  
    }  
  
    page = (char*)__get_free_page(GFP_KERNEL);  
    if(!page) {                  
        printk(KERN_ALERT"Failed to alloc page.\n");  
        return -ENOMEM;  
    }          
  
    /*先把用户提供的缓冲区值拷贝到内核缓冲区中去*/  
    if(copy_from_user(page, buff, len)) {  
        printk(KERN_ALERT"Failed to copy buff from user.\n");                  
        err = -EFAULT;  
        goto out;  
    }  
  
    err = __hello_set_val(hello_dev, page, len);  
  
out:  
    free_page((unsigned long)page);  
    return err;  
}  
  
/*创建/proc/hello文件*/  
static void hello_create_proc(void) {  
    struct proc_dir_entry* entry;  
      
    entry = create_proc_entry(HELLO_DEVICE_PROC_NAME, 0, NU
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值