本文欢迎转载, 请标明出处
本文出处: http://blog.csdn.net/dyron
int __init sysfs_init(void) { int err = -ENOMEM; sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache", sizeof(struct sysfs_dirent), 0, 0, NULL); if (!sysfs_dir_cachep) goto out; err = sysfs_inode_init(); if (err) goto out_err; err = register_filesystem(&sysfs_fs_type); if (!err) { sysfs_mnt = kern_mount(&sysfs_fs_type); if (IS_ERR(sysfs_mnt)) { printk(KERN_ERR "sysfs: could not mount!\n"); err = PTR_ERR(sysfs_mnt); sysfs_mnt = NULL; unregister_filesystem(&sysfs_fs_type); goto out_err; } } else goto out_err; out: return err; out_err: kmem_cache_destroy(sysfs_dir_cachep); sysfs_dir_cachep = NULL; goto out; }
static struct file_system_type sysfs_fs_type = { .name = "sysfs", .get_sb = sysfs_get_sb, .kill_sb = sysfs_kill_sb, }sysfs_get_sb在内核空间创造了一棵独立的VFS树, 内核创建这棵树主要用来沟通系统中总线,设备与驱动,同
struct kobject { const char *name; struct list_head entry; struct kobject *parent; struct kset *kset; struct kobj_type *ktype; struct sysfs_dirent *sd; struct kref kref; unsigned int state_initialized:1; unsigned int state_in_sysfs:1; unsigned int state_add_uevent_sent:1; unsigned int state_remove_uevent_sent:1; unsigned int uevent_suppress:1; }
const char *name: 表示该内核对象的名称. 如果该对象加入系统, 它的name将会出现在sysfs文件系统中. struct list_head entry: 用来将一系列的内核对象构成链表. struct kobject *parent: 指向该内核对象的上层节点. struct kset *kset: 当前内核对象所属的kset对象的指针. kset对象代表一个subsystem, 其中容纳了一系 列同类型的kobject对象. struct kref kref: 其核心数据是一原子型变量, 用来表示内核对象的引用计数. struct kobj_type *ktype: 定义了该内核对象的一组sysfs文件系统相关的操作函数和属性. 不同类型的内 核对象会有不同的ktype, 用以体现kobject所代表的内核对象的特质. 通过该成员,C中 的struct 据类型具备了c++中class类型的某些特点. 同时,内核通过ktype将kobject对 象的sysfs文件操作与其属性文件关联起来. struct sysfs_dirent *sd: 用来表示该内核对象在sysfs文件系统中对应的目录项的实例. unsigned int state_initialized: 表示该kobject代表的对象的初始化状态.1已初始化.0尚未初始化. unsigned int state_in_sysfs: 表示该kobject代表的内核对象有没有在sysfs文件中建立一个入口点. unsigned int uevent_suppress: 如果kobject对象属于某一kset, 那么它的状态变化可以导致其所在的kset 对象向用户空间发送event消息. 该标志表示当该kobject发生变化时, 是否让其所在的k set向用户空间发送event消息. 1表示不让kset发送这种event消息. kboject数据结构最通的的用法是嵌在某一对象的数据结构中. . kobject_set_name 用来设定kobject中的name成员. . kobject_init 用来初始化一个内核对象的kobject结构. . kobject_add 主要功能有两个:1是建立kobject对象间的层次关系.2是在sysfs文件系统中建立一个目录.在 将一个kobject对象通过kobject_add加入系统前, kobject对象必须被初始化. . kobject_init_and_add 实际的工作是将kobject_init和kobject_add两个函数的功能合并到一起. . kobject_create 用来分配并初始化一个kobject对象. . kobject_create_and_add 实际的工作是将kobject_create和kobject_add函数的功能合并到一起. . kobject_del 删除一个kobject对象9.2.2 kobject的类型属性
struct kobj_type { void (*release)(struct kobject *kobj); const struct sysfs_ops *sysfs_ops; struct attribute **default_attrs; const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj); const void *(*namespace)(struct kobject *kobj); }; release 是一个函数指针, sysfs_ops是一struct sysfs_ops类型的指针 struct sysfs_ops { ssize_t (*show)(struct kobject *, struct attribute *,char *); ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t); };sysfs_ops实际上定义了一组针对struct attribute对象的操作函数的集合, struct attribute数据结构则是
struct attribute { const char *name; mode_t mode; }kobject_init初始化一个kobject的时候, 会赋予它一个具体的struct kobj_type对象成员, 为一个kobject
int sysfs_create_file(struct kobject * kobj, const struct attribute * attr) { BUG_ON(!kobj || !kobj->sd || !attr); return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR); }
struct kset { struct list_head list; spinlock_t list_lock; struct kobject kobj; const struct kset_uevent_ops *uevent_ops; };struct list_head list: 用来将其中的kobject对象构成链表.
struct kset_uevent_ops { int (* const filter)(struct kset *kset, struct kobject *kobj); const char *(* const name)(struct kset *kset, struct kobject *kobj); int (* const uevent)(struct kset *kset, struct kobject *kobj, struct kobj_uevent_env *env); };. kset_init: 用来初始化一个kset对象.
int kobject_uevent(struct kobject *kobj, enum kobject_action action) { return kobject_uevent_env(kobj, action, NULL); }参数action是个枚举型变量, 定义为:
enum kobject_action { KOBJ_ADD, KOBJ_REMOVE, KOBJ_CHANGE, KOBJ_MOVE, KOBJ_ONLINE, KOBJ_OFFLINE, KOBJ_MAX };kobject_uevent_env总体上可分成三个功能部分:
static inline int call_usermodehelper(char *path, char **argv, char **envp, enum umh_wait wait) { return call_usermodehelper_fns(path, argv, envp, wait, NULL, NULL, NULL); }跳过非核心的代码, 直接到核心部分.
static inline int call_usermodehelper_fns(char *path, char **argv, char **envp, enum umh_wait wait, int (*init)(struct subprocess_info *info, struct cred *new), void (*cleanup)(struct subprocess_info *), void *data) { struct subprocess_info *info; gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL; info = call_usermodehelper_setup(path, argv, envp, gfp_mask); if (info == NULL) return -ENOMEM; call_usermodehelper_setfns(info, init, cleanup, data); return call_usermodehelper_exec(info, wait); }这个函数的设计思想是采用工作队列的方式, 在call_usermodehelper_setup内部分实始化一个工作队列节点
void __init usermodehelper_init(void) { khelper_wq = create_singlethread_workqueue("khelper"); }其次, call_usermodehelper_exec通过引入一个completion变量done来实现和工作节点sub_info->work上的
int kernel_execve(const char *filename, const char *const argv[], const char *const envp[]) { long __res; asm volatile ("int $0x80" : "=a" (__res) : "0" (__NR_execve), "b" (filename), "c" (argv), "d" (envp) : "memory"); return __res; }kernel_execve是个体系架构相关的函数, 它做的首先是int $0x80陷入系统调用, 进入系统调用后, 一个很
struct bus_type { const char *name; 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 (*uevent)(struct device *dev, struct kobj_uevent_env *env); 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); const struct dev_pm_ops *pm; struct subsys_private *p; };const char *name: 总线的名称.
struct subsys_private { struct kset subsys; struct kset *devices_kset; struct kset *drivers_kset; struct klist klist_devices; struct klist klist_drivers; struct blocking_notifier_head bus_notifier; unsigned int drivers_autoprobe:1; struct bus_type *bus; struct list_head class_interfaces; struct kset glue_dirs; struct mutex class_mutex; struct class *class; };struct kset subsys表示该bus所在的子系统, 内核中所有通过bus_register注册进系统的bus所在的kset都将
int __init buses_init(void) { bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL); if (!bus_kset) return -ENOMEM; return 0; }这里创建一个名为"bus"的kset并将其加入到sysfs文件系统树中, 这里的bus_event_ops定义了当"bus"这个
static int bus_uevent_filter(struct kset *kset, struct kobject *kobj) { struct kobj_type *ktype = get_ktype(kobj); if (ktype == &bus_ktype) return 1; return 0; } static const struct kset_uevent_ops bus_uevent_ops = { .filter = bus_uevent_filter, };如果要求发送的uevent消息类型不是总线类型, 那么函数返回0, 不发送到用户空间. buses_init将在sysfs
struct bus_attribute { struct attribute attr; ssize_t (*show)(struct bus_type *bus, char *buf); ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count); };成员变量attr表示总线的属性信息, 其类型为struct attribute.
struct attribute { const char *name; mode_t mode; }struct bus_attribute的另外两个成员show和store分别用来显示和更改总线的属性. 内核定义了一个宏BUS_
#define BUS_ATTR(_name, _mode, _show, _store) \ struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store) #define __ATTR(_name,_mode,_show,_store) { \ .attr = {.name = __stringify(_name), .mode = _mode }, \ .show = _show, \ .store = _store, \ }BUS_ATTR宏将定义一个以bus_attr_开头的总线属性对象, 生成属性文件则需要bus_create_file函数.
int bus_create_file(struct bus_type *bus, struct bus_attribute *attr) { int error; if (bus_get(bus)) { error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr); bus_put(bus); } else error = -EINVAL; return error; }9.3.3 设备与驱动的绑定
int device_bind_driver(struct device *dev) { int ret; ret = driver_sysfs_add(dev); if (!ret) driver_bound(dev); return ret; }driver_sysfs_add用来在sysfs文件系统中建立绑定的设备与驱动程序间的链接符号文件, driver_bound函数
struct device { struct device *parent; struct device_private *p; struct kobject kobj; const char *init_name; /* initial name of the device */ const struct device_type *type; struct mutex mutex; /* mutex to synchronize calls to * its driver. */ struct bus_type *bus; /* type of bus device is on */ struct device_driver *driver; /* which driver has allocated this device */ void *platform_data; /* Platform specific data, device core doesn't touch it */ struct dev_pm_info power; struct dev_power_domain *pwr_domain; #ifdef CONFIG_NUMA int numa_node; /* NUMA node this device is close to */ #endif u64 *dma_mask; /* dma mask (if dma'able device) */ u64 coherent_dma_mask;/* Like dma_mask, but for alloc_coherent mappings as not all hardware supports 64 bit addresses for consistent allocations such descriptors. */ struct device_dma_parameters *dma_parms; struct list_head dma_pools; /* dma pools (if dma'ble) */ struct dma_coherent_mem *dma_mem; /* internal for coherent mem override */ /* arch specific additions */ struct dev_archdata archdata; struct device_node *of_node; /* associated device tree node */ dev_t devt; /* dev_t, creates the sysfs "dev" */ spinlock_t devres_lock; struct list_head devres_head; struct klist_node knode_class; struct class *class; const struct attribute_group **groups; /* optional groups */ void (*release)(struct device *dev); };
struct device_driver { const char *name; struct bus_type *bus; struct module *owner; const char *mod_name; /* used for built-in modules */ bool suppress_bind_attrs; /* disables bind/unbind via sysfs */ const struct of_device_id *of_match_table; 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); const struct attribute_group **groups; const struct dev_pm_ops *pm; struct driver_private *p; };const char *name : 驱动的名称.
struct class { const char *name; struct module *owner; struct class_attribute *class_attrs; struct device_attribute *dev_attrs; struct bin_attribute *dev_bin_attrs; struct kobject *dev_kobj; int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env); char *(*devnode)(struct device *dev, mode_t *mode); 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); const struct kobj_ns_type_operations *ns_type; const void *(*namespace)(struct device *dev); const struct dev_pm_ops *pm; struct subsys_private *p; };
本文欢迎转载, 请标明出处
本文出处: http://blog.csdn.net/dyron