杂项设备(misc device)和字符设备(char device)区别

2023-11-17

杂项设备(misc device)
杂项设备也是在嵌入式系统中用得比较多的一种设备驱动。在 Linux 内核的include/linux目录下有Miscdevice.h文件,要把自己定义的misc device从设备定义在这里。其实是因为这些字符设备不符合预先确定的字符设备范畴, 所有这些设备采用主编号10 ,一起归于misc device,其实misc_register就是用主标号10调用register_chrdev()的。
也就是说,misc设备其实也就是特殊的字符设备,可自动生成设备节点
查询其次设备号的方法是:

cat /proc/misc

字符设备(char device)
使用register_chrdev(LED_MAJOR,DEVICE_NAME,&dev_fops)注册字符设备驱动程序时,如果有多个设 备使用该函数注册驱动程序,LED_MAJOR不能相同,否则几个设备都无法注册(我已验证)。如果模块使用该方式注册并且 LED_MAJOR 为0(自动分配主设备号 ),使用insmod命令加载模块时会在终端显示分配的主设备号和次设备号,在/dev目录下建立该节点,比如 设备leds,如果加载该模块时分配的主设备号和次设备号为253和0,则建立节点:mknod leds c 253 0。使用 register_chrdev(LED_MAJOR,DEVICE_NAME,&dev_fops)注册字符设备驱动程序时都 要手动建立节点 ,否则在应用程序无法打开该设备。
阅读led驱动程序的代码的时候,没有发现ldd3中提到的各种字符设备注册函数,而是发现了一个misc_register函数,这说明led设备是作为杂项设备出现在内核中的,在内核中,misc杂项设备驱动接口是对一些字符设备的简单封装,他们共享一个主设备号,有不同的次设备号,共享一个open调用,其他的操作函数在打开后运用linux驱动程序的方法重载进行装载。

  1. 主要数据结构
    内核维护一个misc_list链表,misc设备在misc_register注册的时候链接到这个链表,在misc_deregister中解除链接。主要的设备结构就是miscdevice。定义如下:
struct miscdevice  {
	int minor;
	const char *name;
	const struct file_operations *fops;
	struct list_head list;
	struct device *parent;
	struct device *this_device;
	const char *nodename;
	mode_t mode;
};

这个结构体是misc设备基本的结构体,在注册misc设备的时候必须要声明并初始化一个这样的结构体,但其中一般只需填充name minor fops字段就可以了。下面就是led驱动程序中初始化miscdevice的代码:

static struct miscdevice misc = {
	.minor = MISC_DYNAMIC_MINOR,
	.name = DEVICE_NAME,
	.fops = &dev_fops,
};

一般的时候在fops不用实现open方法,因为最初的方法misc_ops包含了open方法。其中minor如果填充MISC_DYNAMIC_MINOR,则是动态次设备号,次设备号由misc_register动态分配的。
2. misc_init 函数
misc也是作为一个模块被加载到内核的,只不过是静态模块。这个函数是misc静态模块加载时的初始化函数。

static int __init misc_init(void)
{
	int err;
 
 
#ifdef CONFIG_PROC_FS
	proc_create("misc", 0, NULL, &misc_proc_fops);
#endif
	misc_class = class_create(THIS_MODULE, "misc");
        //udev创建设备节点使用
	err = PTR_ERR(misc_class);
	if (IS_ERR(misc_class))
		goto fail_remove;
 
 
	err = -EIO;
	if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) //注册一个字符设备
		goto fail_printk;
	misc_class->devnode = misc_devnode;
	return 0;
 
 
fail_printk:
	printk("unable to get major %d for misc devices\n", MISC_MAJOR);
	class_destroy(misc_class);
fail_remove:
	remove_proc_entry("misc", NULL);
	return err;
}

可以看出,这个初始化函数,最主要的功能就是注册字符设备 ,所用的注册接口是2.4内核的register_chrdev。它注册了主设备号为MISC_MAJOR,次设备号为0-255的256个设备。并且创建了一个misc类。
3. misc_register()函数
misc_register()函数在misc.c中,最主要的功能是基于misc_class构造一个设备,将miscdevice结构挂载到misc_list列表上,并初始化与linux设备模型相关的结构,它的参数是miscdevice结构体。

int misc_register(struct miscdevice * misc)
{
	struct miscdevice *c;
	dev_t dev;
	int err = 0;
 
 
	INIT_LIST_HEAD(&misc->list);  //链表项使用时必须初始化
 
 
	mutex_lock(&misc_mtx);
	list_for_each_entry(c, &misc_list, list) {
		if (c->minor == misc->minor) {
			mutex_unlock(&misc_mtx);
			return -EBUSY;
		}
	} //遍历链表如果发现次设备号一样的,返回错误
 
 
	if (misc->minor == MISC_DYNAMIC_MINOR) {  //动态次设备号
		int i = DYNAMIC_MINORS;
		while (--i >= 0)
			if ( (misc_minors[i>>3] & (1 << (i&7))) == 0)
				break;
		if (i<0) {
			mutex_unlock(&misc_mtx);
			return -EBUSY;
		}
		misc->minor = i;
	}
 
 
	if (misc->minor < DYNAMIC_MINORS)
		misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7);
	dev = MKDEV(MISC_MAJOR, misc->minor);
 
 
	misc->this_device = device_create(misc_class, misc->parent, dev,
					  misc, "%s", misc->name);
        //udev创建设备节点使用,linux设备模型相关
	if (IS_ERR(misc->this_device)) {
		err = PTR_ERR(misc->this_device);
		goto out;
	}
 
 
	/*
	 * Add it to the front, so that later devices can "override"
	 * earlier defaults
	 */
	list_add(&misc->list, &misc_list); //添加到misc_list之中
 out:
	mutex_unlock(&misc_mtx);
	return err;
}

可以看出,这个函数首先遍历misc_list链表,查找所用的次设备号是否已经被注册,防止冲突。如果是动态次设备号则分配一个,然后调用MKDEV生成设备号,从这里可以看出所有的misc设备共享一个主设备号MISC_MAJOR,然后调用device_create,生成设备文件。最后加入到misc_list链表中。
关于device_create,class_create 作用: class_create函数在misc.c中的模块初始化中被调用,现在一起说一下。这两个函数看起来很陌生,没有在ldd3中发现过,看源代码的时候发现class_create会调用底层组件__class_regsiter()是说明它是注册一个类。而device_create是创建一个设备,他是创建设备的便捷实现调用了device_register函数。他们都提供给linux设备模型使用,从linux内核2.6的某个版本之后,devfs不复存在,udev成为devfs的替代。相比devfs,udev有很多优势。
struct class *myclass = class_create(THIS_MODULE, “my_device_driver”);
class_device_create(myclass, NULL, MKDEV(major_num, 0), NULL, “my_device”);
这样就创建了一个类和设备,模块被加载时,udev daemon就会自动在/dev下创建my_device设备文件节点。这样就省去了自己创建设备文件的麻烦。这样也有助于动态设备的管理。
4. 总结
杂项设备作为字符设备的封装,为字符设备提供的简单的编程接口,如果编写新的字符驱动,可以考虑使用杂项设备接口,方便简单,只需要初始化一个miscdevice的结构,调用misc_register就可以了。系统最多有255个杂项设备,因为杂项设备模块自己占用了一个次设备号。可以发现,mini2440很多字符设备都是以杂项设备注册到内核的,如mini2440_buttons,mini2440_adc,mini2440_pwm等。

为什么linux驱动要专门有杂项设备呢?字符设备不就可以了吗?
作者:智多芯
链接:https://www.zhihu.com/question/21508904/answer/19623523
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

第一,节省主设备号:使用普通字符设备,不管该驱动的主设备号是静态还是动态分配,都会消耗一个主设备号,这太浪费了。而且如果你的这个驱动最终会提交到内核主线版本上的话,需要申请一个专门的主设备号,这也麻烦。如果使用misc驱动的话就好多了。因为内核中已经为misc驱动分配了一个主设备号。当系统中拥有多个misc设备驱动时,那么它们的主设备号相同,而用子设备号来区分它们。
第二,使用简单:有时候驱动开发人员需要开发一个功能较简单的字符设备驱动,导出接口让用户空间程序方便地控制硬件,只需要使用misc子系统提供的接口即可快速地创建一个misc设备驱动。当使用普通的字符设备驱动时,如果开发人员需要导出操作接口给用户空间的话,需要自己去注册字符驱动,并创建字符设备class以自动在/dev下生成设备节点,相对麻烦一点。而misc驱动则无需考虑这些,基本上只需要把一些基本信息通过struct miscdevice交给misc_register()去处理即可。本质上misc驱动也是一个字符设备驱动,可能相对特殊一点而已。在drivers/char/misc.c的misc驱动初始化函数misc_init()中实际上使用了MISC_MAJOR(主设备号为10)并调用register_chrdev()去注册了一个字符设备驱动。同时也创建了一个misc_class,使得最后可自动在/dev下自动生成一个主设备号为10的字符设备。总的来讲,如果使用misc驱动可以满足要求的话,那么这可以为开发人员省下不少麻烦。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

杂项设备(misc device)和字符设备(char device)区别 的相关文章

  • 如何查明 Ubuntu 上安装了哪个版本的 GTK+?

    我需要确定 Ubuntu 上安装了哪个版本的 GTK 男人似乎不帮忙 这个建议 https stackoverflow com a 126145 会告诉您安装了哪个 2 0 的次要版本 不同的主要版本将具有不同的包名称 因为它们可以在系统上
  • 操作系统什么时候清除进程的内存

    进程在某些操作系统上成功或异常终止 操作系统何时决定擦除分配给该进程的内存 数据 代码等 在退出时或当它想为新进程分配内存时 这个清除内存分配过程在所有操作系统 winXP Win7 linux Mac 上都相同吗 据我了解 页表具有该进程
  • 怎样才能使 Windows 成为一个开箱即用的 POSIX 兼容操作系统?

    这个问题的动机是我的一个牵强的梦想 即 nix 平台上可用的许多优秀软件可以轻松移植到 Windows 微软最近对开源和开放性采取了不同的方法 所以我真的很想知道如果微软有这样的倾向 这样的事情会有多可行 我很好奇的一些更具体的事情是 是否
  • 如何使用AWK脚本检查表的所有列数据类型? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 在这里 我正在检查表中第一列的数据类型 但我想知道AWK中表的所有列数据类型 我尝试过 但只能获得一列数据类型 例如 Column 1
  • linux x86 汇编语言 sys_read 调用的第一个参数应为 0 (stdin)

    我正在编写一个简单的汇编程序来从标准输入读取 如 scanf 这是我的代码 section bss num resb 5 section txt global start start mov eax 3 sys read mov ebx 0
  • 如何让“grep”从文件中读取模式?

    假设有一个很大的文本文件 我只想打印与某些模式不匹配的行 显然 我可以使用egrep v patter1 pattern2 pattern3 现在 如果所有这些模式都在一个文本文件中怎么办 最好的制作方法是什么egrep从文件中读取模式 g
  • 如何在特定 systemd 服务重新启动时触发自定义脚本运行

    我想知道如何安排自定义脚本在重新启动服务时运行 我的用例是 每当重新启动 Tomcat 服务时 我都必须运行多个命令 我想知道是否有一种方法可以编写脚本并安排它在重新启动 Tomcat 服务时运行 我已将 tomcat 脚本设置为 syst
  • 劫持系统调用

    我正在编写一个内核模块 我需要劫持 包装一些系统调用 我正在暴力破解 sys call table 地址 并使用 cr0 来禁用 启用页面保护 到目前为止一切顺利 一旦完成 我将公开整个代码 因此如果有人愿意 我可以更新这个问题 无论如何
  • Composer 安装要求

    我正在尝试将 Composer 安装到 Laravel 项目中 当我做的时候sudo composer install在项目目录中它显示了两个错误 Problem 1 Installation request for simplesoftw
  • Docker:处理 tar 文件时出错(退出状态 1):设置枢轴目录时出错:不是目录

    我是 Docker 新手 不知道是什么原因导致此错误或如何诊断它 任何有关此问题的具体帮助或有关首先检查何处以诊断此类问题的提示将不胜感激 我的 Dockerfile FROM java 8 Install maven RUN apt ge
  • Linux shell 脚本中的 while 循环超时

    这工作正常 无限循环 while TRUE do printf done 我在尝试着timeout this while loop与timeout命令 所有这些都不起作用 timeout 5 while TRUE do printf don
  • 如何使用 sed 仅删除双空行?

    我找到了这个问题和答案 https stackoverflow com questions 4651591 howto use sed to remove only triple empty lines关于如何删除三重空行 但是 我只需要对
  • 如何制作和应用SVN补丁?

    我想制作一个SVN类型的补丁文件httpd conf这样我就可以轻松地将其应用到其他主机上 If I do cd root diff Naur etc httpd conf httpd conf original etc httpd con
  • .NET Core 中的跨平台文件名处理

    如何处理文件名System IO以跨平台方式运行类以使其在 Windows 和 Linux 上运行 例如 我编写的代码在 Windows 上完美运行 但它不会在 Ubuntu Linux 上创建文件 var tempFilename Dat
  • xsel -o 对于 OS X 等效项

    是否有一个等效的解决方案可以在 OS X 中抓取选定的文本 就像适用于 Linux 的 xsel o 一样 只需要当前的选择 这样我就可以在 shell 脚本中使用文本 干杯 埃里克 你也许可以安装xsel在 MacOS 上 更新 根据 A
  • ansible 重新启动 2.1.1.0 失败

    我一直在尝试创建一个非常简单的 Ansible 剧本 它将重新启动服务器并等待它回来 我过去在 Ansible 1 9 上有一个可以运行的 但我最近升级到 2 1 1 0 并且失败了 我正在重新启动的主机名为 idm IP 为 192 16
  • 如何修复“iptables:没有该名称的链/目标/匹配”?

    我在我的 Linux 嵌入式系统上构建并安装了 iptables 如果我列出所有规则 则一切正常 iptables list Chain INPUT policy ACCEPT target prot opt source destinat
  • 何时使用 pthread 条件变量?

    线程问题 看来 只有在其他线程调用 pthread cond notify 之前调用 pthread cond wait 时 条件变量才起作用 如果在等待之前发生通知 那么等待将被卡住 我的问题是 什么时候应该使用条件变量 调度程序可以抢占
  • 修改linux下的路径

    虽然我认为我已经接近 Linux 专业人士 但显然我仍然是一个初学者 当我登录服务器时 我需要使用最新版本的R 统计软件 R 安装在 2 个地方 当我运行以下命令时 which R I get usr bin R 进而 R version
  • awk 子串单个字符

    这是columns txt aaa bbb 3 ccc ddd 2 eee fff 1 3 3 g 3 hhh i jjj 3 kkk ll 3 mm nn oo 3 我可以找到第二列以 b 开头的行 awk if substr 2 1 1

随机推荐

  • unity粒子系统

    添加粒子系统 按照GameObject gt Effect gt Particle System顺序 添加粒子系统 效果如下 粒子系统有其独特的组件 Particle System 展开上面的一系列属性中的Particle System 调
  • 机器学习加速器文献整理

    William J Dally 团队 文献一SCNN An Accelerator for Compresse d sparse Convolutional Neural Networks1 文献二EIE Efficient Inferen
  • DirectX9 SDK Samples(12) CustomUI Sample

    这一次的例子是关于DXUT的UI 下面先翻译文档中的比较重要的说明 这个例子开始时定义了两个CDXUTDialog对象 g HUD和g SampleUI 一个CDXUTDialog是一个装入了一个或多个控件 按钮等 的容器 对话框 CDXU
  • 部分HTTPS网站无法访问的可能原因

    最近访问一些HTTPS的网站 总有一些网站无法正常访问 总是提示证书过期 查看了下对应网站的证书 没到期呀 于是总认为是自己系统或者浏览器的问题 可查来查去 改来改去也无法解决问题 直到仔细观察了下证书颁发机构 才发现都是一个机构的 Let
  • java swing 日志_springBoot swing 界面实现配置和日志打印

    packagecom adao simulater swing importcom adao simulater common Constant importcom adao simulater common PropertiesUtil
  • http请求与Request常用方法

    一 http请求 HTTP请求报文由3部分组成 请求行 请求头 请求体 是请求方法 GET和POST是最常见的HTTP方法 除此以外还包括DELETE HEAD OPTIONS PUT TRACE 不过 当前的大多数浏览器只支持GET和PO
  • 安装cnpm(傻瓜式通俗移动)

    1 首先确保自己安装好node并且npm能正常使用 2 以管理员身份打开cmd 3 输入npm install g cnpm registry https registry npm taobao org并运行 4 等待安装结束后 输入 cn
  • PWM调光调色温技术学习(笔记)

    前言 在智能化的浪潮中 智能照明是智能家居中非常重要的一部分 由于LED照明的大量普及 相对于传统的节能灯和白炽灯 LED照明的可塑性强很多 这其中LED灯的亮度调节和色温调节已经成为智能照明的主流需求 本文就从LED照明的亮度调节 色温调
  • [网络安全自学篇] 三十一.文件上传之Upload-labs靶场及CTF题目01-10(四)

    这是作者的系列网络安全自学教程 主要是关于安全工具和实践操作的在线笔记 特分享出来与博友们学习 希望您们喜欢 一起进步 前文分享了编辑器漏洞和IIS高版本文件上传漏洞 包括FCKeditor eWebEditor 畸形解析漏洞等 本篇文章将
  • Linux 如何快速查看 IP 地址

    查看IP 1 进入Linux 系统 在主页面空旷的地方右键 选择 打开终端 2 在显示的界面中输入 ifconfig a 就可以查看到Linux 的地址了 快速查看IP 和修改 1 点击应用程序 gt 选择系统工具 选择设置 gt 找到网络
  • Ubuntu 安装 zshell

    一 检查系统中原来的shell cat etc shells 二 安装 zsh apt install zsh 安装zsh chsh s bin zsh 将zsh设置成默认shell 不设置的话启动zsh只有直接zsh命令即可 三 安装oh
  • 二叉树知识总结

    一 前言 数组的搜索比较方便 可以直接用下标 但删除和插入就比较麻烦 链表与之相反 删除和插入元素很快 但查找比较慢 此时 二叉树应运而生 二叉树既有链表的好处 也有数组的好处 在处理大批量的动态数据时比较好用 是一种折中的选择 文件系统和
  • 线程——一个计数器计数到100,在每个数字之间暂停1秒,每隔10个数字输出一个字符串

    16 一个计数器计数到100 在每个数字之间暂停1秒 每隔10个数字输出一个字符串 public class MyThread extends Thread public void run for int i 0 i lt 100 i if
  • Qt 环境搭建

    安装QtCreator 进入Qt官网https www qt io zh cn 点击下载按钮 然后选择试用Qt 这里下载的是免费版本 也就是社区版本 如果点击购买则下载专业版 点击下载后需要填写个人信息 填好邮箱和手机 还需要填写用途 并选
  • 【基于深度学习的生活垃圾分类识别管理可视化系统-哔哩哔哩】 https://b23.tv/0UBohX2

    基于深度学习的生活垃圾分类识别管理可视化系统 哔哩哔哩 https b23 tv 0UBohX2 https b23 tv 0UBohX2
  • 【前端】Vue+Element UI案例:通用后台管理系统-Header+导航栏折叠

    文章目录 目标 代码 0 创建组件 1 按钮 2 头像下拉框 3 去除左右缝隙 4 点击按钮折叠导航栏 Vuex 5 折叠标题和Header效果 总代码 CommonHeader vue store的index js store的tab j
  • 误区 一下代码是曾经误认为 radio的onclick 事件在 发生 以下是实例代码

    实际上onclick事件还是在radio上发生 只不过是通过js把 a 标签的href属性的 值 给动态的发生该表了而已 误以为是在 a 标签上发生了onclick事件 a a
  • playwright自动化项目搭建

    具备功能 关键技术 pylaywright测试库 pytest单元测试框架 pytest playwright插件 非关键技术 pytest html插件 pytest rerunfailures插件 seldom 测试框架 实现功能 元素
  • 静态链接原理以及过程

    通常程序的编译中 或多或少会调用其它库中的函数接口 本篇blog就是讲静态库的调用流程 通常我们知道编译一个可执行程序会有这四个过程 预处理 编译 汇编以及链接 前面三步就是产生目标文件 o的过程 链接就是把各个 o文件粘在一起 构成一个可
  • 杂项设备(misc device)和字符设备(char device)区别

    杂项设备 misc device 杂项设备也是在嵌入式系统中用得比较多的一种设备驱动 在 Linux 内核的include linux目录下有Miscdevice h文件 要把自己定义的misc device从设备定义在这里 其实是因为这些