linux设备驱动模型 - device/bus/driver
在linux驅動模型中,為了便于管理各種設備,我們把不同設備分別掛在他們對應的總線上,設備對應的驅動程序也在總線上找,這樣就提出了deivce-bus-driver的模型,硬件上有許多設備總線,那么我們就在設備模型上抽象出bus概念,相應的device就代表設備,driver表示驅動,在代碼中它們對應的結構體下面介紹,對于實際的設備及總線,這些結構體就可以嵌入到實際總線上。
1. bus
了解bus,就要先介紹下bus的結構體,一條總線定義完后要注冊到系統中,第二節介紹注冊函數,最后再介紹下其他一些相關API
1.1 struct bus_type
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);-------匹配函數(用于匹配device&driver)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);-----------PM相關int (*resume)(struct device *dev);--------------------------------PM相關const struct dev_pm_ops *pm;--------------------------------------PM相關const struct iommu_ops *iommu_ops;struct subsys_private *p;struct lock_class_key lock_key; };- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
1.2 注冊總線
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);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;retval = kset_register(&priv->subsys);--------------------在/sys/bus目錄下創建當前總線目錄if (retval)goto out;retval = bus_create_file(bus, &bus_attr_uevent);----------在當前總線目錄下創建文件ueventif (retval)goto bus_uevent_fail;priv->devices_kset = kset_create_and_add("devices", NULL,&priv->subsys.kobj);-----------------在當前總線目錄下創建devices目錄if (!priv->devices_kset) {retval = -ENOMEM;goto bus_devices_fail;}priv->drivers_kset = kset_create_and_add("drivers", NULL,&priv->subsys.kobj);----------------在當前總線目錄下創建drivers目錄if (!priv->drivers_kset) {retval = -ENOMEM;goto bus_drivers_fail;}INIT_LIST_HEAD(&priv->interfaces);__mutex_init(&priv->mutex, "subsys mutex", key);klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);klist_init(&priv->klist_drivers, NULL, NULL);retval = add_probe_files(bus);-------------------------在當前總線目錄下創建probe相關文件if (retval)goto bus_probe_files_fail;retval = bus_add_groups(bus, bus->bus_groups);if (retval)goto bus_groups_fail;pr_debug("bus: '%s': registered\n", bus->name);return 0;。。。。。。 }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
1.3 其他API
總線卸載函數
extern void bus_unregister(struct bus_type *bus);- 1
2. device
先介紹devices結構體,在介紹注冊函數
2.1 struct device
struct device {struct device *parent;-------------------------父設備struct device_private *p;struct kobject kobj;--------------------------------嵌入的kobjectconst char *init_name; /* initial name of the device */const struct device_type *type;---------------------所屬的device類型struct mutex mutex; /* mutex to synchronize calls to* its driver.*/struct bus_type *bus; /* type of bus device is on */---所屬的busstruct device_driver *driver; /* which driver has allocated thisdevice */---------------------------------對應的驅動drivervoid *platform_data; /* Platform specific data, devicecore doesn't touch it */------------------私有platform數據void *driver_data; /* Driver data, set and get withdev_set/get_drvdata */--------------------私有driver數據struct dev_pm_info power;-----------------------------------PM相關struct dev_pm_domain *pm_domain;--------------------------PM相關#ifdef CONFIG_PINCTRLstruct dev_pin_info *pins; #endif#ifdef CONFIG_NUMAint numa_node; /* NUMA node this device is close to */ #endifu64 *dma_mask; /* dma mask (if dma'able device) */u64 coherent_dma_mask;/* Like dma_mask, but foralloc_coherent mappings asnot all hardware supports64 bit addresses for consistentallocations 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 memoverride */ #ifdef CONFIG_DMA_CMAstruct cma *cma_area; /* contiguous memory area for dmaallocations */ #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;-----------------------------------devres相關struct klist_node knode_class;struct class *class;----------------------------------------所屬的classconst struct attribute_group **groups; /* optional groups */void (*release)(struct device *dev);struct iommu_group *iommu_group;bool offline_disabled:1;bool offline:1; };- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
2.2 設備注冊函數
device的注冊函數device_register分兩步,先初始化device_initialize,主要是初始化所屬的kset為/sys/devices目錄,及其他(如PM相關),然后再注冊,函數為device_add
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);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);------------------有初始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);---沒有初始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);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 */error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);---在/sys/devices目錄下創建當前設備目錄if (error)goto Error;/* notify platform of device entry */if (platform_notify)platform_notify(dev);error = device_create_file(dev, &dev_attr_uevent);--------在當前設備目錄下創建文件ueventif (error)goto attrError;error = device_add_class_symlinks(dev);-------------------創建鏈接文件if (error)goto SymlinkError;error = device_add_attrs(dev);----------------------------創建其他文件,如在class目錄下if (error)goto AttrsError;error = bus_add_device(dev);------------------------------device加入到bus-device的鏈表中if (error)goto BusError;error = dpm_sysfs_add(dev);if (error)goto DPMError;device_pm_add(dev);if (MAJOR(dev->devt)) {error = device_create_file(dev, &dev_attr_dev);if (error)goto DevAttrError;error = device_create_sys_dev_entry(dev);if (error)goto SysEntryError;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_attach-------調用此函數來和driver進行匹配if (parent)-----------------------------------------加入到父設備鏈表中klist_add_tail(&dev->p->knode_parent,&parent->p->klist_children);if (dev->class) {-----------------------------------和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);} 。。。。。。 }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
具體device如何匹配到對應的driver在函數__device_attach中進行,加入開始device沒有driver,那么會在bus中找到對應的driver,看下函數__device_attach
static int __device_attach(struct device *dev, bool allow_async) {int ret = 0;device_lock(dev);if (dev->driver) {if (device_is_bound(dev)) {ret = 1;goto out_unlock;}ret = device_bind_driver(dev);---------如果已經有driver,那么就綁定到device并進行probeif (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);----如果沒有driver,就遍歷總線上的driver,直到找到并進行probeif (!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; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
2.3 其他API
device卸載函數
extern void device_unregister(struct device *dev);- 1
3. driver
先介紹driver的結構體,再介紹注冊函數
3.1 struct device_driver
struct device_driver {const char *name;-----------------------------driver名字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 */enum probe_type probe_type;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);---PM相關int (*resume) (struct device *dev);------------------------PM相關const struct attribute_group **groups;const struct dev_pm_ops *pm;-------------------------------PM相關struct driver_private *p; };- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
3.2 注冊函數
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; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
看下函數bus_add_driver
int bus_add_driver(struct device_driver *drv) {struct bus_type *bus;struct driver_private *priv;int error = 0;bus = bus_get(drv->bus);-----------------------得到所屬的總線if (!bus)return -EINVAL;pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);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;priv->kobj.kset = bus->p->drivers_kset;-------設置所屬總線的driverserror = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,"%s", drv->name);------------在所屬總線的drivers目錄下創建本驅動目錄if (error)goto out_unregister;klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);---把本驅動加入到總線驅動鏈表中if (drv->bus->p->drivers_autoprobe) {if (driver_allows_async_probing(drv)) {pr_debug("bus: '%s': probing driver %s asynchronously\n",drv->bus->name, drv->name);async_schedule(driver_attach_async, drv);} else {error = driver_attach(drv);if (error)goto out_unregister;}}------------------__driver_attach--------------調用此函數來進行探測初始化module_add_driver(drv->owner, drv);error = driver_create_file(drv, &driver_attr_uevent);if (error) {printk(KERN_ERR "%s: uevent attr (%s) failed\n",__func__, drv->name);}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);}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; 。。。。。。。。 }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
那么驅動是如何匹配到對應的device的,繼續探索函數__driver_attach
(drivers/base/dd.c)
static int __driver_attach(struct device *dev, void *data) {struct device_driver *drv = data;int ret;/** Lock device and try to bind to it. We drop the error* here and always return 0, because we need to keep trying* to bind to devices and some drivers will return an error* simply if it didn't support the device.** driver_probe_device() will spit a warning if there* is an error.*/ret = driver_match_device(drv, dev);--------調用總線的match函數來進行匹配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 */if (dev->parent) /* Needed for USB */device_lock(dev->parent);device_lock(dev);if (!dev->driver)driver_probe_device(drv, dev);------沒有driver就設置此driver為device的driver,然后調用驅動probe初始化device_unlock(dev);if (dev->parent)device_unlock(dev->parent); return 0; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
3.3 其他API
卸載函數
extern void driver_unregister(struct device_driver *drv);總結
以上是生活随笔為你收集整理的linux设备驱动模型 - device/bus/driver的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux设备驱动模型之 kset原理与
- 下一篇: cond_resched()