platform device driver注册过程
来源:互联网 发布:淘宝店铺名字会重名吗 编辑:程序博客网 时间:2024/06/06 18:51
platform设备注册过程。
已/sys/devices/platform/xxxxx 目录下的文件与/sys/bus/platform/xxxxx之间是用软连接对应起来的。
系统每添加一个Kobject文件,就对应一个sys目录下的一个目录。
在系统调用的读文件时候,会判断文件类型,如果是sysfs文件系统,则会根据Kset–查找得到Kobject–>Kobj_type.attribute—->Kobj_type.sysfs_ops—>sysfs_ops.show/store.
如果是MTD设备文件,则会去判断文件系统类型,调用mtd文件系统的读写方法。
如果是网络设备文件,则会调用系统的socket接口。
如果是字符设备文件,则会调用cdev的file_operations_ops。
下面只分析sysfs的platform。
int platform_device_register(struct platform_device *pdev)
{
device_initialize(&pdev->dev);
return platform_device_add(pdev);
}
void device_initialize(struct device *dev)
{
dev->kobj.kset = devices_kset;//dev->kobj.kset=device_kset,即/sys/devices。
kobject_init(&dev->kobj, &device_ktype);//kobj_type类型,包含sysfs_ops。sysfs_ops包含show、store方法。在它的show、store方法中,会根据attr和container_of找到对应的device_attribute。然后调用他的show、store方法。根据kobj找到dev,device_attribute的show方法的参数是(dev,device_attribute,buff)。注意device_attribute不同于Kobject_type,sysfs_ops;
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);
}
接下来看看platform_device_add
/**
* 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().
*/
int platform_device_add(struct platform_device *pdev)
{
int i, ret = 0;
if (!pdev) return -EINVAL;if (!pdev->dev.parent) pdev->dev.parent = &platform_bus;pdev->dev.bus = &platform_bus_type;if (pdev->id != -1) dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);else dev_set_name(&pdev->dev, "%s", pdev->name);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)) { printk(KERN_ERR "%s: failed to claim resource %d\n", dev_name(&pdev->dev), 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:
while (–i >= 0) {
struct resource *r = &pdev->resource[i];
unsigned long type = resource_type(r);
if (type == IORESOURCE_MEM || type == IORESOURCE_IO) release_resource(r);}return ret;
}
EXPORT_SYMBOL_GPL(platform_device_add);
上面的device_initialize设置了他的kset和kobj_type。下面的platform_device_add就是真正的把设备添加到总线上了。 pdev->dev.parent = &platform_bus;1.设置他的父指针指向platform_bus,接下来Kobject_add的时候会用到这个父指针,这样就建立了/sys/devices/platform/xxxxx的文件夹。2. 设置dev的总线类型为platform_bus_type3. 设置资源文件4. 指向device_add
int device_add(struct device *dev)
{
struct device *parent = NULL;
struct class_interface *class_intf;
int error = -EINVAL;
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() */if (dev->init_name) { dev_set_name(dev, "%s", dev->init_name); dev->init_name = NULL;}if (!dev_name(dev)) { error = -EINVAL; goto name_error;}pr_debug("device: '%s': %s\n", dev_name(dev), __func__);parent = get_device(dev->parent);setup_parent(dev, parent);/* 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);if (error) goto Error;/* notify platform of device entry */if (platform_notify) platform_notify(dev);error = device_create_file(dev, &uevent_attr);if (error) goto attrError;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);}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_sysf_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->class_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->class_interfaces, node) if (class_intf->add_dev) class_intf->add_dev(dev, class_intf); mutex_unlock(&dev->class->p->class_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;
}
下面分析device_add函数1.设置设备名,dev.kobj.parent为之前设置过的parent,这里就是devices_kset。2.kobject_add,kobject_add会把obj加入到kobj.kset的list中。3.创建uevent、dev_attr、以及软连接文件。4.bus_add_device,创建软连接文件且 klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices); 把device->p->knode_bus加入到bus->p->klist_devices。以后bus可以用bus->p->klist_devices来遍历挂载他上面的所有设备。5. kobject_uevent(&dev->kobj, KOBJ_ADD);如果suppress不为真,并且也没有被过滤掉,最终就会执行/sbin/hotplug命令。6.然后执行bus_probe_device,他里面调用了device_attach函数,device_attach函数会判断device的driver成员是否为空,如果不为空则把dev和他的driver进行绑定。如果为空,则会在总线上遍历driver,如果bus上的match函数返回真,则执行driver的probe函数。然后把driver和device进行绑定。7.与开始对应,对dev的引用计数减1.下面分析下driver的注册过程。
int platform_driver_register(struct platform_driver *drv)
{
drv->driver.bus = &platform_bus_type;
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);
}
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);other = driver_find(drv->name, drv->bus);if (other) { put_driver(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;
}
EXPORT_SYMBOL_GPL(driver_register);
1,先设置driver的bus类型2.执行driver_register3、driver_register里面先根据driver_find看是否已经注册过,如果已经注册过则直接返回BUSY4. 执行bus_add_driver。 priv->kobj.kset = bus->p->drivers_kset;5.如果driver-bus->p->autoprobo为真,则执行driver_attach,driver_attach根据bus的match函数返回值来判断是否要执行probe函数,如果match函数为真,则绑定,且执行probe函数,并返回执行结果。6, klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);7,创建属性文件8. kobject_uevent(&priv->kobj, KOBJ_ADD);会根据suppress标志和bustype的subsys_private的Kset subsys的filter函数,如果方法来判断是否要执行sbin/hotplug命令9. `struct bus_type { const char *name; struct bus_attribute *bus_attrs; struct device_attribute *dev_attrs; struct driver_attribute *drv_attrs; int (*match)(struct device *dev, struct device_driver *drv); int (*uevent)(struct device *dev, struct kobj_uevent_env *env); int (*probe)(struct device *dev); int (*remove)(struct device *dev); void (*shutdown)(struct device *dev); int (*suspend)(struct device *dev, pm_message_t state); int (*resume)(struct device *dev); const struct dev_pm_ops *pm; struct subsys_private *p;};struct subsys_private { struct kset subsys; struct kset *devices_kset; struct kset *drivers_kset; struct klist klist_devices; struct klist klist_drivers; struct blocking_notifier_head bus_notifier; unsigned int drivers_autoprobe:1; struct bus_type *bus; struct list_head class_interfaces; struct kset glue_dirs; struct mutex class_mutex; struct class *class;};`
struct kset {
struct list_head list;
spinlock_t list_lock;
struct kobject kobj;
const struct kset_uevent_ops *uevent_ops;
};
struct kset_uevent_ops {
int (* const filter)(struct kset *kset, struct kobject *kobj);
const char ( const name)(struct kset *kset, struct kobject *kobj);
int (* const uevent)(struct kset *kset, struct kobject *kobj,
struct kobj_uevent_env *env);
};
“`
10,执行uevent_helper命令,其中
char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH;//sbin/mdev
所以执行的就是/sbin/mdev命令。
综上可以知道
struct bus_type 的 struct subsys_private *p;成员有几个很重要的成员
struct kset subsys; //提供了sysfs需要的一些方法,如uvent_ops
struct kset *devices_kset;//挂载在总线上的设备kset。/sys/bus/platform/devices/ 目录下都是软连接到/sys/devices/platform/xxx。然后 klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);
struct kset *drivers_kset;//挂载在总线上的驱动kset,在bus_add_driver中会把driver的driver_private的kobj.kset设置为bus->p->drivers_kset;然后执行kobject_init_and_add.就会在/sys/bus/platform/driver目录下建立对应的文件夹。struct klist klist_devices;//可以根据这个遍历总线上的设备struct klist klist_drivers;//可以根据这个遍历总线上的驱动。
1)devices_kset和drivers_kset分别指向该总线下所有设备和驱动的集合,在sysfs中,/sys/bus/xxx/下总是存在/sys/bus/xxx/devices和/sys/bus/xxx/drivers目录。
2)bus_type还管理着两个链表,klist_devices和 klist_drivers,分别表示该总线下的所有设备和所有驱动。
- platform device driver注册过程
- Linux Platform Device and Driver的注册过程解析
- Linux Platform Device and Driver的注册过程解析
- Linux Platform Device and Driver的注册过程解析
- Platform Device和Platform_driver注册过程
- platform device和platform driver
- platform device和platform driver
- platform device 与 platform driver
- platform device和platform driver
- Platform device and platform driver
- platform device和platform driver
- platform device driver
- platform device driver
- linux 内核驱动--Platform Device和Platform_driver注册过程
- linux 内核驱动--Platform Device和Platform_driver注册过程
- linux内核驱动--Platform Device和Platform_driver注册过程
- linux 内核驱动--Platform Device和Platform_driver注册过程
- Linux Platform Device and Driver
- 验证码的生成和验证
- scp命令
- Webmethods IS Truststore四层证书安装
- linux的内网地址映射到公网地址
- 学习
- platform device driver注册过程
- 最短路——洛谷P1027 Car的旅行路线
- JSP知识点
- Oracle 11g 数据库的新特性 —— 虚拟列
- Scala继承
- [leetcode]337. House Robber III
- centos vsftpd 创建 笔记
- 操作防火墙iptalbes
- 解决Nginx服务器中403 forbidden的错误