/*-
* Copyright (c) 1999-2003 MAEKAWA Masahide <gehenna@daemon-systems.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: audio.c,v 1.18 2003/01/11 16:39:06 maekawa Exp $
*/
#include <stdio.h>
#include <unistd.h>
#include <dev/usb/usb.h>
#include "main.h"
#include "audio.h"
#include "uaudioreg.h"
static void audio_control_header(const usb_descriptor_t *);
static void audio_control_input_terminal(const usb_descriptor_t *);
static void audio_control_output_terminal(const usb_descriptor_t *);
static void audio_control_mixer_unit(const usb_descriptor_t *);
static void audio_control_selector_unit(const usb_descriptor_t *);
static void audio_control_feature_unit(const usb_descriptor_t *);
static void audio_control_processing_unit(const usb_descriptor_t *);
static void audio_control_extension_unit(const usb_descriptor_t *);
static void audio_streaming_general(const uint8_t *);
static void audio_streaming_format(const uint8_t *);
static void audio_streaming_format_type1(const uint8_t *);
static void audio_streaming_format_type2(const uint8_t *);
static void audio_streaming_format_type3(const uint8_t *);
static void audio_streaming_format_specific(const uint8_t *);
static void audio_streaming_format_mpeg(const uint8_t *);
static void audio_streaming_format_ac3(const uint8_t *);
static void audio_midi_header(const uint8_t *);
static void audio_midi_midi_in_jack(const uint8_t *);
static void audio_midi_midi_out_jack(const uint8_t *);
static void audio_midi_element(const uint8_t *);
/*
* Class: Audio
*/
void
audio_interface(usb_descriptor_t *desc, uint16_t subclass)
{
switch (subclass) {
case UISUBCLASS_AUDIOCONTROL:
audio_control_interface(desc);
break;
case UISUBCLASS_AUDIOSTREAM:
audio_streaming_interface(desc);
break;
case UISUBCLASS_MIDISTREAM:
audio_midi_interface(desc);
break;
default:
dump_descriptor(desc, "\t\t");
break;
}
}
void
audio_endpoint(usb_descriptor_t *desc, uint16_t subclass)
{
switch (subclass) {
case UISUBCLASS_AUDIOSTREAM:
audio_streaming_endpoint(desc);
break;
case UISUBCLASS_MIDISTREAM:
audio_midi_endpoint(desc);
break;
default:
dump_descriptor(desc, "\t\t");
break;
}
}
/*
* Subclass: Audio Control
*/
void
audio_control_interface(usb_descriptor_t *desc)
{
switch (desc->bDescriptorSubtype) {
case UDESCSUB_AC_HEADER:
audio_control_header(desc);
break;
case UDESCSUB_AC_INPUT:
audio_control_input_terminal(desc);
break;
case UDESCSUB_AC_OUTPUT:
audio_control_output_terminal(desc);
break;
case UDESCSUB_AC_MIXER:
audio_control_mixer_unit(desc);
break;
case UDESCSUB_AC_SELECTOR:
audio_control_selector_unit(desc);
break;
case UDESCSUB_AC_FEATURE:
audio_control_feature_unit(desc);
break;
case UDESCSUB_AC_PROCESSING:
audio_control_processing_unit(desc);
break;
case UDESCSUB_AC_EXTENSION:
audio_control_extension_unit(desc);
break;
default:
dump_descriptor(desc, "\t\t");
}
}
static void
audio_control_header(const usb_descriptor_t *desc)
{
const struct usb_audio_control_descriptor *adesc =
(const struct usb_audio_control_descriptor *)desc;
uint8_t i;
printf("\t\tClass-Specific AC Interface Header Descriptor:\n"
"\t\t bLength %u\n"
"\t\t bDescriptorType %02x\n"
"\t\t bDescriptorSubtype %02x\n"
"\t\t bcdADC %04x\n"
"\t\t wTotalLength %u\n"
"\t\t bInCollection %u\n",
adesc->bLength, adesc->bDescriptorType,
adesc->bDescriptorSubtype, UGETW(adesc->bcdADC),
UGETW(adesc->wTotalLength), adesc->bInCollection);
for (i = 0 ; i < adesc->bInCollection ; i++) {
printf("\t\t baInterfaceNr(%u) %u\n", i+1,
adesc->baInterfaceNr[i]);
}
printf("\n");
}
static void
audio_control_input_terminal(const usb_descriptor_t *desc)
{
const struct usb_audio_input_terminal *adesc =
(const struct usb_audio_input_terminal *)desc;
printf("\t\tInput Terminal Descriptor:\n\t\t bLength %u\n"
"\t\t bDescriptorType %02x\n\t\t bDescriptorSubtype %02x\n"
"\t\t bTerminalID %u\n\t\t wTerminalType %04x\n"
"\t\t bAssocTerminal %u\n\t\t bNrChannels %u\n"
"\t\t wChannelConfig %04x\n\t\t iChannelNames %u\n"
"\t\t iTerminal %u\n\n",
adesc->bLength, adesc->bDescriptorType,
adesc->bDescriptorSubtype, adesc->bTerminalId,
UGETW(adesc->wTerminalType), adesc->bAssocTerminal,
adesc->bNrChannels, UGETW(adesc->wChannelConfig),
adesc->iChannelNames, adesc->iTerminal);
}
static void
audio_control_output_terminal(const usb_descriptor_t *desc)
{
const struct usb_audio_output_terminal *adesc =
(const struct usb_audio_output_terminal *)desc;
printf("\t\tOutput Terminal Descriptor:\n\t\t bLength %u\n"
"\t\t bDescriptorType %02x\n\t\t bDescriptorSubtype %02x\n"
"\t\t bTerminalID %u\n\t\t wTerminalType %04x\n"
"\t\t bAssocTerminal %u\n\t\t bSourceID %u\n"
"\t\t iTerminal %u\n\n",
adesc->bLength, adesc->bDescriptorType,
adesc->bDescriptorSubtype, adesc->bTerminalId,
UGETW(adesc->wTerminalType), adesc->bAssocTerminal,
adesc->bSourceId, adesc->iTerminal);
}
static void
audio_control_mixer_unit(const usb_descriptor_t *desc)
{
const struct usb_audio_mixer_unit *adesc =
(const struct usb_audio_mixer_unit *)desc;
const struct usb_audio_mixer_unit_1 *adesc1;
uint8_t i;
printf("\t\tMixer Unit Descriptor:\n\t\t bLength %u\n"
"\t\t bDescriptorType %02x\n\t\t bDescriptorSubtype %02x\n"
"\t\t bUnitID %u\n\t\t bNrInPins %u\n",
adesc->bLength, adesc->bDescriptorType,
adesc->bDescriptorSubtype, adesc->bUnitId, adesc->bNrInPins);
for (i = 0 ; i < adesc->bNrInPins ; i++) {
printf("\t\t baSourceID(%u) %u\n", i+1,
adesc->baSourceId[i]);
}
adesc1 = (const struct usb_audio_mixer_unit_1 *)
&adesc->baSourceId[adesc->bNrInPins];
printf("\t\t bNrChannels %u\n\t\t wChannelConfig %u\n"
"\t\t iChannelNames %u\n",
adesc1->bNrChannels, UGETW(adesc1->wChannelConfig),
adesc1->iChannelNames);
for (i = 0 ; i < adesc1->bNrChannels ; i++) {
printf("\t\t bmControls(%u) %u\n", i,
adesc1->bmControls[i]);
}
printf("\t\t iMixer %u\n\n",
adesc1->bmControls[adesc1->bNrChannels]);
}
static void
audio_control_selector_unit(const usb_descriptor_t *desc)
{
const struct usb_audio_selector_unit *adesc =
(const struct usb_audio_selector_unit *)desc;
uint8_t i;
printf("\t\tSelector Unit Descriptor:\n\t\t bLength %u\n"
"\t\t bDescriptorType %02x\n\t\t bDescriptorSubtype %02x\n"
"\t\t bUnitID %u\n\t\t bNrInPins %u\n",
adesc->bLength, adesc->bDescriptorType,
adesc->bDescriptorSubtype, adesc->bUnitId, adesc->bNrInPins);
for (i = 0 ; i < adesc->bNrInPins ; i++) {
printf("\t\t baSourceID(%u) %u\n", i+1,
adesc->baSourceId[i]);
}
printf("\t\t iSelector %u\n",
adesc->baSourceId[adesc->bNrInPins]);
printf("\n");
}
static void
audio_control_feature_unit(const usb_descriptor_t *desc)
{
const struct usb_audio_feature_unit *adesc =
(const struct usb_audio_feature_unit *)desc;
uint8_t ch, i, j;
printf("\t\tFeature Unit Descriptor:\n\t\t bLength %u\n"
"\t\t bDescriptorType %02x\n\t\t bDescriptorSubtype %02x\n"
"\t\t bUnitID %u\n\t\t bSourceID %u\n"
"\t\t bControlSize %u\n",
adesc->bLength, adesc->bDescriptorType,
adesc->bDescriptorSubtype, adesc->bUnitId,
adesc->bSourceId, adesc->bControlSize);
ch = (adesc->bLength - 7) / adesc->bControlSize;
for (i = 0 ; i <= ch ; i++) {
for (j = 0 ; j < adesc->bControlSize ; j++) {
printf("\t\t bmaControls(%u) %02x\n",
i, adesc->bmaControls[i*j]);
}
}
printf("\t\t iFeature %u\n\n",
adesc->bmaControls[ch*adesc->bControlSize]);
}
static void
audio_control_processing_unit(const usb_descriptor_t *desc)
{
const struct usb_audio_processing_unit *adesc =
(const struct usb_audio_processing_unit *)desc;
const struct usb_audio_processing_unit_1 *adesc1;
/* XXX - updown should be 2? */
const struct usb_audio_processing_unit_updown *adesc2;
uint8_t i;
int mode = 0;
switch (UGETW(adesc->wProcessType)) {
case UPDOWNMIX_PROCESS:
printf("\t\tUp/Down-mix Processing Unit Descriptor:\n");
mode = 1;
break;
case DOLBY_PROLOGIC_PROCESS:
printf("\t\tDolby Prologic Processing Unit Descriptor:\n");
mode = 1;
break;
case P3D_STEREO_EXTENDER_PROCESS:
printf("\t\t3D-Stereo Extender Processing Unit Descriptor:\n");
break;
case REVERBATION_PROCESS:
printf("\t\tReverberation Processing Unit Descriptor:\n");
break;
case CHORUS_PROCESS:
printf("\t\tChorus Processing Unit Descriptor:\n");
break;
case DYN_RANGE_COMP_PROCESS:
printf("\t\tDynamic Range Compressor"
" Processing Unit Descriptor:\n");
break;
default:
dump_descriptor(desc, "\t\t");
return;
}
printf("\t\t bLength %u\n\t\t bDescriptorType %02x\n"
"\t\t bDescriptorSubtype %02x\n\t\t bUnitID %u\n"
"\t\t wProcessType %04x\n\t\t bNrInPins %u\n",
adesc->bLength, adesc->bDescriptorType,
adesc->bDescriptorSubtype, adesc->bUnitId,
UGETW(adesc->wProcessType), adesc->bNrInPins);
if (adesc->bNrInPins > 1) {
for (i = 0 ; i < adesc->bNrInPins ; i++) {
printf("\t\t baSourceID(%u) %u\n", i+1,
adesc->baSourceId[i]);
}
} else {
printf("\t\t bSourceID %u\n", adesc->baSourceId[0]);
}
adesc1 = (const struct usb_audio_processing_unit_1 *)
&adesc->baSourceId[adesc->bNrInPins];
printf("\t\t bNrChannels %u\n\t\t wChannelConfig %04x\n"
"\t\t iChannelNames %u\n""\t\t bControlSize %u\n",
adesc1->bNrChannels, UGETW(adesc1->wChannelConfig),
adesc1->iChannelNames, adesc1->bControlSize);
for (i = 0 ; i < adesc1->bControlSize ; i++) {
printf("\t\t bmControls(%u) %02x\n", i+1,
adesc1->bmControls[i]);
}
adesc2 = (const struct usb_audio_processing_unit_updown *)
&adesc1->bmControls[adesc1->bControlSize];
printf("\t\t iProcessing %u\n", adesc2->iProcessing);
if (mode) {
printf("\t\t bNrModes %u\n", adesc2->bNrModes);
for (i = 0 ; i < adesc2->bNrModes ; i++) {
printf("\t\t waModes(%u) %02x\n",
i+1, UGETW(adesc2->waModes[i]));
}
}
printf("\n");
}
static void
audio_control_extension_unit(const usb_descriptor_t *desc)
{
const struct usb_audio_extension_unit *adesc =
(const struct usb_audio_extension_unit *)desc;
const struct usb_audio_extension_unit_1 *adesc1;
uint8_t n, i;
printf("\t\tExtension Unit Descriptor:\n\t\t bLength %u\n"
"\t\t bDescriptorType %02x\n\t\t bDescriptorSubtype %02x\n"
"\t\t bUnitID %u\n\t\t wExtensionCode %04x\n"
"\t\t bNrInPins %u\n",
adesc->bLength, adesc->bDescriptorType,
adesc->bDescriptorSubtype, adesc->bUnitId,
UGETW(adesc->wExtensionCode), adesc->bNrInPins);
for (i = 0 ; i < adesc->bNrInPins ; i++) {
printf("\t\t baSourceID(%u) %u\n", i+1,
adesc->baSourceId[i]);
}
adesc1 = (const struct usb_audio_extension_unit_1 *)
&adesc->baSourceId[adesc->bNrInPins];
printf("\t\t bNrChannels %u\n\t\t wChannelConfig %04x\n"
"\t\t iChannelNames %u\n\t\t bControlSize %u\n",
adesc1->bNrChannels, UGETW(adesc1->wChannelConfig),
adesc1->iChannelNames, adesc1->bControlSize);
n = adesc->bLength - 13 - adesc->bNrInPins;
for (i = 0 ; i < n ; i++) {
printf("\t\t bmControls %02x\n",
adesc1->bmControls[i]);
}
printf("\t\t iExtension %u\n\n", adesc1->bmControls[n]);
}
/*
* Subclass: Audio Streaming
*/
void
audio_streaming_interface(usb_descriptor_t *desc)
{
uint8_t *buffer = (uint8_t *)desc;
switch (desc->bDescriptorSubtype) {
case AS_GENERAL:
audio_streaming_general(buffer);
break;
case FORMAT_TYPE:
audio_streaming_format(buffer);
break;
case FORMAT_SPECIFIC:
audio_streaming_format_specific(buffer);
break;
default:
dump_descriptor(buffer, "\t\t");
}
}
void
audio_streaming_endpoint(usb_descriptor_t *desc)
{
const struct usb_audio_streaming_endpoint_descriptor *edesc =
(const struct usb_audio_streaming_endpoint_descriptor *)desc;
printf("\t\tClass-Specific AS Endpoint Descriptor:\n"
"\t\t bLength %d\n\t\t bDescriptorType %02x\n"
"\t\t bDescriptorSubtype %02x\n\t\t bmAttributes %02x\n"
"\t\t bLockDelayUnits %d\n\t\t wLockDelay %d\n\n",
edesc->bLength, edesc->bDescriptorType,
edesc->bDescriptorSubtype, edesc->bmAttributes,
edesc->bLockDelayUnits, UGETW(edesc->wLockDelay));
}
static void
audio_streaming_general(const uint8_t *buffer)
{
const struct usb_audio_streaming_interface_descriptor *idesc =
(const struct usb_audio_streaming_interface_descriptor *)buffer;
printf("\t\tClass-Specific AS Interface Descriptor:\n"
"\t\t bLength %d\n\t\t bDescriptorType %02x\n"
"\t\t bDescriptorSubtype %02x\n\t\t bTerminalLink %d\n"
"\t\t bDecay %d\n\t\t wFormatTag %d\n\n",
idesc->bLength, idesc->bDescriptorType,
idesc->bDescriptorSubtype, idesc->bTerminalLink, idesc->bDelay,
UGETW(idesc->wFormatTag));
}
static void
audio_streaming_format(const uint8_t *buffer)
{
switch (buffer[3]) {
case FORMAT_TYPE_I:
audio_streaming_format_type1(buffer);
break;
case FORMAT_TYPE_II:
audio_streaming_format_type2(buffer);
break;
case FORMAT_TYPE_III:
audio_streaming_format_type3(buffer);
break;
default:
dump_descriptor(buffer, "\t\t");
}
}
static void
audio_streaming_format_type1(const uint8_t *buffer)
{
const struct usb_audio_streaming_type1_descriptor *desc =
(const struct usb_audio_streaming_type1_descriptor *)buffer;
printf("\t\tType I Format Descriptor:\n\t\t bLength %d\n"
"\t\t bDescriptorType %02x\n\t\t bDescriptorSubtype %02x\n"
"\t\t bFormatType %02x\n\t\t bNrChannels %d\n"
"\t\t bSubframeSize %d\n\t\t bBitResolution %d\n"
"\t\t bSamFreqType %d\n",
desc->bLength, desc->bDescriptorType, desc->bDescriptorSubtype,
desc->bFormatType, desc->bNrChannels, desc->bSubFrameSize,
desc->bBitResolution, desc->bSamFreqType);
if (desc->bSamFreqType == UA_SAMP_CONTNUOUS) {
printf("\t\t tLowerSamFreq %d\n"
"\t\t tUpperSamFreq %d\n",
UA_SAMP_LO(desc), UA_SAMP_HI(desc));
} else {
uint8_t i;
for (i = 0 ; i < desc->bSamFreqType ; i++) {
printf("\t\t tSamFreq[%d] %d\n", i+1,
UA_GETSAMP(desc, i));
}
}
printf("\n");
}
static void
audio_streaming_format_type2(const uint8_t *buffer)
{
uint8_t bSamFreqType, i;
printf("\t\tType II Format Descriptor:\n\t\t bLength %d\n"
"\t\t bDescriptorType %02x\n\t\t bDescriptorSubtype %02x\n"
"\t\t bFormatType %02x\n\t\t wMaxBitRate %d\n"
"\t\t wSamplesPerFrame %d\n\t\t bSamFreqType %d\n",
buffer[0], buffer[1], buffer[2], buffer[3],
UGETW(&buffer[4]), UGETW(&buffer[6]), buffer[8]);
bSamFreqType = buffer[8];
if (bSamFreqType == UA_SAMP_CONTNUOUS) {
printf("\t\t tLowerSamFreq %d\n"
"\t\t tUpperSamFreq %d\n",
buffer[9] | buffer[10] << 8 | buffer[11] << 16,
buffer[12] | buffer[13] << 8 | buffer[14] << 16);
} else {
for (i = 0 ; i < bSamFreqType ; i++) {
printf("\t\t tSamFreq[%d] %d\n", i+1,
buffer[9+i*3] | buffer[10+i*3] << 8
| buffer[11+i*3] << 16);
}
}
printf("\n");
}
static void
audio_streaming_format_type3(const uint8_t *buffer)
{
uint8_t bSamFreqType, i;
printf("\t\tType III Format Descriptor:\n\t\t bLength %d\n"
"\t\t bDescriptorType %02x\n\t\t bDescriptorSubtype %02x\n"
"\t\t bFormatType %02x\n\t\t bNrChannels %d\n"
"\t\t bSubframeSize %d\n\t\t bBitResolution %d\n"
"\t\t bSamFreqType %d\n",
buffer[0], buffer[1], buffer[2], buffer[3], buffer[4],
buffer[5], buffer[6], buffer[7]);
bSamFreqType = buffer[7];
if (bSamFreqType == UA_SAMP_CONTNUOUS) {
printf("\t\t tLowerSamFreq %d\n"
"\t\t tUpperSamFreq %d\n",
buffer[8] | buffer[9] << 8 | buffer[10] << 16,
buffer[11] | buffer[12] << 8 | buffer[13] << 16);
} else {
for (i = 0 ; i < bSamFreqType ; i++) {
printf("\t\t tSamFreq[%d] %d\n", i+1,
buffer[8+i*3] | buffer[9+i*3] << 8
| buffer[10+i*3] << 16);
}
}
printf("\n");
}
static void
audio_streaming_format_specific(const uint8_t *buffer)
{
int wFormatTag = UGETW(&buffer[3]);
switch (wFormatTag) {
case UA_FMT_MPEG:
audio_streaming_format_mpeg(buffer);
break;
case UA_FMT_AC3:
audio_streaming_format_ac3(buffer);
break;
default:
dump_descriptor(buffer, "\t\t");
}
}
static void
audio_streaming_format_mpeg(const uint8_t *buffer)
{
printf("\t\tMPEG Format Specific Descriptor:\n"
"\t\t bLength %d\n\t\t bDescriptorType %02x\n"
"\t\t bDescriptorSubtype %02x\n\t\t wFormatTag %04x\n"
"\t\t bmMPEGCapabilities %04x\n"
"\t\t bmMPEGFeatures %02x\n\n",
buffer[0], buffer[1], buffer[2], UGETW(&buffer[3]),
UGETW(&buffer[5]), buffer[7]);
}
static void
audio_streaming_format_ac3(const uint8_t *buffer)
{
printf("\t\tAC-3 Format Specific Descriptor:\n"
"\t\t bLength %d\n\t\t bDescriptorType %02x\n"
"\t\t bDescriptorSubtype %02x\n\t\t wFormatTag %04x\n"
"\t\t bmBSID %08x\n"
"\t\t bmAC3Features %02x\n\n",
buffer[0], buffer[1], buffer[2], UGETW(&buffer[3]),
UGETDW(&buffer[5]), buffer[9]);
}
/*
* Subclass: MIDI Streaming
*/
void
audio_midi_interface(usb_descriptor_t *desc)
{
const uint8_t *buffer = (const uint8_t *)desc;
switch (desc->bDescriptorSubtype) {
case USB_MIDI_MS_HEADER:
audio_midi_header(buffer);
break;
case USB_MIDI_IN_JACK:
audio_midi_midi_in_jack(buffer);
break;
case USB_MIDI_OUT_JACK:
audio_midi_midi_out_jack(buffer);
break;
case USB_MIDI_ELEMENT:
audio_midi_element(buffer);
break;
default:
dump_descriptor(buffer, "\t\t");
}
}
void
audio_midi_endpoint(usb_descriptor_t *desc)
{
const uint8_t *buffer = (const uint8_t *)desc;
uint8_t n, i;
printf("\t\tMS Bulk Data Endpoint Descriptor:\n"
"\t\t bLength %d\n\t\t bDescriptorType %02x\n"
"\t\t bDescriptorSubtype %02x\n\t\t bNumEmbMIDIJack %d\n",
buffer[0], buffer[1], buffer[2], buffer[3]);
n = buffer[3];
for (i = 1 ; i <= n ; i++)
printf("\t\t baAssocJackID(%d) %d\n", i, buffer[4+(i-1)]);
printf("\n");
}
static void
audio_midi_header(const uint8_t *buffer)
{
printf("\t\tMS Interface Header Descriptor:\n"
"\t\t bLength %d\n\t\t bDescriptorType %02x\n"
"\t\t bDescriptorSubtype %02x\n\t\t bcdMSC %04x\n"
"\t\t wTotalLength %d\n\n",
buffer[0], buffer[1], buffer[2], UGETW(&buffer[3]),
UGETW(&buffer[5]));
}
static void
audio_midi_midi_in_jack(const uint8_t *buffer)
{
printf("\t\tMIDI IN Jack Descriptor:\n\t\t bLength %d\n"
"\t\t bDescriptorType %02x\n\t\t bDescriptorSubtype %02x\n"
"\t\t bJackType %02x",
buffer[0], buffer[1], buffer[2], buffer[3]);
switch (buffer[3]) {
case USB_MIDI_EMBEDDED:
printf(" (Embedded)\n");
break;
case USB_MIDI_EXTERNAL:
printf(" (External)\n");
break;
default:
printf(" (unknown)\n");
}
printf("\t\t bJackID %02x\n"
"\t\t iJack %d\n\n",
buffer[4], buffer[5]);
}
static void
audio_midi_midi_out_jack(const uint8_t *buffer)
{
uint8_t p, i;
printf("\t\tMIDI OUT Jack Descriptor:\n\t\t bLength %d\n"
"\t\t bDescriptorType %02x\n\t\t bDescriptorSubtype %02x\n"
"\t\t bJackType %02x",
buffer[0], buffer[1], buffer[2], buffer[3]);
switch (buffer[3]) {
case USB_MIDI_EMBEDDED:
printf(" (Embedded)\n");
break;
case USB_MIDI_EXTERNAL:
printf(" (External)\n");
break;
default:
printf(" (unknown)\n");
}
printf("\t\t bJackID %02x\n\t\t bNrInputPins %d\n",
buffer[4], buffer[5]);
p = buffer[5];
for (i = 0 ; i < p ; i++) {
printf("\t\t baSourceID(%d) %d\n"
"\t\t BaSourcePin(%d) %d\n",
i+1, buffer[6+2*i], i, buffer[6+2*i+1]);
}
printf("\t\t iJack %d\n\n", buffer[5+2*p]);
}
static void
audio_midi_element(const uint8_t *buffer)
{
uint8_t p, n, i;
printf("\t\tElement Descriptor:\n\t\t bLength %d\n"
"\t\t bDescriptorType %02x\n\t\t bDescriptorSubType %02x\n"
"\t\t bElementID %02x\n\t\t bNrInputPins %d\n",
buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]);
p = buffer[4];
for (i = 0 ; i < p ; i++) {
printf("\t\t baSourceID(%d) %d\n"
"\t\t BaSourcePin(%d) %d\n",
i+1, buffer[5+2*i], i, buffer[5+2*i+1]);
}
printf("\t\t bNrOutputPins %d\n\t\t bInTerminalLink %02x\n"
"\t\t bOutTerminalLink %02x\n\t\t bElCapsSize %d\n",
buffer[5+2*p], buffer[6+2*p], buffer[7+2*p], buffer[8+2*p]);
n = buffer[0] - 2 * p;
for (i = 0 ; i < n ; i++)
printf("\t\t bmElementCaps %02x\n", buffer[9+2*p+i]);
printf("\t\t iElement %d\n\n", buffer[9+2*p+n]);
}
syntax highlighted by Code2HTML, v. 0.9.1