zoukankan      html  css  js  c++  java
  • /dev下添加设备节点的方法步骤(通过device_create)

    将自己开发的内核代码加入到Linux内核中,需要3个步骤:

     1、确定把自己开发代码放入到内核合适的位置

          将demo_chardev.c文件拷贝到.../drivers/char/目录下。

    demo_chardev.c

    [cpp] view plain copy
     
    1. #include <linux/init.h>   
    2. #include <linux/module.h>  
    3. #include <linux/kernel.h>  
    4. /*结构体file_operations定义的头文件*/  
    5. #include <linux/fs.h>  
    6. /*声明copy_to/from_user函数的头文件*/  
    7. #include <linux/uaccess.h>  
    8. /*声明class_create 和device_create相关信息*/  
    9. #include <linux/device.h>  
    10.   
    11. #define DEMO_DEBUG  
    12. #ifdef  DEMO_DEBUG  
    13. #define dem_dbg(fmt, arg...)  printk(KERN_WARNING fmt, ##arg)  
    14. #else  
    15. #define dem_dbg(fmt, arg...)  printk(KERN_DEBUG fmt, ##arg)  
    16. #endif  
    17.   
    18. #define DEVICE_COUNT   2  
    19.   
    20.   
    21. /*记录当前驱动所占用的主设备号*/  
    22. static int major = 0;  
    23.   
    24. static int demo_open (struct inode *pnode, struct file *filp)  
    25. {  
    26.      dem_dbg("[kern func]: %s  major: %d  minor: %d ",  
    27.      __FUNCTION__, imajor(pnode), iminor(pnode));  
    28.      return 0;  
    29. }  
    30. static ssize_t demo_read (struct file *filp, char __user *buf, size_t count, loff_t *offp)  
    31. {  
    32.     unsigned char ary[100] = "you are reading successfully!";  
    33.     unsigned long len = min(count, sizeof(ary)); //min是个宏,用来获取两个数中较小的值  
    34.      int retval;  
    35.   
    36.     dem_dbg("[kern func]: %s  major: %d  minor: %d ",  
    37.     __FUNCTION__, imajor(filp->f_dentry->d_inode),   
    38.     iminor(filp->f_dentry->d_inode));  
    39.    
    40.     //file结构体的f_flags成员可用来判断是否阻塞读取,然后进行相应处理  
    41.   
    42.      if(copy_to_user(buf, ary, len) != 0){  
    43.            retval = -EFAULT;  
    44.            goto cp_err;  
    45.      }  
    46.   
    47.      return len; //成功返回实际传输的字节数  
    48.       cp_err:  
    49.      return retval;   
    50. }  
    51.   
    52. static ssize_t demo_write(struct file *filp, const char __user *buf, size_t count, loff_t *offp)  
    53. {  
    54.     unsigned char ary[100] = "";  
    55.     unsigned long len = min(count, sizeof(ary)); //min是个宏,用来获取两个数中较小的值  
    56.      int retval;  
    57.   
    58.     dem_dbg("[kern func]: %s  major: %d  minor: %d ",  
    59.     __FUNCTION__, imajor(filp->f_dentry->d_inode),   
    60.     iminor(filp->f_dentry->d_inode));  
    61.    
    62.     if(copy_from_user(ary, buf, len) != 0){  
    63.            retval = -EFAULT;  
    64.            goto cp_err;  
    65.     }  
    66.     printk("[msg]: writing context: %s ",ary);  
    67.     return len; //成功返回实际传输的字节数  
    68.      cp_err:  
    69.     return retval;   
    70. }  
    71. static int demo_release (struct inode *pnode, struct file *filp)  
    72. {  
    73.      dem_dbg("[kern func]: %s  major: %d  minor: %d ",  
    74.      __FUNCTION__, imajor(pnode), iminor(pnode));  
    75.      return 0;  
    76. }  
    77.   
    78.   
    79. /*@定义file_operations结构体变量*/  
    80. static struct file_operations fops = {  
    81.       .owner = THIS_MODULE,  
    82.       .read = demo_read,  
    83.       .write = demo_write,  
    84.       .open = demo_open,  
    85.       .release = demo_release,  
    86. };   
    87.   
    88. static struct class *demo_class;  
    89. static int __init drvdemo_init(void)  
    90. {  
    91.     struct device *demo_device;  
    92.     int i;  
    93.     int retval;  
    94.    
    95.     dem_dbg("[msg]:this is a driver demo, in module initial function ");  
    96.     /*注册字符驱动函数,成功 返回动态分配好的主设备号,失败 
    97.       *返回错误码(负值)*/  
    98.     major = register_chrdev(0, "demo_chrdev", &fops);  
    99.     if(major < 0){  
    100.             retval = major;  
    101.             goto chrdev_err;  
    102.     }  
    103.   
    104.     /*创建设备类*/  
    105.     demo_class = class_create(THIS_MODULE,"demo_class");  
    106.     if(IS_ERR(demo_class)){  
    107.            retval =  PTR_ERR(demo_class);  
    108.            goto class_err;  
    109.     }  
    110.   
    111.     /*创建设备文件,通知用户在“/dev/”目录下创件名字为demoX的设备文件*/  
    112.     for(i=0; i<DEVICE_COUNT; i++){ //最多可创建255个设备节点(register_chrdev函数会申请0-254范围的从设备号)  
    113.         demo_device = device_create(demo_class,NULL, MKDEV(major, i), NULL,"demo%d",i);  
    114.         if(IS_ERR(demo_device)){  
    115.               retval = PTR_ERR(demo_device);  
    116.               goto device_err;  
    117.         }  
    118.     }      
    119.     return 0;   
    120. device_err:   
    121.     while(i--) //设备节点创建的回滚操作 device_destroy(demo_class,MKDEV(major, i));   
    122.          class_destroy(demo_class); //删除设备类   
    123. class_err:   
    124.     unregister_chrdev(major, "demo_chrdev");  
    125. chrdev_err:   
    126.     return retval;   
    127. }  
    128. static void __exit drvdemo_exit(void)  
    129. {  
    130.       int i;  
    131.    
    132.       dem_dbg("[msg]:in module exit function ");  
    133.       /*注销字符驱动函数,无返回值,major为已分配的主设备号*/  
    134.       unregister_chrdev(major, "demo_chrdev");  
    135.       /*删除设备节点和设备类*/  
    136.       for(i=0; i<DEVICE_COUNT; i++)  
    137.           device_destroy(demo_class,MKDEV(major, i));  
    138.       class_destroy(demo_class);  
    139. }  
    140.   
    141. module_init(drvdemo_init);  
    142. module_exit(drvdemo_exit);  
    143.   
    144. MODULE_LICENSE("Dual BSD/GPL"); //BSD/GPL双重许可证  
    145. MODULE_AUTHOR("hanbo");  //模块作者(可选)  
    146. MODULE_DESCRIPTION("used for studing linux drivers"); //模块儿简介(可选)  

    2、把自己开发的功能增加到Linux内核的配置选项中,使用户能够选择此功能

         vi drivers/char/Konfig   在文件结尾,endmenu的前面加入一个config选项 

    [cpp] view plain copy
     
    1. config  DEMO_CHARDEV  
    2.   
    3.              bool  "demo_chardev  driver  for  hanbo  chardev  boards"  
    4.   
    5.              default  y  
    6.   
    7.               help   
    8.   
    9.                   this  is  CHARDEV  driver  for  hanbo  chardev  boards.  

    3、构建或修改Makefile,根据用户的选择,将相应的代码编译到最终生成的Linux内核中去

                 make  menuconfig(添加配置选项)(如果提示找不到“ncurses”库则执行命令: sudo apt-get install libncurses5-dev )

                  Device driver -->

                        character devices ->

                                  [*] demo_chardev driver for hanbo chardev boards

     4、vi  drivers/char/Makefile  添加内容如下:

                ..........

                obj-$(CONFIG_DEMO_CHARDEV)        +=demo_chardev.o (添加)

                obj-$(CONFIG_JS_RTC)                         +=js-rtc.o(自带)

                js-rtc-y = rtc.o (自带)
     5、make  (更新内核镜像到开发板)

     6、交叉编译测试程序,放到开发板运行

          arm-linux-gcc-gcc  test.c  -o  demo  

       test.c  

    [cpp] view plain copy
     
    1. #include <stdio.h>  
    2. #include <stdlib.h>  
    3. #include <unistd.h>  
    4.   
    5. #include <fcntl.h>  
    6.   
    7. #include <string.h>  
    8.   
    9. int main(int argc, char *argv[])  
    10. {  
    11.        int fd1 = 0, fd2 = 0;  
    12.        unsigned char buf1[100] = "I am a test program!";  
    13.        unsigned char buf2[100] = {0};  
    14.        int retval;  
    15.   
    16.        //以读写、不阻塞方式打开设备文件  
    17.         fd1 = open("/dev/demo0", O_RDWR | O_NONBLOCK);  
    18.         if(fd1 < 0){  
    19.                perror("open /dev/demo1");  
    20.                 goto out;  
    21.          }  
    22.         //以只读、阻塞方式打开设备文件  
    23.        fd2 = open("/dev/demo1", O_RDONLY);  
    24.        if(fd2 < 0){  
    25.                perror("open /dev/demo2");  
    26.                goto out;  
    27.          }  
    28.   
    29.         //成功返回实际写入字节数,失败返回负值  
    30.         retval = write(fd1, buf1, strlen(buf1)+1);  
    31.         if(retval < 0){  
    32.                perror("writing fd1 failed!");  
    33.                goto out;  
    34.          }  
    35.         printf("<user space>: write bytes: %d   write content: %s ", retval, buf1);  
    36.   
    37.         //成功返回实际读取字节数,失败返回负值  
    38.         retval = read(fd2, buf2, sizeof(buf2));  
    39.         if(retval < 0){  
    40.                 perror("reading fd2 failed!");  
    41.                 goto out;  
    42.          }  
    43.          printf("<user space>: read bytes: %d   read content: %s ", retval, buf2);  
    44.   
    45.          return 0;  
    46.    out:  
    47.          if(fd1 > 0)  
    48.                close(fd1);  
    49.          if(fd2 > 0)  
    50.                close(fd2);  
    51.          return -1;  
    52.   }  

    二、手动加载驱动 .ko文件

           1、上面的demo_chardev.c文件放到内核下编译生成 .ko文件

                Makefile    

    [cpp] view plain copy
     
    1. #如果已定义KERNELRELEASE,说明是由内核构造系统调用的  
    2. #可以利用内建语句  
    3. ifneq ($(KERNELRELEASE),)   
    4.     obj-m +=demo_chrdev.o  
    5.     #此时由内核构造系统调用  
    6. else   
    7.     #定义并记录内核源码路径  
    8.     KERNELDIR = /home/hanbo/linux-2.6.35.7(自己源码路径,2.6.35.7指当前内核版本)  
    9.     #记录当前工程目录  
    10.     PWD := $(shell pwd)  
    11.   
    12. default:   
    13.     $(MAKE) -C $(KERNELDIR) M=$(PWD) modules   
    14.     @rm -rf *.o .t* .m* .*.cmd *.mod.c *.order *.symvers  
    15.    
    16. endif  
    17.    
    18. clean:  
    19.     rm -rf *.ko *.o .t* .m* .*.cmd *.mod.c *.order *.symvers         

          2、 然后用命令加载 .ko 驱动

                lsmod          列举当前系统中的所有模块

                lsmod          列举当前系统中的所有模块

                rmmod  xxx      卸载指定模块(不需要.ko后缀)

          3、如果自己编译的代码中没有用

                  /*创建设备类*/
                demo_class = class_create(THIS_MODULE,"demo_class");

                 /*创建设备文件,通知用户在“/dev/”目录下创件名字为demoX的设备文件*/

                demo_device = device_create(demo_class,NULL, MKDEV(major, i), NULL,"demo%d",i);

               则需要手动添加设备节点

                mknod /dev/demo1 c 主设备号 0

                mknod /dev/demo2 c 主设备号 1

    注意:若卸载时出现提示 rmmod:chdir(2.6.35.7):No  such  file  or  directory

              则在开发板根文件系统下创建目录:/lib/modules/2.6.35.7(跟当前内核版本同名)

  • 相关阅读:
    C#在与java对接时候的UrlEncode的坑
    sql server 删除大量数据的一次坑爹之旅
    js实现黑客帝国文字下落效果
    第一个SignalR案例
    简单的放天灯动画
    计量单位符号的书写规范【转】
    阿里云OSS搭建移动应用直传服务的.Net C#示例
    UWP Windows10开发更新磁贴和动态更新磁贴
    UWP Windows10开发获取设备位置(经纬度)
    Asp.Net识别手机访问
  • 原文地址:https://www.cnblogs.com/Ph-one/p/6720095.html
Copyright © 2011-2022 走看看