Linux驱动编程 step-by-step (二) 简单字符设备驱动
1、主次设备号
主设备号标识设备连接的的驱动,此设备好由内核使用,标识在相应驱动下得对应的设备
在linux中设备号是一个32位的dev_t类型
typedef __kernel_dev_t dev_t;
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也是)首先做的事就是申请一个或者多个设备号
- /* 静态分配设备号
- * parameter:
- * first : 分配的第一个设备号
- * count: 分配的设备个数
- * name : 设备名
- * return value:
- * 0: success
- * 负值:出现错误,错误码
- */
- int register_chrdev_region(dev_t first, unsigned int count, char *name);
- /* 动态分配设备号
- * parameter:
- * dev : 用来存储分配的设备号值
- * firstminor: 次设备号(一般填0)
- * count: 分配的设备个数
- * name : 设备名
- * return value:
- * 0: success
- * 负值:出现错误,错误码
- */
- int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);
- /* 释放设备号
- * parameter:
- * first: 设备号
- * count: 分配的设备个数
- */
- void unregister_chrdev_region(dev_t first, unsigned int count);
静态分配设备号,是在已经知道一个可用设备号的时候使用,而程序员在编写程序之前大多并知道设备号是否可用,或者现在可用,不能确保在系统升级时候次设备还是可用的
所以linux社区极力推荐使用动态分配,它会去寻找可用的设备号,而不会产生冲突。在次设备卸载的时候需要释放次设备号。
3、一个没有作用的字符设备驱动
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/fs.h>
- #define SIMPLE_DEBUG 1
- #define DEV_COUNT 2
- #define SIMPLE_NAME "simple_char"
- static int simple_major = 108;
- static int simple_minor = 0;
- static __init int simple_init(void)
- {
- dev_t dev;
- int err;
- #if SIMPLE_DEBUG
- printk(KERN_INFO "In %s\n", __func__);
- #endif
- dev = MKDEV(simple_major, simple_minor); //求取设备号
- if(dev > 0)//设备号有效
- {
- #if SIMPLE_DEBUG
- printk(KERN_INFO "try to register static char dev %d \n", dev);
- #endif
- err = register_chrdev_region(dev,DEV_COUNT, SIMPLE_NAME); //静态分配设备号
- if(err < 0) //静态分配出错 尝试使用动态分配
- {
- printk(KERN_WARNING "register static char dev error\n");
- err = alloc_chrdev_region(&dev, 0, DEV_COUNT, SIMPLE_NAME); //动态分配设备号
- if(err < 0)
- {
- printk(KERN_ERR "register char dev error in line %d\n",__LINE__);
- goto error;
- }
- else
- {
- simple_major = MAJOR(dev);//重新计算主设备号
- simple_minor = MINOR(dev);//重新计算此设备号
- }
- }
- else{
- }
- }
- else //设备号无效使用动态分配
- {
- #if SIMPLE_DEBUG
- printk(KERN_INFO "try to register alloc char dev \n");
- #endif
- err = alloc_chrdev_region(&dev, 0, DEV_COUNT, SIMPLE_NAME);
- if(err < 0)
- {
- printk(KERN_ERR "register char dev error in line %d\n\n",__LINE__);
- goto error;
- }
- else
- {
- simple_major = MAJOR(dev);
- simple_minor = MINOR(dev);
- }
- }
- #if SIMPLE_DEBUG
- printk(KERN_INFO "register char dev success major = %d minor = %d \n", simple_major, simple_minor);
- #endif
- error:
- return err;
- }
- static __exit void simple_exit(void)
- {
- dev_t dev;
- #if SIMPLE_DEBUG
- printk(KERN_INFO "In %s\n", __func__);
- #endif
- dev = MKDEV(simple_major, simple_minor);
- unregister_chrdev_region(dev, DEV_COUNT); //释放设备号
- }
- module_init(simple_init);
- module_exit(simple_exit);
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("kai_zhang(jsha.zk@163.com)");
- MODULE_DESCRIPTION("simple char driver!");
这里只在模块初始化的时候去分配设备号,在模块注销的时候去释放次驱动拥有的设备号
在函数里边我们看到用到了在应用编程里边声名狼藉的goto函数,在linux驱动编程时 goto 函数可以让我们的编程更加有条理性,在出现错误时候能更快的去处理。
如果在调用函数检查返回者都去做错误处理则模块函数就显得臃肿,庞大。所以还是建议合理使用goto函数的。
加载次模块后
运行 $cat /proc/devices可以看到 simple_char 的设备以及主设备号。
这里我们看到原来假设的主设备号是不可用的,所以使用的动态分配设备号,由此我们申请到主设备号为249,我们可以在上边添加我们的设备,具体操作下一节会讲到。呵呵留点悬念先。
Linux驱动编程 step-by-step (二) 简单字符设备驱动相关推荐
- linux内核创建字符节点,Tiny6410学习ing—(四)、嵌入式Linux内核驱动进阶—(7)、高级字符设备驱动(自动创建节点)—#931...
按照国嵌的视频教程上来说的,最后就是-自动创建设备文件! 其实我感觉以前完全可以直接是手动创建了设备文件,然后就可以直接讲述自动创建设备文件,为啥非要拖到最后来讲述,我也就不清楚了!! 不管了,写完收 ...
- Linux设备驱动开发详解【二】_设备驱动相关硬件基础知识
本文简介 本文讲解底层驱动工程师必备的硬件基础,给出了嵌入式系统硬件原理及分析方法的全景视图. 2.1 节讲解微控制器.微处理器.数字信号处理器以及应用于特定领域的处理器各自的特点. ...
- 内核实验(五):传统简单字符设备驱动
文章目录 一.篇头 二.源码 2.1 驱动关键部分 2.2 APP:test\_3\_app.c 2.3 驱动完整源码 2.4 Makefile 三.编译 3.1 编译ko 3.2 编译app 四.测 ...
- 基于简单字符设备驱动框架编写代码驱动io_2
更具体步骤查看: https://blog.csdn.net/oNelson123/article/details/110726961 https://blog.csdn.net/qq_2825888 ...
- Linux内核学习-字符设备驱动学习(二)
在Linux内核学习-字符设备驱动学习(一)中编写字符设备驱动的一种方法,但是需要手动创建设备节点. 有没有能够自动的创建设备节点的呢? 有!使用class_create()和device_creat ...
- 《Linux设备驱动程序》学习2—高级字符设备驱动ioctl
今天进入<Linux设备驱动程序>第六章高级字符设备驱动程序操作的学习,学习的过程和简单字符设备驱动程序的学习是一样的,看书,看程序,然后就是看Tek的博客笔记.依然tek的博客中对于这一 ...
- linux open函数_Linux驱动开发 / 字符设备驱动内幕 (1)
哈喽,我是老吴,继续记录我的学习心得. 一.保持专注的几个技巧 将最重要的事放在早上做. 待在无干扰环境下,比如图书馆. 意识到刚坐下开始投入工作前,有点负面小情绪是特别正常的现象. 让"开 ...
- linux内核led驱动开发,从Linux内核LED驱动来理解字符设备驱动开发流程
目录 博客说明 开发环境 1. Linux字符设备驱动的组成 1.1 字符设备驱动模块加载与卸载函数 1.2 字符设备驱动的file_operations 结构体中的成员函数 2. 字符设备驱动--设 ...
- linux驱动开发篇(四)—— platform平台设备驱动
linux系列目录: linux基础篇(一)--GCC和Makefile编译过程 linux基础篇(二)--静态和动态链接 ARM裸机篇(一)--i.MX6ULL介绍 ARM裸机篇(二)--i.MX6 ...
最新文章
- javascript publish/subscribe or observer pattern
- CDH 5 Maven Repository
- Tomcat介绍及性能优化
- java null转换jason_常见java问题及解决办法汇总(干货可收藏)
- 这些将在新一年改变你的风控内容
- ubuntu下命令行设置壁纸
- [LintCode] Coins in a Line I Coins in a Line II
- LeetCode.206. Reverse Linked List(反转有序链表)C++ and PYTHON
- FreeRTOS(教程非常详细)
- 历史类:罗马帝国兴亡史
- Visual studio 2015(VS2015)的下载和安装,以及安装VS2015中的C++
- 西门子三开接线图解_西门子三位单控开关怎么接线要开关实际图
- min-width、max-width属性中min-content、max-content的含义,css中minmax()用法、1fr单位的含义----使页面具有相应性的属性以及属性值
- 织梦html的网站地图怎么制作,网站地图如何制作?网站地图的制作与提交方法...
- 2021-05-12 MongoDB面试题 什么是MongoDB分片集群
- 计算机开机滴一声513错误,电脑滴一声开不了机怎么办_电脑一声响后就开不了机了的处理办法...
- mysql外键设置不成功_MySQL数据库建立外键失败的原因总结
- LevelDb(二):LevelDb整体架构
- 微信禁止访问国外服务器域名,域名被禁止访问?
- java的各种jar下载网址
热门文章
- boost::mpi模块all_reduce() 集合的测试
- GDCM:gdcm::PDFCodec的测试程序
- GDCM:读取UTF8 QtDir的测试程序
- Boost:将自定义占位符_1复制到arg <1>的测试程序
- VTK:Utilities之LUTUtilities
- VTK:IO之ImageReader2Factory
- VTK:图表之DirectedGraphToMutableDirectedGraph
- OpenCV运行对象检测深度学习网络的实例(附完整代码)
- C++找出数组中的第一个非重复整数的算法(附完整源码)
- C++Miller Rabin算法的实现(附完整源码)