您的位置:首页 > 运维架构 > Linux

设备驱动中的device(kernel-4.7)

2016-12-07 15:43 417 查看
device结构体定义,在kernel-4.7/include/linux/device.h中:

/**
* struct device - The basic device structure
* @driver_data: Private pointer for driver specific info.
* @power:  For device power management.
*      See Documentation/power/devices.txt for details.
* @pm_domain:  Provide callbacks that are executed during system suspend,
*      hibernation, system resume and during runtime PM transitions
*      along with subsystem-level and driver-level callbacks.
* @pins:   For device pin management.
*      See Documentation/pinctrl.txt for details.
* @msi_list:   Hosts MSI descriptors
* @msi_domain: The generic MSI domain this device is using.
* @numa_node:  NUMA node this device is close to.
* @dma_mask:   Dma mask (if dma'ble device).
* @coherent_dma_mask: Like dma_mask, but for alloc_coherent mapping as not all
*      hardware supports 64-bit addresses for consistent allocations
*      such descriptors.
* @dma_pfn_offset: offset of DMA memory range relatively of RAM
* @dma_parms:  A low level driver may set these to teach IOMMU code about
*      segment limitations.
* @dma_pools:  Dma pools (if dma'ble device).
* @dma_mem:    Internal for coherent mem override.
* @cma_area:   Contiguous memory area for dma allocations
* @archdata:   For arch-specific additions.
* @of_node:    Associated device tree node.
* @fwnode: Associated device node supplied by platform firmware.
* @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 device after all references have
*      gone away. This should be set by the allocator of the
*      device (i.e. the bus driver that discovered the device).
* @iommu_group: IOMMU group the device belongs to.
*
* @offline_disabled: If set, the device is permanently online.
* @offline:    Set after successful invocation of bus type's .offline().
*
* At the 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
* a higher-level representation of the device.
*/
struct device {
struct device       *parent;   //指向其父设备。

struct device_private   *p;   // 设备驱动部分的核心私有数据

struct kobject kobj;    // kobject类, 用于联系到sysfs中
const char      *init_name; /* initial name of the device */
const struct device_type *type;   //表示设备的类型

struct mutex        mutex;  /* mutex to synchronize calls to
* its driver.
*/

struct bus_type *bus;       /* type of bus device is on 设备所在总线的指针 */
//设备所用驱动的指针
struct device_driver *driver;   /* which driver has allocated this device */
void        *platform_data; /* Platform specific data, device
core doesn't touch it */
void        *driver_data;   /* Driver data, set and get with
dev_set/get_drvdata */
struct dev_pm_info  power;
struct dev_pm_domain    *pm_domain;

#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
struct irq_domain   *msi_domain;
#endif
#ifdef CONFIG_PINCTRL
struct dev_pin_info *pins;
#endif
#ifdef CONFIG_GENERIC_MSI_IRQ
struct list_head    msi_list;
#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, but for
alloc_coherent mappings as
not all hardware supports
64 bit addresses for consistent
allocations such descriptors. */
unsigned long   dma_pfn_offset;

struct device_dma_parameters *dma_parms;

struct list_head    dma_pools;  /* dma pools (if dma'ble) */

struct dma_coherent_mem *dma_mem; /* internal for coherent mem
override */
#ifdef CONFIG_DMA_CMA
struct cma *cma_area;       /* contiguous memory area for dma
allocations */
#endif
/* arch specific additions */
struct dev_archdata archdata;

struct device_node  *of_node; /* associated device tree node */
struct fwnode_handle    *fwnode; /* firmware device node */

dev_t           devt;   /* dev_t, creates the sysfs "dev" */
u32         id; /* device instance */

spinlock_t      devres_lock;
struct list_head    devres_head;

struct klist_node   knode_class;   //连入class链表时所用的klist节点
struct class        *class;    //指向类的指针
const struct attribute_group **groups;  /* optional groups 设备的属性集合*/

void    (*release)(struct device *dev); //设备释放时调用的函数
struct iommu_group  *iommu_group;

bool            offline_disabled:1;
bool            offline:1;
};


device结构体用于描述设备相关的信息设备之间的层次关系,以及设备与总线、驱动的关系。

/**
* struct device_private - structure to hold the private to the driver core portions of the device structure.
*
* @klist_children - klist containing all children of this device
* @knode_parent - node in sibling list
* @knode_driver - node in driver list
* @knode_bus - node in bus list
* @deferred_probe - entry in deferred_probe_list which is used to retry the
*  binding of drivers which were unable to get all the resources needed by
*  the device; typically because it depends on another driver getting
*  probed first.
* @device - pointer back to the struct device that this structure is
* associated with.
*
* Nothing outside of the driver core should ever touch these fields.
*/
struct device_private {
struct klist klist_children;   //子设备的链表
struct klist_node knode_parent; //连入父设备的klist_children时所用的节点
struct klist_node knode_driver; //连入驱动的设备链表所用的节点
struct klist_node knode_bus;  //连入总线的设备链表时所用的节点
struct list_head deferred_probe;
struct device *device;
};
//从父设备的klist_children上节点,获得相应的device_private
#define to_device_private_parent(obj)   \
container_of(obj, struct device_private, knode_parent)

//从驱动的设备链表上节点,获得对应的device_private
#define to_device_private_driver(obj)   \
container_of(obj, struct device_private, knode_driver)

从总线的设备链表上节点,获得对应的device_private
#define to_device_private_bus(obj)  \
container_of(obj, struct device_private, knode_bus)


struct device
中有一部分不愿意让外界看到,所以做出
struct device_private
结构,包括了设备驱动模型内部的链接。这个结构体定义在drivers/base/base.h文件中。

Linux设备模型中,device相关的sysfs结构的初始化是由
devices_init
函数完成的,该函数定义在drivers/base/core.c文件中,其内容如下:

int __init devices_init(void)
{
//创建devices_kset,它是所有device的集合,它的名字是“devices”,对应/sys/devices目录
devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
if (!devices_kset)
return -ENOMEM;

//创建dev_kobj,它的名字是“dev”,对应/sys/dev目录
dev_kobj = kobject_create_and_add("dev", NULL);
if (!dev_kobj)
goto dev_kobj_err;

//创建sysfs_dev_block_kobj,它的名字是“block”,对应/sys/dev/block目录
sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
if (!sysfs_dev_block_kobj)
goto block_kobj_err;

创建sysfs_dev_char_kobj,它的名字是“char”,对应/sys/dev/char目录
sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
if (!sysfs_dev_char_kobj)
goto char_kobj_err;

return 0;

char_kobj_err:
kobject_put(sysfs_dev_block_kobj);
block_kobj_err:
kobject_put(dev_kobj);
dev_kobj_err:
kset_unregister(devices_kset);
return -ENOMEM;
}


注册一个device是通过调用
device_register
函数完成的,该函数定义在drivers/base/core.c文件中,其内容如下:

/**
* 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
* if it 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); //调用device_initialize函数对device结构体进行初始化
return device_add(dev); //调用device_add函数,将device添加到系统中
}


调用
device_initialize
函数对device结构体进行初始化。该函数定义在drivers/base/core.c文件中,其内容如下:

/**
* device_initialize - init device structure.
* @dev: device.
*
* This prepares the device for use by other layers by initializing
* its fields.
* It is the first half of device_register(), if called by
* that function, though it can also be called separately, so one
* may use @dev's fields. In particular, get_device()/put_device()
* may be used for reference counting of @dev after calling this
* function.
*
* All fields in @dev must be initialized by the caller to 0, except
* for those explicitly set to some other value.  The simplest
* approach is to use kzalloc() to allocate the structure containing
* @dev.
*
* NOTE: Use put_device() to give up your reference instead of freeing
* @dev directly once you have called this function.
*/
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);
#ifdef CONFIG_GENERIC_MSI_IRQ
INIT_LIST_HEAD(&dev->msi_list);
#endif
}


调用device_add函数,将device添加到系统中,该函数定义在drivers/base/core.c文件中,其内容如下:

/**
* device_add - add device to device hierarchy.
* @dev: device.
*
* This is part 2 of device_register(), though may be called
* separately _iff_ device_initialize() has been called separately.
*
* This adds @dev to the kobject hierarchy via kobject_add(), adds it
* to the global and sibling lists for the device, then
* adds it to the other relevant subsystems of the driver model.
*
* Do not call this routine or device_register() more than once for
* any device structure.  The driver model core is not designed to work
* with devices that get unregistered and then spring back to life.
* (Among other things, it's very hard to guarantee that all references
* to the previous incarnation of @dev have been dropped.)  Allocate
* and register a fresh new struct device instead.
*
* NOTE: _Never_ directly free @dev after calling this function, even
* if it returned an error! Always use put_device() to give up your
* reference instead.
*/
int device_add(struct device *dev)
{
struct device *parent = NULL;
struct kobject *kobj;
struct class_interface *class_intf;
int error = -EINVAL;

dev = get_device(dev); //调用get_device增加device(其实是device.kobj)的引用计数
if (!dev)
goto done;

if (!dev->p) {   //如果dev->p是NULL,则调用device_private_init函数为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()
*/
//如果dev->init_name不为空,则调用dev_set_name设置device的名字(其实是设置device.kobj的名字)
if (dev->init_name) {
dev_set_name(dev, "%s", dev->init_name);
dev->init_name = NULL;
}

/* subsystems can specify simple device enumeration */
//如果device的名字为空,并且dev->bus->dev_name不为空,则用dev->bus->dev_name作为device的名字。
if (!dev_name(dev) && dev->bus && dev->bus->dev_name)
dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);

//如果device的名字仍然为空,则出错退出
if (!dev_name(dev)) {
error = -EINVAL;
goto name_error;
}

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

//取得dev->parent,保存在parent变量中
parent = get_device(dev->parent);
//调用get_device_parent函数,该函数的作用是取得dev->kobj.parent,即device对应的kobject的parent kobject
kobj = get_device_parent(dev, parent);
//如果通过get_device_parent函数取得了父kobject,则用它来设置dev->kobj.parent
if (kobj)
dev->kobj.parent = kobj;

/* use parent numa_node */

if (parent && (dev_to_node(dev) == NUMA_NO_NODE))
set_dev_node(dev, dev_to_node(parent));

/* first, register with generic layer. */
/* we require the name to be set before, and pass NULL */
//调用kobject_add将dev->kobj注册到sysfs系统中
error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
if (error)
goto Error;

/* notify platform of device entry */
if (platform_notify)
platform_notify(dev);
//调用device_create_file创建uevent属性文件
error = device_create_file(dev, &dev_attr_uevent);
if (error)
goto attrError;

//调用device_add_class_symlinks(dev)函数,创建dev->class相关的链接
error = device_add_class_symlinks(dev);
if (error)
goto SymlinkError;
//调用device_add_attrs(dev)函数,该函数创建与dev->class相关的一些属性文件
error = device_add_attrs(dev);
if (error)
goto AttrsError;
//调用bus_add_device(dev)函数,该函数在/sys/bus/devices目录下创建一个链接文件,指向/sys/devices/dev->init_name
error = bus_add_device(dev);
if (error)
goto BusError;
error = dpm_sysfs_add(dev);
if (error)
goto DPMError;
device_pm_add(dev);
//通过MAJOR(dev->devt)取得设备对应的主设备号
//如果设备的主设备号不为0,调用device_create_file创建dev属性文件
if (MAJOR(dev->devt)) {
error = device_create_file(dev, &dev_attr_dev);
if (error)
goto DevAttrError;

//调用device_create_sys_dev_entry(dev)函数
error = device_create_sys_dev_entry(dev);
if (error)
goto SysEntryError;

/* 如果device主设备号不为0,还会调用devtmpfs_create_node(dev)函数在/dev目录下自动生成一个设备节点。在Linux早期,/dev下的设备节点是通过mknod命令手动添加的,现在通过devtmpfs文件系统,就可以在调用device_register函数注册设备时自动向/dev目录下添加设备节点,该节点的名字就是dev->init_name*/
devtmpfs_create_node(dev);
}

/* Notify clients of device addition.  This call must come
* after dpm_sysfs_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)函数为新添加的device探测匹配的device_driver
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);
return error;
SysEntryError:
if (MAJOR(dev->devt))
device_remove_file(dev, &dev_attr_dev);
DevAttrError:
device_pm_remove(dev);
dpm_sysfs_remove(dev);
DPMError:
bus_remove_device(dev);
BusError:
device_remove_attrs(dev);
AttrsError:
device_remove_class_symlinks(dev);
SymlinkError:
device_remove_file(dev, &dev_attr_uevent);
attrError:
kobject_uevent(&dev->kobj, KOBJ_REMOVE);
kobject_del(&dev->kobj);
Error:
cleanup_device_parent(dev);
put_device(parent);
name_error:
kfree(dev->p);
dev->p = NULL;
goto done;
}


device_add
函数中,如果
dev->p
是NULL,则调用
device_private_init
函数为
dev->p
分配内存空间并进行初始化,该函数定义在drivers/base/core.c文件中,其内容如下

int device_private_init(struct device *dev)
{
dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL);
if (!dev->p)
return -ENOMEM;
dev->p->device = dev;
klist_init(&dev->p->klist_children, klist_children_get,
klist_children_put);
INIT_LIST_HEAD(&dev->p->deferred_probe);
return 0;
}


device_add
中调用了
get_device_parent
函数,该函数的作用是取得
dev->kobj.parent
,即device对应的kobject的parent kobject。该函数定义在drivers/base/core.c文件中,其内容如下:

static struct kobject *get_device_parent(struct device *dev,
struct device *parent)
{
if (dev->class) {
//如果dev->class不为NULL,并且dev->parent为NULL, 这种情况下系统将为dev->kobj.parent建立一个虚拟上层对象“virtual”,如此,将dev对象加入系统将会在/sys/devices/virtual中产生一个新的目录/sys/devices/virtual/dev->init_name
struct kobject *kobj = NULL;
struct kobject *parent_kobj;
struct kobject *k;

#ifdef CONFIG_BLOCK
/* block disks show up in /sys/block */
if (sysfs_deprecated && dev->class == &block_class) {
if (parent && parent->class == &block_class)
return &parent->kobj;
return &block_class.p->subsys.kobj;
}
#endif

/*
* If we have no parent, we live in "virtual".
* Class-devices with a non class-device as parent, live
* in a "glue" directory to prevent namespace collisions.
*/
if (parent == NULL)
parent_kobj = virtual_device_parent(dev);
else if (parent->class && !dev->class->ns_type)
return &parent->kobj;
else
parent_kobj = &parent->kobj;

mutex_lock(&gdp_mutex);

/* find our class-directory at the parent and reference it */
spin_lock(&dev->class->p->glue_dirs.list_lock);
list_for_each_entry(k, &dev->class->p->glue_dirs.list, entry)
if (k->parent == parent_kobj) {
kobj = kobject_get(k);
break;
}
spin_unlock(&dev->class->p->glue_dirs.list_lock);
if (kobj) {
mutex_unlock(&gdp_mutex);
return kobj;
}

/* or create a new class-directory at the parent device */
k = class_dir_create_and_add(dev->class, parent_kobj);
/* do not emit an uevent for this simple "glue" directory */
mutex_unlock(&gdp_mutex);
return k;
}

/* subsystems can specify a default root directory for their devices */
if (!parent && dev->bus && dev->bus->dev_root)
return &dev->bus->dev_root->kobj;

if (parent)
return &parent->kobj;
return NULL;
}


device_add
函数中调用
device_create_file
创建uevent属性文件。
dev_attr_uevent
定义在drivers/base/core.c文件中,其内容如下:

static DEVICE_ATTR_RW(uevent);


device_attribute
结构体定义在include/linux/device.h文件中,其内容如下:

/* interface for exporting device attributes */
struct device_attribute {
struct attribute    attr;
ssize_t (*show)(struct device *dev, struct device_attribute *attr,
char *buf);
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count);
};


device_create_file
定义在drivers/base/core.c文件中,其内容如下:

/**
* device_create_file - create sysfs attribute file for device.
* @dev: device.
* @attr: device attribute descriptor.
*/
int device_create_file(struct device *dev,
const struct device_attribute *attr)
{
int error = 0;

if (dev) {
WARN(((attr->attr.mode & S_IWUGO) && !attr->store),
"Attribute %s: write permission without 'store'\n",
attr->attr.name);
WARN(((attr->attr.mode & S_IRUGO) && !attr->show),
"Attribute %s: read permission without 'show'\n",
attr->attr.name);
error = sysfs_create_file(&dev->kobj, &attr->attr);
}

return error;
}


device_add
函数中如果设备的主设备号不为0,调用
device_create_file
创建dev属性文件。
dev_attr
定义在drivers/base/core.c文件中,其内容如下

static DEVICE_ATTR_RO(dev);


device_add
函数中调用
device_create_sys_dev_entry(dev)
函数,该函数定义在drivers/base/core.c文件中,其内容如下:

static int device_create_sys_dev_entry(struct device *dev)
{
struct kobject *kobj = device_to_dev_kobj(dev);
int error = 0;
char devt_str[15];

if (kobj) {
format_dev_t(devt_str, dev->devt);
error = sysfs_create_link(kobj, &dev->kobj, devt_str);
}

return error;
}


其中调用
device_to_dev_kobj(dev)
,该函数定义在drivers/base/core.c文件中,其内容如下:

/**
* device_to_dev_kobj - select a /sys/dev/ directory for the device
* @dev: device
*
* By default we select char/ for new entries.  Setting class->dev_obj
* to NULL prevents an entry from being created.  class->dev_kobj must
* be set (or cleared) before any devices are registered to the class
* otherwise device_create_sys_dev_entry() and
* device_remove_sys_dev_entry() will disagree about the presence of
* the link.
*/
static struct kobject *device_to_dev_kobj(struct device *dev)
{
struct kobject *kobj;

if (dev->class)
kobj = dev->class->dev_kobj;
else
kobj = sysfs_dev_char_kobj;

return kobj;
}


从该函数的注释可以看出,该函数的作用是返回device对应的/sys/dev/下的一个目录。该函数的返回值是一个kobject,一个kobject在sysfs系统中对应一个目录。如果
dev->class
不为NULL,该函数返回
dev->class->dev_kobj
;如果
dev->class
为NULL,该函数返回
sysfs_dev_char_kobj
,它对应/sys/dev/char目录。

device_create_sys_dev_entry
调用
format_dev_t
宏,该宏定义在include/linux/kdev_t.h文件中,其内容如下

#define format_dev_t(buffer, dev)                   \
({                              \
sprintf(buffer, "%u:%u", MAJOR(dev), MINOR(dev));   \
buffer;                         \
})


该宏的作用是把“主设备号:次设备号”字符串写入buffer变量中

device_create_sys_dev_entry
调用
sysfs_create_link(kobj, &dev->kobj, devt_str)
创建一个链接。该函数定义在fs/sysfs/symlink.c文件中,其内容如下:

/**
*  sysfs_create_link - create symlink between two objects.
*  @kobj:  object whose directory we're creating the link in.
*  @target:    object we're pointing to.
*  @name:      name of the symlink.
*/
int sysfs_create_link(struct kobject *kobj, struct kobject *target,
const char *name)
{
return sysfs_do_create_link(kobj, target, name, 1);
}


由注释可以看出,第一个参数是我们将要创建的链接所在的目录,第二个参数是链接指向的源,第三个参数是链接的名字。

device_add
函数中调用
bus_probe_device(dev)
函数为新添加的device探测匹配的
device_driver
。该函数定义在drivers/base/bus.c文件中,其内容如下:

/**
* bus_probe_device - probe drivers for a new device
* @dev: device to probe
*
* - Automatically probe for a driver if the bus allows it.
*/
void bus_probe_device(struct device *dev)
{
struct bus_type *bus = dev->bus;//取得device所依附的bus
struct subsys_interface *sif;

if (!bus)
return;

if (bus->p->drivers_autoprobe) // 如果bus->p->drivers_autoprobe值为1,调用device_initial_probe函数
device_initial_probe(dev);

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);
}


其中调用
device_initial_probe
函数,该函数定义在drivers/base/dd.c文件中,其内容如下:

void device_initial_probe(struct device *dev)
{
__device_attach(dev, true);
}


device_initial_probe
函数继续调用
__device_attach
,该函数定义在drivers/base/dd.c文件中,其内容如下:

static int __device_attach(struct device *dev, bool allow_async)
{
int ret = 0;

device_lock(dev);
if (dev->driver) {    // dev->driver不为空, 使用device_bind_driver
if (device_is_bound(dev)) {
ret = 1;
goto out_unlock;
}
ret = device_bind_driver(dev);
if (ret == 0)
ret = 1;
else {
dev->driver = NULL;
ret = 0;
}
} else {
struct device_attach_data data = {
.dev = dev,
.check_async = allow_async,
.want_async = false,
};

if (dev->parent)
pm_runtime_get_sync(dev->parent);

ret = bus_for_each_drv(dev->bus, NULL, &data,
__device_attach_driver);
if (!ret && allow_async && data.have_async) {
/*
* If we could not find appropriate driver
* synchronously and we are allowed to do
* async probes and there are drivers that
* want to probe asynchronously, we'll
* try them.
*/
dev_dbg(dev, "scheduling asynchronous probe\n");
get_device(dev);
async_schedule(__device_attach_async_helper, dev);
} else {
pm_request_idle(dev);
}

if (dev->parent)
pm_runtime_put(dev->parent);
}
out_unlock:
device_unlock(dev);
return ret;
}


可以看到如果
dev->driver
不为空,表明device已经与相应的
device_driver
进行了绑定,这种情况下只需要调用
device_bind_driver
函数在sysfs文件系统中建立device与其
device_driver
的相互关联 。

__device_attach
中调用了
bus_for_each_drv
, 该函数定义在drivers/base/bus.c文件中,其内容如下:

/**
* bus_for_each_drv - driver iterator
* @bus: bus we're dealing with.
* @start: driver to start iterating on.
* @data: data to pass to the callback.
* @fn: function to call for each driver.
*
* This is nearly identical to the device iterator above.
* We iterate over each driver that belongs to @bus, and call
* @fn for each. If @fn returns anything but 0, we break out
* and return it. If @start is not NULL, we use it as the head
* of the list.
*
* NOTE: we don't return the driver that returns a non-zero
* value, nor do we leave the reference count incremented for that
* driver. If the caller needs to know that info, it must set it
* in the callback. It must also be sure to increment the refcount
* so it doesn't disappear before returning to the caller.
*/
int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,
void *data, int (*fn)(struct device_driver *, void *))
{
struct klist_iter i;
struct device_driver *drv;
int error = 0;

if (!bus)
return -EINVAL;

klist_iter_init_node(&bus->p->klist_drivers, &i,
start ? &start->p->knode_bus : NULL);
while ((drv = next_driver(&i)) && !error)  //循环依次遍历bus->p->klist_drivers中的所有device_driver
error = fn(drv, data);
klist_iter_exit(&i);
return error;
}


可以看到while循环依次遍历
bus->p->klist_drivers
中的所有
device_driver
,对于每个
device_driver
,调用
fn(drv, data)
函数,看该
device_driver
是否支持该device。如果匹配成功,fn函数返回非0值。

参数传递过来的fn函数是
__device_attach_driver
,该函数定义在drivers/base/dd.c文件中,其内容如下:

static int __device_attach_driver(struct device_driver *drv, void *_data)
{
struct device_attach_data *data = _data;
struct device *dev = data->dev;
bool async_allowed;
int ret;

/*
* Check if device has already been claimed. This may
* happen with driver loading, device discovery/registration,
* and deferred probe processing happens all at once with
* multiple threads.
*/
if (dev->driver)
return -EBUSY;

ret = driver_match_device(drv, dev); //检查device_driver是否支持该device
if (ret == 0) {
/* no match */
return 0;
} else if (ret == -EPROBE_DEFER) {
dev_dbg(dev, "Device match requests probe deferral\n");
driver_deferred_probe_add(dev);
} else if (ret < 0) {
dev_dbg(dev, "Bus failed to match device: %d", ret);
return ret;
} /* ret > 0 means positive match */

async_allowed = driver_allows_async_probing(drv);

if (async_allowed)
data->have_async = true;

if (data->check_async && async_allowed != data->want_async)
return 0;

return driver_probe_device(drv, dev);
}


其中调用
driver_match_device(drv, dev)
函数,检查
device_drive
r是否支持该device,该函数定义在drivers/base/base.h文件中,其内容如下:

static inline int driver_match_device(struct device_driver *drv,
struct device *dev)
{
//如果定义了drv->bus->match函数,则调用该函数,否则返回1。
return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}


__device_attach_driver
函数最后还调用了
driver_probe_device
, 该函数定义在drivers/base/dd.c文件中,其内容如下:

/**
* driver_probe_device - attempt to bind device & driver together
* @drv: driver to bind a device to
* @dev: device to try to bind to the driver
*
* This function returns -ENODEV if the device is not registered,
* 1 if the device is bound successfully and 0 otherwise.
*
* This function must be called with @dev lock held.  When called for a
* USB interface, @dev->parent lock must be held as well.
*
* If the device has a parent, runtime-resume the parent before driver probing.
*/
int driver_probe_device(struct device_driver *drv, struct device *dev)
{
int ret = 0;

if (!device_is_registered(dev))
return -ENODEV;

pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
drv->bus->name, __func__, dev_name(dev), drv->name);

if (dev->parent)
pm_runtime_get_sync(dev->parent);

pm_runtime_barrier(dev);
ret = really_probe(dev, drv);
pm_request_idle(dev);

if (dev->parent)
pm_runtime_put(dev->parent);

return ret;
}


其中调用
device_is_registered
函数判断device是否已经在sysfs系统中注册过,如果还没有注册过,则返回ENODEV,退出。该函数定义在include/linux/device.h文件中,其内容如下:

static inline int device_is_registered(struct device *dev)
{
return dev->kobj.state_in_sysfs;
}


调用
really_probe(dev, drv)
函数,该函数定义在drivers/base/dd.c文件中,其内容如下:

static int really_probe(struct device *dev, struct device_driver *drv)
{
int ret = -EPROBE_DEFER;
int local_trigger_count = atomic_read(&deferred_trigger_count);

if (defer_all_probes) {
/*
* Value of defer_all_probes can be set only by
* device_defer_all_probes_enable() which, in turn, will call
* wait_for_device_probe() right after that to avoid any races.
*/
dev_dbg(dev, "Driver %s force probe deferral\n", drv->name);
driver_deferred_probe_add(dev);
return ret;
}

atomic_inc(&probe_count);
pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
drv->bus->name, __func__, drv->name, dev_name(dev));
WARN_ON(!list_empty(&dev->devres_head));

dev->driver = drv;

/* If using pinctrl, bind pins now before probing */
ret = pinctrl_bind_pins(dev);
if (ret)
goto pinctrl_bind_failed;

if (driver_sysfs_add(dev)) {
printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
__func__, dev_name(dev));
goto probe_failed;
}

if (dev->pm_domain && dev->pm_domain->activate) {
ret = dev->pm_domain->activate(dev);
if (ret)
goto probe_failed;
}

/*
* Ensure devices are listed in devices_kset in correct order
* It's important to move Dev to the end of devices_kset before
* calling .probe, because it could be recursive and parent Dev
* should always go first
*/
devices_kset_move_last(dev);

if (dev->bus->probe) {
ret = dev->bus->probe(dev);
if (ret)
goto probe_failed;
} else if (drv->probe) {
ret = drv->probe(dev);
if (ret)
goto probe_failed;
}

pinctrl_init_done(dev);

if (dev->pm_domain && dev->pm_domain->sync)
dev->pm_domain->sync(dev);

driver_bound(dev);
ret = 1;
pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
drv->bus->name, __func__, dev_name(dev), drv->name);
goto done;

probe_failed:
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_DRIVER_NOT_BOUND, dev);
pinctrl_bind_failed:
devres_release_all(dev);
driver_sysfs_remove(dev);
dev->driver = NULL;
dev_set_drvdata(dev, NULL);
if (dev->pm_domain && dev->pm_domain->dismiss)
dev->pm_domain->dismiss(dev);
pm_runtime_reinit(dev);

switch (ret) {
case -EPROBE_DEFER:
/* Driver requested deferred probing */
dev_dbg(dev, "Driver %s requests probe deferral\n", drv->name);
driver_deferred_probe_add(dev);
/* Did a trigger occur while probing? Need to re-trigger if yes */
if (local_trigger_count != atomic_read(&deferred_trigger_count))
driver_deferred_probe_trigger();
break;
case -ENODEV:
case -ENXIO:
pr_debug("%s: probe of %s rejects match %d\n",
drv->name, dev_name(dev), ret);
break;
default:
/* driver matched but the probe failed */
printk(KERN_WARNING
"%s: probe of %s failed with error %d\n",
drv->name, dev_name(dev), ret);
}
/*
* Ignore errors returned by ->probe so that the next driver can try
* its luck.
*/
ret = 0;
done:
atomic_dec(&probe_count);
wake_up(&probe_waitqueue);
return ret;
}


可以看到如果定义了
dev->bus->probe
函数,则调用该函数;如果没有定义
dev->bus->probe
函数,但是定义了
drv->probe
函数,则调用
drv->probe
函数。这里,我们一般写Linux驱动程序时都要实现的probe函数就会被调用了。

really_probe
中还调用
driver_bound(dev)
函数,该函数定义在drivers/base/dd.c文件中,其内容如下:

static void driver_bound(struct device *dev)
{
if (device_is_bound(dev)) {
printk(KERN_WARNING "%s: device %s already bound\n",
__func__, kobject_name(&dev->kobj));
return;
}

pr_debug("driver: '%s': %s: bound to device '%s'\n", dev->driver->name,
__func__, dev_name(dev));

klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);

device_pm_check_callbacks(dev);

/*
* Make sure the device is no longer in one of the deferred lists and
* kick off retrying all pending devices
*/
driver_deferred_probe_del(dev);
driver_deferred_probe_trigger();

if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_BOUND_DRIVER, dev);
}


可以看到调用
klist_add_tail
函数将device加入到
device_driver
driver->p->klist_devices
链表中。

将以上device的注册过程倒序捋顺:

driver_bound
->
really_probe
->
driver_probe_device
->
__device_attach_driver
->
bus_for_each_drv
->
__device_attach
->
device_initial_probe
->
bus_probe_device
->
device_add
->
device_register


这样,
device_register
函数就分析完了,也就清楚了device的注册过程。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息