日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux powerpc i2c驱动 之 i2c设备层的注册过程

發布時間:2023/12/10 linux 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux powerpc i2c驱动 之 i2c设备层的注册过程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Linuxi2c驅動的加載過程,分為i2c設備層、i2c?adapter層與i2c核心層

i2c設備驅動層也就是我們為特定i2c設備編寫的驅動,下面是我自己理解的i2c驅動的注冊過程

在我們寫的i2c設備驅動中,我們會調用i2c_add_driver()開始i2c設備驅動的注冊,該函數調用i2c_register_driver完成所有注冊操作

?

?

[plain] view plaincopyprint?
  • static?inline?int?i2c_add_driver(struct?i2c_driver?*driver)??
  • {??
  • return?i2c_register_driver(THIS_MODULE,?driver);??
  • }??
  • i2c_register_driver會調用driver_register() 來將設備驅動添加到總線的設備驅動鏈表中

    [plain] view plaincopyprint?
  • int?i2c_register_driver(struct?module?*owner,?struct?i2c_driver?*driver)??
  • {??
  • int?res;??
  • /*?Can't?register?until?after?driver?model?init?*/??
  • if?(unlikely(WARN_ON(!i2c_bus_type.p)))??
  • return?-EAGAIN;??
  • driver->driver.owner?=?owner;??
  • driver->driver.bus?=?&i2c_bus_type;??
  • /*?When?registration?returns,?the?driver?core??
  • ?*?will?have?called?probe()?for?all?matching-but-unbound?devices.??
  • ?*/??
  • res?=?<strong>driver_register</strong>(&driver->driver);??
  • if?(res)??
  • return?res;??
  • pr_debug("i2c-core:?driver?[%s]?registered\n",?driver->driver.name);??
  • INIT_LIST_HEAD(&driver->clients);??
  • /*?Walk?the?adapters?that?are?already?present?*/??
  • mutex_lock(&core_lock);??
  • bus_for_each_dev(&i2c_bus_type,?NULL,?driver,?__attach_adapter);??
  • mutex_unlock(&core_lock);??
  • return?0;??
  • }??


  • driver_register,通過driver_find來判斷驅動是否已經注冊,然后會調用

    bus_add_drive

    將設備驅動添加到總線上

    [plain] view plaincopyprint?
  • 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)?{??
  • put_driver(other);??
  • printk(KERN_ERR?"Error:?Driver?'%s'?is?already?registered,?"??
  • "aborting...\n",?drv->name);??
  • return?-EBUSY;??
  • }??
  • ret?=?<strong>bus_add_driver</strong>(drv);??
  • if?(ret)??
  • return?ret;??
  • ret?=?driver_add_groups(drv,?drv->groups);??
  • if?(ret)??
  • bus_remove_driver(drv);??
  • return?ret;??
  • }??


  • bus_add_driver中初始化priv->klist_devices的值,并將priv賦值給drv->p

    通過調用klist_add_tail(&priv->knode_bus,?&bus->p->klist_drivers)將驅動信息保存到總線結構中,在此之前將調用driver_attach()

    [plain] view plaincopyprint?
  • 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;??
  • }??
  • <strong>klist_init</strong>(&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?=?<strong>driver_attach</strong>(drv);??
  • if?(error)??
  • goto?out_unregister;??
  • }??
  • <strong>klist_add_tail</strong>(&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:??
  • kfree(drv->p);??
  • drv->p?=?NULL;??
  • kobject_put(&priv->kobj);??
  • out_put_bus:??
  • bus_put(bus);??
  • return?error;??
  • }??


  • driver_attach中,通過調用bus_for_each_dev,遍歷在總線上掛載的所有設備,并對每個設備(dev)調用__driver_attach()

    [plain] view plaincopyprint?
  • int?driver_attach(struct?device_driver?*drv)??
  • {??
  • return?bus_for_each_dev(drv->bus,?NULL,?drv,?<strong>__driver_attach</strong>);??
  • }??

  • __driver_attach里會調用driver_match_device()來判斷devdrivid是否相同,在i2c驅動里就會調用i2c_bus_type->match程序進行判斷,

    id相同時,將會調用driver_probe_device()

    [plain] view plaincopyprint?
  • 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?(!<strong>driver_match_device</strong>(drv,?dev))??
  • return?0;??
  • if?(dev->parent)?/*?Needed?for?USB?*/??
  • down(&dev->parent->sem);??
  • down(&dev->sem);??
  • if?(!dev->driver)??
  • <strong>driver_probe_device</strong>(drv,?dev);??
  • up(&dev->sem);??
  • if?(dev->parent)??
  • up(&dev->parent->sem);??
  • return?0;??
  • }??


  • 在driver_probe_device(),首先會調用device_is_registered()判斷dev是否注冊,若沒注冊則返回;若已經注冊,則調用really_probe

    [plain] view plaincopyprint?
  • 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?=?<strong>really_probe</strong>(dev,?drv);??
  • pm_runtime_put_sync(dev);??
  • return?ret;??
  • }??


  • 在really_probe()里,首先將drv賦值給dev->driver,然后會調用總線的probe函數,在i2c驅動里,

    此時將會調用i2c總線的probe函數:i2c_device_probe

    [plain] view plaincopyprint?
  • 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)???
  • {??
  • //此處調用i2c總線的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;??
  • }??


  • i2c_device_probe()里,會根據to_i2c_driver(dev->driver)獲取i2c驅動,也就是我們編寫的具體的i2c設備驅動的結構體i2c_driver,即

    [plain] view plaincopyprint?
  • static?struct?i2c_driver?XXX_driver?=?{??
  • .driver?=?{??
  • .name?=?"XXXX_name",??
  • .owner?=?THIS_MODULE,??
  • },??
  • .probe?=?XXX_probe,??
  • .remove?=?XXX_remove,??
  • .id_table?=?XXX_id,??
  • };??


  • 這樣就調用了我們驅動的probe()了,這就是我們在驅動里調用i2c_add_driver(),通過driver_register()的一系列調用,最后執行我們所寫的probe()

    [plain] view plaincopyprint?
  • static?int?i2c_device_probe(struct?device?*dev)??
  • {??
  • struct?i2c_client?*client?=?i2c_verify_client(dev);??
  • struct?i2c_driver?*driver;??
  • int?status;??
  • if?(!client)??
  • return?0;??
  • driver?=?to_i2c_driver(dev->driver);??
  • if?(!driver->probe?||?!driver->id_table)??
  • return?-ENODEV;??
  • client->driver?=?driver;??
  • if?(!device_can_wakeup(&client->dev))??
  • device_init_wakeup(&client->dev,??
  • client->flags?&?I2C_CLIENT_WAKE);??
  • dev_dbg(dev,?"probe\n");??
  • status?=?<strong>driver->probe</strong>(client,?i2c_match_id(driver->id_table,?client));//執行我們寫的probe函數??
  • if?(status)??
  • client->driver?=?NULL;??
  • return?status;??
  • }??

  • 總結

    以上是生活随笔為你收集整理的linux powerpc i2c驱动 之 i2c设备层的注册过程的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。