小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

談?wù)刲inux2.6內(nèi)核的驅(qū)動(dòng)框架

 rookie 2012-08-06

linux支持的設(shè)備越來越多,種類越來越多,設(shè)備本身的功能也是越來越復(fù)雜,而操作系統(tǒng)內(nèi)核必須有一種很有效的方式來管理這些設(shè)備,最起碼的要控 制它們的開啟關(guān)閉,更進(jìn)一步要控制它們進(jìn)行協(xié)同工作,實(shí)際上要內(nèi)核僅僅做到這些并不難,關(guān)鍵問題是如何與用戶進(jìn)行交互,那么多設(shè)備怎么以統(tǒng)一的方式提供給 用戶, 畢竟最終要控制設(shè)備的還是用戶啊,在2.6內(nèi)核中引出了一個(gè)叫做kobject的數(shù)據(jù)結(jié)構(gòu),它的作用和著名的list_head一樣,只不過后者是一條環(huán) 鏈而它卻是一棵樹。學(xué)習(xí)2.6內(nèi)核的驅(qū)動(dòng)有兩個(gè)意義:1.學(xué)會(huì)以后寫個(gè)驅(qū)動(dòng);2.學(xué)習(xí)這一切的思想,作者為什么能想到這些。我自己寫過一些驅(qū)動(dòng),根據(jù)經(jīng)驗(yàn) 2.6的內(nèi)核框架有兩條線索,一條就是以kobject為中心往上走,一直和vfs相接直取用戶空間;另一條就是內(nèi)核內(nèi)部的一些鏈表,底層意義上把設(shè)備分 類,按照設(shè)備的性質(zhì)進(jìn)行匯總。先看看第一條線索的基礎(chǔ)設(shè)施:

struct kobject {

         const char              * k_name;

         char                    name[KOBJ_NAME_LEN];

         struct kref             kref;

         struct list_head        entry;

         struct kobject          * parent;

         struct kset             * kset;

         struct kobj_type        * ktype;

         struct dentry           * dentry;

         wait_queue_head_t       poll;

};

再看看第二條線索的基礎(chǔ)設(shè)施:

struct klist {

         spinlock_t              k_lock;

         struct list_head        k_list;

         void                    (*get)(struct klist_node *);

         void                    (*put)(struct klist_node *);

};

struct klist_node {

         struct klist            *n_klist;

         struct list_head        n_node;

         struct kref             n_ref;

         struct completion       n_removed;

};

這 是最底層的數(shù)據(jù)結(jié)構(gòu)了,你可以把它們當(dāng)作“基類”,基類在面向?qū)ο蟮乃枷胫芯褪鞘裁匆膊蛔鰞H僅提供接口的類,它們更實(shí)質(zhì)的意義是為管理設(shè)備提供了一個(gè)切入 點(diǎn),這些數(shù)據(jù)結(jié)構(gòu)主要是為了給上層一個(gè)統(tǒng)一的操作視圖,不管是內(nèi)核本身使用還是用戶使用,可以參看sysfs,這樣用戶端的操作就靠kobject搞定 了,內(nèi)核的操作就靠klist搞定。接下來設(shè)備本身怎么管理呢?所有的設(shè)備被分為“類”,叫class,比如一塊via的聲卡和一塊realtek的聲卡 就屬于一個(gè)類,余下的就是一堆鏈表了,一條總線有兩個(gè)重要鏈表,一條掛載所有設(shè)備,一條掛載所有驅(qū)動(dòng),類也有一個(gè)鏈表,掛載屬于這個(gè)類的設(shè)備,所有的類串 成串,所有的總線也串成串,不要以為操作系統(tǒng)多復(fù)雜,基本就是一堆鏈表,那些在書上看到的十分牛叉的算法在內(nèi)核基本是見不到的,作為一個(gè)統(tǒng)一的管理者,內(nèi) 核數(shù)據(jù)結(jié)構(gòu)和算法要在維護(hù)開銷,自身開銷,綜合性能之間找到一個(gè)平衡點(diǎn),比如說你把大量的技巧用到了內(nèi)核的設(shè)備管理上了,那么結(jié)果有二,不是浪費(fèi)空間就是 浪費(fèi)時(shí)間,只要你有規(guī)則有技巧,規(guī)則和技巧越復(fù)雜你為之付出的代價(jià)就越大,這是個(gè)真理,結(jié)果用戶的資源全被內(nèi)核耗盡了,主次不分,因果倒置。
先看一下這一切是如何串起來的。

int device_add(struct device *dev)

{

         struct device *parent = NULL;

         struct class_interface *class_intf;

         int error = -EINVAL;

...

         parent = get_device(dev->parent);

         setup_parent(dev, parent);

         if (parent)//下面的設(shè)置時(shí)第二條線索相關(guān)的

                 set_dev_node(dev, dev_to_node(parent));

         //設(shè)置第一條線索,這是個(gè)基礎(chǔ),一切從kobject開始

         error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id);

...

...

         //設(shè)置第一條線索,加入一個(gè)事件屬性文件,以便用戶空間寫入數(shù)據(jù)可以觸發(fā)內(nèi)核的一些動(dòng)作

         error = device_create_file(dev, &uevent_attr);

...      //設(shè)置第一條線索,加入其它屬性文件,以便用戶空間可以讀取或更改設(shè)備的屬性

         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;

         }

         //設(shè)置第一條線索,設(shè)備所屬的類被導(dǎo)入sysfs,此處正是將設(shè)備加入sysfs的相應(yīng)類

         error = device_add_class_symlinks(dev);

         if (error)

                 goto SymlinkError;

         error = device_add_attrs(dev);//設(shè)置第一條線索,將sysfs的類信息鏈入本設(shè)備

         if (error)

                 goto AttrsError;

         error = bus_add_device(dev);  //設(shè)置第一條線索,將sysfs的總線信息鏈入本設(shè)備

         if (error)

                 goto BusError;

         error = dpm_sysfs_add(dev);  

         if (error)

                 goto DPMError;

...

         kobject_uevent(&dev->kobj, KOBJ_ADD);

         bus_attach_device(dev);    //設(shè)置第二條線索,在總線上加入設(shè)備

         if (parent)//設(shè)置第二條線索,將父子關(guān)系確定

                 klist_add_tail(&dev->knode_parent, ∥ent->klist_children);

         if (dev->class) {//設(shè)置第二條線索,將本設(shè)備加入相應(yīng)的類別

                 mutex_lock(&dev->class->p->class_mutex);

                 /* tie the class to the device */

                 list_add_tail(&dev->node, &dev->class->p->class_devices);

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

         }

...

}

第二條線索的關(guān)鍵操作就是bus_attach_device 了,它本質(zhì)上就是把本設(shè)備加入它所屬總線的klist,然后總線會(huì)遍歷它的另一個(gè)klist驅(qū)動(dòng)鏈表來尋找能驅(qū)動(dòng)本設(shè)備的驅(qū)動(dòng)程序,如果找到便開始 probe本設(shè)備。相應(yīng)的在driver_register的時(shí)候會(huì)將driver加入bus的driver鏈表,然后遍歷設(shè)備鏈表看它能驅(qū)動(dòng)哪些設(shè)備, 要注意的是,雖然device和driver在bus的角度看是如此對(duì)稱,實(shí)際上它們是不對(duì)稱的,因?yàn)閐evice才是我們要管理的對(duì)象,driver的 出現(xiàn)就是為了我們的設(shè)備可以工作,所以代碼中driver_register遠(yuǎn)遠(yuǎn)沒有device_register復(fù)雜,因?yàn)樗恍枰O(shè)置第一條線索和 部分第二條線索就可以了。
在下一步就是沿著各自的線索開始一步一步前進(jìn)了,我就不再分析了,最好的辦法就是讀源代碼,源代碼本身的更改變動(dòng)很 大,比如2.6.18版本有一個(gè) class_eevice,為了設(shè)備分類,但是這是多余的,所以后面的版本將其去除了,所以分析源碼并不難,關(guān)鍵是沒有意義,實(shí)質(zhì)性的東西不變,就是那兩 條線索,關(guān)于怎么實(shí)現(xiàn)卻一直在變動(dòng),我都懶得跟蹤了。關(guān)鍵問題,作者怎么想到這些的。
首先,要知道管理設(shè)施和被管理對(duì)象一定要分離,不要有任何 雙向關(guān)系,單向關(guān)系一定要保持一個(gè),這就是著名的“好萊塢法則”,比如,klist永遠(yuǎn)不知道自己的屬主是個(gè)設(shè)備還是個(gè)驅(qū)動(dòng),但是不管設(shè)備還是驅(qū)動(dòng)都要有 若干klist,想想看如果klist里面有一個(gè)設(shè)備寄存器信息,那就麻煩了,驅(qū)動(dòng)就必須另實(shí)現(xiàn) 一套機(jī)制,然后考慮如何和帶有寄存器信息的klist通信,事情會(huì)越來越糟糕。于是將設(shè)備和驅(qū)動(dòng)還有總線結(jié)構(gòu)提取公因子,再考慮它們需要什么樣的操作,當(dāng) 想到它們僅僅需要簡(jiǎn)單的鏈接關(guān)系的時(shí)候,klist就出來了,但是用戶這邊就沒有那么簡(jiǎn)單了,用戶需要的不是一個(gè)簡(jiǎn)單的鏈接關(guān)系,而是一個(gè)樹形結(jié)構(gòu),于是 kobject和kset就出來了,這就是一切。
其實(shí)內(nèi)核中處處在用這種方式來管理信息,著名的list_head就不說了,另外還有prio_tree,rb_tree等等都是。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多