Linux驱动程序工作原理简介
Linux设备驱动程序原理及框架-内核模块入门篇

Linux设备驱动程序原理及框架-内核模块入门篇内核模块介绍应用层加载模块操作过程内核如何支持可安装模块内核提供的接口及作用模块实例内核模块内核模块介绍Linux采用的是整体式的内核结构,这种结构采用的是整体式的内核结构,采用的是整体式的内核结构的内核一般不能动态的增加新的功能。
为此,的内核一般不能动态的增加新的功能。
为此,Linux提供了一种全新的机制,叫(可安装) 提供了一种全新的机制,可安装) 提供了一种全新的机制模块” )。
利用这个机制“模块”(module)。
利用这个机制,可以)。
利用这个机制,根据需要,根据需要,在不必对内核重新编译链接的条件将可安装模块动态的插入运行中的内核,下,将可安装模块动态的插入运行中的内核,成为内核的一个有机组成部分;成为内核的一个有机组成部分;或者从内核移走已经安装的模块。
正是这种机制,走已经安装的模块。
正是这种机制,使得内核的内存映像保持最小,的内存映像保持最小,但却具有很大的灵活性和可扩充性。
和可扩充性。
内核模块内核模块介绍可安装模块是可以在系统运行时动态地安装和卸载的内核软件。
严格来说,卸载的内核软件。
严格来说,这种软件的作用并不限于设备驱动,并不限于设备驱动,例如有些文件系统就是以可安装模块的形式实现的。
但是,另一方面,可安装模块的形式实现的。
但是,另一方面,它主要用来实现设备驱动程序或者与设备驱动密切相关的部分(如文件系统等)。
密切相关的部分(如文件系统等)。
课程内容内核模块介绍应用层加载模块操作过程内核如何支持可安装模块内核提供的接口及作用模块实例内核模块应用层加载模块操作过程内核引导的过程中,会识别出所有已经安装的硬件设备,内核引导的过程中,会识别出所有已经安装的硬件设备,并且创建好该系统中的硬件设备的列表树:文件系统。
且创建好该系统中的硬件设备的列表树:/sys 文件系统。
(udev 服务就是通过读取该文件系统内容来创建必要的设备文件的。
)。
linux usb wifi驱动开发原理

linux usb wifi驱动开发原理Linux USB WiFi驱动开发原理一、引言随着无线网络的普及,WiFi成为了人们生活中不可或缺的一部分。
而在Linux操作系统中,为了支持各种WiFi设备,需要进行对应的驱动开发。
本文将介绍Linux USB WiFi驱动开发的原理和过程。
二、USB WiFi驱动开发的基本原理1. USB接口USB(Universal Serial Bus)是一种通用的串行总线标准,用于连接计算机与外部设备。
USB WiFi设备通过USB接口与计算机通信,传输数据和控制命令。
2. 驱动程序驱动程序是用于操作和控制硬件设备的软件。
USB WiFi驱动程序负责与USB WiFi设备进行通信,实现数据的传输和接收。
驱动程序需要与操作系统紧密结合,通过操作系统提供的API接口与设备进行交互。
三、USB WiFi驱动开发的过程1. 设备识别与初始化USB WiFi设备插入计算机后,操作系统会通过USB子系统进行设备的识别和初始化。
在Linux系统中,USB设备的识别和初始化由USB核心驱动完成。
核心驱动会根据设备的VID(Vendor ID)和PID (Product ID)来匹配对应的驱动程序。
2. 驱动程序注册驱动程序需要在Linux系统中进行注册,以便系统能够正确识别和加载驱动。
注册过程通常包括向系统注册设备类型、设备ID等信息。
3. 设备操作接口的实现驱动程序需要实现设备操作接口,包括设备的打开、关闭、读取数据、写入数据等功能。
这些操作接口是通过USB子系统提供的API 来实现的。
4. 数据传输与控制USB WiFi驱动程序需要实现数据的传输和控制功能。
数据传输主要包括从设备读取数据和向设备写入数据,而控制功能包括设置设备参数、配置网络等操作。
5. 错误处理与调试在USB WiFi驱动开发中,错误处理和调试是非常重要的一部分。
驱动程序需要处理各种异常情况,如设备断开连接、传输错误等。
linux virtio原理

linux virtio原理Linux virtio是一种用于虚拟化的设备驱动程序框架,它允许虚拟机与宿主机之间进行高效的通信和数据传输。
本文将从人类的视角出发,对Linux virtio的原理进行描述。
在虚拟化环境中,虚拟机需要与宿主机进行通信,传输数据。
而传统的基于软件模拟的设备驱动程序会导致性能瓶颈,限制了虚拟机的性能。
为了解决这个问题,Linux引入了virtio,它是一种轻量级的设备驱动程序框架。
virtio的原理是基于一种称为"virtqueues"的通信机制。
它通过创建一对队列来实现虚拟机和宿主机之间的通信。
每个队列都有一个描述符表和一个可用环,用于描述数据的传输和状态的通知。
当虚拟机需要发送数据给宿主机时,它将数据写入描述符表中的一个描述符,并通知宿主机更新可用环。
宿主机会检查可用环中的描述符,并根据描述符中的信息来读取数据。
类似地,当宿主机需要向虚拟机发送数据时,它会将数据写入描述符表中的一个描述符,并通知虚拟机更新可用环。
虚拟机会检查可用环中的描述符,并根据描述符中的信息来读取数据。
virtio的优势在于它的高性能和低延迟。
虚拟机和宿主机之间的数据传输是直接的,减少了不必要的复制和上下文切换。
此外,virtio提供了一些高级功能,如中断处理和共享内存,进一步提高了性能和灵活性。
总结一下,Linux virtio是一种用于虚拟化的设备驱动程序框架,通过使用virtqueues实现虚拟机和宿主机之间的高效通信和数据传输。
它的原理简单而有效,能够提供高性能和低延迟的虚拟化解决方案。
通过使用virtio,我们能够充分发挥虚拟机的性能,提高虚拟化环境的效率。
qt linuxfb原理

qt linuxfb原理摘要:1.引言2.Linux FB介绍3.QT与Linux FB的关系4.QT for Linux FB的工作原理5.结论正文:Linux FB(Framebuffer)是一个用于显示图形图像的设备驱动程序,它为上层应用程序提供了一个统一的图形接口。
QT(Qt)是一款跨平台的C++应用程序框架,广泛应用于图形界面开发。
在Linux系统中,QT通过Linux FB实现图形输出。
本文将详细介绍QT for Linux FB的工作原理。
1.引言Linux系统中的图形设备驱动程序负责管理图形硬件设备,向上层提供统一的图形接口。
Linux FB是Linux内核中提供的一个图形设备驱动程序,它支持多种硬件设备,为应用程序提供了一个标准的图形接口。
QT是一款跨平台的C++应用程序框架,提供了丰富的图形界面组件。
在Linux系统中,QT通过Linux FB实现图形输出。
2.Linux FB介绍Linux FB,即Framebuffer,是Linux内核中提供的一个图形设备驱动程序。
它的主要功能是将图形命令转换为硬件设备可以识别的信号,从而实现图形输出。
Linux FB支持多种硬件设备,包括CRT显示器、液晶显示器、投影仪等。
它为上层应用程序提供了一个统一的图形接口,简化了图形编程。
3.QT与Linux FB的关系QT是一款跨平台的C++应用程序框架,提供了丰富的图形界面组件。
在Linux系统中,QT通过Linux FB实现图形输出。
具体来说,QT使用Linux FB的图形设备驱动程序,将应用程序的图形命令转换为硬件设备可以识别的信号,从而实现图形输出。
此外,QT还提供了一套与Linux FB紧密集成的输入设备驱动程序,支持鼠标、键盘等输入设备的操作。
4.QT for Linux FB的工作原理QT for Linux FB的工作原理可以分为以下几个步骤:(1)初始化:在应用程序启动时,QT会调用Linux FB的初始化函数,创建一个与Linux FB相关的QT对象。
Linux的驱动开发分析

f o r ( 1 e f t= c o u n t :l e f t>O :l e f t 一 _ ) {
. .
p u t u s e r ( 1 ,b u r ,1 ) ;
.
2 驱 动程 序原 理
编写设备 驱动程序 的原 理即基于I / O 设备管理 采用的分层 模 型, l / 0 设备 管理 软件位于 内核 中的最底层 , 设备驱动程 序是
-
r e a ( V E R I F YW i f ( v e r i f ya R I T E , b u r , c o u n t ) ==
— —
E F A U L T)
r e t u r n — E F A U L T ;
性 能得到提高 。 许 多广泛应 用的嵌入 式L i n u x 系 统都 采用静态 链接 的设备驱动程序模块。
( 1 ) 工作原理 。 作为内核 的一部分, 设各驱动程 序完 成对 设
据、 读 取应用程序传 送给设备文件 的数 据和 回送应用程 序请求 的数据和 检测处理设备 出现 的错 误的功能。 L i n u x 设备主要分
s t a t i c i n t o p e n
{ i n t l e f t :
化, 尽可能地精简。 嵌入 式L i n u x 系统不能够像桌面L i n u x  ̄ g 样
灵活 地使 用i n s m o d / r m m o d 力 口 载卸载设备驱 动程序 。 从嵌 入式 系统 的整 体性能考虑 , 采用静态链接模块能够使得整 个系统 的
设计分析 ・
L i n u x 的驱动开发分析
姜远志 ( 太原师范 学院 , 山 西 太原 0 3 0 0 0 0 )
linux 驱动的 ioctl 详细说明

linux 驱动的 ioctl 详细说明Linux驱动的ioctl详细说明在Linux操作系统中,ioctl是一种系统调用,它允许用户空间程序与设备驱动程序进行通信。
ioctl通过发送特定的命令给设备驱动程序来控制设备或者获得设备的状态信息。
ioctl的基本语法如下:```cint ioctl(int fd, unsigned long request, ...);```- fd参数是设备文件描述符,用于打开设备文件并与设备进行通信。
- request参数是一个无符号长整型,表示ioctl命令的请求码,用于指定具体的操作。
- 第三个参数是可选的,它是一些特定操作所需的额外参数。
设备驱动程序通过实现ioctl函数来处理特定的ioctl请求。
在驱动程序中,ioctl函数包含了一个switch语句来根据传入的请求码执行相应的操作。
通常,这些请求码会在头文件中定义。
例如,以下是一个虚拟设备驱动程序中的ioctl函数的示例:```c#include <linux/ioctl.h>#define MY_IOCTL_MAGIC 'k'#define MY_IOCTL_RESET _IO(MY_IOCTL_MAGIC, 0)#define MY_IOCTL_SET_DATA _IOW(MY_IOCTL_MAGIC, 1, int)#define MY_IOCTL_GET_DATA _IOR(MY_IOCTL_MAGIC, 2, int) long my_device_ioctl(struct file *file, unsigned int cmd, unsigned long arg) {int data;switch(cmd) {case MY_IOCTL_RESET:// 执行设备重置操作break;case MY_IOCTL_SET_DATA:if (copy_from_user(&data, (int *)arg, sizeof(int)) != 0) {// 错误处理break;}// 执行设置数据操作break;case MY_IOCTL_GET_DATA:data = 123; // 假设设备返回的数据if (copy_to_user((int *)arg, &data, sizeof(int)) != 0) {// 错误处理break;}// 执行获取数据操作break;default:// 错误处理break;}return 0;}```在上述示例中,我们定义了三个ioctl命令的请求码:MY_IOCTL_RESET,MY_IOCTL_SET_DATA和MY_IOCTL_GET_DATA。
linux驱动面试题

linux驱动面试题Linux驱动是指在Linux操作系统中,用于控制与硬件之间的交互和通信的软件模块。
在Linux的工作环境中,驱动程序起着至关重要的作用。
如果你准备参加Linux驱动的面试,以下是一些常见的Linux驱动面试题,希望可以对你有所帮助。
一、简述Linux驱动的作用和功能。
Linux驱动是一种软件模块,用来控制硬件设备与操作系统之间的通信和交互。
它负责将输入/输出请求传递给硬件设备,并处理来自硬件设备的中断和事件。
Linux驱动的功能包括设备初始化和配置、数据传输和处理以及错误处理等。
二、请简要介绍Linux驱动程序的加载过程。
当系统启动时,Linux内核首先会加载核心模块和驱动程序模块。
驱动程序模块是以目标硬件设备为基础的,它们包含了与设备通信所需的函数和数据结构。
一般情况下,系统会根据硬件设备信息自动加载对应的驱动程序模块。
加载驱动程序模块需要通过insmod或modprobe命令进行,这些命令可以在启动时自动执行。
三、请简述Linux驱动程序的实现方式。
Linux驱动程序的实现方式包括内核空间驱动和用户空间驱动。
内核空间驱动是指驱动程序运行在内核空间,直接与硬件设备进行交互。
用户空间驱动是指驱动程序运行在用户空间,通过系统调用和内核模块实现与硬件设备的通信。
内核空间驱动的优势是性能更好,但需要对内核进行编译和加载,而用户空间驱动的优势是开发更加容易,但性能会稍差。
四、请介绍Linux驱动程序中常用的数据结构和函数。
在Linux驱动程序中,常用的数据结构有file结构体、inode结构体和cdev结构体等。
file结构体用于表示一个打开的设备文件,可以通过它传递与设备相关的信息。
inode结构体用于表示一个文件的元数据信息,包括文件的权限、大小和创建时间等。
cdev结构体用于表示一个字符设备,包含了设备文件的操作函数和设备号等信息。
常用的函数包括register_chrdev、unregister_chrdev、request_irq和release_irq等。
详细介绍Linux USB驱动工作流程

详细介绍Linux USB驱动工作流程1. USB主机在Linux驱动中,USB驱动处于最底层的是USB主机控制器硬件,在其之上运行的是USB 主机控制器驱动,主机控制器之上为USB核心层,再上层为USB设备驱动层(插入主机上的U盘、鼠标、USB转串口等设备驱动)。
因此,在主机侧的层次结构中,要实现的USB驱动包括两类:USB主机控制器驱动和USB 设备驱动,前者控制插入其中的USB设备,后者控制USB设备如何与主机通信。
Linux 内核USB核心负责USB驱动管理和协议处理的主要工作。
主机控制器驱动和设备驱动之间的USB核心非常重要,其功能包括:通过定义一些数据结构、宏和功能函数,向上为设备驱动提供编程接口,向下为USB主机控制器驱动提供编程接口;通过全局变量维护整个系统的USB设备信息;完成设备热插拔控制、总线数据传输控制等。
2. USB设备Linux内核中USB设备侧驱动程序分为3个层次:UDC驱动程序、Gadget API和Gadget 驱动程序。
UDC驱动程序直接访问硬件,控制USB设备和主机间的底层通信,向上层提供与硬件相关操作的回调函数。
当前Gadget API是UDC驱动程序回调函数的简单包装。
Gadget驱动程序具体控制USB设备功能的实现,使设备表现出“网络连接”、“打印机”或“USB Mass Storage”等特性,它使用Gadget API控制UDC实现上述功能。
Gadget API 把下层的UDC驱动程序和上层的Gadget驱动程序隔离开,使得在Linux系统中编写USB 设备侧驱动程序时能够把功能的实现和底层通信分离。
3. 在USB设备组织结构中,从上到下分为设备(device)、配置(config)、接口(interface)和端点(endpoint)四个层次。
USB设备程序绑定到接口上。
对于这四个层次的简单描述如下:设备通常具有一个或多个的配置配置经常具有一个或多个的接口接口没有或具有一个以上的端点。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Linux驱动程序工作原理简介一、linux驱动程序的数据结构 (1)二、设备节点如何产生? (2)三、应用程序是如何访问设备驱动程序的? (2)四、为什么要有设备文件系统? (3)五、设备文件系统如何实现? (4)六、如何使用设备文件系统? (4)七、具体设备驱动程序分析 (5)1、驱动程序初始化时,要注册设备节点,创建子设备文件 (5)2、驱动程序卸载时要注销设备节点,删除设备文件 (7)参考书目 (8)一、linux驱动程序的数据结构设备驱动程序实质上是提供一组供应用程序操作设备的接口函数。
各种设备由于功能不同,驱动程序提供的函数接口也不相同,但linux为了能够统一管理,规定了linux下设备驱动程序必须使用统一的接口函数file_operations 。
所以,一种设备的驱动程序主要内容就是提供这样的一组file_operations 接口函数。
那么,linux是如何管理种类繁多的设备驱动程序呢?linux下设备大体分为块设备和字符设备两类。
内核中用2个全局数组存放这2类驱动程序。
#define MAX_CHRDEV 255#define MAX_BLKDEV 255struct device_struct {const char * name;struct file_operations * fops;};static struct device_struct chrdevs[MAX_CHRDEV];static struct {const char *name;struct block_device_operations *bdops;} blkdevs[MAX_BLKDEV];//此处说明一下,struct block_device_operations是块设备驱动程序内部的接口函数,上层文件系统还是通过struct file_operations访问的。
哈哈,现在明白了吧?你的驱动程序调用 int register_chrdev(unsigned int major, const char * name, struct file_operations *fops) 就是将你提供的接口函数fops存放到chrdevs[MAX_CHRDEV]这个数组中,数组下标就是你的驱动的主设备号,数组内容包括驱动名称和驱动接口函数,这样,内核就能看到你的驱动程序了。
BTW,如果你将major设为0,系统会自动给你分配一个空闲的主设备号。
那么?次设备号呢?别急,马上就出现了:)二、设备节点如何产生?驱动程序运行在内核空间,应用程序访问驱动程序通常是通过系统调用文件系统接口函数的,也就是说,在linux下,和磁盘文件一样,设备也是文件,只是他们的文件属性不同而已,应用程序只能通过文件名来访问设备的驱动程序。
所以,文件系统中必须要有一个代表你的设备的文件,应用程序才能访问你的设备驱动程序。
为了便于理解,我们可以将设备文件换个名字,叫做设备节点。
设备节点在哪里?设备节点存在于你的文件系统中,通常在/dev目录下,当然,你也可以在其它地方创建。
一般说来,我们在制作文件系统映像时就已经将可能用到的设备节点都创建好了。
你可以打开/dev目录看一下,它下面的设备节点的数量会让你吃惊的:)如何创建设备节点?。
你可以用mknod命令。
如使用以下命令可以创建一个mtd4的字符设备节点。
Mknod /dev/ mtd4 c MTD_CHAR_MAJOR 4我们创建一个普通的磁盘文件,它的内容是我们写入的数据。
那么设备节点的内容是什么?设备节点文件没有数据,它的文件大小为0,它只有文件属性,包括设备类型、主设备号、次设备号。
没有别的了?对,就这些,没别的了。
那设备节点和设备驱动程序是怎么联系起来的啊?别着急,休息,休息一会儿:)三、应用程序是如何访问设备驱动程序的?举个例子:我们要向nor flash的第四个分区的起始位置偏移512字节写入100字节的数据。
我们是如何做的?主要程序片断如下:fd = open(“/dev/mtd4”, O_RDWR);lseek (fd,512, SEEK_SET);write (fd , write_buffer, 100);close(fd);上面的代码比较简单,但是似乎没有看到我们的应用程序是如何调用到驱动程序的。
没关系,接下来我将带领你们走通这条道路。
应用程序调用Open函数,这是个系统调用函数,程序会进入内核空间调用sys_open函数。
在sys_open,首先会根据文件路径“/dev/mtd4”找到这个文件节点,这部分工作是属于VFS(虚拟文件系统)的。
“/dev/mtd4”的文件属性是字符设备,于是sys_open会调用函数chrdev_open(),在这个函数里有一句话:filp->f_op = get_chrfops(MAJOR(inode->i_rdev), MINOR(inode->i_rdev));哈!看到了眉目吧!猜也能猜到啊,get_chrfops()里面一定会返回chrdevs[major].fops的。
我们终于从文件系统走到驱动程序了,那么,接下来的事情就是可以理解的了。
Write()最终一定会调用到chrdevs[major].fops->write();Read()最终一定会调用到chrdevs[major].fops->read();各种驱动程序比较特殊的功能函数都可以通过ioctl()来得到调用。
而次设备号也会作为参数传递给你。
四、为什么要有设备文件系统?从前面的章节,我们可以看到以主次设备号的形式管理设备驱动程序存在很大的缺点。
首先,设备节点的创建是独立于内核的,是在建立文件系统时就把所有要用到的设备节点都创建好了的,通常我们不会去刻意删除哪些节点,因为我们不知道系统将来会不会用到它们。
由于每个设备节点代表唯一的主次设备号,所以每个可能存在的子设备都对应一个设备节点,可见,这样的设备节点数量是很大的,这些数量庞大的设备节点都(文件)存在于存储介质中,对文件系统的效率也是个影响。
其次,文件系统中存在哪些设备节点,并不代表内核中就有这种设备的驱动程序,也不代表系统中有这种设备,因为设备节点不是动态创建的,它是制作文件系统时建立的。
因此,/dev目录下的信息大多对我们是无用的,而且那么多的设备节点都平铺在/dev目录下,阅读起来也不直观。
最后,目前主次设备号都是用8位整数表示的,也就是说内核最多管理256种字符设备和256种块设备。
现在计算机外设种类越来越多,这样的限制已经不够了。
由于目前的主次设备号的管理形式有以上几个缺点,linux内核小组在2.4版本以后加入了设备文件系统来改进这些缺点。
设备文件系统的思想就是想让设备节点可以动态创建、删除,这样系统中有哪些设备驱动程序就可以一目了然;还要能够把设备节点组织成一棵目录树,方便阅读;最后,希望能够扩大主次设备号的限制,不再限制在256种设备以内。
五、设备文件系统如何实现?要想在内核中方便的做到动态创建、删除设备文件(在这里,我们把设备节点称为设备文件会更恰当些),最自然的做法就是在RAM中创建一个文件系统,内核启动时这个文件系统是空的,以后每加载一种设备驱动程序,就在这个文件系统中创建一个对应的设备文件;卸载设备驱动程序时,再删除这个设备文件。
而且,我们可以在这个文件系统中创建目录,一类设备文件放在同一个目录中,甚至把一种设备的多个子设备文件放在同一个目录下,方便阅读。
在设备文件系统中,我们在注册设备文件时可以把设备驱动程序的ops直接挂到设备文件的inode中,以后访问驱动程序就可以摆脱主次设备号的限制了,不需要再访问chrdev[]数组,这样就突破了256种设备的限制。
我们把设备文件系统mount到/dev目录下,这样,看起来跟以前的方案就很相似了,也方便老的应用程序的移植。
六、如何使用设备文件系统?以前我们写驱动程序时要调用int register_chrdev(unsigned int major, const char * name, struct file_operations *fops)将你提供的接口函数fops 存放到chrdevs[MAX_CHRDEV]这个数组中,然后在文件系统中用mknod创建有相同主设备号的设备节点就可以了。
那么现在有了设备文件系统,我们的驱动程序该如何写呢?很简单,follow me!1、调用devfs_handle_t devfs_mk_dir (devfs_handle_t dir, const char *name, void *info)创建设备文件所在的目录。
Dir是要创建目录的父目录句柄,如为NULL,就是设备文件系统的根目录(/dev);最后一个参数info通常为NULL。
2、调用devfs_handle_t devfs_register (devfs_handle_t dir, const char *name,unsigned int flags,unsigned int major, unsigned int minor,umode_t mode, void *ops, void *info)注册具体的设备,并在指定目录下创建子设备节点。
这里的dir目录名是要创建的设备文件所在的目录名,目录名一般不能为NULL,因为子设备文件名name通常是以0、1、2、3等数字命名的,会和其它设备文件冲突。
3、卸载驱动程序时调用void devfs_unregister (devfs_handle_t de)删除创建的目录和子设备文件。
七、具体设备驱动程序分析这节以mtdchar设备驱动程序来具体分析驱动程序的写法。
Mtdchar字符设备是管理flash驱动程序的,是各种flash驱动程序的抽象层。
Mtdchar的主程序是driver/mtd/mtdchar.c;1、驱动程序初始化时,要注册设备节点,创建子设备文件驱动程序为了兼容以前的方案,通常会既注册设备节点,又创建子设备文件,这样不管内核支持不支持设备文件系统,驱动程序都可以工作。
static int __init init_mtdchar(void){//为了兼容以前的方案,要注册mtdchar的主设备号、设备名以及fops if (register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops)){printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",MTD_CHAR_MAJOR);return -EAGAIN;}//如果内核支持设备文件系统,在这个函数里会创建子设备文件。