linux駆動編のdriver_registerプロセス分析(一)
12235 ワード
linuxドライバ登録プロセス分析--driver_register(一)
個人のノート、転載を歓迎して、出典を明記して、共に共に共に共に進歩を分かち合います
http://blog.csdn.net/richard_liujh/article/details/45825333
kernelバージョン3.10.14
driver_registerはその名の通り、ドライバの登録です.しかし、framebufferでplatformを呼び出すなど、私たちが書いたドライバによって直接呼び出されることはめったにありません.driver_register,i 2 cでi 2 c_を呼び出すadd_driverなどの関数は、対応するドライバを登録します.driverを直接呼び出すわけではありませんがregister、でも最終的にはdriver_を通過しますregisterはドライバの登録を完了してくれました.だから、driver_を知っています.registerの登録プロセスは、linuxのデバイス駆動を理解するのに役立ちます.
よく使われるplatformを利用してdriver_register driverの分析を開始registerの呼び出しプロセス.
1.バスタイプ(bus_type)の初期化、probeなどの関連関数の登録
ファイル./drivers/base/platform.cにplatform_がありますdriver_registerソース:
ここではdriverのバスタイプ(bus_type)がplatform_に初期化されることに注意する必要がある.bus_type
/drivers/base/platform.cに具体的な定義がある
実際には、たとえば./drivers/i2c/i2c-core.cにはI 2 C登録関数i 2 c_がありますregister_driverソースコード(部分無関係コード省略)
res = driver_register(&driver->driver);……return 0;}EXPORT_SYMBOL(i2c_register_driver);
個人のノート、転載を歓迎して、出典を明記して、共に共に共に共に進歩を分かち合います
http://blog.csdn.net/richard_liujh/article/details/45825333
kernelバージョン3.10.14
driver_registerはその名の通り、ドライバの登録です.しかし、framebufferでplatformを呼び出すなど、私たちが書いたドライバによって直接呼び出されることはめったにありません.driver_register,i 2 cでi 2 c_を呼び出すadd_driverなどの関数は、対応するドライバを登録します.driverを直接呼び出すわけではありませんがregister、でも最終的にはdriver_を通過しますregisterはドライバの登録を完了してくれました.だから、driver_を知っています.registerの登録プロセスは、linuxのデバイス駆動を理解するのに役立ちます.
よく使われるplatformを利用してdriver_register driverの分析を開始registerの呼び出しプロセス.
1.バスタイプ(bus_type)の初期化、probeなどの関連関数の登録
ファイル./drivers/base/platform.cにplatform_がありますdriver_registerソース:
/**
* platform_driver_register - register a driver for platform-level devices
* @drv: platform driver structure
*/
int platform_driver_register(struct platform_driver *drv)
{
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);
に該当するprobe remove shutdownなどの関数が登録されてからdriver_の呼び出しが開始されます.register ここではdriverのバスタイプ(bus_type)がplatform_に初期化されることに注意する必要がある.bus_type
drv->driver.bus = &platform_bus_type;
platform_bus_typeもファイルにあります./drivers/base/platform.cに具体的な定義がある
struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};
platformを例に説明したので、登録駆動のバスタイプはplatformです.I 2 Cバスなら?実際には、たとえば./drivers/i2c/i2c-core.cにはI 2 C登録関数i 2 c_がありますregister_driverソースコード(部分無関係コード省略)
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
……
driver->driver.owner = owner;
driver->driver.bus = &i2c_bus_type;
……
}
res = driver_register(&driver->driver);……return 0;}EXPORT_SYMBOL(i2c_register_driver);
所以,如果注册的是i2c驱动,那么总线类型初始化为i2c_bus_type,也可以在文件 ./ drivers/i2c/i2c-core.c中看到其定义struct bus_type i2c_bus_type = { .name = "i2c", .match = i2c_device_match, .probe = i2c_device_probe, .remove = i2c_device_remove, .shutdown = i2c_device_shutdown, .pm = &i2c_device_pm_ops, };
バスタイプやprobe、remove、shutdownなどの関数が登録されるとdriver_の呼び出しが開始されます.registerは対応するドライバを登録しました.
driver_registerソースコードはファイル./drivers/base/driver.c中上記のコードをよりよく読むために、以下のように簡略化します./** * 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
", drv->name); other = driver_find(drv->name, drv->bus); if (other) { printk(KERN_ERR "Error: Driver '%s' is already registered, " "aborting...
", 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);int driver_register(struct device_driver *drv) | |--> driver_find // |--> bus_add_driver// |--> driver_add_groups// |--> kobject_uevent// uevent
2. driver_find分析
driver_registerでdriverを呼び出すfind,driver_findの名前は分かりやすく、「駆動」を探すと簡単に理解できます.linux 2.6バージョンからカーネルはデバイス駆動モデルを採用しているので、いわゆる「ドライバを探す」というのはデバイス駆動モデルの知識を少し知ったほうがいいです.
ファイル./drivers/base/driver.cにdriver_がありますfindソース/** * driver_find - locate driver on a bus by its name. * @name: name of the driver. * @bus: bus to scan for the driver. * * Call kset_find_obj() to iterate over list of drivers on * a bus to find driver by name. Return driver if found. * * This routine provides no locking to prevent the driver it returns * from being unregistered or unloaded while the caller is using it. * The caller is responsible for preventing this. */ struct device_driver *driver_find(const char *name, struct bus_type *bus) { struct kobject *k = kset_find_obj(bus->p->drivers_kset, name); struct driver_private *priv; if (k) { /* Drop reference added by kset_find_obj() */ kobject_put(k); priv = to_driver(k); return priv->driver; } return NULL; } EXPORT_SYMBOL_GPL(driver_find);
注釈とコードで知っていることに注意してくださいdriver_findは私たちが与えたnameを通じてあるbusの中で駆動を探します.これは分かりやすくて、学校に通っている时、先生XXはある学生の名前(name)を知っていて、それから彼のいるクラス(bus)に行ってこの学生を探します.见つけたら(普通はいいことないTT)、学生を呼び出してちゃんと教育して....ではdriver_findが駆動というものを探したらどうなるのでしょうか?driver_を観察しますfindの戻り値は、ポインタ、つまりdriver_を返していることに気づきます.findはポインタ関数ですね.ポインタのタイプはstruct device_driverタイプです.
struct device_driverはファイルinclude/linux/deviceにあります.hで定義という構造体には、名前(name)、バスタイプ(bus)、モジュール(owner)、およびコールバック用の関数ポインタ(probe,remove,suspend...)などのデバイス駆動の重要な情報が含まれている.要するに、この針を手に入れるのは駆動を得たようで、民心を得た者が天下を得たようだ..../** * 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; };
/*******************************************************************************************************************************
以下、設備駆動について説明しますが、ここでは簡単に説明するだけで、一時的に理解できないのは普通です.時間があれば、設備駆動を専門にいくつかのブログを書きたいです.
*******************************************************************************************************************************/
じゃあ問題だdriverfindはいったいどのようにnameを通じてbusの中で駆動を探しているのだろうか.実は次のコードで実現されていますkset_find_objはハイエンドのようですが、linuxのデバイスモデルについてお話ししなければなりません.linux2.6より良い管理のために、「オブジェクト向け」の概念を加え、簡単に言えばより良い管理リソースです.例えば、一部のリソースはメモリ領域を占有していますが、誰も使用していません.このリソースは実際にはメモリから解放されます.struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);
したがって、基本的なオブジェクト向け管理メカニズムが実現する、Linux 2を構成する.6デバイスモデルのコア構造.これはsysfsファイルシステムに密接に接続されており、カーネルに登録されているkobjectオブジェクトごとにsysfsファイルシステムのディレクトリに対応しています.C++のベースクラスと同様に、Kobjectは他のタイプ(すなわち、コンテナ)に埋め込まれることが多い.bus、devices、driversのような典型的な容器です.これらの容器はkobjectで接続され,木状構造を形成している.Bus:カーネルに登録されている各バスは、i 2 c platform spi ide pci scsiなどのサブディレクトリの下に対応しています.各バスディレクトリには、devicesとdriversという2つのサブディレクトリが含まれています.devicesディレクトリには、システム全体で発見されたバスタイプに属するデバイスが含まれています.driversディレクトリには、バスに登録されているものが含まれています.実はこんなに多くて、読者に少し理解してもらいたいのですが、私たちのdriverはbusタイプ、Kobject、ksetなどと大きな関連があります.具体的な原理については、自分で設備駆動の資料を探して見ることができます.ここでは詳しく説明しません.
ファイル./lib/kobject.cファイルにkset_がありますfind_obj関数のソースコードよく使われるマクロ関数list_に関連していますfor_each_entry、知らない子供靴はここをクリックすることができます.kset_find_objはループ操作により,我々が与えた名前nameに基づいて指定したbusでループ対比し,同じ名前name(このnameがkobjに格納されている)があるかどうかを調べる.実はこれは循環チェーンテーブルの遍歴過程で、ksetとkobjの中にチェーンテーブルポインタnextとprevがあります.ksetはa set of kobjectsであり、kobjはkernel objectであるため、ksetは一連のkobjの組合せである.ここでkset、カーネルにおける解釈はstruct kset-a set of kobjects of a specific type、belonging to a specific subsystemである.では、ここに重要なbelonging toがあります.つまり、今分詞を定語とします.ははは、belonging to a specific subsystemはkset(一連のkobjs)が特定のサブシステムに属していると言っています.だから、初心者はこのように考えることができて、1つのkobjはあるksetに属するべきで(あるいはkobjはkset循環チェーンテーブルの中で)、ksetはまたあるsubsystemに属するべきです.だから、nameで駆動を探すには、bustypeを知ってからksetを得て、最後にkobjを得てからnameが同じかどうかを比較しなければなりません.では、driverを呼び出すのを振り返ってみましょう.find(drv->name, drv->bus);というときに、あげるのではないでしょうか.* kset_find_obj - search for object in kset. * @kset: kset we're looking in. * @name: object's name. * * Lock kset via @kset->subsys, and iterate over @kset->list, * looking for a matching kobject. If matching object is found * take a reference and return the object. */ struct kobject *kset_find_obj(struct kset *kset, const char *name) { struct kobject *k; struct kobject *ret = NULL; spin_lock(&kset->list_lock); list_for_each_entry(k, &kset->list, entry) { if (kobject_name(k) && !strcmp(kobject_name(k), name)) { ret = kobject_get_unless_zero(k); break; } } spin_unlock(&kset->list_lock); return ret; }
drv->bus、そして
bus->p->drivers_ksetはksetを得た.
総括driver_findプロセスは次のとおりです.
1. driver_find、drv->nameとdrv->busを手に入れてドライブを探し始めました
2. kset_find_objはdriver_を通過するfind伝達bus->p->drivers_kset,list_を利用for_each_entryはksetループチェーンテーブルを遍歴する.(kset構造体には循環チェーンポインタnextとprevがある)
3.ループチェーンテーブルの各kobjのメンバー変数nameを巡回する
4.strcmp(kobject_name(k)、name)でdrv->nameとkobjのnameを比較し、同じものがあれば検索に成功したことを示す
5.return:見つかった場合はdevice_を返しますdriverのポインタは、見つからなければNULLを返します.
driver_をよりよく説明できるようにfind、次の図で示します.
次のdriverでregisterのコードからdriverを呼び出すことがわかります.findの役割は、判断driver_findの戻り値other、other = driver_find(drv->name, drv->bus); if (other) { printk(KERN_ERR "Error: Driver '%s' is already registered, " "aborting...
", drv->name); return -EBUSY; }
if(other)条件が成立し、otherを説明する
NULLではなくdriver_find検索に成功しました.でもdriver_registerは登録ドライバであり、ドライバが登録されている場合は再登録する必要はありません.すでに登録されている場合は、直接
return -EBUSY;後の操作は不要です.
だからdriver_register呼び出しdriver_findは、ドライバが登録されているかどうかを確認し、重複登録を防止するためです.
==============================================================================
今日は抗日戦争の反ファシズム勝利70周年だ.閲兵式を見て、本当に衝撃的で、やはり祖国の繁栄と富強を望んでいます.ハハハハ
==============================================================================