2019独角兽企业重金招聘Python工程师标准>>>

前言:
android module编译环境搭建及简单设备驱动编写,最后写一个测试POC与驱动通信

一、编译环境搭建

  1. android编译好的内核源码(主要是Kernel相关的头文件)
  2. android NDK编译环境(>4.8)

二、例子

2.1 android驱动程序编写

在Linux机器上新建个目录,添加hello.h、hello.c、Makefile。

hello.h

#ifndef _HELLO_ANDROID_H_
#define _HELLO_ANDROID_H_  #include <linux/cdev.h>
#include <linux/semaphore.h>#define HELLO_DEVICE_NODE_NAME  "hello"
#define HELLO_DEVICE_FILE_NAME  "hello"
#define HELLO_DEVICE_PROC_NAME  "hello"
#define HELLO_DEVICE_CLASS_NAME "hello"  struct hello_android_dev {int val;struct semaphore sem;struct cdev dev;
};#endif

hello.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/device.h>
#include <asm/uaccess.h>#include "hello.h"//模数
#define MEMDEV_IOC_MAGIC  'k'//命令ID
#define MEMDEV_IOCPRINT   _IO(MEMDEV_IOC_MAGIC, 1)    //IO
#define MEMDEV_IOCGETDATA _IOR(MEMDEV_IOC_MAGIC, 2, int)  //读
#define MEMDEV_IOCSETDATA _IOW(MEMDEV_IOC_MAGIC, 3, int)  //写//命令总数
#define MEMDEV_IOC_MAXNR 3//设备版本
static int hello_major = 0;
static int hello_minor = 0;static struct class* hello_class = NULL;
static struct hello_android_dev* hello_dev = NULL;//打开设备的函数
static int hello_open(struct inode* inode, struct file* filp);
//释放设备的函数
static int hello_release(struct inode* inode, struct file* filp);
//直接读设备的函数
static ssize_t hello_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos);
//直接写设备的函数
static ssize_t hello_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos);
//ioctl控制函数
static long hello_ioctl (struct file *filp, unsigned int cmd, unsigned long arg);//设备操作选项(各种函数指针)
static struct file_operations hello_fops = {.owner = THIS_MODULE,.open = hello_open,.release = hello_release,.read = hello_read,.write = hello_write,.unlocked_ioctl = hello_ioctl
};//设备信息展示
static ssize_t hello_val_show(struct device* dev, struct device_attribute* attr,  char* buf);
//设备信息存储
static ssize_t hello_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count);//设备属性
static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, hello_val_show, hello_val_store);

ioctl控制

static long hello_ioctl (struct file *filp, unsigned int cmd, unsigned long arg) {int err = 0;int ret = 0;int ioarg = 0;//判断命令是否合法if (_IOC_NR(cmd) > MEMDEV_IOC_MAXNR)return -EINVAL;//判断地址是否有权限读写if (_IOC_DIR(cmd) & _IOC_READ)err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));else if (_IOC_DIR(cmd) & _IOC_WRITE)err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));if (err)return -EFAULT;switch(cmd) {//打印命令case MEMDEV_IOCPRINT:printk("<--- CMD MEMDEV_IOCPRINT Done--->\n\n");break;//获取数据处理case MEMDEV_IOCGETDATA:ioarg = 1101;ret = __put_user(ioarg, (int *)arg);break;//写数据处理case MEMDEV_IOCSETDATA:ret = __get_user(ioarg, (int *)arg);printk("<--- In Kernel MEMDEV_IOCSETDATA ioarg = %d --->\n\n",ioarg);break;default:return -EINVAL;}return ret;
}

其它操作函数

//打开设备,将设备信息保存
static int hello_open(struct inode* inode, struct file* filp) {struct hello_android_dev* dev;dev = container_of(inode->i_cdev, struct hello_android_dev, dev);filp->private_data = dev;return 0;
}//释放没处理
static int hello_release(struct inode* inode, struct file* filp) {return 0;
}//读取设备中数据 file->private_data为dev设备数据
static ssize_t hello_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos) {ssize_t err = 0;struct hello_android_dev* dev = filp->private_data;if(down_interruptible(&(dev->sem))) {return -ERESTARTSYS;}if(count < sizeof(dev->val)) {goto out;}if(copy_to_user(buf, &(dev->val), sizeof(dev->val))) {err = -EFAULT;goto out;}err = sizeof(dev->val);out:up(&(dev->sem));return err;
}//写设备中数据 file-.private_data为dev设备数据
static ssize_t hello_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos) {struct hello_android_dev* dev = filp->private_data;ssize_t err = 0;if(down_interruptible(&(dev->sem))) {return -ERESTARTSYS;}if(count != sizeof(dev->val)) {goto out;}if(copy_from_user(&(dev->val), buf, count)) {err = -EFAULT;goto out;}err = sizeof(dev->val);out:up(&(dev->sem));return err;
}

val读写相关

static ssize_t __hello_get_val(struct hello_android_dev* dev, char* buf) {int val = 0;if(down_interruptible(&(dev->sem))) {return -ERESTARTSYS;}val = dev->val;up(&(dev->sem));return snprintf(buf, PAGE_SIZE, "%d\n", val);
}err = sizeof(dev->val);out:up(&(dev->sem));return err;
}static ssize_t __hello_get_val(struct hello_android_dev* dev, char* buf) {int val = 0;if(down_interruptible(&(dev->sem))) {return -ERESTARTSYS;}val = dev->val;up(&(dev->sem));return snprintf(buf, PAGE_SIZE, "%d\n", val);
}static ssize_t __hello_set_val(struct hello_android_dev* dev, const char* buf, size_t count) {int val = 0;val = simple_strtol(buf, NULL, 10);if(down_interruptible(&(dev->sem))) {return -ERESTARTSYS;}dev->val = val;up(&(dev->sem));return count;
}static ssize_t hello_val_show(struct device* dev, struct device_attribute* attr, char* buf) {struct hello_android_dev* hdev = (struct hello_android_dev*)dev_get_drvdata(dev);return __hello_get_val(hdev, buf);
}static ssize_t hello_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count) {struct hello_android_dev* hdev = (struct hello_android_dev*)dev_get_drvdata(dev);return __hello_set_val(hdev, buf, count);
}

设备安装函数

static int  __hello_setup_dev(struct hello_android_dev* dev) {int err;dev_t devno = MKDEV(hello_major, hello_minor);memset(dev, 0, sizeof(struct hello_android_dev));cdev_init(&(dev->dev), &hello_fops);dev->dev.owner = THIS_MODULE;dev->dev.ops = &hello_fops;err = cdev_add(&(dev->dev),devno, 1);if(err) {return err;}//init_MUTEX(&(dev->sem));sema_init(&(dev->sem), 1);dev->val = 0;return 0;
}static int __init hello_init(void){int err = -1;dev_t dev = 0;struct device* temp = NULL;printk(KERN_ALERT"Initializing hello device.\n");err = alloc_chrdev_region(&dev, 0, 1, HELLO_DEVICE_NODE_NAME);if(err < 0) {printk(KERN_ALERT"Failed to alloc char dev region.\n");goto fail;}hello_major = MAJOR(dev);hello_minor = MINOR(dev);hello_dev = kmalloc(sizeof(struct hello_android_dev), GFP_KERNEL);if(!hello_dev) {err = -ENOMEM;printk(KERN_ALERT"Failed to alloc hello_dev.\n");goto unregister;}err = __hello_setup_dev(hello_dev);if(err) {printk(KERN_ALERT"Failed to setup dev: %d.\n", err);goto cleanup;}hello_class = class_create(THIS_MODULE, HELLO_DEVICE_CLASS_NAME);if(IS_ERR(hello_class)) {err = PTR_ERR(hello_class);printk(KERN_ALERT"Failed to create hello class.\n");goto destroy_cdev;}temp = device_create(hello_class, NULL, dev, "%s", HELLO_DEVICE_FILE_NAME);if(IS_ERR(temp)) {err = PTR_ERR(temp);printk(KERN_ALERT"Failed to create hello device.");goto destroy_class;}err = device_create_file(temp, &dev_attr_val);if(err < 0) {printk(KERN_ALERT"Failed to create attribute val.");goto destroy_device;}dev_set_drvdata(temp, hello_dev);printk(KERN_ALERT"Succedded to initialize hello device.\n");return 0;destroy_device:device_destroy(hello_class, dev);destroy_class:class_destroy(hello_class);destroy_cdev:cdev_del(&(hello_dev->dev));cleanup:kfree(hello_dev);unregister:unregister_chrdev_region(MKDEV(hello_major, hello_minor), 1);fail:return err;
}static void __exit hello_exit(void) {dev_t devno = MKDEV(hello_major, hello_minor);printk(KERN_ALERT"Destroy hello device.\n");hello_remove_proc();if(hello_class) {device_destroy(hello_class, MKDEV(hello_major, hello_minor));class_destroy(hello_class);}if(hello_dev) {cdev_del(&(hello_dev->dev));kfree(hello_dev);}unregister_chrdev_region(devno, 1);
}MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("First Android Driver");module_init(hello_init);
module_exit(hello_exit);

Makefile

obj-m := hello.oKERNELDIR := /media/sda5/android/kernel/msm/msm/
PWD :=$(shell pwd)
ARCH=arm
CROSS_COMPILE=/media/android/kernel/arm-eabi-4.8/bin/arm-eabi-
CC=$(CROSS_COMPILE)gcc
LD=$(CROSS_COMPILE)ld
#No-pic否则报segment error
CFLAGS_MODULE=-fno-picmodules:  make -C $(KERNELDIR) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) M=$(PWD) modulesclean:rm *.o *.ko *.mod.c *.order *.symvers

切换到程序根目录,然后编译即可生成ko模块文件,如下:

$ make
make -C /media/sda5/android/kernel/msm/msm/   ARCH=arm   CROSS_COMPILE=/media/sda5/android/kernel/arm-eabi-4.8/bin/arm-eabi- M=/media/jowto/sda5/android/kernel/module   modules
make[1]: Entering directory '/media/sda5/android/kernel/msm/msm'CC [M]  /media/sda5/android/kernel/module/hello.oBuilding modules, stage 2.MODPOST 1 modulesCC      /media/sda5/android/kernel/module/hello.mod.oLD [M]  /media/sda5/android/kernel/module/hello.ko
make[1]: Leaving directory `/media/sda5/android/kernel/msm/msm'#### make completed successfully (1 seconds) ####

将编译完的hello.ko传到手机设备上,加载模块如下:

#切换到root用户
$ su#安装模块
$ insmod /data/local/tmp/hello.ko#当前模块列表
$ lsmod
Module                  Size  Used by
hello                   4064  0#查看日志
$ dmesg |grep hello
[ 8889.108997] Destroy hello device.
[ 8903.052067] Initializing hello device.
[ 8903.053140] Succedded to initialize hello device.

2.2 android测试程序与驱动通信

test_conn.c

#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <asm/ioctl.h>/* 定义幻数 */
#define MEMDEV_IOC_MAGIC  'k'/* 定义命令 */
#define MEMDEV_IOCPRINT   _IO(MEMDEV_IOC_MAGIC, 1)
#define MEMDEV_IOCGETDATA _IOR(MEMDEV_IOC_MAGIC, 2, int)
#define MEMDEV_IOCSETDATA _IOW(MEMDEV_IOC_MAGIC, 3, int)
void read_ioctl(int fd)
{int ret;int cmd;int read_i;cmd = MEMDEV_IOCGETDATA;ret = ioctl(fd, cmd, &read_i);if (ret < 0) {printf("read ioctl fail %s\n",strerror(errno));} else{printf("config %d %d \n", read_i);}
}int main(int argc, char *argv[])
{char* path = "/dev/hello";int fd;fd = open(path, O_RDWR);if(fd<0) {printf("open fail %s\n",strerror(errno));return -1;}printf("open %s succ\n",path);//直接IOioctl(fd, MEMDEV_IOCPRINT);int xx = 999;//向驱动设备写ioctl(fd, MEMDEV_IOCSETDATA, &xx);//读取设备read_ioctl(fd);close(fd);return 0;
}

编译成可执行文件test_conn后放入手机进行测试,如下:

# ./test_conn
open /dev/hello succ
config 1101查看日志
# dmesg |grep MEMDEV
[ 9166.054062] <--- CMD MEMDEV_IOCPRINT Done--->
[ 9166.054173] <--- In Kernel MEMDEV_IOCSETDATA ioarg = 999 --->

转载于:https://my.oschina.net/u/2424583/blog/775025

android module驱动编程及通信相关推荐

  1. 免费分享:5本安卓开发经典书籍,Android 7编程入门经典(第4版),Android底层驱动分析和移植,底层驱动分析和移植

    1.Android 7编程入门经典(第4版) 使用Android Studio 2  PDF 下载 下载地址: http://www.askwinds.com/r-c/down-info-02/579 ...

  2. 实现Android底层驱动开发并裁剪定制Android操作系统

    毕业论文 题   目实现Android底层驱动开发并裁剪定制Android操作系统 学   院电子信息与电气工程学院 姓   名牛xxx民 专   业电子信息科学与技术 学   号2012xxxxxx ...

  3. 数据即代码:元驱动编程

    几个小伙伴在考虑下面这个各个语言都会遇到的问题: 问题:设计一个命令行参数解析API 一个好的命令行参数解析库一般涉及到这几个常见的方面: 1) 支持方便地生成帮助信息 2) 支持子命令,比如:git ...

  4. Android USB转串口编程

    安卓手机的对外通信接口就只有USB跟音频口,我们可采用其进行与外设进行通信.今天,我们来讲讲安卓手机利用USB接口与外设进行通信.此时,有两种情况. 第一:USB(手机)<--->USB( ...

  5. Linux驱动编程 step-by-step

    第三次看了LDD3了(虽然现在已经是kernel3.0但从这本书商还是能学到很多) 每次都有一些收获 现在终于能够写一写代码了 驱动程序的作用: 简单来说 驱动程序就是使计算机与设备通信的特殊的代码, ...

  6. 什么是Android - 嵌入式设备编程的历史

    -第一章 暂时可以这样说,传统的桌面 应用程序 开发者已经被惯坏了.这个不是说桌面应用程序开发比其他开发很简单.总之作为桌面应用程序开发者,我们已经有能力按照我们的想法创造出各种应用程序.包括我自己, ...

  7. Android USB驱动源码分析(-)

    Android USB驱动中,上层应用协议里最重要的一个文件是android/kernel/drivers/usb/gadget/android.c.这个文件实现USB的上层应用协议. 首先包含了一些 ...

  8. Android USB驱动源码分析

    Android USB驱动中,上层应用协议里最重要的一个文件是android/kernel/drivers/usb/gadget/android.c.这个文件实现USB的上层应用协议. 首先包含了一些 ...

  9. 嵌入式linux驱动开发之点亮led(驱动编程思想之初体验)

    这节我们就开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的 ...

  10. linux内核_Linux驱动编程的本质就是Linux内核编程

    由于Linux驱动编程的本质属于Linux内核编程,因此我们非常有必要熟悉Linux内核以及Linux内核的特点. 这篇文章将会帮助读者打下Linux驱动编程的基础知识. 本篇文章分为如下三个小节进行 ...

最新文章

  1. LinkedList 实现 Queue
  2. python函数可选参数传递_Python中函数的参数传递
  3. 5 怎么上下分屏_oppo的最新手机reno5系列怎么样
  4. 前端学习(1929)vue之电商管理系统电商系统之美化一层循环的UI结构for循环ui美化点击删除按钮弹出对话框
  5. 【转】CT中的“层“与“排“的区别
  6. 大括号之谜:C++的列表初始化语法解析
  7. vue点击其它侧边栏收缩_企业微信聊天侧边栏功能怎么开启?聊天侧边栏有什么用?...
  8. 原生 遍历_迭代器模式统一集合的遍历方式
  9. urb传输的代码分析【转】
  10. ERROR 1442 (HY000):because it is already used by statement which invoked this stored function/tr
  11. 【java】字符串和基本数据类型之间的转换
  12. zabbix监控Linux系统服务
  13. Windows自动关机设置
  14. java的dataset怎么用_ADO DataSet用法
  15. Python多进程 struct.error: ‘i‘ format
  16. 电脑删除快捷键还有哪些?学会了让工作效率更提升
  17. 文本挖掘 包含中英文数据预处理以及分析
  18. Spire.XLS for Java 12.11.8 Crack
  19. 基于HAL库创建Keil工程模板
  20. [4G/5G/6G专题基础-160]: BLER与MCS的关系、MCS表格的选择

热门文章

  1. atitit.流程标准化--- mysql启动不起来的排查流程attilax总结
  2. paip.提升用户体验与安全性----cookie盗用检测
  3. paip.程序模块间的通讯方式大总结
  4. paip.提升用户体验----记住用户名与自动登录
  5. 达摩院发布AI Earth地球科学云平台
  6. eBPF技术应用云原生网络实践:kubernetes网络 | 凌云时刻
  7. Alex Chen:3月21日阿里云北京峰会演讲大神
  8. 分享 | 内核文件系统XFS的一些最新进展
  9. 【数据预测】基于matlab斑点鬣狗算法优化BP神经网络数据预测【含Matlab 219期】
  10. 【优化算法】混沌单纯形法算子布谷鸟搜索优化算法【含Matlab源码 1193期】