/*++

Copyright (c) 1997-1998 Microsoft Corporation

Module Name:

DISPAUD.C

Abstract:

This source file contains routines which update the edit control
to display information about USB Audio descriptors.

Environment:

user mode

Revision History:

03-07-1998 : created

--*/

//*****************************************************************************
// I N C L U D E S
//*****************************************************************************

#include <windows.h>
#include <basetyps.h>

#include "usbview.h"

//*****************************************************************************
// D E F I N E S
//*****************************************************************************

//*****************************************************************************
// T Y P E D E F S
//*****************************************************************************

typedef struct _TERMTYPE
{
    USHORT TermTypeCode;
    PCHAR  TermTypeName;
} TERMTYPE, *PTERMTYPE;

typedef struct _FORMATTYPE
{
    USHORT FormatTypeCode;
    PCHAR  FormatTypeName;
} FORMATTYPE, *PFORMATTYPE;

//*****************************************************************************
// G L O B A L S    P R I V A T E    T O    T H I S    F I L E
//*****************************************************************************

//
// USB Device Class Definition for Terminal Types  0.9 Draft Revision
//
TERMTYPE TermTypes[] =
{
    //
    // 2.1 USB Terminal Types
    //
    {0x0100, "USB Undefined"},
    {0x0101, "USB streaming"},
    {0x01FF, "USB vendor specific"},
    //
    // 2.2 Input Terminal Types
    //
    {0x0200, "Input Undefined"},
    {0x0201, "Microphone"},
    {0x0202, "Desktop microphone"},
    {0x0203, "Personal microphone"},
    {0x0204, "Omni-directional microphone"},
    {0x0205, "Microphone array"},
    {0x0206, "Processing microphone array"},
    //
    // 2.3 Output Terminal Types
    //
    {0x0300, "Output Undefined"},
    {0x0301, "Speaker"},
    {0x0302, "Headphones"},
    {0x0303, "Head Mounted Display Audio"},
    {0x0304, "Desktop speaker"},
    {0x0305, "Room speaker"},
    {0x0306, "Communication speaker"},
    {0x0307, "Low frequency effects speaker"},
    //
    // 2.4 Bi-directional Terminal Types
    //
    {0x0400, "Bi-directional Undefined"},
    {0x0401, "Handset"},
    {0x0402, "Headset"},
    {0x0403, "Speakerphone, no echo reduction"},
    {0x0404, "Echo-suppressing speakerphone"},
    {0x0405, "Echo-canceling speakerphone"},
    //
    // 2.5 Telephony Terminal Types
    //
    {0x0500, "Telephony Undefined"},
    {0x0501, "Phone line"},
    {0x0502, "Telephone"},
    {0x0503, "Down Line Phone"},
    //
    // 2.6 External Terminal Types
    //
    {0x0600, "External Undefined"},
    {0x0601, "Analog connector"},
    {0x0602, "Digital audio interface"},
    {0x0603, "Line connector"},
    {0x0604, "Legacy audio connector"},
    {0x0605, "S/PDIF interface"},
    {0x0606, "1394 DA stream"},
    {0x0607, "1394 DV stream soundtrack"},
    //
    // Embedded Function Terminal Types
    //
    {0x0700, "Embedded Undefined"},
    {0x0701, "Level Calibration Noise Source"},
    {0x0702, "Equalization Noise"},
    {0x0703, "CD player"},
    {0x0704, "DAT"},
    {0x0705, "DCC"},
    {0x0706, "MiniDisk"},
    {0x0707, "Analog Tape"},
    {0x0708, "Phonograph"},
    {0x0709, "VCR Audio"},
    {0x070A, "Video Disc Audio"},
    {0x070B, "DVD Audio"},
    {0x070C, "TV Tuner Audio"},
    {0x070D, "Satellite Receiver Audio"},
    {0x070E, "Cable Tuner Audio"},
    {0x070F, "DSS Audio"},
    {0x0710, "Radio Receiver"},
    {0x0711, "Radio Transmitter"},
    {0x0712, "Multi-track Recorder"},
    {0x0713, "Synthesizer"},
    //
    // Terminate List
    //
    {0xFFFF, NULL}
};

//
// USB Device Class Definition for Audio Data Formats  0.9 Draft Revision
//
FORMATTYPE FormatTypes[] =
{
    //
    // A.1.1 Audio Data Format Type I Codes
    //
    {0x0000, "TYPE_I_UNDEFINED"},
    {0x0001, "PCM"},
    {0x0002, "PCM8"},
    {0x0003, "IEEE_FLOAT"},
    {0x0004, "ALAW"},
    {0x0005, "MULAW"},
    //
    // A.1.2 Audio Data Format Type II Codes
    //
    {0x1000, "TYPE_II_UNDEFINED"},
    {0x1001, "MPEG"},
    {0x1002, "AC-3"},
    //
    // A.1.3 Audio Data Format Type III Codes
    //
    {0x2000, "TYPE_III_UNDEFINED"},
    {0x2001, "IEC1937_AC-3"},
    {0x2002, "IEC1937_MPEG-1_Layer1"},
    {0x2003, "IEC1937_MPEG-1_Layer2/3 or IEC1937_MPEG-2_NOEXT"},
    {0x2004, "IEC1937_MPEG-2_EXT"},
    {0x2005, "IEC1937_MPEG-2_Layer1_LS"},
    {0x2006, "IEC1937_MPEG-2_Layer2/3_LS"},
    //
    // Terminate List
    //
    {0xFFFF, NULL}
};

//*****************************************************************************
// L O C A L    F U N C T I O N    P R O T O T Y P E S
//*****************************************************************************

BOOL
DisplayACHeader (
    PUSB_AUDIO_AC_INTERFACE_HEADER_DESCRIPTOR HeaderDesc
);

BOOL
DisplayACInputTerminal (
    PUSB_AUDIO_INPUT_TERMINAL_DESCRIPTOR ITDesc
);

BOOL
DisplayACOutputTerminal (
    PUSB_AUDIO_OUTPUT_TERMINAL_DESCRIPTOR OTDesc
);

BOOL
DisplayACMixerUnit (
    PUSB_AUDIO_MIXER_UNIT_DESCRIPTOR MixerDesc
);

BOOL
DisplayACSelectorUnit (
    PUSB_AUDIO_SELECTOR_UNIT_DESCRIPTOR SelectorDesc
);

BOOL
DisplayACFeatureUnit (
    PUSB_AUDIO_FEATURE_UNIT_DESCRIPTOR FeatureDesc
);

BOOL
DisplayACProcessingUnit (
    PUSB_AUDIO_PROCESSING_UNIT_DESCRIPTOR ProcessingDesc
);

BOOL
DisplayACExtensionUnit (
    PUSB_AUDIO_EXTENSION_UNIT_DESCRIPTOR ExtensionDesc
);

BOOL
DisplayASGeneral (
    PUSB_AUDIO_GENERAL_DESCRIPTOR GeneralDesc
);

BOOL
DisplayCSEndpoint (
    PUSB_AUDIO_ENDPOINT_DESCRIPTOR EndpointDesc
);

BOOL
DisplayASFormatType (
    PUSB_AUDIO_COMMON_FORMAT_DESCRIPTOR FormatDesc
);

BOOL
DisplayASFormatSpecific (
    PUSB_AUDIO_COMMON_DESCRIPTOR CommonDesc
);

VOID
DisplayBytes (
    PUCHAR Data,
    USHORT Len
);

PCHAR
TermTypeCodeToName (
    USHORT TermTypeCode
);

PCHAR
FormatTypeCodeToName (
    USHORT FormatTypeCode
);


//*****************************************************************************
// L O C A L    F U N C T I O N S
//*****************************************************************************



//*****************************************************************************
//
// DisplayAudioDescriptor()
//
// CommonDesc - An Audio Class Descriptor
//
// bInterfaceSubClass - The SubClass of the Interface containing the descriptor
//
//*****************************************************************************

BOOL
DisplayAudioDescriptor (
    PUSB_AUDIO_COMMON_DESCRIPTOR CommonDesc,
    UCHAR                        bInterfaceSubClass
)
{
    switch (CommonDesc->bDescriptorType)
    {
        case USB_AUDIO_CS_INTERFACE:
            switch (bInterfaceSubClass)
            {
                case USB_AUDIO_SUBCLASS_AUDIOCONTROL:
                    switch (CommonDesc->bDescriptorSubtype)
                    {
                        case USB_AUDIO_AC_HEADER:
                            return DisplayACHeader((PUSB_AUDIO_AC_INTERFACE_HEADER_DESCRIPTOR)CommonDesc);

                        case USB_AUDIO_AC_INPUT_TERMINAL:
                            return DisplayACInputTerminal((PUSB_AUDIO_INPUT_TERMINAL_DESCRIPTOR)CommonDesc);

                        case USB_AUDIO_AC_OUTPUT_TERMINAL:
                            return DisplayACOutputTerminal((PUSB_AUDIO_OUTPUT_TERMINAL_DESCRIPTOR)CommonDesc);
                            
                        case USB_AUDIO_AC_MIXER_UNIT:
                            return DisplayACMixerUnit((PUSB_AUDIO_MIXER_UNIT_DESCRIPTOR)CommonDesc);
                            
                        case USB_AUDIO_AC_SELECTOR_UNIT:
                            return DisplayACSelectorUnit((PUSB_AUDIO_SELECTOR_UNIT_DESCRIPTOR)CommonDesc);
                            
                        case USB_AUDIO_AC_FEATURE_UNIT:
                            return DisplayACFeatureUnit((PUSB_AUDIO_FEATURE_UNIT_DESCRIPTOR)CommonDesc);
                            
                        case USB_AUDIO_AC_PROCESSING_UNIT:
                            return DisplayACProcessingUnit((PUSB_AUDIO_PROCESSING_UNIT_DESCRIPTOR)CommonDesc);
                            
                        case USB_AUDIO_AC_EXTENSION_UNIT:
                            return DisplayACExtensionUnit((PUSB_AUDIO_EXTENSION_UNIT_DESCRIPTOR)CommonDesc);
                            
                        default:
                            break;
                    }
                    break;

                case USB_AUDIO_SUBCLASS_AUDIOSTREAMING:
                    switch (CommonDesc->bDescriptorSubtype)
                    {
                        case USB_AUDIO_AS_GENERAL:
                            return DisplayASGeneral((PUSB_AUDIO_GENERAL_DESCRIPTOR)CommonDesc);

                        case USB_AUDIO_AS_FORMAT_TYPE:
                            return DisplayASFormatType((PUSB_AUDIO_COMMON_FORMAT_DESCRIPTOR)CommonDesc);
                            break;

                        case USB_AUDIO_AS_FORMAT_SPECIFIC:
                            return DisplayASFormatSpecific(CommonDesc);

                        default:
                            break;
                    }
                    break;

                default:
                    break;
            }
            break;

        case USB_AUDIO_CS_ENDPOINT:
            return DisplayCSEndpoint((PUSB_AUDIO_ENDPOINT_DESCRIPTOR)CommonDesc);

        default:
            break;
    }

    return FALSE;
}


//*****************************************************************************
//
// DisplayACHeader()
//
//*****************************************************************************

BOOL
DisplayACHeader (
    PUSB_AUDIO_AC_INTERFACE_HEADER_DESCRIPTOR HeaderDesc
)
{
    UINT i;

    if (HeaderDesc->bLength < sizeof(USB_AUDIO_AC_INTERFACE_HEADER_DESCRIPTOR))
    {
        OOPS();
        return FALSE;
    }

    AppendTextBuffer("\r\nAudio Control Interface Header Descriptor:\r\n");

    AppendTextBuffer("bLength:              0x%02X\r\n",
                     HeaderDesc->bLength);

    AppendTextBuffer("bDescriptorType:      0x%02X\r\n",
                     HeaderDesc->bDescriptorType);

    AppendTextBuffer("bDescriptorSubtype:   0x%02X\r\n",
                     HeaderDesc->bDescriptorSubtype);

    AppendTextBuffer("bcdADC:             0x%04X\r\n",
                     HeaderDesc->bcdADC);

    AppendTextBuffer("wTotalLength:       0x%04X\r\n",
                     HeaderDesc->wTotalLength);

    AppendTextBuffer("bInCollection:        0x%02X\r\n",
                     HeaderDesc->bInCollection);

    for (i=0; i<HeaderDesc->bInCollection; i++)
    {
        AppendTextBuffer("baInterfaceNr[%d]:     0x%02X\r\n",
                         i+1,
                         HeaderDesc->baInterfaceNr[i]);
    }

    return TRUE;
}


//*****************************************************************************
//
// DisplayACInputTerminal()
//
//*****************************************************************************

BOOL
DisplayACInputTerminal (
    PUSB_AUDIO_INPUT_TERMINAL_DESCRIPTOR ITDesc
)
{
    PCHAR pStr;

    if (ITDesc->bLength != sizeof(USB_AUDIO_INPUT_TERMINAL_DESCRIPTOR))
    {
        OOPS();
        return FALSE;
    }

    AppendTextBuffer("\r\nAudio Control Input Terminal Descriptor:\r\n");

    AppendTextBuffer("bLength:              0x%02X\r\n",
                     ITDesc->bLength);

    AppendTextBuffer("bDescriptorType:      0x%02X\r\n",
                     ITDesc->bDescriptorType);

    AppendTextBuffer("bDescriptorSubtype:   0x%02X\r\n",
                     ITDesc->bDescriptorSubtype);

    AppendTextBuffer("bTerminalID:          0x%02X\r\n",
                     ITDesc->bTerminalID);

    AppendTextBuffer("wTerminalType:      0x%04X",
                     ITDesc->wTerminalType);

    pStr = TermTypeCodeToName(ITDesc->wTerminalType);

    if (pStr)
    {
        AppendTextBuffer(" (%s)\r\n",
                         pStr);
    }
    else
    {
        AppendTextBuffer("\r\n");
    }

    AppendTextBuffer("bAssocTerminal:       0x%02X\r\n",
                     ITDesc->bAssocTerminal);

    AppendTextBuffer("bNrChannels:          0x%02X\r\n",
                     ITDesc->bNrChannels);

    AppendTextBuffer("wChannelConfig:     0x%04X\r\n",
                     ITDesc->wChannelConfig);

    AppendTextBuffer("iChannelNames:        0x%02X\r\n",
                     ITDesc->iChannelNames);

    AppendTextBuffer("iTerminal:            0x%02X\r\n",
                     ITDesc->iTerminal);


    return TRUE;
}


//*****************************************************************************
//
// DisplayACOutputTerminal()
//
//*****************************************************************************

BOOL
DisplayACOutputTerminal (
    PUSB_AUDIO_OUTPUT_TERMINAL_DESCRIPTOR OTDesc
)
{
    PCHAR pStr;

    if (OTDesc->bLength != sizeof(USB_AUDIO_OUTPUT_TERMINAL_DESCRIPTOR))
    {
        OOPS();
        return FALSE;
    }

    AppendTextBuffer("\r\nAudio Control Output Terminal Descriptor:\r\n");

    AppendTextBuffer("bLength:              0x%02X\r\n",
                     OTDesc->bLength);

    AppendTextBuffer("bDescriptorType:      0x%02X\r\n",
                     OTDesc->bDescriptorType);

    AppendTextBuffer("bDescriptorSubtype:   0x%02X\r\n",
                     OTDesc->bDescriptorSubtype);

    AppendTextBuffer("bTerminalID:          0x%02X\r\n",
                     OTDesc->bTerminalID);

    AppendTextBuffer("wTerminalType:      0x%04X",
                     OTDesc->wTerminalType);

    pStr = TermTypeCodeToName(OTDesc->wTerminalType);

    if (pStr)
    {
        AppendTextBuffer(" (%s)\r\n",
                         pStr);
    }
    else
    {
        AppendTextBuffer("\r\n");
    }

    AppendTextBuffer("bAssocTerminal:       0x%02X\r\n",
                     OTDesc->bAssocTerminal);

    AppendTextBuffer("bSoruceID:            0x%02X\r\n",
                     OTDesc->bSoruceID);

    AppendTextBuffer("iTerminal:            0x%02X\r\n",
                     OTDesc->iTerminal);


    return TRUE;
}


//*****************************************************************************
//
// DisplayACMixerUnit()
//
//*****************************************************************************

BOOL
DisplayACMixerUnit (
    PUSB_AUDIO_MIXER_UNIT_DESCRIPTOR MixerDesc
)
{
    UCHAR  i;
    PUCHAR data;

    if (MixerDesc->bLength < 10)
    {
        OOPS();
        return FALSE;
    }

    AppendTextBuffer("\r\nAudio Control Mixer Unit Descriptor:\r\n");

    AppendTextBuffer("bLength:              0x%02X\r\n",
                     MixerDesc->bLength);

    AppendTextBuffer("bDescriptorType:      0x%02X\r\n",
                     MixerDesc->bDescriptorType);

    AppendTextBuffer("bDescriptorSubtype:   0x%02X\r\n",
                     MixerDesc->bDescriptorSubtype);

    AppendTextBuffer("bUnitID:              0x%02X\r\n",
                     MixerDesc->bUnitID);

    AppendTextBuffer("bNrInPins:            0x%02X\r\n",
                     MixerDesc->bNrInPins);

    for (i=0; i<MixerDesc->bNrInPins; i++)
    {
        AppendTextBuffer("baSourceID[%d]:        0x%02X\r\n",
                        i+1,
                        MixerDesc->baSourceID[i]);
    }

    data = &MixerDesc->baSourceID[MixerDesc->bNrInPins];

    AppendTextBuffer("bNrChannels:          0x%02X\r\n",
                     *data++);

    AppendTextBuffer("wChannelConfig:     0x%04X\r\n",
                     *((PUSHORT)data)++);

    AppendTextBuffer("iChannelNames:        0x%02X\r\n",
                     *data++);

    AppendTextBuffer("bmControls:\r\n");
                     
    i = MixerDesc->bLength - 10 - MixerDesc->bNrInPins;

    DisplayBytes(data, i);

    data += i;

    AppendTextBuffer("iMixer:               0x%02X\r\n",
                     *data);

    return TRUE;
}


//*****************************************************************************
//
// DisplayACSelectorUnit()
//
//*****************************************************************************

BOOL
DisplayACSelectorUnit (
    PUSB_AUDIO_SELECTOR_UNIT_DESCRIPTOR SelectorDesc
)
{
    UCHAR  i;
    PUCHAR data;

    if (SelectorDesc->bLength < 6)
    {
        OOPS();
        return FALSE;
    }

    AppendTextBuffer("\r\nAudio Control Selector Unit Descriptor:\r\n");

    AppendTextBuffer("bLength:              0x%02X\r\n",
                     SelectorDesc->bLength);

    AppendTextBuffer("bDescriptorType:      0x%02X\r\n",
                     SelectorDesc->bDescriptorType);

    AppendTextBuffer("bDescriptorSubtype:   0x%02X\r\n",
                     SelectorDesc->bDescriptorSubtype);

    AppendTextBuffer("bUnitID:              0x%02X\r\n",
                     SelectorDesc->bUnitID);

    AppendTextBuffer("bNrInPins:            0x%02X\r\n",
                     SelectorDesc->bNrInPins);

    for (i=0; i<SelectorDesc->bNrInPins; i++)
    {
        AppendTextBuffer("baSourceID[%d]:        0x%02X\r\n",
                        i+1,
                        SelectorDesc->baSourceID[i]);
    }

    data = &SelectorDesc->baSourceID[SelectorDesc->bNrInPins];

    AppendTextBuffer("iSelector:            0x%02X\r\n",
                     *data);

    return TRUE;
}


//*****************************************************************************
//
// DisplayACFeatureUnit()
//
//*****************************************************************************

BOOL
DisplayACFeatureUnit (
    PUSB_AUDIO_FEATURE_UNIT_DESCRIPTOR FeatureDesc
)
{
    UCHAR  i, n, ch;
    PUCHAR data;

    if (FeatureDesc->bLength < 7)
    {
        OOPS();
        return FALSE;
    }

    n = FeatureDesc->bControlSize;

    ch = ((FeatureDesc->bLength - 7) / n) - 1;

    if (FeatureDesc->bLength != (7 + (ch + 1) * n))
    {
        OOPS();
        return FALSE;
    }

    AppendTextBuffer("\r\nAudio Control Feature Unit Descriptor:\r\n");

    AppendTextBuffer("bLength:              0x%02X\r\n",
                     FeatureDesc->bLength);

    AppendTextBuffer("bDescriptorType:      0x%02X\r\n",
                     FeatureDesc->bDescriptorType);

    AppendTextBuffer("bDescriptorSubtype:   0x%02X\r\n",
                     FeatureDesc->bDescriptorSubtype);

    AppendTextBuffer("bUnitID:              0x%02X\r\n",
                     FeatureDesc->bUnitID);

    AppendTextBuffer("bSourceID:            0x%02X\r\n",
                     FeatureDesc->bSourceID);

    AppendTextBuffer("bControlSize:         0x%02X\r\n",
                     FeatureDesc->bControlSize);

    data = &FeatureDesc->bmaControls[0];

    for (i=0; i<=ch; i++)
    {
        AppendTextBuffer("bmaControls[%d]:\r\n",
                         i);

        DisplayBytes(data, n);

        data += n;
    }

    AppendTextBuffer("iFeature:             0x%02X\r\n",
                     *data);

    return TRUE;
}


//*****************************************************************************
//
// DisplayACProcessingUnit()
//
//*****************************************************************************

BOOL
DisplayACProcessingUnit (
    PUSB_AUDIO_PROCESSING_UNIT_DESCRIPTOR ProcessingDesc
)
{
    UCHAR  i;
    PUCHAR data;

    if (ProcessingDesc->bLength < sizeof(USB_AUDIO_PROCESSING_UNIT_DESCRIPTOR))
    {
        OOPS();
        return FALSE;
    }

    AppendTextBuffer("\r\nAudio Control Processing Unit Descriptor:\r\n");

    AppendTextBuffer("bLength:              0x%02X\r\n",
                     ProcessingDesc->bLength);

    AppendTextBuffer("bDescriptorType:      0x%02X\r\n",
                     ProcessingDesc->bDescriptorType);

    AppendTextBuffer("bDescriptorSubtype:   0x%02X\r\n",
                     ProcessingDesc->bDescriptorSubtype);

    AppendTextBuffer("bUnitID:              0x%02X\r\n",
                     ProcessingDesc->bUnitID);

    AppendTextBuffer("wProcessType:       0x%04X",
                     ProcessingDesc->wProcessType);

    switch (ProcessingDesc->wProcessType)
    {
        case USB_AUDIO_PROCESS_UNDEFINED:
            AppendTextBuffer("(Undefined Process)\r\n");
            break;

        case USB_AUDIO_PROCESS_UPDOWNMIX:
            AppendTextBuffer("(Up / Down Mix Process)\r\n");
            break;

        case USB_AUDIO_PROCESS_DOLBYPROLOGIC:
            AppendTextBuffer("(Dolby Prologic Process)\r\n");
            break;

        case USB_AUDIO_PROCESS_3DSTEREOEXTENDER:
            AppendTextBuffer("(3D-Stereo Extender Process)\r\n");
            break;

        case USB_AUDIO_PROCESS_REVERBERATION:
            AppendTextBuffer("(Reverberation Process)\r\n");
            break;

        case USB_AUDIO_PROCESS_CHORUS:
            AppendTextBuffer("(Chorus Process)\r\n");
            break;

        case USB_AUDIO_PROCESS_DYNRANGECOMP:
            AppendTextBuffer("(Dynamic Range Compressor Process)\r\n");
            break;

        default:
            AppendTextBuffer("\r\n");
            break;
    }

    AppendTextBuffer("bNrInPins:            0x%02X\r\n",
                     ProcessingDesc->bNrInPins);

    for (i=0; i<ProcessingDesc->bNrInPins; i++)
    {
        AppendTextBuffer("baSourceID[%d]:        0x%02X\r\n",
                        i+1,
                        ProcessingDesc->baSourceID[i]);
    }

    data = &ProcessingDesc->baSourceID[ProcessingDesc->bNrInPins];

    AppendTextBuffer("bNrChannels:          0x%02X\r\n",
                     *data++);

    AppendTextBuffer("wChannelConfig:     0x%04X\r\n",
                     *((PUSHORT)data)++);

    AppendTextBuffer("iChannelNames:        0x%02X\r\n",
                     *data++);

    i = *data++;

    AppendTextBuffer("bControlSize:         0x%02X\r\n",
                     i);

    AppendTextBuffer("bmControls:\r\n");
                     
    DisplayBytes(data, i);

    data += i;

    AppendTextBuffer("iProcessing:          0x%02X\r\n",
                     *data++);


    i = ProcessingDesc->bLength - 13 - ProcessingDesc->bNrInPins - i;

    if (i)
    {
        AppendTextBuffer("Process Specific:\r\n");

        DisplayBytes(data, i);
    }

    return TRUE;
}


//*****************************************************************************
//
// DisplayACExtensionUnit()
//
//*****************************************************************************

BOOL
DisplayACExtensionUnit (
    PUSB_AUDIO_EXTENSION_UNIT_DESCRIPTOR ExtensionDesc
)
{
    UCHAR  i;
    PUCHAR data;

    if (ExtensionDesc->bLength < 13)
    {
        OOPS();
        return FALSE;
    }

    AppendTextBuffer("\r\nAudio Control Extension Unit Descriptor:\r\n");

    AppendTextBuffer("bLength:              0x%02X\r\n",
                     ExtensionDesc->bLength);

    AppendTextBuffer("bDescriptorType:      0x%02X\r\n",
                     ExtensionDesc->bDescriptorType);

    AppendTextBuffer("bDescriptorSubtype:   0x%02X\r\n",
                     ExtensionDesc->bDescriptorSubtype);

    AppendTextBuffer("bUnitID:              0x%02X\r\n",
                     ExtensionDesc->bUnitID);

    AppendTextBuffer("wExtensionCode:     0x%04X\r\n",
                     ExtensionDesc->wExtensionCode);


    AppendTextBuffer("bNrInPins:            0x%02X\r\n",
                     ExtensionDesc->bNrInPins);

    for (i=0; i<ExtensionDesc->bNrInPins; i++)
    {
        AppendTextBuffer("baSourceID[%d]:        0x%02X\r\n",
                        i+1,
                        ExtensionDesc->baSourceID[i]);
    }

    data = &ExtensionDesc->baSourceID[ExtensionDesc->bNrInPins];

    AppendTextBuffer("bNrChannels:          0x%02X\r\n",
                     *data++);

    AppendTextBuffer("wChannelConfig:     0x%04X\r\n",
                     *((PUSHORT)data)++);

    AppendTextBuffer("iChannelNames:        0x%02X\r\n",
                     *data++);

    i = *data++;

    AppendTextBuffer("bControlSize:         0x%02X\r\n",
                     i);

    AppendTextBuffer("bmControls:\r\n");
                     
    DisplayBytes(data, i);

    data += i;

    AppendTextBuffer("iExtension:           0x%02X\r\n",
                     *data);
    return TRUE;
}


//*****************************************************************************
//
// DisplayASGeneral()
//
//*****************************************************************************

BOOL
DisplayASGeneral (
    PUSB_AUDIO_GENERAL_DESCRIPTOR GeneralDesc
)
{
    PCHAR pStr;

    if (GeneralDesc->bLength != sizeof(USB_AUDIO_GENERAL_DESCRIPTOR))
    {
        OOPS();
        return FALSE;
    }

    AppendTextBuffer("\r\nAudio Streaming Class Specific Interface Descriptor:\r\n");

    AppendTextBuffer("bLength:              0x%02X\r\n",
                     GeneralDesc->bLength);

    AppendTextBuffer("bDescriptorType:      0x%02X\r\n",
                     GeneralDesc->bDescriptorType);

    AppendTextBuffer("bDescriptorSubtype:   0x%02X\r\n",
                     GeneralDesc->bDescriptorSubtype);

    AppendTextBuffer("bTerminalLink:        0x%02X\r\n",
                     GeneralDesc->bTerminalLink);

    AppendTextBuffer("bDelay:               0x%02X\r\n",
                     GeneralDesc->bDelay);

    AppendTextBuffer("wFormatTag:         0x%04X",
                     GeneralDesc->wFormatTag);

    pStr = FormatTypeCodeToName(GeneralDesc->wFormatTag);

    if (pStr)
    {
        AppendTextBuffer(" (%s)\r\n",
                         pStr);
    }
    else
    {
        AppendTextBuffer("\r\n");
    }

    return TRUE;
}


//*****************************************************************************
//
// DisplayCSEndpoint()
//
//*****************************************************************************

BOOL
DisplayCSEndpoint (
    PUSB_AUDIO_ENDPOINT_DESCRIPTOR EndpointDesc
)
{
    if (EndpointDesc->bLength != sizeof(USB_AUDIO_ENDPOINT_DESCRIPTOR))
    {
        OOPS();
        return FALSE;
    }

    AppendTextBuffer("\r\nAudio Streaming Class Specific Audio Data Endpoint Descriptor:\r\n");

    AppendTextBuffer("bLength:              0x%02X\r\n",
                     EndpointDesc->bLength);

    AppendTextBuffer("bDescriptorType:      0x%02X\r\n",
                     EndpointDesc->bDescriptorType);

    AppendTextBuffer("bDescriptorSubtype:   0x%02X\r\n",
                     EndpointDesc->bDescriptorSubtype);

    AppendTextBuffer("bmAttributes:         0x%02X\r\n",
                     EndpointDesc->bmAttributes);

    AppendTextBuffer("bLockDelayUnits:      0x%02X\r\n",
                     EndpointDesc->bLockDelayUnits);

    AppendTextBuffer("wLockDelay:         0x%04X\r\n",
                     EndpointDesc->wLockDelay);

    return TRUE;
}


//*****************************************************************************
//
// DisplayASFormatType()
//
//*****************************************************************************

BOOL
DisplayASFormatType (
    PUSB_AUDIO_COMMON_FORMAT_DESCRIPTOR FormatDesc
)
{
    UCHAR  i, n;
    ULONG  freq;
    PUCHAR data;

    if (FormatDesc->bLength < sizeof(USB_AUDIO_COMMON_FORMAT_DESCRIPTOR))
    {
        OOPS();
        return FALSE;
    }

    AppendTextBuffer("\r\nAudio Streaming Format Type Descriptor:\r\n");

    AppendTextBuffer("bLength:              0x%02X\r\n",
                     FormatDesc->bLength);

    AppendTextBuffer("bDescriptorType:      0x%02X\r\n",
                     FormatDesc->bDescriptorType);

    AppendTextBuffer("bDescriptorSubtype:   0x%02X\r\n",
                     FormatDesc->bDescriptorSubtype);

    AppendTextBuffer("bFormatType:          0x%02X\r\n",
                     FormatDesc->bFormatType);


    if (FormatDesc->bFormatType == 0x01 ||
        FormatDesc->bFormatType == 0x03)
    {
        PUSB_AUDIO_TYPE_I_OR_III_FORMAT_DESCRIPTOR FormatI_IIIDesc;

        FormatI_IIIDesc = (PUSB_AUDIO_TYPE_I_OR_III_FORMAT_DESCRIPTOR)FormatDesc;

        AppendTextBuffer("bNrChannels:          0x%02X\r\n",
                         FormatI_IIIDesc->bNrChannels);

        AppendTextBuffer("bSubframeSize:        0x%02X\r\n",
                         FormatI_IIIDesc->bSubframeSize);

        AppendTextBuffer("bBitResolution:       0x%02X\r\n",
                         FormatI_IIIDesc->bBitResolution);

        AppendTextBuffer("bSamFreqType:         0x%02X\r\n",
                         FormatI_IIIDesc->bSamFreqType);

        data = (PUCHAR)(FormatI_IIIDesc + 1);

        n = FormatI_IIIDesc->bSamFreqType;

    }
    else if (FormatDesc->bFormatType == 0x02)
    {
        PUSB_AUDIO_TYPE_II_FORMAT_DESCRIPTOR FormatIIDesc;

        FormatIIDesc = (PUSB_AUDIO_TYPE_II_FORMAT_DESCRIPTOR)FormatDesc;

        AppendTextBuffer("wMaxBitRate:        0x%04X\r\n",
                         FormatIIDesc->wMaxBitRate);

        AppendTextBuffer("wSamplesPerFrame:   0x%04X\r\n",
                         FormatIIDesc->wSamplesPerFrame);

        AppendTextBuffer("bSamFreqType:         0x%02X\r\n",
                         FormatIIDesc->bSamFreqType);

        data = (PUCHAR)(FormatIIDesc + 1);

        n = FormatIIDesc->bSamFreqType;

    }
    else
    {
        data == NULL;
    }

    if (data != NULL)
    {
        if (n == 0)
        {
            freq = (data[0]) + (data[1] << 8) + (data[2] << 16);
            data += 3;

            AppendTextBuffer("tLowerSamFreq:    0x%06X (%d Hz)\r\n",
                             freq,
                             freq);

            freq = (data[0]) + (data[1] << 8) + (data[2] << 16);
            data += 3;

            AppendTextBuffer("tUpperSamFreq:    0x%06X (%d Hz)\r\n",
                             freq,
                             freq);
        }
        else
        {
            for (i=0; i<n; i++)
            {
                freq = (data[0]) + (data[1] << 8) + (data[2] << 16);
                data += 3;

                AppendTextBuffer("tSamFreq[%d]:      0x%06X (%d Hz)\r\n",
                                 i+1,
                                 freq,
                                 freq);
            }
        }
    }

    return TRUE;
}


//*****************************************************************************
//
// DisplayASFormatSpecific()
//
//*****************************************************************************

BOOL
DisplayASFormatSpecific (
    PUSB_AUDIO_COMMON_DESCRIPTOR CommonDesc
)
{
    AppendTextBuffer("\r\nAudio Streaming Format Specific Descriptor:\r\n");

    AppendTextBuffer("bLength:              0x%02X\r\n",
                     CommonDesc->bLength);

    AppendTextBuffer("bDescriptorType:      0x%02X\r\n",
                     CommonDesc->bDescriptorType);

    AppendTextBuffer("bDescriptorSubtype:   0x%02X\r\n",
                     CommonDesc->bDescriptorSubtype);

    DisplayBytes((PUCHAR)(CommonDesc + 1),
                 CommonDesc->bLength);

    return TRUE;
}

//*****************************************************************************
//
// DisplayBytes()
//
//*****************************************************************************

VOID
DisplayBytes (
    PUCHAR Data,
    USHORT Len
)
{
    USHORT i;

    for (i = 0; i < Len; i++)
    {
        AppendTextBuffer("%02X ",
                         Data[i]);

        if (i % 16 == 15)
        {
            AppendTextBuffer("\r\n");
        }
    }

    if (i % 16 != 0)
    {
        AppendTextBuffer("\r\n");
    }
}


//*****************************************************************************
//
// TermTypeCodeToName()
//
//*****************************************************************************

PCHAR
TermTypeCodeToName (
    USHORT TermTypeCode
)
{
    PTERMTYPE termType;

    for (termType=TermTypes; termType->TermTypeName; termType++)
    {
        if (termType->TermTypeCode == TermTypeCode)
        {
            break;
        }
    }

    return termType->TermTypeName;
}


//*****************************************************************************
//
// FormatTypeCodeToName()
//
//*****************************************************************************

PCHAR
FormatTypeCodeToName (
    USHORT FormatTypeCode
)
{
    PFORMATTYPE formatType;

    for (formatType=FormatTypes; formatType->FormatTypeName; formatType++)
    {
        if (formatType->FormatTypeCode == FormatTypeCode)
        {
            break;
        }
    }

    return formatType->FormatTypeName;
}
