usb_audio: add missing descriptors for USB Audio 2.0 and update listusb.

Change-Id: Ic294ca78aaf9bd5ac8476595af5e4e223b07e25e
Reviewed-on: https://review.haiku-os.org/c/haiku/+/8372
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
This commit is contained in:
Greg Crain 2024-09-25 08:51:39 +00:00 committed by waddlesplash
parent 8bacd281ba
commit 8251b2c8f6
2 changed files with 273 additions and 92 deletions

View File

@ -8,7 +8,8 @@
#include <SupportDefs.h>
#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

View File

@ -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 <MediaDefs.h>
@ -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);
}