第一章:JNI的简单使用(5)-加载内核驱动

上一节我们介绍 了andriod软件层怎么调用C程序,以及C库的编译与加载,实现了应用层和底层连系的关键部分,接下来,把内核驱动部分编写完成,该章节就结束了,假定你已经看过之前的博文。

LED驱动加载

相信大家看到这里已经有了一定linux驱动的基础,简单驱动不做介绍,可另行查阅其他资料,创建C文件leds_drv.c,代码如下:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/ioport.h>
#include <linux/miscdevice.h>
#include <linux/ioctl.h>
#include <linux/delay.h>
#include <linux/gpio.h>

static const int led1_gpio = (32*0 + 8*1 + 4);
static const int led2_gpio = (32*0 + 8*1 + 0);

static int gec3399_leds_open(struct inode *inode, struct file *file)
{
	return 0;
}

static long gec3399_leds_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
	//printk("cmd = %u    arg = %lu\n",cmd,arg);
	switch(cmd)
	{
		case 0:	switch(arg)
				{
					case 0: gpio_set_value(led1_gpio,0); break;
					case 1:	gpio_set_value(led1_gpio,1); break;
				}break;
		
		case 1: switch(arg)
				{
					case 0: gpio_set_value(led2_gpio,0); break;
					case 1:	gpio_set_value(led2_gpio,1); break;			
				}break;
	}
	return 0;
}

static int gec3399_leds_release(struct inode *inode, struct file *file)
{
	return 0;
}

static const struct file_operations gec3399_leds_fops = {
	.owner = THIS_MODULE,
	.open = gec3399_leds_open,
	.unlocked_ioctl = gec3399_leds_ioctl,
	.release = gec3399_leds_release,
}; 

static struct miscdevice gec3399_leds_misc = {
	.minor = MISC_DYNAMIC_MINOR,
	.fops = &gec3399_leds_fops,
	.name   = "leds_drv",	
}; 

static int __init gec3399_leds_init(void)
{
    int ret;
	ret =  misc_register(&gec3399_leds_misc);   //注册字符设备
	if(ret < 0){
		printk("misc register error\n");
		goto err0;		
	}
	ret = gpio_request(led1_gpio,"led1_gpio");    //申请led1_gpio引脚为GPIO模式
	if(ret < 0){
		printk("gpio_request led1_gpio error\n");
		goto err1;
	}
	
	ret = gpio_request(led2_gpio,"led2_gpio");    //申请led2_gpio引脚为GPIO模式
	if(ret < 0){
		printk("gpio_request  led2_gpio error\n");
		goto err2;
	}
	
	ret = gpio_direction_output(led1_gpio,1);      //初始划LED1为熄灭状态
	if(ret < 0){
		printk("gpio direction output  led1_gpio error\n");
		goto err3;
	}

	ret = gpio_direction_output(led2_gpio,1);      //初始划LED2为熄灭状态
	if(ret < 0){
		printk("gpio direction output  led2_gpio error\n");
		goto err3;
	}

    return 0;
	
err3:
	gpio_free(led2_gpio);
err2:
	gpio_free(led1_gpio);
err1:
	misc_deregister(&gec3399_leds_misc);
err0:
    return ret;

}


static void __exit gec3399_leds_exit(void)
{
	misc_deregister(&gec3399_leds_misc);
}

module_init(gec3399_leds_init);
module_exit(gec3399_leds_exit);

MODULE_LICENSE("GPL");

编写完成之后,把该文件放在SDK/kernel/drivers/char/目录下,并且修改该目录下Makefile文件,添加:
obj-y+= led_drv.o
然后执行:
make ARCH=arm64 rk3399-sapphire-excavator-edp.img -j4
编译内核,编译完成之后,返回到SDK目录,执行:
source build/envsetup.sh
lunch rk3399_all-userdebug
make bootimage -j3
等待编译完成之后,可以看到打印信息:
Target boot image: out/target/product/rk3399/boot.img
把该boot.img烧写到开发板

C库修改

在上一小节中,向需虚拟机注册的C函数,只做了简单的打印信息,现在把hardcontrol.c代码补全如下:

#include <jni.h>  /* /usr/lib/jvm/java-1.8.0-openjdk-amd64/include/ */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>

#include <android/log.h>  /* liblog */
 
#if 0
typedef struct {
    char *name;          /* Java閲岃皟鐢ㄧ殑鍑芥暟鍚?*/
    char *signature;    /* JNI瀛楁鎻忚堪绗? 鐢ㄦ潵琛ㄧずJava閲岃皟鐢ㄧ殑鍑芥暟鐨勫弬鏁板拰杩斿洖鍊肩被鍨?*/
    void *fnPtr;          /* C璇█瀹炵幇鐨勬湰鍦板嚱鏁?*/
} JNINativeMethod;
#endif

static jint fd;

jint ledOpen(JNIEnv *env, jobject cls)
{
	fd = open("/dev/leds_drv", O_RDWR);
	__android_log_print(ANDROID_LOG_DEBUG, "LEDDemo", "native ledOpen : %d", fd);
	if (fd >= 0)
		return 0;
	else
		return -1;
}

void ledClose(JNIEnv *env, jobject cls)
{
	__android_log_print(ANDROID_LOG_DEBUG, "LEDDemo", "native ledClose : %d", fd);
	close(fd);
}

jint ledCtrl(JNIEnv *env, jobject cls, jint which, jint status)
{
	int ret = ioctl(fd, which, status);
	__android_log_print(ANDROID_LOG_DEBUG, "LEDDemo", "native ledCtrl : %d, %d, %d", which, status, ret);
	return ret;
}


static const JNINativeMethod methods[] = {
	{"ledOpen", "()I", (void *)ledOpen},
	{"ledClose", "()V", (void *)ledClose},
	{"ledCtrl", "(II)I", (void *)ledCtrl},
};




/* System.loadLibrary */
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *jvm, void *reserved)
{
	JNIEnv *env;
	jclass cls;

	if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4)) {
		return JNI_ERR; /* JNI version not supported */
	}
	cls = (*env)->FindClass(env, "com/example/administrator/hardlibrary/HardControl");
	if (cls == NULL) {
		return JNI_ERR;
	}

	/* 2. map java hello <-->c c_hello */
	if ((*env)->RegisterNatives(env, cls, methods, sizeof(methods)/sizeof(methods[0])) < 0)
		return JNI_ERR;

	return JNI_VERSION_1_4;
}

实验现象

编译hardcontrol.c文件生成动态C库,加载到我们的APP工程中(加载过程和位置可以参考前面的博文),运行APP之前,我们先查看开发板/dev/leds_drv是否存在,然后通过chmod命令赋予其权限777,然后执行APP程序,通过点击button和checkbox可以控制LED的状态

章节结语

该章节到此结束,从andriod源码的编译,到APP界面程序的设计,以及JNI的简单使用已经讲解完成。现在我们是通过JNI直接访问硬件的,这样是十分不安全的,比如,如果多个APP同时访问LED将导致实际现象和预计现象的不一样。在andriod系统中,存在专门管理硬件访问的服务框架,下一章节将对其进行解刨。

源码下载

[系统移植相关源码]
(https://github.com/944284742/android7.1Transplant.git)
[AndriodStudioAPP]
(https://github.com/944284742/andriod7.1APP.git)

猜你喜欢

转载自blog.csdn.net/weixin_43013761/article/details/86738892