转:内核空间与用户空间数据交换的方式之一 --ioctl(通过字符设备演示)
对于linux而言,内核程序和用户程序分别运行在内核空间和用户空间,要实现两者的数据交换,主要有以下几种方式:系统调用,读写系统文件(procfs,sysfs, seq_file,debugfs等), Netlink, 内核模块加载参数,内核启动参数,以及设备驱动实现的设备读、写、控制(ioctl)(这种方式可以归结到读写系统文件)。
设备驱动的实现过程中一般都会通过struct file_operations来实现对设备文件读、写以及控制命令。下面就仅通过ioctl的实现来说明通过字符设备,如何实现内核空间与用户空间的数据交换的。本例分为两个部分,内核代码为ict_k.c和ict_k.h,用户代码为ict_u.c
下面为内核部分代码:
1.ict_k.h
- #ifndef __ICT_K_H__
- #define __ICT_K_H__
- #define MAX_BUFFER_SIZE 64
- #define ICTDEV_MAJOR 250
- #define ICT_IOCTL_MAGIC_NUM 'K'
- #define ICTIOC_GETDEV_INFO _IOR(ICT_IOCTL_MAGIC_NUM, 0, int)
- #define ICTIOC_SETDEV_INFO _IOWR(ICT_IOCTL_MAGIC_NUM, 1, int)
- #endif
2.ict_k.c
- /********************************************************************************
- *FileName :ict_k.c
- *
- *Description :This program is the kernel part which is used to illustrate the usage of ioctl.
- *
- *Author :Michael Zhang <zhang_mq@sina.com>
- *
- *Version :V0.1 2013-09-02
- *********************************************************************************/
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/cdev.h>
- #include <linux/types.h>
- #include <asm/uaccess.h>
- #include <linux/fs.h> /*struct file*/
- #include <linux/slab.h> /*kfree*/
- #include "ict_k.h"
- struct ict_dev
- {
- struct cdev cdev;
- char buffer[MAX_BUFFER_SIZE];
- };
- static int mod_param = 0;
- static int ictdev_major = ICTDEV_MAJOR;
- static struct ict_dev *ict_devp;
- static int devinfo = 0;
- /*Device open function*/
- static int ictdev_open(struct inode *inode, struct file *filp)
- {
- printk(KERN_INFO"Ict device has been open.\n");
- return 0;
- }
- /*ioctl: device control function*/
- //static long ictdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
- static long ictdev_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
- {
- int ret = 0;
- int tmp;
- void __user *argp = (void __user *)arg;
- switch(cmd)
- {
- case ICTIOC_GETDEV_INFO:
- put_user(devinfo, (int *)arg);
- break;
- case ICTIOC_SETDEV_INFO:
- get_user(tmp, (int __user *)argp);
- devinfo = tmp;
- printk(KERN_INFO"Set devinfo as: %d\n", devinfo);
- break;
- default:
- break;
- }
- return ret;
- }
- static int ictdev_release(struct inode *inode, struct file *filp)
- {
- printk(KERN_INFO"Ict device will be closed.\n");
- return 0;
- }
- struct file_operations ictdev_fops =
- {
- .owner = THIS_MODULE,
- .open = ictdev_open,
- .ioctl = ictdev_ioctl,
- //.unlock_ioct = ictdev_ioctl,
- .release = ictdev_release,
- };
- static void ict_dev_setup(dev_t devno, struct ict_dev *dev)
- {
- int ret;
- cdev_init(&dev->cdev, &ictdev_fops);
- dev->cdev.owner = THIS_MODULE;
- ret = cdev_add(&dev->cdev, devno, 1);
- if(ret)
- {
- printk(KERN_ERR"Add cdev fail.\n");
- }
- return;
- }
- /*Ict module intilization*/
- static int __init ict_ill_init(void)
- {
- int result;
- dev_t devno;
- devno = MKDEV(ictdev_major, 0);
- if(ictdev_major)
- {
- result = register_chrdev_region(devno, 1, "ictdev");
- }
- else
- {
- result = alloc_chrdev_region(&devno, 0, 1, "ictdev");
- ictdev_major = MAJOR(devno);
- }
- printk(KERN_INFO"ictdev_major is %d\n", ictdev_major);
- if(result < 0)
- {
- printk("Register/Allocate device number fail.\n");
- return result;
- }
- ict_devp = kmalloc(sizeof(struct ict_dev), GFP_KERNEL);
- if(!ict_devp)
- {
- printk("Memory allocation fail.\n");
- result = -ENOMEM;
- goto fail_malloc;
- }
- memset(ict_devp, 0, sizeof(struct ict_dev));
- ict_dev_setup(devno, ict_devp);
- return 0;
- fail_malloc:
- unregister_chrdev_region(devno, 1);
- return result;
- }
- static void __exit ict_ill_exit(void)
- {
- cdev_del(&ict_devp->cdev);
- kfree(ict_devp);
- unregister_chrdev_region(MKDEV(ictdev_major, 0), 1);
- }
- module_init(ict_ill_init);
- module_exit(ict_ill_exit);
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Michael Zhang <zhang_mq@sina.com>");
- module_param(mod_param, int, S_IRUGO);
- MODULE_PARM_DESC(mod_param, "Initialization param of ioctl illustration program.");
- module_param(ictdev_major, int, S_IRUGO);
- MODULE_PARM_DESC(mod_param, "Initialization param of ioctl illustration program.");
3.内核部分代码通过下面的Makefile文件可编译成ict_u.ko
- ifneq ($(KERNELRELEASE),)
- obj-m := ict_k.o
- else
- KERNELDIR ?= /lib/modules/$(shell uname -r)/build
- PWD := $(shell pwd)
- default:
- $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
- clean:
- rm -rf *.o *.mod.c *.ko
- endif
- 在编译出ict_k.ko后,将模块记载到内核,查看设备的主设备号。
- 在/dev目录下通过运行以下命令来生成设备节点: sudo mkdev ictdev c 250 0
- 对于内核代码中,struct file_operations实现了成员ioctl,但是对于大于2.6.36内核版本,其将会被unlocked_ioctl取代。
- 4.用户空间代码ict_u.c
- <pre name="code" class="cpp">/********************************************************************************
- *FileName :ict_u.c
- *
- *Description :This program is the user part which is used to illustrate the usage of ioctl.
- *
- *Author :Michael Zhang <zhang_mq@sina.com>
- *
- *Version :V0.1 2013-09-04
- *********************************************************************************/
- #include <stdio.h>
- #include <unistd.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/ioctl.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- /**********************Define Error Return Value**********************************/
- #define ICT_SUCCESS 0
- #define ICT_ERROR_DEV 1
- #define ICT_ERROR_PARAM 2
- #define ICT_ERROR_IOCTL 3
- /**************************IOCTL Releate Macro**********************************/
- #define ICT_IOCTL_MAGIC_NUM 'K'
- #define ICTIOC_GETDEV_INFO _IOR(ICT_IOCTL_MAGIC_NUM, 0, int)
- #define ICTIOC_SETDEV_INFO _IOWR(ICT_IOCTL_MAGIC_NUM, 1, int)
- #define ICT_DEV_FILE "/dev/ictdev"
- static int ict_fd;
- static void usage()
- {
- printf("************************************************\n");
- printf("ictdev [get | set [0|1]]\n");
- printf(" -get Get ict device info\n");
- printf(" -set Set ict device info\n");
- printf(" -0 Set ict device info as 0\n");
- printf(" -1 Set ict device info as 0\n");
- printf("************************************************\n");
- }
- static int parse_param(char *param)
- {
- if(*param == '1')
- return 1;
- else if(*param == '0')
- return 0;
- else
- usage();
- return -1;
- }
- int main(int argc, char **argv)
- {
- int fd;
- int devinfo;
- if(argc < 2)
- {
- usage();
- return ICT_ERROR_PARAM;
- }
- /*Open device file*/
- ict_fd = open(ICT_DEV_FILE, O_RDWR);
- if(ict_fd < 0)
- {
- printf("Open ict device fail\n");
- return ICT_ERROR_DEV;
- }
- if(strcmp("get", argv[1]) == 0)
- {
- if(ioctl(ict_fd, ICTIOC_GETDEV_INFO, &devinfo) < 0)
- {
- printf("Get ICT device info fail.\n");
- return ICT_ERROR_IOCTL;
- }
- printf("ICT device info is: %d\n", devinfo);
- return ICT_SUCCESS;
- }
- else if(strcmp("set", argv[1]) == 0)
- {
- devinfo = parse_param(argv[2]);
- if(devinfo == -1)
- {
- return ICT_ERROR_PARAM;
- }
- if(ioctl(ict_fd, ICTIOC_SETDEV_INFO, &devinfo))
- {
- printf("Set ICT device info fail.\n");
- return ICT_ERROR_IOCTL;
- }
- return ICT_SUCCESS;
- }
- else
- {
- usage();
- return ICT_ERROR_PARAM;
- }
- }
- </pre><br>
- <br>
- 通过gcc将其便以为可执行文件,如: gcc ict_u.c -o ict_app<br>
- 通过运行 ./ict_app get 或./ict_app set [0/1] 就可观察内核与用户空间是如何实现数据交换的。<br>
- 在运行ict_app是会去打开设备/dev/ictdev,故可能会因读写权限问题出现打开失败的问题,则可先修改/dev/ictdev的读写权限。<br>
- <pre></pre>
- <p></p>
- <pre></pre>
- <p><br>
- </p>
转:内核空间与用户空间数据交换的方式之一 --ioctl(通过字符设备演示)的更多相关文章
- GPIO硬件资源的申请,内核空间和用户空间的数据交换,ioctl(.....),设备文件的自动创建
1.通过GPIO库函数控制LED open("/dev/myleds",...) close(fd) ----------------------------- ...
- linux内核空间与用户空间信息交互方法
linux内核空间与用户空间信息交互方法 本文作者: 康华:计算机硕士,主要从事Linux操作系统内核.Linux技术标准.计算机安全.软件测试等领域的研究与开发工作,现就职于信息产业部软件与 ...
- 内核空间和用户空间的分界 PAGE_OFFSET
PAGE_OFFSET 首先看看PAGE_OFFSET的功能 内存映射 | 用户空间 | 内核空间 | |——————+———— ...
- Linux 内核空间与用户空间
本文以 32 位系统为例介绍内核空间(kernel space)和用户空间(user space). 内核空间和用户空间 对 32 位操作系统而言,它的寻址空间(虚拟地址空间,或叫线性地址空间)为 4 ...
- linux内核空间和用户空间详解
linux驱动程序一般工作在内核空间,但也可以工作在用户空间.下面我们将详细解析,什么是内核空间,什么是用户空间,以及如何判断他们.Linux简化了分段机制,使得虚拟地址与线性地址总是一致,因此,Li ...
- linux内存(一) 内核空间与用户空间
来自如下网站 https://www.cnblogs.com/sparkdev/p/8410350.html 内核空间和用户空间 对 32 位操作系统而言,它的寻址空间(虚拟地址空间,或叫线性地址空间 ...
- Linux操作系统,为什么需要内核空间和用户空间?
点击上方"开源Linux",选择"设为星标" 回复"学习"获取独家整理的学习资料! 本文以 32 位系统为例介绍内核空间(kernel sp ...
- 用户空间与内核空间数据交换的方式(9)------netlink【转】
转自:http://www.cnblogs.com/hoys/archive/2011/04/10/2011722.html Netlink 是一种特殊的 socket,它是 Linux 所特有的,类 ...
- 例说linux内核与应用数据通信(四):映射设备内核空间到用户态
[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet.文章仅供学习交流,请勿用于商业用途] 一个进程的内存映象由以下几部分组成:代码段.数据段.BSS段和 ...
随机推荐
- tomcat thread dump 分析【转载】
前言 Java Thread Dump 是一个非常有用的应用诊断工具, 通过thread dump出来的信息, 可以定位到你需要了解的线程, 以及这个线程的调用栈. 如果配合linux的top命令, ...
- Java学习日记-2.1 运算符
1. 赋值运算符 赋值运算符是有值的 int i; System.out.println(i = 5); //输出5 正因为赋值运算符有值,所以可以可以连等地赋值 int j,k,l,m,n; j = ...
- Mac 下 Scala 平台搭建
1.先要安装 JDK,下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html ...
- [Design Pattern] Proxy Pattern 简单案例
Proxy Pattern, 即代理模式,用一个类代表另一个类的功能,用于隐藏.解耦真正提供功能的类,属于结构类的设计模式. 下面是 代理模式的一个简单案例. Image 定义接口,RealImage ...
- POJ 3669 广度优先搜索
题意:巨大流星雨即将袭来.每个流星会对击中的地方以及周围(上下左右四格)造成破坏.Bessie开始时位于(0, 0)位置,并希望逃到一处不会被袭击到的地方(在第一象限内).已知每移动一格需要1个时间单 ...
- 大规模Hadoop集群在腾讯数据仓库TDW的实践
随着业务的快速增长,TDW的节点数也在增加,对单个大规模Hadoop集群的需求也越来越强烈.TDW需要做单个大规模集群,主要是从数据共享.计算资源共享.减轻运营负担和成本等三个方面考虑. 数据共享.T ...
- layout布局实例化
实例化xml中的Layout布局在开发中经常会用到,有几种方法可以使用 1.在Activity中使用getLayoutInflater()方法 View layout = getLayoutInfla ...
- CComPtr用法
COM接口指针很危险,因为使用过程中需要每一个使用者都要严格并且正确的AddRef和Release,一旦出现问题,就会造成对象不能被正常释放,或者对象被重复删除,造成程序崩溃.所以使用COM接口,必须 ...
- [Angular 2] Using ngrx/store and Reducers for Angular 2 Application State
ngrx/store is a library that simplifies common RxJS patterns for managing state and gives you an eas ...
- RollPagerView的用法:
RollPagerView的用法: /** * * @author smiling * @date 2016/10 */ Android Studio 导包: compile 'com.jude:ro ...