android驱动学习-led次设备号(2)

 跟上篇同例,只是测试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里编译,具体步骤看上篇博文。

你可能感兴趣的:(android 驱动 jni)