乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      談談linux2.6內(nèi)核的驅(qū)動框架

       rookie 2012-08-06

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

      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;

      };

      再看看第二條線索的基礎設施:

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

                       set_dev_node(dev, dev_to_node(parent));

               //設置第一條線索,這是個基礎,一切從kobject開始

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

      ...

      ...

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

               error = device_create_file(dev, &uevent_attr);

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

               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;

               }

               //設置第一條線索,設備所屬的類被導入sysfs,此處正是將設備加入sysfs的相應類

               error = device_add_class_symlinks(dev);

               if (error)

                       goto SymlinkError;

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

               if (error)

                       goto AttrsError;

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

               if (error)

                       goto BusError;

               error = dpm_sysfs_add(dev);  

               if (error)

                       goto DPMError;

      ...

               kobject_uevent(&dev->kobj, KOBJ_ADD);

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

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

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

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

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

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

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多