简单字符设备驱动

1、主次设备号
主设备号标识设备连接的的驱动,此设备好由内核使用,标识在相应驱动下得对应的设备
在linux中设备号是一个32位的dev_t类型

typedef __u32    __kernel_dev_t;
typedef __kernel_dev_t    dev_t;
crw------- 1 root  root  10, 1 Apr 11  2011 psaux 
crw------- 1 root  root  4,  1 Oct 2803:04 tty1 
crw-rw-rw- 1 root  tty   4, 64 Apr 11  2011 ttys0 
crw-rw---- 1 root  uucp  4, 65 Apr 11  2011 ttyS

上图是再/dev目录下用$ls -l 命令显示的部分结果可以看到tty driver的主设备号都为4(各个系统版本有差别),次设备号不同

前12位标识主设备号 MAJOR(dev_t dev) 获得主设备号
后20位标识此设备号 MINOR(dev_t dev) 获得此设备号

由主次设备号生成设备号
可以使用宏MKDEV
dev_t  dev_num = MKDEV(dev_t major, dev_t minor);

2、分配与释放设备号

在linux2.6的字符设备中(kernel3.0也是)首先做的事就是申请一个或者多个设备号

  1. /*  静态分配设备号
  2. *  parameter:
  3. *      first : 分配的第一个设备号
  4. *      count: 分配的设备个数
  5. *      name : 设备名
  6. *  return value:
  7. *      0: success
  8. *      负值:出现错误,错误码
  9. */
  10. int register_chrdev_region(dev_t first, unsigned int count, char *name);
  11. /*  动态分配设备号
  12. *  parameter:
  13. *      dev : 用来存储分配的设备号值
  14. *      firstminor: 次设备号(一般填0)
  15. *      count: 分配的设备个数
  16. *      name : 设备名
  17. *  return value:
  18. *      0: success
  19. *      负值:出现错误,错误码
  20. */
  21. int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);
  22. /*  释放设备号
  23. *  parameter:
  24. *      first: 设备号
  25. *      count: 分配的设备个数
  26. */
  27. void unregister_chrdev_region(dev_t first, unsigned int count);

静态分配设备号,是在已经知道一个可用设备号的时候使用,而程序员在编写程序之前大多并知道设备号是否可用,或者现在可用,不能确保在系统升级时候次设备还是可用的
所以linux社区极力推荐使用动态分配,它会去寻找可用的设备号,而不会产生冲突。在次设备卸载的时候需要释放次设备号。

3、一个没有作用的字符设备驱动

  1. #include <linux/init.h>
  2. #include <linux/module.h>
  3. #include <linux/types.h>
  4. #include <linux/fs.h>
  5. #define SIMPLE_DEBUG 1
  6. #define DEV_COUNT 2
  7. #define SIMPLE_NAME "simple_char"
  8. static int simple_major = 108;
  9. static int simple_minor = 0;
  10. static __init int simple_init(void)
  11. {
  12. dev_t dev;
  13. int err;
  14. #if SIMPLE_DEBUG
  15. printk(KERN_INFO "In %s\n", __func__);
  16. #endif
  17. dev = MKDEV(simple_major, simple_minor); //求取设备号
  18. if(dev > 0)//设备号有效
  19. {
  20. #if SIMPLE_DEBUG
  21. printk(KERN_INFO "try to register static char dev  %d \n", dev);
  22. #endif
  23. err = register_chrdev_region(dev,DEV_COUNT, SIMPLE_NAME); //静态分配设备号
  24. if(err < 0) //静态分配出错 尝试使用动态分配
  25. {
  26. printk(KERN_WARNING "register static char dev error\n");
  27. err = alloc_chrdev_region(&dev, 0, DEV_COUNT, SIMPLE_NAME); //动态分配设备号
  28. if(err < 0)
  29. {
  30. printk(KERN_ERR "register char dev error in line %d\n",__LINE__);
  31. goto error;
  32. }
  33. else
  34. {
  35. simple_major = MAJOR(dev);//重新计算主设备号
  36. simple_minor = MINOR(dev);//重新计算此设备号
  37. }
  38. }
  39. else{
  40. }
  41. }
  42. else //设备号无效使用动态分配
  43. {
  44. #if SIMPLE_DEBUG
  45. printk(KERN_INFO "try to register alloc char dev  \n");
  46. #endif
  47. err = alloc_chrdev_region(&dev, 0, DEV_COUNT, SIMPLE_NAME);
  48. if(err < 0)
  49. {
  50. printk(KERN_ERR "register char dev error in line %d\n\n",__LINE__);
  51. goto error;
  52. }
  53. else
  54. {
  55. simple_major = MAJOR(dev);
  56. simple_minor = MINOR(dev);
  57. }
  58. }
  59. #if SIMPLE_DEBUG
  60. printk(KERN_INFO "register char dev success major = %d minor = %d \n", simple_major, simple_minor);
  61. #endif
  62. error:
  63. return err;
  64. }
  65. static __exit void simple_exit(void)
  66. {
  67. dev_t dev;
  68. #if SIMPLE_DEBUG
  69. printk(KERN_INFO "In %s\n", __func__);
  70. #endif
  71. dev = MKDEV(simple_major, simple_minor);
  72. unregister_chrdev_region(dev, DEV_COUNT); //释放设备号
  73. }
  74. module_init(simple_init);
  75. module_exit(simple_exit);
  76. MODULE_LICENSE("GPL");
  77. MODULE_AUTHOR("kai_zhang(jsha.zk@163.com)");
  78. MODULE_DESCRIPTION("simple char driver!");

这里只在模块初始化的时候去分配设备号,在模块注销的时候去释放次驱动拥有的设备号
在函数里边我们看到用到了在应用编程里边声名狼藉的goto函数,在linux驱动编程时 goto 函数可以让我们的编程更加有条理性,在出现错误时候能更快的去处理。
如果在调用函数检查返回者都去做错误处理则模块函数就显得臃肿,庞大。所以还是建议合理使用goto函数的。
加载次模块后 
运行 $cat /proc/devices可以看到 simple_char 的设备以及主设备号。

这里我们看到原来假设的主设备号是不可用的,所以使用的动态分配设备号,由此我们申请到主设备号为249,我们可以在上边添加我们的设备,具体操作下一节会讲到。呵呵留点悬念先。

Linux驱动编程 step-by-step (二) 简单字符设备驱动相关推荐

  1. linux内核创建字符节点,Tiny6410学习ing—(四)、嵌入式Linux内核驱动进阶—(7)、高级字符设备驱动(自动创建节点)—#931...

    按照国嵌的视频教程上来说的,最后就是-自动创建设备文件! 其实我感觉以前完全可以直接是手动创建了设备文件,然后就可以直接讲述自动创建设备文件,为啥非要拖到最后来讲述,我也就不清楚了!! 不管了,写完收 ...

  2. Linux设备驱动开发详解【二】_设备驱动相关硬件基础知识

    本文简介 本文讲解底层驱动工程师必备的硬件基础,给出了嵌入式系统硬件原理及分析方法的全景视图.         2.1 节讲解微控制器.微处理器.数字信号处理器以及应用于特定领域的处理器各自的特点. ...

  3. 内核实验(五):传统简单字符设备驱动

    文章目录 一.篇头 二.源码 2.1 驱动关键部分 2.2 APP:test\_3\_app.c 2.3 驱动完整源码 2.4 Makefile 三.编译 3.1 编译ko 3.2 编译app 四.测 ...

  4. 基于简单字符设备驱动框架编写代码驱动io_2

    更具体步骤查看: https://blog.csdn.net/oNelson123/article/details/110726961 https://blog.csdn.net/qq_2825888 ...

  5. Linux内核学习-字符设备驱动学习(二)

    在Linux内核学习-字符设备驱动学习(一)中编写字符设备驱动的一种方法,但是需要手动创建设备节点. 有没有能够自动的创建设备节点的呢? 有!使用class_create()和device_creat ...

  6. 《Linux设备驱动程序》学习2—高级字符设备驱动ioctl

    今天进入<Linux设备驱动程序>第六章高级字符设备驱动程序操作的学习,学习的过程和简单字符设备驱动程序的学习是一样的,看书,看程序,然后就是看Tek的博客笔记.依然tek的博客中对于这一 ...

  7. linux open函数_Linux驱动开发 / 字符设备驱动内幕 (1)

    哈喽,我是老吴,继续记录我的学习心得. 一.保持专注的几个技巧 将最重要的事放在早上做. 待在无干扰环境下,比如图书馆. 意识到刚坐下开始投入工作前,有点负面小情绪是特别正常的现象. 让"开 ...

  8. linux内核led驱动开发,从Linux内核LED驱动来理解字符设备驱动开发流程

    目录 博客说明 开发环境 1. Linux字符设备驱动的组成 1.1 字符设备驱动模块加载与卸载函数 1.2 字符设备驱动的file_operations 结构体中的成员函数 2. 字符设备驱动--设 ...

  9. linux驱动开发篇(四)—— platform平台设备驱动

    linux系列目录: linux基础篇(一)--GCC和Makefile编译过程 linux基础篇(二)--静态和动态链接 ARM裸机篇(一)--i.MX6ULL介绍 ARM裸机篇(二)--i.MX6 ...

最新文章

  1. javascript publish/subscribe or observer pattern
  2. CDH 5 Maven Repository
  3. Tomcat介绍及性能优化
  4. java null转换jason_常见java问题及解决办法汇总(干货可收藏)
  5. 这些将在新一年改变你的风控内容
  6. ubuntu下命令行设置壁纸
  7. [LintCode] Coins in a Line I Coins in a Line II
  8. LeetCode.206. Reverse Linked List(反转有序链表)C++ and PYTHON
  9. FreeRTOS(教程非常详细)
  10. 历史类:罗马帝国兴亡史
  11. Visual studio 2015(VS2015)的下载和安装,以及安装VS2015中的C++
  12. 西门子三开接线图解_西门子三位单控开关怎么接线要开关实际图
  13. min-width、max-width属性中min-content、max-content的含义,css中minmax()用法、1fr单位的含义----使页面具有相应性的属性以及属性值
  14. 织梦html的网站地图怎么制作,网站地图如何制作?网站地图的制作与提交方法...
  15. 2021-05-12 MongoDB面试题 什么是MongoDB分片集群
  16. 计算机开机滴一声513错误,电脑滴一声开不了机怎么办_电脑一声响后就开不了机了的处理办法...
  17. mysql外键设置不成功_MySQL数据库建立外键失败的原因总结
  18. LevelDb(二):LevelDb整体架构
  19. 微信禁止访问国外服务器域名,域名被禁止访问?
  20. java的各种jar下载网址

热门文章

  1. boost::mpi模块all_reduce() 集合的测试
  2. GDCM:gdcm::PDFCodec的测试程序
  3. GDCM:读取UTF8 QtDir的测试程序
  4. Boost:将自定义占位符_1复制到arg <1>的测试程序
  5. VTK:Utilities之LUTUtilities
  6. VTK:IO之ImageReader2Factory
  7. VTK:图表之DirectedGraphToMutableDirectedGraph
  8. OpenCV运行对象检测深度学习网络的实例(附完整代码)
  9. C++找出数组中的第一个非重复整数的算法(附完整源码)
  10. C++Miller Rabin算法的实现(附完整源码)