本文主要是介绍<Linux>(极简关键、省时省力)《Linux操作系统原理分析之Linux 设备管理》(29),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
《Linux操作系统原理分析之Linux 设备管理》(29)
- 10 Linux 设备管理
- 10.1 Linux 设备分类与识别
- 10.1.1 Linux 设备的分类
- 10.1.2 设备文件
- 10.2 设备驱动程序与设备注册
- 10.2.1 设备驱动程序
- 10.2.2 设备注册
- 10.3Linux 的 I/O 控制方式
- 10.3.1 查询等待方式((轮询方式 轮询方式)
- 10.3.2 中断方式
- 10.4Linux 设备 I/O 操作
10 Linux 设备管理
10.1 Linux 设备分类与识别
10.1.1 Linux 设备的分类
类别 | 详细 |
---|---|
字符设备 | 以字符为单位输入输出数据的设备,并且以字符为单位对设备中的信息进行组织和处理。显示器、键盘等 |
块设备 | 以一定大小的数据块为单位输入输出数据,并且设备中的数据也是以物理块为单位进行组织和管理的。硬盘、软盘、光盘等。 |
网络设备 | 通过网络与外部近程或远程计算机进行通信的设备。网卡 |
10.1.2 设备文件
linux 设备管理的特点:物理设备抽象化,把物理设备看成文件,采用文件系统的接口和系统调用来
管理和控制设备。Linux 设备就是一种特殊文件,称为设备文件。
- 从设备向内存输入数据,相当于从设备文件读取数据;把数据从内存输出到设备可以看作是把数据写
入设备文件;启动设备时可以看作是打开设备文件;停止设备可看作是关闭设备文件。 - Linux 的设备文件一般置于/dev 目录下。系统中每个设备文件都有设备文件名。设备文件名由两个部分
组成:
第一部分 2~3 个字符,表示设备的种类;
第二部分通常是字母或数字,区分同种设备中的单个设备
👉IDE 普通硬盘是以 hd 命名;第一个 ide 设备是 hda,第二个是 hdb… ;而 hda1,hda2 表示第一块硬盘的第一、第二个磁盘分区。每个硬盘可以最多有四个主分区,因此 1-4 命名硬盘的主分区。
逻辑分区是从 5 开始的,每多一个分区,数字加 1 就可以。
👉SCSI 硬盘是用 sd 命名
👉软盘是用 fs 命名 - Linux 设备中有一个特殊的设备:null 设备。通常称其为“黑洞”设备,并没有实体与之对应。向 null
设备输出的一切数据都被舍弃。(相当于“回收站”) - 在终端使用 ls –l /dev 查看设备列表
- 逻辑设备名( 设备类型, 面向进程),物理设备名(设备文件名,面向内核),设备无关性。
- 设备文件与与普通文件的差异
👉设备文件没有象普通文件那样的文件实体,不在外存占据数据块来存放数据
👉进程访问普通文件是读写磁盘分区中的数据,访问设备文件是对硬件设备进行读写,完成设备与内存之间的数据传送 - 网络设备并不与设备文件对应,故网络设备没有设备文件名,只有逻辑设备名。如系统的第一块以太
网网卡的逻辑设备名是 eth0。Linux 文件系统不能用来管理和控制网络设备。
10.1.3 Linux 设备的识别
Linux 内核对设备的识别是通过: 设备类型+设备号(主、次设备号)。
👉设备类型:字符设备、块设备
👉主设备号:使用同一个驱动程序的每种设备有一个唯一的主设备号
👉次设备号:区分同种设备中的各个具体设备
主次设备号值都是从 0~255
10.2 设备驱动程序与设备注册
10.2.1 设备驱动程序
1.功能:
👉对设备进行初始化
👉启动、停止设备的运行
👉把设备上的数据传到内存
👉把数据从内存传送到设备
👉检测设备状态
2. 驱动程序虽然是在设备生产厂家开发的,但装入系统后由内核统一管理,处于内核态,成为内核的一部分。
3. Linux 对设备的管理和控制是使用 VFS 提供的各种数据结构和操作函数实现的
4. 驱动程序的编制:
Linux 中对文件的操作使用的是 VFS 虚拟文件系统的文件操作接口,即 file_operations 结构 。
file_operations 结构是文件操作函数指针的集合,在设备管理中,该结构体各个成员项指向的操作函数就是设备驱动程序的各个操作例程。
编制设备驱动程序的工作就是使用汇编或 c 语言编写控制设备完成各种操作的例程,然后把这些操作例程的入口地址赋予 file_operations 结构体的有关成员项即可。
各个操作函数的主要功能:
10.2.2 设备注册
当一种设备安装到系统时,必须向系统进行注册,注册之后才能使用,设备注册的任务是把驱动程
序加载到系统中。
👉设备的驱动程序是系统在启动时装载到系统中的;
👉对于“即装即用”设备,驱动程序作为程序模块可以随时加载到系统中,
- 设备注册表
两个设备注册表:字符设备注册表、块设备注册表。
#define MAX_CHRDEV 255
#define MAX_BLKDEV 255
static struct device_struct chrdevs[MAX_CHRDEV];
static struct device_struct blkdevs[MAX_BLKDEV];
每个注册表都有 255 个表项,每个表项表示一个设备,都是一个 device_struct 结构,称为设备描述符。
在 fs/device.c 中。
struct device_struct {
const char * name; /*指向设备名字符串*/
struct file_operations * fops; /*指向文件操作函数 file_operations 的指针*/
};
说明:
👉设备注册表的下标是某种设备的主设备号。使用主设备号作为索引就可以从设备注册表得到这种
设备的驱动程序。
👉两个注册表的第一个表项通常为 null,因为系统中不存在主设备号为 0 的字符设备和块设备。
- 设备注册函数
设备被注册时,系统首先构筑 file_operations 结构体,然后把驱动程序的各个操作函数的入口地址
赋予结构体的有关成员项,成员项没有对应函数时,则置为 null。设备注册是通过系统调用注册函数实现
的。在 fs/device.c 中。
字符设备注册函数:
int register_chrdev(unsigned int major, const char * name, struct file_operations *fops)
块设备注册函数:
int register_blkdev(unsigned int major, const char * name, struct file_operations *fops)
👉若major=0。注册一个新设备,由系统自动分配一个主设备号给驱动程序,成功则返回主设备号。
👉若major!=0,此时注册函数可以变更主设备号为 major 的设备的: 设备名或驱动程序。 成功返回0;
if (major == 0){
for (major = MAX_CHRDEV-1; major > 0; major--)
if (chrdevs[major].fops == NULL) /*从注册表 chrdevs[]的底部开始,,,,向上搜寻一个空表项 向上搜寻一个空表项。。。。
{
chrdevs[major].name = name;
chrdevs[major].fops = fops;
write_unlock(&chrdevs_lock);
return major;
}
}
write_unlock(&chrdevs_lock);
return -EBUSY;
}
- 设备注销
当设备需要撤销时,可以使用注销函数从设备注册表中删除。
int unregister_blkdev(unsigned int major, const char * name) /* 块设备注销函数*/
int unregister_chrdev(unsigned int major, const char * name) /* 字符设备注销函数*/
{
if (strcmp(chrdevs[major].name, name)) return -EINVAL;
chrdevs[major].name = NULL;
chrdevs[major].fops = NULL;
return 0;
}
10.3Linux 的 I/O 控制方式
Linux 对设备的输入、输出过程实际上是在 cpu 的控制下主机(内存)与外部设备之间传送数据的过程。
所以 Linux 的 I/O 控制方式有 3 种:
👉查询等待方式
👉中断方式
👉DMA 方式
10.3.1 查询等待方式((轮询方式 轮询方式)
驱动程序不断检测设备状态,当设备准备好传送数据时,cpu 执行驱动完成一次 I/O 过程,若设备未转备好,则驱动程序反复检测设备状态,直到设备转备好。适用于:不支持设备中断的系统、系统支持的中断数目有限时;例如并行接口(打印机接口)的驱动程序中默认的控制方式就是轮询方式。
10.3.2 中断方式
当进程向设备提出 I/O 请求时并不等待设备完成 I/O 操作,而是把 cpu 让给其它进程使用,自己则进入睡眠状态。在设备完成 I/O 操作时发出中断信号,系统根据中断信号调用相应的中断服务唤醒等待的进程继续执行后面的操作。
在机器硬件支持中断的情况下,设备驱动程序就可以使用中断方式控制设备的 I/O 操作。因此,设备驱动程序中处理包含各种操作函数外,同时还要提供进行各种中断处理的中断服务例程。CPU 接受到来自硬件的中断请求后,则通过中断请求好就能够执行该设备驱动程序的中断服务例程。
-
中断服务例程
👉 中断服务例程描述表:Linux 中,各种中断服务例程是通过中断服务例程描述表进行管理。中断
服务例程描述表是一个名为 Irq_action 的指针数组,定义如下:
Static struct irqaction * irq_action[NR_IRQS+1];
👉中断服务例程描述符:Irqaction 结构体;
👉机器支持硬件中断源的数目:NR_IRQS;
👉中断服务例程描述表数组的下标:与中断请求号 IRQ 对应,使用 IRQ 作为索引就可以找到该设备的中断例程描述符。 -
Irqaction 结构体
Irqaction 结构体定义在/include/linux/interrupte.h 中,如下所示:
Struct irqaction
{
Void(*handler)(int,void*,struct pt_regs*);/*指向中断服务例程*/
Unsigned long flags; /*中断标志*/
Unsigned long mask; /*中断掩码*/
Const char *name; /*设备名*/
Void *dev_id; /*设备号*/
Struct irqaction *next; /*指向下一个描述符:允许多个设备共享一个中断
请求号 IRQ,一个 IRQ 对应的多个中断例程描述符链接成一个单向链表*/
}
- Request_irq()
在设备驱动程序加载时,通过调用内核函数 Request_irq()建立驱动程序中断例程描述符 irqaction 结构体,并把它登记到 Irq_action 数组中。Request_irq()与硬件相关。在 80x86 机器上 Request_irq()函数定义在arch/i386/kernel/irq.c 中:
int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),unsigned long irqflags, const
char * devname, void *dev_id)
- free_irq()
撤消中断例程时,可以使用函数:
Void free_irq(unsigned int irq, void *dev_id)
把中断例程描述符表中下标为 irq,设备号为 dev_id 占用的表项释放。
10.4Linux 设备 I/O 操作
10.4.1 设备 I/O 操作
-
设备文件的建立 设备文件的建立
调用:mknod (const char *pathname, mode_t mode, dev_t dev)
终端:mknod /dev/name type major minor
提供文件名、类型、主设备号 、次设备号 -
设备文件的打开 设备文件的打开、关闭
int open(const char *pathname,int flags) /*flag 给出的对文件的处理方式:只读、只写、读写*/
int close(int fd) /*fd 设备的文件标识号*/
- 的读写 的读写
int read(int fd,void *buf,int count)
int write(int fd,void *buf,int count)
这篇关于<Linux>(极简关键、省时省力)《Linux操作系统原理分析之Linux 设备管理》(29)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!