diff --git a/headers/os/drivers/usb/USB_audio.h b/headers/os/drivers/usb/USB_audio.h index c02a767b8a..53e5fea22d 100644 --- a/headers/os/drivers/usb/USB_audio.h +++ b/headers/os/drivers/usb/USB_audio.h @@ -8,7 +8,8 @@ #include #define USB_AUDIO_DEVICE_CLASS 0x01 -#define USB_AUDIO_CLASS_VERSION 0x0100 +#define USB_AUDIO_CLASS_VERSION_1 0x0100 +#define USB_AUDIO_CLASS_VERSION_2 0x0200 enum { USB_AUDIO_INTERFACE_AUDIO_CLASS = 0x01 @@ -21,8 +22,8 @@ enum { // Audio Interface Subclasses USB_AUDIO_INTERFACE_MIDISTREAMING_SUBCLASS }; -enum { // Audio Interface Protocol Codes - USB_AUDIO_PROTOCOL_UNDEFINED = 0x00 +enum { // Audio Interface Protocol Codes + USB_AUDIO_PROTOCOL_UNDEFINED = 0x00 }; enum { // Audio Interface Class-Specific Descriptor Types @@ -56,7 +57,7 @@ enum { // Audio Class-Specific AudioControl Interface descriptor subtypes // Class Specific Audio Control Interface Header -// R1: Table 4-2 p.37 / R2: Table 4-5 p.48 +// R1: Table 4-2 p.37 / R2: Table 4-5 p.48 typedef struct { uint8 length; uint8 descriptor_type; // USB_AUDIO_CS_INTERFACE @@ -77,6 +78,43 @@ typedef struct { }; } _PACKED usb_audiocontrol_header_descriptor; +// Clock Source Descriptor +// R2: Table 4-6 p.49 +typedef struct { + uint8 length; + uint8 descriptor_type; // USB_AUDIO_CS_INTERFACE + uint8 descriptor_subtype; // USB_AUDIO_CLOCKSOURCE_HEADER + uint8 clock_id; + uint8 bm_attributes; + uint8 bm_controls; + uint8 assoc_terminal; + uint8 clock_source_idx; +} _PACKED usb_audio_clocksource_descriptor; + +// Clock Selector Descriptor +// R2: Table 4-7 p.50 +typedef struct { + uint8 length; + uint8 descriptor_type; // USB_AUDIO_CS_INTERFACE + uint8 descriptor_subtype; // USB_AUDIO_CLOCKSELECTOR_HEADER + uint8 clock_id; + uint8 nrinpins; + uint8 Csourceid[1]; + uint8 bm_controls; + uint8 clockselector; +} _PACKED usb_audio_clockselector_descriptor; + +// Clock Multiplier Descriptor +// R2: Table 4-8 p.51 +typedef struct { + uint8 length; + uint8 descriptor_type; // USB_AUDIO_CS_INTERFACE + uint8 descriptor_subtype; // USB_AUDIO_CLOCKMULTIPLIER + uint8 clockid; + uint8 clksourceid; + uint8 bm_controls; + uint8 clockmultiplier; +} _PACKED usb_audio_clockmultiplier_descriptor; // Input Terminal Descriptor // R1: Table 4-3 p.39 / R2: Table 4-9, page 53 @@ -116,16 +154,16 @@ typedef struct { uint8 terminal_id; uint16 terminal_type; uint8 assoc_terminal; - uint8 source_id; + uint8 source_id; union { struct { - uint8 terminal; + uint8 terminal; } _PACKED r1; struct { - uint8 clock_source_id; - uint16 bm_controls; - uint8 terminal; + uint8 clock_source_id; + uint16 bm_controls; + uint8 terminal; } _PACKED r2; }; } _PACKED usb_audio_output_terminal_descriptor; @@ -168,7 +206,7 @@ typedef struct { uint8 unit_id; uint8 num_input_pins; uint8 input_pins[1]; - // uint8 selector_string; + // uint8 selector_string; } _PACKED usb_audio_selector_unit_descriptor; @@ -182,14 +220,13 @@ typedef struct { uint8 source_id; union { struct { - uint8 control_size; - uint8 bma_controls[1]; + uint8 control_size; + uint8 bma_controls[1]; // uint8 feature_string; } _PACKED r1; struct { - uint32 bma_controls[1]; - // uint8 feature_string; + uint32 bma_controls[1]; } _PACKED r2; }; } _PACKED usb_audio_feature_unit_descriptor; @@ -198,13 +235,13 @@ typedef struct { // Processing Unit Descriptor // R1: Table 4-8 p.45 / R2: Table 4-20, page 66 typedef struct { - uint8 length; - uint8 descriptor_type; // USB_AUDIO_CS_INTERFACE - uint8 descriptor_subtype; // USB_AUDIO_AC_PROCESSING_UNIT - uint8 unit_id; - uint16 process_type; - uint8 num_input_pins; - uint8 input_pins[1]; + uint8 length; + uint8 descriptor_type; // USB_AUDIO_CS_INTERFACE + uint8 descriptor_subtype; // USB_AUDIO_AC_PROCESSING_UNIT + uint8 unit_id; + uint16 process_type; + uint8 num_input_pins; + uint8 input_pins[1]; // use usb_audio_output_channels_descriptor to parse the rest // TODO - the bmControl!!!! } _PACKED usb_audio_processing_unit_descriptor; @@ -231,7 +268,7 @@ enum { // Audio Class-Specific AudioStreaming Interface descriptor subtypes }; // Class Specific Audio Streaming Interface Descriptor -// R1: Table 4-19 p.60 / R2: Table 4-27 p.76 +// R1: Table 4-19 p.60 / R2: Table 4-27 p.76 typedef struct { uint8 length; uint8 descriptor_type; // USB_AUDIO_CS_INTERFACE @@ -246,7 +283,7 @@ typedef struct { struct { uint8 bm_controls; uint8 format_type; - uint32 bm_formats; + uint32 bm_formats; uint8 num_output_pins; uint32 channel_config; uint8 channel_names; @@ -258,12 +295,12 @@ typedef struct { // Class-specific As Isochronous Audio Data Endpoint descriptor // R1: Table 4-21, p. 62 / R2: Table 4-34, page 87 typedef struct { - uint8 length; - uint8 descriptor_type; // USB_AUDIO_CS_ENDPOINT - uint8 descriptor_subtype; // USB_AUDIO_EP_GENERAL - uint8 attributes; - uint8 lock_delay_units; - uint16 lock_delay; + uint8 length; + uint8 descriptor_type; // USB_AUDIO_CS_ENDPOINT + uint8 descriptor_subtype; // USB_AUDIO_EP_GENERAL + uint8 attributes; + uint8 lock_delay_units; + uint16 lock_delay; } _PACKED usb_audio_streaming_endpoint_descriptor; @@ -432,7 +469,7 @@ typedef struct { uint8 sample_freq_type; uint8 sample_freq[3]; // [0] + [1] << 8 + [2] << 16 // if sample_freq_type != 1, - // (sample_freq_type - 1) x uint8 sample_freq[3] follows... + // (sample_freq_type - 1) x uint8 sample_freq[3] follows... } _PACKED usb_audio_format_type_descriptor; */ // bitset for feature control bitmap diff --git a/src/bin/listusb/usb_audio.cpp b/src/bin/listusb/usb_audio.cpp index ec86e9e481..27594ecbb0 100644 --- a/src/bin/listusb/usb_audio.cpp +++ b/src/bin/listusb/usb_audio.cpp @@ -2,8 +2,8 @@ * Originally released under the Be Sample Code License. * Copyright 2000, Be Incorporated. All rights reserved. * - * Modified for Haiku by François Revol and Michael Lotz. - * Copyright 2007-2016, Haiku Inc. All rights reserved. + * Modified for Haiku by François Revol, Michael Lotz and Greg Crain. + * Copyright 2007-2024, Haiku Inc. All rights reserved. */ #include @@ -15,7 +15,82 @@ #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) { @@ -23,15 +98,25 @@ DumpAudioCSInterfaceDescriptorHeader( descriptor->descriptor_type); printf(" Subtype ........... 0x%02x (Header)\n", descriptor->descriptor_subtype); - printf(" ADC Release ....... %d.%d\n", + printf(" Audio codec version .. %d.%d\n", descriptor->bcd_release_no >> 8, descriptor->bcd_release_no & 0xFF); - 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"); + 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 { + // Audio 2.0 + 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; } @@ -138,8 +223,10 @@ TerminalTypeName(uint16 terminalType) void DumpAudioCSInterfaceDescriptorInputTerminal( - const usb_audio_input_terminal_descriptor* descriptor) + 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", @@ -151,23 +238,33 @@ DumpAudioCSInterfaceDescriptorInputTerminal( TerminalTypeName(descriptor->terminal_type)); printf(" Associated Terminal %u\n", descriptor->assoc_terminal); - 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); + 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 { + // Audio 2.0 + 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) + 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", @@ -179,10 +276,16 @@ DumpAudioCSInterfaceDescriptorOutputTerminal( TerminalTypeName(descriptor->terminal_type)); printf(" Associated Terminal %u\n", descriptor->assoc_terminal); - printf(" Source ID ......... %u\n", - descriptor->source_id); - printf(" Terminal .......... %u\n", - descriptor->r1.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 { + // Audio 2.0 + 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); + } } @@ -190,6 +293,7 @@ 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", @@ -249,7 +353,7 @@ DumpAudioCSInterfaceDescriptorSelectorUnit( void -DumpBMAControl(uint8 channel, uint32 bma) +DumpBMAControl(uint8 channel, uint32 bma, uint16 bcd_release_no) { const char* BMAControls[] = { "Mute", @@ -273,59 +377,75 @@ DumpBMAControl(uint8 channel, uint32 bma) 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 { + // Audio 2.0 + 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) + 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 ......... %u\n", - descriptor->source_id); + printf(" Source ID ......... 0x%02x\n", descriptor->source_id); - 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]); - break; - case 2: - DumpBMAControl(i, *(uint16*)&descriptor->r1.bma_controls[i * 2]); - break; - case 4: - DumpBMAControl(i, *(uint32*)&descriptor->r1.bma_controls[i * 4]); - 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; + 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; + } + // usb_generic_descriptor* generic = (usb_generic_descriptor*)descriptor; + // printf(" Feature ........... %u\n", + // (uint8)generic->data[descriptor->length - 3]); + } + } else { + // Audio 2.0 + printf(" BMA Controls ....... 0x%08" B_PRIx32 "\n", + descriptor->r2.bma_controls[0]); + DumpBMAControl(0, descriptor->r2.bma_controls[0], bcd_release_no); } - } - - usb_generic_descriptor* generic = (usb_generic_descriptor*)descriptor; - printf(" Feature ........... %u\n", - (uint8)generic->data[descriptor->length - 3]); } - void DumpAudioCSInterfaceDescriptorAssociated( const usb_generic_descriptor* descriptor) @@ -348,18 +468,20 @@ void DumpAudioControlCSInterfaceDescriptor(const usb_generic_descriptor* descriptor) { uint8 descriptorSubtype = descriptor->data[0]; + static uint16 bcd_release_no; + switch (descriptorSubtype) { case USB_AUDIO_AC_HEADER: - DumpAudioCSInterfaceDescriptorHeader( + bcd_release_no = DumpAudioCSInterfaceDescriptorHeader( (usb_audiocontrol_header_descriptor*)descriptor); break; case USB_AUDIO_AC_INPUT_TERMINAL: DumpAudioCSInterfaceDescriptorInputTerminal( - (usb_audio_input_terminal_descriptor*)descriptor); + (usb_audio_input_terminal_descriptor*)descriptor, bcd_release_no); break; case USB_AUDIO_AC_OUTPUT_TERMINAL: DumpAudioCSInterfaceDescriptorOutputTerminal( - (usb_audio_output_terminal_descriptor*)descriptor); + (usb_audio_output_terminal_descriptor*)descriptor, bcd_release_no); break; case USB_AUDIO_AC_MIXER_UNIT: DumpAudioCSInterfaceDescriptorMixerUnit( @@ -371,11 +493,33 @@ DumpAudioControlCSInterfaceDescriptor(const usb_generic_descriptor* descriptor) break; case USB_AUDIO_AC_FEATURE_UNIT: DumpAudioCSInterfaceDescriptorFeatureUnit( - (usb_audio_feature_unit_descriptor*)descriptor); + (usb_audio_feature_unit_descriptor*)descriptor, bcd_release_no); break; case USB_AUDIO_AC_EXTENSION_UNIT: - DumpAudioCSInterfaceDescriptorAssociated(descriptor); + // USB_AUDIO_AC_PROCESSING_UNIT_R2 == USB_AUDIO_AC_EXTENSION_UNIT + if (bcd_release_no < USB_AUDIO_CLASS_VERSION_2) + DumpAudioCSInterfaceDescriptorAssociated(descriptor); break; + case USB_AUDIO_AC_PROCESSING_UNIT: + // USB_AUDIO_AC_EFFECT_UNIT_R2 == 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); }