Udev设备文件系统:linux2.6内核中,devfs被认为是过时的。 1.udev完全工作在用户态工作,利用设备加入或移除锁发送的热插拔时间(hotplug event)工作。在热插拔时,设备的详细信息会由内核输出到位于/sys的sysfs文件系统,由于udev根据硬件动态更新设备文件,进行设备文件的创建和删除,所以在/dev目录下就会只包含真正存在的设备。Devfs和udev明显区别;采用devfs当一个并不存在的/dev节点被打开适合会自动加载驱动,而udev认为在设备被发现时候才加载驱动模块。 Sysfs文件系统与linux设备模型 Sysfs文件系统:把连接到系统上的设备和总线组织成为一个分级文件,可以由用户空间存取,向用户空间导出内核数据及其他们的属性,sysfs的一个目的就是展示涉笔驱动模型中各组件的层次关系。 设备模型中的关键数据结构:
是构成设备管理能力的核心结构,一个kobject对应于一个sysfs文件系统的一个目录。 Kref成员实现对象应用计数器管理,提供kobject_get(),kobject_put()分别用于增加和减少应用计数器,当引用计数器为0时,该对象使用资源被释放。 Ktype指向kobj_type结构指针,标识该对象类型。
包括了释放kobject占用资源的release()函数,指向sysfs操作的sysfs_ops指针和sysfs文件系统默认属性列表。
分别用于属性的读和写 一系列的kobject操作函数: Kobject_init用于初始kobject,设置kobject引用计数器为以,entry指向自身,其所属kset引用计数器加1. Kobject_add(struct kobject *kobj);//该函数将kobject对象加入linux设备层次,挂接到kobject对象到所属的kset的list链表中,增加kobject引用计数器,在parent指向的目录下创建文件节点,并启动该类型内核对象的hotplug函数。对应有kobject_del()从linux设备层次(hierarchy)中删除kobject对象。 Kobject_register()先调用kobject_init初始化,然后调用kobject_add(),对应相反的是kobject_unregister 2.kset:kobject通过kset组织成为层次化的结构,kset是具有相同类型的kobject的集合。
//与kobject相似,linux提供了一系列的函数操作kset,kset_init完成指定的kset初始化,kset_get()和kset_put()分别增加和减少kset对象引用计数器,kset_add()和kset_del()函数把指定的kset对象加入设备层次和从其中删除,kset_register()函数完成kset的注册和kset_unregister函数则完成kset的注销。Kobject被创建或删除时能产生event,kobject所属的kset可以过滤event或者为用户空间添加消息。Kset的uevent_ops成员执行该kset事件集合kset_uevent_ops指针。 3. struct subsystem { struct kset kset; struct rw_semaphore rwsem; };//一系列kset的集合,描述一类子系统,如字符设备,块设备等等。每个kset必须属于某个subsystem,设置kset结构中的subsys域指向指定的subsystem可以将kset加入到该subsystem,所有挂接到同一个subsystem的kset共享同一个rwsem信号量,用于同步访问kset中的链表。内核提供类似kset和kobject的函数操作subsystem操作。
1. linux设备模型组件:任一设备都在设备模型中有一个device相对应。 struct device { struct list_head g_list; struct list_head node; struct list_head bus_list; struct list_head driver_list; struct list_head intf_list; struct list_head children; struct device * parent; char name[DEVICE_NAME_SIZE]; char bus_id[BUS_ID_SIZE]; spinlock_t lock; atomic_t refcount; struct bus_type * bus; struct driver_dir_entry dir; u32 class_num; struct device_driver *driver; void *driver_data; void *platform_data; u32 current_state; unsigned char *saved_state; void (*release)(struct device * dev); }; Fields ~~~~~~ g_list: Node in the global device list. node: Node in device's parent's children list. bus_list: Node in device's bus's devices list. driver_list: Node in device's driver's devices list. intf_list: List of intf_data. There is one structure allocated for each interface that the device supports. children: List of child devices. parent: *** FIXME *** name: ASCII description of device. Example: " 3Com Corporation 3c905 100BaseTX [Boomerang]" bus_id: ASCII representation of device's bus position. This field should be a name unique across all devices on the bus type the device belongs to. Example: PCI bus_ids are in the form of <bus number>:<slot number>.<function number> This name is unique across all PCI devices in the system. lock: Spinlock for the device. refcount: Reference count on the device. bus: Pointer to struct bus_type that device belongs to. dir: Device's sysfs directory. class_num: Class-enumerated value of the device. driver: Pointer to struct device_driver that controls the device. driver_data: Driver-specific data. platform_data: Platform data specific to the device. current_state: Current power state of the device. saved_state: Pointer to saved state of the device. This is usable by the device driver controlling the device. release: Callback to free the device after all references have gone away. This should be set by the allocator of the device (i.e. the bus driver that discovered the device). Device结构体用于描述设备相关的信息设备之间的层次关系,以及设备与总线,驱动的关系。内核提供函数device_resgister()函数将一个新的device对象插入设备模型,并自动在/sys/device下创建一个对应的目录。通常device结构体不单独使用,而包含于更大的机构体中,比如struct pci_dev.驱动程序由device_driver对象描述,对应的机构如下: struct device_driver { const char *name; struct bus_type *bus;
struct module *owner; const char *mod_name; /* used for built-in modules */
int (*probe) (struct device *dev); int (*remove) (struct device *dev); void (*shutdown) (struct device *dev); int (*suspend) (struct device *dev, pm_message_t state); int (*resume) (struct device *dev); struct attribute_group **groups;
struct dev_pm_ops *pm;
struct driver_private *p; };//通过内嵌的kobject对象实现引用计数器管理和层次结构组织。Driver_register()用于相设备模型插入新的driver对象,同时在sysfs文件系统中创建相应目录。
系统中的总线由struct bus_type描述 Definition struct bus_type { char * name; struct subsystem subsys;//与该总线相关的subsystem struct kset drivers;//所有与该总线相关的驱动程序集合 struct kset devices;//所有挂载在该总线上的设备 struct bus_attribute * bus_attrs;//总线属性 struct device_attribute * dev_attrs;//设备属性 struct driver_attribute * drv_attrs;//驱动程序属性 int (*match)(struct device * dev, struct device_driver * drv); int (*hotplug) (struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size); int (*suspend)(struct device * dev, pm_message_t state); int (*resume)(struct device * dev); }; 每个bus_type对象都内嵌一个subsystem对象,bus_subsys对象管理系统中所有总线类型的subsystem对象,每个bus_type对象都对应/sys/bus目录下的一个子目录,该目录下都存在两个子目录:devices和drivers(分别对应bus_type机构中的devices和drivers域)
系统中的设备类由struct class描述,表示一类设备,所有的class对象都属于class_subsys子系统,对应于sysfs文件系统中的/sys/class目录。 /* * device classes */ struct class { const char *name; struct module *owner;
struct class_attribute *class_attrs; struct device_attribute *dev_attrs; struct kobject *dev_kobj;
int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
void (*class_release)(struct class *class); void (*dev_release)(struct device *dev);
int (*suspend)(struct device *dev, pm_message_t state); int (*resume)(struct device *dev);
struct dev_pm_ops *pm; struct class_private *p; }; struct device_class { char * name; rwlock_t lock; u32 devnum; struct list_head node; struct list_head drivers; struct list_head intf_list; struct driver_dir_entry dir; struct driver_dir_entry device_dir; struct driver_dir_entry driver_dir; devclass_add add_device; devclass_remove remove_device; }; 每个class对象包括一个class——device链表,每个class_device对象表示一个逻辑设备,并通过struct class_device中的dev成员并联一个物理设备。这样,一个逻辑设备总对应一个物理设备,但是一个物理设备却却可能对应多个逻辑设备。
属性 在bus,device,driver,class层次上都分别定义了其属性结构体,包括bus_attribute ,driver_attribute, class_device_attribute.这几个结构本质完全相同
udev组成:设计目标: 1. 用户空间中执行 2. 动态建立/删除设备文件 3. 允许每个人都不关心主/次设备号 4. 提供LSB标准名称 5. 如果需要,提供固定的名称 Udev由下面3部分分割计划发展,namedev,libsysfs,udev,namedev为设备命名子系统,libsysfs提供访问sysfs文件系统从中获取消息的标准接口,udev提供/dev设备节点文件的动态创建和删除策略。 原理:内核检测到系统新设备后,内核在sysfs文件系统中为新设备生产记录并导出设备信息及其所发生的事件。Udev获取内核导出信息,调用namedev决定设备指定名称,udev调用libsysfs决定应该为该设备的是被文件指定主/次设备号,并用分析获取设备名称和主/次设备号创建/dev设备文件。 Namedev规则: 1. 标签/序号:检查设备是否有唯一的识别标号。 2. 设备设备号:进一步检查总线设备编号,如果找到规则,那么规则中的名字被使用 3. 总线上的拓扑:当设备在总线位置匹配用户指定规则,则使用该该规则指定名称。 4. 替代名称:内核提供的名称匹配指定的替代字符串时,就会使用替代字符串指定的名称。 5. 内核提供的名称:以上步骤规则没有提供,缺省的内核规则将被指定给该设备。 (songok2007) |