内核代码为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流程一样