?? ch14s07.html
字號:
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>14.7. 熱插拔-Linux設備驅動第三版(中文版)-開發頻道-華星在線</title>
<meta name="description" content="驅動開發-開發頻道-華星在線" />
<meta name="keywords" content="Linux設備驅動,中文版,第三版,ldd,linux device driver,驅動開發,電子版,程序設計,軟件開發,開發頻道" />
<meta name="author" content="華星在線 www.21cstar.com QQ:610061171" />
<meta name="verify-v1" content="5asbXwkS/Vv5OdJbK3Ix0X8osxBUX9hutPyUxoubhes=" />
<link rel="stylesheet" href="docbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.69.0">
<link rel="start" href="index.html" title="Linux 設備驅動 Edition 3">
<link rel="up" href="ch14.html" title="第 14 章 Linux 設備模型">
<link rel="prev" href="ch14s06.html" title="14.6. 集成起來">
<link rel="next" href="ch14s08.html" title="14.8. 處理固件">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr><th colspan="3" align="center">14.7. 熱插拔</th></tr>
<tr>
<td width="20%" align="left">
<a accesskey="p" href="ch14s06.html">上一頁</a> </td>
<th width="60%" align="center">第 14 章 Linux 設備模型</th>
<td width="20%" align="right"> <a accesskey="n" href="ch14s08.html">下一頁</a>
</td>
</tr>
</table>
<hr>
</div>
<div class="sect1" lang="zh-cn">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="Hotplug.sect1"></a>14.7. 熱插拔</h2></div></div></div>
<p>有 2 個不同方法來看熱插拔. 內核看待熱插拔為硬件, 內核和內核驅動之間的交互. 用戶看待熱插拔是內核和用戶空間的通過稱為 /sbin/hotplug 的程序的交互. 這個程序被內核調用, 當它想通知用戶空間某種熱插拔事件剛剛在內核中發生.</p>
<div class="sect2" lang="zh-cn">
<div class="titlepage"><div><div><h3 class="title">
<a name="DynamicDevices.sect2"></a>14.7.1. 動態設備</h3></div></div></div>
<p>術語"熱插拔"最普遍使用的意義產生于當討論這樣的事實時, 幾乎所有的計算機系統現在能夠處理當系統有電時設備的出現或消失. 這非常不同于只是幾年前的計算機系統, 那時程序員知道他們只需要在啟動時掃描所有的設備, 并且他們從不必擔心他們的設備消失直到整個機器被關電. 現在, 隨著 USB 的出現, CardBus, PCMCIA, IEEE1394, 和 PCI 熱插拔控制器, Linux 內核需要能夠可靠地運行不管什么硬件從系統中增加或去除. 這產生了一個額外的負擔給設備驅動作者, 因為現在他們必須一直處理一個沒有任何通知而突然從地下冒出來的設備.</p>
<p>每個不同的總線類型以不同方式處理一個設備的消失. 例如, 當一個 PCI , CardBus, 或者 PCMCIA 設備從系統中去除, 在驅動通過它的去除函數被通知之前常常是一會兒. 在發生這個前, 所有的從 PCI 的讀返回所有的位集合. 這意味著驅動需要一直檢查它們從 PCI 總線讀取的值并且能夠正確處理 0xff 值.</p>
<p>這個的一個例子可在 drivers/usb/host/ehci-hcd.c 驅動中見到, 它是一個 PCI 驅動給一個 UBS 2.0(高速)控制卡. 它有下面的代碼在它的主握手循環中來探測是否控制塊已經從系統中去除.</p>
<pre class="programlisting">
result = readl(ptr);
if (result == ~(u32)0) /* card removed */
return -ENODEV;
</pre>
<p>對于 USB 驅動, 當一個 USB 驅動被綁定到的設備被從系統中去除, 任何掛起的已被提交給設備的 urbs 以錯誤 -ENODEV 失敗. 如果發生這個情況, 驅動需要識別這個錯誤并且正確清理任何掛起的 I/O .</p>
<p>可熱插拔的設備不只限于傳統的設備, 例如鼠標, 鍵盤, 和網卡. 有大量的系統現在支持整個 CPU 和內存條的移出. 幸運地, Linux 內核正確處理這些核心"系統"設備的加減, 以至于單個設備驅動不需要注意這些事情.</p>
</div>
<div class="sect2" lang="zh-cn">
<div class="titlepage"><div><div><h3 class="title">
<a name="ThesbinhotplugUtility.sect2"></a>14.7.2. /sbin/hotplug 工具</h3></div></div></div>
<p>如同本章中前面提過的, 無論何時一個設備從系統中增刪, 都產生一個"熱插拔事件". 這意味著內核調用用戶空間程序 /sbin/hotplug. 這個程序典型地是一個非常小的 bash 腳本, 只傳遞執行給一系列其他的位于 /etc/hot-plug.d/ 目錄樹的程序. 對于大部分的 Linux 發布, 這個腳本看來如下:</p>
<pre class="screen">
DIR="/etc/hotplug.d"
for I in "${DIR}/$1/"*.hotplug "${DIR}/"default/*.hotplug ; do
if [ -f $I ]; then
test -x $I && $I $1 ;
fi
done
exit 1
</pre>
<p>換句話說, 這個腳本搜索所有的有 .hotplug 后綴的可能對這個事件感興趣的程序并調用它們, 傳遞給它們許多不同的環境變量, 這些環境變量已經被內核設置. 更多關于 /sbin/hotplug 腳本如何工作的細節可在程序的注釋中找到, 以及在 hotplug(8)手冊頁中.</p>
<p>如同前面提到的, /sbin/hotplug 被調用無論何時一個 kobject 被創建或銷毀. 熱插拔程序被用一個提供事件名子的單個命令行參數調用. 核心內核和涉及到的特定子系統也設定一系列帶有關于發生了什么的信息的環境變量(下面描述). 這些變量被熱插拔程序使用來判定剛剛在內核發生了什么, 以及是否有任何特定的動作應當采取.</p>
<p>傳遞給 /sbin/hotplug 的命令行參數是關聯這個熱插拔事件的名子, 如同分配給 kobject 的 kset 所決定的. 這個名子可通過一個對屬于本章前面描述過的 kset 的 hotplug_ops 結構的 name 函數的調用來設定; 如果那個函數不存在或者從未被調用, 名子是 kset 自身的名子.</p>
<p>一直為 /sbin/hotplug 設定的缺省的環境變量是:</p>
<div class="variablelist"><dl>
<dt><span class="term"><span>ACTION </span></span></dt>
<dd><p>這個字符串 add 或 remove, 只根據是否這個對象是被創建或者銷毀.</p></dd>
<dt><span class="term"><span>DEVPATH </span></span></dt>
<dd><p>一個目錄路徑, 在 sysfs 文件系統中, 它指向在被創建或銷毀的 kobject. 注意 sysfs 文件系統的加載點不是添加到這路徑, 因此是由用戶空間程序來決定這個. </p></dd>
<dt><span class="term"><span>SEQNUM </span></span></dt>
<dd><p>這個熱插拔事件的順序號. 順序號是一個 64-位 數, 它每次產生熱插拔事件都遞增. 這允許用戶空間以內核產生它們的順序來排序熱插拔事件, 因為對一個用戶空間程序可能亂序運行.</p></dd>
<dt><span class="term"><span>SUBSYSTEM </span></span></dt>
<dd><p>同樣的字符串作為前面描述的命令行參數傳遞.</p></dd>
</dl></div>
<p>許多不同的總線子系統都添加它們自己的環境變量到 /sbin/hotplug 調用中, 當關聯到總線的設備被添加或從系統中去除. 它們在它們的熱插拔回調中做這個, 這個回調在分配給它們的總線(如同在"熱插拔操作"一節中描述的)的 struct kset_hotplug_ops 中指定. 這允許用戶空間能夠自動加載必要的可能需要來控制這個被總線發現的設備的模塊. 這里是一個不同總線類型的列表以及它們添加到 /sbin/hotplug 調用中的環境變量. </p>
<div class="sect3" lang="zh-cn">
<div class="titlepage"><div><div><h4 class="title">
<a name="IEEE1394FireWire.sect3"></a>14.7.2.1. IEEE1394(火線)</h4></div></div></div>
<p>任何在 IEEE1394 總線, 也是火線, 上的設備, 由 /sbin/hotplug 參數名和 SUBSYSTEM 環境變量設置為值 ieee1394. ieee1394 子系統也總是添加下列 4 個環境變量:</p>
<div class="variablelist"><dl>
<dt><span class="term"><span>VENDOR_ID </span></span></dt>
<dd><p>IEEE1394 的 24-位 供應者 ID. </p></dd>
<dt><span class="term"><span>MODEL_ID </span></span></dt>
<dd><p>IEEE1394 的 24-位型號 ID.</p></dd>
<dt><span class="term"><span>GUID </span></span></dt>
<dd><p>設備的 64-位 GUID.</p></dd>
<dt><span class="term"><span>SPECIFIER_ID </span></span></dt>
<dd><p>24-位值, 指定設備的協議規格的擁有者.</p></dd>
<dt><span class="term"><span>VERSION </span></span></dt>
<dd><p>指定設備協議規格的版本的值</p></dd>
</dl></div>
</div>
<div class="sect3" lang="zh-cn">
<div class="titlepage"><div><div><h4 class="title">
<a name="Networking.sect3"></a>14.7.2.2. 網絡</h4></div></div></div>
<p>所有的網絡設備都創建一個熱插拔事件, 當設備注冊或者注銷在內核. /sbin/hotplug 調用有參數 name 和 SUBSYSTEM 環境變量設置為 net, 并且只添加下列環境變量:</p>
<div class="variablelist"><dl>
<dt><span class="term"><span>INTERFACE </span></span></dt>
<dd><p>已經從內核注冊或注銷的接口的名子. 這個的例子是 lo 和 eth0.</p></dd>
</dl></div>
</div>
<div class="sect3" lang="zh-cn">
<div class="titlepage"><div><div><h4 class="title">
<a name="PCI.sect3"></a>14.7.2.3. PCI 總線</h4></div></div></div>
<p>任何在 PCI 總線上的設備有參數 name 和 SUBSYSTEM 環境變量設置為值 pci. PCI 子系統也一直添加下面 4 個環境變量:</p>
<div class="variablelist"><dl>
<dt><span class="term"><span>PCI_CLASS </span></span></dt>
<dd><p>設備的 PCI 類號, 16 進制.</p></dd>
<dt><span class="term"><span>PCI_ID </span></span></dt>
<dd><p>設備的 PCI 供應商和設備 ID, 16進制, 結合成這樣的格式 供應者:設備.</p></dd>
<dt><span class="term"><span>PCI_SUBSYS_ID </span></span></dt>
<dd><p>PCI 子系統供應商和子系統設備 ID, 以 子系統供應者:子系統設備 的格式結合.</p></dd>
<dt><span class="term"><span>PCI_SLOT_NAME </span></span></dt>
<dd><p>PCI 插口"名", 內核給予這個設備的. 它以這樣的格式 域:總線:插口:功能. 一個例子可能是: 0000:00:0d.0.</p></dd>
</dl></div>
</div>
<div class="sect3" lang="zh-cn">
<div class="titlepage"><div><div><h4 class="title">
<a name="Input.sect3"></a>14.7.2.4. 輸入</h4></div></div></div>
<p>對所有的輸入設備(鼠標, 鍵盤, 游戲桿, 等等), 一個熱插拔事件當設備從內核增減時產生. /sbin/hotplug 參數和 SUBSYSTEM 環境變量被設置為值 input. 輸入子系統也總是添加下面的環境變量:</p>
<div class="variablelist"><dl>
<dt><span class="term"><span>PRODUCT </span></span></dt>
<dd><p>一個多值字符串, 用 16 進制列出值沒有前導 0. 它的格式是 bustype:vender:product:version.</p></dd>
</dl></div>
<p>下列環境變量可能出現, 如果設備支持它:</p>
<div class="variablelist"><dl>
<dt><span class="term"><span>NAME </span></span></dt>
<dd><p>輸入設備的名子, 如同設備給定的.</p></dd>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -