当前位置: 首页 > news >正文

/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\n",  
  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\n",  
  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\n",  
  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\n",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\n",  
  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\n");  
  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\n");  
  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\n", 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\n", 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(跟当前内核版本同名)

转载于:https://www.cnblogs.com/Ph-one/p/6720095.html

相关文章:

  • memcpy
  • ubuntu主板信息
  • 秒懂单链表及其反转(reverse)
  • C语言一个单链表的实现
  • linux 一个超简单的makefile
  • C语言一个双向链表的实现
  • 如何只在堆或者栈上分配类对象
  • mtk6589显示子系统笔记(一)
  • 如何配置DSI时钟频率
  • /dev/sda2 is mounted; will not make a filesystem here!
  • 怎样使用alsa API
  • ubuntu下如下错误alsa/asoundlib.h: No such file or directory
  • ubuntu:undefined reference to `snd_pcm_open'
  • ubuntu 12.04安装alsa-lib、alsa-utils【转】
  • malloc、calloc、realloc和alloca各种的区别
  • 【Amaple教程】5. 插件
  • iOS筛选菜单、分段选择器、导航栏、悬浮窗、转场动画、启动视频等源码
  • js中forEach回调同异步问题
  • Laravel5.4 Queues队列学习
  • Node项目之评分系统(二)- 数据库设计
  • Vue 重置组件到初始状态
  • Zepto.js源码学习之二
  • 阿里云爬虫风险管理产品商业化,为云端流量保驾护航
  • 安卓应用性能调试和优化经验分享
  • 从输入URL到页面加载发生了什么
  • 基于Javascript, Springboot的管理系统报表查询页面代码设计
  • 开源SQL-on-Hadoop系统一览
  • 聊聊spring cloud的LoadBalancerAutoConfiguration
  • 面试总结JavaScript篇
  • 学习HTTP相关知识笔记
  • 学习JavaScript数据结构与算法 — 树
  • 一起来学SpringBoot | 第十篇:使用Spring Cache集成Redis
  • 从如何停掉 Promise 链说起
  • 教程:使用iPhone相机和openCV来完成3D重建(第一部分) ...
  • ​​​​​​​GitLab 之 GitLab-Runner 安装,配置与问题汇总
  • ​LeetCode解法汇总2304. 网格中的最小路径代价
  • ### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTr
  • #《AI中文版》V3 第 1 章 概述
  • (day 12)JavaScript学习笔记(数组3)
  • (机器学习-深度学习快速入门)第一章第一节:Python环境和数据分析
  • (十一)图像的罗伯特梯度锐化
  • (原創) 如何安裝Linux版本的Quartus II? (SOC) (Quartus II) (Linux) (RedHat) (VirtualBox)
  • (转)Linux整合apache和tomcat构建Web服务器
  • .Family_物联网
  • .net core webapi Startup 注入ConfigurePrimaryHttpMessageHandler
  • [Android] 修改设备访问权限
  • [Android]How to use FFmpeg to decode Android f...
  • [Android]通过PhoneLookup读取所有电话号码
  • [CUDA 学习笔记] CUDA kernel 的 grid_size 和 block_size 选择
  • [EFI]MSI GF63 Thin 9SCXR电脑 Hackintosh 黑苹果efi引导文件
  • [FROM COM张]如何解决Nios II SBTE中出现的undefined reference to `xxx'警告
  • [fsevents@^2.1.2] optional install error: Package require os(darwin) not compatible with your platfo
  • [hdu1561] The more, The Better 【树形DP】
  • [iOS]-网络请求总结
  • [iOS开发]iOS中TabBar中间按钮凸起的实现