Linux的平台总线及其驱动和设备模型分析

一. Linux平台设备和平台驱动模型简介

        Linux在系统总线有一类总线成为平台总线(platform bus),平台总线包括平台设备(platform device)和平台驱动(platform driver),平台总线是一种虚拟的总线,但是同spi和i2c等物理总线一样,Linux通过系统总线来管理他们。

         总线及其设备和驱动模型是Linux驱动中一种基本模型,可以将一类总线的多个设备和多个驱动管理起来,当总线的驱动和设备匹配成功后,会使驱动产生probe行为。由于将一个驱动功能分成了设备部分和驱动部分代码,当板级引脚资源发生变化时,只需要修改代码中的设备部分就可以,驱动部分代码可以不动。

        由于本文会用到较多的kobject相关的函数,如果对此不熟,可以先参考我前面的博文设备模型管理对象kobject介绍

二. Linux系统总线和平台总线分析

1. 系统总线初始化

        在了解平台总线之前需要先了解系统总线的初始化过程。

int __init buses_init(void)
{
	bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
	if (!bus_kset)
		return -ENOMEM;

	......

	return 0;
}

        所有的总线都是由一个struct kset类型的bus_kset结构管理的,kset_create_and_add函数没有指定parent,所以会在/sys下创建一个bus的目录。bus_kset->kobj.name初始化为bus,bus_kset->kobj->kset为NULL。

 2. 平台总线初始化

        平台总线是由一个全局结构体platform_bus_type管理,通过bus_register函数注册到bus_kset,并做一些初始化工作。


int bus_register(struct bus_type *bus)
{
	int retval;
	struct subsys_private *priv;
	struct lock_class_key *key = &bus->lock_key;

    /* 每个总线分配一个struct subsys_private结构体,用于管理驱动和设备 */
	priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL); 
	if (!priv)
		return -ENOMEM;

    /* 通过priv->bus可以访问platform_bus_type */
	priv->bus = bus;  

    /* platform_bus_type.p可以访问到priv结构 */
	bus->p = priv;    

	BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);

	retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);  /*  */
	if (retval)
		goto out;

    /* priv->subsys.kobj.kset指向bus_kset */
	priv->subsys.kobj.kset = bus_kset;  

	/* priv->subsys.kobj.ktype指向bus_ktype */
    priv->subsys.kobj.ktype = &bus_ktype;  

    /* 表示device和driver match成功后,driver自动probe */	
    priv->drivers_autoprobe = 1;           

    /* 将priv->subsys链入到bus_kset */
	retval = kset_register(&priv->subsys); 
	if (retval)
		goto out;

    /* 创建/sys/bus下的platform目录 */
	retval = bus_create_file(bus, &bus_attr_uevent);  
	if (retval)
		goto bus_uevent_fail;

    /* 将priv->devices_kset链入到priv->subsys.kobj中 */
	priv->devices_kset = kset_create_and_add("devices", NULL,
						 &priv->subsys.kobj);        
	if (!priv->devices_kset) {
		retval = -ENOMEM;
		goto bus_devices_fail;
	}

    /* 将priv->drivers_kset链入到priv->subsys.kobj中 */
	priv->drivers_kset = kset_create_and_add("drivers", NULL,
						 &priv->subsys.kobj);  
	if (!priv->drivers_kset) {
		retval = -ENOMEM;
		goto bus_drivers_fail;
	}

    /* 初始化priv->interface链表 */
	INIT_LIST_HEAD(&priv->interfaces);  
	__mutex_init(&priv->mutex, "subsys mutex", key);

    /* 初始化priv->klist_devices klist,这个链表用来链入总线下的设备 */
	klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);  

    /* 初始化priv->klist_drivers */
	klist_init(&priv->klist_drivers, NULL, NULL);

	retval = add_probe_files(bus);
	if (retval)
		goto bus_probe_files_fail;

	retval = bus_add_groups(bus, bus->bus_groups);
	if (retval)
		goto bus_groups_fail;

	pr_debug("bus: '%s': registered\n", bus->name);
	return 0;

bus_groups_fail:
	remove_probe_files(bus);
bus_probe_files_fail:
	kset_unregister(bus->p->drivers_kset);
bus_drivers_fail:
	kset_unregister(bus->p->devices_kset);
bus_devices_fail:
	bus_remove_file(bus, &bus_attr_uevent);
bus_uevent_fail:
	kset_unregister(&bus->p->subsys);
out:
	kfree(bus->p);
	bus->p = NULL;
	return retval;
}

int __init platform_bus_init(void)
{
	int error;

	......

    /* 通过bus_register函数将platform_bus_type注册到bus_kset */
	error =  bus_register(&platform_bus_type);   
	if (error)
		device_unregister(&platform_bus);
	return error;
}

        通过上面的代码,bus_register通过内存分配创建struct subsys_private结构,并且链入到bus_kset中。

 三. LInux平台驱动和平台设备分析

        本章以一个具体的代码案例开始,通过分析案例代码执行过程,进一步分析平台设备和平台驱动的工作原理。代码如下:

platform_driver.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>

int platform_drviver_probe(struct platform_device *pdev)
{
    printk("platform driver probe !\n");

	return 0;
}

struct platform_driver platform_drv = {
    .probe = platform_drviver_probe,
    .driver = {
        .name = "platform_driver_test",
    }
};

static int platform_driver_init(void)
{
    platform_driver_register(&platform_drv);

    return 0;
}

void platform_driver_exit(void)
{
    platform_driver_unregister(&platform_drv);

    return;
}

module_init(platform_driver_init);
module_exit(platform_driver_exit);
MODULE_LICENSE("GPL");

 platform_device.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>

struct platform_device platform_dev = {
    .name = "platform_driver_test",
};

static int platform_device_init(void)
{
    platform_device_register(&platform_dev);
    return 0;
}

void platform_device_exit(void)
{
    platform_device_unregister(&platform_dev);
    return;
}

module_init(platform_device_init);
module_exit(platform_device_exit);
MODULE_LICENSE("GPL");

Makefile模板

obj-m := platform_device.o

CROSS_COMPILE:=/opt/mipsel-mt7620-linux-gnu/bin/mipsel-mt7620-linux-gnu-

KDIR:=/opt/linux-3.18.45

all:
        make CROSS_COMPILE=$(CROSS_COMPILE) ARCH="mips" -C $(KDIR) M=$$PWD

代码效果

/media/platform_model/platform_driver # insmod platform_driver.ko 
/media/platform_model/platform_driver # cd ../platform_device/
/media/platform_model/platform_device # insmod platform_device.ko 
[   70.540000] platform driver probe !
[   70.550000] platform_driver_test: probe of platform_driver_test.0 failed with error 23

        当platform_drver.ko加载后,再加载platform_device.ko驱动后,打印了"platform driver probe !",说明platform_driver.c中的platform_drviver_probe函数被调用了。接下来就通过分析platform_driver_register和platform_device_register,了解平台驱动和平台设备的工作原理。

1. platformm_driver_register函数分析

struct kobject *kset_find_obj(struct kset *kset, const char *name)
{
	struct kobject *k;
	struct kobject *ret = NULL;

	spin_lock(&kset->list_lock);

    /* 通过遍历devices_kset的驱动的kobj链表,找出是否有与name相同的驱动 */
	list_for_each_entry(k, &kset->list, entry) {  
		if (kobject_name(k) && !strcmp(kobject_name(k), name)) {
            /* kobj->kref这里会加1 */
			ret = kobject_get_unless_zero(k);
			break;
		}
	}

	spin_unlock(&kset->list_lock);
	return ret;
}

static int platform_match(struct device *dev, struct device_driver *drv)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct platform_driver *pdrv = to_platform_driver(drv);

	/* When driver_override is set, only bind to the matching driver */
	if (pdev->driver_override)
		return !strcmp(pdev->driver_override, drv->name);

	/* Attempt an OF style match first */
    /* 在设备树中找和dev匹配的drv */
	if (of_driver_match_device(dev, drv))
		return 1;

	/* Then try ACPI style match */
	if (acpi_driver_match_device(dev, drv))
		return 1;

	/* Then try to match against the id table */
	if (pdrv->id_table)
		return platform_match_id(pdrv->id_table, pdev) != NULL;

	/* fall-back to driver name match */
    /* 通过比较pdev->name和drv->name是否一致 */
	return (strcmp(pdev->name, drv->name) == 0);
}

static inline int driver_match_device(struct device_driver *drv,
				      struct device *dev)
{
    /* 此处drv->bus->match指向platform_match函数 */
	return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}

static int really_probe(struct device *dev, struct device_driver *drv)
{
	int ret = 0;
	int local_trigger_count = atomic_read(&deferred_trigger_count);

	atomic_inc(&probe_count);
	pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
		 drv->bus->name, __func__, drv->name, dev_name(dev));
	WARN_ON(!list_empty(&dev->devres_head));

    /* dev->driver指向匹配的drv */
	dev->driver = drv;

	/* If using pinctrl, bind pins now before probing */
	ret = pinctrl_bind_pins(dev);
	if (ret)
		goto probe_failed;

	if (driver_sysfs_add(dev)) {
		printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
			__func__, dev_name(dev));
		goto probe_failed;
	}

    /* dev->bus->probe为NULL */
	if (dev->bus->probe) {
		ret = dev->bus->probe(dev);
		if (ret)
			goto probe_failed;
    /* 运行platform_driver中指定的probe函数 */
	} else if (drv->probe) {
		ret = drv->probe(dev);
		if (ret)
			goto probe_failed;
	}

	driver_bound(dev);
	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;

probe_failed:
	devres_release_all(dev);
	driver_sysfs_remove(dev);
	dev->driver = NULL;
	dev_set_drvdata(dev, NULL);

	if (ret == -EPROBE_DEFER) {
		/* Driver requested deferred probing */
		dev_info(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();
	} else if (ret != -ENODEV && ret != -ENXIO) {
		/* driver matched but the probe failed */
		printk(KERN_WARNING
		       "%s: probe of %s failed with error %d\n",
		       drv->name, dev_name(dev), ret);
	} else {
		pr_debug("%s: probe of %s rejects match %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;
}

int driver_probe_device(struct device_driver *drv, struct device *dev)
{
	int ret = 0;
    
    /* dev->kobj->state_in_sysfs是否为1 */
	if (!device_is_registered(dev))
		return -ENODEV;

	pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
		 drv->bus->name, __func__, dev_name(dev), drv->name);

	pm_runtime_barrier(dev);
	ret = really_probe(dev, drv);
	pm_request_idle(dev);

	return ret;
}

static int __driver_attach(struct device *dev, void *data)
{
	struct device_driver *drv = data;

	/*
	 * 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.
	 */

	if (!driver_match_device(drv, dev))
		return 0;

	if (dev->parent)	/* Needed for USB */
		device_lock(dev->parent);
	device_lock(dev);

    /* 如果dev没有指定driver,调用probe */
	if (!dev->driver)
		driver_probe_device(drv, dev);
	device_unlock(dev);
	if (dev->parent)
		device_unlock(dev->parent);

	return 0;
}

int bus_for_each_dev(struct bus_type *bus, struct device *start,
		     void *data, int (*fn)(struct device *, void *))
{
	struct klist_iter i;
	struct device *dev;
	int error = 0;

	if (!bus || !bus->p)
		return -EINVAL;

    /* 初始化struct klist_iter i, i.i_klist = &bus->p->klist_devices, i.i_cur = NULL */
	klist_iter_init_node(&bus->p->klist_devices, &i,
			     (start ? &start->p->knode_bus : NULL));

    /* 遍历bus->p->klist_devices,执行__driver_attach(dev, drv) */
	while ((dev = next_device(&i)) && !error)
		error = fn(dev, data);
	klist_iter_exit(&i);
	return error;
}

int driver_attach(struct device_driver *drv)
{
    
	return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}

int bus_add_driver(struct device_driver *drv)
{
	struct bus_type *bus;
	struct driver_private *priv;
	int error = 0;

    /* 检查drv->bus是否为空,并且drv->bus->p->subsys.kobj.kref加1,返回drv->bus */
	bus = bus_get(drv->bus);
	if (!bus)
		return -EINVAL;

	pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);

    /* 分配一个struct driver_private结构 */
	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
	if (!priv) {
		error = -ENOMEM;
		goto out_put_bus;
	}
    
    /* 初始化struct driver_private priv->klist_devices链表 */
	klist_init(&priv->klist_devices, NULL, NULL);

    /* struct driver_private priv->driver指向drv */
	priv->driver = drv;

    /* drv->p也指向priv结构 */
	drv->p = priv;

    /* priv->kobj.kset指向platform_bus_type.p->drivers_kset */
	priv->kobj.kset = bus->p->drivers_kset;

    /* 初始化priv->kobj,priv->kobj->name为drv->name */
	error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
				     "%s", drv->name);
	if (error)
		goto out_unregister;

    /* priv->knode_bus加入到bus->p->klist_drivers链表中 */
	klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
    
    /* 判断驱动是否设置为自动probe */
	if (drv->bus->p->drivers_autoprobe) {
		error = driver_attach(drv);
		if (error)
			goto out_unregister;
	}
	module_add_driver(drv->owner, drv);

    /* 在/sys/bus/platform/drivers下创建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);
		}
	}

	return 0;

out_unregister:
	kobject_put(&priv->kobj);
	kfree(drv->p);
	drv->p = NULL;
out_put_bus:
	bus_put(bus);
	return error;
}

struct device_driver *driver_find(const char *name, struct bus_type *bus)
{
	struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);
	struct driver_private *priv;

	if (k) {
		/* Drop reference added by kset_find_obj() */

        /* kset_find_obj使kobj->kref加1,这里需要减1 */
		kobject_put(k);

        /* 通过kobj地址获取struct driver_private结构的地址 */
		priv = to_driver(k);

        /* 返回找到的已注册的struct device_driver结构的地址 */
		return priv->driver;
	}
	return NULL;
}

int driver_register(struct device_driver *drv)
{
	int ret;
	struct device_driver *other;

	BUG_ON(!drv->bus->p);

	if ((drv->bus->probe && drv->probe) ||
	    (drv->bus->remove && drv->remove) ||
	    (drv->bus->shutdown && drv->shutdown))
		printk(KERN_WARNING "Driver '%s' needs updating - please use "
			"bus_type methods\n", drv->name);

    /* 检查drv->bus中是否注册过该驱动 */
	other = driver_find(drv->name, drv->bus);
	if (other) {
		printk(KERN_ERR "Error: Driver '%s' is already registered, "
			"aborting...\n", drv->name);
		return -EBUSY;
	}

    
	ret = bus_add_driver(drv);
	if (ret)
		return ret;
	ret = driver_add_groups(drv, drv->groups);
	if (ret) {
		bus_remove_driver(drv);
		return ret;
	}
	kobject_uevent(&drv->p->kobj, KOBJ_ADD);

	return ret;
}

struct bus_type platform_bus_type = {
	.name		= "platform",
	.dev_groups	= platform_dev_groups,
	.match		= platform_match,
	.uevent		= platform_uevent,
	.pm		= &platform_dev_pm_ops,
};

int __platform_driver_register(struct platform_driver *drv,
				struct module *owner)
{
	drv->driver.owner = owner;

    /* drv->driver.bus指向platform_bus_type */
	drv->driver.bus = &platform_bus_type;
    /* drv->probe指定的情况,drv->driver.probe指向platform_drv_probe */            
	if (drv->probe)
		drv->driver.probe = platform_drv_probe;
	if (drv->remove)
		drv->driver.remove = platform_drv_remove;
	if (drv->shutdown)
		drv->driver.shutdown = platform_drv_shutdown;

	return driver_register(&drv->driver);
}


/* include/linux/platform_device.h */
#define platform_driver_register(drv) \
	__platform_driver_register(drv, THIS_MODULE)

        重要代码的解析在代码的上方。经过上面的代码处理,结构大概如下所示。

 

2. 系统设备分析

        在介绍平台设备之前需要先介绍系统设备,也就是我们在/sys/devices下看到的设备,其实/sys/bus/platform/devices下的设备都是链接的/sys/devices下的设备,所以需要先分析它。

int __init devices_init(void)
{
	devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
	if (!devices_kset)
		return -ENOMEM;

    ......
}

        此处会在/sys下创建devices目录,初始化结构示意图如下

3. platform_device_register函数分析



int device_private_init(struct device *dev)
{
    /* 分配一个struct device_private结构 */
	dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL);
	if (!dev->p)
		return -ENOMEM;

    /* dev->p->device指向dev */
	dev->p->device = dev;

    /* 初始化dev->p->klist_children链表 */
	klist_init(&dev->p->klist_children, klist_children_get,
		   klist_children_put);
	INIT_LIST_HEAD(&dev->p->deferred_probe);
	return 0;
}


int bus_add_device(struct device *dev)
{
	struct bus_type *bus = bus_get(dev->bus);
	int error = 0;

	if (bus) {
		pr_debug("bus: '%s': add device %s\n", bus->name, dev_name(dev));
        /* 在dev->kobject.name目录下创建文件属性文件 */
		error = device_add_attrs(bus, dev);                              
		if (error)
			goto out_put;
        /* 在dev->kobject.name目录下创建group文件 */
		error = device_add_groups(dev, bus->dev_groups);                 
		if (error)
			goto out_id;
        /* /sys/bus/*/devices/的设备文件链接到/sys/devices/*下的设备文件,参考下面的参考例子*/
		error = sysfs_create_link(&bus->p->devices_kset->kobj,          
						&dev->kobj, dev_name(dev));
		if (error)
			goto out_groups;
        /* /sys/devices/*下subsystem文件链接到/sys/bus/*/devices/的设备路径,参考下面的参考例子 */
		error = sysfs_create_link(&dev->kobj,                           
				&dev->bus->p->subsys.kobj, "subsystem");
		if (error)
			goto out_subsys;
        /* dev->p->knode_bus会被加入到platform_bus_type的subsys_private的klist_devices */
		klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);    
	}
	return 0;

out_subsys:
	sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));
out_groups:
	device_remove_groups(dev, bus->dev_groups);
out_id:
	device_remove_attrs(bus, dev);
out_put:
	bus_put(dev->bus);
	return error;
}
参考:
    /sys/bus/platform/devices/下文件会链接到/sys/devices下的某个设备文件的目录文件
例如:
    /sys/devices/platform/platform_driver_test.0
    /sys/bus/platform/devices/platform_driver_test.0 -> ../../../devices/platform/platform_driver_test.0



int device_attach(struct device *dev)
{
	int ret = 0;

	device_lock(dev);
    /* dev->driver有指定情况,一般不指定 */
	if (dev->driver) {                                           
		if (klist_node_attached(&dev->p->knode_driver)) {
			ret = 1;
			goto out_unlock;
		}
		ret = device_bind_driver(dev);
		if (ret == 0)
			ret = 1;
		else {
			dev->driver = NULL;
			ret = 0;
		}
	} else {
        /* dev->driver没有指定情况,这里通过dev找到bus,通过bus找到driver,遍历bus->p->klist_drivers,一个个进行匹配,找到名字相同的driver,调用really_probe */
		ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);    
		pm_request_idle(dev);
	}
out_unlock:
	device_unlock(dev);
	return ret;
}

void bus_probe_device(struct device *dev)
{
	struct bus_type *bus = dev->bus;
	struct subsys_interface *sif;
	int ret;

    /* 判断dev的bus指针是否为空 */
	if (!bus)
		return;
    
    /* device都是默认自动probe的,此处为1 */
	if (bus->p->drivers_autoprobe) {
		ret = device_attach(dev);
		WARN_ON(ret < 0);
	}

	mutex_lock(&bus->p->mutex);
	list_for_each_entry(sif, &bus->p->interfaces, node)
		if (sif->add_dev)
			sif->add_dev(dev, sif);
	mutex_unlock(&bus->p->mutex);
}

int device_add(struct device *dev)
{
	struct device *parent = NULL;
	struct kobject *kobj;
	struct class_interface *class_intf;
	int error = -EINVAL;

    /* dev->kobj加1 */
	dev = get_device(dev);
	if (!dev)
		goto done;

	if (!dev->p) {
		error = device_private_init(dev);
		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()
	 */
    /* plateform_device_register注册的pdev->dev一般不指定init_name */
	if (dev->init_name) {
		dev_set_name(dev, "%s", dev->init_name);
		dev->init_name = NULL;
	}

	/* subsystems can specify simple device enumeration */
    /* dev_name前面dev_set_name设置过dev->kobj.name,所以此处不满足条件 */
	if (!dev_name(dev) && dev->bus && dev->bus->dev_name)
		dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);

    /* 此处也不满足条件 */
	if (!dev_name(dev)) {
		error = -EINVAL;
		goto name_error;
	}

	pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
    /* 因为dev->parent的是platform_bus(struct device),此处获取platform_bus,并使platform_bus.kobj.kref加1 */
	parent = get_device(dev->parent);

    /* 获取platform_bus的kobj */
	kobj = get_device_parent(dev, parent);
	if (kobj)
        /* 如果platform_bus的kobj存在,则dev->kobj.parent指向platform_bus的kobj */
		dev->kobj.parent = kobj;

	/* use parent numa_node */
	if (parent)
        /* 设置platform_bus的numa_node到dev->numa_node */
		set_dev_node(dev, dev_to_node(parent));

	/* first, register with generic layer. */
	/* we require the name to be set before, and pass NULL */
    /* 将dev->kobj加入到platform_bus中,platform_bus的kobj的kset指向devices_kset */
	error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
	if (error)
		goto Error;

	/* notify platform of device entry */
	if (platform_notify)
		platform_notify(dev);

	error = device_create_file(dev, &dev_attr_uevent);
	if (error)
		goto attrError;

	if (MAJOR(dev->devt)) {
		error = device_create_file(dev, &dev_attr_dev);
		if (error)
			goto ueventattrError;

		error = device_create_sys_dev_entry(dev);
		if (error)
			goto devtattrError;

		devtmpfs_create_node(dev);
	}

	error = device_add_class_symlinks(dev);
	if (error)
		goto SymlinkError;
	error = device_add_attrs(dev);
	if (error)
		goto AttrsError;
	error = bus_add_device(dev);
	if (error)
		goto BusError;
	error = dpm_sysfs_add(dev);
	if (error)
		goto DPMError;
	device_pm_add(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);
    /* match函数如果通过,则调用driver的probe函数, */
	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);

		/* 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);
	}
done:
	put_device(dev);
	return error;
 DPMError:
	bus_remove_device(dev);
 BusError:
	device_remove_attrs(dev);
 AttrsError:
	device_remove_class_symlinks(dev);
 SymlinkError:
	if (MAJOR(dev->devt))
		devtmpfs_delete_node(dev);
	if (MAJOR(dev->devt))
		device_remove_sys_dev_entry(dev);
 devtattrError:
	if (MAJOR(dev->devt))
		device_remove_file(dev, &dev_attr_dev);
 ueventattrError:
	device_remove_file(dev, &dev_attr_uevent);
 attrError:
	kobject_uevent(&dev->kobj, KOBJ_REMOVE);
	kobject_del(&dev->kobj);
 Error:
	cleanup_device_parent(dev);
	if (parent)
		put_device(parent);
name_error:
	kfree(dev->p);
	dev->p = NULL;
	goto done;
}

int platform_device_add(struct platform_device *pdev)
{
	int i, ret;

	if (!pdev)
		return -EINVAL;

    /* pdev->dev的父设备为platform_bus */
	if (!pdev->dev.parent)
		pdev->dev.parent = &platform_bus;

    /* pdev->dev.bus指向platform_bus_type */
	pdev->dev.bus = &platform_bus_type;

    /* pdev->id用来设置设备后缀 */
	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;
	}

    /* 解析resource */
	for (i = 0; i < pdev->num_resources; i++) {
		struct resource *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;
			else if (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) {
		struct resource *r = &pdev->resource[i];
		if (r->parent)
			release_resource(r);
	}

 err_out:
	return ret;
}

void device_initialize(struct device *dev)
{
    /* dev->kobj.kset指向devices_kset */
	dev->kobj.kset = devices_kset;

    /* 初始化dev->kobj的ktype */
	kobject_init(&dev->kobj, &device_ktype);
	INIT_LIST_HEAD(&dev->dma_pools);
	mutex_init(&dev->mutex);
	lockdep_set_novalidate_class(&dev->mutex);
	spin_lock_init(&dev->devres_lock);
	INIT_LIST_HEAD(&dev->devres_head);
	device_pm_init(dev);
    /* 设置dev->numa_node为-1 */
	set_dev_node(dev, -1);
}

int platform_device_register(struct platform_device *pdev)
{
	device_initialize(&pdev->dev);
	arch_setup_pdev_archdata(pdev);
	return platform_device_add(pdev);
}

        执行完上面的代码,内核对设备的管理示意图大概是这样:

         从上面代码来看注册的pdev->dev设备并没有被platform_bus_type.p->devices_kset管理,而是被devices_kset管理的,初始化platform_bus_type.p->devices_kset只是为了在/sys/bus/platform下创建devices目录,/sys/bus/platform/devices下的文件都是链接到/sys/devices下的文件。

五. 总结

        platform_device->dev.bus和platform_driver->driver.bus都是指向platform_bus_type,由platform_bus_type.p管理驱动和设备链表,当加载驱动或设备ko时候,platform_drver_register和platform_device_register最终都会去匹配同一名称的驱动和设备,最终调用驱动代码的probe函数。

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux驱动总线设备模型(Driver model)是一种抽象的设备模型,用于描述系统中各种设备设备之间的关系。它提供了一种标准的设备访问接口,使得设备驱动程序可以独立于硬件平台而存在,从而提高了设备驱动程序的可移植性和可维护性。 在Linux中,驱动总线设备模型包括以下几个主要的概念: 1. 总线(Bus):总线是一种连接设备的物理或逻辑结构,用于实现设备之间的通信。Linux支持多种总线类型,例如PCI、USB、I2C等。 2. 设备(Device):设备是指在总线上注册的硬件设备,每个设备都有一个唯一的设备树路径和设备标识符。设备可以包括子设备和属性,例如硬件资源、中断、供电等信息。 3. 驱动程序(Driver):驱动程序是指用于控制设备的软件程序,它通过向设备发送命令和读取设备的状态来实现对设备的控制。驱动程序可以注册到总线上,当设备被插入到总线上时,总线会自动匹配相应的驱动程序并加载它。 4. 类(Class):类是一组具有相似功能的设备的集合,例如输入设备、网络设备、存储设备等。类提供了一些通用的接口和属性,使得驱动程序可以更加方便地操作设备Linux驱动总线设备模型的主要优点包括: 1. 支持多种总线类型,使得驱动程序可以在不同的硬件平台上运行。 2. 提供标准的设备访问接口,使得驱动程序可以独立于硬件平台而存在。 3. 支持设备热插拔和动态配置,使得系统更加灵活和可扩展。 4. 提供了类的概念,使得驱动程序可以更加方便地操作设备

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值