设备驱动模型-device、driver、bus (1/2)

旧时模样 提交于 2020-01-29 01:49:52

目录

一. 总线(bus)、设备(device)、驱动(driver)模型

​1.1 简介

1.2工作流程

二. bus

2.1 简介

2.2实例--platform总线

2.2.1 platform总线建立流程

2.2.2 相关函数讲解

三. device

3.1 简介

3.2 实例---platform_bus 虚拟平台设备

3.2.1 流程

3.2.2 接口函数

四. driver

4.1 简介

4.2 实例


 

内核版本:3.18.20
博客:https://blog.csdn.net/yj4231/article/details/7799245
       https://blog.csdn.net/adc0809608/article/details/7254684

一. 总线(bus)、设备(device)、驱动(driver)模型


1.1 简介

     大多数情况下, Linux内核中的设备模型代码会作为“幕后黑手” 处理好这些关系,内核中的总线和其他内核子系统会完成与设备模型的交互,这使得驱动工程师几乎不需要关心设备模型,只需要按照每个框架的要求,“填鸭式”地填充xxx_driver里面的各种回调函数(xxx是总线的名称)在 Linux 内核中,分别使用 bus_type、 device_driver 和 device 来描述总线、驱动和设备。

1.2工作流程

    device_driver和device分别表示驱动和设备,而这两者都必须依附于一种总线,因此都包含struct bus_type指针。在linux内核中,设备和驱动是分开注册的,注册1个设备的时候,并不需要驱动已经存在,而1个驱动被注册的时候,也不需要对应的设备已经被注册。设备和驱动各自涌向内核,而每个设备和驱动涌向内核的时候,都会去寻找自己的另一半,而正是bus_type的match()成员函数将两者捆绑在一起。
    简单地说,设备和驱动就是红尘中漂浮的男女,而bus_type的match()则是牵引红线的月老,它可以识别什么设备与什么驱动是可配对的。一旦配对成功,xxx_driver的probe()就被执行。(xxx是总线名,如platform、pci、i2c、spi、usb等)
    注:总线、驱动和设备最终都会落实为sysfs中的一个目录,因为进一步追踪代码会发现,他们实际上都可以认为是kobject的派生类,kobject可看作是所有总线、设备和驱动的抽象基类,一个kobject对应sysfs中的一个目录。


二. bus

2.1 简介

    总线是处理器与一个设备或者多个设备之间的通道。在设备模型中,所有的设备都挂载在某一个总线上。
内核表示:
 

/*路径:include/linux/device.h*/

/**
 * struct bus_type - The bus type of the device
 *
 * @name:    The name of the bus.
 * @dev_name:    Used for subsystems to enumerate devices like ("foo%u", dev->id).
 * @dev_root:    Default device to use as the parent.
 * @dev_attrs:    Default attributes of the devices on the bus.
 * @bus_groups:    Default attributes of the bus.
 * @dev_groups:    Default attributes of the devices on the bus.
 * @drv_groups: Default attributes of the device drivers on the bus.
 * @match:    Called, perhaps multiple times, whenever a new device or driver
 *        is added for this bus. It should return a nonzero value if the
 *        given device can be handled by the given driver.
 * @uevent:    Called when a device is added, removed, or a few other things
 *        that generate uevents to add the environment variables.
 * @probe:    Called when a new device or driver add to this bus, and callback
 *        the specific driver's probe to initial the matched device.
 * @remove:    Called when a device removed from this bus.
 * @shutdown:    Called at shut-down time to quiesce the device.
 *
 * @online:    Called to put the device back online (after offlining it).
 * @offline:    Called to put the device offline for hot-removal. May fail.
 *
 * @suspend:    Called when a device on this bus wants to go to sleep mode.
 * @resume:    Called to bring a device on this bus out of sleep mode.
 * @pm:        Power management operations of this bus, callback the specific
 *        device driver's pm-ops.
 * @iommu_ops:  IOMMU specific operations for this bus, used to attach IOMMU
 *              driver implementations to a bus and allow the driver to do
 *              bus-specific setup
 * @p:        The private data of the driver core, only the driver core can
 *        touch this.
 * @lock_key:    Lock class key for use by the lock validator
 *
 * A bus is a channel between the processor and one or more devices. For the
 * purposes of the device model, all devices are connected via a bus, even if
 * it is an internal, virtual, "platform" bus. Buses can plug into each other.
 * A USB controller is usually a PCI device, for example. The device model
 * represents the actual connections between buses and the devices they control.
 * A bus is represented by the bus_type structure. It contains the name, the
 * default attributes, the bus' methods, PM operations, and the driver core's
 * private data.
 */
struct bus_type {
    const char        *name;
    const char        *dev_name;
    struct device        *dev_root;
    struct device_attribute    *dev_attrs;    /* use dev_groups instead */
    const struct attribute_group **bus_groups;
    const struct attribute_group **dev_groups;
    const struct attribute_group **drv_groups;

    int (*match)(struct device *dev, struct device_driver *drv);
    int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
    int (*probe)(struct device *dev);
    int (*remove)(struct device *dev);
    void (*shutdown)(struct device *dev);

    int (*online)(struct device *dev);
    int (*offline)(struct device *dev);

    int (*suspend)(struct device *dev, pm_message_t state);
    int (*resume)(struct device *dev);

    const struct dev_pm_ops *pm;

    const struct iommu_ops *iommu_ops;

    struct subsys_private *p;
    struct lock_class_key lock_key;
};


/**
 * struct subsys_private - structure to hold the private to the driver core portions of the bus_type/class structure.
 *
 * @subsys - the struct kset that defines this subsystem
 * @devices_kset - the subsystem's 'devices' directory
 * @interfaces - list of subsystem interfaces associated
 * @mutex - protect the devices, and interfaces lists.
 *
 * @drivers_kset - the list of drivers associated
 * @klist_devices - the klist to iterate over the @devices_kset
 * @klist_drivers - the klist to iterate over the @drivers_kset
 * @bus_notifier - the bus notifier list for anything that cares about things
 *                 on this bus.
 * @bus - pointer back to the struct bus_type that this structure is associated
 *        with.
 *
 * @glue_dirs - "glue" directory to put in-between the parent device to
 *              avoid namespace conflicts
 * @class - pointer back to the struct class that this structure is associated
 *          with.
 *
 * This structure is the one that is the actual kobject allowing struct
 * bus_type/class to be statically allocated safely.  Nothing outside of the
 * driver core should ever touch these fields.
 */
struct subsys_private {
    struct kset subsys;
    struct kset *devices_kset;
    struct list_head interfaces;
    struct mutex mutex;

    struct kset *drivers_kset;
    struct klist klist_devices;
    struct klist klist_drivers;
    struct blocking_notifier_head bus_notifier;
    unsigned int drivers_autoprobe:1;
    struct bus_type *bus;

    struct kset glue_dirs;
    struct class *class;
};

/*可得:
 - 每个bus_type都包含一个kset对象subsys,该kset在/sys/bus/目录下有着对应的一个目录,目录名即为字段name。
 - drivers_kset和devices_kset对应着两个目录,该两个目录下将包含该总线上的设备和相应的驱动程序。
 - 总线上的设备和驱动将分别保存在两个链表中:klist_devices和klist_drivers。
*/

2.2实例--platform总线

2.2.1 platform总线建立流程

    platform总线的注册是由platform_bus_init函数完成的。该函数在内核启动阶段被调用,我们来简单看下调用过程:   

 - 调用流程:

start_kernel() /*路径:/init/main.c*/
    rest_init()
        kernel_thread(kernel_init, NULL, CLONE_FS)  /*即调用kernel_init() */
            kernel_init_freeable()
                do_basic_setup()
                    driver_init()   /*路径:drivers/base/init.c*/
                        platform_bus_init() /*路径:drivers/base/platform.c*/

注:kernel_init()是在rest_init函数中创建内核线程来执行的。

2.2.2 相关函数讲解

/*1.platform_bus_init()*/
struct bus_type platform_bus_type = {
    .name        = "platform",
    .dev_groups    = platform_dev_groups,
    .match        = platform_match,
    .uevent        = platform_uevent,
    .pm        = &platform_dev_pm_ops,
};
EXPORT_SYMBOL_GPL(platform_bus_type);

int __init platform_bus_init(void)
{
    int error;

    early_platform_cleanup();

    error = device_register(&platform_bus);
    if (error)
        return error;
    error =  bus_register(&platform_bus_type);
    if (error)
        device_unregister(&platform_bus);
    return error;
}


/*2.bus_register()*/
/**
 * bus_register - register a driver-core subsystem
 * @bus: bus to register
 *
 * Once we have that, we register the bus with the kobject
 * infrastructure, then register the children subsystems it has:
 * the devices and drivers that belong to the subsystem.
 */
int bus_register(struct bus_type *bus)
{
    int retval;
    struct subsys_private *priv;
    struct lock_class_key *key = &bus->lock_key;

    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);
    
    /*设置bus set的名字,即kobject->name*/
    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;
    
    /*注册kset,即在sysfs的bus目录下,建立子目录xxx (xxx:为bus->name)*/
    retval = kset_register(&priv->subsys);
    if (retval)
        goto out;
    
    /*创建属性文件,即bus/xxx/文件uevent*/
    retval = bus_create_file(bus, &bus_attr_uevent);
    if (retval)
        goto bus_uevent_fail;
    
    /*创建devices kset,在bus/xxx/目录devices*/
    priv->devices_kset = kset_create_and_add("devices", NULL,
                         &priv->subsys.kobj);
    if (!priv->devices_kset) {
        retval = -ENOMEM;
        goto bus_devices_fail;
    }
    
    /*创建drivers kset,在bus/xxx/目录drivers*/
    priv->drivers_kset = kset_create_and_add("drivers", NULL,
                         &priv->subsys.kobj);
    if (!priv->drivers_kset) {
        retval = -ENOMEM;
        goto bus_drivers_fail;
    }
    
    INIT_LIST_HEAD(&priv->interfaces);
    __mutex_init(&priv->mutex, "subsys mutex", key);

     /*初始化2个内核链表*/
    klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
    klist_init(&priv->klist_drivers, NULL, NULL);
    
    /*创建属性文件,即bus/xxx/建立文件drivers_autoprobe和drivers_probe*/
    retval = add_probe_files(bus);
    if (retval)
        goto bus_probe_files_fail;
    
     /*根据bus->bus_attribute创建属性,在bus/xxx/下建立相应的文件*/
    retval = bus_add_groups(bus, bus->bus_groups);
    if (retval)
        goto bus_groups_fail;

    pr_debug("bus: '%s': registered\n", bus->name);
    return 0;

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


三. device

3.1 简介

    设备在内核中表示:
 

/*路径:include/linux/device.h*/
/**
 * 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 some sort 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 of the driver core portions of the device.
 *         See the comment of the struct device_private for detail.
 * @kobj:    A top-level, abstract class from which other classes are derived.
 * @init_name:    Initial name of the device.
 * @type:    The type of device.
 *         This identifies the device type and carries type-specific
 *         information.
 * @mutex:    Mutex to synchronize calls to its driver.
 * @bus:    Type of bus device is on.
 * @driver:    Which driver has allocated this
 * @platform_data: Platform data specific to the device.
 *         Example: For devices on custom boards, as typical of embedded
 *         and SOC based hardware, Linux often uses platform_data to point
 *         to board-specific structures describing devices and how they
 *         are wired.  That can include what ports are available, chip
 *         variants, which GPIO pins act in what additional roles, and so
 *         on.  This shrinks the "Board Support Packages" (BSPs) and
 *         minimizes board-specific #ifdefs in drivers.
 * @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.
 * @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.
 * @acpi_node:    Associated ACPI device 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 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;
    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_PINCTRL
    struct dev_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, 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
    struct removed_region *removed_mem;
    /* arch specific additions */
    struct dev_archdata    archdata;

    struct device_node    *of_node; /* associated device tree node */
    struct acpi_dev_node    acpi_node; /* associated ACPI 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;
    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;
};

/**
 * 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 class 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;
    struct klist_node knode_driver;
    struct klist_node knode_bus;
    struct list_head deferred_probe;
    struct device *device;
};

/*可得:
1. device本身包含一个kobject,也就是说这个device在sysfs的某个地方有着一个对应的目录。
2. 该device所挂载的bus由knode_bus指定。
3. 该device所对应的设备驱动由knode_driver指定。
*/

3.2 实例---platform_bus 虚拟平台设备

3.2.1 流程

platform_bus_init()   /*路径:drivers/base/platform.c*/
    device_register() /*路径:drivers/base/core.c*/

3.2.2 接口函数

/*1. platform_bus_init() 路径:drivers/base/platform.c*/

struct device platform_bus = {
    .init_name    = "platform",
};
EXPORT_SYMBOL_GPL(platform_bus);

int __init platform_bus_init(void)
{
    int error;

    early_platform_cleanup();

    error = device_register(&platform_bus);
    if (error)
        return error;
    error =  bus_register(&platform_bus_type);
    if (error)
        device_unregister(&platform_bus);
    return error;
}


/*2. 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);   /*初始化dev的某些字段*/
    return device_add(dev);   /*将设备添加到系统中*/
}
EXPORT_SYMBOL_GPL(device_register);



/*设备的注册都分为两步:

 1. 设备的初始化
 2. 添加到内核中
*/

/*3.设备初始化相关接口*/


/*3.1 初始化*/
/**
 * 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.
 *
 * 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;           /*设置kobj属于哪个kset。实际为:/sys/devices/ */  

    /*该函数在做了一系列的必要检查后,调用kobject_init_internal初始化了kobject的某些字段。*/
    kobject_init(&dev->kobj, &device_ktype); /*初始化dev->kobj */  
    
    INIT_LIST_HEAD(&dev->dma_pools);         /*初始化链表头*/  
    init_MUTEX(&dev->sem);                   /*初始化互斥体*/  
    spin_lock_init(&dev->devres_lock);       /*初始化自旋锁*/  
    INIT_LIST_HEAD(&dev->devres_head);       /*初始化链表头*/  

    /*设置电源的状态*/
    device_pm_init(dev);                     /*设置该device可操作*/  

    /*如果使用NUMA,则设置NUMA节点*/
    set_dev_node(dev, -1);                   /*设置NUMA节点*/  
}  

/*3.2 device_initialize()中所用的devices_kset 容器的创建*/
int __init devices_init(void)
{
    devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
    if (!devices_kset)
        return -ENOMEM;
    dev_kobj = kobject_create_and_add("dev", NULL);
    if (!dev_kobj)
        goto dev_kobj_err;
    sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
    if (!sysfs_dev_block_kobj)
        goto block_kobj_err;
    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;
}

/*
即:devices_kset对象表示的目录为/sys下的devices目录。
*/



/**4.设备添加相关接口**/

/**
 * 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);  /*增加引用计数*/
    if (!dev)
        goto done;

    if (!dev->p) {
        error = device_private_init(dev);  /*初始化device_private结构*/
        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->kobject->name = dev->init_name*/
        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);
    
     /*检查dev->kobject->name*/
    if (!dev_name(dev)) {
        error = -EINVAL;
        goto name_error;
    }

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

    parent = get_device(dev->parent);  /*增加父设备引用计数*/
    kobj = get_device_parent(dev, parent);    /*设置dev->kobject->parent*/
    if (kobj)
        dev->kobj.parent = kobj;

    /* 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 */
    /* 执行完以后,将在/sys/devices/下建立目录XXX,目录名XXX为dev->kobj->name*/
    error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
    if (error)
        goto Error;

    /* notify platform of device entry */
    if (platform_notify)
        platform_notify(dev);
    
     /*在XXX下建立文件uevent*/
    error = device_create_file(dev, &dev_attr_uevent);
    if (error)
        goto attrError;

    if (MAJOR(dev->devt)) {
        /*创建属性文件dev*/  
        error = device_create_file(dev, &dev_attr_dev);
        if (error)
            goto ueventattrError;
        
        /* 在sys/dev/char/下建立symlink,名字为主设备号:次设备号,该链接指向XXX */
        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;

    /*添加3个symlink*/
    error = bus_add_device(dev);    
    if (error)
        goto BusError;
        
     /*创建power子目录,并在其下添加电源管理的属性组文件*/
    error = dpm_sysfs_add(dev);
    if (error)
        goto DPMError;
    if ((dev->pm_domain) || (dev->type && dev->type->pm)
        || (dev->class && (dev->class->pm || dev->class->resume))
        || (dev->bus && (dev->bus->pm || dev->bus->resume)) ||
        (dev->driver && dev->driver->pm)) {
        device_pm_add(dev); /*将该device添加到电源管理链表中*/
    }


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

    /*有父设备,则将该设备添加到父设备的儿子链表中*/
    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 */
        /*将device添加到class的类设备链表中*/
        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;
 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, &dev_attr_dev);
 ueventattrError:
    device_remove_file(dev, &dev_attr_uevent);
 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;
    goto done;
}
EXPORT_SYMBOL_GPL(device_add);


结论:
当device_register调用完成以后,将在/sys/devices/下建立目录platform,并在platfrom下建立属性文件uevent和子目录power,最后在power子目录下建立wakeup属性文件。


四. driver

4.1 简介

  驱动在内核中表示:
 

/**
 * struct device_driver - The basic device driver structure
 * @name:    Name of the device driver.
 * @bus:    The bus which the device of this driver belongs to.
 * @owner:    The module owner.
 * @mod_name:    Used for built-in modules.
 * @suppress_bind_attrs: Disables bind/unbind via sysfs.
 * @of_match_table: The open firmware table.
 * @acpi_match_table: The ACPI match table.
 * @probe:    Called to query the existence of a specific device,
 *        whether this driver can work with it, and bind the driver
 *        to a specific device.
 * @remove:    Called when the device is removed from the system to
 *        unbind a device from this driver.
 * @shutdown:    Called at shut-down time to quiesce the device.
 * @suspend:    Called to put the device to sleep mode. Usually to a
 *        low power state.
 * @resume:    Called to bring a device from sleep mode.
 * @groups:    Default attributes that get created by the driver core
 *        automatically.
 * @pm:        Power management operations of the device which matched
 *        this driver.
 * @p:        Driver core's private data, no one other than the driver
 *        core can touch this.
 *
 * The device driver-model tracks all of the drivers known to the system.
 * The main reason for this tracking is to enable the driver core to match
 * up drivers with new devices. Once drivers are known objects within the
 * system, however, a number of other things become possible. Device drivers
 * can export information and configuration variables that are independent
 * of any specific device.
 */
struct device_driver {
    const char        *name;
    struct bus_type        *bus;

    struct module        *owner;
    const char        *mod_name;    /* used for built-in modules */

    bool suppress_bind_attrs;    /* disables bind/unbind via sysfs */

    const struct of_device_id    *of_match_table;
    const struct acpi_device_id    *acpi_match_table;

    int (*probe) (struct device *dev);
    int (*remove) (struct device *dev);
    void (*shutdown) (struct device *dev);
    int (*suspend) (struct device *dev, pm_message_t state);
    int (*resume) (struct device *dev);
    const struct attribute_group **groups;

    const struct dev_pm_ops *pm;

    struct driver_private *p;
};

struct driver_private {
    struct kobject kobj;
    struct klist klist_devices;
    struct klist_node knode_bus;
    struct module_kobject *mkobj;
    struct device_driver *driver;
};

/*可得:
1. device_driver本身包含一个kobject,也就是说这个device_driver在sysfs的某个地方有着一个对应的目录。
2. 该设备驱动所支持的设备由klist_devices指定。
3. 该设备驱动所挂载的总线由knode_bus制定
*/

4.2 实例

/*1.驱动注册*/
/**
 * platform_driver_probe - register driver for non-hotpluggable device
 * @drv: platform driver structure
 * @probe: the driver probe routine, probably from an __init section
 *
 * Use this instead of platform_driver_register() when you know the device
 * is not hotpluggable and has already been registered, and you want to
 * remove its run-once probe() infrastructure from memory after the driver
 * has bound to the device.
 *
 * One typical use for this would be with drivers for controllers integrated
 * into system-on-chip processors, where the controller devices have been
 * configured as part of board setup.
 *
 * Note that this is incompatible with deferred probing.
 *
 * Returns zero if the driver registered and bound to a device, else returns
 * a negative error code and with the driver not registered.
 */
int __init_or_module platform_driver_probe(struct platform_driver *drv,
        int (*probe)(struct platform_device *))
{
    int retval, code;

    /*
     * Prevent driver from requesting probe deferral to avoid further
     * futile probe attempts.
     */
    drv->prevent_deferred_probe = true;

    /* make sure driver won't have bind/unbind attributes */
    drv->driver.suppress_bind_attrs = true;

    /* temporary section violation during probe() */
    drv->probe = probe;

    /*注册platform驱动*/
    retval = code = platform_driver_register(drv);

    /*
     * Fixup that section violation, being paranoid about code scanning
     * the list of drivers in order to probe new devices.  Check to see
     * if the probe was successful, and make sure any forced probes of
     * new devices fail.
     */
    spin_lock(&drv->driver.bus->p->klist_drivers.k_lock);
    drv->probe = NULL;
    if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list))
        retval = -ENODEV;
    drv->driver.probe = platform_drv_probe_fail;
    spin_unlock(&drv->driver.bus->p->klist_drivers.k_lock);

    if (code != retval)
        platform_driver_unregister(drv);
    return retval;
}
EXPORT_SYMBOL_GPL(platform_driver_probe);


/*2. 注册*/
/**
 * __platform_driver_register - register a driver for platform-level devices
 * @drv: platform driver structure
 * @owner: owning module/driver
 */
int __platform_driver_register(struct platform_driver *drv,
                struct module *owner)
{
    drv->driver.owner = owner;
    drv->driver.bus = &platform_bus_type;
    if (drv->probe)
        drv->driver.probe = platform_drv_probe;
    if (drv->remove)
        drv->driver.remove = platform_drv_remove;
    if (drv->shutdown)
        drv->driver.shutdown = platform_drv_shutdown;

    return driver_register(&drv->driver);
}
EXPORT_SYMBOL_GPL(__platform_driver_register);

#define platform_driver_register(drv) \
    __platform_driver_register(drv, THIS_MODULE)

/*注:
driver_register函数就是driver注册的核心函数。需要注意的是,在调用函数之前,
将该驱动所挂载的总线设置为platform总线(platform_bus_type)。
*/

/*3.驱动注册*/
/**
 * driver_register - register driver with bus
 * @drv: driver to register
 *
 * We pass off most of the work to the bus_add_driver() call,
 * since most of the things we have to do deal with the bus
 * structures.
 */
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) {
        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;
    }
    kobject_uevent(&drv->p->kobj, KOBJ_ADD);

    return ret;
}
EXPORT_SYMBOL_GPL(driver_register);


/*4. 将驱动加入到bus中*/
/**
 * bus_add_driver - Add a driver to the bus.
 * @drv: driver.
 */
int bus_add_driver(struct device_driver *drv)
{
    struct bus_type *bus;
    struct driver_private *priv;
    int error = 0;
    
    /*增加引用计数获取bus_type*/
    bus = bus_get(drv->bus);
    if (!bus)
        return -EINVAL;

    pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);

     /*分配driver_private结构体*/
    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;

    /*设置该kobj属于那个kset*/
    priv->kobj.kset = bus->p->drivers_kset;

    /*parent=NULL*/
     /*执行完以后,会在bus/总线名/drivers/下建立名为drv->name的目录*/
    error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
                     "%s", drv->name);
    if (error)
        goto out_unregister;
    
     /*添加该驱动到bus的内核链表中*/
    klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
    if (drv->bus->p->drivers_autoprobe) {
         /*尝试绑定驱动和设备*/
        error = driver_attach(drv);
        if (error)
            goto out_unregister;
    }
    module_add_driver(drv->owner, drv);

     /*创建属性,在bus/总线名/drivers/驱动名/下建立文件uevent*/
    error = driver_create_file(drv, &driver_attr_uevent);
    if (error) {
        printk(KERN_ERR "%s: uevent attr (%s) failed\n",
            __func__, drv->name);
    }

     /*利用bus->drv_groups创建属性,位于bus/总线名/drivers/驱动名/*/
    error = driver_add_groups(drv, bus->drv_groups);
    if (error) {
        /* How the hell do we get out of this pickle? Give up */
        printk(KERN_ERR "%s: driver_create_groups(%s) failed\n",
            __func__, drv->name);
    }

     /*创建属性,在bus/总线名/drivers/驱动名/下建立文件bind和unbind*/
    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);
        }
    }

    return 0;

out_unregister:
    kobject_put(&priv->kobj);
    kfree(drv->p);
    drv->p = NULL;
out_put_bus:
    bus_put(bus);
    return error;
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!