硬件抽像hal

1android中添加hal层是为了

统一硬件的调用接口

解决了GPL的版权问题

针对特殊要求’

2android的框架

Android最初的架构如下图所示

新的hal架构

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

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

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

3LED驱动增加HAL

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

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

mini6410_leds_hal.cmini6410_leds_hal.hleds_hal_define.hMakefile

build.shbuild_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>

#defineDEVICE_NAME"mini6410_leds_hal"

#defineDEVICE_COUNT1

#defineMINI6410_LEDS_MAJOR0

#defineMINI6410_LEDS_MINOR244

leds_hal_define.h文件的内容如下:

//写入数据

#defineMINI6410_LEDS_HAL_WRITE_GPKPUD1

#defineMINI6410_LEDS_HAL_WRITE_GPKCON2

#defineMINI6410_LEDS_HAL_WRITE_GPKDAT3

//读取数据

#defineMINI6410_LEDS_HAL_READ_GPKPUD4

#defineMINI6410_LEDS_HAL_READ_GPKCON5

#defineMINI6410_LEDS_HAL_READ_GPKDAT6

mini6410_leds_hal.c文件内容如下:

#include"mini6410_leds_hal.h"

#include"leds_hal_define.h"

//读写寄存器的数据

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

staticunsignedcharmem[5];

//主设备号

staticintmajor=MINI6410_LEDS_MAJOR;

//次设备号

staticintminor=MINI6410_LEDS_MINOR;

//设备号

staticdev_tdev_number;

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

staticstructclass*leds_class=NULL;

//描述字符设备的structcdev

staticstructcdevleds_cdev;

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

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

staticintbytes_to_int(unsignedcharbuf[],intstart){

intn=0;

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

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

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

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

returnn;

}

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

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

staticvoidint_to_bytes(intn,unsignedcharbuf[],intstart){

buf[start]=n>>24;

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

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

buf[start+3]=n;

}

//设备文件的write函数

staticssize_tmini6410_leds_hal_write(structfile*file,constchar__user*buf,size_tcount,loff_t*ppos){

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

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

return-EFAULT;

}else{

//取得gpk寄存器类型

intgpk_type=mem[0];

//向寄存器写入数据

switch(gpk_type){

caseMINI6410_LEDS_HAL_WRITE_GPKPUD:

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

break;

caseMINI6410_LEDS_HAL_WRITE_GPKCON:

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

break;

caseMINI6410_LEDS_HAL_WRITE_GPKDAT:

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

break;

}

}

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

return5;

}

//设备文件的read函数

staticssize_tmini6410_leds_hal_read(structfile*file,char__user*buf,size_tcount,loff_t*ppos){

//取得gpk类型

intgpk_type=mem[0];

intgpk_value=0;

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

switch(gpk_type){

caseMINI6410_LEDS_HAL_READ_GPKPUD:

gpk_value=ioread32(S3C64XX_GPKPUD);

break;

caseMINI6410_LEDS_HAL_READ_GPKCON:

gpk_value=ioread32(S3C64XX_GPKCON);

break;

caseMINI6410_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;

}

return5;

}

//file_operations结构体

staticstructfile_operationsdev_fops={

.owner=THIS_MODULE,

.read=mini6410_leds_hal_read,

.write=mini6410_leds_hal_write

};

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

staticintleds_create_device(void){

intret=0;

interr=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");

returnerr;

}

}

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

returnerr;

}

//获取主设备号

major=MAJOR(leds_cdev.dev);

//获取次设备号

minor=MINOR(leds_cdev.dev);

//自动分配的设备号

dev_number=leds_cdev.dev;

}

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

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

//创建structclass

leds_class=class_create(THIS_MODULE,DEVICE_NAME);

//创建设备文件

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

returnret;

}

//初始化led驱动

staticintleds_init(void){

intret;

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

ret=leds_create_device();

printk(DEVICE_NAME"\tinitialized\n");

returnret;

}

//销毁字符设备

staticvoidleds_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驱动

staticvoidleds_exit(void){

leds_destroy_device();

printk(DEVICE_NAME"\texit!\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_PATHM=${PWD}

find_devices

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

exit

else

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

testing=$(adb-s$selected_deviceshelllsmod|grep"mini6410_leds_hal")

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

adb-s$selected_deviceshellrmmodmini6410_leds_hal

fi

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

adb-s$selected_deviceshell"chmod777/dev/mini6410_leds_hal"

fi

测试写寄存器操作

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

#include<fcntl.h>

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

#include<sys/ioctl.h>

intmain(intargc,char**argv){

intfile_handler=0;

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

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

if(argc<4){

printf("%s\n",usage);

return0;

}

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

char*cmd=argv[1];

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

printf("%s\n",usage);

return0;

}

//设备文件名

char*dev_filename=argv[2];

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

intbyte_count=atoi(argv[3]);

//用于读写数据的数组

unsignedcharbuf[byte_count];

inti=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("%dbytes:",byte_count);

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

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

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

}

printf("\n");

}elseif(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);

return0;

}

Build.sh文件内容如下:

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

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

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

adbpush/opt/linux/driver/read_write_dev/rwdev/data/local/rwdev

编译安装测试结果:

//点亮四个led

/data/local#./rwdevw/dev/mini6410_leds_hal530000

更多相关文章

  1. Android(安卓)DataBinding 找不到生成的binding类的原因
  2. Android创建文件夹
  3. Android(安卓)xmlns 的作用及其自定义
  4. [Android] 该文件包与具有同一名称的现有文件包存在冲突
  5. Android多分辨率适配
  6. 分析Android(安卓)根文件系统启动过程(init守护进程分析)
  7. Android(安卓)UI设计技巧
  8. 听说”双11”是这么解决线上bug的
  9. NPM 和webpack 的基础使用

随机推荐

  1. Android初始化语言 (init.*.rc、init.con
  2. android Animation的xml的编写
  3. android 退出程序三种方法及两种形式
  4. 【持续更新】Android(安卓)Studio各种疑
  5. cocos2dx2.2移植到Android
  6. Android(安卓)保存图片到Sqlite数据库
  7. 当忘记Android发布签名和别名的时候
  8. 安卓入门(八)
  9. Gradle在Android中的简单使用
  10. android Audio 详解( 一 )