一、Linux设备分类
Linux将设备主要分为三类:字符设备、块设备、网络设备。
1. 字符设备:必须以串行顺序依次访问的设备,不能让随机访问设备内存中某一组数据;
2. 块设备:可以按照任意顺序进行访问,以块为单位,例如硬盘、eMMc等;
3. 网络设备:面向数据包的接收和发送而设计,不倾向于对应文件系统的节点。
二、Linux设备驱动程序与外界的接口
1. 驱动程序于操作系统内核的接口
2. 驱动程序与系统引导的接口
3. 驱动程序与设备的接口
三、根据功能划分
1. 驱动程序的注册和注销。
设备驱动程序可以再系统启动的时候初始化,也可以在需要的时候动态加载。
字符设备的初始化由chr_dev_init()完成。
块设备初始化由blk_dev_init()完成。
每个字符设备或是块设备的初始化都是通过devfs_register_chrdev() 或是devfs_register_blkdev() 向内核注册,在关闭字符设备或是块设备时,需要通过devfs_unregister_chrdev() 或是 devfs_register_blkdev() 从内核中注销设备。
2. 设备的打开与释放
设备打开:
打开设备是由open()来完成的,例如打印机lp_open()
设备打开要经过一下几个步骤:
(1)增加设备使用计数
(2)检查设备相关错误,如设备尚未准备好类似的硬件问题
(3)检查是首次打开,则初始化设备
(4)识别设备号,如有必要则更新f_op指针
(5)如果需要,分配且设置要放在filp->private_data里的数据结构
设备释放:
关闭释放设备由release()来完成,例如释放打印机是用lp_release(),而释放终端设备是用tty_release ().
释放设备步骤如下:
(1)释放在filp->private_data中的open分配的内存。
(2)如果是最后一次释放,则关闭设备。
(3)递减设备使用计数。
3. 设备的读写操作
字符设备使用各自的read()和write()来进行数据读写。
块设备使用 generic_file_read() 和genertc_file_write()来进行数据读写。
这两个通用函数向请求表添加读写请求,内核可以通过ll_rw_block()优化请求顺序。由于是对内存缓冲区而不是设
备进行操作的,因而可以加快读写请求。如果内存缓冲区内没有要读入的数据或是要将写请求写入设备,那么就要真正
的执行数据传输。这是通过数据结构request_queue和request_fn()来完成 (include/linux/blkdev.h)。
4. 设备的控制操作
除了读写操作,有时还要控制设备。这可以通过设备驱动程序中的ioctl()来完成。例如IDE硬盘的控制可以通过hd_ioctl(),对光驱的控制可以通过cdrom_ioctl()。
与读写操作不同,ioctl()的用法与具体设备密切相关。以软驱的floppy_ioctl()为例(drivers/block/floppy。c):
static int fd_ioctl(struct inode *inode,
struct file *filp,
unsigned int cmd,
unsigned long param);
其中,cmd的取值及含义都是与软驱有关的,比如,FDEJECT表示弹出软盘。
除了ioctl(),设备驱动程序还可能有其他控制函数,比如llseek()等。
5. 设备的中断和轮询处理
对于不支持中断的设备,读写时需要轮询设备状态,以及是否需要继续进行数据传输。例如,打印机。如果设备支持中断,则可按照中断方式进行。
本文摘自:https://tech.hqew.com/news_589150