本文主要是总结出应用层与内核驱动层的主要交互方式,并提供示例代码分析交互过程。但不涉及更细节的内核代码的分析。
应用层与内核驱动层交互的方式多种多样,这里只写出了我目前理解到的3种方式,至于其它等以后再做整理。

应用与驱动3种方式

所谓的应用与驱动层的交互主要是数据的传递,这里主要是使用内核提供给应用层的API接口,从而实现应用与驱动数据传递。应用层操作硬件设备也是通过内核层提供的API接口或文件设备提供的操作接口来实现调用驱动来操作硬件设备。

总结来是应用层与驱动层数据相互传递,或应用层通过驱动提供的方法来操作硬件从而来实现对硬件的操作。

  • 通过系统调用open(), read(), write()等方式实现对驱动层的交互,获取驱动层数据或调用方法操作硬件。
  • 通过IOCTL CMD命令方式与内核驱动层交互,从而获取驱动层数据或调用驱动层方法来操作硬件。
  • 通过mmap方式来实现应用层与内核共享内存来传递数据。这种方式优点是速度快,且可以数据大块的数据量。

不管理在应用层,还是在系统NFS层,或是在内核驱动层。他们之所以能访问到同驱动/设备提供的数据或方法。主是应该LINUX内核的设备文件描述符的作用。通过为每一个设备分配固定的主,次设备号从而绑定设备与驱动。并在驱动中把操作的接口暴露给系统或应该。这样不管是在应用打开的file类型指针,或是系统层打开的inode节点信息,或驱动中的设备类型中都包含某一个设备共同信息(主、次设备号, file operation操作方法)这些都是与设备绑定好的。无论在哪个层都是相同。所以在各层能通过不同的方式访问到相同的驱动或说操作同一设备。

系统调用的方式,通过设备文件描述符找到设备主次设备号,从而找到设备并调用设备的驱动方法及传递数据。

查看/dev目录下的某个设备文件获取的主、次设备号,由驱动向内核申请或定义固定数值

crw------- 1 root root 238, 0  1月  5 09:03 /dev/demo_dev

第二、三种方式主是通过驱动提供的file operation结构体实现,结构体具体项如下

struct file_operations {struct module *owner;loff_t(*llseek) (struct file *, loff_t, int);ssize_t(*read) (struct file *, char __user *, size_t, loff_t *);ssize_t(*aio_read) (struct kiocb *, char __user *, size_t, loff_t);ssize_t(*write) (struct file *, const char __user *, size_t, loff_t *);ssize_t(*aio_write) (struct kiocb *, const char __user *, size_t, loff_t);int (*readdir) (struct file *, void *, filldir_t);unsigned int (*poll) (struct file *, struct poll_table_struct *);int (*ioctl) (struct inode *, struct file *, unsigned int,unsigned long);int (*mmap) (struct file *, struct vm_area_struct *);int (*open) (struct inode *, struct file *);int (*flush) (struct file *);int (*release) (struct inode *, struct file *);int (*fsync) (struct file *, struct dentry *, int datasync);int (*aio_fsync) (struct kiocb *, int datasync);int (*fasync) (int, struct file *, int);int (*lock) (struct file *, int, struct file_lock *);ssize_t(*readv) (struct file *, const struct iovec *, unsigned long,loff_t *);ssize_t(*writev) (struct file *, const struct iovec *, unsigned long,loff_t *);ssize_t(*sendfile) (struct file *, loff_t *, size_t, read_actor_t,void __user *);ssize_t(*sendpage) (struct file *, struct page *, int, size_t,loff_t *, int);unsigned long (*get_unmapped_area) (struct file *, unsigned long,unsigned long, unsigned long,unsigned long);};

以后是第二种、第三种交互方式的接口

 ssize_t(*read) (struct file *, char __user *, size_t, loff_t *);ssize_t(*write) (struct file *, const char __user *, size_t, loff_t *); int (*mmap) (struct file *, struct vm_area_struct *);

直接上代码,这里IOCTL传递的数据是结构体

#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/i2c.h>
#include <linux/ioctl.h>
#include <linux/types.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/unistd.h>
#include <asm/ioctl.h>
#include <linux/ioctl.h>
#include <linux/mman.h>
#include <linux/fb.h>
#include <linux/mm.h>typedef struct mdata{int dev_major;short data;
} data_t;#define DEMO_NAME "demo_dev"
//定义命令及传递的数据
#define DEMO_OPEN   _IOW('d', 1, struct mdata)
#define DEMO_CLOSE  _IOW('d', 2, struct mdata)
#define DEMO_MMAP   _IOW('d', 3, struct mdata)struct demo_dev{int major;int minor;int data;void* private;char* name;struct device* dev;struct class* cls;
};static void* demo_mem;
struct demo_dev* ddev;static int demo_open(struct inode* inode, struct file* file)
{printk("<-KERNEL->-----Demo open-----");demo_mem = kzalloc(PAGE_SIZE, GFP_KERNEL);if(!demo_mem)return -ENOMEM;return 0;
}static ssize_t demo_write(struct file* file, const char __user* buf, size_t count, loff_t* ppos)
{struct mdata md;copy_from_user(&md, buf, sizeof(struct mdata));printk("<-KERNEL->----From user major:%d, data:%d-----", md.dev_major, md.data);return 0;
}static ssize_t demo_read(struct file* file, char __user* buf, size_t count, loff_t* ppos)
{struct mdata md = {.dev_major = 120,.data = 119,};copy_to_user(buf, &md, sizeof(struct mdata));printk("<-KERNEL->-----To user major:%d, data:%d -----", md.dev_major, md.data);return 0;
}static long int demo_device_ioctl(struct file* file, unsigned int cmd, unsigned long int arg)
{struct mdata mydata;struct mdata* dd;copy_from_user(&mydata, (struct mdata*)arg, sizeof(struct mdata));switch(cmd){case DEMO_OPEN:printk("<-KERNEL-> ioctl DEMO_OPEN from user major:%d, data:%d\n", mydata.dev_major, mydata.data); break;case DEMO_CLOSE:printk("<-KERNEL-> ioctl DEMO_CLOSE from user major:%d, data:%d\n", mydata.dev_major, mydata.data); break;case DEMO_MMAP:dd = (struct mdata*)demo_mem;printk("<-KERNEL-> ioctl DEMO_MMAP from user major:%d, data:%d\n", dd->dev_major, dd->data); break;default:break;}return 0;
}static int demo_mmap(struct file* filp, struct vm_area_struct* vma)
{if(remap_pfn_range(vma, vma->vm_start, virt_to_phys(demo_mem) >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot))return -EAGAIN;printk("<----------KERNEL mmap Ok------------>");return 0;
}static int demo_release(struct inode* inode, struct file* file)
{printk("-----demo release -----");return 0;
}static const struct file_operations ddev_fops = {.open = demo_open,.write = demo_write,.read = demo_read,.unlocked_ioctl = demo_device_ioctl,.release = demo_release,.mmap = demo_mmap,
};static int __init demo_init(void)
{printk("<-KERNEL-> Demo init ----\n");ddev = kzalloc(sizeof(*ddev), GFP_KERNEL);if(!ddev)return -ENOMEM;ddev->name = DEMO_NAME;ddev->major = register_chrdev(0, ddev->name, &ddev_fops);ddev->cls = class_create(THIS_MODULE, DEMO_NAME);if(IS_ERR(&ddev->cls)){pr_err("Demo: device class create failed\n");goto err_class_create;}ddev->dev = device_create(ddev->cls, NULL, MKDEV(ddev->major, 0), NULL, DEMO_NAME);if(IS_ERR(&ddev->dev)){pr_err("Demo: create device failed@@\n");goto err_device_create;}return 0;err_device_create:class_destroy(ddev->cls);
err_class_create:unregister_chrdev(ddev->major, DEMO_NAME);kfree(ddev);return -EFAULT;
}static void __exit demo_exit(void)
{printk("<-KERNEL-> Demo exit ----!@! \n");device_destroy(ddev->cls, MKDEV(ddev->major, 0));class_destroy(ddev->cls);unregister_chrdev(ddev->major, DEMO_NAME);kfree(ddev);
}module_init(demo_init);
module_exit(demo_exit);MODULE_AUTHOR("Jerry<jerry@xxx.com>");
MODULE_DESCRIPTION("Driver for Demo");
MODULE_LICENSE("GPL");

应用层测试代码,这里的ioctl命令其它可以通过包含同一个头件来共用,这样就不需要在程序中重新定义。因为是自己测试为了理解命令以方便测试,这里重新在代码里自己定义了命令及数据。

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>typedef struct mdata{int dev_major;short data;
} data_t;
// define ioctl cmd or include corresponding driver heard file.
#define DEMO_OPEN _IOW('d', 1, struct mdata)
#define DEMO_CLOSE _IOW('d', 2, struct mdata)
#define DEMO_MMAP  _IOW('d', 3, struct mdata)struct mdata* demo_map;int main(int argc, char** argv)
{int fd = -1, ret = -1;struct mdata mybuf;struct mdata mydata = {.dev_major = 1314,.data = 666,};fd = open("/dev/demo_dev", O_RDWR);if(fd < 0){printf("Open demo device failed\n");return -1;}puts("<----------------------- Read and Write @@@ ------------------------------>");printf("Write to KERNEL data--> major:%d, data:%d\n", mydata.dev_major, mydata.data);if( write(fd, &mydata, sizeof(struct mdata) < 0)){printf("Demo wirte data error!!!\n");return -1;}if( read(fd, &mybuf, sizeof(struct mdata) < 0 )){printf("Demo read data error\n");return -1;}printf("Read from KERNEL data--> major:%d, data:%d\n", mybuf.dev_major, mybuf.data);puts("<----------------------- IOCTL DEMO_OPEN View kernel Mesges @@@ ------------------------------>");ioctl(fd, DEMO_OPEN, &mydata);puts("<----------------------- IOCTL MMAP @@@ ------------------------------>");demo_map = (struct mdata*)mmap(NULL, sizeof(struct mdata), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);if(demo_map == NULL){printf("mmap memory failed@@!!");return -1;}demo_map->dev_major = 520;demo_map->data = 999;printf("MMAP Write to virtual memory data--> major:%d, data:%d\n", mydata.dev_major, mydata.data);ioctl(fd, DEMO_MMAP, &mydata);if(demo_map != NULL)munmap(demo_map, sizeof(struct mdata));close(fd);return 0;}

以上代码得到的执行结果

<----------------------- Read and Write @@@ ------------------------------>
Write to KERNEL data--> major:1314, data:666
# 传递给内核的数据 对应内核打印获取的数据[2] (数据正确)Read from KERNEL data--> major:120, data:119
# 从内核打印信息[3] 在应用层获取的数据 (数据正确)<----------------------- IOCTL DEMO_OPEN View kernel Mesges @@@ ------------------------------>
#对应内核打印的[4]信息 内核执行了ioctl DEMO_OPEN命令<----------------------- IOCTL MMAP @@@ ------------------------------>MMAP Write to virtual memory data--> major:1314, data:666
#应用写数据到映射的共享内存空间,在内核获取并转换成相应的数据格式并打印[6](数据正确)dmesg | tail -10 查看内核打印信息
[1] <-KERNEL->-----Demo open-----
[2] <-KERNEL->----From user major:1314, data:666-----
[3] <-KERNEL->-----To user major:120, data:119 -----
[4] <-KERNEL-> ioctl DEMO_OPEN from user major:1314, data:666
[5] <----------KERNEL mmap Ok------------>
[6] <-KERNEL-> ioctl DEMO_MMAP from user major:520, data:999

具体的各个知识点等有时候再一一总结。比如ioctl命令的执行过程,mmap相关等内容。

其它的注意下头文件的即可,可以通过man 2 来查找相关系统函数的使用说明及包含的头文件。

注意:在mmap函数映射的内存空间,第三个参数并不是简单的内存地址,需要把地址转换成物理地址,并把内存空间转换成相应系统的页个数。如果小于PAGE_SIZE进行page页对齐的时候,由于不够一个页内存空间。因为是页对齐,所以系统会默认申请一个页内存空间,超过一个则除以页获得需要的页的个数。

Linux应用层与内核驱动层3种交互方式相关推荐

  1. python echo和linux交互_Python与shell的3种交互方式介绍

    概述 考虑这样一个问题,有hello.py脚本,输出"hello, world!":有TestInput.py脚本,等待用户输入,然后打印用户输入的数据.那么,怎么样把hello. ...

  2. linux内核下网络驱动流程,基于Linux内核驱动的网络带宽测速方法与流程

    本发明涉及一种测速方法,尤其是一种网络带宽测速方法. 背景技术: :电信运营商为客户提供一定带宽的Internet接入:为了检验带宽是否达标,一般均由客户使用个人电脑在网页上直接测速.但是随着智能网关 ...

  3. 应用层与驱动层通信DeviceIoControl

    驱动层与应用层通信是通过DeviceIoControl, 符号定义 #define DEVICE_NAME L"\\Device\\myDriver" // Driver Name ...

  4. linux查看磁盘对应槽位,一种linux系统硬盘槽位识别方法与流程

    技术领域 本发明涉及计算机技术领域,尤具体地说是一种实用性强.linux系统硬盘槽位识别方法. 背景技术: 近年来,随着技术的迅速发展,linux系统的应用也越来越广泛,特别对于国产处理器,linux ...

  5. 天锐绿盾驱动层透明加密防泄密管理系统

    [文件透明加密模块] 文件透明加密模块是防止电子文件由于单位内部员工泄露而开发的内核驱动层加密系统.在不影响员工对电脑任何正常操作的前提下,文件在复制.新建.修改时被系统强制自动加密.加密的文件只能在 ...

  6. 嵌入式Linux应用层开发教程(一)基本概念

    1 应用层与驱动层 要想学习嵌入式Linux应用层的开发,首先要区分好应用层和驱动层之间的关系.我们在本科阶段学习51等较简单的单片机时,都是把应用层和驱动层混在一个文件里写的.比如拿下面的I2C程序 ...

  7. Ubuntu 19.04(Disco Dingo)将采用 Linux 5.0 内核

    开发四年只会写业务代码,分布式高并发都不会还做程序员?   Canonical 决定将即将发布 Ubuntu19.04(disco dingo)操作系统与新的内核系列(即最近发布的Linux5.0内核 ...

  8. 转载:linux驱动层到应用层的重要接口sys文件系统---/sys目录详解

    linux驱动层到应用层的重要接口sys文件系统---/sys目录详解 Linux2.6内核中引入了sysfs文件系统.sysfs文件系统整理的设备驱动的相关文件节点,被视为dev文件系统的替代者.同 ...

  9. Linux 网卡驱动学习(六)(应用层、tcp 层、ip 层、设备层和驱动层作用解析)

    本文将介绍网络连接建立的过程.收发包流程,以及其中应用层.tcp层.ip层.设备层和驱动层各层发挥的作用. 1.应用层 对于使用socket进行网络连接的服务器端程序,我们会先调用socket函数创建 ...

最新文章

  1. 【Groovy】自定义 Xml 生成器 BuilderSupport ( setParent 方法中设置父节点与子节点关系 )
  2. 【正一专栏】恒大中超七连冠到手了
  3. OpenCV超分辨率基准测试
  4. QT学习笔记(二):QT MinGW 和 MSVC 编译方式
  5. javascript中基本包装、算数运算符、递增递减运算符、赋值运算符、比较运算符、逻辑运算符、运算符优先级
  6. wpf esc key 检测不到_爬虫笔记之requests检测网站编码方式(zozo.jp)(碎碎念) - CC11001100...
  7. C++17 Any类
  8. python中md5方法返回值_python中的md5加密
  9. 用计算机处理表格信息,怎么制作表格-三线表丨做数据表格必须学会的处理技巧...
  10. windows10配置内外网IP切换bat脚本
  11. 设计师们必须要知道的素材网站
  12. python pppoe拨号_linux文本模式下使用PPPOE拨号ADSL上网的方法
  13. 多天线技术(MIMO)基础
  14. 语义分割标注工具Semantic Segmentation Editor 快速安装指南
  15. 拳皇重生服务器维护,《拳皇97 OL》3月10日更新维护公告
  16. Python开源Devops定时任务管理系统(含定时调用接口、定时ssh远程执行命令)
  17. 《青浦区加快发展跨境电子商务实施细则(审议稿)》
  18. C# 抽象类与接口异同
  19. MacBook Pro 13 A1502 更换电池
  20. 人心难测——远离垃圾人

热门文章

  1. 推荐3款在线编辑器(IDE)
  2. 小程序的营销推广拓客方式
  3. libfuse install error: fusermount.c:295:44: error: ‘CLONE_NEWNS’ undeclared (first use in this funct
  4. 男士成功面试着装指南
  5. 6.10数藏汇总|国家队入场数字藏品,成为风向标?
  6. 五个了解自己天赋优势的分析工具(四)MBTI测试
  7. 「分治法」棋盘覆盖问题
  8. mysql共同好友_Hadoop实例之寻找博客中共同好友
  9. 第128届广交会10月15-24日在网上举办
  10. 柔性电子: 石墨烯涂覆poly(dopamine)和还原石墨烯涂覆的Poly(vinyl alchol)复合材料的机械性能和用于压阻