These descriptor definitions descibe how raw descriptor data should be interpreted. Signed-off-by: Michael Drake <michael.drake@xxxxxxxxxxxxxxx> --- desc-defs.c | 728 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ desc-defs.h | 153 +++++++++++++ 2 files changed, 881 insertions(+) create mode 100644 desc-defs.c create mode 100644 desc-defs.h diff --git a/desc-defs.c b/desc-defs.c new file mode 100644 index 0000000..a01aae2 --- /dev/null +++ b/desc-defs.c @@ -0,0 +1,728 @@ +/*****************************************************************************/ + +/* + * desc-defs.c -- USB descriptor definitions + * + * Copyright (C) 2017 Michael Drake <michael.drake@xxxxxxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/*****************************************************************************/ + +#include "config.h" + +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> + +#include "desc-defs.h" + +/** Macro for computing number of elements in array. */ +#define ARRAY_LEN(a) ((sizeof(a)) / (sizeof(a[0]))) + +/** USB Audio Device Class 1 Channel Names. (Note: Order matters.) */ +static const char * const uac1_channel_names[] = { + "Left Front (L)", "Right Front (R)", "Center Front (C)", + "Low Frequency Enhancement (LFE)", "Left Surround (LS)", + "Right Surround (RS)", "Left of Center (LC)", "Right of Center (RC)", + "Surround (S)", "Side Left (SL)", "Side Right (SR)", "Top (T)" +}; + +/** USB Audio Device Class 2 Channel Names. (Note: Order matters.) */ +static const char * const uac2_channel_names[] = { + "Front Left (FL)", "Front Right (FR)", "Front Center (FC)", + "Low Frequency Effects (LFE)", "Back Left (BL)", "Back Right (BR)", + "Front Left of Center (FLC)", "Front Right of Center (FRC)", + "Back Center (BC)", "Side Left (SL)", "Side Right (SR)", + "Top Center (TC)", "Top Front Left (TFL)", "Top Front Center (TFC)", + "Top Front Right (TFR)", "Top Back Left (TBL)", "Top Back Center (TBC)", + "Top Back Right (TBR)", "Top Front Left of Center (TFLC)", + "Top Front Right of Center (TFRC)", "Left Low Frequency Effects (LLFE)", + "Right Low Frequency Effects (RLFE)", "Top Side Left (TSL)", + "Top Side Right (TSR)", "Bottom Center (BC)", + "Back Left of Center (BLC)", "Back Right of Center (BRC)" +}; + +/** Audio Control Interface Header bmControls; Human readable bit meanings. */ +static const char * const uac2_interface_header_bmcontrols[] = { + [0] = "Latency control", + [1] = NULL +}; + +/** UAC1: 4.3.2 Class-Specific AC Interface Descriptor; Table 4-2. */ +static const struct desc desc_audio_1_ac_header[] = { + { .field = "bcdADC", .size = 2, .type = DESC_BCD }, + { .field = "wTotalLength", .size = 2, .type = DESC_CONSTANT }, + { .field = "bInCollection", .size = 1, .type = DESC_CONSTANT }, + { .field = "baInterfaceNr", .size = 1, .type = DESC_NUMBER, + .array = { .array = true } }, + { .field = NULL } +}; + +/** UAC2: 4.7.2 Class-Specific AC Interface Descriptor; Table 4-5. */ +static const struct desc desc_audio_2_ac_header[] = { + { .field = "bcdADC", .size = 2, .type = DESC_BCD }, + { .field = "bCategory", .size = 1, .type = DESC_CONSTANT }, + { .field = "wTotalLength", .size = 2, .type = DESC_NUMBER }, + { .field = "bmControls", .size = 1, .type = DESC_BMCONTROL_2, + .bmcontrol = uac2_interface_header_bmcontrols }, + { .field = NULL } +}; + +/** AudioControl Header descriptor definitions for the three Audio Device Class protocols */ +const struct desc * const desc_audio_ac_header[3] = { + desc_audio_1_ac_header, + desc_audio_2_ac_header, + NULL, /* UAC3 not implemented yet */ +}; + +/** UAC2: 4.7.2.10 Effect Unit Descriptor; Table 4-15. */ +static const struct desc desc_audio_2_ac_effect_unit[] = { + { .field = "bUnitID", .size = 1, .type = DESC_NUMBER }, + { .field = "wEffectType", .size = 2, .type = DESC_CONSTANT }, + { .field = "bSourceID", .size = 1, .type = DESC_CONSTANT }, + { .field = "bmaControls", .size = 4, .type = DESC_BITMAP, + .array = { .array = true } }, + { .field = "iEffects", .size = 1, .type = DESC_STR_DESC_INDEX }, + { .field = NULL } +}; + +/** Effect Unit descriptor definitions for the three Audio Device Class protocols */ +const struct desc * const desc_audio_ac_effect_unit[3] = { + NULL, /* UAC1 not supported */ + desc_audio_2_ac_effect_unit, + NULL, /* UAC3 not implemented yet */ +}; + +/** UAC2 Input Terminal bmControls; Human readable bit meanings. */ +static const char * const uac2_input_term_bmcontrols[] = { + [0] = "Copy Protect", + [1] = "Connector", + [2] = "Overload", + [3] = "Cluster", + [4] = "Underflow", + [5] = "Overflow", + [6] = NULL +}; + +/** UAC1: 4.3.2.1 Input Terminal Descriptor; Table 4-3. */ +static const struct desc desc_audio_1_ac_input_terminal[] = { + { .field = "bTerminalID", .size = 1, .type = DESC_NUMBER }, + { .field = "wTerminalType", .size = 2, .type = DESC_TERMINAL_STR }, + { .field = "bAssocTerminal", .size = 1, .type = DESC_CONSTANT }, + { .field = "bNrChannels", .size = 1, .type = DESC_NUMBER }, + { .field = "wChannelConfig", .size = 2, .type = DESC_BITMAP_STRINGS, + .bitmap_strings = { .strings = uac1_channel_names, .count = 12 } }, + { .field = "iChannelNames", .size = 1, .type = DESC_STR_DESC_INDEX }, + { .field = "iTerminal", .size = 1, .type = DESC_STR_DESC_INDEX }, + { .field = NULL } +}; + +/** UAC2: 4.7.2.4 Input Terminal Descriptor; Table 4-9. */ +static const struct desc desc_audio_2_ac_input_terminal[] = { + { .field = "bTerminalID", .size = 1, .type = DESC_NUMBER }, + { .field = "wTerminalType", .size = 2, .type = DESC_TERMINAL_STR }, + { .field = "bAssocTerminal", .size = 1, .type = DESC_CONSTANT }, + { .field = "bCSourceID", .size = 1, .type = DESC_CONSTANT }, + { .field = "bNrChannels", .size = 1, .type = DESC_NUMBER }, + { .field = "bmChannelConfig", .size = 4, .type = DESC_BITMAP_STRINGS, + .bitmap_strings = { .strings = uac2_channel_names, .count = 26 } }, + { .field = "iChannelNames", .size = 1, .type = DESC_STR_DESC_INDEX }, + { .field = "bmControls", .size = 2, .type = DESC_BMCONTROL_2, + .bmcontrol = uac2_input_term_bmcontrols }, + { .field = "iTerminal", .size = 1, .type = DESC_STR_DESC_INDEX }, + { .field = NULL } +}; + +/** Input Terminal descriptor definitions for the three Audio Device Class protocols */ +const struct desc * const desc_audio_ac_input_terminal[3] = { + desc_audio_1_ac_input_terminal, + desc_audio_2_ac_input_terminal, + NULL, /* UAC3 not implemented yet */ +}; + +/** UAC2 Output Terminal bmControls; Human readable bit meanings. */ +static const char * const uac2_output_term_bmcontrols[] = { + [0] = "Copy Protect", + [1] = "Connector", + [2] = "Overload", + [3] = "Underflow", + [4] = "Overflow", + [5] = NULL +}; + +/** UAC1: 4.3.2.2 Output Terminal Descriptor; Table 4-4. */ +static const struct desc desc_audio_1_ac_output_terminal[] = { + { .field = "bTerminalID", .size = 1, .type = DESC_NUMBER }, + { .field = "wTerminalType", .size = 2, .type = DESC_TERMINAL_STR }, + { .field = "bAssocTerminal", .size = 1, .type = DESC_NUMBER }, + { .field = "bSourceID", .size = 1, .type = DESC_NUMBER }, + { .field = "iTerminal", .size = 1, .type = DESC_STR_DESC_INDEX }, + { .field = NULL } +}; + +/** UAC2: 4.7.2.5 Output Terminal Descriptor; Table 4-10. */ +static const struct desc desc_audio_2_ac_output_terminal[] = { + { .field = "bTerminalID", .size = 1, .type = DESC_NUMBER }, + { .field = "wTerminalType", .size = 2, .type = DESC_TERMINAL_STR }, + { .field = "bAssocTerminal", .size = 1, .type = DESC_NUMBER }, + { .field = "bSourceID", .size = 1, .type = DESC_NUMBER }, + { .field = "bCSourceID", .size = 1, .type = DESC_NUMBER }, + { .field = "bmControls", .size = 2, .type = DESC_BMCONTROL_2, + .bmcontrol = uac2_output_term_bmcontrols }, + { .field = "iTerminal", .size = 1, .type = DESC_STR_DESC_INDEX }, + { .field = NULL } +}; + +/** Output Terminal descriptor definitions for the three Audio Device Class protocols */ +const struct desc * const desc_audio_ac_output_terminal[3] = { + desc_audio_1_ac_output_terminal, + desc_audio_2_ac_output_terminal, + NULL, /* UAC3 not implemented yet */ +}; + +/** UAC2 Mixer Unit bmControls; Human readable bit meanings. */ +static const char * const uac2_mixer_unit_bmcontrols[] = { + [0] = "Cluster", + [1] = "Underflow", + [2] = "Overflow", + [3] = NULL +}; + +/** UAC1: 4.3.2.3 Mixer Unit Descriptor; Table 4-5. */ +static const struct desc desc_audio_1_ac_mixer_unit[] = { + { .field = "bUnitID", .size = 1, .type = DESC_NUMBER }, + { .field = "bNrInPins", .size = 1, .type = DESC_NUMBER }, + { .field = "baSourceID", .size = 1, .type = DESC_NUMBER, + .array = { .array = true, .length_field1 = "bNrInPins" } }, + { .field = "bNrChannels", .size = 1, .type = DESC_NUMBER }, + { .field = "wChannelConfig", .size = 2, .type = DESC_BITMAP_STRINGS, + .bitmap_strings = { .strings = uac1_channel_names, .count = 12 } }, + { .field = "iChannelNames", .size = 1, .type = DESC_STR_DESC_INDEX }, + { .field = "bmControls", .size = 1, .type = DESC_BITMAP, + .array = { .array = true, .bits = true, + .length_field1 = "bNrInPins", + .length_field2 = "bNrChannels" } }, + { .field = "iMixer", .size = 1, .type = DESC_STR_DESC_INDEX }, + { .field = NULL } +}; + +/** UAC2: 4.7.2.6 Mixer Unit Descriptor; Table 4-11. */ +static const struct desc desc_audio_2_ac_mixer_unit[] = { + { .field = "bUnitID", .size = 1, .type = DESC_NUMBER }, + { .field = "bNrInPins", .size = 1, .type = DESC_NUMBER }, + { .field = "baSourceID", .size = 1, .type = DESC_NUMBER, + .array = { .array = true, .length_field1 = "bNrInPins" } }, + { .field = "bNrChannels", .size = 1, .type = DESC_NUMBER }, + { .field = "bmChannelConfig",.size = 4, .type = DESC_BITMAP_STRINGS, + .bitmap_strings = { .strings = uac2_channel_names, .count = 26 } }, + { .field = "iChannelNames", .size = 1, .type = DESC_STR_DESC_INDEX }, + { .field = "bmMixerControls",.size = 1, .type = DESC_BITMAP, + .array = { .array = true, .bits = true, + .length_field1 = "bNrInPins", + .length_field2 = "bNrChannels" } }, + { .field = "bmControls", .size = 1, .type = DESC_BMCONTROL_2, + .bmcontrol = uac2_mixer_unit_bmcontrols }, + { .field = "iMixer", .size = 1, .type = DESC_STR_DESC_INDEX }, + { .field = NULL } +}; + +/** Mixer Unit descriptor definitions for the three Audio Device Class protocols */ +const struct desc * const desc_audio_ac_mixer_unit[3] = { + desc_audio_1_ac_mixer_unit, + desc_audio_2_ac_mixer_unit, + NULL, /* UAC3 not implemented yet */ +}; + +/** Selector Unit bmControls; Human readable bit meanings. */ +static const char * const uac2_selector_unit_bmcontrols[] = { + [0] = "Selector", + [1] = NULL +}; + +/** UAC1: 4.3.2.4 Selector Unit Descriptor; Table 4-6. */ +static const struct desc desc_audio_1_ac_selector_unit[] = { + { .field = "bUnitID", .size = 1, .type = DESC_NUMBER }, + { .field = "bNrInPins", .size = 1, .type = DESC_NUMBER }, + { .field = "baSourceID", .size = 1, .type = DESC_NUMBER, + .array = { .array = true, .length_field1 = "bNrInPins" } }, + { .field = "iSelector", .size = 1, .type = DESC_STR_DESC_INDEX }, + { .field = NULL } +}; + +/** UAC2: 4.7.2.7 Selector Unit Descriptor; Table 4-12. */ +static const struct desc desc_audio_2_ac_selector_unit[] = { + { .field = "bUnitID", .size = 1, .type = DESC_NUMBER }, + { .field = "bNrInPins", .size = 1, .type = DESC_NUMBER }, + { .field = "baSourceID", .size = 1, .type = DESC_NUMBER, + .array = { .array = true, .length_field1 = "bNrInPins" } }, + { .field = "bmControls", .size = 1, .type = DESC_BMCONTROL_2, + .bmcontrol = uac2_selector_unit_bmcontrols }, + { .field = "iSelector", .size = 1, .type = DESC_STR_DESC_INDEX }, + { .field = NULL } +}; + +/** Selector Unit descriptor definitions for the three Audio Device Class protocols */ +const struct desc * const desc_audio_ac_selector_unit[3] = { + desc_audio_1_ac_selector_unit, + desc_audio_2_ac_selector_unit, + NULL, /* UAC3 not implemented yet */ +}; + +/** UAC1: 4.3.2.6 Processing Unit Descriptor; Table 4-8. */ +static const struct desc desc_audio_1_ac_processing_unit[] = { + { .field = "bUnitID", .size = 1, .type = DESC_NUMBER }, + { .field = "wProcessType", .size = 2, .type = DESC_CONSTANT }, + { .field = "bNrInPins", .size = 1, .type = DESC_NUMBER }, + { .field = "baSourceID", .size = 1, .type = DESC_NUMBER, + .array = { .array = true, .length_field1 = "bNrInPins" } }, + { .field = "bNrChannels", .size = 1, .type = DESC_NUMBER }, + { .field = "wChannelConfig", .size = 2, .type = DESC_BITMAP_STRINGS, + .bitmap_strings = { .strings = uac1_channel_names, .count = 12 } }, + { .field = "iChannelNames", .size = 1, .type = DESC_STR_DESC_INDEX }, + { .field = "bControlSize", .size = 1, .type = DESC_NUMBER }, + { .field = "bmControls", .size = 1, .type = DESC_BITMAP, + .array = { .array = true, .length_field1 = "bControlSize" } }, + { .field = "iProcessing", .size = 1, .type = DESC_STR_DESC_INDEX }, + { .field = "Process-specific", .size = 1, .type = DESC_BITMAP, + .array = { .array = true } }, + { .field = NULL } +}; + +/** UAC2: 4.7.2.11 Processing Unit Descriptor; Table 4-20. */ +static const struct desc desc_audio_2_ac_processing_unit[] = { + { .field = "bUnitID", .size = 1, .type = DESC_NUMBER }, + { .field = "wProcessType", .size = 2, .type = DESC_CONSTANT }, + { .field = "bNrInPins", .size = 1, .type = DESC_NUMBER }, + { .field = "baSourceID", .size = 1, .type = DESC_NUMBER, + .array = { .array = true, .length_field1 = "bNrInPins" } }, + { .field = "bNrChannels", .size = 1, .type = DESC_NUMBER }, + { .field = "bmChannelConfig", .size = 4, .type = DESC_BITMAP_STRINGS, + .bitmap_strings = { .strings = uac2_channel_names, .count = 26 } }, + { .field = "iChannelNames", .size = 1, .type = DESC_STR_DESC_INDEX }, + { .field = "bControlSize", .size = 1, .type = DESC_NUMBER }, + { .field = "bmControls", .size = 2, .type = DESC_BITMAP, + .array = { .array = true, .length_field1 = "bControlSize" } }, + { .field = "iProcessing", .size = 1, .type = DESC_STR_DESC_INDEX }, + { .field = "Process-specific", .size = 1, .type = DESC_BITMAP, + .array = { .array = true } }, + { .field = NULL } +}; + +/** Processing Unit descriptor definitions for the three Audio Device Class protocols */ +const struct desc * const desc_audio_ac_processing_unit[3] = { + desc_audio_1_ac_processing_unit, + desc_audio_2_ac_processing_unit, + NULL, /* UAC3 not implemented yet */ +}; + +/** Audio Control Feature Unit bmControls; Human readable bit meanings. */ +static const char * const uac_feature_unit_bmcontrols[] = { + [ 0] = "Mute", + [ 1] = "Volume", + [ 2] = "Bass", + [ 3] = "Mid", + [ 4] = "Treble", + [ 5] = "Graphic Equalizer", + [ 6] = "Automatic Gain", + [ 7] = "Delay", + [ 8] = "Bass Boost", + [ 9] = "Loudness", + [10] = "Input gain", + [11] = "Input gain pad", + [12] = "Phase inverter", + [13] = NULL +}; + +/** UAC1: 4.3.2.5 Feature Unit Descriptor; Table 4-7. */ +static const struct desc desc_audio_1_ac_feature_unit[] = { + { .field = "bUnitID", .size = 1, .type = DESC_NUMBER }, + { .field = "bSourceID", .size = 1, .type = DESC_CONSTANT }, + { .field = "bControlSize", .size = 1, .type = DESC_NUMBER }, + { .field = "bmaControls", .size_field = "bControlSize", .type = DESC_BMCONTROL_1, + .bmcontrol = uac_feature_unit_bmcontrols, .array = { .array = true } }, + { .field = "iFeature", .size = 1, .type = DESC_STR_DESC_INDEX }, + { .field = NULL } +}; + +/** UAC2: 4.7.2.8 Feature Unit Descriptor; Table 4-13. */ +static const struct desc desc_audio_2_ac_feature_unit[] = { + { .field = "bUnitID", .size = 1, .type = DESC_NUMBER }, + { .field = "bSourceID", .size = 1, .type = DESC_CONSTANT }, + { .field = "bmaControls", .size = 4, .type = DESC_BMCONTROL_2, + .bmcontrol = uac_feature_unit_bmcontrols, .array = { .array = true } }, + { .field = "iFeature", .size = 1, .type = DESC_STR_DESC_INDEX }, + { .field = NULL } +}; + +/** Feature Unit descriptor definitions for the three Audio Device Class protocols */ +const struct desc * const desc_audio_ac_feature_unit[3] = { + desc_audio_1_ac_feature_unit, + desc_audio_2_ac_feature_unit, + NULL, /* UAC3 not implemented yet */ +}; + +/** UAC2 Extension Unit bmControls; Human readable bit meanings. */ +static const char * const uac2_extension_unit_bmcontrols[] = { + [0] = "Enable", + [1] = "Cluster", + [2] = "Underflow", + [3] = "Overflow", + [4] = NULL +}; + +/** UAC1: 4.3.2.7 Extension Unit Descriptor; Table 4-15. */ +static const struct desc desc_audio_1_ac_extension_unit[] = { + { .field = "bUnitID", .size = 1, .type = DESC_NUMBER }, + { .field = "wExtensionCode", .size = 2, .type = DESC_CONSTANT }, + { .field = "bNrInPins", .size = 1, .type = DESC_NUMBER }, + { .field = "baSourceID", .size = 1, .type = DESC_NUMBER, + .array = { .array = true, .length_field1 = "bNrInPins" } }, + { .field = "bNrChannels", .size = 1, .type = DESC_NUMBER }, + { .field = "wChannelConfig", .size = 2, .type = DESC_BITMAP_STRINGS, + .bitmap_strings = { .strings = uac1_channel_names, .count = 12 } }, + { .field = "iChannelNames", .size = 1, .type = DESC_STR_DESC_INDEX }, + { .field = "bControlSize", .size = 1, .type = DESC_NUMBER }, + { .field = "bmControls", .size = 1, .type = DESC_BITMAP, + .array = { .array = true, .length_field1 = "bControlSize" } }, + { .field = "iExtension", .size = 1, .type = DESC_STR_DESC_INDEX }, + { .field = NULL } +}; + +/** UAC2: 4.7.2.12 Extension Unit Descriptor; Table 4-24. */ +static const struct desc desc_audio_2_ac_extension_unit[] = { + { .field = "bUnitID", .size = 1, .type = DESC_NUMBER }, + { .field = "wExtensionCode", .size = 2, .type = DESC_CONSTANT }, + { .field = "bNrInPins", .size = 1, .type = DESC_NUMBER }, + { .field = "baSourceID", .size = 1, .type = DESC_NUMBER, + .array = { .array = true, .length_field1 = "bNrInPins" } }, + { .field = "bNrChannels", .size = 1, .type = DESC_NUMBER }, + { .field = "bmChannelConfig", .size = 4, .type = DESC_BITMAP_STRINGS, + .bitmap_strings = { .strings = uac2_channel_names, .count = 26 } }, + { .field = "iChannelNames", .size = 1, .type = DESC_STR_DESC_INDEX }, + { .field = "bmControls", .size = 1, .type = DESC_BMCONTROL_2, + .bmcontrol = uac2_extension_unit_bmcontrols }, + { .field = "iExtension", .size = 1, .type = DESC_STR_DESC_INDEX }, + { .field = NULL } +}; + +/** Extension Unit descriptor definitions for the three Audio Device Class protocols */ +const struct desc * const desc_audio_ac_extension_unit[3] = { + desc_audio_1_ac_extension_unit, + desc_audio_2_ac_extension_unit, + NULL, /* UAC3 not implemented yet */ +}; + +/** UAC2 Clock Source bmControls; Human readable bit meanings. */ +static const char * const uac2_clock_source_bmcontrols[] = { + [0] = "Clock Frequency", + [1] = "Clock Validity", + [2] = NULL +}; + +static const char * const uac2_clk_src_bmattr[] = { + [0] = "External", + [1] = "Internal fixed", + [2] = "Internal variable", + [3] = "Internal programmable" +}; + +static const char * const uac3_clk_src_bmattr[] = { + [0] = "External", + [1] = "Internal", + [2] = "(asynchronous)", + [3] = "(synchronized to SOF)" +}; + +/** Special rendering function for UAC2 clock source bmAttributes */ +static void desc_snowflake_dump_uac2_clk_src_bmattr( + unsigned long long value, + unsigned int indent) +{ + printf(" %s clock %s\n", + uac2_clk_src_bmattr[value & 0x3], + (value & 0x4) ? uac3_clk_src_bmattr[3] : ""); +} + +/** UAC2: 4.7.2.1 Clock Source Descriptor; Table 4-6. */ +static const struct desc desc_audio_2_ac_clock_source[] = { + { .field = "bClockID", .size = 1, .type = DESC_CONSTANT }, + { .field = "bmAttributes", .size = 1, .type = DESC_SNOWFLAKE, + .snowflake = desc_snowflake_dump_uac2_clk_src_bmattr }, + { .field = "bmControls", .size = 1, .type = DESC_BMCONTROL_2, + .bmcontrol = uac2_clock_source_bmcontrols }, + { .field = "bAssocTerminal", .size = 1, .type = DESC_CONSTANT }, + { .field = "iClockSource", .size = 1, .type = DESC_STR_DESC_INDEX }, + { .field = NULL } +}; + +/** Clock Source descriptor definitions for the three Audio Device Class protocols */ +const struct desc * const desc_audio_ac_clock_source[3] = { + NULL, /* UAC1 not supported */ + desc_audio_2_ac_clock_source, + NULL, /* UAC3 not implemented yet */ +}; + +/** UAC2 Clock Selector bmControls; Human readable bit meanings. */ +static const char * const uac2_clock_selector_bmcontrols[] = { + [0] = "Clock Selector", + [1] = NULL +}; + +/** UAC2: 4.7.2.2 Clock Selector Descriptor; Table 4-7. */ +static const struct desc desc_audio_2_ac_clock_selector[] = { + { .field = "bClockID", .size = 1, .type = DESC_NUMBER }, + { .field = "bNrInPins", .size = 1, .type = DESC_NUMBER }, + { .field = "baCSourceID", .size = 1, .type = DESC_NUMBER, + .array = { .array = true, .length_field1 = "bNrInPins" } }, + { .field = "bmControls", .size = 1, .type = DESC_BMCONTROL_2, + .bmcontrol = uac2_clock_selector_bmcontrols }, + { .field = "iClockSelector", .size = 1, .type = DESC_STR_DESC_INDEX }, + { .field = NULL } +}; + +/** Clock Selector descriptor definitions for the three Audio Device Class protocols */ +const struct desc * const desc_audio_ac_clock_selector[3] = { + NULL, /* UAC1 not supported */ + desc_audio_2_ac_clock_selector, + NULL, /* UAC3 not implemented yet */ +}; + +/** UAC2 Clock Multiplier bmControls; Human readable bit meanings. */ +static const char * const uac2_clock_multiplier_bmcontrols[] = { + [0] = "Clock Numerator", + [1] = "Clock Denominator", + [2] = NULL +}; + +/** UAC2: 4.7.2.3 Clock Multiplier Descriptor; Table 4-8. */ +static const struct desc desc_audio_2_ac_clock_multiplier[] = { + { .field = "bClockID", .size = 1, .type = DESC_CONSTANT }, + { .field = "bCSourceID", .size = 1, .type = DESC_NUMBER }, + { .field = "bmControls", .size = 1, .type = DESC_BMCONTROL_2, + .bmcontrol = uac2_clock_multiplier_bmcontrols }, + { .field = "iClockMultiplier", .size = 1, .type = DESC_STR_DESC_INDEX }, + { .field = NULL } +}; + +/** Clock Multiplier descriptor definitions for the three Audio Device Class protocols */ +const struct desc * const desc_audio_ac_clock_multiplier[3] = { + NULL, /* UAC1 not supported */ + desc_audio_2_ac_clock_multiplier, + NULL, /* UAC3 not implemented yet */ +}; + +/** UAC2: 4.7.2.9 Sampling Rate Converter Descriptor; Table 4-14. */ +static const struct desc desc_audio_2_ac_sample_rate_converter[] = { + { .field = "bUnitID", .size = 1, .type = DESC_CONSTANT }, + { .field = "bSourceID", .size = 1, .type = DESC_CONSTANT }, + { .field = "bCSourceInID", .size = 1, .type = DESC_CONSTANT }, + { .field = "bCSourceOutID", .size = 1, .type = DESC_CONSTANT }, + { .field = "iSRC", .size = 1, .type = DESC_STR_DESC_INDEX }, + { .field = NULL } +}; + +/** Sample Rate Converter descriptor definitions for the three Audio Device Class protocols */ +const struct desc * const desc_audio_ac_sample_rate_converter[3] = { + NULL, /* UAC1 not supported */ + desc_audio_2_ac_sample_rate_converter, + NULL, /* UAC3 not implemented yet */ +}; + +/** UAC2 AudioStreaming Interface bmControls; Human readable bit meanings. */ +static const char * const uac2_as_interface_bmcontrols[] = { + [0] = "Active Alternate Setting", + [1] = "Valid Alternate Setting", + [2] = NULL +}; + +/* wFormatTag hex prefix for format type */ +#define UAC_FORMAT_TYPE_I 0x0 +#define UAC_FORMAT_TYPE_II 0x1 +#define UAC_FORMAT_TYPE_III 0x2 + +/** Format type I codes; Human-readable values. */ +static const char * const audio_data_format_type_i[] = { + [0] = "TYPE_I_UNDEFINED", + [1] = "PCM", + [2] = "PCM8", + [3] = "IEEE_FLOAT", + [4] = "ALAW", + [5] = "MULAW" +}; + +/** Format type II codes; Human-readable values. */ +static const char * const audio_data_format_type_ii[] = { + [0] = "TYPE_II_UNDEFINED", + [1] = "MPEG", + [2] = "AC-3" +}; + +/** Format type III codes; Human-readable values. */ +static const char * const audio_data_format_type_iii[] = { + [0] = "TYPE_III_UNDEFINED", + [1] = "IEC1937_AC-3", + [2] = "IEC1937_MPEG-1_Layer1", + [3] = "IEC1937_MPEG-Layer2/3/NOEXT", + [4] = "IEC1937_MPEG-2_EXT", + [5] = "IEC1937_MPEG-2_Layer1_LS", + [6] = "IEC1937_MPEG-2_Layer2/3_LS" +}; + +/** Special rendering function for UAC1 AS interface wFormatTag */ +static void desc_snowflake_dump_uac1_as_interface_wformattag( + unsigned long long value, + unsigned int indent) +{ + const char *format_string = "undefined"; + + /* Format codes are 0xTNNN, where T=Type prefix, NNN = format code. */ + + if (value <= ((UAC_FORMAT_TYPE_I << 12) + + ARRAY_LEN(audio_data_format_type_i))) { + format_string = audio_data_format_type_i[value]; + + } else if ((value >= (UAC_FORMAT_TYPE_II << 12)) && + (value <= ((UAC_FORMAT_TYPE_II << 12) + + ARRAY_LEN(audio_data_format_type_ii)))) { + format_string = audio_data_format_type_ii[value & 0xfff]; + + } else if ((value >= (UAC_FORMAT_TYPE_III << 12)) && + (value <= ((UAC_FORMAT_TYPE_III << 12) + + ARRAY_LEN(audio_data_format_type_iii)))) { + format_string = audio_data_format_type_iii[value & 0xfff]; + } + + printf(" %s\n", format_string); +} + +/** Special rendering function for UAC1 AS interface wFormatTag */ +static void desc_snowflake_dump_uac1_as_interface_wformattag( + unsigned long long value, + unsigned int indent) +{ + const char *format_string = "undefined"; + + if (value <= 5) { + format_string = audio_data_format_type_i[value]; + + } else if (value >= 0x1000 && value <= 0x1002) { + format_string = audio_data_format_type_ii[value & 0xfff]; + + } else if (value >= 0x2000 && value <= 0x2006) { + format_string = audio_data_format_type_iii[value & 0xfff]; + } + + printf(" %s\n", format_string); +} + +/** Special rendering function for UAC2 AS interface bmFormats */ +static void desc_snowflake_dump_uac2_as_interface_bmformats( + unsigned long long value, + unsigned int indent) +{ + unsigned int i; + + printf("\n"); + for (i = 0; i < 5; i++) { + if ((value >> i) & 0x1) { + printf("%*s%s\n", indent * 2, "", + audio_data_format_type_i[i + 1]); + } + } + +} + +/** UAC1: 4.5.2 Class-Specific AS Interface Descriptor; Table 4-19. */ +static const struct desc desc_audio_1_as_interface[] = { + { .field = "bTerminalLink", .size = 1, .type = DESC_CONSTANT }, + { .field = "bDelay", .size = 1, .type = DESC_NUMBER_POSTFIX, + .number_postfix = " frames" }, + { .field = "wFormatTag", .size = 2, .type = DESC_SNOWFLAKE, + .snowflake = desc_snowflake_dump_uac1_as_interface_wformattag }, + { .field = NULL } +}; + +/** UAC2: 4.9.2 Class-Specific AS Interface Descriptor; Table 4-27. */ +static const struct desc desc_audio_2_as_interface[] = { + { .field = "bTerminalLink", .size = 1, .type = DESC_NUMBER }, + { .field = "bmControls", .size = 1, .type = DESC_BMCONTROL_2, + .bmcontrol = uac2_as_interface_bmcontrols }, + { .field = "bFormatType", .size = 1, .type = DESC_CONSTANT }, + { .field = "bmFormats", .size = 4, .type = DESC_SNOWFLAKE, + .snowflake = desc_snowflake_dump_uac2_as_interface_bmformats }, + { .field = "bNrChannels", .size = 1, .type = DESC_NUMBER }, + { .field = "bmChannelConfig", .size = 4, .type = DESC_BITMAP_STRINGS, + .bitmap_strings = { .strings = uac2_channel_names, .count = 26 } }, + { .field = "iChannelNames", .size = 1, .type = DESC_STR_DESC_INDEX }, + { .field = NULL } +}; + +const struct desc * const desc_audio_as_interface[3] = { + desc_audio_1_as_interface, + desc_audio_2_as_interface, + NULL, /* UAC3 not implemented yet */ +}; + +static const char * const uac1_as_endpoint_bmattributes[] = { + [0] = "Sampling Frequency", + [1] = "Pitch", + [2] = "Audio Data Format Control", + [7] = "MaxPacketsOnly" +}; + +static const char * const uac2_as_endpoint_bmattributes[] = { + [7] = "MaxPacketsOnly", +}; + +static const char * const uac2_as_isochronous_audio_data_endpoint_bmcontrols[] = { + "Pitch", + "Data Overrun", + "Data Underrun", + NULL +}; + +static const char * const uac_as_isochronous_audio_data_endpoint_blockdelayunits[] = { + "Undefined", + "Milliseconds", + "Decoded PCM samples", + NULL +}; + +/** UAC1: 4.6.1.2 Class-Specific AS Isochronous Audio Data Endpoint Descriptor; Table 4-21. */ +static const struct desc desc_audio_1_as_isochronous_audio_data_endpoint[] = { + { .field = "bmAttributes", .size = 1, .type = DESC_BITMAP_STRINGS, + .bitmap_strings = { .strings = uac1_as_endpoint_bmattributes, .count = 8 } }, + { .field = "bLockDelayUnits", .size = 1, .type = DESC_NUMBER_STRINGS, + .number_strings = uac_as_isochronous_audio_data_endpoint_blockdelayunits }, + { .field = "wLockDelay", .size = 2, .type = DESC_NUMBER }, + { .field = NULL } +}; + +/** UAC2: 4.10.1.2 Class-Specific AS Isochronous Audio Data Endpoint Descriptor; Table 4-34. */ +static const struct desc desc_audio_2_as_isochronous_audio_data_endpoint[] = { + { .field = "bmAttributes", .size = 1, .type = DESC_BITMAP_STRINGS, + .bitmap_strings = { .strings = uac2_as_endpoint_bmattributes, .count = 8 } }, + { .field = "bmControls", .size = 1, .type = DESC_BMCONTROL_2, + .bmcontrol = uac2_as_isochronous_audio_data_endpoint_bmcontrols }, + { .field = "bLockDelayUnits", .size = 1, .type = DESC_NUMBER_STRINGS, + .number_strings = uac_as_isochronous_audio_data_endpoint_blockdelayunits }, + { .field = "wLockDelay", .size = 2, .type = DESC_NUMBER }, + { .field = NULL } +}; + +const struct desc * const desc_audio_as_isochronous_audio_data_endpoint[3] = { + desc_audio_1_as_isochronous_audio_data_endpoint, + desc_audio_2_as_isochronous_audio_data_endpoint, + NULL, /* UAC3 not implemented yet */ +}; diff --git a/desc-defs.h b/desc-defs.h new file mode 100644 index 0000000..759ac4c --- /dev/null +++ b/desc-defs.h @@ -0,0 +1,153 @@ +/*****************************************************************************/ + +/* + * desc-defs.h -- USB descriptor definitions + * + * Copyright (C) 2017 Michael Drake <michael.drake@xxxxxxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/*****************************************************************************/ + +#ifndef _DESC_DEFS_H +#define _DESC_DEFS_H + +/* ---------------------------------------------------------------------- */ + +/** + * Descriptor field value type. + * + * Note that there are more types here than exist in the descriptor definitions + * in the specifications. This is because the type here is used to do `lsusb` + * specific rendering of certain fields. + * + * Note that the use of certain types mandates the setting of various entries + * in the type-specific anonymous union in `struct desc`. + */ +enum desc_type { + DESC_CONSTANT, /** Plain numerical value; no annotation. */ + DESC_NUMBER, /** Plain numerical value; no annotation. */ + DESC_NUMBER_POSTFIX, /**< Number with a postfix string. */ + DESC_BITMAP, /**< Plain hex rendered value; no annotation. */ + DESC_BCD, /**< Binary coded decimal */ + DESC_BMCONTROL_1, /**< UAC1 style bmControl field */ + DESC_BMCONTROL_2, /**< UAC2/UAC3 style bmControl field */ + DESC_STR_DESC_INDEX, /**< String index. */ + DESC_TERMINAL_STR, /**< Audio terminal string. */ + DESC_BITMAP_STRINGS, /**< Bitfield with string per bit. */ + DESC_NUMBER_STRINGS, /**< Use for enum-style value to string. */ + DESC_SNOWFLAKE, /**< Value with custom annotation callback function. */ +}; + +/** + * Callback function for the DESC_SNOWFLAKE descriptor field value type. + * + * This is used when some special rendering of the value is required, which + * is specific to the field in question, so no generic type's rendering is + * suitable. + * + * The core descriptor dumping code will have already dumped the numerical + * value for the field, but not the trailing newline character. It is up + * to the callback function to ensure it always finishes by writing a '\n' + * character to stdout. + * + * \param[in] value The value to dump a human-readable representation of. + * \param[in] indent The current indent level. + */ +typedef void (*desc_snowflake_dump_fn)( + unsigned long long value, + unsigned int indent); + + +/** + * Descriptor field definition. + * + * Whole descriptors can be defined as NULL terminated arrays of these + * structures. + */ +struct desc { + const char *field; /**< Field's name */ + unsigned int size; /**< Byte size of field, if (size_field == NULL) */ + const char *size_field; /**< Name of field specifying field size. */ + enum desc_type type; /**< Field's value type. */ + + /** Anonymous union containing type-specific data. */ + union { + /** + * Corresponds to types DESC_BMCONTROL_1 and DESC_BMCONTROL_2. + * + * Must be a NULL terminated array of '\0' terminated strings. + */ + const char * const *bmcontrol; + /** Corresponds to type DESC_BITMAP_STRINGS */ + struct { + /** Must contain '\0' terminated strings. */ + const char * const *strings; + /** Number of strings in strings array. */ + unsigned int count; + } bitmap_strings; + /** + * Corresponds to type DESC_NUMBER_STRINGS. + * + * Must be a NULL terminated array of '\0' terminated strings. + */ + const char * const *number_strings; + /** + * Corresponds to type DESC_NUMBER_POSTFIX. + * + * Must be a '\0' terminated string. + */ + const char *number_postfix; + /** + * Corresponds to type DESC_SNOWFLAKE. + * + * Callback function called to annotate snowflake value type. + */ + desc_snowflake_dump_fn snowflake; + }; + + /** Grouping of array-specific fields. */ + struct { + bool array; /**< True if entry is an array. */ + bool bits; /**< True if array length is specified in bits */ + /** Name of field specifying the array entry count. */ + const char *length_field1; + /** Name of field specifying multiplier for array entry count. */ + const char *length_field2; + } array; +}; + +/* ---------------------------------------------------------------------- */ + +/* Audio Control (AC) descriptor definitions */ +extern const struct desc * const desc_audio_ac_header[3]; +extern const struct desc * const desc_audio_ac_effect_unit[3]; +extern const struct desc * const desc_audio_ac_input_terminal[3]; +extern const struct desc * const desc_audio_ac_output_terminal[3]; +extern const struct desc * const desc_audio_ac_mixer_unit[3]; +extern const struct desc * const desc_audio_ac_selector_unit[3]; +extern const struct desc * const desc_audio_ac_processing_unit[3]; +extern const struct desc * const desc_audio_ac_feature_unit[3]; +extern const struct desc * const desc_audio_ac_extension_unit[3]; +extern const struct desc * const desc_audio_ac_clock_source[3]; +extern const struct desc * const desc_audio_ac_clock_selector[3]; +extern const struct desc * const desc_audio_ac_clock_multiplier[3]; +extern const struct desc * const desc_audio_ac_sample_rate_converter[3]; + +/* Audio Streaming (AS) descriptor definitions */ +extern const struct desc * const desc_audio_as_interface[3]; +extern const struct desc * const desc_audio_as_isochronous_audio_data_endpoint[3]; + +/* ---------------------------------------------------------------------- */ + +#endif /* _DESC_DEFS_H */ -- 2.11.0 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html