对于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. *Description       :This program is the kernel part which is used to illustrate the usage of ioctl.  
  4. *Author              :Michael Zhang <zhang_mq@sina.com> 
  5. *Version             :V0.1  2013-09-02 
  6. *********************************************************************************/  
  7. #include <linux/kernel.h>  
  8. #include <linux/module.h>  
  9. #include <linux/cdev.h>  
  10. #include <linux/types.h>  
  11. #include <asm/uaccess.h>  
  12. #include <linux/fs.h>     /*struct file*/  
  13. #include <linux/slab.h>  /*kfree*/  
  14. #include "ict_k.h"  
  15.   
  16. struct ict_dev  
  17. {  
  18.     struct cdev cdev;  
  19.     char buffer[MAX_BUFFER_SIZE];  
  20. };  
  21.   
  22. static int mod_param = 0;  
  23. static int ictdev_major = ICTDEV_MAJOR;  
  24. static struct ict_dev *ict_devp;  
  25. static int devinfo = 0;  
  26.   
  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.   
  34. /*ioctl: device control function*/  
  35. //static long ictdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  
  36. static long ictdev_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)  
  37. {  
  38.     int ret = 0;  
  39.     int tmp;  
  40.     void __user *argp = (void __user *)arg;  
  41.   
  42.     switch(cmd)  
  43.     {  
  44.         case ICTIOC_GETDEV_INFO:  
  45.             put_user(devinfo, (int *)arg);  
  46.             break;  
  47.   
  48.         case ICTIOC_SETDEV_INFO:  
  49.             get_user(tmp, (int __user *)argp);  
  50.             devinfo = tmp;  
  51.             printk(KERN_INFO"Set devinfo as: %d\n", devinfo);  
  52.             break;  
  53.               
  54.         default:  
  55.             break;  
  56.     }  
  57.   
  58.     return ret;  
  59.   
  60. }  
  61.   
  62. static  int ictdev_release(struct inode *inode, struct file *filp)  
  63. {  
  64.     printk(KERN_INFO"Ict device will be closed.\n");  
  65.     return 0;  
  66. }  
  67.   
  68. struct file_operations ictdev_fops =  
  69. {  
  70.     .owner = THIS_MODULE,  
  71.     .open = ictdev_open,  
  72.     .ioctl = ictdev_ioctl,  
  73.     //.unlock_ioct = ictdev_ioctl,  
  74.     .release = ictdev_release,  
  75. };  
  76.   
  77.   
  78. static void ict_dev_setup(dev_t devno, struct ict_dev *dev)  
  79. {  
  80.     int ret;  
  81.     cdev_init(&dev->cdev, &ictdev_fops);  
  82.     dev->cdev.owner = THIS_MODULE;  
  83.     ret = cdev_add(&dev->cdev, devno, 1);  
  84.     if(ret)  
  85.     {  
  86.         printk(KERN_ERR"Add cdev fail.\n");  
  87.     }  
  88.   
  89.     return;    
  90. }  
  91.   
  92.   
  93. /*Ict module intilization*/  
  94. static int __init ict_ill_init(void)  
  95. {  
  96.     int result;  
  97.     dev_t devno;  
  98.       
  99.     devno = MKDEV(ictdev_major, 0);  
  100.   
  101.     if(ictdev_major)  
  102.     {  
  103.         result = register_chrdev_region(devno, 1, "ictdev");  
  104.     }  
  105.     else  
  106.     {  
  107.         result = alloc_chrdev_region(&devno, 0, 1, "ictdev");  
  108.         ictdev_major = MAJOR(devno);  
  109.     }  
  110.   
  111.     printk(KERN_INFO"ictdev_major is %d\n", ictdev_major);  
  112.     if(result < 0)  
  113.     {  
  114.         printk("Register/Allocate device number fail.\n");  
  115.         return result;  
  116.     }  
  117.   
  118.     ict_devp = kmalloc(sizeof(struct ict_dev), GFP_KERNEL);  
  119.     if(!ict_devp)  
  120.     {  
  121.         printk("Memory allocation fail.\n");  
  122.         result = -ENOMEM;  
  123.         goto fail_malloc;  
  124.     }  
  125.   
  126.     memset(ict_devp, 0, sizeof(struct ict_dev));  
  127.     ict_dev_setup(devno, ict_devp);  
  128.     return 0;  
  129.   
  130. fail_malloc:  
  131.     unregister_chrdev_region(devno, 1);  
  132.     return result;  
  133.       
  134. }  
  135.   
  136.   
  137. static void __exit ict_ill_exit(void)  
  138. {  
  139.     cdev_del(&ict_devp->cdev);  
  140.     kfree(ict_devp);  
  141.     unregister_chrdev_region(MKDEV(ictdev_major, 0), 1);  
  142. }  
  143.   
  144.   
  145. module_init(ict_ill_init);  
  146. module_exit(ict_ill_exit);  
  147.   
  148. MODULE_LICENSE("GPL");  
  149. MODULE_AUTHOR("Michael Zhang <zhang_mq@sina.com>");  
  150.   
  151. module_param(mod_param, int, S_IRUGO);  
  152. MODULE_PARM_DESC(mod_param, "Initialization param of ioctl illustration program.");  
  153.   
  154. module_param(ictdev_major, int, S_IRUGO);  
  155. 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. *Description       :This program is the user part which is used to illustrate the usage of ioctl.  
    23. *Author              :Michael Zhang <zhang_mq@sina.com> 
    24. *Version             :V0.1  2013-09-04 
    25. *********************************************************************************/  
    26. #include <stdio.h>  
    27. #include <unistd.h>  
    28. #include <string.h>  
    29. #include <sys/types.h>  
    30. #include <sys/ioctl.h>  
    31. #include <sys/stat.h>  
    32. #include <fcntl.h>  
    33.   
    34. /**********************Define Error Return Value**********************************/  
    35. #define ICT_SUCCESS            0  
    36. #define ICT_ERROR_DEV        1  
    37. #define ICT_ERROR_PARAM   2  
    38. #define ICT_ERROR_IOCTL     3  
    39.   
    40. /**************************IOCTL Releate Macro**********************************/  
    41. #define ICT_IOCTL_MAGIC_NUM    'K'  
    42. #define ICTIOC_GETDEV_INFO       _IOR(ICT_IOCTL_MAGIC_NUM, 0, int)  
    43. #define ICTIOC_SETDEV_INFO       _IOWR(ICT_IOCTL_MAGIC_NUM, 1, int)  
    44.   
    45. #define ICT_DEV_FILE        "/dev/ictdev"  
    46.   
    47. static int ict_fd;  
    48.   
    49. static void usage()  
    50. {  
    51.     printf("************************************************\n");  
    52.     printf("ictdev [get | set [0|1]]\n");  
    53.     printf("        -get    Get ict device info\n");  
    54.     printf("        -set    Set ict device info\n");  
    55.     printf("                -0    Set ict device info as 0\n");  
    56.     printf("                -1    Set ict device info as 0\n");  
    57.     printf("************************************************\n");  
    58. }  
    59.   
    60. static int parse_param(char *param)  
    61. {  
    62.     if(*param == '1')  
    63.         return 1;  
    64.     else if(*param == '0')  
    65.         return 0;  
    66.     else  
    67.         usage();  
    68.       
    69.     return -1;  
    70. }  
    71.   
    72. int main(int argc, char **argv)  
    73. {  
    74.     int fd;  
    75.     int devinfo;  
    76.       
    77.     if(argc < 2)  
    78.     {  
    79.         usage();  
    80.         return ICT_ERROR_PARAM;  
    81.     }  
    82.   
    83.     /*Open device file*/  
    84.     ict_fd = open(ICT_DEV_FILE, O_RDWR);  
    85.     if(ict_fd < 0)  
    86.     {  
    87.         printf("Open ict device fail\n");  
    88.         return ICT_ERROR_DEV;  
    89.     }  
    90.     if(strcmp("get", argv[1]) == 0)  
    91.     {  
    92.         if(ioctl(ict_fd, ICTIOC_GETDEV_INFO, &devinfo) < 0)  
    93.         {  
    94.             printf("Get ICT device info fail.\n");  
    95.             return ICT_ERROR_IOCTL;  
    96.         }  
    97.   
    98.         printf("ICT device info is: %d\n", devinfo);  
    99.         return ICT_SUCCESS;  
    100.     }  
    101.     else if(strcmp("set", argv[1]) == 0)  
    102.     {  
    103.         devinfo = parse_param(argv[2]);  
    104.         if(devinfo == -1)  
    105.         {  
    106.             return ICT_ERROR_PARAM;  
    107.         }  
    108.         if(ioctl(ict_fd, ICTIOC_SETDEV_INFO, &devinfo))  
    109.         {  
    110.             printf("Set ICT device info fail.\n");  
    111.             return ICT_ERROR_IOCTL;  
    112.         }  
    113.         return ICT_SUCCESS;  
    114.     }  
    115.     else  
    116.     {  
    117.         usage();  
    118.         return ICT_ERROR_PARAM;  
    119.     }  
    120. }  
    121. </pre><br>  
    122. <br>  
    123. 通过gcc将其便以为可执行文件,如: gcc ict_u.c -o ict_app<br>  
    124. 通过运行 ./ict_app get 或./ict_app set [0/1] 就可观察内核与用户空间是如何实现数据交换的。<br>  
    125. 在运行ict_app是会去打开设备/dev/ictdev,故可能会因读写权限问题出现打开失败的问题,则可先修改/dev/ictdev的读写权限。<br>  
    126. <pre></pre>  
    127. <p></p>  
    128. <pre></pre>  
    129. <p><br>  
    130. </p>  
    131.      
posted on 2016-08-29 15:15  care2014  阅读(775)  评论(0编辑  收藏  举报