对于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

  1. #ifndef __ICT_K_H__
  2. #define __ICT_K_H__
  3. #define MAX_BUFFER_SIZE            64
  4. #define ICTDEV_MAJOR                  250
  5. #define ICT_IOCTL_MAGIC_NUM    'K'
  6. #define ICTIOC_GETDEV_INFO       _IOR(ICT_IOCTL_MAGIC_NUM, 0, int)
  7. #define ICTIOC_SETDEV_INFO       _IOWR(ICT_IOCTL_MAGIC_NUM, 1, int)
  8. #endif

2.ict_k.c

  1. /********************************************************************************
  2. *FileName          :ict_k.c
  3. *
  4. *Description       :This program is the kernel part which is used to illustrate the usage of ioctl.
  5. *
  6. *Author              :Michael Zhang <zhang_mq@sina.com>
  7. *
  8. *Version             :V0.1  2013-09-02
  9. *********************************************************************************/
  10. #include <linux/kernel.h>
  11. #include <linux/module.h>
  12. #include <linux/cdev.h>
  13. #include <linux/types.h>
  14. #include <asm/uaccess.h>
  15. #include <linux/fs.h>     /*struct file*/
  16. #include <linux/slab.h>  /*kfree*/
  17. #include "ict_k.h"
  18. struct ict_dev
  19. {
  20. struct cdev cdev;
  21. char buffer[MAX_BUFFER_SIZE];
  22. };
  23. static int mod_param = 0;
  24. static int ictdev_major = ICTDEV_MAJOR;
  25. static struct ict_dev *ict_devp;
  26. static int devinfo = 0;
  27. /*Device open function*/
  28. static int ictdev_open(struct inode *inode, struct file *filp)
  29. {
  30. printk(KERN_INFO"Ict device has been open.\n");
  31. return 0;
  32. }
  33. /*ioctl: device control function*/
  34. //static long ictdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
  35. static long ictdev_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
  36. {
  37. int ret = 0;
  38. int tmp;
  39. void __user *argp = (void __user *)arg;
  40. switch(cmd)
  41. {
  42. case ICTIOC_GETDEV_INFO:
  43. put_user(devinfo, (int *)arg);
  44. break;
  45. case ICTIOC_SETDEV_INFO:
  46. get_user(tmp, (int __user *)argp);
  47. devinfo = tmp;
  48. printk(KERN_INFO"Set devinfo as: %d\n", devinfo);
  49. break;
  50. default:
  51. break;
  52. }
  53. return ret;
  54. }
  55. static  int ictdev_release(struct inode *inode, struct file *filp)
  56. {
  57. printk(KERN_INFO"Ict device will be closed.\n");
  58. return 0;
  59. }
  60. struct file_operations ictdev_fops =
  61. {
  62. .owner = THIS_MODULE,
  63. .open = ictdev_open,
  64. .ioctl = ictdev_ioctl,
  65. //.unlock_ioct = ictdev_ioctl,
  66. .release = ictdev_release,
  67. };
  68. static void ict_dev_setup(dev_t devno, struct ict_dev *dev)
  69. {
  70. int ret;
  71. cdev_init(&dev->cdev, &ictdev_fops);
  72. dev->cdev.owner = THIS_MODULE;
  73. ret = cdev_add(&dev->cdev, devno, 1);
  74. if(ret)
  75. {
  76. printk(KERN_ERR"Add cdev fail.\n");
  77. }
  78. return;
  79. }
  80. /*Ict module intilization*/
  81. static int __init ict_ill_init(void)
  82. {
  83. int result;
  84. dev_t devno;
  85. devno = MKDEV(ictdev_major, 0);
  86. if(ictdev_major)
  87. {
  88. result = register_chrdev_region(devno, 1, "ictdev");
  89. }
  90. else
  91. {
  92. result = alloc_chrdev_region(&devno, 0, 1, "ictdev");
  93. ictdev_major = MAJOR(devno);
  94. }
  95. printk(KERN_INFO"ictdev_major is %d\n", ictdev_major);
  96. if(result < 0)
  97. {
  98. printk("Register/Allocate device number fail.\n");
  99. return result;
  100. }
  101. ict_devp = kmalloc(sizeof(struct ict_dev), GFP_KERNEL);
  102. if(!ict_devp)
  103. {
  104. printk("Memory allocation fail.\n");
  105. result = -ENOMEM;
  106. goto fail_malloc;
  107. }
  108. memset(ict_devp, 0, sizeof(struct ict_dev));
  109. ict_dev_setup(devno, ict_devp);
  110. return 0;
  111. fail_malloc:
  112. unregister_chrdev_region(devno, 1);
  113. return result;
  114. }
  115. static void __exit ict_ill_exit(void)
  116. {
  117. cdev_del(&ict_devp->cdev);
  118. kfree(ict_devp);
  119. unregister_chrdev_region(MKDEV(ictdev_major, 0), 1);
  120. }
  121. module_init(ict_ill_init);
  122. module_exit(ict_ill_exit);
  123. MODULE_LICENSE("GPL");
  124. MODULE_AUTHOR("Michael Zhang <zhang_mq@sina.com>");
  125. module_param(mod_param, int, S_IRUGO);
  126. MODULE_PARM_DESC(mod_param, "Initialization param of ioctl illustration program.");
  127. module_param(ictdev_major, int, S_IRUGO);
  128. MODULE_PARM_DESC(mod_param, "Initialization param of ioctl illustration program.");

3.内核部分代码通过下面的Makefile文件可编译成ict_u.ko

    1. ifneq ($(KERNELRELEASE),)
    2. obj-m := ict_k.o
    3. else
    4. KERNELDIR ?= /lib/modules/$(shell uname -r)/build
    5. PWD := $(shell pwd)
    6. default:
    7. $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
    8. clean:
    9. rm -rf *.o *.mod.c *.ko
    10. endif
    11. 在编译出ict_k.ko后,将模块记载到内核,查看设备的主设备号。
    12. 在/dev目录下通过运行以下命令来生成设备节点: sudo mkdev ictdev c 250 0
    13. 对于内核代码中,struct file_operations实现了成员ioctl,但是对于大于2.6.36内核版本,其将会被unlocked_ioctl取代。
    14. 4.用户空间代码ict_u.c
    15. <pre name="code" class="cpp">/********************************************************************************
    16. *FileName          :ict_u.c
    17. *
    18. *Description       :This program is the user part which is used to illustrate the usage of ioctl.
    19. *
    20. *Author              :Michael Zhang <zhang_mq@sina.com>
    21. *
    22. *Version             :V0.1  2013-09-04
    23. *********************************************************************************/
    24. #include <stdio.h>
    25. #include <unistd.h>
    26. #include <string.h>
    27. #include <sys/types.h>
    28. #include <sys/ioctl.h>
    29. #include <sys/stat.h>
    30. #include <fcntl.h>
    31. /**********************Define Error Return Value**********************************/
    32. #define ICT_SUCCESS            0
    33. #define ICT_ERROR_DEV        1
    34. #define ICT_ERROR_PARAM   2
    35. #define ICT_ERROR_IOCTL     3
    36. /**************************IOCTL Releate Macro**********************************/
    37. #define ICT_IOCTL_MAGIC_NUM    'K'
    38. #define ICTIOC_GETDEV_INFO       _IOR(ICT_IOCTL_MAGIC_NUM, 0, int)
    39. #define ICTIOC_SETDEV_INFO       _IOWR(ICT_IOCTL_MAGIC_NUM, 1, int)
    40. #define ICT_DEV_FILE        "/dev/ictdev"
    41. static int ict_fd;
    42. static void usage()
    43. {
    44. printf("************************************************\n");
    45. printf("ictdev [get | set [0|1]]\n");
    46. printf("        -get    Get ict device info\n");
    47. printf("        -set    Set ict device info\n");
    48. printf("                -0    Set ict device info as 0\n");
    49. printf("                -1    Set ict device info as 0\n");
    50. printf("************************************************\n");
    51. }
    52. static int parse_param(char *param)
    53. {
    54. if(*param == '1')
    55. return 1;
    56. else if(*param == '0')
    57. return 0;
    58. else
    59. usage();
    60. return -1;
    61. }
    62. int main(int argc, char **argv)
    63. {
    64. int fd;
    65. int devinfo;
    66. if(argc < 2)
    67. {
    68. usage();
    69. return ICT_ERROR_PARAM;
    70. }
    71. /*Open device file*/
    72. ict_fd = open(ICT_DEV_FILE, O_RDWR);
    73. if(ict_fd < 0)
    74. {
    75. printf("Open ict device fail\n");
    76. return ICT_ERROR_DEV;
    77. }
    78. if(strcmp("get", argv[1]) == 0)
    79. {
    80. if(ioctl(ict_fd, ICTIOC_GETDEV_INFO, &devinfo) < 0)
    81. {
    82. printf("Get ICT device info fail.\n");
    83. return ICT_ERROR_IOCTL;
    84. }
    85. printf("ICT device info is: %d\n", devinfo);
    86. return ICT_SUCCESS;
    87. }
    88. else if(strcmp("set", argv[1]) == 0)
    89. {
    90. devinfo = parse_param(argv[2]);
    91. if(devinfo == -1)
    92. {
    93. return ICT_ERROR_PARAM;
    94. }
    95. if(ioctl(ict_fd, ICTIOC_SETDEV_INFO, &devinfo))
    96. {
    97. printf("Set ICT device info fail.\n");
    98. return ICT_ERROR_IOCTL;
    99. }
    100. return ICT_SUCCESS;
    101. }
    102. else
    103. {
    104. usage();
    105. return ICT_ERROR_PARAM;
    106. }
    107. }
    108. </pre><br>
    109. <br>
    110. 通过gcc将其便以为可执行文件,如: gcc ict_u.c -o ict_app<br>
    111. 通过运行 ./ict_app get 或./ict_app set [0/1] 就可观察内核与用户空间是如何实现数据交换的。<br>
    112. 在运行ict_app是会去打开设备/dev/ictdev,故可能会因读写权限问题出现打开失败的问题,则可先修改/dev/ictdev的读写权限。<br>
    113. <pre></pre>
    114. <p></p>
    115. <pre></pre>
    116. <p><br>
    117. </p>

转:内核空间与用户空间数据交换的方式之一 --ioctl(通过字符设备演示)的更多相关文章

  1. GPIO硬件资源的申请,内核空间和用户空间的数据交换,ioctl(.....),设备文件的自动创建

    1.通过GPIO库函数控制LED   open("/dev/myleds",...)       close(fd)   ----------------------------- ...

  2. linux内核空间与用户空间信息交互方法

    linux内核空间与用户空间信息交互方法     本文作者: 康华:计算机硕士,主要从事Linux操作系统内核.Linux技术标准.计算机安全.软件测试等领域的研究与开发工作,现就职于信息产业部软件与 ...

  3. 内核空间和用户空间的分界 PAGE_OFFSET

      PAGE_OFFSET 首先看看PAGE_OFFSET的功能   内存映射 |            用户空间                  |   内核空间   | |——————+———— ...

  4. Linux 内核空间与用户空间

    本文以 32 位系统为例介绍内核空间(kernel space)和用户空间(user space). 内核空间和用户空间 对 32 位操作系统而言,它的寻址空间(虚拟地址空间,或叫线性地址空间)为 4 ...

  5. linux内核空间和用户空间详解

    linux驱动程序一般工作在内核空间,但也可以工作在用户空间.下面我们将详细解析,什么是内核空间,什么是用户空间,以及如何判断他们.Linux简化了分段机制,使得虚拟地址与线性地址总是一致,因此,Li ...

  6. linux内存(一) 内核空间与用户空间

    来自如下网站 https://www.cnblogs.com/sparkdev/p/8410350.html 内核空间和用户空间 对 32 位操作系统而言,它的寻址空间(虚拟地址空间,或叫线性地址空间 ...

  7. Linux操作系统,为什么需要内核空间和用户空间?

    点击上方"开源Linux",选择"设为星标" 回复"学习"获取独家整理的学习资料! 本文以 32 位系统为例介绍内核空间(kernel sp ...

  8. 用户空间与内核空间数据交换的方式(9)------netlink【转】

    转自:http://www.cnblogs.com/hoys/archive/2011/04/10/2011722.html Netlink 是一种特殊的 socket,它是 Linux 所特有的,类 ...

  9. 例说linux内核与应用数据通信(四):映射设备内核空间到用户态

    [版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet.文章仅供学习交流,请勿用于商业用途]         一个进程的内存映象由以下几部分组成:代码段.数据段.BSS段和 ...

随机推荐

  1. DLL入门浅析(5)——使用DLL在进程间共享数据

    转载自:http://www.cppblog.com/suiaiguo/archive/2009/07/21/90734.html 在Win16环境中,DLL的全局数据对每个载入它的进程来说都是相同的 ...

  2. Aggregating tests in suites

    我们可以将来自不同类的test组成一个test suite.在JUnit 3.8.x我们使用 static Test suite()方法,但是在JUnit4我们使用在类前面加上注释 @RunWith( ...

  3. H - Can you answer these queries? - (区间查询更新)

    有一列数,(都是2^63范围内的并且都大于0的整数),现在呢有一些操作, 操作 0 可以把区间LR内的所有数都变成它的平方根数(是取整后的),操作 1 可以就是求区间LR内的和了. 分析:因为这个操作 ...

  4. CSS里的 no-repeat 是什么意思

    CSS里的 no-repeat是针对背景图片来说的.当你设置了no-repeat这个属性后,你的背景图片将不会被重复,再换一种说法,你在网站上所看到的背景图片就是你所添加的图片, 不会出现平铺或者重复 ...

  5. Git详解之一 Git起步

    起步 本章介绍开始使用 Git 前的相关知识.我们会先了解一些版本控制工具的历史背景,然后试着让 Git 在你的系统上跑起来,直到最后配置好,可以正常开始开发工作.读完本章,你就会明白为什么 Git ...

  6. 一个高级PHP工程师所应该具备的

    初次接触PHP,就为他的美所折服,于是一发不可收拾. 很多面试,很多人员能力要求都有“PHP高级工程师的字眼”,如果您真心喜欢PHP,并且您刚起步,那么我简单说说一个PHP高级工程师所应该具备的,希望 ...

  7. java 全角字符半角字符转换

    /// <summary> /// 判断字符是否英文半角字符或标点 /// </summary> /// <remarks> /// 32    空格 /// 33 ...

  8. SAX PULL解析实例

    XML三种解析方式: SAX解析:基于事件驱动,事件机制基于回调函数的,得到节点和节点之间内容时也会回调事件 PULL解析:相同基于事件驱动,仅仅只是回调时是常量 DOM解析:是先把XML文件装入内存 ...

  9. make文件中静态连接库在command里面的位置

    linux软件第一次调用动态连接库的时候要延迟几秒,怀疑在突然掉库的时候动态库加载耗费了时间,所以造成延时,遂改为静态库方式,原来的makefile文件是 testmac:         cp $( ...

  10. Because the people who are crazy enough to think they can change the world, are the ones who do.

    Here's to the crazy ones. The misfits. The rebels. The troublemakers. The round pegs in the square h ...