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

 硬件抽像hal 

1 android 中添加hal层是为了 

 统一硬件的调用接口

解决了GPL的版权问题

针对特殊要求’

 

2 android 的框架

Android 最初的架构如下图所示

 android深度搜索学习笔记四(硬件抽像hal第一部分)_第1张图片

新的hal架构

 android深度搜索学习笔记四(硬件抽像hal第一部分)_第2张图片

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\n");

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\n");

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"\t initialized \n");

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"\t exit! \n");

}

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\n",usage);

return 0;

}

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

char *cmd=argv[1];

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

printf("%s\n",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("\n");

}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

你可能感兴趣的:(android深度搜索学习笔记四(硬件抽像hal第一部分))