my代码跟踪之device_register

来源:互联网 发布:淘宝怎么删除空间图集 编辑:程序博客网 时间:2024/06/02 04:10

内核代码为Linux Kernel:3.4.x

/**

 *struct device - The basic device structure

 *@parent:   The device's"parent" device, the device to which it is attached.

 *        In most cases, a parent device is somesort of bus or host

 *        controller. If parent is NULL, the device,is a top-level device,

 *        which is not usually what you want.

 *@p:          Holds the private data ofthe driver core portions of the device.

 *        See the comment of the structdevice_private for detail.

 *@kobj:     A top-level, abstract classfrom which other classes are derived.

 *@init_name:    Initial name of thedevice.

 *@type:     The type of device.

 *        This identifies the device type andcarries type-specific

 *        information.

 *@mutex:   Mutex to synchronize calls toits driver.

 *@bus:Type of bus device is on.

 *@driver:   Which driver has allocatedthis

 *@platform_data: Platform data specific to the device.

 *        Example: For devices on custom boards,as typical of embedded

 *        and SOC based hardware, Linux oftenuses platform_data to point

 *        to board-specific structures describingdevices and how they

 *        are wired. That can include what ports are available,chip

 *        variants, which GPIO pins act in whatadditional roles, and so

 *        on. This shrinks the "Board Support Packages" (BSPs) and

 *        minimizes board-specific #ifdefs indrivers.

 *@power:   For device power management.

 *        See Documentation/power/devices.txt fordetails.

 *@pm_domain:  Provide callbacks that areexecuted during system suspend,

 *        hibernation, system resume and duringruntime PM transitions

 *        along with subsystem-level anddriver-level callbacks.

 *@pins:      For device pin management.

 *          See Documentation/pinctrl.txt fordetails.

 *@numa_node:  NUMA node this device isclose to.

 *@dma_mask:   Dma mask (if dma'bledevice).

 *@coherent_dma_mask: Like dma_mask, but for alloc_coherent mapping as not all

 *        hardware supports 64-bit addresses forconsistent allocations

 *        such descriptors.

 *@dma_parms:  A low level driver may setthese to teach IOMMU code about

 *        segment limitations.

 *@dma_pools:   Dma pools (if dma'bledevice).

 *@dma_mem:    Internal for coherent memoverride.

 *@archdata:For arch-specific additions.

 *@of_node:Associated device tree node.

 *@devt:     For creating the sysfs"dev".

 *@id:         device instance

 *@devres_lock: Spinlock to protect the resource of the device.

 *@devres_head: The resources list of the device.

 *@knode_class: The node used to add the device to the class list.

 *@class:     The class of the device.

 *@groups:  Optional attribute groups.

 *@release:  Callback to free the deviceafter all references have

 *        gone away. This should be set by theallocator of the

 *        device (i.e. the bus driver thatdiscovered the device).

 *

 * Atthe lowest level, every device in a Linux system is represented by an

 *instance of struct device. The device structure contains the information

 *that the device model core needs to model the system. Most subsystems,

 *however, track additional information about the devices they host. As a

 * result,it is rare for devices to be represented by bare device structures;

 *instead, that structure, like kobject structures, is usually embedded within

 * ahigher-level representation of the device.

 */

struct device {

      structdevice         *parent;

 

      structdevice_private     *p;

 

      structkobject kobj;

      constchar             *init_name; /* initialname of the device */

      conststruct device_type *type;

 

      structmutex          mutex;   /* mutex to synchronize calls to

                                   * its driver.

                                   */

 

      structbus_type      *bus;             /* type of bus device is on */

      structdevice_driver *driver; /* which driverhas allocated this

                                    device */

      void       *platform_data;     /* Platform specific data, device

                                    core doesn't touch it */

      structdev_pm_infopower;

      structdev_pm_domain  *pm_domain;

 

#ifdef CONFIG_PINCTRL

      structdev_pin_info*pins;

#endif

 

#ifdef CONFIG_NUMA

      int         numa_node;   /* NUMA node this device is close to */

#endif

      u64        *dma_mask;  /* dma mask (if dma'able device) */

      u64        coherent_dma_mask;/* Like dma_mask, butfor

                                      alloc_coherent mappings as

                                      not all hardware supports

                                      64 bit addresses for consistent

                                      allocations such descriptors. */

 

      structdevice_dma_parameters *dma_parms;

 

      structlist_head      dma_pools;    /* dma pools (if dma'ble) */

 

      structdma_coherent_mem    *dma_mem; /* internalfor coherent mem

                                      override */

#ifdef CONFIG_CMA

      structcma *cma_area;          /* contiguousmemory area for dma

                                    allocations */

#endif

      /*arch specific additions */

      structdev_archdataarchdata;

 

      structdevice_node *of_node; /* associateddevice tree node */

 

      dev_t                   devt;      /* dev_t, creates the sysfs "dev" */

      u32               id;  /* device instance */

 

      spinlock_t             devres_lock;

      structlist_head      devres_head;

 

      structklist_node    knode_class;

      structclass            *class;

      conststruct attribute_group **groups; /*optional groups */

 

      void(*release)(struct device *dev);

      structiommu_group     *iommu_group;

};

 

/**

 *device_register - register a device with the system.

 *@dev: pointer to the device structure

 *

 *This happens in two clean steps - initialize the device

 *and add it to the system. The two steps can be called

 *separately, but this is the easiest and most common.

 *I.e. you should only call the two helpers separately if

 *have a clearly defined need to use and refcount the device

 *before it is added to the hierarchy.

 *

 *For more information, see the kerneldoc for device_initialize()

 *and device_add().

 *

 *NOTE: _Never_ directly free @dev after calling this function, even

 * ifit returned an error! Always use put_device() to give up the

 *reference initialized in this function instead.

 */

 

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所属集合,devices_kset其实在第一层,sys/devices/

      kobject_init(&dev->kobj,&device_ktype); //初始化设备的kobject

      INIT_LIST_HEAD(&dev->dma_pools);     //初始化设备的DMA池,用于传递大数据

      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);           //power相关的初始化

      set_dev_node(dev,-1);         //设置numa_node

}

标注一end

int device_add(structdevice *dev)

{

      structdevice *parent = NULL;

      structkobject *kobj;

      structclass_interface *class_intf;

      interror = -EINVAL;

 

      dev= get_device(dev);  //增加设备的kobject的引用计数

      if(!dev)

             gotodone;

 

      if(!dev->p) {

             error= device_private_init(dev);  //初始化dev的私有成员,及其链表操作函数

             if(error)

                    gotodone;

      }

 

      /*

       * for statically allocated devices, whichshould all be converted

       * some day, we need to initialize the name. Weprevent reading back

       * the name, and force the use of dev_name()

       */

      if(dev->init_name) {

             dev_set_name(dev,"%s", dev->init_name);        //设置名字,给kobj  

             dev->init_name= NULL;

      }

 

      /*subsystems can specify simple device enumeration */

      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;

             gotoname_error;

      }

 

      pr_debug("device:'%s': %s\n", dev_name(dev), __func__);

 

      parent= get_device(dev->parent);       //增加父设备kobject的引用

      kobj= get_device_parent(dev, parent);

      if(kobj)

             dev->kobj.parent= kobj;             //设置该设备kobject父对象

 

      /*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添加进父对象设备模型

      if(error)

             gotoError;

 

      /*notify platform of device entry */

      if(platform_notify)

             platform_notify(dev);

 

      error= device_create_file(dev, &uevent_attr);

      if(error)

             gotoattrError;

 

      if(MAJOR(dev->devt)) {

             error= device_create_file(dev, &devt_attr);

             if(error)

                    gotoueventattrError;

 

             error= device_create_sys_dev_entry(dev);

             if(error)

                    gotodevtattrError;

 

             devtmpfs_create_node(dev);

      }

 

      error= device_add_class_symlinks(dev);

      if(error)

             gotoSymlinkError;

      error= device_add_attrs(dev);

      if(error)

             gotoAttrsError;

      error= bus_add_device(dev);             //将设备添加进总线中

      if(error)

             gotoBusError;

      error= dpm_sysfs_add(dev);

      if(error)

             gotoDPMError;

      device_pm_add(dev);

 

      /*Notify clients of device addition. Thiscall must come

       * after dpm_sysfs_add() and beforekobject_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);

             /*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);

      returnerror;

 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;

      gotodone;

}

 

voidbus_probe_device(struct device *dev)

{

      structbus_type *bus = dev->bus;

      structsubsys_interface *sif;

      intret;

 

      if(!bus)

             return;

 

      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_attach(structdevice *dev)

{

      intret = 0;

 

      device_lock(dev);

      if(dev->driver) {

             if(klist_node_attached(&dev->p->knode_driver)) {

                    ret= 1;

                    gotoout_unlock;

             }

             ret= device_bind_driver(dev);

             if(ret == 0)

                    ret= 1;

             else{

                    dev->driver= NULL;

                    ret= 0;

             }

      }else {

             pm_runtime_get_noresume(dev);

             ret= bus_for_each_drv(dev->bus, NULL, dev, __device_attach);

             pm_runtime_put_sync(dev);

      }

out_unlock:

      device_unlock(dev);

      returnret;

}

static int__device_attach(struct device_driver *drv, void *data)

{

      structdevice *dev = data;

 

      if(!driver_match_device(drv, dev))

             return0;

 

      returndriver_probe_device(drv, dev);

}此函数以后的分支和driver_register流程一样

0 0
原创粉丝点击