安卓驱动开发和linux驱动开发是一摸一样的,只不过安卓驱动要被上层应用调用到与linux的方式不同
Android 应用调用驱动:
上层apk---->jni层--->驱动层 (这只是一个访问的路径示意图,中间还需要为SElinux和init.rc赋予给apk访问驱动权限问题)
一,驱动层:
1.在驱动路径下新建test目录和修改Makefile
cjx@ubuntu:~/work/linux$ mkdir drivers/test
cjx@ubuntu:~/work/linux$ vim drivers/Makefile
drivers/Makefile文件末尾添加
obj-y += test/
2.新建test.c文件和Makefile
cjx@ubuntu:~/work/linux$ cd drivers/test
cjx@ubuntu:~/work/linux/drivers/test$ vim test.c;vim Makefile
test.c内容如下
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/log2.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/reboot.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/input/sparse-keymap.h>
#include <linux/gpio_keys.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/wait.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
typedef struct _test_t {
timming_t timing;
unsigned long long pininfo;
RTK_GPIO_ID gid;
struct cdev cdev;
struct class *class;
}test_t;
static dev_t devno_base;
static
int test_open(struct inode *inode, struct file *file)
{
printk(KERN_ALERT "cjx open================================\n");
return 0;
}
static
int test_release(struct inode *inode, struct file *file)
{
return 0;
}
static
long test_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
printk(KERN_ALERT "cjx============================\n", cmd, arg);
return 0;
}
static struct file_operations test_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = test_ioctl,
.open = test_open,
.release = test_release,
};
static char *test_devnode(struct device *dev, mode_t *mode)
{
if(mode)
*mode = 0666;
return NULL;
}
static int __init test_module_init(void)
{
unsigned int result = 0;
int major_node = 0;
int minor_node = 0;
if (alloc_chrdev_region(&devno_base, 0, 1, "test") != 0)
return -EFAULT;
major_node = MAJOR(devno_base);
test_info.class = class_create(THIS_MODULE, "test-dev");
if (IS_ERR(test_info.class)) {
result = PTR_ERR(test_info.class);
goto err_create_class_failed;
}
test_info.class->devnode = test_devnode;
cdev_init(&test_info.cdev, &test_fops);
test_info.cdev.owner = THIS_MODULE;
test_info.cdev.ops = &test_fops;
cdev_add (&test_info.cdev, MKDEV(major_node, minor_node), 1);
device_create(test_info.class, NULL, MKDEV(major_node, minor_node), NULL, "test");
return 0;
err_create_class_failed:
unregister_chrdev_region(devno_base, 1);
return result;
}
static void __exit test_module_exit(void)
{
device_destroy(test_info.class, MKDEV(0, 0));
cdev_del(&test_info.cdev);
unregister_chrdev_region(devno_base, 1);
class_destroy(test_info.class);
}
MODULE_LICENSE("GPL");
module_init(test_module_init);
module_exit(test_module_exit);
Makefile:
obj-y += test.o
到这里驱动层已经添加完毕,编译烧录后会产生/dev/test文件
二:应用层和jni层:
在要调用的驱动的apk的代码下新建test.java
mkdir src/android/hikeen/
vim src/android/hikeen/test.java
/***test.java:***/
package android.hikeen;
public class test {
private static test mtest = null;
private static boolean isOpen = false;
static {
System.loadLibrary("test");
}
public native void inittest();
public native void test(int direction, int repeat, int time);
public native void move(int direction, int repeat, int time);
public native void closetest();
public native int istesting();
public static test getInstance(){
if (mtest == null) {
mtest = new test();
}
return mtest;
};
public void open(){
if (!isOpen) {
inittest();
}
isOpen = true;
};
public void close(){
if (isOpen) {
closetest();
}
isOpen = false;
};
}
cd src;
javah android.hikeen.test //在当前文件夹下就会产生android_hikeen_test.h文件,这个就是jni c++的头文件
一般写jni的位置在源码/external下
mkdir 源码/external/test/
将android_hikeen_test.h 移到 源码/external/test/
然后在源码/external/test/路径下新建Android.mk android_hikeen_test.cpp
/***android_hikeen_test.cpp***/
#include <jni.h>
#include <android/bitmap.h>
#include <stdio.h>
#include <stdlib.h>
#include <android/log.h>
#include <math.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <string.h>
#include <errno.h>
#include <linux/input.h>
#include <stdint.h>
#include <pthread.h>
#define SCROLL_UP 0
#define SCROLL_DOWN 1
#define SCROLL_LEFT 2
#define SCROLL_RIGHT 3
#include<android/log.h>
#define MOVE_UP 11
#define MOVE_DOWN 22
#include "android_hikeen_test.h"
#ifdef __cplusplus
extern "C" {
#endif
int fd;
#define TAG "myDemo-jni" // 这个是自定义的LOG的标识
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定义LOGD类型
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定义LOGI类型
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) // 定义LOGW类型
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) // 定义LOGE类型
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__) // 定义LOGF类型
JNIEXPORT void JNICALL Java_android_hikeen_test_inittest(JNIEnv *, jobject)
{
fd = open("/dev/test", O_RDWR);
if(fd < 0) {
LOGD("open test file error %d",fd);
}
}
JNIEXPORT void JNICALL Java_android_hikeen_test_test(JNIEnv *, jobject , jint direction, jint repeat, jint time)
{
int i=direction+repeat+time,ret;
LOGD(" test test i= %d",i);
ret=ioctl(fd,1);
if(ret<0){
LOGD("ioctl test file error %d",ret);
}
return ;
}
JNIEXPORT void JNICALL Java_android_hikeen_test_move(JNIEnv *, jobject , jint direction, jint repeat, jint time)
{
int i=direction+repeat+time,ret=0;
LOGD(" test test i= %d",i);
ret=ioctl(fd,1);
if(ret<0){
LOGD(" move test file error %d",ret);
}
return ;
}
JNIEXPORT void JNICALL Java_android_hikeen_test_closetest(JNIEnv *, jobject)
{
close(fd);
LOGD(" close test file error");
}
JNIEXPORT jint JNICALL Java_android_hikeen_test_istesting(JNIEnv *, jobject)
{
return 0;
}
#ifdef __cplusplus
}
#endif
/***Android.mk***/
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libtest
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code -Wunused-parameter
LOCAL_SRC_FILES := android_hikeen_test.cpp
LOCAL_MODULE_TAGS := eng debug
LOCAL_LDLIBS := -ljnigraphics
LOCAL_LDLIBS += -llog
include $(BUILD_SHARED_LIBRARY)
编译烧录完成后在板子上的system/lib/下就有libtest.so这个文件,这个就是test 的jni库
到现在还未完成,因为还需要赋权限和SELinux的权限才能正常调用