//将drv挂入到总线的链表中 klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); if (drv->bus->p->drivers_autoprobe) { //如果总线可以自动的probe,就会调用匹配函数 error = driver_attach(drv); if (error) goto out_unregister; } //创建driver相关的模块 module_add_driver(drv->owner, drv);
error = driver_create_file(drv, &driver_attr_uevent); if (error) { printk(KERN_ERR "%s: uevent attr (%s) failed\n", __func__, drv->name); } error = driver_add_groups(drv, bus->drv_groups); if (error) { /* How the hell do we get out of this pickle? Give up */ printk(KERN_ERR "%s: driver_create_groups(%s) failed\n", __func__, drv->name); }
if (!drv->suppress_bind_attrs) { error = add_bind_files(drv); if (error) { /* Ditto */ printk(KERN_ERR "%s: add_bind_files(%s) failed\n", __func__, drv->name); } }
/* * Lock device and try to bind to it. We drop the error * here and always return 0, because we need to keep trying * to bind to devices and some drivers will return an error * simply if it didn't support the device. * * driver_probe_device() will spit a warning if there * is an error. */
// 调用bus的match函数对设备和驱动进行匹配,若匹配driver_match_device函数的返回值为1,则程序立即返回,若匹配则继续向下执行 if (!driver_match_device(drv, dev)) return0;
if (dev->parent) /* Needed for USB */ device_lock(dev->parent); device_lock(dev); if (!dev->driver) driver_probe_device(drv, dev);// 若设备和驱动匹配且设备的驱动程序为空,则将该驱动程序绑定到该设备(调用驱动程序的probe函数) device_unlock(dev); if (dev->parent) device_unlock(dev->parent);
/* If using pinctrl, bind pins now before probing */ ret = pinctrl_bind_pins(dev); if (ret) goto probe_failed; //drivers_sysfs_add()负责创建sysfs中driver和device指向对方的软链接 if (driver_sysfs_add(dev)) { printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n", __func__, dev_name(dev)); goto probe_failed; }
if (dev->pm_domain && dev->pm_domain->activate) { ret = dev->pm_domain->activate(dev); if (ret) goto probe_failed; }
if (dev->bus->probe) {//如果device attachd的bus本身就有probe函数,那么就调用device的probe函数 ret = dev->bus->probe(dev); if (ret) goto probe_failed; } elseif (drv->probe) {//如果device没有probe函数,那么就调用driver的probe函数 ret = drv->probe(dev); if (ret) goto probe_failed; }
if (dev->pm_domain && dev->pm_domain->sync) dev->pm_domain->sync(dev);
driver_bound(dev); //将device加入驱动的设备链表。 ret = 1; pr_debug("bus: '%s': %s: bound device %s to driver %s\n", drv->bus->name, __func__, dev_name(dev), drv->name); goto done;
switch (ret) { case -EPROBE_DEFER: /* Driver requested deferred probing */ dev_dbg(dev, "Driver %s requests probe deferral\n", drv->name); driver_deferred_probe_add(dev); /* Did a trigger occur while probing? Need to re-trigger if yes */ if (local_trigger_count != atomic_read(&deferred_trigger_count)) driver_deferred_probe_trigger(); break; case -ENODEV: case -ENXIO: pr_debug("%s: probe of %s rejects match %d\n", drv->name, dev_name(dev), ret); break; default: /* driver matched but the probe failed */ printk(KERN_WARNING "%s: probe of %s failed with error %d\n", drv->name, dev_name(dev), ret); } /* * Ignore errors returned by ->probe so that the next driver can try * its luck. */ ret = 0; done: atomic_dec(&probe_count); wake_up(&probe_waitqueue); return ret; }
ret = of_clk_set_defaults(_dev->of_node, false); if (ret < 0) return ret;
ret = dev_pm_domain_attach(_dev, true); if (ret != -EPROBE_DEFER) { ret = drv->probe(dev);// 此处间接地调用了platform_driver提供的probe函数,如果是imx6ul,就调用相应的platform_driver if (ret) dev_pm_domain_detach(_dev, true); }
if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) { dev_warn(_dev, "probe deferral not supported\n"); ret = -ENXIO; }
/* * Make sure the device is no longer in one of the deferred lists and * kick off retrying all pending devices */ driver_deferred_probe_del(dev); driver_deferred_probe_trigger();
if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_BOUND_DRIVER, dev); }
/** * platform_device_add - add a platform device to device hierarchy * @pdev: platform device we're adding * * This is part 2 of platform_device_register(), though may be called * separately _iff_ pdev was allocated by platform_device_alloc(). */ intplatform_device_add(struct platform_device *pdev) { int i, ret;
if (!pdev) return -EINVAL;
if (!pdev->dev.parent) pdev->dev.parent = &platform_bus;
pdev->dev.bus = &platform_bus_type;
switch (pdev->id) { default: dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); break; case PLATFORM_DEVID_NONE: dev_set_name(&pdev->dev, "%s", pdev->name); break; case PLATFORM_DEVID_AUTO: /* * Automatically allocated device ID. We mark it as such so * that we remember it must be freed, and we append a suffix * to avoid namespace collision with explicit IDs. */ ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL); if (ret < 0) goto err_out; pdev->id = ret; pdev->id_auto = true; dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id); break; }
for (i = 0; i < pdev->num_resources; i++) {//获取资源 structresource *p, *r = &pdev->resource[i];
if (r->name == NULL) r->name = dev_name(&pdev->dev);
p = r->parent; if (!p) {//设置资源类型 if (resource_type(r) == IORESOURCE_MEM) p = &iomem_resource; elseif (resource_type(r) == IORESOURCE_IO) p = &ioport_resource; }
if (p && insert_resource(p, r)) { dev_err(&pdev->dev, "failed to claim resource %d\n", i); ret = -EBUSY; goto failed; } }
pr_debug("Registering platform device '%s'. Parent at %s\n", dev_name(&pdev->dev), dev_name(pdev->dev.parent));
ret = device_add(&pdev->dev); if (ret == 0) return ret;
failed: if (pdev->id_auto) { ida_simple_remove(&platform_devid_ida, pdev->id); pdev->id = PLATFORM_DEVID_AUTO; }
while (--i >= 0) { structresource *r = &pdev->resource[i]; if (r->parent) release_resource(r); }
dev = get_device(dev);//增加device的引用计数 if (!dev) goto done;
if (!dev->p) { error = device_private_init(dev);//初始化device的私有成员p if (error) goto done; }
/* * for statically allocated devices, which should all be converted * some day, we need to initialize the name. We prevent reading back * the name, and force the use of dev_name() */ if (dev->init_name) { dev_set_name(dev, "%s", dev->init_name);//初始化device内部的kobject dev->init_name = NULL; }
/* subsystems can specify simple device enumeration */ if (!dev_name(dev) && dev->bus && dev->bus->dev_name)//如果bus存在,使用bus以及设备id来初始化设备内部kobject名字 dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);
/* use parent numa_node */ if (parent) set_dev_node(dev, dev_to_node(parent));
/* first, register with generic layer. */ /* we require the name to be set before, and pass NULL */ error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);//将设备加入到kobject模型中,创建sys相关目录 if (error) goto Error;
/* notify platform of device entry */ if (platform_notify) platform_notify(dev);
error = device_create_file(dev, &dev_attr_uevent);//创建sys目录下设备的uevent属性文件,通过它可以查看设备的uevent事件 if (error) goto attrError;
error = device_add_class_symlinks(dev);//dev与class创建软链接 if (error) goto SymlinkError; error = device_add_attrs(dev);//创建sys目录下设备其他属性文件,即添加device/type/class定义的属性集合 if (error) goto AttrsError; error = bus_add_device(dev);//将设备加入到管理它的bus总线的设备连表上 if (error) goto BusError; error = dpm_sysfs_add(dev);//电源管理相关 if (error) goto DPMError; device_pm_add(dev);
if (MAJOR(dev->devt)) { error = device_create_file(dev, &dev_attr_dev);//如果没有设备号,就创建dev属性 if (error) goto DevAttrError;
error = device_create_sys_dev_entry(dev);//创建软链接 if (error) goto SysEntryError;
devtmpfs_create_node(dev);//在dev下创建设备文件 }
/* Notify clients of device addition. This call must come * after dpm_sysfs_add() and before kobject_uevent(). */ if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_ADD_DEVICE, dev);//通知注册监听该总线的设备,有新设备加入
kobject_uevent(&dev->kobj, KOBJ_ADD);//产生一个内核uevent事件,该事件可以被内核以及应用层捕获,属于linux设备模型中热插拔机制 // 为总线上的设备寻找驱动 bus_probe_device(dev); if (parent) klist_add_tail(&dev->p->knode_parent, &parent->p->klist_children);
if (dev->class) { mutex_lock(&dev->class->p->mutex); /* tie the class to the device */ klist_add_tail(&dev->knode_class, &dev->class->p->klist_devices);//将设备挂接在其设备class上面
/* notify any interfaces that the device is here */ list_for_each_entry(class_intf, &dev->class->p->interfaces, node) if (class_intf->add_dev) class_intf->add_dev(dev, class_intf);//通知有新设备加入 mutex_unlock(&dev->class->p->mutex); } ...... }