1 IO端口映射
IO端口与CPU直连,CPU读取IO端口时需要一个地址,就是IO端口物理地址的映射。
IO映射有两种方式:
- 内存映射:ARM架构芯片只有一个物理地址空间,因此IO端口直接被内存的一部分,内核像访问内存一样访问端口
- IO空间映射:X86架构有专门的IO空间,CPU通过设立专门的I/O指令(如X86的IN和OUT指令)来访问这一空间中的地址单元(也即I/O端口)
2 IO端口模型
2.1 IO端口寄存器
内核对IO编程提供统一的方法,每个设备的IO端口都被组织成一组专用寄存器:
- 控制寄存器
- 状态寄存器
- 输入寄存器
- 输出寄存器
2.2 IO设备树
IO设备驱动程序使用资源(struct resource)记录分配给每个硬件的IO端口,以免资源冲突!
- char *name:资源拥有者的描述
- unsigned long start:资源范围的开始
- unsigned long end:资源范围的结束
- unsigned long flags:各种标志
- struct resource *parent:指向资源树中的父节点
- struct resource *parent:指向资源树中的兄弟节点
- struct resource *parent:指向资源树中的子节点,子节点的范围(start->end)一定包含在主节点范围内
主节点和子节点的地址范围类似harden和subdev、subdev和component的关系。
可以从/proc/ioports文件中获取当前分配给IO设备的所有IO地址树。比如这里:
3 IO接口
3.1 概念
IO端口就是带有地址的port口,IO接口则是处于一组IO端口和对应设备控制器之间的一种硬件电路;
它起到翻译作用:
- IO端口的值 -> IO接口 -> 设备需要的数据和命令
- 设备状态变化 -> IO接口 -> 更新IO端口寄存器
IO接口还可以通过一条IRQ线把电路连接到可编程中断控制器,代表硬件设备发起中断请求。
3.2 分类
① 专用IO接口:键盘接口,图形接口(GPU),磁盘接口,总线鼠标接口,网络接口,等
② 通用IO接口:并口,串口,PCMCIA接口,SCSI接口,通用串行总线(USB),等
4 设备驱动程序模型的组成
Linux2.6提供了一些数据结构和辅助函数,为系统中所有总线、设备以及驱动程序提供了一个统一的视图 —— 设备驱动程序模型。在/sys目录下有:
- block:块设备
- devices:被内核识别的硬件设备
- bus:系统中用于连接设备的总线
- class:系统中设备的类型(声卡、网卡、显卡等)
- power:处理一些硬件设备电源状态的文件
- firmwarm:处理一些硬件设备的固件的文件
5 struct kobject和kset容器
5.1 struct kobject
- char *k_name:容器名称
- struct kref:容器的引用计数
- struct kset *kset:kobject嵌入的容器
- struct kobj_type *ktype:指向kobject的类型描述符
- struct list_head entry:kobject所插入链表的指针
- struct kobject *parent:指向父kobject
每个kobject对应于sysfs文件系统中的一个目录!kobject被嵌入一个叫做容器的更大的对象中:这个容器叫做kset,kset是具有相同类型的kobject的集合。kobject是一个抽象的结构体,并不包含任何实际的设备信息,它被嵌入容器中,其他重要结构体(struct device或struct device_driver)包含kobject,用于结构体本身的层级描述,比如device的层级关系描述存放在其包含的kobject中。
5.2 struct kset
- struct subsystem *subsys:指向subsystem描述符
- struct kobj_type *ktype:指向set的kobject类型描述符(kset->ktype == kset->kobj->ktype)
- struct list_head list:包含在kset中的kobject链表的首部
- struct kobject *kobj:嵌入的kobject结构
- struct kset_hotplug_ops *hotplug_ops:只想用于处理kobject结构的过滤和热插拔操作的回到函数表
kset最重要的是建立上层(sub-system)和下层的(kobject)的关联性。kset是一组kobject的集合,当某一件事发生时,可以同时由kset通知到集合中的kobject。
6 设备和设备驱动程序
6.1 设备struct device
- struct kobject *kobj:内嵌的kobject结构
- struct device_driver *driver:指向控制设备驱动程序的指针
device对象全部收集在device_subsys子系统中,对应的目录为/sys/devices;
每个设备驱动程序都保持一个device对象链表,链接了所有可被管理的设备;
6.2 设备驱动程序struct device_driver
- char *name:设备驱动程序的名称
- struct kobject kobj:内嵌的kobject结构
- struct list_head devices:驱动程序支持的所有设备的链表
- struct module *owner:标识实现设备驱动程序的模块
- int (*)(struct device *) probe:探测设备的方法
- int (*)(struct device *) remove:移走设备的方法
- int (*)(struct device *) suspend:设置设备低功率状态的方法
- int (*)(struct device *) resume:设备恢复正常时所调用的方法
device_driver被嵌入到一个更大的描述符中,比如相机驱动程序由数据结构vcam_driver描述,其包含一个device_driver对象;
device_register()/device_unregister():往设备驱动模型中插入/移除一个新的device_driver。
设备驱动程序注册的时机:静态被编译进内核,则在内核初始化的时候进行;如果作为一个内核模块(ko),则在模块装入(insmod)的时候注册。
设备驱动程序可以早些注册,方便用户态程序使用,但是需要尽可能晚的初始化(分配内存,IRQ等资源),以节省资源。
7 总线
7.1 struct bus_type
- char *name:总线类型的名称
- struct subsustem subsys:与总线类型相关的kobject子系统,与/sys/bus/*是对应的,比如/sys/bus/pci表示总线类型为pci,子系统就是pci总线子系统
- struct kset drivers:驱动程序的kobject集合,包含描述符struct device_driver
- struct kset devices:设备的kobject集合,包含描述符struct device
内核所支持的每一种总线类型都由bus_type对象描述。
8 设备文件
设备文件的索引节点包含硬件设备的标识符,对应字符或块设备;
设备标识符 = 设备类型 + 主设备号 + 次设备号,具有相同设备类型(字符设备或块设备)和主设备号的所有设备文件可以由同一个设备驱动程序处理,次设备号标识了具体的设备。
早期版本Linux主设备号和次设备号都是8位长,Linux2.6增加了设备号的位长:主12位 + 次20位.
动态分配主次设备号:alloc_chrdev_region()注册设备,传入次设备号、分配设备数量和设备名;该函数会把分配的到的设备号保存在dev中。cdev_init()和cdev_add()注册设备到驱动设备模型,输入参数需要cdev而不是设备号,与动态分配设备号呼应。
动态创建设备文件:udev工具集扫描/sys/class子目录寻找dev文件,在/dev目录下创建对应的设备文件。这样/dev目录下只会创建系统内核支持的设备文件,没有其他多余文件。
创建时机:加载设备驱动程序,或热拔插设备。
普通文件和设备文件在用户层看来没有区别,是因为VFS屏蔽了操作细节,并根据设备类型实现不同函数的调用(open,read,write,lseek,ioctl)。
9 DMA
CPU可以读写RAM,所以RAM和IO设备通信的时候需要CPU参与;DMA电路就是替代CPU实现RAM和IO设备通信的电路。
DMA一旦被激活,可以自行传输数据,当传输完成,会触发一个中断;
当CPU和DMA同时访问RAM,由内存仲裁器解决冲突。
DMA的设置时间比较长,因此传输数据量较少时不如直接使用CPU效率高。
10 内核对设备驱动程序的支持
① 内核不识别端口:使用in/out 汇编语言 + 端口物理地址 可以直接与设备的IO端口交互
② 内核仅识别端口:把IO接口视为能够读写的字符流的顺序设备;只有某些操作系统的并口和串口使用了这种方法
③ 内核识别设备文件:通过对设备文件的VFS接口操作设备
11 字符设备驱动程序
字符设备驱动程序描述符:struct cdev
- struct kobject kobj: 内嵌的object
- struct module *owner: 驱动程序模块指针
- struct file_operations *ops: 驱动程序文件操作表指针
- struct list_head list: 相同字符设备驱动所对应的字符设备文件的链表
- dev_t dev: 初始主设备号和次设备号
- unsigned int count:设备号范围
本文来自博客园,作者:moonのsun,转载请注明原文链接:https://www.cnblogs.com/moon-sun-blog/p/18826130