• 转:内核空间与用户空间数据交换的方式之一 --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

        

    [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. ");  
    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 ", 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. ");  
    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. ");  
    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 ", ictdev_major);  
    112.     if(result < 0)  
    113.     {  
    114.         printk("Register/Allocate device number fail. ");  
    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. ");  
    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("************************************************ ");  
      52.     printf("ictdev [get | set [0|1]] ");  
      53.     printf("        -get    Get ict device info ");  
      54.     printf("        -set    Set ict device info ");  
      55.     printf("                -0    Set ict device info as 0 ");  
      56.     printf("                -1    Set ict device info as 0 ");  
      57.     printf("************************************************ ");  
      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 ");  
      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. ");  
      95.             return ICT_ERROR_IOCTL;  
      96.         }  
      97.   
      98.         printf("ICT device info is: %d ", 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. ");  
      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.      
  • 相关阅读:
    Beego 学习笔记12:文件的操作
    Beego 学习笔记11:文件的上传下载
    Beego 学习笔记10:Easyui使用
    Beego 学习笔记9:Boostrap使用介绍
    Beego 学习比较8:SQL语句
    Beego 学习笔记7:JS分页
    Beego学习笔记6:分页的实现
    【嵌入式linux】用户登录密码验证配置
    【Linux 环境搭建】ubuntu下nfs安装与配置
    【嵌入式 Linux文件系统】如何使用NFS文件系统
  • 原文地址:https://www.cnblogs.com/yfz0/p/5818104.html
Copyright © 2020-2023  润新知