デバイスが sysfs に現れていても、ドライバがバインドされていないことがあります。また、ドライバのアンバインド後、デバイスオブジェクトがまだ参照されている可能性があります。デバイスモデルを読む際には、検出、マッチング、機能登録、そして最終的な解放 の各段階に焦点を当てて確認する必要があります。
確認目標 読むべき箇所
オブジェクトと probe 第 1~2 節
参照と managed リソース 第 3 節
ユーザ空間のビューと読み取り専用実験 第 4~5 節
1. 4つのオブジェクトがそれぞれ解決する問題
オブジェクト 問われる問題 例
deviceこれはどのデバイスか、親デバイスは誰か、どのようなリソースがあるか? 1つのPCI function、1つのUSB interface
device_driverそれを操作できるのはどの実装か? PCIネットワークカード用ドライバ、USBシリアル用ドライバ
bus_typeデバイスとドライバをどのように発見し、マッチングさせ、整理するか? PCI、USB、platform
classユーザはどのような機能の観点からデバイスを探すか? net、block、tty
バスとクラスは異なる視点です。PCIネットワークカードはまずPCIバス上のデバイスであり、そのネットワークインターフェースはネットワークサブシステムを通じて機能オブジェクトを提供します。/sys/class/net/eth0 を単なるPCIデバイスオブジェクトの別名として扱うことはできません。1つの物理デバイスが複数の機能オブジェクトを公開することもあります。
kobject はより低レベルな命名、階層、参照カウントの基盤であり、device はこれを内包しています。kset は関連する kobject を整理し、イベント管理にも参加します。これらはバスモデルを代替するドライバインターフェースのセットではありません。通常、既存のサブシステムが提供する device API を使用すべきであり、ドライバのために独自に kobject ツリーを構築すべきではありません。
カーネル構造体はバージョンによって変化します。include/linux/device.h、include/linux/kobject.h を読む際には、メンバの役割に注目してください。kobject.sd は kernfs ノードを指しており、VFS の dentry ではありません。オブジェクトの最終的な解放は release コールバックとそのコンテナ管理に依存しており、参照カウントがゼロになっても、外側の構造体をどのように解放すべきかを自動的に推測することはできません。
2. ハードウェア情報から probe へ
発見、バインド、解放は3つの異なる段階
デバイス登録
列挙またはファームウェア記述
バスマッチング
ID / compatible / HID
ドライバ登録
ビルトインまたはモジュールロード
probe:リソースの取得と初期化
依存関係が未準備の場合はプローブを遅延可能
デバイスがサブシステムで利用可能に
remove:停止とアンバインド
最後の参照解放でオブジェクト解放
アンバインドは即時解放を意味しません。sysfs で見えるからといって、デバイスが利用可能であるとは限りません。
デバイスが先に登録されても、ドライバが先に登録されても、マッチングをトリガーできます。バスがマッチングルールを担当します。PCI では通常 vendor/device/class が使用され、USB ではデバイスまたはインターフェース記述子によるマッチングが可能です。platform ドライバはファームウェアマッチングテーブルなどの経路でマッチングできます。
match は候補ドライバがデバイスをサポートする可能性があることを示すだけです。probe ではさらに、クロック、電源、レジスタ、割り込みなどのリソースを取得し、ハードウェアを初期化し、機能サブシステムに登録する必要があります。どの段階でも失敗した場合、実行中の半初期化状態のデバイスを残してはいけません。
regulator、clock、またはその他のサプライヤがまだ準備できていない場合は、-EPROBE_DEFER を返すことができます。コアは後で条件が満たされたときに再試行します。これは依存関係が一時的に不足していることを示すものであり、永久的にサポートされていないハードウェアやエラーパラメータを隠すために使用してはいけません。デバイスのリンクはサプライヤ/コンシューマ関係を表現し、プローブと電源管理の順序に影響を与えます。
遅延プローブは初期化の再試行であり、半分の初期化の継続ではない
センサーのコンシューマが列挙されているが、それが参照する電源レギュレータのドライバがまだ登録を完了していないとします。最初の probe でプライベートコンテキストが構築されていた場合、レギュレータの取得時に -EPROBE_DEFER が返されることがあります。この probe では、現在の試行で確保されたリソースを退出してクリーンアップする必要があります。依存関係の変化によって再度プローブが行われる際には、一貫した未バインドの状態から再開する必要があります。
時点 コンシューマの状態 本次試行のリソース
列挙済み、未プローブ デバイスは存在するが未バインド 成功したドライバインスタンスなし
最初の probe でサプライヤ取得失敗 EPROBE_DEFER を返し、バインドはまだ完了していない 本次の managed リソースを回収し、手動リソースも処理する必要がある
サプライヤが後で準備完了 後続のプローブパスをトリガー可能 以前のプライベートバッファがまだ有効であると仮定してはならない
後続の probe 成功 ドライババインドと機能登録を完了 新しい試行のリソースはアンバインドまで保持される
したがって、probe ログが繰り返し表示されるのは依存関係の再試行である可能性があり、必ずしもデバイスが複数回列挙されたわけではありません。逆に、誤ったファームウェアパラメータやサポートされていないデバイスを一律に EPROBE_DEFER に書き換えると、実際のエラーが永遠に依存関係が不足しているように見えてしまいます。ドライバはリソースAPIのエラー意味を保持し、デバイスリンク、遅延理由、および元の戻り値を組み合わせて特定する必要があります。初期化の順序が偶然成立するように固定の sleep 時間を追加してはいけません。
ファームウェア記述とバス列挙の連携
Device Tree :アドレス、割り込み、クロック、デバイス接続などの情報を記述し、compatible は互換性のあるインターフェースを示します。ARM、RISC-V で一般的ですが、これらのアーキテクチャに固有の形式ではありません。
ACPI :デバイスID、リソース、電源管理方法などを提供します。x86 で一般的ですが、arm64 サーバーでも ACPI が使用されます。
PCI/USB 列挙 :バスプロトコルを通じてデバイスを見つけ、ID を読み取ります。PCI ルートブリッジ、設定空間アクセス方法、割り込みルーティングなどは、ACPI や DT に依存する可能性があり、「自己列挙であれば完全にファームウェア記述を必要としない」と一般化することはできません。
platform bus は、これらのバスプロトコルで自己列挙できないオンチップデバイスに一般的に使用されます。platform device はデバイスモデル内の実際のオブジェクトであり、ハードウェアが模擬されていることを意味するものではありません。DT ノードがすべて platform device に変換されるわけではなく、ノードが存在するバスがインスタンス化方法を決定します。
3. オブジェクトの寿命とドライババインドの寿命
get_device() / put_device() はデバイスの参照を管理します。device_unregister() は登録を取り消し、登録者の参照を解放します。まだ参照が残っている場合、オブジェクトは存続し続け、最後の put のみで最終的な解放に入ります。
境界 終了するのは何か
remove ドライバサービスとバインド関係
release デバイスオブジェクト自体のメモリ寿命
参照が残っている オブジェクトのメモリが存続し続けることを示すだけ
参照は、取り外されたハードウェアをオンラインに戻すものでもなく、レジスタにアクセスできることを保証するものでもありません。
device_register() には初期化と追加のステップが含まれます。登録に失敗した場合でも、呼び出し元は通常、初期化によって取得した参照を返すために put_device() が必要であり、デバイスモデル管理に渡されたオブジェクトを安易に kfree() してはいけません。具体的なコンテナの割り当てと release ルールは、所属するサブシステムに従うべきです。
struct device を守っても、ドライバのプライベートデータまでは守れない
登録者がデバイスの参照を保持し、非同期利用者がさらに参照を取得しているとします。ドライバのアンバインド時、devm によるプライベートメモリは解放される可能性がありますが、非同期利用者が保持している device 参照によりデバイスオブジェクト自体は存続し続けます。非同期利用者が古い drvdata ポインタを保存し、その後で間接参照を行うと、すでに解放されたドライバデータにアクセスしてしまう可能性があります。
参照はデバイスオブジェクトを保護するが、アンバインドされたドライバリソースの寿命を延ばすことはできない
バインド中
アンバインド完了
登録取消
最後の put
参照 2
プライベートデータ有効
参照 2
プライベートデータ解放済み
参照 1
オブジェクトは存続中
参照 0
release 実行
古い drvdata ポインタは、device 参照を保持し続けていても有効になり続けるわけではない
これは登録者と外部保持者のみを示しており、カーネル内部の他の一時参照は含んでいません。
以下では、登録者と1つの外部保持者の参照のみをカウントし、カーネル内部のすべての一時参照を再現しません。状態モデルは、登録、バインド、プライベートリソース、オブジェクト解放を分離しており、どの保証がどのステップで終了するかを観察しやすくしています。
class Device :
def __init__ ( self ) :
self . refs = 1 self . registered = False
self . bound = False
self . private_live = False
self . releases = 0
def get_from_live_reference ( self ) :
if self . refs == 0 :
raise RuntimeError ( " 解放済みのオブジェクトを復活させることはできない" )
self . refs += 1
def put ( self ) :
assert self . refs > 0
self . refs -= 1
if self . refs == 0 :
assert not self . registered and not self . bound
self . releases += 1
def add_and_bind ( self ) :
assert self . refs > 0 and not self . registered
self . registered = self . bound = self . private_live = True
def unbind ( self ) :
assert self . bound
self . bound = False
self . private_live = False
def unregister ( self ) :
assert self . registered
if self . bound :
self . unbind ( )
self . registered = False
self . put ( )
def io ( self ) :
if not self . bound or not self . private_live :
raise RuntimeError ( " オブジェクト参照は、ドライバがまだサービスを提供できることを意味しない" )
return " ok"
dev = Device ( )
dev . add_and_bind ( )
dev . get_from_live_reference ( )
assert dev . refs == 2 and dev . io ( ) == " ok"
dev . unbind ( )
assert dev . registered and dev . refs == 2 and not dev . private_live
try :
dev . io ( )
except RuntimeError :
pass
else :
raise AssertionError ( " アンバインド後、参照に依存してドライバにアクセスすることはできない" )
dev . unregister ( )
assert dev . refs == 1 and dev . releases == 0
dev . put ( ) assert dev . refs == 0 and dev . releases == 1
try :
dev . get_from_live_reference ( )
except RuntimeError :
pass
else :
raise AssertionError ( " 終了したライフサイクルを get で再開することはできない" )
failed_add = Device ( ) failed_add . put ( )
assert failed_add . releases == 1
実際の get_device() は参照操作のみを行い、呼び出し元に代わって、すでに無効になっている可能性のある生ポインタから安全にオブジェクトを取り戻すことはありません。最初に参照を取得するには、ロックで保護された検索、既存の参照、または所属サブシステムが規定する取得プロトコルに依存する必要があります。すでに取得した参照はオブジェクトのメモリ寿命を保護しますが、アンバインドの同期やプライベート状態自体の参照ルールを代替するものではありません。
ローカルカーネルの実装では、drivers/base/core.c の device_unregister で、まず device_del、次に put_device が行われるのを見ることができます。アンバインドのクリーンアップは drivers/base/dd.c に含まれており、devres_release_all と drvdata のクリアが含まれます。2つのパスの責任は異なるため、ドライバ設計では非同期利用者がどのレベルのオブジェクトを保持しているかを明確にする必要があります。デバイスオブジェクトのライフサイクル 、devres 解放セマンティクス
devres はリソース解放の順序を管理する
devm_kzalloc() などの managed API はリソースをデバイスにアタッチし、プローブの失敗またはアンバインド時には通常、逆順でクリーンアップされます。これはエラー分岐を減らしますが、すべての非同期アクティビティを自動的に解決するわけではありません。
新しいリクエストの進入を防ぐ。
ハードウェアプロトコルに従って DMA を停止し、割り込みソースを無効にする。
実行中のワーク、コールバック、およびリクエストを待機またはキャンセルする。
これらのパスがまだアクセスしているリソースを解放する。
待機操作中には、完了コールバックに必要なロックを保持してはいけません。managed と unmanaged API は併用できますが、どのリソースが誰によって解放されるかを明確にし、手動解放後に再度自動解放されないようにする必要があります。デバイスのライフサイクル と devres ドキュメント を参照してください。
呼び出し元の参照を取得し、ドライバのバインド解除またはデバイスの登録解除を行う。device オブジェクトが生きている間に、どのドライバリソースがすでに無効になっているかを観察する。参照カウントがデバイスのアクセス可能性のスイッチではない。
図を準備しています 再読み込み
デバイスオブジェクトは存続しているが、managed リソースもまだ存在するか? device の参照寿命がドライババインド寿命より長いことは合法な状態である。get_device はオブジェクトのメモリを保護するが、アンバインドされた devres やオフラインになったハードウェアまでは保護しない。
{"id":"device-binding-lifetimes","title":"デバイスオブジェクトは存続しているが、managed リソースもまだ存在するか?","summary":"device の参照寿命がドライババインド寿命より長いことは合法な状態である。get_device はオブジェクトのメモリを保護するが、アンバインドされた devres やオフラインになったハードウェアまでは保護しない。","height":1000,"html":"<h2 data-i18n=\"heading\"></h2><p class=\"intro\" data-i18n=\"intro\"></p><div class=\"actions\"><button id=\"get\" data-i18n=\"get\"></button><button id=\"put\" data-i18n=\"put\"></button></div><div class=\"actions\"><button id=\"unbind\" data-i18n=\"unbind\"></button><button id=\"bind\" data-i18n=\"bind\"></button></div><div class=\"actions\"><button id=\"unregister\" data-i18n=\"unregister\"></button></div><div class=\"track-row\"><span data-i18n=\"refs\"></span><div id=\"refs\" class=\"track\"></div></div><div class=\"track-row\"><span data-i18n=\"binding\"></span><div id=\"binding\" class=\"track\"></div></div><div class=\"metrics\"><div><span data-i18n=\"object\"></span><strong id=\"object\"></strong></div><div><span data-i18n=\"count\"></span><strong id=\"count\"></strong></div></div><div class=\"actions\"><button id=\"access\" data-i18n=\"access\"></button></div><div class=\"card\"><header data-i18n=\"result\"></header><div id=\"result\" class=\"readout\"></div></div><div class=\"copy\"><p id=\"explanation\" role=\"status\"></p><p class=\"reserve\" aria-hidden=\"true\" data-i18n=\"note\"></p></div><div class=\"actions\"><button id=\"reset\" data-i18n=\"reset\"></button></div><details class=\"scope\"><summary data-i18n=\"scopeLabel\"></summary><p data-i18n=\"scope\"></p></details>","css":".intro{margin:8px 0 18px;color:var(--muted);font-size:14px}.caption,.hint{font-size:12px;color:var(--muted);margin-top:12px}.control{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px 12px;align-items:center;margin:14px 0;font-size:13px}.control label{font-size:13px}.control output{color:var(--accent);min-width:5em;text-align:right;font-variant-numeric:tabular-nums}.control input{grid-column:1/-1;width:100%;margin:0}.presets{display:flex;gap:4px;align-items:stretch}.presets button{flex:1 1 0;min-width:0;overflow-wrap:anywhere;font-size:13px}.actions{display:flex;gap:8px;flex-wrap:wrap;margin:14px 0}.actions button{flex:1;min-width:0;font-size:13px;min-height:42px}.copy{display:grid;font-size:14px;margin:16px 0}.copy>*{grid-area:1/1;margin:0}.reserve{visibility:hidden}.scope{margin-top:14px;color:var(--muted);font-size:12px}.scope summary{padding:8px 0;cursor:pointer}.scope p{margin-top:10px}.two{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.card{border:1px solid var(--rule);border-radius:9px;padding:14px;min-width:0}.card header{font-size:14px;font-weight:600;margin-bottom:10px}.card button{font-size:12px;width:100%;min-width:0}.card small{display:block;font-size:12px;color:var(--muted)}.card code{font-size:12px;overflow-wrap:anywhere}.metrics{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:16px 0}.metrics>div{border-left:2px solid var(--accent);padding-left:10px;min-width:0}.metrics span{display:block;min-height:3.2em;color:var(--muted);font-size:12px}.metrics strong{font-size:23px;display:block;font-weight:500;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.formula{border-top:1px solid var(--rule);padding-top:12px;margin-top:14px;font-size:13px;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}.value{font:500 20px var(--viz-font-ui)}.legend{display:flex;flex-wrap:wrap;gap:6px 14px;font-size:12px;color:var(--muted);margin:12px 0}.legend span:before{content:'';display:inline-block;width:8px;height:8px;border-radius:2px;background:var(--accent);margin-right:6px}.legend .second:before{background:var(--second)}.check{display:flex;align-items:center;gap:8px;font-size:13px;margin:12px 0}.check input{width:16px;height:16px;flex-shrink:0;accent-color:var(--accent)}select,input[type=text],input[type=number]{background:var(--paper);color:var(--ink);font:inherit;font-size:13px;padding:10px;border:1px solid var(--rule);border-radius:7px;max-width:100%;min-width:0}select{width:100%;min-height:42px}.band{height:20px;display:flex;background:var(--surface);border-radius:4px;overflow:hidden}.band i{height:100%;display:block;background:var(--accent);transition:width .25s}.band i.second{background:var(--second)}button:disabled{cursor:default}.status{font-size:13px;min-height:4.8em}.mono{font-family:var(--viz-font-mono);font-variant-numeric:tabular-nums}.muted{color:var(--muted)}\n@media(max-width:480px){.two{gap:8px}.card{padding:12px 9px}.actions button,.presets button{font-size:12px}.metrics strong{font-size:20px}.metrics{gap:8px}}\n@media(prefers-reduced-motion:reduce){*,*::before,*::after{transition:none!important;animation:none!important}}\n.track-row{margin:16px 0}.track-row>span{display:block;font-size:12px;color:var(--muted);margin-bottom:7px}.track{display:flex;gap:5px;min-width:0}.cell{flex:1;min-width:0;min-height:48px;border:1px solid var(--rule);border-radius:5px;background:var(--surface);display:flex;align-items:center;justify-content:center;text-align:center;padding:5px 3px;font-size:12px;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}.cell.on{background:var(--accent-soft);border-color:var(--accent)}.cell.gold{background:var(--second-soft);border-color:var(--second)}.cell.empty{border-style:dashed;color:var(--muted)}.cell.error{border-color:var(--second);text-decoration:line-through}.choices{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px;margin:14px 0}.choices button{min-width:0;padding:10px 4px;font-size:12px;overflow-wrap:anywhere}.choices button[aria-current=true]{border-color:var(--accent);background:var(--accent-soft)}.relation{display:grid;grid-template-columns:minmax(0,1fr) 28px minmax(0,1fr);align-items:center;gap:6px;margin:12px 0}.relation .cell{min-height:72px}.relation>i{text-align:center;font-style:normal;color:var(--accent)}.readout{font-size:13px;white-space:pre-line;min-height:6.4em;overflow-wrap:anywhere}.plot{position:relative;border-left:1px solid var(--rule);border-bottom:1px solid var(--rule);padding:8px 0;margin:18px 0}.plot-row{height:28px;position:relative;margin:4px 0;background:var(--surface)}.plot-row i{position:absolute;inset-block:5px;background:var(--accent);min-width:2px;transition:width .2s,left .2s}.plot-row b{position:relative;padding:4px 6px;font:11px/28px var(--viz-font-ui);background:var(--paper);border-radius:3px}.axis{display:flex;justify-content:space-between;font-size:11px;color:var(--muted)}\n\n.readout{min-height:5em}","js":"const $=s=>document.querySelector(s);const set=(id,v)=>$('#'+id).textContent=v;const t=k=>viz.t(k);function cells(id,values){$('#'+id).replaceChildren(...values.map(v=>{const e=document.createElement('div');e.className='cell '+(v.cls||'');e.textContent=v.text;e.title=v.title||v.text;return e;}));}function pressed(mode){document.querySelectorAll('[data-mode]').forEach(e=>e.setAttribute('aria-pressed',String(e.dataset.mode===mode)));}let registered=true,bound=true,extra=0,result='pending';function draw(){const count=Number(registered)+extra,alive=count>0;cells('refs',[{text:'registry '+Number(registered)+' + caller '+extra+' → device',cls:alive?'on':'empty'}]);cells('binding',[{text:bound?'driver → MMIO / buffer':'driver × MMIO / buffer',cls:bound?'gold':'empty'}]);set('object',t(alive?'yes':'no'));set('count',count);$('#get').disabled=!alive||extra===4;$('#put').disabled=extra===0;$('#unbind').disabled=!bound;$('#bind').disabled=!registered||bound;$('#unregister').disabled=!registered;set('result',t(result));set('explanation',t('note'));}$('#get').onclick=()=>{extra++;draw();};$('#put').onclick=()=>{extra--;draw();};$('#unbind').onclick=()=>{bound=false;draw();};$('#bind').onclick=()=>{bound=true;draw();};$('#unregister').onclick=()=>{registered=bound=false;draw();};$('#access').onclick=()=>{result=bound?'allowed':'denied';draw();};$('#reset').onclick=()=>{registered=bound=true;extra=0;result='pending';draw();};draw();","audio":false,"strings":{"access":"レジスタがアクセス可能かチェック","allowed":"バインドはまだ有効であり、デバイスプロトコルに従ってアクセス可能","bind":"再バインド","binding":"ドライババインド → managed リソース","count":"モデル参照の合計数","denied":"アクセス不可:オブジェクト参照はバインドリソースを保護しない","get":"追加参照を取得","heading":"デバイスオブジェクトは存続しているが、managed リソースもまだ存在するか?","intro":"追加の device 参照を取得し、ドライバのアンバインドまたは登録取消を行う。登録参照、呼び出し元参照、バインドリソース、最後のアクセスチェックを比較する。","no":"解放済み","note":"まず get、次に unbind:オブジェクトは存続するが、リソースは解放済み。次に unregister、最後に put:この時点で消滅するのはデバイスオブジェクト自体である。","object":"オブジェクトは存続中か","pending":"未チェック","put":"追加参照を1つ返却","refs":"参照 → デバイスオブジェクト","reset":"リセット","result":"最近のアクセスチェック","scope":"登録済みかつバインドされたデバイス。登録者が1つの参照を保持し、追加参照は最大4つまで。unbind はハードウェア/非同期ワークを正しく停止し、managed リソースを解放済み。unregister にはアンバインドと登録参照の返却が含まれる。コア内部の一時参照とハードウェアのホットプラグは省略し、実際のデバイス操作は行わない。","scopeLabel":"モデル範囲と規約","unbind":"ドライバをアンバインド","unregister":"デバイス登録を取消","yes":"存続中"}}
4. sysfs、devtmpfs、udev の分担
/sys/devices はデバイスの階層を表示します。/sys/bus/.../devices と /sys/class/... は他の検索ビューを提供し、しばしばシンボリックリンクを含みます。sysfs ファイルはカーネルがエクスポートした属性インターフェースであり、通常のディスクファイルではなく、またすべてのファイルが device_attribute に対応しているわけではありません。
デバイス属性の show では通常 sysfs_emit() が出力に使用され、store では kstrto*() が入力の解析に使用されます。属性には適切なロック、権限、およびデバイス状態のチェックが必要です。安定してエクスポートされた後は、ユーザ空間 ABI も考慮する必要があり、単位や意味を安易に変更してはいけません。
デバイス番号を持ち、対応するメカニズムを使用して登録されたデバイスに対して、devtmpfs はカーネルによって基本デバイスノードを作成できます 。udev は uevent を受信し、属性を読み取り、ルールに基づいて権限を設定し、安定したシンボリックリンクを作成し、modalias に応じてモジュールロードをトリガーします。ビルトインドライバにはモジュールロードは不要であり、また多くのデバイスには /dev ノードが存在しません。例えば、ネットワークインターフェースは通常、ソケットと netlink を介して使用されます。
期待されるデバイスが見えない場合 次の証拠層
発見されたか バス列挙と device オブジェクト
バインドされたか ドライバ関連付け、マッチング、および probe 結果
機能を提供できるか サブシステム機能オブジェクトの登録
名前/アクセスが正しいか ユーザ空間の命名、権限、およびルール
/dev 名が欠落しているだけでは、probe が実行されていないことを直接証明するものではありません。
5. PCI デバイスの読み取り専用確認
以下では sysfs のみを読み取り、デバイスのアンバインドやリソースの変更は行いません。ホットプラグにより、トラバーサル中にファイルが消える可能性があるため、読み取り例外を処理しています。
from pathlib import Path
for dev in sorted ( Path ( ' /sys/bus/pci/devices' ) . glob ( ' *' ) ) [ : 8 ] :
try :
vendor = ( dev / ' vendor' ) . read_text ( ) . strip ( )
product = ( dev / ' device' ) . read_text ( ) . strip ( )
link = dev / ' driver'
driver = link . resolve ( strict = True ) . name if link . is_symlink ( ) else ' (unbound)'
print ( dev . name , vendor , product , driver )
except OSError as exc :
print ( dev . name , type ( exc ) . __name__ )
例えば、名前 0000:03:00.0 には PCI domain、bus、device、function が含まれています。driver リンクがないのは、現在バインドされていないことを示すだけで、その理由についてはマッチングテーブル、モジュール、プローブログ、およびデバイス状態を組み合わせて分析する必要があります。
続きを読む