最近为了学习底层设备驱动而把Linux底层设备驱动复习整理了一下。
Linux设备驱动程序是一个内核模块,可以随时添加到内核和随时从内核中删除。很自然,在模块被他人使用时无法删除,因而存在一个模块被使用的计数器。
对比vxWorks/Linux/QNX/OSE等等系统的设备驱动程序,万变不离其宗,任何系统的驱动层界面应该有如下根本的东西:
1、OS系统必定有某种设备链表,并有某种挂入函数能够将一个新设备及其驱动程序挂入这个链表。
2、从OS往下看,设备必定会提供一套读写接口。
找到这两者就摸清了这个OS体系的驱动脉络,其他细节可以顺藤摸瓜找出来。对应上述1,设备及驱动挂入函数往往类似 dev_register(dev_num, dev_attr)和drv_register(dev_num, drv_funcs_pointer),Linux体系的字符设备的对应函数是cdev_add()。对应上述2,驱动软件必须提供类似 open/read/write/set/close之类函数,Linux把普通非网络设备当文件看待,故这类函数接口和文件操作函数接口一致。
Linux有一个设备链表,这已经足够,但是为了更好地观察和管理设备及驱动而发展了统一设备模型,其核心数据结构是kobject和kset。
每一个设备对应一个kobject结构,设备被使用的计数器也在这个结构里面。kset是一组相近设备集合的父节点结构,"a set of"在英文中是“一套”的意思,我猜测kset里面的set就是这个“套”的意思。
一组相近设备集合中每个kobject的父指针都指向其kset,而kset有个指针指向这个设备集合的第一个kobject,这个kobject的next指针指向第二个kobject,类推,所有kobject被这样的链表串接。
由于kset下属这组设备类型近似,所以kset结构链接一个kobj_type结构,在这个type结构中统一描述了组内所有设备的type情况。单个kobject内的type信息可能被忽略。
由于kset管理一组kobject,故存在将kobject添加到kset的接口,以及对应的删除接口,可能还有查询接口。
若干相近的kset组成一个驱动子系统subsystem,比如多种输入设备组成的输入子系统。
通过kset/kobject/kobj_type/subsystem等,所有设备组成了一颗设备树,这样Linux系统可以方便地查看整个系统的设备的层次和从属情况,可能还有分类统计情况。
进一步,Linux将这种树形结构对应成一个虚拟的,也即内存中的文件目录树结构,即sysfs。其中大多数目录都对应设备树,其中最深一层子目录 对应一个设备,该目录中的文件对应设备的属性attr。另外sysfs还有设备的类视图class目录等,不过这些并非理解Linux设备驱动结构的关 键。