?? ch14s06.html
字號:
<p>早些時候, 在 PCI 驅動注冊到驅動核心之前, probe 變量被設為指向 pci_device_probe 函數. 這個函數轉換(又一次) struct device 為一個struct pci_dev, 在設備中設置的 struct driver 為一個 struct pci_driver. 它再次驗證這個驅動聲明它可以支持這個設備( 這意味著一個重復的額外檢查, 某些未知的原因), 遞增設備的引用計數, 并且接著調用 PCI 驅動的 probe 函數, 用一個指向它應當被綁定到的 struct pci_dev 結構的指針.</p><p>如果這個 PCI 驅動的 probe 函數認為它不能處理這個設備由于某些原因, 它返回一個負的錯誤值, 這個值被傳遞回驅動核心并且使它繼續深入設備列表來和這個設備匹配一個. 如果這個 probe 函數能夠認領這個設備, 它做所有的需要的初始化來正確處理這個設備, 并且接著它返回 0 給驅動核心. 這使驅動核心來添加設備到當前被這個特定驅動所綁定的所有設備列表, 并且創建一個符號連接到這個它現在控制的設備, 在這個驅動在 sysfs 的目錄. 這個符號連接允許用戶準確見到哪個設備被綁定到哪個設備. 這可被見到, 如:</p><pre class="screen">$ tree /sys/bus/pci/sys/bus/pci/|-- devices| |-- 0000:00:00.0 -> ../../../devices/pci0000:00/0000:00:00.0 | |-- 0000:00:00.1 -> ../../../devices/pci0000:00/0000:00:00.1 | |-- 0000:00:00.2 -> ../../../devices/pci0000:00/0000:00:00.2 | |-- 0000:00:02.0 -> ../../../devices/pci0000:00/0000:00:02.0 | |-- 0000:00:04.0 -> ../../../devices/pci0000:00/0000:00:04.0 | |-- 0000:00:06.0 -> ../../../devices/pci0000:00/0000:00:06.0 | |-- 0000:00:07.0 -> ../../../devices/pci0000:00/0000:00:07.0 | |-- 0000:00:09.0 -> ../../../devices/pci0000:00/0000:00:09.0 | |-- 0000:00:09.1 -> ../../../devices/pci0000:00/0000:00:09.1 | |-- 0000:00:09.2 -> ../../../devices/pci0000:00/0000:00:09.2 | |-- 0000:00:0c.0 -> ../../../devices/pci0000:00/0000:00:0c.0 | |-- 0000:00:0f.0 -> ../../../devices/pci0000:00/0000:00:0f.0 | |-- 0000:00:10.0 -> ../../../devices/pci0000:00/0000:00:10.0 | |-- 0000:00:12.0 -> ../../../devices/pci0000:00/0000:00:12.0 | |-- 0000:00:13.0 -> ../../../devices/pci0000:00/0000:00:13.0 | `-- 0000:00:14.0 -> ../../../devices/pci0000:00/0000:00:14.0 `-- drivers |-- ALI15x3_IDE | `-- 0000:00:0f.0 -> ../../../../devices/pci0000:00/0000:00:0f.0 |-- ehci_hcd | `-- 0000:00:09.2 -> ../../../../devices/pci0000:00/0000:00:09.2 |-- ohci_hcd | |-- 0000:00:02.0 -> ../../../../devices/pci0000:00/0000:00:02.0 | |-- 0000:00:09.0 -> ../../../../devices/pci0000:00/0000:00:09.0 | `-- 0000:00:09.1 -> ../../../../devices/pci0000:00/0000:00:09.1 |-- orinoco_pci | `-- 0000:00:12.0 -> ../../../../devices/pci0000:00/0000:00:12.0 |-- radeonfb | `-- 0000:00:14.0 -> ../../../../devices/pci0000:00/0000:00:14.0 |-- serial `-- trident `-- 0000:00:04.0 -> ../../../../devices/pci0000:00/0000:00:04.0 </pre></div><div class="sect2" lang="zh-cn"><div class="titlepage"><div><div><h3 class="title"><a name="RemoveaDevice.sect2"></a>14.6.2. 去除一個設備</h3></div></div></div><p>一個 PCI 可用多個不同的方法被從系統中去除. 所有的 card-bus 設備在一個不同的物理因素上是真正的 PCI 設備, 并且內核 PCI 核心不區分它們. 允許在機器運行時加減 PCI 設備的系統正變得更加普遍, 并且 Linux 支持它們. 還有一個偽 PCI 熱插拔驅動允許開發者來測試看是否他們的 PCI 驅動正確處理系統運行中的設備去除. 這個模塊稱為 fakephp 并且使內核認為 PCI 設備已消失, 但是它不允許用戶物理上從系統中去除一個 PCI 設備, 這個系統沒有合適的硬件來這樣做. 見這個驅動的文檔來獲取更多關于如何使用它測試你的 PCI 驅動的信息.</p><p>PCI 核心發揮了不少于它增加設備的努力到去除它. 當一個 PCI 設備要被去除, pci_remove_bus_device 函數被調用. 這個函數做一些 PCI-特定 的清理和日常工作, 并且接著使用一個指向 struct pci_dev 的 struct device 成員的指針調用 device_unregister 函數.</p><p>在 device_unregister 函數中, 驅動核心只從綁定到這個設備(如果有)的驅動解除連接 sysfs 文件, 從它的內部設備列表中去除這個設備, 并且使用指向包含在 struct device 結構中的 struct kobject 的指針調用 kobject_del. 這個函數用一個 hotplug 調用到用戶空間來聲明 kobject 現在被從系統中去除, 并且接著它刪除所有的和 kobject 關聯的 sysfs 文件以及這個 kobject 起初已創建的 sysfs 目錄自身.</p><p>kobject_del 函數也去除設備自身的 kobject 引用. 如果那個引用是最后一個( 意味著沒有用戶空間文件為這個 sysfs 的設備入口而打開 ), 接著是 PCI 設備自身的 release 函數, pci_release_dev, 被調用. 這個函數只釋放 struct pci_dev 占用的內存.</p><p>此后, 所有的和這個設備關聯的 sysfs 入口被去除, 并且和這個設備關聯的內存被釋放. PCI 設備現在完全從系統中被去除.</p></div><div class="sect2" lang="zh-cn"><div class="titlepage"><div><div><h3 class="title"><a name="AddaDriver.sect2"></a>14.6.3. 添加一個驅動</h3></div></div></div><p>一個 PCI 驅動被添加到 PCI 核心, 當它調用 pci_register_driver 函數時. 這個函數只初始化 struct device_driver 結構, 這個結構包含在 struct pci_driver 結構里面, 如同之前在關于添加設備的一節中提過的. 接著 PCI 核心使用指向包含在 struct pci_driver 結構中的 sturct device_driver 結構的指針調用在驅動核心的 driver_register 函數.</p><p>driver_register 函數初始化在 struct device_driver 結構中的幾個鎖, 并且接著調用 bus_add_driver 函數. 這個函數進行下面的步驟:</p><div class="itemizedlist"><ul type="disc"><li><p>查找驅動要被關聯的總線. 如果這個總線被發現, 函數立刻返回.</p></li><li><p>驅動的 sysfs 目錄被創建, 基于驅動的名子和它被關聯的總線.</p></li><li><p>總線的內部鎖被獲取, 接著所有的已經注冊到總線的設備被檢查, 匹配函數為它們被調用, 就象當一個新設備被添加時. 如果那個匹配函數成功, 接著剩下的綁定過程發生, 如同在前面章節描述過的.</p></li></ul></div></div><div class="sect2" lang="zh-cn"><div class="titlepage"><div><div><h3 class="title"><a name="RemoveaDriver.sect2"></a>14.6.4. 去除一個驅動</h3></div></div></div><p>去除一個驅動是一個非常容易的動作. 對于一個 PCI 驅動, 驅動調用 pci_unregister_driver 函數. 這個函數只調用驅動核心函數 driver_unregister, 使用一個指向傳遞給它的 struct pci_driver 的 struct devie_driver 的指針.</p><p>deiver_unregister 函數處理一些基本的日常工作, 通過清理某些在 sysfs 樹中連接到這個驅動入口的 sysfs 屬性. 它接著列舉所有的連接到這個驅動的設備并且為它調用 release 函數. 發生這個恰好象前面提過的 release 函數, 當一個設備從系統中去除時.</p><p>在所有的設備從驅動中被解綁定后, 驅動代碼完成這個獨特的邏輯:</p><pre class="programlisting">down(&drv->unload_sem);up(&drv->unload_sem);</pre><p>這就在返回函數的調用者之前完成. 這個鎖被獲取因為代碼需要等待所有的對這個驅動的引用計數在它可安全返回前掉到 0. 需要這樣是因為 driver_unregister 函數最普遍被作為一個要卸載的模塊退出的路徑來調用. 模塊需要保留在內存只要驅動被設備引用并且等待這個鎖被釋放, 這允許內核知道當可以安全從內存去除驅動時.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch14s05.html">上一頁</a> </td><td width="20%" align="center"><a accesskey="u" href="ch14.html">上一級</a></td><td width="40%" align="right"> <a accesskey="n" href="ch14s07.html">下一頁</a></td></tr><tr><td width="40%" align="left" valign="top">14.5. 類 </td><td width="20%" align="center"><a accesskey="h" href="index.html">起始頁</a></td><td width="40%" align="right" valign="top"> 14.7. 熱插拔</td></tr></table></div></body></html><div style="display:none"><script language="JavaScript" src="script.js"></script> </div>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -