1: 在LINUX中最让人不解的大概就是/sys下面的内容了
2:
3: 下面首先让我们来创建一个简单的platform设备,并从这个设备的视角进行深入,在此篇文章的深入过程中,我们只看kobeject的模型
4: 我所使用的内核版本号为2.6.26,操作系统的内核版本号为2.6.27-7,暂未发现2.6.27-7与2.6.26的重大不同
5:
6: 首先写一个简单的模块
7:
8: #include
9: #include
10: #include
11:
12: static int __init test_probe(struct platform_device *pdev)
13: {
14: int err = 0;
15: return err;
16: }
17:
18: static int test_remove(struct platform_device *pdev)
19: {
20: return 0;
21: }
22: static struct platform_device test_device = {
23: .name = "test_ts",
24: .id = -1,
25: };
26:
27: static struct platform_driver test_driver = {
28: .probe = test_probe,
29: .remove = test_remove,
30: .driver = {
31: .name = "test_ts",
32: .owner = THIS_MODULE,
33: },
34: };
35:
36: static int __devinit test_init(void)
37: {
38: platform_device_register(&test_device);
39: return platform_driver_register(&test_driver);
40: }
41:
42: static void __exit test_exit(void)
43: {
44: platform_device_unregister(&test_device);
45: platform_driver_unregister(&test_driver);
46: }
47:
48: module_init(test_init);
49: module_exit(test_exit);
50:
51: MODULE_AUTHOR("zwolf");
52: MODULE_DESCRIPTION("Module test");
53: MODULE_LICENSE("GPL");
54: MODULE_ALIAS("test");
55:
56:
57: 接下来是makefile
58:
59: #Makefile
60:
61: obj-m:=test.o
62: KDIR:=/lib/modules/2.6.27-7-generic/build
63: PWD:=$(shell pwd)
64:
65: default:
66: $(MAKE) -C $(KDIR) M=$(PWD) modules
67:
68:
69: KDIR中的目录请改为各位实际运行中的内核目录
70:
71: make之后进行模块的加载 sudo insmod ./test.ko
72:
73: 现在到sys目录中查看我们的设备是否已经加载上了
74:
75: 首先是/sys/bus/platform/devices/
76:
77: 在devices下,每一个连接文件都代表了一个设备
78:
79: ls可看见test_ts,进入test_ts,ls可发现driver这个链接文件,ls-l查看,发现这个文件是连到/sys/bus/platform/drivers/test_ts的
80:
81: 这里需要说明的是连接的含义,并不是driver驱动存在于test_ts这个设备中,而是test_ts使用的驱动为/sys/bus/platform/drivers/test_ts
82:
83: 现在换到/sys/bus/platform/drivers这个目录下
84:
85: ls查看会发现这里的文件都为目录,而非连接文件,说明这是驱动真正放置的位置
86:
87: 现在进入test_ts目录,然后ls,发现有一个test_ts的连接文件,ls –l查看可发现该文件连接到/sys/devices/platform/test_ts下
88:
89: 回到/sys/bus/platform/devices/下ls –l也会发现test_ts连接到/sys/devices/platform/test_ts
90:
91: 为什么test_ts这个设备放置于/sys/devices/platform下,而不是/sys/bus/platform/devices下呢
92:
93: 我认为和直观性有关,在sys下有这么几个目录block bus class dev devices firmware kernel module fs power
94: devices很直观的说明了设备在这个目录下,便于大家查找
95: 而/sys/bus/platform/devices下的连接是为了分类查找
96:
97: 画了张目录图,如下,绿色框的为连接文件,绿色线条为连接的对象
98:
99:
100:
101: 题外话:我自身对于这样的分类不是很喜欢,臃肿 重复 而且信息也不好规划,希望在以后的版本能对sys进行大的改造
102:
103:
104: 现在来看另两个图,也就是构成sys的核心kobject,首先第一个是我去掉了连接部分的内容 也就是绿色线条的目录图
105:
106:
107: 第二个是组成这个目录图的核心,kobject图,我也叫他层次图
108:
109: 不看大号绿色箭头右边的内容的话是不是发现两个架构相同?
110: 对的,kobject的层次决定了目录的结构
111: kobeject图很大,但也不要担心,里面的内容其实不多,基础框架涉及3个主要结构kset kobject和ktype
112: 在说明test_ts的注册之前,先让我们看一下sys下的两个基础目录bus,devices
113:
114: 首先是bus
115: bus的注册在/drivers/base/bus.c里
116: int __init buses_ini
117:
118: t(void)
119: {
120: bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
121: if (!bus_kset)
122: return -ENOMEM;
123: return 0;
124: }
125:
126: 先看bus_uevent_ops,这是一个uevent的操作集(我也还没清楚uevent的用途,所以uevent的内容先放着)
127:
128: 然后到kset_create_and_add
129:
130: struct kset *kset_create_and_add(const char *name,
131: struct kset_uevent_ops *uevent_ops,
132: struct kobject *parent_kobj)
133: //传递进来的参数为("bus", &bus_uevent_ops, NULL)
134: {
135: struct kset *kset;
136: int error;
137:
138: //创建一个kset容器
139: kset = kset_create(name, uevent_ops, parent_kobj);
140: if (!kset)
141: return NULL;
142:
143: //注册创建的kset容器
144: error = kset_register(kset);
145: if (error) {
146: kfree(kset);
147: return NULL;
148: }
149: return kset;
150: }
151:
152: 首先需要创建一个kset容器
153: static struct kset *kset_create(const char *name,
154: struct kset_uevent_ops *uevent_ops,
155: struct kobject *parent_kobj)
156: //传递进来的参数为("bus", &bus_uevent_ops, NULL)
157: {
158: struct kset *kset;
159:
160: //为kset分配内存
161: kset = kzalloc(sizeof(*kset), GFP_KERNEL);
162: if (!kset)
163: return NULL;
164:
165: //设置kset中kobject的名字,这里为bus
166: kobject_set_name(&kset->kobj, name);
167:
168: //设置uevent操作集,这里为bus_uevent_ops
169: kset->uevent_ops = uevent_ops;
170:
171: //设置父对象,这里为NULL
172: kset->kobj.parent = parent_kobj;
173:
174: //设置容器操作集
175: kset->kobj.ktype = &kset_ktype;
176:
177: //设置父容器
178: kset->kobj.kset = NULL;
179:
180: return kset;
181: }
182:
183: 这里的ktype,也就是kset_ktype是一个操作集,用于为sys下文件的实时反馈做服务,例如我们cat name的时候就要通过ktype提供的show函数,具体什么怎么运用,将在后面讲解
184:
185: 现在回到kset_create_and_add中的kset_register,将建立好的kset添加进sys里
186:
187: int kset_register(struct kset *k)
188: {
189: int err;
190:
191: if (!k)
192: return -EINVAL;
193:
194: //初始化
195: kset_init(k);
196:
197: //添加该容器
198: err = kobject_add_internal(&k->kobj);
199: if (err)
200: return err;
201: kobject_uevent(&k->kobj, KOBJ_ADD);
202: return 0;
203: }
204:
205: kset_init进行一些固定的初始化操作,里面没有我们需要关心的内容
206: kobject_add_internal为重要的一个函数,他对kset里kobj的从属关系进行解析,搭建正确的架构
207:
208: static int kobject_add_internal(struct kobject *kobj)
209: {
210: int error = 0;
211: struct kobject *parent;
212:
213: //检测kobj是否为空
214: if (!kobj)
215: return -ENOENT;
216:
217: //检测kobj名字是否为空
218: if (!kobj->name || !kobj->name[0]) {
219: pr_debug("kobject: (%p): attempted to be registered with empty "
220: "name!\n", kobj);
221: WARN_ON(1);
222: return -EINVAL;
223: }
224:
225: //提取父对象
226: parent = kobject_get(kobj->parent);
227:
228: /* join kset if set, use it as parent if we do not already have one */
229: //父容器存在则设置父对象
230: if (kobj->kset) {//在bus的kset中为空,所以不会进入到下面的代码
231:
232: //检测是否已经设置父对象
233: if (!parent)
234: //无则使用父容器为父对象
235: parent = kobject_get(&kobj->kset->kobj);
236:
237: //添加该kobj到父容器的链表中
238: kobj_kset_join(kobj);
239:
240: //设置父对象
241: kobj->parent = parent;
242: }
243:
244: pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
245: kobject_name(kobj), kobj, __func__,
246: parent ? kobject_name(parent) : "",
247: kobj->kset ? kobject_name(&kobj->kset->kobj) : "");
248:
249: //建立相应的目录
250: error = create_dir(kobj);
251:
252: if (error) {
253: kobj_kset_leave(kobj);
254: kobject_put(parent);
255: kobj->parent = NULL;
256:
257: if (error == -EEXIST)
258: printk(KERN_ERR "%s failed for %s with "
259: "-EEXIST, don't try to register things with "
260: "the same name in the same directory.\n",
261: __func__, kobject_name(kobj));
262: else
263: printk(KERN_ERR "%s failed for %s (%d)\n",
264: __func__, kobject_name(kobj), error);
265: dump_stack();
266: } else
267: kobj->state_in_sysfs = 1;
268:
269: return error;
270: }
271:
272: 至此bus的目录就建立起来了
273:
274: 模型如下
275:
276:
277: 接下来是devices,在/drivers/base/core.c里
278:
279: int __init devices_init(void)
280: {
281: devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
282: if (!devices_kset)
283: return -ENOMEM;
284: return 0;
285: }
286: 过程和bus的注册一致,我就不复述了~
287: 模型如下
288:
289:
290: 然后是platform的注册
291: 在platform的注册中,分为两个部分,一部分是注册到devices中,另一部分是注册到bus中,代码在/drivers/base/platform.c中
292: int __init platform_bus_init(void)
293: {
294: int error;
295:
296: //注册到devices目录中
297: error = device_register(&platform_bus);
298: if (error)
299: return error;
300:
301: //注册到bus目录中
302: error = bus_register(&platform_bus_type);
303:
304: if (error)
305: device_unregister(&platform_bus);
306: return error;
307: }
308:
309: 首先是device_register,注册的参数为platform_bus,如下所示
310: struct device platform_bus = {
311: .bus_id = "platform",
312: };
313: 很简单,只有一个参数,表明了目录名
314:
315: int device_register(struct device *dev)
316: {
317: //初始化dev结构
318: device_initialize(dev);
319: //添加dev至目录
320: return device_add(dev);
321: }
322:
323: void device_initialize(struct device *dev)
324: {
325: //重要的一步,指明了父容器为devices_kset,而devices_kset的注册在前面已经介绍过了
326: dev->kobj.kset = devices_kset;
327: //初始化kobj的ktype为device_ktype
328: kobject_init(&dev->kobj, &device_ktype);
329: klist_init(&dev->klist_children, klist_children_get,
330: klist_children_put);
331: INIT_LIST_HEAD(&dev->dma_pools);
332: INIT_LIST_HEAD(&dev->node);
333: init_MUTEX(&dev->sem);
334: spin_lock_init(&dev->devres_lock);
335: INIT_LIST_HEAD(&dev->devres_head);
336: device_init_wakeup(dev, 0);
337: set_dev_node(dev, -1);
338: }
339:
340: int device_add(struct device *dev)
341: {
342: struct device *parent = NULL;
343: struct class_interface *class_intf;
344: int error;
345:
346: dev = get_device(dev);
347: if (!dev || !strlen(dev->bus_id)) {
348: error = -EINVAL;
349: goto Done;
350: }
351:
352: pr_debug("device: '%s': %s\n", dev->bus_id, __func__);
353:
354: parent = get_device(dev->parent);
355: setup_parent(dev, parent);
356:
357: if (parent)
358: set_dev_node(dev, dev_to_node(parent));
359:
360: //设置dev->kobj的名字和父对象,并建立相应的目录
361: error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id);
362: if (error)
363: goto Error;
364:
365: if (platform_notify)
366: platform_notify(dev);
367:
368: if (dev->bus)
369: blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
370: BUS_NOTIFY_ADD_DEVICE, dev);
371:
372: //建立uevent文件
373: error = device_create_file(dev, &uevent_attr);
374: if (error)
375: goto attrError;
376:
377: if (MAJOR(dev->devt)) {
378: error = device_create_file(dev, &devt_attr);
379: if (error)
380: goto ueventattrError;
381: }
382: //建立subsystem连接文件连接到所属class,这里没有设置class对象所以不会建立
383: error = device_add_class_symlinks(dev);
384: if (error)
385: goto SymlinkError;
386: //建立dev的描述文件,这里没有设置描述文件所以不会建立
387: error = device_add_attrs(dev);
388: if (error)
389: goto AttrsError;
390: //建立链接文件至所属bus,这里没有设置所属bus所以不会建立
391: error = bus_add_device(dev);
392: if (error)
393: goto BusError;
394: //添加power文件,因为platform不属于设备,所以不会建立power文件
395: error = device_pm_add(dev);
396: if (error)
397: goto PMError;
398: kobject_uevent(&dev->kobj, KOBJ_ADD);
399:
400: //检测驱动中有无适合的设备进行匹配,但没有设置bus,所以不会进行匹配
401: bus_attach_device(dev);
402: if (parent)
403: klist_add_tail(&dev->knode_parent, &parent->klist_children);
404:
405: if (dev->class) {
406: down(&dev->class->sem);
407: list_add_tail(&dev->node, &dev->class->devices);
408:
409: list_for_each_entry(class_intf, &dev->class->interfaces, node)
410: if (class_intf->add_dev)
411: class_intf->add_dev(dev, class_intf);
412: up(&dev->class->sem);
413: }
414: Done:
415: put_device(dev);
416: return error;
417: PMError:
418: bus_remove_device(dev);
419: BusError:
420: if (dev->bus)
421: blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
422: BUS_NOTIFY_DEL_DEVICE, dev);
423: device_remove_attrs(dev);
424: AttrsError:
425: device_remove_class_symlinks(dev);
426: SymlinkError:
427: if (MAJOR(dev->devt))
428: device_remove_file(dev, &devt_attr);
429: ueventattrError:
430: device_remove_file(dev, &uevent_attr);
431: attrError:
432: kobject_uevent(&dev->kobj, KOBJ_REMOVE);
433: kobject_del(&dev->kobj);
434: Error:
435: cleanup_device_parent(dev);
436: if (parent)
437: put_device(parent);
438: goto Done;
439: }
440:
441:
442:
443: 在kobject_add-> kobject_add_varg-> kobject_add_internal中
444:
445: //提取父对象,因为没有设置,所以为空
446: parent = kobject_get(kobj->parent);
447:
448: //父容器存在则设置父对象,在前面的dev->kobj.kset = devices_kset中设为了devices_kset
449: if (kobj->kset) {
450: //检测是否已经设置父对象
451: if (!parent)
452: //无则使用父容器为父对象
453: parent = kobject_get(&kobj->kset->kobj);
454: //添加该kobj到父容器的链表中
455: kobj_kset_join(kobj);
456:
457: //设置父对象
458: kobj->parent = parent;
459: }
460:
461: 现在devices下的platform目录建立好了,模型如下,其中红线描绘了目录关系
462:
463: 现在到bus_register了
464:
465: 注册的参数platform_bus_type如下所示
466: struct bus_type platform_bus_type = {
467: .name = "platform",
468: .dev_attrs = platform_dev_attrs,
469: .match = platform_match,
470: .uevent = platform_uevent,
471: .suspend = platform_suspend,
472: .suspend_late = platform_suspend_late,
473: .resume_early = platform_resume_early,
474: .resume = platform_resume,
475: };
476:
477:
478: int bus_register(struct bus_type *bus)
479: {
480: int retval;
481:
482: //声明一个总线私有数据并分配空间
483: struct bus_type_private *priv;
484: priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);
485: if (!priv)
486: return -ENOMEM;
487:
488: //互相关联
489: priv->bus = bus;
490: bus->p = priv;
491:
492: BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
493:
494: //设置私有数据中kobj对象的名字
495: retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
496: if (retval)
497: goto out;
498:
499: //设置父容器为bus_kset,操作集为bus_ktype
500: priv->subsys.kobj.kset = bus_kset;
501: priv->subsys.kobj.ktype = &bus_ktype;
502: priv->drivers_autoprobe = 1;
503:
504: //注册bus容器
505: retval = kset_register(&priv->subsys);
506: if (retval)
507: goto out;
508:
509: //建立uevent属性文件
510: retval = bus_create_file(bus, &bus_attr_uevent);
511: if (retval)
512: goto bus_uevent_fail;
513:
514: //建立devices目录
515: priv->devices_kset = kset_create_and_add("devices", NULL,
516: &priv->subsys.kobj);
517: if (!priv->devices_kset) {
518: retval = -ENOMEM;
519: goto bus_devices_fail;
520: }
521:
522: //建立drivers目录
523: priv->drivers_kset = kset_create_and_add("drivers", NULL,
524: &priv->subsys.kobj);
525: if (!priv->drivers_kset) {
526: retval = -ENOMEM;
527: goto bus_drivers_fail;
528: }
529:
530: //初始化klist_devices和klist_drivers链表
531: klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
532: klist_init(&priv->klist_drivers, NULL, NULL);
533:
534: //增加probe属性文件
535: retval = add_probe_files(bus);
536: if (retval)
537: goto bus_probe_files_fail;
538:
539: //增加总线的属性文件
540: retval = bus_add_attrs(bus);
541: if (retval)
542: goto bus_attrs_fail;
543:
544: pr_debug("bus: '%s': registered\n", bus->name);
545: return 0;
546:
547: bus_attrs_fail:
548: remove_probe_files(bus);
549: bus_probe_files_fail:
550: kset_unregister(bus->p->drivers_kset);
551: bus_drivers_fail:
552: kset_unregister(bus->p->devices_kset);
553: bus_devices_fail:
554: bus_remove_file(bus, &bus_attr_uevent);
555: bus_uevent_fail:
556: kset_unregister(&bus->p->subsys);
557: kfree(bus->p);
558: out:
559: return retval;
560: }
561:
562: 在kset_register-> kobject_add_internal中
563:
564: //提取父对象,因为没有设置父对象,所以为空
565: parent = kobject_get(kobj->parent);
566:
567: //父容器存在则设置父对象,在上文中设置了父容器priv->subsys.kobj.kset = bus_kset
568: if (kobj->kset) {
569:
570: //检测是否已经设置父对象
571: if (!parent)
572: //无则使用父容器为父对象
573: parent = kobject_get(&kobj->kset->kobj);
574:
575: //添加该kobj到父容器的链表中
576: kobj_kset_join(kobj);
577:
578: //设置父对象
579: kobj->parent = parent;
580: }
581:
582: 在retval = kset_register(&priv->subsys)完成之后platform在bus下的模型如下图
583:
584:
585:
586: 有印象的话大家还记得在platform下面有两个目录devices和drivers吧~
587: 现在就到这两个目录的注册了
588: priv->devices_kset = kset_create_and_add("devices", NULL,&priv->subsys.kobj);
589: priv->drivers_kset = kset_create_and_add("drivers", NULL, &priv->subsys.kobj);
590: 注意这两条语句的头部
591: priv->devices_kset = kset_create_and_add
592: priv->drivers_kset = kset_create_and_add
593: 可以清楚的看到bus_type_private下的devices_kset, drivers_kset分别连接到了devices,drivers的kset上
594:
595: 现在来看kset_create_and_add("devices", NULL,&priv->subsys.kobj);
596: struct kset *kset_create_and_add(const char *name,
597: struct kset_uevent_ops *uevent_ops,
598: struct kobject *parent_kobj)
599: //参数为"devices", NULL,&priv->subsys.kobj
600: {
601: struct kset *kset;
602: int error;
603:
604: //创建一个kset容器
605: kset = kset_create(name, uevent_ops, parent_kobj);
606: if (!kset)
607: return NULL;
608:
609: //注册创建的kset容器
610: error = kset_register(kset);
611: if (error) {
612: kfree(kset);
613: return NULL;
614: }
615: return kset;
616: }
617: 在kset_create 中比较重要的操作为
618: kset->kobj.ktype = &kset_ktype //设置了ktype,为kset_ktype
619: kset->kobj.parent = parent_kobj; //设置了父对象,为priv->subsys.kobj,也就是platform_bus_type->p->subsys.kobj
620: kset->kobj.kset = NULL; //设置父容器为空
621: 在kset_register中
622:
623: //提取父对象
624: parent = kobject_get(kobj->parent); //在之前设置为了
625:
626: //父容器存在则设置父对象,由于父容器为空,不执行以下代码
627: if (kobj->kset) {
628:
629: //检测是否已经设置父对象
630: if (!parent)
631: //无则使用父容器为父对象
632: parent = kobject_get(&kobj->kset->kobj);
633:
634: //添加该kobj到父容器的链表中
635: kobj_kset_join(kobj);
636:
637: //设置父对象
638: kobj->parent = parent;
639: }
640:
641: 至此, devices的模型就建立好了,drivers模型的建立和devices是一致的,只是名字不同而已,我就不复述了,建立好的模型如下
642:
643:
644:
645:
646: 好了~ 到了这里,bus,devices和platform的基础模型就就建立好了,就等设备来注册了
647: 在platform模型设备的建立中,需要2个部分的注册,驱动的注册和设备的注册
648: platform_device_register(&test_device);
649: platform_driver_register(&test_driver);
650: 首先看platform_device_register
651: 注册参数为test_device,结构如下
652: static struct platform_device test_device = {
653: .name = "test_ts",
654: .id = -1,
655: //. resource
656: //.dev
657: };
658: 这个结构主要描述了设备的名字,ID和资源和私有数据,其中资源和私有数据我们在这里不使用,将在别的文章中进行讲解
659:
660: int platform_device_register(struct platform_device *pdev)
661: {
662: //设备属性的初始化
663: device_initialize(&pdev->dev);
664: //将设备添加进platform里
665: return platform_device_add(pdev);
666: }
667:
668: void device_initialize(struct device *dev)
669: {
670: dev->kobj.kset = devices_kset; //设置kset为devices_kset,则将设备挂接上了devices目录
671: kobject_init(&dev->kobj, &device_ktype); //初始化kobeject,置ktype为device_ktype
672: klist_init(&dev->klist_children, klist_children_get,
673: klist_children_put);
674: INIT_LIST_HEAD(&dev->dma_pools);
675: INIT_LIST_HEAD(&dev->node);
676: init_MUTEX(&dev->sem);
677: spin_lock_init(&dev->devres_lock);
678: INIT_LIST_HEAD(&dev->devres_head);
679: device_init_wakeup(dev, 0);
680: set_dev_node(dev, -1);
681: }
682:
683: int platform_device_add(struct platform_device *pdev)
684: {
685: int i, ret = 0;
686:
687: if (!pdev)
688: return -EINVAL;
689:
690: //检测是否设置了dev中的parent,无则赋为platform_bus
691: if (!pdev->dev.parent)
692: pdev->dev.parent = &platform_bus;
693:
694: //设置dev中的bus为platform_bus_type
695: pdev->dev.bus = &platform_bus_type;
696:
697: //检测id,id为-1表明该设备只有一个,用设备名为bus_id
698: //不为1则表明该设备有数个,需要用序号标明bus_id
699: if (pdev->id != -1)
700: snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%d", pdev->name,
701: pdev->id);
702: else
703: strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);
704:
705: //增加资源到资源树中
706: for (i = 0; i < pdev->num_resources; i++) {
707: struct resource *p, *r = &pdev->resource;
708:
709: if (r->name == NULL)
710: r->name = pdev->dev.bus_id;
711:
712: p = r->parent;
713: if (!p) {
714: if (r->flags & IORESOURCE_MEM)
715: p = &iomem_resource;
716: else if (r->flags & IORESOURCE_IO)
717: p = &ioport_resource;
718: }
719:
720: if (p && insert_resource(p, r)) {
721: printk(KERN_ERR "%s: failed to claim resource %d\n",pdev->dev.bus_id, i);
722: ret = -EBUSY;
723: goto failed;
724: }
725: }
726:
727: pr_debug("Registering platform device '%s'. Parent at %s\n",pdev->dev.bus_id, pdev->dev.parent->bus_id);
728:
729: //添加设备到设备层次中
730: ret = device_add(&pdev->dev);
731: if (ret == 0)
732: return ret;
733:
734: failed:
735: while (--i >= 0)
736: if (pdev->resource.flags & (IORESOURCE_MEM|IORESOURCE_IO))
737: release_resource(&pdev->resource);
738: return ret;
739: }
740:
741:
742:
743: int device_add(struct device *dev)
744: {
745: struct device *parent = NULL;
746: struct class_interface *class_intf;
747: int error;
748:
749: dev = get_device(dev);
750: if (!dev || !strlen(dev->bus_id)) {
751: error = -EINVAL;
752: goto Done;
753: }
754:
755: pr_debug("device: '%s': %s\n", dev->bus_id, __func__);
756:
757: //取得上层device,而dev->parent的赋值是在platform_device_add中的pdev->dev.parent = &platform_bus完成的
758: parent = get_device(dev->parent);
759:
760: //以上层devices为准重设dev->kobj.parent
761: setup_parent(dev, parent);
762:
763: if (parent)
764: set_dev_node(dev, dev_to_node(parent));
765:
766: //设置dev->kobj的名字和父对象,并建立相应目录
767: error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id);
768: if (error)
769: goto Error;
770:
771: if (platform_notify)
772: platform_notify(dev);
773:
774: //一种新型的通知机制,但是platform中没有设置相应的结构,所以在这里跳过
775: /* notify clients of device entry (new way) */
776: if (dev->bus)
777: blocking_notifier_call_chain(&dev->bus->p->bus_notifier,BUS_NOTIFY_ADD_DEVICE, dev);
778:
779: //建立uevent文件
780: error = device_create_file(dev, &uevent_attr);
781: if (error)
782: goto attrError;
783:
784: //设备有设备号则建立dev文件
785: if (MAJOR(dev->devt)) {
786: error = device_create_file(dev, &devt_attr);
787: if (error)
788: goto ueventattrError;
789: }
790: //建立subsystem连接文件连接到所属class
791: error = device_add_class_symlinks(dev);
792: if (error)
793: goto SymlinkError;
794: //添加dev的描述文件
795: error = device_add_attrs(dev);
796: if (error)
797: goto AttrsError;
798: //添加链接文件至所属bus
799: error = bus_add_device(dev);
800: if (error)
801: goto BusError;
802: //添加power文件
803: error = device_pm_add(dev);
804: if (error)
805: goto PMError;
806: kobject_uevent(&dev->kobj, KOBJ_ADD);
807:
808: //检测驱动中有无适合的设备进行匹配,现在只添加了设备,还没有加载驱动,所以不会进行匹配
809: bus_attach_device(dev);
810: if (parent)
811: klist_add_tail(&dev->knode_parent, &parent->klist_children);
812:
813: if (dev->class) {
814: down(&dev->class->sem);
815: list_add_tail(&dev->node, &dev->class->devices);
816:
817: list_for_each_entry(class_intf, &dev->class->interfaces, node)
818: if (class_intf->add_dev)
819: class_intf->add_dev(dev, class_intf);
820: up(&dev->class->sem);
821: }
822: Done:
823: put_device(dev);
824: return error;
825: PMError:
826: bus_remove_device(dev);
827: BusError:
828: if (dev->bus)
829: blocking_notifier_call_chain(&dev->bus->p->bus_notifier,BUS_NOTIFY_DEL_DEVICE, dev);
830: device_remove_attrs(dev);
831: AttrsError:
832: device_remove_class_symlinks(dev);
833: SymlinkError:
834: if (MAJOR(dev->devt))
835: device_remove_file(dev, &devt_attr);
836: ueventattrError:
837: device_remove_file(dev, &uevent_attr);
838: attrError:
839: kobject_uevent(&dev->kobj, KOBJ_REMOVE);
840: kobject_del(&dev->kobj);
841: Error:
842: cleanup_device_parent(dev);
843: if (parent)
844: put_device(parent);
845: goto Done;
846: }
847:
848: static void setup_parent(struct device *dev, struct device *parent)
849: {
850: struct kobject *kobj;
851: //取得上层device的kobj
852: kobj = get_device_parent(dev, parent);
853: //kobj不为空则重设dev->kobj.parent
854: if (kobj)
855: dev->kobj.parent = kobj;
856: }
857:
858:
859: static struct kobject *get_device_parent(struct device *dev,
860: struct device *parent)
861: {
862: int retval;
863:
864: //因为dev->class为空,所以跳过这段代码
865: if (dev->class) {
866: struct kobject *kobj = NULL;
867: struct kobject *parent_kobj;
868: struct kobject *k;
869:
870: if (parent == NULL)
871: parent_kobj = virtual_device_parent(dev);
872: else if (parent->class)
873: return &parent->kobj;
874: else
875: parent_kobj = &parent->kobj;
876:
877: spin_lock(&dev->class->class_dirs.list_lock);
878: list_for_each_entry(k, &dev->class->class_dirs.list, entry)
879: if (k->parent == parent_kobj) {
880: kobj = kobject_get(k);
881: break;
882: }
883: spin_unlock(&dev->class->class_dirs.list_lock);
884: if (kobj)
885: return kobj;
886:
887: k = kobject_create();
888: if (!k)
889: return NULL;
890: k->kset = &dev->class->class_dirs;
891: retval = kobject_add(k, parent_kobj, "%s", dev->class->name);
892: if (retval < 0) {
893: kobject_put(k);
894: return NULL;
895: }
896: return k;
897: }
898:
899: if (parent)
900: //返回上层device的kobj
901: return &parent->kobj;
902: return NULL;
903: }
904:
905: 在bus_attach_device中虽然没有成功进行匹配,但是有很重要的一步为之后正确的匹配打下基础
906: void bus_attach_device(struct device *dev)
907: {
908: struct bus_type *bus = dev->bus;
909: int ret = 0;
910:
911: if (bus) {
912: if (bus->p->drivers_autoprobe)
913: ret = device_attach(dev);
914: WARN_ON(ret < 0);
915: if (ret >= 0)
916: klist_add_tail(&dev->knode_bus, &bus->p->klist_devices);
917: }
918: }
919:
920: klist_add_tail(&dev->knode_bus, &bus->p->klist_devices)就是这一行
921: 在这一行代码中将设备挂载到了bus下的devices链表下,这样,当驱动请求匹配的时候,platform总线就会历遍devices链表为驱动寻找合适的设备
922:
923:
924: 现在来看一下test_device的模型
925:
926:
927:
928: 然后platform_driver_unregister,他的参数 test_driver的结构如下
929: static struct platform_driver test_driver = {
930: .probe = test_probe,
931: .remove = test_remove,
932: .driver = {
933: .name = "test_ts",
934: .owner = THIS_MODULE,
935: },
936: };
937:
938: int platform_driver_register(struct platform_driver *drv)
939: {
940: drv->driver.bus = &platform_bus_type;
941: if (drv->probe)
942: drv->driver.probe = platform_drv_probe;
943: if (drv->remove)
944: drv->driver.remove = platform_drv_remove;
945: if (drv->shutdown)
946: drv->driver.shutdown = platform_drv_shutdown;
947: if (drv->suspend)
948: drv->driver.suspend = platform_drv_suspend;
949: if (drv->resume)
950: drv->driver.resume = platform_drv_resume;
951: return driver_register(&drv->driver);
952: }
953:
954: 从上面代码可以看出,在platform_driver中设置了probe, remove, shutdown, suspend或resume函数的话
955: 则drv->driver也会设置成platform对应的函数
956:
957: int driver_register(struct device_driver *drv)
958: {
959: int ret;
960: struct device_driver *other;
961:
962: //检测总线的操作函数和驱动的操作函数是否同时存在,同时存在则提示使用总线提供的操作函数
963: if ((drv->bus->probe && drv->probe) ||
964: (drv->bus->remove && drv->remove) ||
965: (drv->bus->shutdown && drv->shutdown))
966: printk(KERN_WARNING "Driver '%s' needs updating - please use ""bus_type methods\n", drv->name);
967:
968: //检测是否已经注册过
969: other = driver_find(drv->name, drv->bus);
970: if (other) {
971: put_driver(other);
972: printk(KERN_ERR "Error: Driver '%s' is already registered, “"aborting...\n", drv->name);
973: return -EEXIST;
974: }
975:
976: //添加驱动到总线上
977: ret = bus_add_driver(drv);
978: if (ret)
979: return ret;
980:
981:
982: ret = driver_add_groups(drv, drv->groups);
983: if (ret)
984: bus_remove_driver(drv);
985: return ret;
986: }
987:
988:
989:
990: int bus_add_driver(struct device_driver *drv)
991: {
992: struct bus_type *bus;
993: struct driver_private *priv;
994: int error = 0;
995:
996: //取bus结构
997: bus = bus_get(drv->bus);
998: if (!bus)
999: return -EINVAL;
1000:
1001: pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
1002:
1003: //分配驱动私有数据
1004: priv = kzalloc(sizeof(*priv), GFP_KERNEL);
1005: if (!priv) {
1006: error = -ENOMEM;
1007: goto out_put_bus;
1008: }
1009:
1010: //初始化klist_devices链表
1011: klist_init(&priv->klist_devices, NULL, NULL);
1012:
1013: //互相关联
1014: priv->driver = drv;
1015: drv->p = priv;
1016:
1017: //设置私有数据的父容器,在这一步中,设置了kset为platform下的drivers_kset结构,也就是drivers呢个目录
1018: priv->kobj.kset = bus->p->drivers_kset;
1019:
1020: //初始化kobj对象,设置容器操作集并建立相应的目录,这里由于没有提供parent,所以会使用父容器中的kobj为父对象
1021: error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
1022: "%s", drv->name);
1023: if (error)
1024: goto out_unregister;
1025:
1026: //检测所属总线的drivers_autoprobe属性是否为真
1027: //为真则进行与设备的匹配,到这里,就会与我们之前注册的test_device连接上了,至于如何连接,进行了什么操作,将在别的文章中详细描述
1028: if (drv->bus->p->drivers_autoprobe) {
1029: error = driver_attach(drv);
1030: if (error)
1031: goto out_unregister;
1032: }
1033:
1034: //挂载到所属总线驱动链表上
1035: klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
1036: module_add_driver(drv->owner, drv);
1037:
1038: //建立uevent属性文件
1039: error = driver_create_file(drv, &driver_attr_uevent);
1040: if (error) {
1041: printk(KERN_ERR "%s: uevent attr (%s) failed\n",
1042: __func__, drv->name);
1043: }
1044:
1045: //建立设备属性文件
1046: error = driver_add_attrs(bus, drv);
1047: if (error) {
1048: printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",__func__, drv->name);
1049: }
1050: error = add_bind_files(drv);
1051: if (error) {
1052: printk(KERN_ERR "%s: add_bind_files(%s) failed\n",__func__, drv->name);
1053: }
1054:
1055: kobject_uevent(&priv->kobj, KOBJ_ADD);
1056: return error;
1057: out_unregister:
1058: kobject_put(&priv->kobj);
1059: out_put_bus:
1060: bus_put(bus);
1061: return error;
1062: }
1063:
1064: 到这里test_driver的模型就建立好了,图就是最上面的层次图,我就不再贴了
1065:
1066: 到这里一个基本的框架就建立起来了~
1067:
1068: 下面,我开始对kobject kset和ktype做分析
1069:
1070: 先说说关系,ktype与kobject和kset这两者之前的关系较少,让我画一个图,是这样的
1071:
1072:
1073:
1074: ktype依赖于kobject,kset也依赖于kobject,而kobject有时需要kset(所以用了一个白箭头),不一定需要ktype(真可怜,连白箭头都没有)
1075:
1076: 首先先说一下这个可有可无的ktype
1077:
1078: 到/sys/bus/platform下面可以看见一个drivers_autoprobe的文件
1079: cat drivers_autoprobe可以查看这个文件的值
1080: echo 0 > drivers_autoprobe则可以改变这个文件的值
1081: drivers_autoprobe这个文件表示的是是否自动进行初始化
1082: 在
1083: void bus_attach_device(struct device *dev)
1084: {
1085: struct bus_type *bus = dev->bus;
1086: int ret = 0;
1087:
1088: if (bus) {
1089: if (bus->p->drivers_autoprobe)
1090: ret = device_attach(dev);
1091: WARN_ON(ret < 0);
1092: if (ret >= 0)
1093: klist_add_tail(&dev->knode_bus, &bus->p->klist_devices);
1094: }
1095: }
1096: 中可以看见这么一段代码
1097: if (bus->p->drivers_autoprobe)
1098: ret = device_attach(dev);
1099: bus->p->drivers_autoprobe的值为真则进行匹配
1100: 而drivers_autoprobe这个文件则可以动态的修改这个值选择是否进行匹配
1101: 使用外部文件修改内核参数,ktype就是提供了这么一种方法
1102:
1103: 现在让我们看看ktype是怎么通过kobject进行运作的
1104: 首先是ktype及通过ktype进行运作的drivers_autoprobe的注册
1105:
1106: ktype的挂载十分简单,因为他是和kobject是一体的
1107: 只有这么下面一句
1108: priv->subsys.kobj.ktype = &bus_ktype;
1109: 这样就将bus_ktype挂载到了platform_bus_type的kobject上
1110: drivers_autoprobe的注册如下
1111: retval = bus_create_file(bus, &bus_attr_drivers_autoprobe);
1112:
1113: bus_attr_drivers_autoprobe这个结构由一系列的宏进行组装
1114: static BUS_ATTR(drivers_autoprobe, S_IWUSR | S_IRUGO,
1115: show_drivers_autoprobe, store_drivers_autoprobe);
1116:
1117: #define BUS_ATTR(_name, _mode, _show, _store) \
1118: struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store)
1119:
1120: #define __ATTR(_name,_mode,_show,_store) { \
1121: .attr = {.name = __stringify(_name), .mode = _mode }, \
1122: .show = _show, \
1123: .store = _store, \
1124: }
1125:
1126: 最后bus_attr_drivers_autoprobe的模型如下
1127:
1128: struct bus_attribute bus_attr_drivers_autoprobe
1129: {
1130: .attr = {
1131: .name = “drivers_autoprobe”,
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }