my代码跟踪之device_register

内核代码为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_info power;

       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_archdata archdata;

 

       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流程一样

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

suvine

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值