Chinaunix首页 | 论坛 | 博客
  • 博客访问: 438007
  • 博文数量: 133
  • 博客积分: 3259
  • 博客等级: 中校
  • 技术积分: 1255
  • 用 户 组: 普通用户
  • 注册时间: 2010-04-14 13:49
文章存档

2012年(6)

2011年(112)

2010年(16)

分类: LINUX

2011-06-01 15:20:15

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; }
阅读(948) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~