一、编写linux驱动
------s5pv210_leds.c#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/device.h>
#include <linux/cdev.h>
#define S5PV210_GPJ2CON 0
#define S5PV210_GPJ2DAT 1
volatile unsigned int *gpj2con = NULL;
volatile unsigned int *gpj2dat= NULL;
static unsigned int mem[2];
static dev_t devno;
static struct class *leds_class = NULL;
static ssize_t leds_hal_write(struct file *file, const char __user *buf,size_t count, loff_t *ppos)
{
if (copy_from_user(mem, buf, count)) //成功返回0,失败返回没拷贝的字节数
{
return -EFAULT;
}
else
{
switch (buf[0])
{
case S5PV210_GPJ2CON:
*gpj2con=mem[1];
printk("gpj2con=%u\n",*gpj2con);
break;
case S5PV210_GPJ2DAT:
*gpj2dat=mem[1];
printk("gpj2dat:%u\n",*gpj2dat);
break;
}
}
return count;
}
static struct file_operations dev_fops =
{
.owner = THIS_MODULE,
.write = leds_hal_write,
};
static struct cdev cdev;
static int leds_init(void)
{
cdev_init(&cdev, &dev_fops);
cdev.owner = THIS_MODULE;
alloc_chrdev_region(&devno, 0, 1,"lyl_hal_leds");
cdev_add(&cdev, devno, 1);
leds_class = class_create(THIS_MODULE, "lyl_hal_leds");
device_create(leds_class, NULL, devno, NULL, "lyl_hal_leds");
gpj2con = (volatile unsigned int*)ioremap(0xe0200280, 8);
gpj2dat = gpj2con + 1;
printk("leds_init\n");
return 0;
}
static void leds_exit(void)
{
device_destroy(leds_class, devno);
class_destroy(leds_class);
unregister_chrdev_region(devno, 0);
cdev_del(&cdev);
iounmap(gpj2con);
printk("leds_exit\n");
}
module_init(leds_init);
module_exit(leds_exit);
MODULE_LICENSE("GPL");
------Makefile
KERN_DIR = /home/linux-3.0.8
all:
make -C $(KERN_DIR) M=`pwd` modules
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order
obj-m += s5pv210_leds.o
------wdev.c
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/ioctl.h>
int main(int argc,char**argv)
{
int fd=0;
unsigned int buf[2];
buf[0]=atoi(argv[1]);
buf[1]=atoi(argv[2]);
fd=open("/dev/lyl_hal_leds",O_RDWR);
if(fd<0)
{
printf("open error\n");
return -1;
}
write(fd,buf,sizeof(buf));
close(fd);
return 0;
}
------测试linux驱动
root@lyl:/home/test# ls
Makefile s5pv210_leds.c wdev.c
root@lyl:/home/test# make
root@lyl:/home/test# arm-linux-gcc -static wdev.c -o wdev //必须静态编译
root@lyl:/home/test# adb push s5pv210_leds.ko /data/local/
root@lyl:/home/test# adb push wdev /data/local/
root@lyl:/home/test# adb shell
/data/local # insmod s5pv210_leds.ko
/data/local # ./wdev 0 4369
/data/local # ./wdev 1 0 //led全点亮,说明linux驱动正常
二、编写HAL library
------leds_hal.c#include "leds_hal.h"
static int dev_file=0;
static int led_on(struct led_control_device_t*dev,int led)
{
unsigned int buf[2];
buf[0]=0;
buf[1]=4369;
write(dev_file,buf,sizeof(buf));
if(led>=0&&led<=3)
{
buf[0]=1;
switch(led)
{
case 0:
buf[1]=14;
LOGI("led 0 on");
break;
case 1:
LOGI("led 1 on");
buf[1]=13;
break;
case 2:
LOGI("led 2 on");
buf[1]=11;
break;
case 3:
LOGI("led 3 on");
buf[1]=7;
break;
}
write(dev_file,buf,sizeof(buf));
}
else
{
LOGI("LED Stub:set led %d on error,no this led",led);
}
return 0;
}
static int led_device_close(struct hw_device_t*device)
{
struct led_control_device_t*ctx=(struct led_control_device_t*)device;
if(ctx)
{
free(ctx);
}
close(dev_file);
return 0;
}
static int led_device_open(const struct hw_module_t*module,const char*name,struct hw_device_t**device)
{
struct led_control_device_t *dev=(struct led_control_device_t*)malloc(sizeof(*dev));
if(dev==NULL)
{
LOGI("malloc led_control_device_t fail");
return -1;
}
else
{
LOGI("malloc led_control_device_t success\n");
}
memset(dev,0,sizeof(*dev));
dev->hw_device.tag=HARDWARE_DEVICE_TAG; //值固定
dev->hw_device.version=0;
dev->hw_device.module=(struct hw_module_t*)module;
dev->hw_device.close=led_device_close;
dev->set_on=led_on;
*device=&dev->hw_device;
dev_file=open(DEVICE,O_RDWR);
if(dev_file<0)
{
LOGI("LED Stub:open /dev/lyl_leds_hal fail");
return -1;
}
else
{
LOGI("LED Stub:open /dev/lyl_leds_hal success.");
}
return 0;
}
static struct hw_module_methods_t led_module_methods=
{
open:led_device_open,
};
struct led_module_t HAL_MODULE_INFO_SYM=
{
hw_module:
{
tag:HARDWARE_MODULE_TAG, //值固定
version_major:1,
version_minor:0,
id:LED_HARDWARE_MODULE_ID, //通过该id找到HAL模块
name:"lyl_leds_hal",
author:"liyanlong",
methods:&led_module_methods,
},
};
------leds_hal.h
#include <hardware/hardware.h>
#include <fcntl.h>
#include <cutils/log.h>
struct led_module_t //不能直接使用hw_module_t结构体
{
struct hw_module_t hw_module; //必须为第一个成员
};
struct led_control_device_t
{
struct hw_device_t hw_device; //必须为第一个成员
int (*set_on)(struct led_control_device_t*dev,int led);
};
#define LED_HARDWARE_MODULE_ID "led_hal"
#define DEVICE "/dev/lyl_hal_leds"
------Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(PWD)/
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_SRC_FILES := leds_hal.c
LOCAL_MODULE := led_hal.default
#id必须为LED_HARDWARE_MODULE_ID
LOCAL_MODULE_TAGS := eng
include $(BUILD_SHARED_LIBRARY)
------编译
root@lyl:/test/android-4.0.3# . build/envsetup.sh
root@lyl:/test/android-4.0.3# lunch 1
root@lyl:/test/android-4.0.3/hardware/hal# ls
Android.mk leds_hal.c leds_hal.h
root@lyl:/test/android-4.0.3/hardware/hal# mm
root@lyl:/test/android-4.0.3/hardware/hal# adb push led_hal.default.so /system/lib/hw/
三、编写JNI library
------LedHalService.cpp#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <jni.h>
#include "leds_hal.h"
struct led_control_device_t *led_hal_device;
static jboolean led_setOn(JNIEnv*env,jobject thiz,jint led)
{
if(led_hal_device==NULL)
{
LOGI("led_hal_device was not fetched correctly.");
return -1;
}
else
{
return led_hal_device->set_on(led_hal_device,led);
}
}
static jboolean led_init(JNIEnv*env,jclass clazz)
{
led_module_t *module;
if(hw_get_module(LED_HARDWARE_MODULE_ID,(const struct hw_module_t **)&module)==0)
{
return module->hw_module.methods->open((const struct hw_module_t*)module,LED_HARDWARE_MODULE_ID,(struct hw_device_t**)&led_hal_device);
}
LOGI("Get stub operations failed.");
return -1;
}
static const JNINativeMethod methods[]= //函数映射
{
{"_init","()Z",(void*)led_init},
{"_set_on","(I)Z",(void*)led_setOn},
};
int register_led_hal_jni(JNIEnv*env)
{
static const char*const kClassName="lyl/leds/hal/LedHalService"; //由该类调用当前JNI库
jclass clazz;
clazz=env->FindClass(kClassName);
if(clazz==NULL)
{
LOGE("can not find class %s",kClassName);
return -1;
}
if(env->RegisterNatives(clazz,methods,sizeof(methods)/sizeof(methods[0]))!=JNI_OK)
{
LOGE("failed registering methods for %s",kClassName);
return -1;
}
return 0;
}
jint JNI_OnLoad (JavaVM*vm,void*reserved) //装载该库后自动调用JNI_OnLoad函数
{
JNIEnv*env=NULL;
jint result=-1;
if(vm->GetEnv((void**)&env,JNI_VERSION_1_4)!=JNI_OK)
{
LOGE("GetEnv failed!");
return result;
}
register_led_hal_jni(env);
return JNI_VERSION_1_4;
}
------Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(PWD)/
LOCAL_SHARED_LIBRARIES := libandroid_runtime libcutils libhardware libhardware_legacy \
libnativehelper libsystem_server libutils libui
LOCAL_C_INCLUDES += $(PWD)/
LOCAL_SRC_FILES := LedHalService.cpp
LOCAL_MODULE := jni
LOCAL_MODULE_TAGS := eng
include $(BUILD_SHARED_LIBRARY)
------编译
root@lyl:/test/android-4.0.3/hardware/jni# ls
Android.mk LedHalService.cpp leds_hal.h
root@lyl:/test/android-4.0.3/hardware/jni# mm
root@lyl:/test/android-4.0.3/hardware/jni# adb push jni.so /system/lib/
四、编写android APP
------LedServer.javapackage lyl.leds.hal;
import android.R.bool;
public class LedHalService {
private static LedHalService halService;
public static LedHalService getInstance(){
if(halService==null){
return new LedHalService();
}else{
return halService;
}
}
private LedHalService() {
_init();
}
public boolean setOn(int led){
return _set_on(led);
}
private native boolean _init();
private native boolean _set_on(int led);
static{
System.load("/system/lib/jni.so");
}
}
------MainActivity.java
package lyl.leds.hal;
import lyl.leds.service.R;
import android.app.Activity;
import android.os.Bundle;
import android.widget.RadioButton;
import android.widget.RadioGroup;
public class MainActivity extends Activity {
LedHalService halService=LedHalService.getInstance();
private RadioGroup ledGroup = null;
private RadioButton led0 = null;
private RadioButton led1 = null;
private RadioButton led2 = null;
private RadioButton led3 = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ledGroup=(RadioGroup)findViewById(R.id.led);
led0=(RadioButton)findViewById(R.id.led0);
led1=(RadioButton)findViewById(R.id.led1);
led2=(RadioButton)findViewById(R.id.led2);
led3=(RadioButton)findViewById(R.id.led3);
ledGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
if(led0.getId() == checkedId){
halService.setOn(0);
}
else if(led1.getId() == checkedId)
{
halService.setOn(1);
}
else if(led2.getId()==checkedId){
halService.setOn(2);
}
else if(led3.getId()==checkedId){
halService.setOn(3);
}
}
});
}
}
------activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<RadioGroup
android:id="@+id/led"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<RadioButton
android:id="@+id/led0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="led0"
/>
<RadioButton
android:id="@+id/led1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="led1"
/>
<RadioButton
android:id="@+id/led2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="led2"
/>
<RadioButton
android:id="@+id/led3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="led3"
/>
</RadioGroup>
</LinearLayout>
------测试
root@lyl:/home# adb push leds_hal.apk /mnt/sdcard/
/mnt/sdcard # adb install leds_hal.apk
/data/local # chmod 777 /dev/lyl_hal_leds
点击LCD屏单选按钮即可点亮相应LED