linux中platform总线解析(一)(platform总线初始化)

来源:互联网 发布:长沙软件学校排名 编辑:程序博客网 时间:2024/06/15 07:08

platform初始化的函数调用:

start_kernel-->rest_init-->kernel_init-->kernel_init_freeable-->do_base_setup--->driver_init--->platform_bus_init

初始化函数:

platform初始化函数:

int __init platform_bus_init(void){int error;//平台初始化前的一些清理工作early_platform_cleanup();//注册platform_bus设备error = device_register(&platform_bus);if (error)return error;//注册platform_bus_type总线error =  bus_register(&platform_bus_type);if (error)device_unregister(&platform_bus);return error;}

下面就分开解析初始化函数所作的工作。

1, eraly_platform_cleanup函数

早期清理工作,主要是清理early_platform_device_list链表

static __initdata LIST_HEAD(early_platform_driver_list);static __initdata LIST_HEAD(early_platform_device_list);
void __init early_platform_cleanup(void){struct platform_device *pd, *pd2;//把early_platform_device_list链表中的元素删除,并把元素占据空间清零list_for_each_entry_safe(pd, pd2, &early_platform_device_list, dev.devres_head) {list_del(&pd->dev.devres_head);memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head));}}

2,platform设备的定义

struct device platform_bus = {.init_name= "platform",};

可以看到设备只是初始化了名字


3,platform总线的定义

struct bus_type platform_bus_type = {.name= "platform",.dev_attrs= platform_dev_attrs,   .match= platform_match,     //总线匹配函数(device和driver).uevent= platform_uevent,     //事件(热插拔)函数.pm= &platform_dev_pm_ops,//电源管理相关的操作函数};
在这里对总线的定义主要是设置总线的操作函数

4,platform设备注册函数device_register

对于platform总线就是初始化了操作总线的函数。

/*设备的注册分为两个步骤
*第一步:初始化设备
*第二部:把设备加载到系统中
*/

int device_register(struct device *dev){device_initialize(dev);return device_add(dev);}

4-1,设备初始化

/**注册设备时的i初始化动作*/void device_initialize(struct device *dev){//这是设置设备在sysfs文件系统中的显示位置(sys/device目录下)//这里知道作用就好,后面会再来介绍kset,kobject和sysfs文件系统的相关内容dev->kobj.kset = devices_kset;//初始化设备对应的kobj_type的类型,主要时sysfs相关的,包含了对sysfs的操作函数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);//在多核操作系统中,设置设备和那个物理核近set_dev_node(dev, -1);}

4-2,把设备加入到系统中

/**把设备注册进系统中*这个函数中很多跟sysfs相关的了解就好,后面会仔细分析*/int device_add(struct device *dev){struct device *parent = NULL;struct kobject *kobj;struct class_interface *class_intf;int error = -EINVAL;//如果设备不为空,就增加一次对设备的引用计数dev = get_device(dev);if (!dev)goto done;//红帽相关的结构体if (!dev->device_rh)device_rh_alloc(dev);//初始化设备的私有化数据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() *把设备在sysfs中显示的名字设备为当时初始化的init_name的值 *并把设备的dev->init_name设置为空 */if (dev->init_name) {dev_set_name(dev, "%s", dev->init_name);dev->init_name = NULL;}/*设置设备的名字,不过这里条件不符合,跳过*/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__);//增加父设备的引用计数,并返回父设备的结构体parent = get_device(dev->parent);//返回父设备的kobject的结构体,platfrom没有父设备,所以父设备名字是virtual,虚拟设备kobj = get_device_parent(dev, parent);if (kobj)dev->kobj.parent = kobj;/* use parent numa_node *根据父设备的numa_node设置本设备的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 * 在sysfs中创建对应的目录 */error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);/* notify platform of device entry */if (platform_notify)platform_notify(dev);//在platform目录下,创建uevent文件error = device_create_file(dev, &uevent_attr);if (error)goto attrError;//如果devt>>20大于0,就创建dev这个文件if (MAJOR(dev->devt)) {error = device_create_file(dev, &devt_attr);if (error)goto ueventattrError;error = device_create_sys_dev_entry(dev);if (error)goto devtattrError;devtmpfs_create_node(dev);}//在class中为这个设备创建链接文件(platforms不是设备,不会创建)error = device_add_class_symlinks(dev);if (error)goto SymlinkError;//为设备创建属性文件error = device_add_attrs(dev);if (error)goto AttrsError;//把设备加入到设备对应总线的链表中(platformo没有对应的总线)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);//为这个刚注册的设备查找一个对应的驱动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);//把设备加入到设备对应的class的设备链表中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, &devt_attr); ueventattrError:device_remove_file(dev, &uevent_attr); 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;}

4-3,获取设备名字dev_name

/**获取设备的名字*/static inline const char *dev_name(const struct device *dev){/**如果由init_name就返回init_name,否则返回kobject中的名字*/if (dev->init_name)return dev->init_name;return kobject_name(&dev->kobj);}

4-4,为设备寻找驱动

/*为设备查找驱动*因为这里的platform没有bus,所以直接返回*/void bus_probe_device(struct device *dev){struct bus_type *bus = dev->bus;struct subsys_interface *sif;int ret;if (!bus)return;//调用device_attach为设备找驱动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);}

这时platform设备就加入到系统中了。

5,向系统注册总线

总线注册:int bus_register(struct bus_type *bus){int retval;struct subsys_private *priv;struct lock_class_key *key = &bus->lock_key;priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL);if (!priv)return -ENOMEM;//分配subsys_private结构,用于存储设备和驱动priv->bus = bus;bus->p = priv;//初始化bus上的通知连BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);//为subsys设置nameretval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);if (retval)goto out;//指示属于哪一个子系统priv->subsys.kobj.kset = bus_kset;//设置总线对应的sysfs上的操作方法priv->subsys.kobj.ktype = &bus_ktype;//设置自动匹配驱动priv->drivers_autoprobe = 1;//注册子系统retval = kset_register(&priv->subsys);if (retval)goto out;//创建总线的uevent文件retval = bus_create_file(bus, &bus_attr_uevent);if (retval)goto bus_uevent_fail;//创建devices目录priv->devices_kset = kset_create_and_add("devices", NULL, &priv->subsys.kobj);if (!priv->devices_kset) {retval = -ENOMEM;goto bus_devices_fail;}//创建drivers目录priv->drivers_kset = kset_create_and_add("drivers", NULL, &priv->subsys.kobj);if (!priv->drivers_kset) {retval = -ENOMEM;goto bus_drivers_fail;}INIT_LIST_HEAD(&priv->interfaces);__mutex_init(&priv->mutex, "subsys mutex", key);//设置klist_devices对应的操作方法函数klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);klist_init(&priv->klist_drivers, NULL, NULL);//创建bus_attr_drivers_probe和bus_attr_drivers_autoprobe文件retval = add_probe_files(bus);if (retval)goto bus_probe_files_fail;//为bus增加默认的属性文件retval = bus_add_attrs(bus);if (retval)goto bus_attrs_fail;//创建groups的属性文件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:bus_remove_attrs(bus);bus_attrs_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;}

其中使用到的重要的数据结构:

//存储device,driver,bus上关于挂接的设备相关信息struct subsys_private {struct kset subsys;         //定义在哪个子系统struct kset *devices_kset;  //在这个子系统中的device目录struct list_head interfaces; //子系统结构struct mutex mutex;struct kset *drivers_kset; //子系统中driver目录struct klist klist_devices; //分配的设备,在bus中指挂接的设备struct klist klist_drivers; //分配的驱动,在bus中指挂接的驱动struct blocking_notifier_head bus_notifier; //通知连unsigned int drivers_autoprobe:1; //是否自动匹配驱动struct bus_type *bus;     //指向所属的busstruct kset glue_dirs;struct class *class;    //指向所属的class};



哦啦,这时就把platform总线加入到了系统中了。
其中好多对于sysfs的操作,以及在sysfs中的显示等,在这里只是需要了解就可以了,后面会详细介绍相关的内容。







原创粉丝点击