android深度搜索学习笔记四(硬件抽像hal第一部分)
硬件抽像hal
1android中添加hal层是为了
统一硬件的调用接口
解决了GPL的版权问题
针对特殊要求’
2android的框架
Android最初的架构如下图所示
新的hal架构
Hal源代码文件存储目录不固定,一般存放在/hardware目录中,
其中/hardware/libhardware_legacy存放着旧的hal源代码文件
最终编译生成的.so库存放在system/lib/hw
3为LED驱动增加HAL
编写支持hal的linux驱动程序的步骤:
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
更多相关文章
- Android(安卓)DataBinding 找不到生成的binding类的原因
- Android创建文件夹
- Android(安卓)xmlns 的作用及其自定义
- [Android] 该文件包与具有同一名称的现有文件包存在冲突
- Android多分辨率适配
- 分析Android(安卓)根文件系统启动过程(init守护进程分析)
- Android(安卓)UI设计技巧
- 听说”双11”是这么解决线上bug的
- NPM 和webpack 的基础使用