Linux 里的设备 驱动

 

 

D.1. Linux 里的设备 https://www.debian.org/releases/stable/s390x/apds01.zh-cn.html

D.1. Linux 里的设备
Linux 的许多特殊文件可以在 /dev 目录下找到。这些文件称为设备文件,其行为与普通文件不同。大多数设备文件的类型是块设备和字符设备。这些文件是访问硬件的驱动程序(Linux 内核的一部分)的接口。另外一些,不那么常见的类型,是命名管道(pipe)。下表中列出了最重要的设备文件。

sda 第一块硬盘
sdb 第一块硬盘
sda1 第一块硬盘上的第一个分区
sdb7 第二块硬盘上的第七个分区
sr0 第一个 CD-ROM
sr1 第二个 CD-ROM
ttyS0 串口 0,即 MS-DOS 下的 COM1
ttyS1 串口 1,即 MS-DOS 下的 COM2
psaux PS/2 鼠标设备
gpmdata 伪设备,中转从 GPM(鼠标)服务传来的数据
cdrom 指向光驱的符号链接
mouse 指向鼠标设备文件的符号链接
null 所有写入该设备的东西都会消失
zero 可以从该设备永无休止地读出零

 

1.IDE硬盘 /dev/hd[a-d]
2.SCSI/SATA/USB硬盘 /dev/sd[a-p]
3.光驱 /dev/cdrom或/dev/hdc
4.软盘 /dev/fd[0-1]
5.打印机(25针) /dev/lp[0-2]
6.打印机(USB) /dev/usb/lp[0-15]
7.鼠标 /dev/mouse

Linux驱动基础-Linux中设备分类 - 飞凌嵌入式行业资讯 - 保定飞凌嵌入式技术有限公司 https://www.forlinx.com/article-new-c22/368.html

Linux系统上每一个设备的运行都有其固定的规则,而且设备种类、型号众多,将每一个设备的固定规则写入内核是不现实的,也是没有意义的。所以每一个设备都会有相对应的驱动,小到一个led灯,大到一个网卡,都要有相关的驱动。驱动程序可以看做是应用程序和实际设备之间的一个软件层。应用程序控制一个设备,首先要向驱动发出信号,驱动接收到信号再控制设备完成相对应的动作。应用程序想要获取设备采集的数据同样也是要经过驱动来完成。

Linux中设备分类

Linux系统将设备分成三个基本类型,每个模块通常实现为其中某一类。

1、字符设备

字符设备是一个能够像字节流一样被访问的设备,由字符设备驱动程序来实现这种特性。字符设备驱动程序通常至少要实现打开、关闭、读取和写入系统调用。字符设备是一个顺序访问的,只有在设备响应后才能读到相应信息。不能随机访问,且每个字符设备都有一个设备号,设备号由主设备号和次设备号组成。常见的字符设备如串口、IIC等。字符设备的对应的文件都在/dev目录下,每一个文件对应一个硬件。在linux系统中/dev目录下使用ls -l命令查看详细信息,第一个字母“c”为字符设备文件的标识。

 

2、块设备

和字符设备类似,块设备也是通过/dev目录下的文件系统节点来访问。块设备上能够容纳文件系统。常见的块设备如磁盘、emmc  flash、nand  flash、 SD卡等。每个块设备同样有r--+’/h涡阳【5片【一个设备号,设备号由主设备号和次设备号组成。在linux系统中/dev目录下使用ls -l命令查看详细信息,第一个字母“b”为块设备文件的标识。/dev下每个块设备文件对应一个磁盘的分区。

 

3、网络设备

任何网络相关的事务都要经过一个网络接口,即一个能够与其他主机交换数据的设备。通常,接口是个硬件设备,但也可能是纯软件设备,比如在ifconfig查看网口信息的时候有一个lo,就是网络回环(loopback)接口。访问网络接口的方法是给它们分配一个唯一的名字,比如eth0、eth1、lo等。但这个名字在文件系统中不存在相应的节点。网络接口没有像字符设备和块设备一样的设备号,只有一个唯一的名字,如eth0、eth1等,而这个名字也不需要与设备文件节点对应。内核使用一套与数据包传输相关的函数来与网络设备驱动程序通信,它们不同于字符设备和块设备的read()和write()方法。

 

 

各种字符设备和块设备都体现了linux“一切都是文件的”的设计思想,网络设备是唯一没有体现这一思想的设备。

设备节点、设备驱动及设备的关联

整个系统上挂载的设备很多,当我们访问一个设备节点时,系统是如何知道使用哪个设备驱动及访问哪个设备的呢?这个是通过设备号来实现的。创建一个设备节点时需要指定主设备号和次设备号。对于设备节点来说,名字不是重要的,设备号才是最重要的,它实际指定了对应的驱动程序和对应的设备。主设备号用来区分不同种类的设备,而次设备号用来区分同一类型的多个设备。对于常用设备,Linux有约定俗成的编号,如硬盘的主设备号是3。在/dev目录下使用命令ls -l加名字可查看相应的主设备号和次设备号。

 

主设备号

驱动程序在初始化时,会注册它的驱动及对应主设备号到系统中,这样当应用程序访问设备节点时,系统就知道它所访问的驱动程序了。可以通过/proc/devices文件来驱动系统设备的主设备号。

 

 

次设备号

驱动程序运行时,每发现一个它能驱动的设备,就会创建一个设备对象,并为其分配一个次设备号以区分不同的设备。这样当应用程序访问设备节点时驱动程序就可以根据次设备号知道它所访问的设备了。

 

嵌入式Linux之我行——设备文件系统剖析与使用-deem_passion-ChinaUnix博客 http://m.blog.chinaunix.net/uid-25120309-id-3787750.html

一、什么是Linux设备文件系统

      首先我们不看定义,定义总是太抽象很难理解,我们先看现象。当我们往开发板上移植了一个新的文件系统之后(假如各种设备驱动也移植好了),启动开发板,我们用串口工具进入开发板,查看系统/dev目录,往往里面没有或者就只有null、console等几个系统必须的设备文件在这儿外,没有任何设备文件了。那我们移植好的各种设备驱动的设备文件怎么没有啊?如果要使用这些设备,那不是要一个一个的去手动的创建这些设备的设备文件节点,这给我们使用设备带来了极为的不便(在之前篇幅中讲的各种设备驱动的移植都是这样)。

      设备文件系统就是给我们解决这一问题的关键,他能够在系统设备初始化时动态的在/dev目录下创建好各种设备的设备文件节点(也就是说,系统启动后/dev目录下就有了各种设备的设备文件,直接就可使用了)。除此之外,他还可以在设备卸载后自动的删除/dev下对应的设备文件节点(这对于一些热插拔设备很有用,插上的时候自动创建,拔掉的时候又自动删除)。还有一个好处就是,在我们编写设备驱动的时候,不必再去为设备指定主设备号,在设备注册时用0来动态的获取可用的主设备号,然后在驱动中来实现创建和销毁设备文件(一般在驱动模块加载和卸载函数中来实现)。

二、设备文件系统的种类

      设备文件系统有:devfs、udev、mdev等。

      mdev是udev的简化版本,是busybox中所带的程序,最适合用在嵌入式系统,而udev一般都用在PC上的Linux中,相对mdev来说要复杂些;devfs是2.4内核引入的,而在2.6内核中却被udev所替代,他们有着共同的优点,只是devfs中存在着一些未修复的bug,作者也停止了对他的维护,最显著的一个区别是:采用devfs时,当一个并不存在的设备节点被打开时,他却还能自动加载对应的驱动,而udev则不能,udev认为当打开并不存在的设备节点时不应该加载对应的驱动模块,因为加载了也没用,浪费系统资源。

 

Learning-Notes/Linux驱动.c at master · Ikaros-521/Learning-Notes · GitHub https://github.com/Ikaros-521/Learning-Notes/blob/master/Linux%E9%A9%B1%E5%8A%A8.c

三、驱动的类型
字符设备:在IO过程中以字符或字节为单位进行数据传输,数据也要按照一定的顺序进行读写。
操作这种设备的接口有:open/close/read/write
常见的字符设备有:鼠标、键盘、串口、LED灯、温度传感器、湿度传感器等。
字符设备由于功能杂乱,设备也混乱,一般都是小厂家生产的没有统一的接口,所以大多数据需要编写驱动的都是字符设备。
块设备:以块为单位进行数据的读写,用记在读写数据时必须最少读一块,这种设备一般都带缓冲区,而且数据量一般都很大,数据在读写时一般不会立即到达硬件。
操作这种设备的接口有:open/close/read/write/sync/fsync/fdatasync。
常见的块设备有:硬盘、SD卡、Nand、iNand。
虽然存储介质不同,但都有一个控制器不需要外部直接操作,只需要按照控制器的接口来操作即可。
网络设备:具有网络通信协议的设备,网络设备没有设备文件,必须使用socket进行操作。
操作这种设备的接口有:send/recv/sendto/recvfrom。
网络设备都非常标准的、规范,所以有了万能的网卡驱动,顶多需要移植一下,也不需要编写驱动。

四、设备文件
在Linux系统会把硬件抽象成文件来制作(网上除外)。
查看设备文件:ls -l /dev
每个字母表示文件的类型:
- 普通文件
d 目录文件
l 链接文件
c 字符设备文件
b 块设备文件
p 管道文件
s socket文件
设备号:主设备号+从设备号组成
主设备号:表示硬件的类型,1~254
从设备号:硬件的编号,0~255
它是在驱动程序中确定的,可以让内核自动生成,也可以手动确定,或者手动创建。
注意:设备不能重复。

 

 

基于嵌入式ARM Linux步进电机驱动程序的设计-老古开发网 http://www.laogu.com/cms/xw_292992.htm

嵌入式设备驱动整体可分以下两部分:

(1)硬件设备接口层。这部分主要描述驱动程序与设备的交互。
(2)驱动与内核接口层,它实现驱动模块在Linux内核的注册加载与卸除工作。
对于驱动程序与内核接口层,Linux提供了标准的入口点函数init_funcTIonO;在通过模块化的设计方法设计驱动程序时,使用insmod加载核心模块时会调用本函数,通知内核对驱动程序进行注册。模块的卸除工作与加载工作类似,通过rmmod卸载模块时,调用cleanup_funct-ion0取消驱动程序的注册。

 

 

Linux 设备驱动 Edition 3

By Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartman

Linux设备驱动第三版-嵌入式linux中文站在线图书 http://www.embeddedlinux.org.cn/ldd3/index.html

Linux设备驱动第三版-嵌入式linux中文站在线图书 http://www.embeddedlinux.org.cn/ldd3/index.html

2.2. Hello World 模块

许多编程书籍从一个 "hello world" 例子开始, 作为一个展示可能的最简单的程序的方法. 本书涉及的是内核模块而不是程序; 因此, 对无耐心的读者, 下面的代码是一个完整的 "hello world"模块:

#include 
#include 
MODULE_LICENSE("Dual BSD/GPL");

static int hello_init(void)
{
        printk(KERN_ALERT "Hello, world\n");
        return 0;
}
static void hello_exit(void)
{

        printk(KERN_ALERT "Goodbye, cruel world\n");
}

module_init(hello_init);
module_exit(hello_exit);

这个模块定义了两个函数, 一个在模块加载到内核时被调用( hello_init )以及一个在模块被去除时被调用( hello_exit ). moudle_init 和 module_exit 这几行使用了特别的内核宏来指出这两个函数的角色. 另一个特别的宏 (MODULE_LICENSE) 是用来告知内核, 该模块带有一个自由的许可证; 没有这样的说明, 在模块加载时内核会抱怨.

printk 函数在 Linux 内核中定义并且对模块可用; 它与标准 C 库函数 printf 的行为相似. 内核需要它自己的打印函数, 因为它靠自己运行, 没有 C 库的帮助. 模块能够调用 printk 是因为, 在 insmod 加载了它之后, 模块被连接到内核并且可存取内核的公用符号 (函数和变量, 下一节详述). 字串 KERN_ALERT 是消息的优先级. [3]

我们在此模块中指定了一个高优先级, 因为使用缺省优先级的消息可能不会在任何有用的地方显示, 这依赖于你运行的内核版本, klogd 守护进程的版本, 以及你的配置. 现在你可以忽略这个因素; 我们在第 4 章讲解它.

你可以用 insmod 和 rmmod 工具来测试这个模块. 注意只有超级用户可以加载和卸载模块.

% make 
make[1]: Entering directory `/usr/src/linux-2.6.10'
 CC [M] /home/ldd3/src/misc-modules/hello.o
 Building modules, stage 2.
 MODPOST
 CC /home/ldd3/src/misc-modules/hello.mod.o
 LD [M] /home/ldd3/src/misc-modules/hello.ko 
make[1]: Leaving directory `/usr/src/linux-2.6.10'
% su
root# insmod ./hello.ko
Hello, world
root# rmmod hello
Goodbye cruel world
root#

请再一次注意, 为使上面的操作命令顺序工作, 你必须在某个地方有正确配置和建立的内核树, 在那里可以找到 makefile (/usr/src/linux-2.6.10, 在展示的例子里面 ). 我们在 "编译和加载" 这一节深入模块建立的细节.

依据你的系统用来递交消息行的机制, 你的输出可能不同. 特别地, 前面的屏幕输出是来自一个字符控制台; 如果你从一个终端模拟器或者在窗口系统中运行 insmod 和 rmmod, 你不会在你的屏幕上看到任何东西. 消息进入了其中一个系统日志文件中, 例如 /var/log/messages (实际文件名子随 Linux 发布而变化). 内核递交消息的机制在第 4 章描述.

 

 

2.3.1. 用户空间和内核空间

A module runs in kernel space, whereas applications run in user space. This concept is at the base of operating systems theory. 一个模块在内核空间运行, 而应用程序在用户空间运行. 这个概念是操作系统理论的基础.

操作系统的角色, 实际上, 是给程序提供一个一致的计算机硬件的视角. 另外, 操作系统必须承担程序的独立操作和保护对于非授权的资源存取. 这一不平凡的任务只有 CPU 增强系统软件对应用程序的保护才有可能.

 

posted @ 2023-11-29 09:36  papering  阅读(153)  评论(0编辑  收藏  举报