设备

linux系统中,每个设备都用device结构的一个实例来表示,
 
1. device定义如下:
    struct device {
        struct device        *parent;   //父设备,指该设备所属的设备。
        struct device_private    *p;  //私有数据
        struct kobject kobj;          //表示该设备是哪类设备,并把它连接到体系中的kobject。
        const char        *init_name; /* initial name of the device */
        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 */
        struct dev_pm_info    power;
    #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. */
        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 */
        /* arch specific additions */
        struct dev_archdata    archdata;
    #ifdef CONFIG_OF
        struct device_node    *of_node;
    #endif
        dev_t            devt;    /* dev_t, creates the sysfs "dev" */
        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);  //该设备被删除时调用
    };



2. 设备注册和注销,device_register()/ device_unregister():

    /**
     * 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.
     *
     * 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);
        return device_add(dev);   //其实调用了device_add()
    }

    /**
     * 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.
     *
     * 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 class_interface *class_intf;
        int error = -EINVAL;
        dev = get_device(dev);
        if (!dev)
            goto done;
        if (!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()
         */
        if (dev->init_name) {
            dev_set_name(dev, "%s", dev->init_name);
            dev->init_name = NULL;
        }
        if (!dev_name(dev)) {
            error = -EINVAL;
            goto name_error;
        }
        pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
        parent = get_device(dev->parent);
        setup_parent(dev, parent);
        /* 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);
        if (error)
            goto Error;
        /* notify platform of device entry */
        if (platform_notify)
            platform_notify(dev);
        error = device_create_file(dev, &uevent_attr);    //添加uevent属性。
        if (error)
            goto attrError;
        if (MAJOR(dev->devt)) {
            error = device_create_file(dev, &devt_attr);   //添加设备属性
            if (error)
                goto ueventattrError;
            error = device_create_sys_dev_entry(dev);    //添加sys下设备名
            if (error)
                goto devtattrError;
            devtmpfs_create_node(dev);
        }
        error = device_add_class_symlinks(dev);     //添加class链接
        if (error)
            goto SymlinkError;
        error = device_add_attrs(dev);            //添加device属性
        if (error)
            goto AttrsError;
        error = bus_add_device(dev);            //添加bus属性
        if (error)
            goto BusError;
        error = dpm_sysfs_add(dev);             //添加dpm, pm相关吧
        if (error)
            goto DPMError;
        device_pm_add(dev);
        /* Notify clients of device addition. This call must come
         * after dpm_sysf_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->class_mutex);
            /* tie the class to the device */
            klist_add_tail(&dev->knode_class,
                 &dev->class->p->class_devices);
            /* notify any interfaces that the device is here */
            list_for_each_entry(class_intf,
                     &dev->class->p->class_interfaces, node)
                if (class_intf->add_dev)
                    class_intf->add_dev(dev, class_intf);
            mutex_unlock(&dev->class->p->class_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, &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;
        goto done;
    }


    /**
     * device_unregister - unregister device from system.
     * @dev: device going away.
     *
     * We do this in two parts, like we do device_register(). First,
     * we remove it from all the subsystems with device_del(), then
     * we decrement the reference count via put_device(). If that
     * is the final reference count, the device will be cleaned up
     * via device_release() above. Otherwise, the structure will
     * stick around until the final reference to the device is dropped.
     */
    void device_unregister(struct device *dev)
    {
        pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
        device_del(dev);
        put_device(dev);
    }

3. 设备属性:

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

a. 可以用DEVICE_ATTR宏 来构造device_attribute结构:

    #define DEVICE_ATTR(_name, _mode, _show, _store) \
    struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)

b. 下面两个函数用来处理属性文件,device_create_file() / device_remove_file():

    /**
     * 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)
            error = sysfs_create_file(&dev->kobj, &attr->attr);
        return error;
    }
    /**
     * device_remove_file - remove sysfs attribute file.
     * @dev: device.
     * @attr: device attribute descriptor.
     */
    void device_remove_file(struct device *dev,
                const struct device_attribute *attr)
    {
        if (dev)
            sysfs_remove_file(&dev->kobj, &attr->attr);
    }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值