USBインターフェースディスクリプタ:マルチインターフェースデバイスの実装方法

USBインターフェースディスクリプタは、USBデバイスの各機能をホストに知らせるための重要な要素です。特に、マルチインターフェースデバイスでは、複数の機能を提供するために複数のインターフェースディスクリプタを使用します。ここでは、USBインターフェースディスクリプタの基本構造と、マルチインターフェースデバイスの実装方法について詳しく解説します。

 

moun45.hatenablog.com

 

1. インターフェースディスクリプタとは?

USBインターフェースディスクリプタは、USBデバイスが提供する各機能やエンドポイントの詳細を定義する構造体です。ホストはこれを使用して、デバイスの各インターフェースを識別し、適切なドライバをロードします。

2. インターフェースディスクリプタの基本構造

USBインターフェースディスクリプタは、以下のフィールドで構成されています:

  • bLength
  • bDescriptorType
  • bInterfaceNumber
  • bAlternateSetting
  • bNumEndpoints
  • bInterfaceClass
  • bInterfaceSubClass
  • bInterfaceProtocol
  • iInterface

3. 各フィールドの詳細と設定方法

a. bLength

uint8_t bLength = 9;

b. bDescriptorType

uint8_t bDescriptorType = 0x04;

c. bInterfaceNumber

  • 意味: このインターフェースの番号(0から始まる)
  • 設定方法: デバイス内のインターフェースの順番に従って設定
uint8_t bInterfaceNumber = 0; // 例:インターフェース0

d. bAlternateSetting

  • 意味: インターフェースの代替設定番号(通常0)
  • 設定方法: 通常は0、異なる設定がある場合は増加
uint8_t bAlternateSetting = 0; // 例:代替設定0

 

e. bNumEndpoints

  • 意味: このインターフェースに属するエンドポイントの数(エンドポイント0は含まない)
  • 設定方法: インターフェースが使用するエンドポイントの数を設定
uint8_t bNumEndpoints = 2; // 例:2つのエンドポイント

f. bInterfaceClass

  • 意味: インターフェースのクラスコード(USB-IFにより定義)
  • 設定方法: デバイスの機能に基づいて設定(例:0x08はマスストレージクラス)
uint8_t bInterfaceClass = 0x08; // 例:マスストレージクラス

g. bInterfaceSubClass

  • 意味: サブクラスコード
  • 設定方法: デバイスの機能に基づいて設定(例:0x06はSCSIトランスペアレントコマンドセット)
uint8_t bInterfaceSubClass = 0x06; // 例:SCSIトランスペアレントコマンドセット

 

h. bInterfaceProtocol

  • 意味: プロトコルコード
  • 設定方法: デバイスの機能に基づいて設定(例:0x50はBOT(Bulk-Only Transport))
uint8_t bInterfaceProtocol = 0x50; // 例:BOT

 

i. iInterface

uint8_t iInterface = 0; // 例:インデックス0(文字列なし)

 

4. マルチインターフェースデバイスの実装方法

マルチインターフェースデバイスは、複数のインターフェースディスクリプタを持ち、それぞれが異なる機能を提供します。以下に、マルチインターフェースデバイスの設定例を示します。

コンフィギュレーションディスクリプタの設定

struct configuration_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wTotalLength;
uint8_t bNumInterfaces;
uint8_t bConfigurationValue;
uint8_t iConfiguration;
uint8_t bmAttributes;
uint8_t bMaxPower;
};

struct configuration_descriptor config_desc = {
.bLength = 9,
.bDescriptorType = 0x02,
.wTotalLength = sizeof(config_desc) + sizeof(interface_desc1) + sizeof(interface_desc2) + sizeof(endpoint_desc1) + sizeof(endpoint_desc2),
.bNumInterfaces = 2, // 2つのインターフェース
.bConfigurationValue = 1,
.iConfiguration = 0,
.bmAttributes = 0xC0, // セルフパワード、リモートウェイクアップ有効
.bMaxPower = 50 // 100mA
};

 

 

インターフェースディスクリプタの設定

struct interface_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bInterfaceNumber;
uint8_t bAlternateSetting;
uint8_t bNumEndpoints;
uint8_t bInterfaceClass;
uint8_t bInterfaceSubClass;
uint8_t bInterfaceProtocol;
uint8_t iInterface;
};

struct interface_descriptor interface_desc1 = {
.bLength = 9,
.bDescriptorType = 0x04,
.bInterfaceNumber = 0,
.bAlternateSetting = 0,
.bNumEndpoints = 2, // 例:インターフェース1に2つのエンドポイント
.bInterfaceClass = 0x08, // マスストレージクラス
.bInterfaceSubClass = 0x06,
.bInterfaceProtocol = 0x50,
.iInterface = 0
};

struct interface_descriptor interface_desc2 = {
.bLength = 9,
.bDescriptorType = 0x04,
.bInterfaceNumber = 1,
.bAlternateSetting = 0,
.bNumEndpoints = 1, // 例:インターフェース2に1つのエンドポイント
.bInterfaceClass = 0x03, // HIDクラス
.bInterfaceSubClass = 0x01,
.bInterfaceProtocol = 0x01,
.iInterface = 0
};

 

 

エンドポイントディスクリプタの設定

struct endpoint_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bEndpointAddress;
uint8_t bmAttributes;
uint16_t wMaxPacketSize;
uint8_t bInterval;
};

struct endpoint_descriptor endpoint_desc1 = {
.bLength = 7,
.bDescriptorType = 0x05,
.bEndpointAddress = 0x81, // エンドポイント1(IN方向)
.bmAttributes = 0x02, // バルクエンドポイント
.wMaxPacketSize = 512,
.bInterval = 0
};

struct endpoint_descriptor endpoint_desc2 = {
.bLength = 7,
.bDescriptorType = 0x05,
.bEndpointAddress = 0x01, // エンドポイント2(OUT方向)
.bmAttributes = 0x02, // バルクエンドポイント
.wMaxPacketSize = 512,
.bInterval = 0
};

struct endpoint_descriptor endpoint_desc3 = {
.bLength = 7,
.bDescriptorType = 0x05,
.bEndpointAddress = 0x82, // エンドポイント3(IN方向)
.bmAttributes = 0x03, // インタラプトエンドポイント
.wMaxPacketSize = 64,
.bInterval = 10
};

 

まとめ

USBインターフェースディスクリプタは、デバイスの各機能を定義し、マルチインターフェースデバイスの実装において重要な役割を果たします。正確なディスクリプタの設定により、ホストがデバイスを正しく認識し、適切なドライバをロードすることができます。このガイドを参考にして、マルチインターフェースデバイスを正しく実装し、USBデバイスの性能を最大限に引き出しましょう。