跟上篇同例,只是测试LED次设备号。
内核版本:android-kernel-2.6.36
android版本:2.3.4
目的:应用上布局4个按键,分别点亮LED1~4.
------------------------------------------------------------
驱动:
#include <linux/module.h> /* For module specific items */ #include <linux/moduleparam.h> /* For new moduleparam's */ #include <linux/types.h> /* For standard types (like size_t) */ #include <linux/errno.h> /* For the -ENODEV/... values */ #include <linux/kernel.h> /* For printk/panic/... */ #include <linux/fs.h> /* For file operations */ #include <linux/ioport.h> /* For io-port access */ #include <linux/platform_device.h> /* For platform_driver framework */ #include <linux/init.h> /* For __init/__exit/... */ #include <linux/uaccess.h> /* For copy_to_user/put_user/... */ #include <linux/io.h> /* For inb/outb/... */ #include <linux/gpio.h> #include <linux/device.h> #include <linux/cdev.h> #include <linux/slab.h> /*kmalloc */ #define CMD_FLAG 'i' #define LED_ON _IOR(CMD_FLAG,0x00000000,__u32) #define LED_OFF _IOR(CMD_FLAG,0x00000001,__u32) //LED1 - LED4 //gpk4 - gpk7 static int major =0; static int minor =4; static struct class *led_class; struct cdev_led { struct cdev cdev; }; static struct cdev_led *led_dev; //ioctl static int led_ioctl (struct file* filp,unsigned int cmd,unsigned long argv) { printk(KERN_INFO "ioctl mode...\n"); int minor = iminor(filp->f_path.dentry->d_inode); printk(KERN_INFO "minor :%d\n",minor); switch(cmd) { case LED_ON: gpio_set_value(S3C64XX_GPK(minor+4),0); break; case LED_OFF: gpio_set_value(S3C64XX_GPK(minor+4),1); break; default: return -EINVAL; } return 0; } //open static int led_open(struct inode* i_node,struct file* filp) { printk(KERN_INFO "open mode...\n"); int err; int minor = iminor(i_node); printk(KERN_INFO "open minor : %d\n",minor); err = gpio_request(S3C64XX_GPK(minor+4),"myled"); if(err<0) { printk(KERN_INFO "gpio request faile\n"); return err; } gpio_direction_output(S3C64XX_GPK(minor+4),1); return 0; } //close static void led_close(struct inode* i_node,struct file* filp) { printk(KERN_INFO "close mode...\n"); int minor = iminor(i_node); gpio_free(S3C64XX_GPK(minor+4)); } // file operations static struct file_operations fops={ .owner = THIS_MODULE, .open = led_open, .unlocked_ioctl = led_ioctl, .release = led_close }; static void led_init_hw(struct cdev_led *dev,int minor) { dev_t dev_no=MKDEV(major,minor); //根据主设备号和次设备号,获取设备节点。 cdev_init( &dev->cdev,&fops); dev->cdev.owner = THIS_MODULE; int err = cdev_add(&dev->cdev,dev_no,1); //根据一个设备节点,加载一个设备。 if(err) printk(KERN_INFO "error , add cdev\n"); } static int __init led_init(void) { dev_t dev_no; int result; result = alloc_chrdev_region(&dev_no,0,minor,"myled"); //动态创建字符设备节点,有4个次设备号,就分配4个。 if(result < 0) { printk(KERN_INFO "alloc dev_no faile\n"); return result; } major = MAJOR(dev_no); led_dev = kmalloc(4*sizeof(struct cdev_led),GFP_KERNEL); if(!led_dev) { result =-ENOMEM; goto faile_malloc; } memset(led_dev,0,4*(sizeof(struct cdev_led))); int i ; for(i=0;i<minor;i++) { led_init_hw(&led_dev[i],i); //创建4个设备。 } led_class = class_create(THIS_MODULE,"myled"); for(i=0;i<minor;i++) { device_create(led_class,NULL,MKDEV(major,i),NULL,"myled%d",i); } return 0; faile_malloc: return result; } static void __exit led_exit(void) { dev_t dev_no = MKDEV(major,0); int i; for(i=0;i<minor;i++) cdev_del(&((led_dev+i)->cdev)); unregister_chrdev_region(dev_no,4); kfree(led_dev); device_destroy(led_class,dev_no); class_destroy(led_class); } module_init(led_init); module_exit(led_exit); MODULE_AUTHOR("koliy <[email protected]>"); MODULE_DESCRIPTION("ARM test led minor"); MODULE_LICENSE("GPL");
Makefile:
KERN_DIR = /android/linux-2.6.36-android all: make -C $(KERN_DIR) M=`pwd` modules clean: make -C $(KERN_DIR) M=`pwd` clean obj-m += android_led.o
================================================================
接下来布局好android的应用层按键,这里就简单贴上,主要是怎么调用JNI接口。
在这里说下,类名和JNI接口函数名称不要带'_'符号,因JNI会转换成' . ',造成java调用不到JNI接口。
package sz.ics.arm.test; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Toast; public class Minor extends Activity implements OnClickListener { private Button bt_led1_on,bt_led1_off; private Button bt_led2_on,bt_led2_off; private Button bt_led3_on,bt_led3_off; private Button bt_led4_on,bt_led4_off; private Button bt_led_exit; private static final int LED_ON = 0; private static final int LED_OFF = 1; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); findID(); setOnclick(); // Minor_ledActivity p = new Minor_ledActivity(); } private void findID() { bt_led1_on = (Button)findViewById(R.id.led1_on); bt_led1_off = (Button)findViewById(R.id.led1_off); bt_led2_on = (Button)findViewById(R.id.led2_on); bt_led2_off = (Button)findViewById(R.id.led2_off); bt_led3_on = (Button)findViewById(R.id.led3_on); bt_led3_off = (Button)findViewById(R.id.led3_off); bt_led4_on = (Button)findViewById(R.id.led4_on); bt_led4_off = (Button)findViewById(R.id.led4_off); bt_led_exit =(Button)findViewById(R.id.led_exit); } private void setOnclick() { bt_led1_on.setOnClickListener(this); bt_led1_off.setOnClickListener(this); bt_led2_on.setOnClickListener(this); bt_led2_off.setOnClickListener(this); bt_led3_on.setOnClickListener(this); bt_led3_off.setOnClickListener(this); bt_led4_on.setOnClickListener(this); bt_led4_off.setOnClickListener(this); bt_led_exit.setOnClickListener(this); } @Override public void onClick(View v) { // TODO Auto-generated method stub try{ switch(v.getId()){ case R.id.led1_on:{ Minor p =new Minor(); int err = p.ledopen("/dev/myled0"); if(err < 0) { setTitle("don't open."); finish(); } setTitle("open"); p.ledioctl(LED_ON); break; } case R.id.led1_off:{ Minor p =new Minor(); p.ledioctl(LED_OFF); p.ledclose("/dev/myled0"); break; } case R.id.led2_on:{ int err = this.ledopen("/dev/myled1"); if(err < 0) { Toast.makeText(this, "error! don't load lib", Toast.LENGTH_LONG); finish(); } this.ledioctl(LED_ON); break; } case R.id.led2_off:{ this.ledioctl(LED_OFF); this.ledclose("/dev/myled1"); break; } case R.id.led3_on:{ int err = this.ledopen("/dev/myled2"); if(err < 0) { Toast.makeText(this, "error! don't load lib", Toast.LENGTH_LONG); finish(); } this.ledioctl(LED_ON); break; } case R.id.led3_off:{ this.ledioctl(LED_OFF); this.ledclose("/dev/myled2"); break; } case R.id.led4_on:{ int err = this.ledopen("/dev/myled3"); if(err < 0) { Toast.makeText(this, "error! don't load lib", Toast.LENGTH_LONG); finish(); } this.ledioctl(LED_ON); break; } case R.id.led4_off:{ this.ledioctl(LED_OFF); this.ledclose("/dev/myled3"); break; } case R.id.led_exit:{ finish(); break; } default: { finish(); return ; } } }catch(Exception e) { e.printStackTrace(); } } /* * load lib */ static { try{ System.loadLibrary("led"); }catch(Exception e){ e.printStackTrace(); } } public native int ledopen(String dev); public native void ledclose(String dev); public native int ledioctl(int cmd); }
JNI:对JNI方法不了解的请到我的第一篇去下载JNI学习资料。
/* * Copyright 2009 Cedric Priscal * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <termios.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <errno.h> #include <unistd.h> #include <jni.h> #include <dirent.h> int fd =0; #define CMD_FLAG 'i' #define LED_ON _IOR(CMD_FLAG,0x00000000,__u32) #define LED_OFF _IOR(CMD_FLAG,0x00000001,__u32) #include "android/log.h" static const char *TAG="led-jni"; #define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, TAG, fmt, ##args) #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args) #define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args) /* * Class: minor_led * Method: led_open * Signature: ([java/lang/string)I */ JNIEXPORT jint JNICALL Java_sz_ics_arm_test_Minor_ledopen(JNIEnv*env,jobject obj,jstring dev) { LOGI("entry open---> "); char dev_name[128]; int len=(*env)->GetStringLength(env,dev); (*env)->GetStringUTFRegion(env,dev,0,len,dev_name); //不涉及内存操作 LOGI("%s\n",dev_name); dev_name[len]='\0'; fd = open(dev_name,O_RDWR); if(fd<0) { LOGI("Don't open %s\n",dev_name); return -1; } return 0; } /** Class minor_led * Method: led_close * Signature: ([java/lang/string)V */ JNIEXPORT void JNICALL Java_sz_ics_arm_test_Minor_ledclose(JNIEnv*env,jobject obj,jstring dev) { LOGI("entry close---> "); const char * dev_name; dev_name =(*env)->GetStringUTFChars(env,dev,NULL); //涉及内存操作,需另外malloc、strcpy之后,再操作返回值,耗时费力 if(dev_name == NULL){ LOGI("Don't get %s\n",dev_name); return; } LOGI(" get %s\n",dev_name); (*env)->ReleaseStringUTFChars(env,dev,dev_name); close(fd); } /** Class minor_led * Method: led_ioctl * Signature: (I)I */ JNIEXPORT jint JNICALL Java_sz_ics_arm_test_Minor_ledioctl(JNIEnv* env,jobject obj,jint cmd) { LOGI("entry ioctl---> "); if(cmd>0) ioctl(fd,LED_OFF,NULL); else ioctl(fd,LED_ON,NULL); return 0; }
上文提到,生成libxx.so通过NDK工具来生成,所以编写
Android.mk 文件
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) TARGET_PLATFORM := android-3 LOCAL_MODULE := led LOCAL_SRC_FILES := led.c LOCAL_LDLIBS := -llog include $(BUILD_SHARED_LIBRARY)
最后把应用工程包放进NDK里编译,具体步骤看上篇博文。