インテリジェントな検出

しまった。昨日書きかけのままだった。

本日は、昨日の「1. /proc/bus/pciを使う」の方法でPCIの自動検出ツールを実装完了。


まず/proc/bus/pci/devicesを見ると、接続されているPCIデバイスすべての情報がカーネルから出力される。
1行につき1デバイスで、1行の書式は↓こう。 Linuxカーネルのソースのdrivers/pci/proc.cに書いてある。

bbff    VVVVDDDD    Q    ????    ????    ????    ...

bbはそのデバイスが接続されているPCIバスの番号で、16進数で8ビット。
ffはinclude/linux/pci.h曰く「encoded device & function index」らしい。8ビット。
VVVVはベンダーIDで16ビット。DDDDはデバイスIDで16ビット。
QはIRQらしい。
後はメモリの絡みらしい。


で、これだけだとクラスIDがわからない。これは困る。
そうすると次は/proc/bus/pci/バス番号(16進数8ビット)/*なファイル(1デバイスにつき1ファイル)を読み込まないといけなくて、そのファイル名は、「encoded device & function index」をdevfnとすると、

sprintf(path, "%02x.%x", ( ((devfn)>>3) & 0x1f ), ((devfn)&0x07) );

らしい。なんともややこしい…。カーネルソースと格闘でした。


さらに、そのファイルはバイナリファイルで、linux/pci/pci.hに書いてあるpci_dev構造体をごっそり出力したものらしい。しかしこれがPCIの規格で言うところの「コンフィグレーションレジスタ」そのままらしく、後はosdev-jのPCIのページを読みつつ、クラスIDやサブシステムベンダーIDなどを取り出す。
>||
char buf[256];
devinfo.getline(buf, sizeof(buf)); // devinfoはstd::iostream devinfo("さっきのパス");
unsigned short sub_class_id = buf[0x0a]&0x00ff;
unsigned short base_class_id = buf[0x0b]&0x00ff;
unsigned short subsystem_vendor_id = (buf[0x2c]&0x00ff) | ((buf[0x2d]&0x00ff)<<8);
unsigned short subsystem_device_id = (buf[0x2e]&0x00ff) | ((buf[0x2f]&0x00ff)<<8);
|