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

    

[cpp] view plain copy
 
  1. #ifndef __ICT_K_H__  
  2. #define __ICT_K_H__  
  3.   
  4. #define MAX_BUFFER_SIZE            64  
  5. #define ICTDEV_MAJOR                  250  
  6.   
  7. #define ICT_IOCTL_MAGIC_NUM    'K'  
  8. #define ICTIOC_GETDEV_INFO       _IOR(ICT_IOCTL_MAGIC_NUM, 0, int)  
  9. #define ICTIOC_SETDEV_INFO       _IOWR(ICT_IOCTL_MAGIC_NUM, 1, int)  
  10.   
  11. #endif  


       2.ict_k.c

 

 

[cpp] view plain copy
 
  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.   
  19. struct ict_dev  
  20. {  
  21.     struct cdev cdev;  
  22.     char buffer[MAX_BUFFER_SIZE];  
  23. };  
  24.   
  25. static int mod_param = 0;  
  26. static int ictdev_major = ICTDEV_MAJOR;  
  27. static struct ict_dev *ict_devp;  
  28. static int devinfo = 0;  
  29.   
  30. /*Device open function*/  
  31. static int ictdev_open(struct inode *inode, struct file *filp)  
  32. {  
  33.     printk(KERN_INFO"Ict device has been open.\n");  
  34.     return 0;  
  35. }  
  36.   
  37. /*ioctl: device control function*/  
  38. //static long ictdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  
  39. static long ictdev_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)  
  40. {  
  41.     int ret = 0;  
  42.     int tmp;  
  43.     void __user *argp = (void __user *)arg;  
  44.   
  45.     switch(cmd)  
  46.     {  
  47.         case ICTIOC_GETDEV_INFO:  
  48.             put_user(devinfo, (int *)arg);  
  49.             break;  
  50.   
  51.         case ICTIOC_SETDEV_INFO:  
  52.             get_user(tmp, (int __user *)argp);  
  53.             devinfo = tmp;  
  54.             printk(KERN_INFO"Set devinfo as: %d\n", devinfo);  
  55.             break;  
  56.               
  57.         default:  
  58.             break;  
  59.     }  
  60.   
  61.     return ret;  
  62.   
  63. }  
  64.   
  65. static  int ictdev_release(struct inode *inode, struct file *filp)  
  66. {  
  67.     printk(KERN_INFO"Ict device will be closed.\n");  
  68.     return 0;  
  69. }  
  70.   
  71. struct file_operations ictdev_fops =  
  72. {  
  73.     .owner = THIS_MODULE,  
  74.     .open = ictdev_open,  
  75.     .ioctl = ictdev_ioctl,  
  76.     //.unlock_ioct = ictdev_ioctl,  
  77.     .release = ictdev_release,  
  78. };  
  79.   
  80.   
  81. static void ict_dev_setup(dev_t devno, struct ict_dev *dev)  
  82. {  
  83.     int ret;  
  84.     cdev_init(&dev->cdev, &ictdev_fops);  
  85.     dev->cdev.owner = THIS_MODULE;  
  86.     ret = cdev_add(&dev->cdev, devno, 1);  
  87.     if(ret)  
  88.     {  
  89.         printk(KERN_ERR"Add cdev fail.\n");  
  90.     }  
  91.   
  92.     return;    
  93. }  
  94.   
  95.   
  96. /*Ict module intilization*/  
  97. static int __init ict_ill_init(void)  
  98. {  
  99.     int result;  
  100.     dev_t devno;  
  101.       
  102.     devno = MKDEV(ictdev_major, 0);  
  103.   
  104.     if(ictdev_major)  
  105.     {  
  106.         result = register_chrdev_region(devno, 1, "ictdev");  
  107.     }  
  108.     else  
  109.     {  
  110.         result = alloc_chrdev_region(&devno, 0, 1, "ictdev");  
  111.         ictdev_major = MAJOR(devno);  
  112.     }  
  113.   
  114.     printk(KERN_INFO"ictdev_major is %d\n", ictdev_major);  
  115.     if(result < 0)  
  116.     {  
  117.         printk("Register/Allocate device number fail.\n");  
  118.         return result;  
  119.     }  
  120.   
  121.     ict_devp = kmalloc(sizeof(struct ict_dev), GFP_KERNEL);  
  122.     if(!ict_devp)  
  123.     {  
  124.         printk("Memory allocation fail.\n");  
  125.         result = -ENOMEM;  
  126.         goto fail_malloc;  
  127.     }  
  128.   
  129.     memset(ict_devp, 0, sizeof(struct ict_dev));  
  130.     ict_dev_setup(devno, ict_devp);  
  131.     return 0;  
  132.   
  133. fail_malloc:  
  134.     unregister_chrdev_region(devno, 1);  
  135.     return result;  
  136.       
  137. }  
  138.   
  139.   
  140. static void __exit ict_ill_exit(void)  
  141. {  
  142.     cdev_del(&ict_devp->cdev);  
  143.     kfree(ict_devp);  
  144.     unregister_chrdev_region(MKDEV(ictdev_major, 0), 1);  
  145. }  
  146.   
  147.   
  148. module_init(ict_ill_init);  
  149. module_exit(ict_ill_exit);  
  150.   
  151. MODULE_LICENSE("GPL");  
  152. MODULE_AUTHOR("Michael Zhang <zhang_mq@sina.com>");  
  153.   
  154. module_param(mod_param, int, S_IRUGO);  
  155. MODULE_PARM_DESC(mod_param, "Initialization param of ioctl illustration program.");  
  156.   
  157. module_param(ictdev_major, int, S_IRUGO);  
  158. MODULE_PARM_DESC(mod_param, "Initialization param of ioctl illustration program.");  

 

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

 

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