Linux设备模型---总线、设备、驱动、设备类的相关操作

总线相关的操作

注册

?
int bus_register( struct bus_type *bus)
{
         int retval;
         struct subsys_private *priv;
 
         priv = kzalloc( sizeof ( struct subsys_private), GFP_KERNEL);
         if (!priv)
                 return -ENOMEM;
 
         priv->bus = bus;
         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.ktype = &bus_ktype;
         priv->drivers_autoprobe = 1;
 
         retval = kset_register(&priv->subsys);
         if (retval)
                 goto out;
 
         retval = bus_create_file(bus, &bus_attr_uevent);
         if (retval)
                 goto bus_uevent_fail;
 
         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 = kset_create_and_add( "drivers" , NULL,
                                                  &priv->subsys.kobj);
         if (!priv->drivers_kset) {
                 retval = -ENOMEM;
                 goto bus_drivers_fail;
         }
 
         klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
         klist_init(&priv->klist_drivers, NULL, NULL);
 
         retval = add_probe_files(bus);
         if (retval)
                 goto bus_probe_files_fail;
 
         retval = bus_add_attrs(bus);
         if (retval)
                 goto bus_attrs_fail;
 
         pr_debug( "bus: '%s': registered\n" , bus->name);
         return 0;
 
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;
}
EXPORT_SYMBOL_GPL(bus_register);

此函数包括如下几项工作:

1、首先会动态创建一个subsys_private结构体priv,并且设置priv与bus之间的映射关系。然后会阻塞notifier。紧接着会初始化priv->subsys.kobj,其中包括设置名称、其属于bus_kset以及类型为bus_ktype,接着就会注册此kset(关于kset_register参见前文)。紧接着会在sysfs文件系统中创建响应的目录以及文件。

2、接下来,就会创建两个kset,一个用于组织本总线上的设备对应的kobject,另一个用于组织本总线上的驱动对应的kobject。如果成功,就会创建两个klist用于组织设备和驱动的相关信息。

3、最后,就是根据默认属性在sysfs文件系统中创建相关的文件。

注销

?
void bus_unregister( struct bus_type *bus)
{
         pr_debug( "bus: '%s': unregistering\n" , bus->name);
         bus_remove_attrs(bus);
         remove_probe_files(bus);
         kset_unregister(bus->p->drivers_kset);
         kset_unregister(bus->p->devices_kset);
         bus_remove_file(bus, &bus_attr_uevent);
         kset_unregister(&bus->p->subsys);
         kfree(bus->p);
         bus->p = 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);
 
         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);

其实这个函数绝大部分工作都推到了函数bus_add_driver中(添加设备也是这种做法),在调用这个函数前只是简单的验证了一下该驱动是否已经注册过了。

?
int bus_add_driver( struct device_driver *drv)
{
         struct bus_type *bus;
         struct driver_private *priv;
         int error = 0;
 
         bus = bus_get(drv->bus);
         if (!bus)
                 return -EINVAL;
 
         pr_debug( "bus: '%s': add driver %s\n" , bus->name, drv->name);
 
         priv = kzalloc( sizeof (*priv), GFP_KERNEL);
         if (!priv) {
                 error = -ENOMEM;
                 goto out_put_bus;
         }
         klist_init(&priv->klist_devices, NULL, NULL);
         priv->driver = drv;
         drv->p = priv;
         priv->kobj.kset = bus->p->drivers_kset;
         error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
                                      "%s" , drv->name);
         if (error)
                 goto out_unregister;
 
         if (drv->bus->p->drivers_autoprobe) {
                 error = driver_attach(drv);
                 if (error)
                         goto out_unregister;
         }
         klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
         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_attrs(bus, drv);
         if (error) {
                 /* How the hell do we get out of this pickle? Give up */
                 printk(KERN_ERR "%s: driver_add_attrs(%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);
                 }
         }
 
         kobject_uevent(&priv->kobj, KOBJ_ADD);
         return 0;
 
out_unregister:
         kobject_put(&priv->kobj);
         kfree(drv->p);
         drv->p = NULL;
out_put_bus:
         bus_put(bus);
         return error;
}

这个函数在为驱动的私有数据分配了存储空间后,就会设置驱动模型中的核心结构,包括父节点、所属kset,以及初始化私有数据内嵌的kobject等。同时会将自己加入到所属总线的所有驱动构成的链表之中。

紧接着就会做sysfs相关的操作,包括创建对应的目录,属性文件等,同时会想用户空间发送uevent事件。

注销

和注册相反的过程

设备

注册

?
int device_register( struct device *dev)
{
         device_initialize(dev);
         return device_add(dev);
}
 
 
void device_initialize( struct device *dev)
{
         dev->kobj.kset = devices_kset;
         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);
}
 
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);

你可能感兴趣的:(Linux设备模型---总线、设备、驱动、设备类的相关操作)