linux 驅動入門5

慢慢的開始轉驅動,目前比較有時間,必定要把驅動學會。哎。人生慢慢路,一回頭。已經工做了八九年了。努力。在買套房。改退休了。學驅動。我的認爲首先要熟悉驅動框架。慢慢來。心急吃不了熱豆腐。編程

看網上都說的設備是掛在總線的。固然硬件佈線是這樣的。軟件也是模擬了這個過程。那總線是如何組織的呢。其實能夠看到。閉環。閉環。雙向閉環鏈表。 對。全部的設備是個閉環鏈表。全部的總線也是
閉環鏈表。那這些總線是如何造成這個閉環鏈表的呢?框架

這就是以黨中央爲中心,牢牢的團結圍繞在黨中央周圍。換句話就是,以bus.c爲中心。其餘各類i2c, usb, platform牢牢的圍繞在他的周圍。那是如何圍繞的呢。既然是鏈表,只要抓住表頭,就能夠了。因此bus.c爲中心。其餘各類i2c
定義了表頭,其餘總線不斷加入這個環了。模塊化

關於這個環結構。這個相對花點時間能夠看明白。也就是kset kobject的關係。這個網上太多了。就不必說了。函數

那下面咱們分析下。各類具體的總線是如何掛到了bus.c的聊表頭裏的。spa

在device.h中
/* This is a #define to keep the compiler from merging different
* instances of the __key variable */
#define bus_register(subsys) \
({ \
static struct lock_class_key __key; \
__bus_register(subsys, &__key); \ // marvell, honeywell 臧春傑
})debug

哎,就它,全部的具體總線都要經過它來掛到鏈表裏。就像platform.c裏
int __init platform_bus_init(void)
{
int error;指針

early_platform_cleanup();orm

error = device_register(&platform_bus);
if (error)
// marvell, honeywell 臧春傑
return error;
error = bus_register(&platform_bus_type);
if (error)
device_unregister(&platform_bus);
return error;
}
都是這樣註冊的。對象

那下面咱們具體分析註冊過程。很差整。看內核代碼,須要對c比較熟悉。對模塊化編程方法比較熟悉。進程

這樣就進到了int __bus_register(struct bus_type *bus, struct lock_class_key *key)
傳進的參數都是bus_type. 看看這個結構體,很大。很嚇人。可是若是實現某個具體總線。卻設置的變量很少。咱們能夠看到subsys_private這個,這個爲何叫private呢? 在面向對象裏。private是私有的。
莫非有什麼特殊含義。個人我的理解是,這樣的結構體不須要外圍模塊操做。也就是不須要platform.c操做。這個東西會有bus.c內部處理。

果真能夠看到,進到函數裏。來了這樣一句
priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL); // marvell, honeywell 臧春傑
priv->bus = bus;
bus->p = priv;
看來真的不要具體總線模塊操做。即便你真的寫了值了。那塊內存也是垃圾內存。這裏會重新分配操做。嗯。

retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
if (retval)
goto out;

priv->subsys.kobj.kset = bus_kset;
// marvell, honeywell 臧春傑
priv->subsys.kobj.ktype = &bus_ktype;
priv->drivers_autoprobe = 1;

retval = kset_register(&priv->subsys);

這幾句須要和起來,完成了動做。操做subsys的kobj, 由於kset進程之kobject. 也就是kobject是kset的成員。 看來,熟悉kset kobject的關係相當重要。因此,這個是基礎,必定得熟悉,否則無法整。

對kobj設置名字。 指定kobj的所屬kset. 也就是kobje屬於哪一個環,要把kobj加到kset鏈表,全靠這個指定。下面對kobj的ktype ,也就是指定kobj的屬性,和屬性操做方法。操做方法? 什麼操做方法。

屬性attribute對應的sysfs的文件, sysfs_ops就是對這些屬性文件作show store後的實現方法。

這裏,這個ops和這個kobj綁定上了。那全部對這個kobj的屬性的讀寫都是有ops來處理。對。是這樣的。

下面一句是保存值,之後對屬性副職。

把內存初始化完後,下面就改真正的掛到聊表裏了。前面只是對內存操做。kset_register,經過這個函數,就是把subsys的kobj加// marvell, honeywell 臧春傑到了bus_kset這個連表頭裏了。哪這個bus_kset這個東西哪裏呢?

這是在bus.c初始化的時候建立的。因此各個模塊初始化的時候不是胡亂的。有書序的。經過各類initcall把函數指針加到對應的初始化段裏。分7個段。也就是7級。從1級慢慢初始化。 至關於7個堆棧。每一個棧有不少的函數指針。

一個棧就是一級。以及一級的來初始化。

全部,bus.c的初始化
int __init buses_init(void)
{
bus_kset = kset_create_and_add("bus", // marvell, honeywell 臧春傑*/&bus_uevent_ops, NULL);
if (!bus_kset)
return -ENOMEM;

system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj);
if (!system_kset)
return -ENOMEM;

return 0;
}
建立了bus_kset.

這樣register後,具體的總線結構體就掛到了總線鏈表頭了。

retval = bus_create_file(bus, &bus_attr_uevent);
這句就是在sysfs建立了文件, // marvell, honeywell 臧春傑 文件名和權限都有bus_attr_uevent決定。對了。這個結構體就是
static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store);

這就是這個結構體定義。文件名uevent. 咱們能夠在/sys/bus/platform下有個uevent文件--w------- root root 4096 1970-01-01 17:04 uevent 看到沒,文件名和權限是否是對的。

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);

下面就是這兩句了。沒什麼,就是建立了兩個kset結構體。咱們主要看到了兩個字符串。devices, drivers這個沒什麼奇怪,他會生成兩個目錄,真的生成了嗎? 確實有
drwxr-xr-x root root 1970-01-01 17:04 devices
drwxr-xr-x root root 1970-01-01 17:04 drivers
// marvell, honeywell 臧春傑
-rw-r--r-- root root 4096 1970-01-01 17:04 drivers_autoprobe
--w------- root root 4096 1970-01-01 17:04 drivers_probe
--w------- root root 4096 1970-01-01 17:04 uevent
真的有,它是何時,生成的呢? 如何生成的呢? 就是在kobj註冊的時候,雖然這裏的kobj的kset位null. 可是進入kobject.c裏,咱們看到error = create_dir(kobj);對,就是在這裏建立了這兩個目錄。

此時有個疑問,文件夾的名字知道了。那系統如何知道該放到這裏呢? sysfs的目錄放到哪裏取決於parent。這裏能夠看到parent就是platform的subsys的kobj。 因此就放到這了。

INIT_LIST_HEAD(&priv->interfaces);
__mutex_init(&priv->mutex, "subsys mutex", key);
klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
// marvell, honeywell 臧春傑
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;

下面這幾句都同樣了。都是建立了sysfs的文件,關聯上show store處理函數。值得一提的是 klist_init這裏初始化後,就爲了把device driver掛到這上面。具體device driver如何掛總線上,咱們後續說。

先把bus.c分析I明白了。一個個來。不着急。

那這樣bus.c的總線註冊函數就分析完了。

相關文章
相關標籤/搜索