当前位置:嗨网首页>书籍在线阅读

11-sysfs文件系统与Linux设备模型

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

5.4.2 sysfs文件系统与Linux设备模型

Linux 2.6的内核引入了sysfs文件系统,sysfs被看成是与proc、devfs和devpty同类别的文件系统,该文件系统是一个虚拟的文件系统,它可以产生一个包括所有系统硬件的层级视图,与提供进程和状态信息的proc文件系统十分类似。

sysfs把连接在系统上的设备和总线组织成为一个分级的文件,它们可以由用户空间存取,向用户空间导出内核数据结构以及它们的属性。sysfs的一个目的就是展示设备驱动模型中各组件的层次关系,其顶级目录包括block、device、bus、drivers、class、power和firmware。

block目录包含所有的块设备;devices目录包含系统所有的设备,并根据设备挂接的总线类型组织成层次结构;bus目录包含系统中所有的总线类型;drivers目录包括内核中所有已注册的设备驱动程序;class目录包含系统中的设备类型(如网卡设备、声卡设备、输入设备等)。在/sys目录运行tree会得到一个相当长的树型目录,下面摘取一部分:

|-- block

| |-- fd0

| |-- md0

| |-- ram0

| |-- ram1

| |-- ...

|-- bus

| |-- eisa

| | |-- devices

| | '-- drivers

| |-- ide

| |-- ieee1394

| |-- pci

| | |-- devices

| | | |-- 0000:00:00.0 -> ../../../devices/pci0000:00/0000:00:00.0

| | | |-- 0000:00:01.0 -> ../../../devices/pci0000:00/0000:00:01.0

| | | |-- 0000:00:07.0 -> ../../../devices/pci0000:00/0000:00:07.0

| | '-- drivers

| | |-- PCI_IDE

| | | |-- bind

| | | |-- new_id

| | | '-- unbind

| | '-- pcnet32

| | |-- 0000:00:11.0 -> ../../../../devices/pci0000:00/0000:00:11.0

| | |-- bind

| | |-- new_id

| | '-- unbind

| |-- platform

| |-- pnp

| '-- usb

| |-- devices

| '-- drivers

| |-- hub

| |-- usb

| |-- usb-storage

| '-- usbfs

|-- class

| |-- graphics

| |-- hwmon

| |-- ieee1394

| |-- ieee1394_host

| |-- ieee1394_node

| |-- ieee1394_protocol

| |-- input

| |-- mem

| |-- misc

| |-- net

| |-- pci_bus

| | |-- 0000:00

| | | |-- bridge -> ../../../devices/pci0000:00

| | | |-- cpuaffinity

| | | '-- uevent

| | '-- 0000:01

| | |-- bridge -> ../../../devices/pci0000:00/0000:00:01.0

| | |-- cpuaffinity

| | '-- uevent

| |-- scsi_device

| |-- scsi_generic

| |-- scsi_host

| |-- tty

| |-- usb

| |-- usb_device

| |-- usb_host

| '-- vc

|-- devices

| |-- pci0000:00

| | |-- 0000:00:00.0

| | |-- 0000:00:07.0

| | |-- 0000:00:07.1

| | |-- 0000:00:07.2

| | |-- 0000:00:07.3

| |-- platform

| | |-- floppy.0

| | |-- host0

| | |-- i8042

| |-- pnp0

| '-- system

|-- firmware

|-- kernel

| '-- hotplug_seqnum

|-- module

| |-- apm

| |-- autofs

| |-- cdrom

| |-- eisa_bus

| |-- i8042

| |-- ide_cd

| |-- ide_scsi

| |-- ieee1394

| |-- md_mod

| |-- ohci1394

| |-- parport

| |-- parport_pc

| |-- usb_storage

| |-- usbcore

| | |-- parameters

| | |-- refcnt

| | '-- sections

| |-- virtual_root

| | '-- parameters

| | '-- force_probe

| '-- vmhgfs

| |-- refcnt

| '-- sections

| '-- _ _versions

'-- power

'-- state

在/sys/bus的pci等子目录下,又会再分出drivers和devices目录,而devices目录中的文件是对/sys/devices目录中文件的符号链接。同样地,/sys/class目录下也包含许多对/sys/devices下文件的链接。如图5.2所示,这与设备、驱动、总线和类的现实状况是直接对应的,也正符合Linux 2.6的设备模型。

P125_40640.jpg 随着技术的不断进步,系统的拓扑结构越来越复杂,对智能电源管理、热插拔以及即插即用的支持要求也越来越高,Linux 2.4内核已经难以满足这些需求。为适应这种形势的需要,Linux 2.6内核开发了上述全新的设备、总线、类和驱动环环相扣的设备模型。图5.3形象地表示了Linux驱动模型中设备、总线和类之间的关系。

大多数情况下,Linux 2.6内核中的设备模型代码会作为“幕后黑手”处理好这些关系,内核中的总线级和其他内核子系统会完成与设备模型的交互,这使得驱动工程师几乎不需要关心设备模型。

在Linux内核中,分别使用bus_type、device_driver和device来描述总线、驱动和设备,这3个结构体定义于include/linux/device.h头文件中,其定义如代码清单5.6所示。

P126_40697.jpg 代码清单5.6 bus_type、device_driver和device结构体

1 struct bus_type {

2 const char *name;

3 struct bus_attribute *bus_attrs;

4 struct device_attribute *dev_attrs;

5 struct driver_attribute *drv_attrs;

6

7 int (match)(struct device dev, struct device_driver *drv);

8 int (uevent)(struct device dev, struct kobj_uevent_env *env);

9 int (probe)(struct device dev);

10 int (remove)(struct device dev);

11 void (shutdown)(struct device dev);

12

13 int (suspend)(struct device dev, pm_message_t state);

14 int (suspend_late)(struct device dev, pm_message_t state);

15 int (resume_early)(struct device dev);

16 int (resume)(struct device dev);

17

18 struct pm_ext_ops *pm;

19

20 struct bus_type_private *p;

21 };

22

23 struct device_driver {

24 const char *name;

25 struct bus_type *bus;

26

27 struct module *owner;

28 const char *mod_name;

29

30 int (probe) (struct device dev);

31 int (remove) (struct device dev);

32 void (shutdown) (struct device dev);

33 int (suspend) (struct device dev, pm_message_t state);

34 int (resume) (struct device dev);

35 struct attribute_group **groups;

36

37 struct pm_ops *pm;

38

39 struct driver_private *p;

40 };

41

42 struct device {

43 struct klist klist_children;

44 struct klist_node knode_parent;

45 struct klist_node knode_driver;

46 struct klist_node knode_bus;

47 struct device *parent;

48

49 struct kobject kobj;

50 char bus_id[BUS_ID_SIZE]; / 在父总线中的位置 /

51 const char init_name; / 设备的初始名 */

52 struct device_type *type;

53 unsigned uevent_suppress:1;

54

55 struct semaphore sem;

56

57 struct bus_type bus; / 设备所在的总线类型 */

58 struct device_driver driver; / 设备用到的驱动 */

59 void *driver_data;

60 void *platform_data;

61 struct dev_pm_info power;

62

63 #ifdef CONFIG_NUMA

64 int numa_node;

65 #endif

66 u64 *dma_mask;

67 u64 coherent_dma_mask;

68

69 struct device_dma_parameters *dma_parms;

70

71 struct list_head dma_pools;

72

73 struct dma_coherent_mem *dma_mem;

74

75 struct dev_archdata archdata;

76

77 spinlock_t devres_lock;

78 struct list_head devres_head;

79

80 struct klist_node knode_class;

81 struct class *class;

82 dev_t devt; / dev_t, 创建sysfs "dev" /

83 struct attribute_group**groups;

84

85 void (release)(struct device dev);

86 };

device_driver和device分别表示驱动和设备,而这两者都必须依附于一种总线,因此都包含struct bus_type指针。在Linux内核中,设备和驱动是分开注册的,注册1个设备的时候,并不需要驱动已经存在,而1个驱动被注册的时候,也不需要对应的设备已经被注册。设备和驱动各自涌向内核,而每个设备和驱动涌入的时候,都会去寻找自己的另一半。茫茫人海,何处觅踪?正是bus_type的match()成员函数将两者捆绑在一起。简单地说,设备和驱动就是红尘中漂浮的男女,而bus_type的match()则是牵引红线的月老,它可以识别什么设备与什么驱动可以配对。

注意,总线、驱动和设备都最终会落实为sysfs中的1个目录,因为进一步追踪代码会发现,它们实际上都可以认为是kobject的派生类(device结构体直接包含了kobject kobj成员,而bus_type 和device_driver则透过bus_type_private、driver_private间接包含kobject),kobject可看作所有总线、设备和驱动的抽象基类,1个kobject对应sysfs中的1个目录。

总线、设备和驱动中的各个attribute则直接落实为sysfs中的1个文件,attribute会伴随着show() 和store()这两个函数,分别用于读和写该attribute对应的sysfs文件结点,代码清单5.7给出了attribute、bus_attribute、driver_attribute和device_attribute这几个结构体的定义。

代码清单5.7 attribute、bus_attribute、driver_attribute和device_attribute结构体

1 struct attribute {

2 const char *name;

3 struct module *owner;

4 mode_t mode;

5 };

6

7 struct bus_attribute {

8 struct attribute attr;

9 ssize_t (show)(struct bus_type bus, char *buf);

10 ssize_t (store)(struct bus_type bus, const char *buf, size_t count);

11 };

12

13 struct driver_attribute {

14 struct attribute attr;

15 ssize_t (show)(struct device_driver driver, char *buf);

16 ssize_t (store)(struct device_driver driver, const char *buf,

17 size_t count);

18 };

19

20 struct device_attribute {

21 struct attribute attr;

22 ssize_t (show)(struct device dev, struct device_attribute *attr,

23 char *buf);

24 ssize_t (store)(struct device dev, struct device_attribute *attr,

25 const char *buf, size_t count);

26 };

事实上,udev规则中各信息的来源实际上就是bus_type、device_driver、device以及attribute等所对应sysfs节点。