USB-MIDI (9)

前回の規格書付録 B のディスクリプタと同等のディスクリプタを。C 言語の初期値付き配列の形で表現したものを下に示します。
LPC11U35 を使った FM 音源プログラムの USB-MIDI 機能部分で、このディスクリプタを使ってコンパイルして MIDI OUT 機能が正常に動作することを確かめてあります。 (MIDI IN 機能は、もともと実装していない)

//
// Macro for split WORD (2 byte) value 
// into little-endian order bytes
//
#define lew(x) ((uint8_t)(x)), (((uint16_t)(x)) >> 8)

const uint8_t ConfigurationDescriptor[] = {
//
// Configuration descriptor (9 byte)
//
  0x09,         // bLength 
  0x02,         // bDescriptorType 
  lew(0x0065),  // wTotalLength 
  0x02,         // bNumInterfaces 
  0x01,         // bConfigurationValue 
  0x00,         // iConfiguration 
  0x80,         // bmAttributes 
  0x32,         // MaxPower 
//
// Standard AudioControl
// Interface descriptor (9 byte)
//  
  0x09,         // bLength 
  0x04,         // bDescriptorType 
  0x00,         // bInterfaceNumber
  0x00,         // bAlternateSetting
  0x00,         // bNumEndpoints
  0x01,         // bInterfaceClass
  0x01,         // bInterfaceSubClass
  0x00,         // bInterfaceProtocol
  0x00,         // iInferface 
//
// Class-Specific AudioControl
// Interface descriptor (9 byte)
//  
  0x09,         // bLength 
  0x24,         // bDescriptorType 
  0x01,         // bDescriptorSubType 
  lew(0x0100),  // bcdADC
  lew(0x0009),  // wTotalLength 
  0x01,         // bInCollection
  0x01,         // baInferfaceNr(1) 
//
// Standard MIDIStreaming
// Interface descriptor (9 byte)
//  
  0x09,         // bLength 
  0x04,         // bDescriptorType 
  0x01,         // bInterfaceNumber
  0x00,         // bAlternateSetting
  0x02,         // bNumEndpoints
  0x01,         // bInterfaceClass
  0x03,         // bInterfaceSubClass
  0x00,         // bInterfaceProtocol
  0x00,         // iInferface 
//
// Class-Specific MIDIStreaming
// Interface descriptor (7 byte)
//  
  0x07,         // bLength 
  0x24,         // bDescriptorType 
  0x01,         // bDescriptorSubType 
  lew(0x0100),  // bcdMSC
  lew(0x0025),  // wTotalLength 
//
// Class-Specific MIDI IN Jack
// descriptor (Embedded) (6 byte)
//  
  0x06,         // bLength 
  0x24,         // bDescriptorType 
  0x02,         // bDescriptorSubType 
  0x01,         // bJackType
  0x01,         // bJackID
  0x00,         // iJack 
//
// Class-Specific MIDI IN Jack
// descriptor (External) (6 byte)
//  
  0x06,         // bLength 
  0x24,         // bDescriptorType 
  0x02,         // bDescriptorSubType 
  0x02,         // bJackType
  0x02,         // bJackID
  0x00,         // iJack 
//
// Class-Specific MIDI OUT Jack
// descriptor (Embedded) (9 byte)
//  
  0x09,         // bLength 
  0x24,         // bDescriptorType 
  0x03,         // bDescriptorSubType 
  0x01,         // bJackType
  0x03,         // bJackID
  0x01,         // bNrInputPins
  0x02,         // baSourceID(1)
  0x01,         // baSourcePin(1)
  0x00,         // iJack 
//
// Class-Specific MIDI OUT Jack
// descriptor (External) (9 byte)
//  
  0x09,         // bLength 
  0x24,         // bDescriptorType 
  0x03,         // bDescriptorSubType 
  0x02,         // bJackType
  0x04,         // bJackID
  0x01,         // bNrInputPins
  0x01,         // baSourceID(1)
  0x01,         // baSourcePin(1)
  0x00,         // iJack 
//
// Standard Bulk OUT
// Endpoint descriptor (9 byte)
//  
  0x09,         // bLength 
  0x05,         // bDescriptorType 
  0x01,         // bEndpointAddress
  0x02,         // bmAttributes
  lew(0x0040),  // wMaxPacketSize
  0x00,         // bInterval
  0x00,         // bRefresh
  0x00,         // bSynchAddress
//
// Class-Specific Bulk OUT
// Endpoint descriptor (5 byte)
//  
  0x05,         // bLength 
  0x25,         // bDescriptorType 
  0x01,         // bDescriptorSubType 
  0x01,         // bNumEmbMIDIJack
  0x01,         // baAssocJackID(1)
//
// Standard Bulk IN
// Endpoint descriptor (9 byte)
//  
  0x09,         // bLength 
  0x05,         // bDescriptorType 
  0x81,         // bEndpointAddress
  0x02,         // bmAttributes
  lew(0x0040),  // wMaxPacketSize
  0x00,         // bInterval
  0x00,         // bRefresh
  0x00,         // bSynchAddress
//
// Class-Specific Bulk IN
// Endpoint descriptor (5 byte)
//  
  0x05,         // bLength 
  0x25,         // bDescriptorType 
  0x01,         // bDescriptorSubType 
  0x01,         // bNumEmbMIDIJack
  0x03          // baAssocJackID(1)
}; // uint8_t ConfigurationDescriptor[]

ディスクリプタ内には MINI IN 側の構成も含まれているので、ホスト PC 側は IN エンドポイントからデータを入力しようとします。
USB-MIDI のファームで MIDI 入力がサポートされていない場合でも、多くの場合には問題になりません。
動作可能な IN エンドポイントのバッファにデータが何も書き込まれていない場合には USB モジュールのハードウェアで自動的に「NAK」を返します。
IN エンドポイントが動作不能の状態で、ホストからの IN 要求に対して「無反応」となる場合にはエラーと認識されますが、これは大したことではありません。
決して入力されない IN エンドポイントに対してホストは IN 要求を投げ続けるわけで、効率は悪くなりますが、 OUT 動作の障害にはなりません。
逆に MIDI IN だけサポートして MIDI OUT は放置の場合は、OUT 要求に NAK あるいは無反応を出し続けて、ホスト側は先に進めなくなります。
この場合、OUT エンドポイントに溜まったデータを読み捨てて、ホスト側の MIDI 出力処理が進むようにします。
下にディスクリプタの 16 進ダンプを示します。

0000  09 02 65 00 02 01 00 80 32 09 04 00 00 00 01 01
0010  00 00 09 24 01 00 01 09 00 01 01 09 04 01 00 02
0020  01 03 00 00 07 24 01 00 01 25 00 06 24 02 01 01
0030  00 06 24 02 02 02 00 09 24 03 01 03 01 02 01 00
0040  09 24 03 02 04 01 01 01 00 09 05 01 02 40 00 00
0050  00 00 05 25 01 01 01 09 05 81 02 40 00 00 00 00
0060  05 25 01 01 03

この 16 進ダンプを、1 行に 1 つのディスクリプタが並ぶように区切って表示したものを下に示します。
規格書の記述と突き合わせて見ると理解が進むかと思います。

 09 02 65 00 02 01 00 80 32  // Configuration desc.
 
 09 04 00 00 00 01 01 00 00  // Std. AC IF desc.
 09 24 01 00 01 09 00 01 01  // CS   AC IF desc.
 
 09 04 01 00 02 01 03 00 00  // Std. MS IF desc.
 07 24 01 00 01 25 00        // CS   MS IF desc. (HEADER)
 06 24 02 01 01 00           // |-- Emb. MIDI IN  Jack
 06 24 02 02 02 00           // |-- Ext. MIDI IN  Jack
 09 24 03 01 03 01 02 01 00  // |-- Emb. MIDI OUT Jack
 09 24 03 02 04 01 01 01 00  // |-- Ext. MIDI OUT Jack
 
 09 05 01 02 40 00 00 00 00  // Std. Bulk OUT EP desc.
 05 25 01 01 01              // CS   Bulk OUT EP desc.
 
 09 05 81 02 40 00 00 00 00  // Std. Bulk IN EP desc.
 05 25 01 01 03              // CS   Bulk IN EP desc.