在Android下加载驱动并进行调用

来源:互联网 发布:手机新软件 编辑:程序博客网 时间:2024/06/14 19:29

Android下加载驱动和Linux下类似,不过需要使用JNI技术来调用c语言中的open、close、read和write等函数。这个实验中做了一个取数传数的驱动作为练习。把中间遇到的问题说明一下,为以后做一个备忘:

1、编译Linux头文件

    使用arm-linux-gcc交叉编译工具,对Linux源文件进行编译,如果不编译Linux源文件,在编译自己的模块的时候会产生头文件不存在的错误。编译完成Linux头文件后就可以编译自己的模块了

2、编写内核模块源文件

    按照Linux规范编写内核模块源文件,并编写makefile,使用的Makefile示例如下:
obj-m := chdev_test.oARCH = armKDIR := ${ARM_LINUX_ROOT}KERNELHEAD := ${ARM_LINUX_ROOT}/includeCORSS_COMPILE := arm-linux-all:$(MAKE) -C $(KDIR) -I $(KERNELHEAD) M=$(shell pwd) modulesclean:$(MAKE) -C $(KDIR) -I $(KERNELHEAD) M=$(shell pwd) clean




主要定义了输入源文件,内核目录、内核头文件目录和交叉编译器

按照Linux规范编写的源文件如下:
#include <linux/module.h>#include <linux/types.h>#include <linux/fs.h>#include <linux/errno.h>#include <linux/mm.h>#include <linux/init.h>#include <linux/cdev.h>#include <linux/slab.h>#include <asm/io.h>#include <asm/uaccess.h>static int g_testmodule_major = 0;struct testmodule_dev{struct cdev dev;char buf[100];};struct testmodule_dev* testmodule_devp;static ssize_t testmodule_read(struct file* filp, char __user* buf, size_t buf_size, loff_t* f_pos){int i = 0;struct testmodule_dev* dev = filp->private_data;copy_to_user(buf,dev->buf,100);return 100;}static ssize_t testmodule_write(struct file* filp, const char __user* buf, size_t buf_size, loff_t* f_pos){struct testmodule_dev* dev = filp->private_data;copy_from_user(dev->buf,buf,buf_size);return buf_size;}static int testmodule_open(struct inode* node, struct file* filp){struct testmodule_dev* dev = container_of(node->i_cdev,struct testmodule_dev, dev);filp->private_data = dev;return 0;}static long testmodule_ioctl(struct file* filp, unsigned int cmd, unsigned long arg){struct testmodule_dev* dev = filp->private_data;switch(cmd){case 0:memset(dev->buf,0,100);printk(KERN_INFO "buf set to zero!");break;case 1:memset(dev->buf,1,100);printk(KERN_INFO "buf set to 1!");break;default:break;}return 0;}static const struct file_operations testmodule_fops = {.owner = THIS_MODULE,.read = testmodule_read,.write = testmodule_write,.unlocked_ioctl = testmodule_ioctl,.open = testmodule_open};void updateDev(struct testmodule_dev* dev, int index){dev_t devno = MKDEV(g_testmodule_major, index);int error;cdev_init(&dev->dev, &testmodule_fops);dev->dev.owner = THIS_MODULE;error = cdev_add(&dev->dev, devno, 1);if(error)printk(KERN_NOTICE "Error %d adding testmodule %d", error, index);}int __init testmodule_init(void){dev_t device_no;/*Get Major Number*/alloc_chrdev_region(&device_no,0,1,"testmodule");g_testmodule_major = MAJOR(device_no);/*Generate device struct*/testmodule_devp = kmalloc(sizeof(struct testmodule_dev), GFP_KERNEL);if(!testmodule_devp){/*Generate Failed*/int result;result = -ENOMEM;unregister_chrdev_region(device_no, 0);return result; }memset(testmodule_devp,0,sizeof(struct testmodule_dev));/*Update device struct*/updateDev(testmodule_devp,MINOR(device_no));return 0;}void __exit testmodule_exit(void){cdev_del(&testmodule_devp->dev);kfree(testmodule_devp);unregister_chrdev_region(MKDEV(g_testmodule_major,0),1);}module_init(testmodule_init);module_exit(testmodule_exit);MODULE_LICENSE("Dual BSD/GPL");

在根目录下使用make命令就能够得到.ko文件了。

3、内核的加载

使用adb命令可以方便地加载内核,将内核.ko文件push到开发板中,使用insmod *.ko可以加载内核,通过lsmod查看内核是否加载成功,cat /proc/device 查看内核的主设备号,最后通过mknod /dev/device c 250 0 创建内核节点文件

4、Android中使用JNI调用内核函数

使用JNI编写c语言可以调用Linux标准输入输出文件,代码如下:
#include "nativeMethod.h"#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#define BYTE unsigned char/* * Class:     com_ruif_nativepackage_nativeMethod * Method:    OpenDevice * Signature: ()V */JNIEXPORT jint JNICALL Java_com_ruif_nativepackage_nativeMethod_OpenDevice  (JNIEnv *env, jclass jniclass){int fd = 0;fd = open("/dev/testmodule",O_RDWR);return fd;}/* * Class:     com_ruif_nativepackage_nativeMethod * Method:    ReadDevice * Signature: ()V */JNIEXPORT void JNICALL Java_com_ruif_nativepackage_nativeMethod_ReadDevice  (JNIEnv *env, jclass jniclass, jint fd, jbyteArray data, jint datalen){BYTE * olddata = (BYTE*)(*env)->GetByteArrayElements(env, data, 0);read(fd,olddata,datalen);}/* * Class:     com_ruif_nativepackage_nativeMethod * Method:    WriteDevice * Signature: ()V */JNIEXPORT void JNICALL Java_com_ruif_nativepackage_nativeMethod_WriteDevice  (JNIEnv *env, jclass jniclass, jint fd, jbyteArray data, jint datalen){BYTE *olddata = (BYTE*)(*env)->GetByteArrayElements(env, data, 0);write(fd,olddata,datalen);}/* * Class:     com_ruif_nativepackage_nativeMethod * Method:    IoctlDevice * Signature: ()V */JNIEXPORT void JNICALL Java_com_ruif_nativepackage_nativeMethod_IoctlDevice  (JNIEnv *env, jclass jinclass, jint fd, jint cmd){ioctl(fd,cmd);}/* * Class:     com_ruif_nativepackage_nativeMethod * Method:    CloseDevice * Signature: (I)V */JNIEXPORT void JNICALL Java_com_ruif_nativepackage_nativeMethod_CloseDevice  (JNIEnv *env, jclass jinclass, jint fd){close(fd);}

实现了一个很简单的功能,进行数据的拷贝。然后在Java中定义相应的native函数就能够调用内核驱动了~
原创粉丝点击