从内核LED驱动到APK应用实例(旧HAL架构 )

来源:互联网 发布:网络歌曲你是否爱过我 编辑:程序博客网 时间:2024/06/01 07:48

一、内核驱动

 myled/
├── Kconfig
├── Makefile
└── led.c

/*led.c*/#include <linux/init.h>#include <linux/module.h>#include <linux/fs.h>#include <linux/cdev.h>#include <linux/io.h>#include <linux/highmem.h>#include <linux/ioport.h>#include <linux/platform_device.h>#include <linux/miscdevice.h>#define GPMBASE 0x7f008000#define GPMCON (GPMBASE + 0x820)#define GPMDAT (GPMBASE + 0x824)#define LED_ON      1111#define LED_OFF     2222static void *gpio_virt;static struct resource *conf_res, *data_res;static int led_open(struct inode *inode, struct file *filp){    int ret = 0;    return ret;}static long led_ioctl(struct file *filp, unsigned int cmd, unsigned long args){    int ret = 0;    switch (cmd) {    case LED_ON:        iowrite32(ioread32(GPMCON) & ~0xffff, GPMCON);        iowrite32(ioread32(GPMCON) | 0x1111, GPMCON);        iowrite32(ioread32(GPMDAT) | ~0xF, GPMDAT);        break;    case LED_OFF:        iowrite32(ioread32(GPMCON) & ~0xffff, GPMCON);        iowrite32(ioread32(GPMCON) | 0x1111, GPMCON);        iowrite32(ioread32(GPMDAT) | 0xf, GPMDAT);        break;    }    return ret;}static int led_release(struct inode *inode, struct file *filp){    int ret = 0;    return ret;}struct file_operations ledops = {    .open       = led_open,    .unlocked_ioctl      = led_ioctl,    .release    = led_release,};struct miscdevice led_misc = {    .name = "led_misc",    .minor= 100,    .fops = &ledops,};static int led_probe(struct platform_device *dev){    int ret = -1;        conf_res = request_mem_region(GPMCON, 4, "myled_conf");    if (conf_res == NULL)     {        goto ERR0;    }    data_res = request_mem_region(GPMDAT, 4, "myled_dat");    if (data_res == NULL)    {        goto ERR1;    }       gpio_virt = ioremap(GPMBASE, SZ_4K);    if (gpio_virt == NULL)    {        goto ERR2;    }    ret = misc_register(&led_misc);    if (ret)    {        goto ERR3;    }    return ret;ERR3:    iounmap(gpio_virt);ERR2:    release_resource(data_res);ERR1:    release_resource(conf_res);ERR0:    return ret;}static int led_remove(struct platform_device *dev){    int ret = 0;    misc_deregister(&led_misc);    iounmap(gpio_virt);    return ret;}static void led_pdev_release(struct device *dev){}struct platform_device led_pdev = {    .name = "s3c6410_led",    .dev  = {        .release = led_pdev_release,    },};struct platform_driver led_pdrv = {    .probe  = led_probe,    .remove = led_remove,    .driver = {        .name = "s3c6410_led",    }};static int __init led_init(void){    int ret;    ret = platform_device_register(&led_pdev);    if (ret) {        goto ERR0;            }    ret = platform_driver_register(&led_pdrv);        if (ret) {        goto ERR1;    }    return ret;ERR1:    platform_device_unregister(&led_pdev);ERR0:    return ret;}static void __exit led_exit(void){    platform_device_unregister(&led_pdev);    platform_device_unregister(&led_pdev);}module_init(led_init);module_exit(led_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Micky Liu");

/*Makefile*/obj-$(CONFIG_MY_LED_TEST) = myled.o

/*Kconfig*/config MY_LED_TEST    tristate "MY_LED_TEST"    ---help---    It's my led test.

myled是放在android-kernel-*.*.*/drivers/目录下面的。

在drivers目录下Makefile中加入一行:

   obj-$(CONFIG_MY_LED_TEST)   += myled/
在drivers目录下的Kconfig中加入一行:    

   source "drivers/myled/Kconfig"

接着在内核根目录下make menuconfig,找到刚才的MY_LED_TEST选项,设置成*号,然后保存,make。OK,现在LED驱动已经编译进内核了。


2、编写JNI代码

jni
├── Android.mk
└── led.c

/*led.c*/#include <jni.h>#include <unistd.h>#include <fcntl.h>#include <sys/types.h>#include <errno.h>#define LOG_TAG "LED_JNI"#undef LOG#include <utils/Log.h>#define LED_ON  1111#define LED_OFF 2222static jboolean turn_led(int cmd){    int fd, ret = -1;    fd = open("/dev/led_misc", O_RDWR);    if (fd < 0)    {        goto ERR0;    }    ret = ioctl(fd, cmd);    close(fd);    if (ret)    {        LOGE("ioctl /dev/led_misc failed!");        goto ERR0;    }    return JNI_TRUE;ERR0:    return JNI_FALSE;}/* * Class:       com_lhw_framework_led_Led * Method:      turnOn * Signature:   ()Z */JNIEXPORT jboolean JNICALL com_lhw_led_Led_turnOn(JNIEnv *env, jobject thiz){    LOGD("LED ON!");    return turn_led(LED_ON);}/* * Class:       com_lhw_framework_led_Led * Method:      turnOff * Signature:   ()Z */JNIEXPORT jboolean JNICALL com_lhw_led_Led_turnOff(JNIEnv *env, jobject thiz){    LOGE("LED OFF!");    return turn_led(LED_OFF);}static JNINativeMethod gMethods[] = {    {"turnOn", "()Z", (void *)com_lhw_led_Led_turnOn},    {"turnOff", "()Z", (void *)com_lhw_led_Led_turnOff},};static int register_com_lhw_led_Led(JNIEnv *env) {    jclass clazz = (*env)->FindClass(env, "com/lhw/framework/led/Led");    return (*env)->RegisterNatives(env, clazz, gMethods,                 sizeof(gMethods) / sizeof(gMethods[0]));}jint JNI_OnLoad(JavaVM *vm, void *reserved){    JNIEnv *env = NULL;    jint result = -1;    if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_4) != JNI_OK) {        LOGE("ERROR: GetEnv failed!\n");        goto bail;    }    if (register_com_lhw_led_Led(env) < 0) {        LOGE("ERROR: LED_JNI native registration failed!\n");        goto bail;    }    result = JNI_VERSION_1_4;bail:        return result;}


/*Android.mk*/LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_SRC_FILES := led.cLOCAL_MODULE:= libled_jniLOCAL_MODULE_TAGS:= libled_jniLOCAL_PRELINK_MODULE:= falseLOCAL_C_INCLUDES:= $(JNI_H_INCLUDE)LOCAL_SHARED_LIBRARIES:= \libc \libutilsinclude $(BUILD_SHARED_LIBRARY)

接着使用在Android源码目录下使用mmm命令编译.

mmm /home/administrator/workspace/android_test/led/ljni

cp system/lib/libled_jni.so /nfsroot1/system/lib/


3、framework jar包

framework/
├── Android.mk
└── com
    └── lhw
        └── framework
            └── led
                └── Led.java


/*Led.java*/package com.lhw.framework.led;import android.util.Log;/* * Led 操作Jar库 * @author Micky Liu * @email sglazelhw@126.com */public class Led {        static {        System.loadLibrary("led_jni");    }    public native boolean turnOn();    public native boolean turnOff();       /*开灯*/    public boolean turnLedOn() {        return turnOn();    }    /*关灯*/    public boolean turnLedOff() {        return turnOff();    }}

/*Android.mk*/LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_SRC_FILES:= $(call all-subdir-java-files)LOCAL_MODULE:= ledLOCAL_MODULE_TAGS:= ledLOCAL_JAVA_LIBRARIES:=LOCAL_STATIC_JAVA_LIBRARIES :=include $(BUILD_JAVA_LIBRARY)

接着使用在Android源码目录下使用mmm命令编译.

mmm /home/administrator/workspace/android_test/led/framework

cp system/framework/led.jar /nfsroot1/system/framework/


4、APK应用

使用如下命令创建Android应用:

android create project -t 1 -k com.lhw.led_test -a MainActivity -p ./apk

led_apk
├── AndroidManifest.xml
├── Android.mk
├── bin
├── default.properties
├── libs
├── res
│   ├── drawable-hdpi
│   │   └── icon.png
│   ├── drawable-ldpi
│   │   └── icon.png
│   ├── drawable-mdpi
│   │   └── icon.png
│   ├── layout
│   │   └── main.xml
│   └── values
│       └── strings.xml
└── src
    └── com
        └── lhw
            └── led_test
                └── MainActivity.java

/*MainActivity.java*/package com.lhw.led_test;import android.app.Activity;import android.os.Bundle;import android.widget.Button;import android.widget.TextView;import android.view.View;import android.view.View.OnClickListener;import com.lhw.framework.led.Led;public class MainActivity extends Activity{    private Button btnOn;    private Button btnOff;    private TextView tvState;    private View.OnClickListener listener;    private Led led;    @Override    public void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        btnOn = (Button) findViewById(R.id.btn_on);        btnOff = (Button) findViewById(R.id.btn_off);        tvState = (TextView) findViewById(R.id.tv_state);        listener = new MyListener();        btnOn.setOnClickListener(listener);        btnOff.setOnClickListener(listener);                led = new Led();    }    class MyListener implements View.OnClickListener {        public void onClick(View v) {            switch(v.getId())            {            case R.id.btn_on:                if(led.turnLedOn()) {                    tvState.setText("LED ON");                 }                break;            case R.id.btn_off:                if(led.turnLedOff()) {                    tvState.setText("LED OFF");                }                break;            default:                break;            }        }    }}


<!-- main.xml --><?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    >    <TextView        android:id="@+id/tv_state"        android:layout_width="wrap_content"        android:layout_height="wrap_content" />    <Button        android:id="@+id/btn_on"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="@string/turn_on" />    <Button        android:id="@+id/btn_off"        android:layout_marginLeft="10dip"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="@string/turn_off" /></LinearLayout>

<!-- AndroidManifest --><?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"      package="com.lhw.led_test"      android:versionCode="1"      android:versionName="1.0">    <application android:label="@string/app_name" android:icon="@drawable/icon">        <uses-library android:name="led" />         <activity android:name=".MainActivity"                  android:label="@string/app_name">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>    </application></manifest>

/*Android.mk*/LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_SRC_FILES:= $(call all-subdir-java-files)LOCAL_PACKAGE_NAME:= led_testLOCAL_JAVA_LIBRARIES:= led LOCAL_STATIC_JAVA_LIBRARIES:=include $(BUILD_PACKAGE)


接着使用在Android源码目录下使用mmm命令编译.

mmm /home/administrator/workspace/android_test/led/led_apk

cp system/framework/led_apk.apk  /nfsroot1/system/app/


===================================================

到这,APK-->> framework  -->> JNI -->> Kernel Driver,整个过程都已完成。可以从Android应用里面控制LED等的亮和灭了。

在这个过程中,遇到很多问题,这里小记一下:

     一、在超级中端里不能执行system/bin下的一些命令,解决方法:

     修init.rc文件

      service console /system/bin/sh
          console
          disabled
          user  sh
          group log
     修改后设置:
     service console /system/bin/sh
        console
        disabled
        user root
        group log


     二、在JNI里打开/dev/下的设备文件报没权限错误,解决办法:

         方法一、进入高级终端,chmod 777 /dev/led_misc
         方法二、在init.rc中加入这么一行:chmod 777 /dev/led_misc


原创粉丝点击