• android深度搜索学习笔记四(硬件抽像hal第一部分)


     硬件抽像hal 

    1 android 中添加hal层是为了 

     统一硬件的调用接口

    解决了GPL的版权问题

    针对特殊要求’

    2 android 的框架

    Android 最初的架构如下图所示

     

    新的hal架构

     

    Hal源代码文件存储目录不固定,一般存放在/hardware目录中,

    其中/hardware/libhardware_legacy存放着旧的hal源代码文件

    最终编译生成的.so库存放在system/lib/hw

    LED驱动增加HAL

      编写支持hallinux驱动程序的步骤:

    a编写linux驱动程序,包含以下向个文件:

    mini6410_leds_hal.c    mini6410_leds_hal.h    leds_hal_define.h     Makefile 

    build.sh   build_mini6410.sh

    mini6410_leds_hal.h 文件内容如下:

    #include <linux/fs.h>

    #include <linux/cdev.h>

    #include <linux/pci.h>

    #include <linux/uaccess.h>

    #include <mach/map.h>

    #include <mach/regs-gpio.h>

    #include <mach/gpio-bank-k.h>

    #define DEVICE_NAME "mini6410_leds_hal"

    #define DEVICE_COUNT 1

    #define MINI6410_LEDS_MAJOR 0

    #define MINI6410_LEDS_MINOR 244

    leds_hal_define.h文件的内容如下:

    //写入数据

    #define MINI6410_LEDS_HAL_WRITE_GPKPUD 1 

    #define MINI6410_LEDS_HAL_WRITE_GPKCON 2 

    #define MINI6410_LEDS_HAL_WRITE_GPKDAT 3 

    //读取数据

    #define MINI6410_LEDS_HAL_READ_GPKPUD 4 

    #define MINI6410_LEDS_HAL_READ_GPKCON 5 

    #define MINI6410_LEDS_HAL_READ_GPKDAT 6 

    mini6410_leds_hal.c文件内容如下:

    #include "mini6410_leds_hal.h"

    #include "leds_hal_define.h"

    //读写寄存器的数据

    //第一个字节保存gpk寄存器类型,后四个字节保存gpk寄存器的值

    static unsigned char mem[5];

    //主设备号

    static int major=MINI6410_LEDS_MAJOR;

    //次设备号

    static int minor=MINI6410_LEDS_MINOR;

    //设备号

    static dev_t dev_number;

    //struct class表示led字符设备的结构体

    static struct class *leds_class=NULL;

    //描述字符设备的struct cdev

    static struct cdev leds_cdev;

    //将四个字节转换成int类型的数据

    //只处理从start开始的四个字节

    static int bytes_to_int(unsigned char buf[],int start){

    int n = 0;

    n = ((int) buf[start]) << 24 | //

        ((int) buf[start + 1]) << 16 |//

                ((int) buf[start + 2]) << 8 | //

                ((int) buf[start + 3]);

    return n;

    }

    //int类型数据转换成byte数组类型

    //n为待转换的数,buf存储转换结果,start将结果存放在buf的指定位置

    static void int_to_bytes(int n,unsigned char buf[],int start){

    buf[start] = n >> 24;

    buf[start + 1] = n >> 16;

    buf[start + 2] = n >> 8;

    buf[start + 3] = n;

    }

    //设备文件的write函数

    static ssize_t mini6410_leds_hal_write(struct file *file,const char __user *buf,size_t count,loff_t *ppos){

    //从用户空间复制数据到内核空间

    if(copy_from_user(mem,buf,5)){

    return -EFAULT;

    }else{

    //取得gpk寄存器类型

    int gpk_type = mem[0];

    //向寄存器写入数据

    switch(gpk_type){

    case MINI6410_LEDS_HAL_WRITE_GPKPUD:

    iowrite32(bytes_to_int(mem,1),S3C64XX_GPKPUD);

    break;   

              case MINI6410_LEDS_HAL_WRITE_GPKCON:  

                             iowrite32(bytes_to_int(mem,1),S3C64XX_GPKCON);

    break;

                            case MINI6410_LEDS_HAL_WRITE_GPKDAT: 

    iowrite32(bytes_to_int(mem,1),S3C64XX_GPKDAT);

    break;

    }

    }

    //必须返回大于等于5?否则会调用多次

    return 5;

    }

    //设备文件的read函数

    static ssize_t mini6410_leds_hal_read(struct file *file,char __user *buf,size_t count,loff_t *ppos){

    //取得gpk类型

    int gpk_type = mem[0];

    int gpk_value = 0;

    //从寄存器读取一个int类型的数据

    switch(gpk_type){

    case MINI6410_LEDS_HAL_READ_GPKPUD:

    gpk_value=ioread32(S3C64XX_GPKPUD);

    break;

    case MINI6410_LEDS_HAL_READ_GPKCON:

    gpk_value=ioread32(S3C64XX_GPKCON); 

    break;

    case MINI6410_LEDS_HAL_READ_GPKDAT: 

    gpk_value=ioread32(S3C64XX_GPKDAT);

    break; 

    }

    //int型数据转换为byte数组

    int_to_bytes(gpk_value,mem,1);

    //将转换后的数据复制到用户空间

    if(copy_to_user(buf,(void*)mem,5)){

    return -EFAULT;

    }

    return 5;

    }

    //file_operations 结构体

    static struct file_operations dev_fops={

    .owner = THIS_MODULE,

    .read = mini6410_leds_hal_read,

    .write = mini6410_leds_hal_write

    };

    //-------创建设备文件

    static int leds_create_device(void){

    int ret =0;

    int err=0;

    //初始化cdev成员

    cdev_init(&leds_cdev,&dev_fops);

    //创建的设备文件属于当前的驱动模块

    leds_cdev.owner=THIS_MODULE;

    //主设备号大于0,通过指定设备号的方式注册字符设备

    if(major>0){

    //获取设备号

    dev_number=MKDEV(major,minor);

    //通过指定设备号的方式注册字符设备区域

    err=register_chrdev_region(dev_number,DEVICE_COUNT,DEVICE_NAME);

    //注册失败

    if(err<0){

    printk(KERN_WARNING "register_chrdev_region() failed ");

    return err;

    }

    }

    else{//主设备号为0,自动分配主设备号和次设备号

    //通过自动分配主设备号和次设备号的方式

    //10表示起始次设备号

    err=alloc_chrdev_region(&leds_cdev.dev,10,DEVICE_COUNT,DEVICE_NAME);

    //注册失败

    if(err<0){

    printk(KERN_WARNING "alloc_chrdev_region() failed ");

    return err;

    }

    //获取主设备号

    major=MAJOR(leds_cdev.dev);

    //获取次设备号

    minor=MINOR(leds_cdev.dev);

    //自动分配的设备号

    dev_number= leds_cdev.dev;

    }

    //将字符设备添加到内核中的字符设备数组中

    ret=cdev_add(&leds_cdev,dev_number,DEVICE_COUNT);

    //创建struct class

    leds_class=class_create(THIS_MODULE,DEVICE_NAME);

    //创建设备文件

    device_create(leds_class,NULL,dev_number,NULL,DEVICE_NAME);

    return ret;

    }

    //初始化led驱动

    static int leds_init(void){

    int ret;

    //创建led驱动的设备文件

    ret=leds_create_device();

    printk(DEVICE_NAME"  initialized  ");

    return ret;

    }

    //销毁字符设备

    static void leds_destroy_device(void){

    //销毁字符设备

    device_destroy(leds_class,dev_number);

    //销毁class结构体

    if(leds_class){

    class_destroy(leds_class);

    }

    //注销字符设备区

    unregister_chrdev_region(dev_number,DEVICE_COUNT);

    return;

    }

    //卸载led驱动

    static void leds_exit(void){

    leds_destroy_device();

    printk(DEVICE_NAME"  exit!  ");

    }

    module_init(leds_init);

    module_exit(leds_exit);

    MODULE_LICENSE("GPL");

    MODULE_AUTHOR("retacn");

    Makefile文件的内容如下:

    obj-m := mini6410_leds_hal.o

    DEBUG = y

    Build.sh文件的内容如下:

    source ./build_mini6410.sh

    Build_mini6410.sh文件内容如下:

    source /opt/linux/driver/common.sh

    make -C $MINI6410_ANDROID_KERNEL_PATH M=${PWD}

    find_devices 

    if [ "$selected_device" == "" ]; then 

        exit

    else

        adb -s $selected_device push ${PWD}/mini6410_leds_hal.ko /data/local

        testing=$(adb -s $selected_device shell lsmod | grep  "mini6410_leds_hal")

        if [ "$testing" != "" ]; then

    adb -s $selected_device shell rmmod mini6410_leds_hal

        fi

        adb -s $selected_device shell "insmod /data/local/mini6410_leds_hal.ko"

        adb -s $selected_device shell  "chmod 777 /dev/mini6410_leds_hal"

    fi

    测试写寄存器操作

    向设备文件发送字节类型的测试程序

    #include <fcntl.h>

    #include <stdio.h>

    #include <stdlib.h>

    #include <string.h>

    #include <sys/ioctl.h>

    int main(int argc,char **argv){

    int file_handler=0;

    char *usage = "Usage: rwdev <r|w> <dev_file> <byte_count> <byet1> <byte2> ... <byten>";

    //如果输出参数不满足条件,则输出rwdev命令的语法

    if (argc < 4){

    printf("%s ",usage);

    return 0;

    }

    //必需指定读或是写,否则输出提示语法

    char *cmd=argv[1];

    if(strcmp("r",cmd)!=0 && strcmp("w",cmd)!=0){

    printf("%s ",usage);

    return 0;

    }

    //设备文件名

    char *dev_filename=argv[2];

    //将要读写的数据转换为int类型

    int byte_count=atoi(argv[3]);

    //用于读写数据的数组

    unsigned char buf[byte_count];

    int i=0;

    //从设备读数据

    if(strcmp("r",cmd)==0){

    //以读写的方式打开设备文件

    file_handler= open(dev_filename,O_RDWR);

    //表示读取寄存器的类型

    buf[0]=atoi(argv[4]);

    //写入要读取哪个寄存器的数据

    write(file_handler,buf,1);

    //读取寄存器数据

    read(file_handler,buf,byte_count);

    //输出读取的字节数

    printf("%d bytes: ",byte_count);

    //以十进制形式输出读取的字节数

    for(;i<byte_count;i++){

    printf("%d ",buf[i]);

    }

    printf(" ");

    }else if(strcmp("w",cmd)==0){//向设备写数据

    //将要写入的数据存储到buf

    for(;i<byte_count;i++){

    buf[i]=atoi(argv[4+i]);

    }

    //以只写方式打开设备文件

    file_handler=open(dev_filename,O_WRONLY);

    //向设备文件写义数据

    write(file_handler,buf,byte_count);

    }

    //关闭设备文件

    close(file_handler);

    return 0;

    }

    Build.sh文件内容如下:

    #利用Android源代码编译,未实现????

    #  直接利用交叉编译器进行编译

    arm-linux-gcc -static  -o  /opt/linux/driver/read_write_dev/rwdev  /opt/linux/driver/read_write_dev/rw_dev.c

    adb push /opt/linux/driver/read_write_dev/rwdev /data/local/rwdev

    编译安装测试结果:

    //点亮四个led 

    /data/local # ./rwdev w /dev/mini6410_leds_hal 5 3 0 0 0 0

  • 相关阅读:
    (100%成功超详细图文教程)虚拟机VM ware中centos7无法上网及Xshell配置正确但是连接不上本地虚拟机问题汇总
    react-art 初步
    React-父组件访问子组件内部
    React学习随笔
    关于Git使用的常见问题和命令
    ES6随笔--Module
    ES6随笔--Set和Map
    ES6随笔--Promise
    ES6随笔--Symbol
    ES6随笔--各数据类型的扩展(3)--函数
  • 原文地址:https://www.cnblogs.com/retacn-yue/p/6194251.html
Copyright © 2020-2023  润新知