《对Kjobject的一点研究.doc》由会员分享,可在线阅读,更多相关《对Kjobject的一点研究.doc(56页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、【精品文档】如有侵权,请联系网站删除,仅供学习与交流对Kjobject的一点研究.精品文档.在LINUX中最让人不解的大概就是/sys下面的内容了下面首先让我们来创建一个简单的platform设备,并从这个设备的视角进行深入,在此篇文章的深入过程中,我们只看kobeject的模型我所使用的内核版本号为2.6.26,操作系统的内核版本号为2.6.27-7,暂未发现2.6.27-7与2.6.26的重大不同首先写一个简单的模块#include #include #include static int _init test_probe(struct platform_device *pdev) int
2、 err = 0; return err;static int test_remove(struct platform_device *pdev) return 0;static struct platform_device test_device = .name = test_ts, .id = -1,;static struct platform_driver test_driver = .probe = test_probe, .remove = test_remove, .driver = .name = test_ts, .owner = THIS_MODULE, ,;static
3、int _devinit test_init(void) platform_device_register(&test_device); return platform_driver_register(&test_driver);static void _exit test_exit(void) platform_device_unregister(&test_device); platform_driver_unregister(&test_driver);module_init(test_init);module_exit(test_exit);MODULE_AUTHOR(zwolf);M
4、ODULE_DESCRIPTION(Module test);MODULE_LICENSE(GPL);MODULE_ALIAS(test);接下来是makefile#Makefileobj-m:=test.oKDIR:=/lib/modules/2.6.27-7-generic/buildPWD:=$(shell pwd)default: $(MAKE) -C $(KDIR) M=$(PWD) modulesKDIR中的目录请改为各位实际运行中的内核目录make之后进行模块的加载 sudo insmod ./test.ko现在到sys目录中查看我们的设备是否已经加载上了首先是/sys/bus/
5、platform/devices/在devices下,每一个连接文件都代表了一个设备ls可看见test_ts,进入test_ts,ls可发现driver这个链接文件,ls-l查看,发现这个文件是连到/sys/bus/platform/drivers/test_ts的这里需要说明的是连接的含义,并不是driver驱动存在于test_ts这个设备中,而是test_ts使用的驱动为/sys/bus/platform/drivers/test_ts现在换到/sys/bus/platform/drivers这个目录下ls查看会发现这里的文件都为目录,而非连接文件,说明这是驱动真正放置的位置现在进入tes
6、t_ts目录,然后ls,发现有一个test_ts的连接文件,ls l查看可发现该文件连接到/sys/devices/platform/test_ts下回到/sys/bus/platform/devices/下ls l也会发现test_ts连接到/sys/devices/platform/test_ts为什么test_ts这个设备放置于/sys/devices/platform下,而不是/sys/bus/platform/devices下呢我认为和直观性有关,在sys下有这么几个目录blockbusclassdevdevicesfirmwarekernelmodulefs power devic
7、es很直观的说明了设备在这个目录下,便于大家查找而/sys/bus/platform/devices下的连接是为了分类查找画了张目录图,如下,绿色框的为连接文件,绿色线条为连接的对象 题外话:我自身对于这样的分类不是很喜欢,臃肿 重复而且信息也不好规划,希望在以后的版本能对sys进行大的改造现在来看另两个图,也就是构成sys的核心kobject,首先第一个是我去掉了连接部分的内容也就是绿色线条的目录图第二个是组成这个目录图的核心,kobject图,我也叫他层次图不看大号绿色箭头右边的内容的话是不是发现两个架构相同?对的,kobject的层次决定了目录的结构kobeject图很大,但也不要担心,
8、里面的内容其实不多,基础框架涉及3个主要结构kset kobject和ktype在说明test_ts的注册之前,先让我们看一下sys下的两个基础目录bus,devices首先是busbus的注册在/drivers/base/bus.c里int _init buses_init(void) bus_kset = kset_create_and_add(bus, &bus_uevent_ops, NULL); if (!bus_kset) return -ENOMEM; return 0;先看bus_uevent_ops,这是一个uevent的操作集(我也还没清楚uevent的用途,所以ueven
9、t的内容先放着)然后到kset_create_and_addstruct kset *kset_create_and_add(const char *name, struct kset_uevent_ops *uevent_ops, struct kobject *parent_kobj)/传递进来的参数为(bus, &bus_uevent_ops, NULL) struct kset *kset; int error; /创建一个kset容器 kset = kset_create(name, uevent_ops, parent_kobj); if (!kset) return NULL;
10、/注册创建的kset容器 error = kset_register(kset); if (error) kfree(kset); return NULL; return kset;首先需要创建一个kset容器static struct kset *kset_create(const char *name, struct kset_uevent_ops *uevent_ops, struct kobject *parent_kobj)/传递进来的参数为(bus, &bus_uevent_ops, NULL) struct kset *kset; /为kset分配内存 kset = kzallo
11、c(sizeof(*kset), GFP_KERNEL); if (!kset) return NULL; /设置kset中kobject的名字,这里为bus kobject_set_name(&kset-kobj, name); /设置uevent操作集,这里为bus_uevent_ops kset-uevent_ops = uevent_ops; /设置父对象,这里为NULL kset-kobj.parent = parent_kobj; /设置容器操作集 kset-kobj.ktype = &kset_ktype; /设置父容器 kset-kobj.kset = NULL; return
12、 kset;这里的ktype,也就是kset_ktype是一个操作集,用于为sys下文件的实时反馈做服务,例如我们cat name的时候就要通过ktype提供的show函数,具体什么怎么运用,将在后面讲解现在回到kset_create_and_add中的kset_register,将建立好的kset添加进sys里int kset_register(struct kset *k) int err; if (!k) return -EINVAL; /初始化 kset_init(k); /添加该容器 err = kobject_add_internal(&k-kobj); if (err) retu
13、rn err; kobject_uevent(&k-kobj, KOBJ_ADD); return 0;kset_init进行一些固定的初始化操作,里面没有我们需要关心的内容kobject_add_internal为重要的一个函数,他对kset里kobj的从属关系进行解析,搭建正确的架构static int kobject_add_internal(struct kobject *kobj) int error = 0; struct kobject *parent; /检测kobj是否为空 if (!kobj) return -ENOENT; /检测kobj名字是否为空 if (!kobj-
14、name | !kobj-name0) pr_debug(kobject: (%p): attempted to be registered with empty name!n, kobj); WARN_ON(1); return -EINVAL; /提取父对象 parent = kobject_get(kobj-parent); /* join kset if set, use it as parent if we do not already have one */ /父容器存在则设置父对象 if (kobj-kset) /在bus的kset中为空,所以不会进入到下面的代码 /检测是否已经
15、设置父对象 if (!parent) /无则使用父容器为父对象 parent = kobject_get(&kobj-kset-kobj); /添加该kobj到父容器的链表中 kobj_kset_join(kobj); /设置父对象 kobj-parent = parent; pr_debug(kobject: %s (%p): %s: parent: %s, set: %sn, kobject_name(kobj), kobj, _func_, parent ? kobject_name(parent) : , kobj-kset ? kobject_name(&kobj-kset-kobj
16、) : ); /建立相应的目录 error = create_dir(kobj); if (error) kobj_kset_leave(kobj); kobject_put(parent); kobj-parent = NULL; if (error = -EEXIST) printk(KERN_ERR %s failed for %s with -EEXIST, dont try to register things with the same name in the same directory.n, _func_, kobject_name(kobj); else printk(KER
17、N_ERR %s failed for %s (%d)n, _func_, kobject_name(kobj), error); dump_stack(); else kobj-state_in_sysfs = 1; return error;至此bus的目录就建立起来了模型如下接下来是devices,在/drivers/base/core.c里int _init devices_init(void) devices_kset = kset_create_and_add(devices, &device_uevent_ops, NULL); if (!devices_kset) return
18、 -ENOMEM; return 0;过程和bus的注册一致,我就不复述了模型如下然后是platform的注册在platform的注册中,分为两个部分,一部分是注册到devices中,另一部分是注册到bus中,代码在/drivers/base/platform.c中int _init platform_bus_init(void) int error; /注册到devices目录中 error = device_register(&platform_bus); if (error) return error; /注册到bus目录中 error =bus_register(&platform_b
19、us_type); if (error) device_unregister(&platform_bus); return error;首先是device_register,注册的参数为platform_bus,如下所示struct device platform_bus = .bus_id = platform,;很简单,只有一个参数,表明了目录名int device_register(struct device *dev) /初始化dev结构 device_initialize(dev); /添加dev至目录 return device_add(dev);void device_initi
20、alize(struct device *dev) /重要的一步,指明了父容器为devices_kset,而devices_kset的注册在前面已经介绍过了 dev-kobj.kset = devices_kset; /初始化kobj的ktype为device_ktype kobject_init(&dev-kobj, &device_ktype); klist_init(&dev-klist_children, klist_children_get, klist_children_put); INIT_LIST_HEAD(&dev-dma_pools); INIT_LIST_HEAD(&de
21、v-node); init_MUTEX(&dev-sem); spin_lock_init(&dev-devres_lock); INIT_LIST_HEAD(&dev-devres_head); device_init_wakeup(dev, 0); set_dev_node(dev, -1);int device_add(struct device *dev) struct device *parent = NULL; struct class_interface *class_intf; int error; dev = get_device(dev); if (!dev | !strl
22、en(dev-bus_id) error = -EINVAL; goto Done; pr_debug(device: %s: %sn, dev-bus_id, _func_); parent = get_device(dev-parent); setup_parent(dev, parent); if (parent) set_dev_node(dev, dev_to_node(parent); /设置dev-kobj的名字和父对象,并建立相应的目录 error = kobject_add(&dev-kobj, dev-kobj.parent, %s, dev-bus_id); if (er
23、ror) goto Error; if (platform_notify) platform_notify(dev); if (dev-bus) blocking_notifier_call_chain(&dev-bus-p-bus_notifier, BUS_NOTIFY_ADD_DEVICE, dev); /建立uevent文件 error = device_create_file(dev, &uevent_attr); if (error) goto attrError; if (MAJOR(dev-devt) error = device_create_file(dev, &devt_
24、attr); if (error) goto ueventattrError; /建立subsystem连接文件连接到所属class,这里没有设置class对象所以不会建立 error = device_add_class_symlinks(dev); if (error) goto SymlinkError; /建立dev的描述文件,这里没有设置描述文件所以不会建立 error = device_add_attrs(dev); if (error) goto AttrsError; /建立链接文件至所属bus,这里没有设置所属bus所以不会建立 error = bus_add_device(
25、dev); if (error) goto BusError; /添加power文件,因为platform不属于设备,所以不会建立power文件 error = device_pm_add(dev); if (error) goto PMError; kobject_uevent(&dev-kobj, KOBJ_ADD); /检测驱动中有无适合的设备进行匹配,但没有设置bus,所以不会进行匹配 bus_attach_device(dev); if (parent) klist_add_tail(&dev-knode_parent, &parent-klist_children); if (de
26、v-class) down(&dev-class-sem); list_add_tail(&dev-node, &dev-class-devices); list_for_each_entry(class_intf, &dev-class-interfaces, node) if (class_intf-add_dev) class_intf-add_dev(dev, class_intf); up(&dev-class-sem); Done: put_device(dev); return error;PMError: bus_remove_device(dev);BusError: if
27、(dev-bus) blocking_notifier_call_chain(&dev-bus-p-bus_notifier, BUS_NOTIFY_DEL_DEVICE, dev); device_remove_attrs(dev);AttrsError: device_remove_class_symlinks(dev);SymlinkError: if (MAJOR(dev-devt) device_remove_file(dev, &devt_attr);ueventattrError: device_remove_file(dev, &uevent_attr);attrError:
28、kobject_uevent(&dev-kobj, KOBJ_REMOVE); kobject_del(&dev-kobj);Error: cleanup_device_parent(dev); if (parent) put_device(parent); goto Done;在kobject_add- kobject_add_varg- kobject_add_internal中/提取父对象,因为没有设置,所以为空parent = kobject_get(kobj-parent);/父容器存在则设置父对象,在前面的dev-kobj.kset = devices_kset中设为了device
29、s_ksetif (kobj-kset) /检测是否已经设置父对象 if (!parent) /无则使用父容器为父对象 parent = kobject_get(&kobj-kset-kobj);/添加该kobj到父容器的链表中 kobj_kset_join(kobj); /设置父对象 kobj-parent = parent;现在devices下的platform目录建立好了,模型如下,其中红线描绘了目录关系现在到bus_register了注册的参数platform_bus_type如下所示struct bus_type platform_bus_type = .name = platfor
30、m, .dev_attrs = platform_dev_attrs, .match = platform_match, .uevent = platform_uevent, .suspend = platform_suspend, .suspend_late = platform_suspend_late, .resume_early = platform_resume_early, .resume = platform_resume,;int bus_register(struct bus_type *bus) int retval; /声明一个总线私有数据并分配空间 struct bus
31、_type_private *priv; priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL); if (!priv) return -ENOMEM; /互相关联 priv-bus = bus; bus-p = priv; BLOCKING_INIT_NOTIFIER_HEAD(&priv-bus_notifier); /设置私有数据中kobj对象的名字 retval = kobject_set_name(&priv-subsys.kobj, %s, bus-name); if (retval) goto out; /设置父容器
32、为bus_kset,操作集为bus_ktype priv-subsys.kobj.kset = bus_kset; priv-subsys.kobj.ktype = &bus_ktype; priv-drivers_autoprobe = 1; /注册bus容器 retval = kset_register(&priv-subsys); if (retval) goto out; /建立uevent属性文件 retval = bus_create_file(bus, &bus_attr_uevent); if (retval) goto bus_uevent_fail; /建立devices目
33、录 priv-devices_kset = kset_create_and_add(devices, NULL, &priv-subsys.kobj); if (!priv-devices_kset) retval = -ENOMEM; goto bus_devices_fail; /建立drivers目录 priv-drivers_kset = kset_create_and_add(drivers, NULL, &priv-subsys.kobj); if (!priv-drivers_kset) retval = -ENOMEM; goto bus_drivers_fail; /初始化k
34、list_devices和klist_drivers链表 klist_init(&priv-klist_devices, klist_devices_get, klist_devices_put); klist_init(&priv-klist_drivers, NULL, NULL); /增加probe属性文件 retval = add_probe_files(bus); if (retval) goto bus_probe_files_fail; /增加总线的属性文件 retval = bus_add_attrs(bus); if (retval) goto bus_attrs_fail; pr_debug(bus: %s: registeredn, bus-name); return 0;bus_attrs_fa