* Originally released under the Be Sample Code License.
* Copyright 2000, Be Incorporated. All rights reserved.
*
* Modified for Haiku by François Revol, Michael Lotz and Greg Crain.
* Copyright 2007-2024, Haiku Inc. All rights reserved.
*/
#include <MediaDefs.h>
#include <USBKit.h>
#include <stdio.h>
#include <usb/USB_audio.h>
#include <usb/USB_midi.h>
#include "listusb.h"
void
DumpClockSource(uint8 attributes)
{
switch (attributes & 0x3){
case 0:
printf(" External clock.");
break;
case 1:
printf(" Internal fixed clock.");
break;
case 2:
printf(" Internal variable clock.");
break;
case 3:
printf(" Internal programmable clock.");
break;
}
if (attributes & 0x4){
printf(" Clock synchronized to SOF.");
}
printf("\n");
}
void
DumpAudioCSInterfaceDescriptorClockSourceUnit(
const usb_audio_clocksource_descriptor* descriptor)
{
printf(" Length............. 0x%02x\n", descriptor->length);
printf(" Type .............. 0x%02x\n", descriptor->descriptor_type);
printf(" Subtype ........... 0x%02x (Clock Source)\n",
descriptor->descriptor_subtype);
printf(" Clock ID .......... 0x%02x\n", descriptor->clock_id);
printf(" Attributes......... 0x%02x", descriptor->bm_attributes);
DumpClockSource(descriptor->bm_attributes);
printf(" bm controls ....... 0x%02x", descriptor->bm_controls);
if (descriptor->bm_controls & 0x3)
printf(" Clock Valid.");
printf("\n");
printf(" Assoc Term ........ 0x%02x\n", descriptor->assoc_terminal);
printf(" Clock Src Idx ..... 0x%02x\n", descriptor->clock_source_idx);
}
void
DumpAudioCSInterfaceDescriptorClockSelectorUnit(
const usb_audio_clockselector_descriptor* descriptor)
{
printf(" Length ............ 0x%02x\n", descriptor->length);
printf(" Type .............. 0x%02x\n", descriptor->descriptor_type);
printf(" Subtype ........... 0x%02x (Clock Selector)\n",
descriptor->descriptor_subtype);
printf(" Clock ID .......... 0x%02x\n", descriptor->clock_id);
printf(" Num Of Input Pins .. 0x%02x\n", descriptor->nrinpins);
printf(" Clock Src Entity ... 0x%02x\n", descriptor->Csourceid[0]);
printf(" Controls ........... 0x%02x\n", descriptor->bm_controls);
printf(" Clock Selector...... 0x%02x\n", descriptor->clockselector);
}
void
DumpAudioCSInterfaceDescriptorClockMultiplier(
const usb_audio_clockmultiplier_descriptor* descriptor)
{
printf(" Length ............ 0x%02x\n", descriptor->length);
printf(" Type .............. 0x%02x\n", descriptor->descriptor_type);
printf(" Subtype ........... 0x%02x (Clock Multiplier)\n",
descriptor->descriptor_subtype);
printf(" Clock ID .......... 0x%02x\n", descriptor->clockid);
printf(" Clock Src Entity ... 0x%02x\n", descriptor->clksourceid);
printf(" bm_controls ........ 0x%02x\n", descriptor->bm_controls);
printf(" Clock Multipler .... 0x%02x\n", descriptor->clockmultiplier);
}
uint16
DumpAudioCSInterfaceDescriptorHeader(
const usb_audiocontrol_header_descriptor* descriptor)
{
printf(" Type .............. 0x%02x\n",
descriptor->descriptor_type);
printf(" Subtype ........... 0x%02x (Header)\n",
descriptor->descriptor_subtype);
printf(" Audio codec version .. %d.%d\n",
descriptor->bcd_release_no >> 8, descriptor->bcd_release_no & 0xFF);
if (descriptor->bcd_release_no < USB_AUDIO_CLASS_VERSION_2) {
printf(" Total Length ...... %u\n",
descriptor->r1.total_length);
printf(" Interfaces ........ ");
for (uint8 i = 0; i < descriptor->r1.in_collection; i++)
printf("%u, ", descriptor->r1.interface_numbers[i]);
printf("\n");
} else {
printf(" Function Category...... %u\n", descriptor->r2.function_category);
printf(" Total Length ...........%d\n", descriptor->r2.total_length);
printf(" bm Controls ............0x%02x\n", descriptor->r2.bm_controls);
}
return descriptor->bcd_release_no;
}
void
DumpChannelConfig(uint32 wChannelConfig)
{
struct _Entry {
const char* name;
uint32 mask;
} aClusters[] = {
{ "Front .......... ", B_CHANNEL_LEFT | B_CHANNEL_RIGHT
| B_CHANNEL_CENTER },
{ "L.F.E .......... ", B_CHANNEL_SUB },
{ "Back ........... ", B_CHANNEL_REARLEFT | B_CHANNEL_REARRIGHT
| B_CHANNEL_BACK_CENTER },
{ "Center ......... ", B_CHANNEL_FRONT_LEFT_CENTER
| B_CHANNEL_FRONT_RIGHT_CENTER },
{ "Side ........... ", B_CHANNEL_SIDE_LEFT | B_CHANNEL_SIDE_RIGHT },
{ "Top ............ ", B_CHANNEL_TOP_CENTER },
{ "Top Front ...... ", B_CHANNEL_TOP_FRONT_LEFT
| B_CHANNEL_TOP_FRONT_CENTER | B_CHANNEL_TOP_FRONT_RIGHT },
{ "Top Back ....... ", B_CHANNEL_TOP_BACK_LEFT
| B_CHANNEL_TOP_BACK_CENTER | B_CHANNEL_TOP_BACK_RIGHT }
};
struct _Entry aChannels[] = {
{ "Left", B_CHANNEL_LEFT | B_CHANNEL_FRONT_LEFT_CENTER
| B_CHANNEL_REARLEFT | B_CHANNEL_SIDE_LEFT | B_CHANNEL_TOP_BACK_LEFT
| B_CHANNEL_TOP_FRONT_LEFT },
{ "Right", B_CHANNEL_FRONT_RIGHT_CENTER | B_CHANNEL_TOP_FRONT_RIGHT
| B_CHANNEL_REARRIGHT | B_CHANNEL_RIGHT | B_CHANNEL_SIDE_RIGHT
| B_CHANNEL_TOP_BACK_RIGHT },
{ "Center", B_CHANNEL_BACK_CENTER | B_CHANNEL_CENTER
| B_CHANNEL_TOP_BACK_CENTER | B_CHANNEL_TOP_CENTER
| B_CHANNEL_TOP_FRONT_CENTER },
{ "L.F.E.", B_CHANNEL_SUB }
};
for (size_t i = 0; i < sizeof(aClusters) / sizeof(aClusters[0]); i++) {
uint32 mask = aClusters[i].mask & wChannelConfig;
if (mask != 0) {
printf(" %s", aClusters[i].name);
for (size_t j = 0; j < sizeof(aChannels) / sizeof(aChannels[0]); j++)
if ((aChannels[j].mask & mask) != 0)
printf("%s ", aChannels[j].name);
printf("\n");
}
}
}
static const char*
TerminalTypeName(uint16 terminalType)
{
switch (terminalType) {
case USB_AUDIO_UNDEFINED_USB_IO:
return "USB Undefined";
case USB_AUDIO_STREAMING_USB_IO:
return "USB Streaming";
case USB_AUDIO_VENDOR_USB_IO:
return "USB vendor specific";
case USB_AUDIO_UNDEFINED_IN:
return "Undefined";
case USB_AUDIO_MICROPHONE_IN:
return "Microphone";
case USB_AUDIO_DESKTOPMIC_IN:
return "Desktop microphone";
case USB_AUDIO_PERSONALMIC_IN:
return "Personal microphone";
case USB_AUDIO_OMNI_MIC_IN:
return "Omni-directional microphone";
case USB_AUDIO_MICS_ARRAY_IN:
return "Microphone array";
case USB_AUDIO_PROC_MICS_ARRAY_IN:
return "Processing microphone array";
case USB_AUDIO_LINE_CONNECTOR_IO:
return "Line I/O";
case USB_AUDIO_SPDIF_INTERFACE_IO:
return "S/PDIF";
case USB_AUDIO_UNDEFINED_OUT:
return "Undefined";
case USB_AUDIO_SPEAKER_OUT:
return "Speaker";
case USB_AUDIO_HEAD_PHONES_OUT:
return "Headphones";
case USB_AUDIO_HMD_AUDIO_OUT:
return "Head Mounted Display Audio";
case USB_AUDIO_DESKTOP_SPEAKER:
return "Desktop speaker";
case USB_AUDIO_ROOM_SPEAKER:
return "Room speaker";
case USB_AUDIO_COMM_SPEAKER:
return "Communication speaker";
case USB_AUDIO_LFE_SPEAKER:
return "Low frequency effects speaker";
default:
return "Unknown";
}
}
void
DumpAudioCSInterfaceDescriptorInputTerminal(
const usb_audio_input_terminal_descriptor* descriptor,
uint16 bcd_release_no)
{
printf(" Length............. %u\n", descriptor->length);
printf(" Type .............. 0x%02x\n",
descriptor->descriptor_type);
printf(" Subtype ........... 0x%02x (Input Terminal)\n",
descriptor->descriptor_subtype);
printf(" Terminal ID ....... %u\n",
descriptor->terminal_id);
printf(" Terminal Type ..... 0x%04x (%s)\n",
descriptor->terminal_type,
TerminalTypeName(descriptor->terminal_type));
printf(" Associated Terminal %u\n",
descriptor->assoc_terminal);
if (bcd_release_no < USB_AUDIO_CLASS_VERSION_2){
printf(" Nr Channels ....... %u\n", descriptor->r1.num_channels);
printf(" Channel Config .... 0x%x\n", descriptor->r1.channel_config);
DumpChannelConfig(descriptor->r1.channel_config);
printf(" Channel Names ..... %u\n", descriptor->r1.channel_names);
printf(" Terminal .......... %u\n", descriptor->r1.terminal);
} else {
printf(" Clock Source ID.....0x%02x\n", descriptor->r2.clock_source_id);
printf(" Nr Channels ....... %u\n", descriptor->r2.num_channels);
printf(" Channel Config .... 0x%08" B_PRIx32 "\n",
descriptor->r2.channel_config);
DumpChannelConfig(descriptor->r2.channel_config);
printf(" Channel Names ..... %u\n", descriptor->r2.channel_names);
printf(" bm_controls.........0x%04x\n", descriptor->r2.bm_controls);
printf(" Terminal .......... %u\n", descriptor->r2.terminal);
}
}
void
DumpAudioCSInterfaceDescriptorOutputTerminal(
const usb_audio_output_terminal_descriptor* descriptor,
uint16 bcd_release_no)
{
printf(" Length............. %u\n", descriptor->length);
printf(" Type .............. 0x%02x\n",
descriptor->descriptor_type);
printf(" Subtype ........... 0x%02x (Output Terminal)\n",
descriptor->descriptor_subtype);
printf(" Terminal ID ....... %u\n",
descriptor->terminal_id);
printf(" Terminal Type ..... 0x%04x (%s)\n",
descriptor->terminal_type,
TerminalTypeName(descriptor->terminal_type));
printf(" Associated Terminal %u\n",
descriptor->assoc_terminal);
printf(" Source ID ......... 0x%02x\n", descriptor->source_id);
if (bcd_release_no < USB_AUDIO_CLASS_VERSION_2) {
printf(" Terminal .......... %u\n", descriptor->r1.terminal);
} else {
printf(" Clock Source ID.....0x%02x\n", descriptor->r2.clock_source_id);
printf(" bm_controls.........0x%04x\n", descriptor->r2.bm_controls);
printf(" Terminal .......... %u\n", descriptor->r2.terminal);
}
}
void
DumpAudioCSInterfaceDescriptorMixerUnit(
const usb_audio_mixer_unit_descriptor* descriptor)
{
printf(" Length............. %u\n", descriptor->length);
printf(" Type .............. 0x%02x\n",
descriptor->descriptor_type);
printf(" Subtype ........... 0x%02x (Mixer Unit)\n",
descriptor->descriptor_subtype);
printf(" Unit ID ........... %u\n",
descriptor->unit_id);
printf(" Source IDs ........ ");
for (uint8 i = 0; i < descriptor->num_input_pins; i++)
printf("%u, ", descriptor->input_pins[i]);
printf("\n");
usb_audio_output_channels_descriptor_r1* channels
= (usb_audio_output_channels_descriptor_r1*)
&descriptor->input_pins[descriptor->num_input_pins];
printf(" Channels .......... %u\n",
channels->num_output_pins);
printf(" Channel Config .... 0x%x\n",
channels->channel_config);
DumpChannelConfig(channels->channel_config);
printf(" Channel Names ..... %u\n",
channels->channel_names);
usb_generic_descriptor* generic = (usb_generic_descriptor*)descriptor;
uint8 idx = 7 + descriptor->num_input_pins;
printf(" Bitmap Control .... 0x");
for (uint i = 1; idx < descriptor->length - 3; idx++, i++)
printf("%02x ", (uint8)generic->data[idx]);
printf("\n");
printf(" Mixer ............. %u\n",
generic->data[generic->length - 3]);
}
void
DumpAudioCSInterfaceDescriptorSelectorUnit(
const usb_audio_selector_unit_descriptor* descriptor)
{
printf(" Type .............. 0x%02x\n",
descriptor->descriptor_type);
printf(" Subtype ........... 0x%02x (Selector Unit)\n",
descriptor->descriptor_subtype);
printf(" Unit ID ........... %u\n",
descriptor->unit_id);
printf(" Source IDs ........ ");
for (uint8 i = 0; i < descriptor->num_input_pins; i++)
printf("%u, ", descriptor->input_pins[i]);
printf("\n");
usb_generic_descriptor* generic = (usb_generic_descriptor*)descriptor;
printf(" Selector .......... %u\n",
(uint8)generic->data[descriptor->num_input_pins + 2]);
}
void
DumpBMAControl(uint8 channel, uint32 bma, uint16 bcd_release_no)
{
const char* BMAControls[] = {
"Mute",
"Volume",
"Bass",
"Mid",
"Treble",
"Graphic Equalizer",
"Automatic Gain",
"Delay",
"Bass Boost",
"Loudness"
};
if (bma == 0)
return;
if (channel == 0)
printf(" Master Channel . ");
else
printf(" Channel %u ...... ", channel);
int mask = 1;
if (bcd_release_no < USB_AUDIO_CLASS_VERSION_2) {
for (uint8 i = 0;
i < sizeof(BMAControls) / sizeof(BMAControls[0]); i++, mask <<= 1)
if (bma & mask)
printf("%s ", BMAControls[i]);
} else {
mask = 0x3;
for (uint8 i = 0; i < sizeof(BMAControls) / sizeof(BMAControls[0]); i++, mask <<= 2) {
if (bma & mask) {
printf("%s ", BMAControls[i]);
}
}
}
printf("\n");
}
void
DumpAudioCSInterfaceDescriptorFeatureUnit(
const usb_audio_feature_unit_descriptor* descriptor,
uint16 bcd_release_no)
{
printf(" Length............. %u\n", descriptor->length);
printf(" Type .............. 0x%02x\n",
descriptor->descriptor_type);
printf(" Subtype ........... 0x%02x (Feature Unit)\n",
descriptor->descriptor_subtype);
printf(" Unit ID ........... %u\n",
descriptor->unit_id);
printf(" Source ID ......... 0x%02x\n", descriptor->source_id);
if (bcd_release_no < USB_AUDIO_CLASS_VERSION_2) {
printf(" Control Size ...... %u\n", descriptor->r1.control_size);
uint8 channels = 0;
if (descriptor->r1.control_size > 0)
channels = (descriptor->length - 6) / descriptor->r1.control_size;
for (uint8 i = 0; i < channels; i++) {
switch (descriptor->r1.control_size) {
case 1:
DumpBMAControl(i, descriptor->r1.bma_controls[i], bcd_release_no);
break;
case 2:
DumpBMAControl(i, *(uint16*)&descriptor->r1.bma_controls[i * 2],
bcd_release_no);
break;
case 4:
DumpBMAControl(i, *(uint32*)&descriptor->r1.bma_controls[i * 4],
bcd_release_no);
break;
default:
printf(" BMA Channel %u ... ", i);
for (uint8 j = 0; j < descriptor->r1.control_size; j++)
printf("%02x ", descriptor->r1.bma_controls[i + j]);
printf("\n");
break;
}
}
} else {
printf(" BMA Controls ....... 0x%08" B_PRIx32 "\n",
descriptor->r2.bma_controls[0]);
DumpBMAControl(0, descriptor->r2.bma_controls[0], bcd_release_no);
}
}
void
DumpAudioCSInterfaceDescriptorAssociated(
const usb_generic_descriptor* descriptor)
{
printf(" Type .............. 0x%02x\n",
descriptor->descriptor_type);
printf(" Subtype ........... 0x%02x (Associate Interface)\n",
(uint8)descriptor->data[0]);
printf(" Interface ......... %u\n",
(uint8)descriptor->data[1]);
printf(" Data .............. ");
for (uint8 i = 0; i < descriptor->length - 2; i++)
printf("%02x ", descriptor->data[i]);
printf("\n");
}
void
DumpAudioControlCSInterfaceDescriptor(const usb_generic_descriptor* descriptor)
{
uint8 descriptorSubtype = descriptor->data[0];
static uint16 bcd_release_no;
switch (descriptorSubtype) {
case USB_AUDIO_AC_HEADER:
bcd_release_no = DumpAudioCSInterfaceDescriptorHeader(
(usb_audiocontrol_header_descriptor*)descriptor);
break;
case USB_AUDIO_AC_INPUT_TERMINAL:
DumpAudioCSInterfaceDescriptorInputTerminal(
(usb_audio_input_terminal_descriptor*)descriptor, bcd_release_no);
break;
case USB_AUDIO_AC_OUTPUT_TERMINAL:
DumpAudioCSInterfaceDescriptorOutputTerminal(
(usb_audio_output_terminal_descriptor*)descriptor, bcd_release_no);
break;
case USB_AUDIO_AC_MIXER_UNIT:
DumpAudioCSInterfaceDescriptorMixerUnit(
(usb_audio_mixer_unit_descriptor*)descriptor);
break;
case USB_AUDIO_AC_SELECTOR_UNIT:
DumpAudioCSInterfaceDescriptorSelectorUnit(
(usb_audio_selector_unit_descriptor*)descriptor);
break;
case USB_AUDIO_AC_FEATURE_UNIT:
DumpAudioCSInterfaceDescriptorFeatureUnit(
(usb_audio_feature_unit_descriptor*)descriptor, bcd_release_no);
break;
case USB_AUDIO_AC_EXTENSION_UNIT:
if (bcd_release_no < USB_AUDIO_CLASS_VERSION_2)
DumpAudioCSInterfaceDescriptorAssociated(descriptor);
break;
case USB_AUDIO_AC_PROCESSING_UNIT:
break;
case USB_AUDIO_AC_EXTENSION_UNIT_R2:
break;
case USB_AUDIO_AC_CLOCK_SOURCE_R2:
DumpAudioCSInterfaceDescriptorClockSourceUnit(
(usb_audio_clocksource_descriptor*)descriptor);
break;
case USB_AUDIO_AC_CLOCK_SELECTOR_R2:
DumpAudioCSInterfaceDescriptorClockSelectorUnit(
(usb_audio_clockselector_descriptor*)descriptor);
break;
case USB_AUDIO_AC_CLOCK_MULTIPLIER_R2:
DumpAudioCSInterfaceDescriptorClockMultiplier(
(usb_audio_clockmultiplier_descriptor*)descriptor);
break;
case USB_AUDIO_AC_SAMPLE_RATE_CONVERTER_R2:
break;
default:
DumpDescriptorData(descriptor);
}
}
void
DumpGeneralASInterfaceDescriptor(
const usb_audio_streaming_interface_descriptor* descriptor)
{
printf(" Subtype ........... %u (AS_GENERAL)\n",
descriptor->descriptor_subtype);
printf(" Terminal link ..... %u\n",
descriptor->terminal_link);
printf(" Delay ............. %u\n",
descriptor->r1.delay);
printf(" Format tag ........ %u\n",
descriptor->r1.format_tag);
}
uint32
GetSamplingFrequency(const usb_audio_sampling_freq& freq)
{
return freq.bytes[0] | freq.bytes[1] << 8 | freq.bytes[2] << 16;
}
void
DumpSamplingFrequencies(uint8 type, const usb_audio_sampling_freq* freqs)
{
if (type > 0) {
printf(" Sampling Freq ..... ");
for (uint8 i = 0; i < type; i++)
printf("%" B_PRIu32 ", ", GetSamplingFrequency(freqs[i]));
printf("\n");
} else {
printf(" Sampling Freq ..... %" B_PRIu32 " to %"
B_PRIu32 "\n", GetSamplingFrequency(freqs[0]),
GetSamplingFrequency(freqs[1]));
}
}
void
DumpASFormatTypeI(const usb_audio_format_descriptor* descriptor)
{
printf(" Subtype ........... %u (FORMAT_TYPE)\n",
descriptor->descriptor_subtype);
printf(" Format Type ....... %u (FORMAT_TYPE_I)\n",
descriptor->format_type);
printf(" Channels .......... %u\n",
descriptor->typeI.nr_channels);
printf(" Subframe size ..... %u\n",
descriptor->typeI.subframe_size);
printf(" Bit resolution .... %u\n",
descriptor->typeI.bit_resolution);
DumpSamplingFrequencies(descriptor->typeI.sam_freq_type,
descriptor->typeI.sam_freqs);
}
void
DumpASFormatTypeIII(const usb_audio_format_descriptor* descriptor)
{
printf(" Subtype ........... %u (FORMAT_TYPE)\n",
descriptor->descriptor_subtype);
printf(" Format Type ....... %u (FORMAT_TYPE_III)\n",
descriptor->format_type);
printf(" Channels .......... %u\n",
descriptor->typeIII.nr_channels);
printf(" Subframe size ..... %u\n",
descriptor->typeIII.subframe_size);
printf(" Bit resolution .... %u\n",
descriptor->typeIII.bit_resolution);
DumpSamplingFrequencies(descriptor->typeIII.sam_freq_type,
descriptor->typeIII.sam_freqs);
}
void
DumpASFormatTypeII(const usb_audio_format_descriptor* descriptor)
{
printf(" Subtype ........... %u (FORMAT_TYPE)\n",
descriptor->descriptor_subtype);
printf(" Format Type ....... %u (FORMAT_TYPE_II)\n",
descriptor->format_type);
printf(" Max Bitrate ....... %u\n",
descriptor->typeII.max_bit_rate);
printf(" Samples per Frame . %u\n",
descriptor->typeII.samples_per_frame);
DumpSamplingFrequencies(descriptor->typeII.sam_freq_type,
descriptor->typeII.sam_freqs);
}
void
DumpASFmtType(const usb_audio_format_descriptor* descriptor)
{
uint8 format = descriptor->format_type;
switch (format) {
case USB_AUDIO_FORMAT_TYPE_I:
DumpASFormatTypeI(descriptor);
break;
case USB_AUDIO_FORMAT_TYPE_II:
DumpASFormatTypeII(descriptor);
break;
case USB_AUDIO_FORMAT_TYPE_III:
DumpASFormatTypeIII(descriptor);
break;
default:
DumpDescriptorData((usb_generic_descriptor*)descriptor);
break;
}
}
void
DumpMPEGCapabilities(uint16 capabilities)
{
const char* MPEGCapabilities[] = {
"Layer I",
"Layer II",
"Layer III",
"MPEG-1 only",
"MPEG-1 dual-channel",
"MPEG-2 second stereo",
"MPEG-2 7.1 channel augumentation",
"Adaptive multi-channel predicion"
};
uint16 mask = 1;
for (uint8 i = 0;
i < sizeof(MPEGCapabilities) / sizeof(MPEGCapabilities[0]); i++) {
if (capabilities & mask)
printf(" %s\n", MPEGCapabilities[i]);
mask <<= 1;
}
mask = 0x300;
uint16 multilingualSupport = (capabilities & mask) >> 8;
switch (multilingualSupport) {
case 0:
printf(" No Multilingual support\n");
break;
case 1:
printf(" Supported at Fs\n");
break;
case 3:
printf(" Supported at Fs and 1/2Fs\n");
break;
default:
break;
}
}
void
DumpMPEGFeatures(uint8 features)
{
uint8 mask = 0x30;
uint8 dynRangeControl = (features & mask) >> 4;
switch (dynRangeControl) {
case 0:
printf(" Not supported\n");
break;
case 1:
printf(" Supported, not scalable\n");
break;
case 2:
printf(" Scalable, common boost, "
"cut scaling value\n");
break;
case 3:
printf(" Scalable, separate boost, "
"cut scaling value\n");
default:
break;
}
}
void
DumpASFmtSpecificMPEG(const usb_generic_descriptor* descriptor)
{
printf(" Subtype ........... %u (FORMAT_SPECIFIC)\n",
descriptor->data[0]);
printf(" Format Tag ........ %u\n",
*(uint16*)&descriptor->data[1]);
printf(" MPEG Capabilities . %u\n",
*(uint16*)&descriptor->data[3]);
DumpMPEGCapabilities(*(uint16*)&descriptor->data[3]);
printf(" MPEG Features ..... %u\n",
descriptor->data[5]);
DumpMPEGFeatures(descriptor->data[5]);
}
void
DumpAC_3Features(uint8 features)
{
const char* featuresStr[] = {
"RF mode",
"Line mode",
"Custom0 mode",
"Custom1 mode"
};
uint8 mask = 1;
for (uint8 i = 0; i < sizeof(featuresStr) / sizeof(const char*); i++) {
if (features & mask)
printf(" %s\n", featuresStr[i]);
mask <<= 1;
}
mask = 0x30;
uint8 dynRangeControl = (features & mask) >> 4;
switch (dynRangeControl) {
case 0:
printf(" Not supported\n");
break;
case 1:
printf(" Supported, not scalable\n");
break;
case 2:
printf(" Scalable, common boost, "
"cut scaling value\n");
break;
case 3:
printf(" Scalable, separate boost, "
"cut scaling value\n");
default:
break;
}
}
void
DumpASFmtSpecificAC_3(const usb_generic_descriptor* descriptor)
{
printf(" Subtype ........... %u (FORMAT_TYPE)\n",
descriptor->data[0]);
printf(" Format Tag ........ %u\n",
*(uint16*)&descriptor->data[1]);
printf(" BSID .............. %" B_PRIx32 "\n",
*(uint32*)&descriptor->data[2]);
printf(" AC3 Features ...... %u\n",
descriptor->data[6]);
DumpAC_3Features(descriptor->data[6]);
}
void
DumpASFmtSpecific(const usb_generic_descriptor* descriptor)
{
enum {
TYPE_II_UNDEFINED = 0x1000,
MPEG = 0x1001,
AC_3 = 0x1002
};
uint16 formatTag = *(uint16*)&descriptor->data[1];
switch (formatTag) {
case MPEG:
DumpASFmtSpecificMPEG(descriptor);
break;
case AC_3:
DumpASFmtSpecificAC_3(descriptor);
break;
default:
DumpDescriptorData(descriptor);
break;
}
}
void
DumpAudioStreamCSInterfaceDescriptor(const usb_generic_descriptor* descriptor)
{
uint8 subtype = descriptor->data[0];
switch (subtype) {
case USB_AUDIO_AS_GENERAL:
DumpGeneralASInterfaceDescriptor(
(usb_audio_streaming_interface_descriptor*)descriptor);
break;
case USB_AUDIO_AS_FORMAT_TYPE:
DumpASFmtType(
(usb_audio_format_descriptor*)descriptor);
break;
case USB_AUDIO_AS_FORMAT_SPECIFIC:
DumpASFmtSpecific(descriptor);
break;
default:
DumpDescriptorData(descriptor);
break;
}
}
void
DumpAudioStreamCSEndpointDescriptor(
const usb_audio_streaming_endpoint_descriptor* descriptor)
{
printf(" Type .............. 0x%02x (CS_ENDPOINT)\n",
descriptor->descriptor_type);
printf(" Subtype ........... 0x%02x (EP_GENERAL)\n",
descriptor->descriptor_subtype);
printf(" Attributes ........ 0x%02x ",
descriptor->attributes);
const char* attributes[] = {
"Sampling Frequency",
"Pitch",
"", "", "", "", "",
"Max Packet Only"
};
uint8 mask = 1;
for (uint8 i = 0; i < sizeof(attributes) / sizeof(attributes[0]); i++) {
if ((descriptor->attributes & mask) != 0)
printf("%s ", attributes[i]);
mask <<= 1;
}
printf("\n");
const char* aUnits[] = {
"Undefined",
"Milliseconds",
"Decoded PCM samples",
"Unknown (%u)"
};
const char* units = descriptor->lock_delay_units >= 4
? aUnits[3] : aUnits[descriptor->lock_delay_units];
printf(" Lock Delay Units .. %u (%s)\n",
descriptor->lock_delay_units, units);
printf(" Lock Delay ........ %u\n",
descriptor->lock_delay);
}
void
DumpMidiInterfaceHeaderDescriptor(
const usb_midi_interface_header_descriptor* descriptor)
{
printf(" Type .............. 0x%02x (CS_ENDPOINT)\n",
descriptor->descriptor_type);
printf(" Subtype ........... 0x%02x (MS_HEADER)\n",
descriptor->descriptor_subtype);
printf(" MSC Version ....... 0x%04x\n",
descriptor->ms_version);
printf(" Length ............ 0x%04x\n",
descriptor->total_length);
}
void
DumpMidiInJackDescriptor(
const usb_midi_in_jack_descriptor* descriptor)
{
printf(" Type .............. 0x%02x (CS_INTERFACE)\n",
descriptor->descriptor_type);
printf(" Subtype ........... 0x%02x (MIDI_IN_JACK)\n",
descriptor->descriptor_subtype);
printf(" Jack ID ........... 0x%02x\n",
descriptor->id);
printf(" String ............ 0x%02x\n",
descriptor->string_descriptor);
switch (descriptor->type) {
case USB_MIDI_EMBEDDED_JACK:
printf(" Jack Type ......... Embedded\n");
break;
case USB_MIDI_EXTERNAL_JACK:
printf(" Jack Type ......... External\n");
break;
default:
printf(" Jack Type ......... 0x%02x (unknown)\n",
descriptor->type);
break;
}
}
void
DumpMidiOutJackDescriptor(
const usb_midi_out_jack_descriptor* descriptor)
{
printf(" Type .............. 0x%02x (CS_INTERFACE)\n",
descriptor->descriptor_type);
printf(" Subtype ........... 0x%02x (MIDI_OUT_JACK)\n",
descriptor->descriptor_subtype);
printf(" Jack ID ........... 0x%02x\n",
descriptor->id);
switch (descriptor->type) {
case USB_MIDI_EMBEDDED_JACK:
printf(" Jack Type ......... Embedded\n");
break;
case USB_MIDI_EXTERNAL_JACK:
printf(" Jack Type ......... External\n");
break;
default:
printf(" Jack Type ......... 0x%02x (unknown)\n",
descriptor->type);
break;
}
for (int i = 0; i < descriptor->inputs_count; i++) {
printf(" Pin %02d ............ (%d,%d)\n", i,
descriptor->input_source[i].source_id,
descriptor->input_source[i].source_pin);
}
}
void
DumpMidiStreamCSInterfaceDescriptor(const usb_generic_descriptor* descriptor)
{
uint8 subtype = descriptor->data[0];
switch (subtype) {
case USB_MS_HEADER_DESCRIPTOR:
DumpMidiInterfaceHeaderDescriptor(
(usb_midi_interface_header_descriptor*)descriptor);
break;
case USB_MS_MIDI_IN_JACK_DESCRIPTOR:
DumpMidiInJackDescriptor(
(usb_midi_in_jack_descriptor*)descriptor);
break;
case USB_MS_MIDI_OUT_JACK_DESCRIPTOR:
DumpMidiOutJackDescriptor(
(usb_midi_out_jack_descriptor*)descriptor);
break;
case USB_MS_ELEMENT_DESCRIPTOR:
DumpDescriptorData(descriptor);
break;
default:
DumpDescriptorData(descriptor);
break;
}
}
void
DumpMidiStreamCSEndpointDescriptor(
const usb_midi_endpoint_descriptor* descriptor)
{
printf(" Type .............. 0x%02x (CS_ENDPOINT)\n",
descriptor->descriptor_type);
printf(" Subtype ........... 0x%02x (MS_GENERAL)\n",
descriptor->descriptor_subtype);
printf(" Jacks ............. ");
for (int i = 0; i < descriptor->jacks_count; i++)
printf("%d, ", descriptor->jacks_id[i]);
printf("\n");
}
void
DumpAudioStreamInterfaceDescriptor(const usb_interface_descriptor* descriptor)
{
printf(" Type .............. %u (INTERFACE)\n",
descriptor->descriptor_type);
printf(" Interface ........... %u\n",
descriptor->interface_number);
printf(" Alternate setting ... %u\n",
descriptor->alternate_setting);
printf(" Endpoints ........... %u\n",
descriptor->num_endpoints);
printf(" Interface class ..... %u (AUDIO)\n",
descriptor->interface_class);
printf(" Interface subclass .. %u (AUDIO_STREAMING)\n",
descriptor->interface_subclass);
printf(" Interface ........... %u\n",
descriptor->interface);
}
void
DumpAudioDescriptor(const usb_generic_descriptor* descriptor, int subclass)
{
const uint8 USB_AUDIO_INTERFACE = 0x04;
switch (subclass) {
case USB_AUDIO_INTERFACE_AUDIOCONTROL_SUBCLASS:
switch (descriptor->descriptor_type) {
case USB_AUDIO_CS_INTERFACE:
DumpAudioControlCSInterfaceDescriptor(descriptor);
break;
default:
DumpDescriptorData(descriptor);
break;
}
break;
case USB_AUDIO_INTERFACE_AUDIOSTREAMING_SUBCLASS:
switch (descriptor->descriptor_type) {
case USB_AUDIO_INTERFACE:
DumpAudioStreamInterfaceDescriptor(
(const usb_interface_descriptor*)descriptor);
break;
case USB_AUDIO_CS_INTERFACE:
DumpAudioStreamCSInterfaceDescriptor(descriptor);
break;
case USB_AUDIO_CS_ENDPOINT:
DumpAudioStreamCSEndpointDescriptor(
(const usb_audio_streaming_endpoint_descriptor*)descriptor);
break;
default:
DumpDescriptorData(descriptor);
break;
}
break;
case USB_AUDIO_INTERFACE_MIDISTREAMING_SUBCLASS:
switch (descriptor->descriptor_type) {
case USB_AUDIO_CS_INTERFACE:
DumpMidiStreamCSInterfaceDescriptor(descriptor);
break;
case USB_AUDIO_CS_ENDPOINT:
DumpMidiStreamCSEndpointDescriptor(
(const usb_midi_endpoint_descriptor*)descriptor);
break;
default:
DumpDescriptorData(descriptor);
break;
}
break;
default:
DumpDescriptorData(descriptor);
break;
}
}