這裏所說的SPI核心,就是指/drivers/spi/目錄下spi.c文件中提供給其他文件的函數,首先看下spi核心的初始化函數spi_init(void)。程序如下:
點擊(此處)摺疊或打開
- static int __init spi_init(void)
- {
- int status;
- buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
- if (!buf) {
- status = -ENOMEM;
- goto err0;
- }
- status = bus_register(&spi_bus_type);
- if (status < 0)
- goto err1;
- status = class_register(&spi_master_class);
- if (status < 0)
- goto err2;
- return 0;
- err2:
- bus_unregister(&spi_bus_type);
- err1:
- kfree(buf);
- buf = NULL;
- err0:
- return status;
- }
- postcore_initcall(spi_init);
說明:
1) 由postcore_initcall(spi_init);可以看出,此宏在系統初始化時是先於module_init()執行的。
2) 申請的buf空間用於在spi數據傳輸中。
3) 接下來是總線註冊和類註冊,首先看下總線註冊。
點擊(此處)摺疊或打開
- struct subsys_private {
- struct kset subsys;
- struct kset *devices_kset;
- 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 list_head class_interfaces;
- struct kset glue_dirs;
- struct mutex class_mutex;
- struct class *class;
- };
- struct bus_type {
- const char *name;
- struct bus_attribute *bus_attrs;
- struct device_attribute *dev_attrs;
- struct driver_attribute *drv_attrs;
- 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 (*suspend)(struct device *dev, pm_message_t
state);
- int (*resume)(struct
device *dev);
- const struct dev_pm_ops *pm;
- struct subsys_private *p;
- };
- struct bus_type spi_bus_type = {
- .name = "spi",
- .dev_attrs = spi_dev_attrs,
- .match = spi_match_device,
- .uevent = spi_uevent,
- .pm = &spi_pm,
- };
- int bus_register(struct bus_type *bus)
- {
- int retval;
- struct subsys_private *priv;
- 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);
- //總線的名字”spi”,我們說過了一個kobject對應一個目錄,這裏爲這個目錄賦值名字
- 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;
- //創建devices命名的目錄
- retval = kset_register(&priv->subsys);
- if (retval)
- goto out;
- //創建屬性文件
- retval = bus_create_file(bus, &bus_attr_uevent);
- if (retval)
- goto bus_uevent_fail;
- priv->devices_kset = kset_create_and_add("devices", NULL,
- &priv->subsys.kobj);
- if (!priv->devices_kset) {
- retval = -ENOMEM;
- goto bus_devices_fail;
- }
- priv->drivers_kset = kset_create_and_add("drivers", NULL,
- &priv->subsys.kobj);
- if (!priv->drivers_kset) {
- retval = -ENOMEM;
- goto bus_drivers_fail;
- }
- klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
- klist_init(&priv->klist_drivers, NULL, NULL);
- retval = add_probe_files(bus); //添加探測屬性
- if (retval)
- goto bus_probe_files_fail;
- retval = bus_add_attrs(bus); //添加其他屬性
- if (retval)
- goto bus_attrs_fail;
- pr_debug("bus: '%s': registered\n", bus->name);
- return 0;
- bus_attrs_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;
- }
說明:
1) 首先不管是設備還是驅動,都是掛接在某條總線上的,也就是說我們根據總線類型的不同來區分各種設備和驅動。
2) 從總線註冊函數bus_register(struct bus_type *bus)中可以發現,首先申請了一個subsys_private結構體內存。該結構體中包含了三個kset結構,分別是struct kset subsys、struct kset *devices_kset和struct kset *drivers_kset。
3) subsys是用來向上鏈接的。
4) 當發現一個設備或者驅動的時候,對於每一次設備或者驅動註冊(設備是被插入了,驅動就是.ko模塊被加載),都得分配一個device或者device_drive結構,每一次都需要將device結構掛入drivers或devices(kset結構)鏈表中,這樣才能通過總線找到掛接在這個總線上的所有設備和驅動。這裏僅僅將設備和驅動掛接在總線上,並不能表明設備和驅動之間的關係,這樣的處理僅僅表明了驅動、設備與總線的關係,它們申明瞭我現在掛接在這條總線上,以後操作我就通過這條總線。
5) 總線的目錄名爲”spi”。也就是說在/sys/bus目錄下有一個spi目錄,即/sys/bus/spi。內核中有spi總線驅動,bus_register(&spi_bus_type)就是用來註冊總線的,該函數調用完成後,就會在/sys/bus/目錄下創建spi目錄。
接下來看下總線中spi_match_device()函數,此函數在(四)中的設備註冊中會調用,如下:
點擊(此處)摺疊或打開
- static int spi_match_device(struct device *dev, struct device_driver *drv)
- {
- const struct spi_device *spi = to_spi_device(dev);
- const struct spi_driver *sdrv = to_spi_driver(drv);
- /* Attempt an OF style match */
- if (of_driver_match_device(dev, drv))
- return 1;
- if (sdrv->id_table)
- return !!spi_match_id(sdrv->id_table, spi);
- return strcmp(spi->modalias, drv->name) == 0;
- }
說明:
1) 首先查看驅動和設備是否匹配,如果不匹配,退出。
2) 判斷驅動中是否支持id數組,如果支持,查找匹配此id的spi_device。
3) 比較設備的名字的和驅動的名字是否相同。
二、spi驅動註冊
在《Linux spi驅動分析(四)----SPI設備驅動(W25Q32BV)》中,執行語句spi_register_driver(&w25q_driver);,從而註冊spi驅動。函數如下:
點擊(此處)摺疊或打開
- struct spi_driver {
- const struct spi_device_id *id_table;
- int (*probe)(struct spi_device *spi);
- int (*remove)(struct spi_device *spi);
- void (*shutdown)(struct spi_device *spi);
- int (*suspend)(struct spi_device *spi, pm_message_t
mesg);
- int (*resume)(struct
spi_device *spi);
- struct device_driver driver;
- };
- static struct spi_driver w25q_driver = {
- .driver = {
- .name = "spi-w25q",
- .owner = THIS_MODULE,
- },
- //.id_table = w25q_ids,
- .probe = w25q_probe,
- .remove = __devexit_p(w25q_remove),
- };
- int spi_register_driver(struct spi_driver *sdrv)
- {
- sdrv->driver.bus = &spi_bus_type;
- if (sdrv->probe)
- sdrv->driver.probe = spi_drv_probe;
- if (sdrv->remove)
- sdrv->driver.remove = spi_drv_remove;
- if (sdrv->shutdown)
- sdrv->driver.shutdown = spi_drv_shutdown;
- return driver_register(&sdrv->driver);
- }
說明:
1) 驅動是如何插入到/sys/bus/drivers/spi目錄下的?在driver_register->driver_register->bus_add_driver函數中有個重要的語句drv->kobj.kset = &bus->drivers,這裏就是將driver的kobj所屬的kset掛接上總線的kset。
2) 在struct spi_driver中指明驅動的名稱,這裏是"spi-w25q"。
3) spi_register_driver()函數的參數爲spi_driver結構。函數定義了bus_type,也就是驅動掛接的總線類型。函數接下來對結構體spi_driver中的device_driver成員賦值。
4) 驅動註冊,程序如下:
點擊(此處)摺疊或打開
- 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;
- 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;
- };
- 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);
- /* 在kobject結構組成的鏈表中查找是否已經存在這個驅動,前面講過,驅動必然掛接在某個總線
- 上,返回值是device_driver結構的指針 */
- other = driver_find(drv->name, drv->bus);
- if (other) {
- put_driver(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;
- }
說明:
1) driver_register()完成掛接驅動至總線及生成設備樹的過程。
2) 首先調用driver_find()函數在spi總線上查找該驅動是否已經存在,如果存在,忙退出。
3) 如果該驅動在SPI總線上不存在,調用bus_add_driver(drv)增加該驅動。
4) 調用driver_add_groups(drv, drv->groups)函數增加驅動組。
接下來看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;
- error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
- "%s", drv->name);
- if (error)
- goto out_unregister;
- if (drv->bus->p->drivers_autoprobe) {
- error = driver_attach(drv); //這個函數是重點.
- if (error)
- goto out_unregister;
- }
- klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
- 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_attrs(bus, drv);
- if (error) {
- /* How the hell do we get out of this pickle? Give
up */
- printk(KERN_ERR "%s: driver_add_attrs(%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);
- }
- }
- kobject_uevent(&priv->kobj, KOBJ_ADD);
- return 0;
- out_unregister:
- kobject_put(&priv->kobj);
- kfree(drv->p);
- drv->p = NULL;
- out_put_bus:
- bus_put(bus);
- return error;
- }
說明:
1) 首先創建struct driver_private *priv結構體內存,注意此結構體是struct device_driver的成員變量。
2) 初始化priv成員變量。
3) 如果驅動總線支持自動探測,則調用error = driver_attach(drv); 實現探測。由(二)中bus_register()函數可以看出,bus->p->drivers_autoprobe = 1,支持自動探測。
4) driver_attach(drv); 的作用是:如果驅動還未掛接在總線上,掛接它並且調用probe函數進行探測。
點擊(此處)摺疊或打開
- int driver_attach(struct device_driver *drv)
- {
- return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
- }
點擊(此處)摺疊或打開
- static int __driver_attach(struct device *dev, void *data)
- {
- struct device_driver *drv = data;
- /*
- * 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.
- */
- if (!driver_match_device(drv, dev))
- return 0;
- if (dev->parent) /* Needed for USB */
- device_lock(dev->parent);
- device_lock(dev);
- if (!dev->driver)
- driver_probe_device(drv, dev); //此函數就是我們要找的函數
- device_unlock(dev);
- if (dev->parent)
- device_unlock(dev->parent);
- return 0;
- }
點擊(此處)摺疊或打開
- 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);
- pm_runtime_get_noresume(dev);
- pm_runtime_barrier(dev);
- ret = really_probe(dev, drv);
- pm_runtime_put_sync(dev);
- return ret;
- }
點擊(此處)摺疊或打開
- static int really_probe(struct device *dev, struct device_driver *drv)
- {
- int ret = 0;
- 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 (driver_sysfs_add(dev)) {
- printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
- __func__, dev_name(dev));
- goto probe_failed;
- }
- 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;
- }
- 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:
- devres_release_all(dev);
- driver_sysfs_remove(dev);
- dev->driver = NULL;
- if (ret != -ENODEV && ret != -ENXIO) {
- /* 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;
- }
說明:
1) 在if (dev->bus->probe)中,由於此處還沒有定義設備,所以不執行if裏面的程序。在elseif (drv->probe)中,驅動裏面有探測函數,所以執行ret = drv->probe(dev);。因爲此處還沒有定義設備,所以此處執行沒有效果。
在 bus_for_each_dev函數中可以找到device結構:
點擊(此處)摺疊或打開
- int bus_for_each_dev(struct bus_type *bus, struct device *start,
- void *data, int (*fn)(struct
device *, void *))
- {
- struct klist_iter i;
- struct device *dev;
- int error = 0;
- if (!bus)
- return -EINVAL;
- klist_iter_init_node(&bus->p->klist_devices, &i,
- (start ? &start->p->knode_bus : NULL));
-
- while ((dev = next_device(&i)) && !error)
- error = fn(dev, data);
- klist_iter_exit(&i);
- return error;
- }
說明:
1) 查找每個掛接在spi總線上的設備,看他們是否有註冊,並調用相應的函數也就是__driver_attach函數。實際上就是查找device結構。
三、spi設備註冊
在《Linux spi驅動分析(一)----總線驅動》中,spi_new_device()函數調用了spi_add_device(proxy),程序如下:
點擊(此處)摺疊或打開
- 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 */
- struct dev_pm_info power;
- struct dev_power_domain *pwr_domain;
- #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;
- struct device_node *of_node; /* associated device tree node */
- 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);
- };
- int spi_add_device(struct spi_device *spi)
- {
- static DEFINE_MUTEX(spi_add_lock);
- struct device *dev = spi->master->dev.parent;
- struct device *d;
- int status;
- /* Chipselects are numbered 0..max; validate. */
- if (spi->chip_select >= spi->master->num_chipselect) {
- dev_err(dev, "cs%d >= max %d\n",
- spi->chip_select,
- spi->master->num_chipselect);
- return -EINVAL;
- }
- /* Set the bus ID string */
- dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->master->dev),
- spi->chip_select);
- /* We need to make sure there's no other device with this
- * chipselect **BEFORE** we call setup(), else we'll
trash
- * its configuration. Lock against concurrent add() calls.
- */
- mutex_lock(&spi_add_lock);
- d = bus_find_device_by_name(&spi_bus_type, NULL, dev_name(&spi->dev));
- if (d != NULL) {
- dev_err(dev, "chipselect %d already in use\n",
- spi->chip_select);
- put_device(d);
- status = -EBUSY;
- goto done;
- }
- /* Drivers may modify this initial i/o setup, but will
- * normally rely on the device being setup. Devices
- * using SPI_CS_HIGH can't coexist well otherwise...
- */
- status = spi_setup(spi);
- if (status < 0) {
- dev_err(dev, "can't setup %s, status %d\n",
- dev_name(&spi->dev), status);
- goto done;
- }
- /* Device may be bound to an active driver when this returns */
- status = device_add(&spi->dev);
- if (status < 0)
- dev_err(dev, "can't add %s, status %d\n",
- dev_name(&spi->dev), status);
- else
- dev_dbg(dev, "registered child %s\n", dev_name(&spi->dev));
- done:
- mutex_unlock(&spi_add_lock);
- return status;
- }
說明:
1) 在設備device的定義中,定義了這個設備掛接的總線和驅動。
2) spi_add_device()函數首先判斷是否超出最大設備數,如果超過,直接退出。
3) 設置設備名稱,此名稱即是/sys/bus/spi/devices/下的一個目錄。
4) 在spi總線上尋找此設備,如果找到,退出。
5) 調用spi_setup(spi)函數。
6) 調用device_add(&spi->dev)函數對設備進行初始化和註冊。程序如下:
點擊(此處)摺疊或打開
- 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);
- 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);
- 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;
- error = bus_add_device(dev);
- if (error)
- goto BusError;
- error = dpm_sysfs_add(dev);
- 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->klist_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;
- }
說明:
1) 首先獲取設備dev,對dev的成員進行初始化。
2) kobject_add()完成目錄的創建。
3) 創建文件。
4) bus_probe_device(dev);,總線探測設備,程序如下:
點擊(此處)摺疊或打開
- void bus_probe_device(struct device *dev)
- {
- struct bus_type *bus = dev->bus;
- int ret;
- if (bus && bus->p->drivers_autoprobe) {
- ret = device_attach(dev);
- WARN_ON(ret < 0);
- }
- }
- int device_attach(struct device *dev)
- {
- int ret = 0;
- device_lock(dev);
- if (dev->driver) {
- if (klist_node_attached(&dev->p->knode_driver)) {
- ret = 1;
- goto out_unlock;
- }
- ret = device_bind_driver(dev);
- if (ret == 0)
- ret = 1;
- else {
- dev->driver = NULL;
- ret = 0;
- }
- } else {
- pm_runtime_get_noresume(dev);
- ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
- pm_runtime_put_sync(dev);
- }
- out_unlock:
- device_unlock(dev);
- return ret;
- }
說明:
1) 由(二)中的總線註冊函數可知,bus->p->drivers_autoprobe = 1。
2) 調用device_attach()函數加載設備。
3) 由於程序還沒有對dev->driver進行賦值,所以此處程序走的是else。
4) bus_for_each_drv()函數調用__device_attach()函數,程序如下:
點擊(此處)摺疊或打開
- 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)
- error = fn(drv, data);
- klist_iter_exit(&i);
- return error;
- }
- static inline int driver_match_device(struct device_driver *drv,
- struct device *dev)
- {
- return drv->bus->match ? drv->bus->match(dev, drv) : 1;
- }
- static int __device_attach(struct device_driver *drv, void *data)
- {
- struct device *dev = data;
- if (!driver_match_device(drv, dev))
- return 0;
- return driver_probe_device(drv, dev);
- }
說明:
1) __device_attach()函數使用了兩個參數,一個參數爲dev,另外一個就是bus_for_each_drv()函數提供的。
2) __device_attach()函數首先使用函數driver_match_device(drv, dev)查看驅動是否匹配設備,如果不匹配,退出。driver_match_device(drv, dev)中,判斷是否有drv->bus->match,從(二)總線註冊中知道,總線中有match,所以調用(二)中的spi_match_device()函數。
3) driver_probe_device()函數完成驅動探測,程序如下:
點擊(此處)摺疊或打開
- 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);
- pm_runtime_get_noresume(dev);
- pm_runtime_barrier(dev);
- ret = really_probe(dev, drv);
- pm_runtime_put_sync(dev);
- return ret;
- }
- static int really_probe(struct device *dev, struct device_driver *drv)
- {
- int ret = 0;
- 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 (driver_sysfs_add(dev)) {
- printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
- __func__, dev_name(dev));
- goto probe_failed;
- }
- 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;
- }
- 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:
- devres_release_all(dev);
- driver_sysfs_remove(dev);
- dev->driver = NULL;
- if (ret != -ENODEV && ret != -ENXIO) {
- /* 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;
- }
說明:
1) driver_probe_device()函數調用really_probe()函數。
2) 在really_probe()函數中,由於設備的總線中沒有探測函數,所以不執行if (dev->bus->probe)。
3) spi驅動中有探測函數,所以執行else if (drv->probe)裏面的程序,即ret = drv->probe(dev);,從(三)中的int
spi_register_driver(struct spi_driver *sdrv)函數可以看到,驅動的探測函數爲spi_drv_probe(),程序如下:
點擊(此處)摺疊或打開
- static int spi_drv_probe(struct device *dev)
- {
- const struct spi_driver *sdrv = to_spi_driver(dev->driver);
- return sdrv->probe(to_spi_device(dev));
- }
說明:
1) 首先獲取spi_driver結構體。
2) 調用spi_driver結構體中的探測函數,即爲(三)中的w25q_probe()函數。
在really_probe()函數中,調用driver_bound(dev);函數實現設備與驅動的綁定,程序如下:
點擊(此處)摺疊或打開
- static void driver_bound(struct device *dev)
- {
- if (klist_node_attached(&dev->p->knode_driver)) {
- 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_name(dev),
- __func__, dev->driver->name);
- klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);
- if (dev->bus)
- blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
- BUS_NOTIFY_BOUND_DRIVER, dev);
- }
說明:
1) 使用klist_add_tail()將設備與驅動鏈接在一起。
四、總結
在device和device_drive結構中,device中存在一個struct
device_driver *driver,而在device_drive中並沒有同樣的包含device結構。對於一個設備來說,只能綁定一個驅動;而對於一個驅動來說,可以對應多個設備。 也就是說這裏device中的driver指針將會指向其綁定的驅動。回到probe探測函數,對一個設備驅動進行註冊的過程中,會在其相應的總線(也就是其掛接的總線)上發出一個探測,這個探測會搜尋所有掛接在這個總線上的尚未被綁定的設備(也就是driver指針爲NULL),然後將driver指針指向這個驅動的結構,同時將這個設備的device結構掛接在device_driver結構中的klist鏈表中。 當一個設備被註冊時,它也會去尋找掛接在同一條總線上的驅動,並將自己與這個驅動聯繫起來。
五、spi傳輸函數
spi核心提供了數據傳輸函數,如下:
點擊(此處)摺疊或打開
- static inline void spi_message_init(struct spi_message *m)
- {
- memset(m, 0, sizeof *m);
- INIT_LIST_HEAD(&m->transfers);
- }
- static inline void
- spi_message_add_tail(struct spi_transfer *t, struct spi_message *m)
- {
- list_add_tail(&t->transfer_list, &m->transfers);
- }
- static inline int
- spi_write(struct spi_device *spi, const void *buf, size_t len)
- {
- struct spi_transfer t = {
- .tx_buf = buf,
- .len = len,
- };
- struct spi_message m;
- spi_message_init(&m);
- spi_message_add_tail(&t, &m);
- return spi_sync(spi, &m);
- }
- static inline int
- spi_read(struct spi_device *spi, void *buf, size_t len)
- {
- struct spi_transfer t = {
- .rx_buf = buf,
- .len = len,
- };
- struct spi_message m;
- spi_message_init(&m);
- spi_message_add_tail(&t, &m);
- return spi_sync(spi, &m);
- }
- static inline ssize_t spi_w8r8(struct spi_device *spi, u8 cmd)
- {
- ssize_t status;
- u8 result;
- status = spi_write_then_read(spi, &cmd, 1, &result, 1);
- /* return negative errno or unsigned value */
- return (status < 0) ? status : result;
- }
- static inline ssize_t spi_w8r16(struct spi_device *spi, u8 cmd)
- {
- ssize_t status;
- u16 result;
- status = spi_write_then_read(spi, &cmd, 1, (u8 *) &result, 2);
- /* return negative errno or unsigned value */
- return (status < 0) ? status : result;
- }
說明:
1) 傳輸開始時,首先初始化spi_message,然後將傳輸的spi_transfer鏈入spi_message中。
2) spi_message中,有一個transfers隊列,spi_transfer結構體通過這個隊列掛到spi_message中。一個spi_message代表一次傳輸會話,spi_transfer代表一次單獨的IO操作。比如,有些spi設備需要先讀後寫,那麼這個讀寫過程就是一次spi會話,裏面包括兩個transfer,一個定義寫操作的參數,另一個定義讀操作的參數。
3) 最後都是調用spi_sync()函數實現傳輸的,如下:
點擊(此處)摺疊或打開
- int spi_sync(struct spi_device *spi, struct spi_message *message)
- {
- return __spi_sync(spi, message, 0);
- }
- static int __spi_sync(struct spi_device *spi, struct spi_message *message,
- int bus_locked)
- {
- DECLARE_COMPLETION_ONSTACK(done);
- int status;
- struct spi_master *master = spi->master;
- message->complete = spi_complete;
- message->context = &done;
- if (!bus_locked)
- mutex_lock(&master->bus_lock_mutex);
- status = spi_async_locked(spi, message);
- if (!bus_locked)
- mutex_unlock(&master->bus_lock_mutex);
- if (status == 0) {
- wait_for_completion(&done);
- status = message->status;
- }
- message->context = NULL;
- return status;
- }
- int spi_async_locked(struct spi_device *spi, struct spi_message *message)
- {
- struct spi_master *master = spi->master;
- int ret;
- unsigned long flags;
- spin_lock_irqsave(&master->bus_lock_spinlock, flags);
- ret = __spi_async(spi, message);
- spin_unlock_irqrestore(&master->bus_lock_spinlock, flags);
- return ret;
- }
- static int __spi_async(struct spi_device *spi, struct spi_message *message)
- {
- struct spi_master *master = spi->master;
- /* Half-duplex links include original MicroWire, and ones
with
- * only one data pin like SPI_3WIRE (switches direction) or where
- * either MOSI or MISO is missing. They can also be caused by
- * software limitations.
- */
- if ((master->flags & SPI_MASTER_HALF_DUPLEX)
- || (spi->mode & SPI_3WIRE)) {
- struct spi_transfer *xfer;
- unsigned flags = master->flags;
- list_for_each_entry(xfer, &message->transfers, transfer_list) {
- if (xfer->rx_buf && xfer->tx_buf)
- return -EINVAL;
- if ((flags & SPI_MASTER_NO_TX) && xfer->tx_buf)
- return -EINVAL;
- if ((flags & SPI_MASTER_NO_RX) && xfer->rx_buf)
- return -EINVAL;
- }
- }
- message->spi = spi;
- message->status = -EINPROGRESS;
- return master->transfer(spi, message);
- }
說明:
1) 由上面的函數調用軌跡看,最後就是調用master的transfer函數實現傳輸的。