#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include "usb.h"
#include "USBAudio1.h"
#include "USBAudio2.h"
#include "USBVideo1.h"
#include "HID.h"
#include <stdbool.h>

//#define TEST

#ifdef TEST
#define dprintf_here() fprintf(stderr,"%s (%d)\n",__func__,__LINE__)

#else
#define dprintf_here()
#endif

#define pf(...) fprintf(stderr,__VA_ARGS__)

#define pline  fprintf(stderr,"%*s----+----+---------------------------+----------+------------+\n",off,"+")
#define ptitle(name,o)  int off=o;    int num=0;pf("%*s"#name"\n",off,"");\
                pline;fprintf(stderr,"%*sOff :Sz  :Name                       :Value hex :Value dec   :\n",off,":");pline
#define pformat "%*s %2d : %2d : %-25s : %8x : %10d : "        
#define pfnn(v) do { fprintf(stderr,pformat,off,":",num,sizeof(d->##v),#v,d->##v,d->##v); num+=sizeof(d->##v); } while(0)
#define pfnamenn(name,val,size)  do { fprintf(stderr,pformat,off,":",num,size,name,val,val); num+=size; } while(0)
#define pfnamen(name,val,size) pfnamenn(name,val,size);pf("\n")
#define pfn(v) pfnn(v);pf("\n")
#define pfs(v) pfnn(v);printString(device,d->##v)

#define pfa(v) fprintf(stderr,"%-25s : %8x : %10d :\n",#v,p->##v,p->##v)
#define pf1(n,v) fprintf(stderr,"%-25s : %8x : %10d :\n",#n,v,v)

#define   LEAF_OFFSET    9
#define listArgs(list) (list), (sizeof(list)/sizeof((list)[0]))

static const char* getListValue(int item, const char* list[], int numitems)
{
    if (list == 0 || item >= numitems) return "";
    return list[item];
}

const char* classList[] =
{
    "",
    "Audio",
    "Communications and CDC Control",
    "HID",
    "",
    "Physical",
    "Image",
    "Printer",
    "Mass Storage",
    "Hub",
    "CDC Data",
    "Smart Card",
    "",
    "Content Security",
    "Video",
    "Personal Heathcare",
    "Audio/Video Devices"
};

static const char* getClass(int c)
{
    switch (c)
    {
        case USB_DIAGNOSTIC_DEVICE_CLASS:      return "Diagnostic Device";
        case USB_WIRELESS_CONTROLLER_CLASS:    return "Wireless Controller";
        case USB_MISCELLANEOUS_CLASS:          return "Miscellaneous";
        case USB_APPLICATION_SPECIFIC_CLASS:   return "Application Specific";
        case USB_VENDOR_SPECIFIC_CLASS:        return "Vendor Specific";
    }
    return getListValue(c,listArgs(classList));
}

static const char* getSubClass(int c, int s)
{
    switch (c)
    {
        case USB_AUDIO_CLASS:
                switch (s)
                {
                    case USB_AUDIO_CONTROL_SUBCLASS: return "Control";
                    case USB_AUDIO_STREAMING_SUBCLASS: return "Streaming";
                }
                break;
        case USB_HID_CLASS:
                switch (s)
                {
                    case USB_HID_BOOT_SUBCLASS: return "Boot interface";
                }
    }
    return "";
}

static const char* getProtocol(int c, int s, int p)
{
    switch (c)
    {
        case USB_HID_CLASS:
                switch (p)
                {
                    case USB_HID_KEYBOARD_PROTOCOL: return "Keyboard";
                    case USB_HID_MOUSE_PROTOCOL: return "Mouse";
                }
    }
    return "";
}

static void printStringList(USBDevice* device, int first, int count)
{
    if (first == 0 || count <= 0)
    {
        pf("''");
        return;
    }
    
    for (int i = 0; i < count; i++)
    {
        if (i != 0) pf(" ");
        USB_StringDescriptor *str=USB_makeStringDescriptor(device, i + first);
        pf("'");
        if (str)
        {
            for (int len=0;len < ((str->bLength-2)/2);len+=1)
            {
                if (isprint(str->str[len])) pf("%c",str->str[len]);
            }
        }
        pf("'");
        free((void*)str);
    }
}

static void printString(USBDevice* device, int i)
{
    printStringList(device,i,1);
    pf("\n");
}

static void deviceDescriptor(USBDevice* device,const USB_DeviceDescriptor* d)
{
    ptitle(Standard Device Descriptor,1);
    pfn(bLength);
    pfn(bDescriptorType);
    pfn(bcdUSB);
    pfnn(bDeviceClass);pf("%s\n",getClass(d->bDeviceClass));
    pfnn(bDeviceSubClass);
            pf("%s\n",getSubClass(d->bDeviceClass,d->bDeviceSubClass));
    pfnn(bDeviceProtocol);
            pf("%s\n",getProtocol(d->bDeviceClass,d->bDeviceSubClass,d->bDeviceProtocol));
    pfn(bMaxPacketSize);
    pfn(idVendor);
    pfn(idProduct);
    pfn(bcdDevice);
    pfs(iManufacturer);
    pfs(iProduct);
    pfs(iSerialNumber);
    pfn(bNumConfigurations);
    pline;
    pf("\n");
}

static void configurationDescriptor(USBDevice* device,const USB_ConfigurationDescriptor* d)
{
    ptitle(Standard Configuration Descriptor,1);
    pfn(bLength);
    pfn(bDescriptorType);
    pfn(wTotalLength);
    pfn(bNumInterfaces);
    pfn(bConfigurationValue);
    pfs(iConfiguration);
    pfnn(bmAttributes);
    if (d->bmAttributes & (1<<7)) pf("(bit7) USB 1.0 bus powered ");
    pf("(bit6) %s,",(d->bmAttributes & (1<<6))?"Self powered":"Bus powered");
    pf(" (bit5) %s",(d->bmAttributes & (1<<5))?"Remote wakeup":"No remote wakeup");
    pf("\n");
    pfnn(bMaxPower);
    pf("%dmA\n",d->bMaxPower*2);
    pline;
    pf("\n");
}

static void interfaceDescriptor(USBDevice* device,const USB_InterfaceDescriptor* d)
{
    ptitle(Standard Interface Descriptor,5);
    pfn(bLength);
    pfn(bDescriptorType);
    pfn(bInterfaceNumber);
    pfn(bAlternateSetting);
    pfn(bNumEndpoints);
    pfnn(bInterfaceClass);pf("%s\n",getClass(d->bInterfaceClass));
    pfnn(bInterfaceSubClass);
            pf("%s\n",getSubClass(d->bInterfaceClass,d->bInterfaceSubClass));
    pfnn(bInterfaceProtocol);
            pf("%s\n",getProtocol(d->bInterfaceClass,d->bInterfaceSubClass,d->bInterfaceProtocol));
    pfs(iInterface);
    pline;
    pf("\n");
}

static void endpointDescriptor(int csClass, const USB_EndpointDescriptor* des)
{
    const USB_EndpointDescriptor* d = des; // d used by pf
    ptitle(Standard Endpoint Descriptor,LEAF_OFFSET);
    pfn(bLength);
    pfn(bDescriptorType);
    pfnn(bEndpointAddress);
    pf("Endpoint %d - ",d->bEndpointAddress & 0x1f);
    if (d->bEndpointAddress & 0x80) pf("IN\n"); else pf("OUT\n");
    pfnn(bmAttributes);
    switch (d->bmAttributes & 3)
    {
       case 0: pf("Control");break;
       case 1: pf("Isochronous");
               switch ((d->bmAttributes>>2) & 3)
               {
                  case 1: pf(", Asynchronous");break;
                  case 2: pf(", Adaptive");break;
                  case 3: pf(", Synchronous");break;
               }

               switch ((d->bmAttributes>>4) & 3)
               {
                  case 0: pf(", Data Endpoint ");break;
                  case 1: pf(", Feedback Endpoint ");break;
                  case 2: pf(", Implicit Feedback Endpoint ");break;
               }
               break;
       case 2: pf("Bulk");break;
       case 3: pf("Interrupt");break;
    }


    pf("\n");
    pfnn(wMaxPacketSize); pf("%d x %d byte max packets\n",((d->wMaxPacketSize >> 11) + 1),(d->wMaxPacketSize & 0x7ff));
    pfn(bInterval);
    
    switch (csClass & 0xFFFF00)
    {
        case USB_AUDIO_CS_STREAMING:
        case USB_AUDIO_CS_CONTROL:
            if ((csClass & 0xFF) == 0)
            {
                const USBAudio_ST_EndpointDescriptor* d = (USBAudio_ST_EndpointDescriptor*)des;
                pfn(bRefresh);
                pfn(bSynchAddress);
            }
            break;
    }

    pline;
    pf("\n");
}

static void interfaceAssociationDescriptor(USBDevice* device,const USB_InterfaceAssociationDescriptor* d)
{
    ptitle(Standard Interface Association Descriptor,0);
    pfn(bLength);
    pfn(bDescriptorType);
    pfn(bFirstInterface);
    pfn(bInterfaceCount);
    pfnn(bFunctionClass); ;pf("%s\n",getClass(d->bFunctionClass));
    pfn(bFunctionSubClass);
    pfn(bFunctionProtocol);
    pfs(iFunction);
    pline;
    pf("\n");
}

static void stringDescriptor(const USB_StringDescriptor* d)
{
    pf("*** String Descriptor ***\n");
    pf("bLength:                 %4x\n",d->bLength);
    pf("bDescriptorType:         %4x\n",d->bDescriptorType);
    for (int i=0;i<d->bLength-2;i++)
    {
        pf("Byte %3d:  0x%02x (%3d)",i,d->str[i],d->str[i]);
        if (isprint(d->str[i])) pf(" %c",d->str[i]);
        printf("\n");
    }
    printf("\n");
}

#define pfhid(s)  fprintf(stderr,"%*s%-45s",hidoff," ",s)

#define pfhiduv(s)  do {                                                \
  char str[64];                                                         \
  snprintf(str,sizeof(str),"%s (%d)", s, getHIDuValue(buf + i - 1));    \
  pfhid(str);                                                           \
} while (0)

static int getHIDsValue(uint8_t* buf)
{
    uint8_t size = *buf & 3;
    buf++;
    switch (size)
    {
        case 1: return (*buf << 24) >> 24;
        case 2: return ((buf[0] + (buf[1] << 8)) << 16) >> 16;
        case 3: return buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24);
    }
    return 0;  
}

static unsigned int getHIDuValue(uint8_t* buf)
{
    uint8_t size = *buf & 3;
    buf++;
    switch (size)
    {
        case 1: return *buf;
        case 2: return buf[0] + (buf[1] << 8);
        case 3: return buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24);
    }
    return 0;  
}

static void hidDeviceDescriptor(USBDevice* device, const USB_HIDDeviceDescriptor* d)
{
    ptitle(HID Device Descriptor,LEAF_OFFSET);
    pfn(bLength);
    pfn(bDescriptorType);
    pfn(bcdHID);
    pfn(bCountryCode);
    pfn(bNumDescriptors);
    pfn(bReportDescType);
    pfn(wReportDescLength);
    pline;
    pf("\n");
    
    int hidoff = off;
    
    if (d->bReportDescType != 0x22) return;
    
    uint8_t* buf = calloc(1,d->wReportDescLength);
    if (buf == NULL) return;
    
    _kernel_oserror* e = USB_control(device, 0x81, 6, (d->bReportDescType << 8), 0, d->wReportDescLength, buf);
    if (e != NULL)
    {
        free(buf);
        pf("%s\n",e->errmess);
        return;
    }
    
    unsigned int n;
    
    for (int i = 0; i <  d->wReportDescLength ; )
    {
        int temp = i;
        switch ((buf[i] & 0xc) >> 2)
        {
            case 0: /* main items */
                switch (buf[i++] >> 4)
                {
                    case 0x8: pfhid("...Input");
                        break;
                    case 0x9: pfhid("...Output");
                        break;
                    case 0xa: 
                        n = getHIDuValue(buf + i - 1);
                        switch (n)
                        {
                            case 0:pfhid("Collection (Physical)"); break;
                            case 1:pfhid("Collection (Application)"); break;
                            case 2:pfhid("Collection (Logical)"); break;
                            case 3:pfhid("Collection (Report)"); break;
                            case 4:pfhid("Collection (Named Array)"); break;
                            case 5:pfhid("Collection (Usage Switch)"); break;
                            case 6:pfhid("Collection (Usage Modifier)"); break;
                            default:
                                if (n < 0x80)
                                    pfhid("Collection (Reserved)");
                                else
                                    pfhid("Collection (Vendor defined)");
                                break;
                        }
                        hidoff += 2;
                        if (hidoff < 0) hidoff = 0;
                        break;
                    case 0xb: pfhid("...Feature");
                        break;
                    case 0xc: hidoff -= 2;
                              if (hidoff < 0) hidoff = 0;
                              pfhid("End Collection");
                        break;
                    default: pfhid("Reserved");
                        break;
                }
                break;
            case 1: /* Global type */
                switch (buf[i++] >> 4)
                {
                    case 0x0: 
                        n = getHIDuValue(buf + i - 1);
                        switch (n)
                        {
                            case 0: pfhid("Usage Page (Undefined)"); break;
                            case 1: pfhid("Usage Page (Generic Desktop Controls)"); break;
                            case 2: pfhid("Usage Page (Simulation Controls)"); break;
                            case 3: pfhid("Usage Page (VR Controls)"); break;
                            case 4: pfhid("Usage Page (Sport Controls)"); break;
                            case 5: pfhid("Usage Page (Game Controls)"); break;
                            case 6: pfhid("Usage Page (Generic Device Controls)"); break;
                            case 7: pfhid("Usage Page (Keyboard/Keypad)"); break;
                            case 8: pfhid("Usage Page (LEDs)"); break;
                            case 9: pfhid("Usage Page (Button)"); break;
                            case 0xa: pfhid("Usage Page (Ordinal)"); break;
                            case 0xb: pfhid("Usage Page (Telephony)"); break;
                            case 0xc: pfhid("Usage Page (Consumer)"); break;
                            case 0xd: pfhid("Usage Page (Digitiser)"); break;
                            case 0xf: pfhid("Usage Page (PID page)"); break;
                            case 0x10: pfhid("Usage Page (Unicode)"); break;
                            case 0x14: pfhid("Usage Page (Alphanumeric Display)"); break;
                            case 0x40: pfhid("Usage Page (Medical Instruments)"); break;
                            case 0x80:
                            case 0x81:                       
                            case 0x82:
                            case 0x83: pfhid("Usage Page (Monitor Page)"); break;
                            case 0x84:
                            case 0x85:
                            case 0x86:
                            case 0x87: pfhid("Usage Page (Power Page)"); break;
                            case 0x8c: pfhid("Usage Page (Bar Code Scanner)"); break;
                            case 0x8d: pfhid("Usage Page (Scale Page)"); break;
                            case 0x8e: pfhid("Usage Page (Magnetic Stripe Reading Devices)"); break;
                            case 0x8f: pfhid("Usage Page (Reserved Point OF Sale Pages)"); break;
                            case 0x90: pfhid("Usage Page (Camera Control)"); break;
                            case 0x91: pfhid("Usage Page (Arcade)"); break;
                            default: 
                                 if (n >= 0xff00)
                                     pfhid("Usage Page (Vendor Defined)");
                                 else
                                     pfhid("Usage Page (Reserved)");;
                        }
                        
                   
                        break;
                    case 0x1: pfhid("Logical Minimum"); break;
                    case 0x2: pfhid("Logical Maximum"); break;
                    case 0x3: pfhid("Physical Minimum"); break;
                    case 0x4: pfhid("Physical Maximum"); break;
                    case 0x5: pfhid("Unit Exponent"); break;
                    case 0x6: pfhid("Unit"); break;
                    case 0x7: pfhiduv("Report Size"); break;
                    case 0x8: pfhiduv("Report ID"); break;
                    case 0x9: pfhiduv("Report Count"); break;
                    case 0xa: pfhid("Push"); break;
                    case 0xb: pfhid("Pop"); break;
                    default: pfhid("Reserved"); break;
                }
                break;
            case 2: /* local type */
                switch (buf[i++] >> 4)
                {
                    case 0x0: pfhid("Usage"); break;
                    case 0x1: pfhid("Usage Minimum"); break;
                    case 0x2: pfhid("Usage Maximum"); break;
                    case 0x3: pfhid("Designator Index"); break;
                    case 0x4: pfhid("Designator Minimum"); break;
                    case 0x5: pfhid("Designator Maximum"); break;
                    case 0x7: pfhiduv("String Index"); break;
                    case 0x8: pfhid("String Minimum"); break;
                    case 0x9: pfhid("String Maximum"); break;
                    case 0xa: pfhid("Delimiter"); break;
                    default: pfhid("Reserved"); break;
                }
                break;
        };
        i = temp;
        uint8_t size = buf[i++];
        pf(" :%02x ", size);
        size &= 3;
        if (size == 3) size = 4;
        for (; size; size--)
        {
            pf("%02x ", buf[i++]) ;
        }
        
        pf("\n");
    }
    pf ("\n");
    
    free(buf);
}

static bool audioStreamEndpoint(uint8_t protocol, const USB_Descriptor* des)
{
    switch (des->bDescriptorSubType)
    {
        case USB_AUDIO_SE_GENERAL:
            {
                USBAudio_SE_General* d = (USBAudio_SE_General*) des;
                ptitle(Audio Streaming Endpoint Descriptor,LEAF_OFFSET);
                pfn(bLength);
                pfn(bDescriptorType);
                pfn(bDescriptorSubType);
                pfnn(bmAttributes);
                
                int comma = 0;
                if (d->bmAttributes & USB_AUDIO_SE_CTRL_SAMP_FREQ)
                {
                        comma = 1;
                        pf("Samp freq ctrl");
                }
                        
                if (d->bmAttributes & USB_AUDIO_SE_CTRL_PITCH)
                {
                        if (comma) pf(", ");
                        comma = 1;
                        pf("Pitch ctrl");
                }
                
                if (d->bmAttributes & USB_AUDIO_SE_MAXPACKETS_ONLY)
                {
                        if (comma) pf(", ");
                        comma = 1;
                        pf("MaxPackets only");
                }
                
                pf("\n");

                if (protocol == 0)
                {
                    pfn(bLockDelayUnits);
                    pfn(wLockDelay);
                }
                else
                {
                    USBAudio2_SE_General* d = (USBAudio2_SE_General*) des;
                    pfn(bmControls);
                    pfn(bLockDelayUnits);
                    pfn(wLockDelay);
                }
                pline;
                pf("\n");
            }
            return false;
    }
    return true; //unknown 
}


static const char* audioTerminalType(int n)
{
    switch (n & ~0xFF)
    {
        case 0x100: switch (n & 0xFF)
                    {
                        case 0x00: return "USB undefined";
                        case 0x01: return "USB streaming";
                        case 0xFF: return "USB vendor Specific";
                    }
                    break;
        case 0x200: switch (n & 0xFF)
                    {
                        case 0x00: return "Input undefined";
                        case 0x01: return "Microphone";
                        case 0x02: return "Desktop microphone";
                        case 0x03: return "Personal microphone";
                        case 0x04: return "Omni directional microphone";
                        case 0x05: return "Microphone array";
                        case 0x06: return "Processing microphone array";
                    }
                    break;
        case 0x300: switch(n & 0xFF)
                    {
                        case 0x00: return "Output Undefined";
                        case 0x01: return "Speaker";
                        case 0x02: return "Headphones";
                        case 0x03: return "Head mounted display audio";
                        case 0x04: return "Desktop speaker";
                        case 0x05: return "Room Speaker";
                        case 0x06: return "Communication speaker";
                        case 0x07: return "Low frequency effects speaker";
                    }
                    break;
        case 0x400: switch(n & 0xFF)
                    {
                        case 0x00: return "Bi -directional undefined";
                        case 0x01: return "Handset";
                        case 0x02: return "Headset";
                        case 0x03: return "Speakerphone, no echo reduction";
                        case 0x04: return "Echo-suppressing speakerphone";
                        case 0x05: return "Echo-cancelling speakerphone";
                    }
                    break;
        case 0x500: switch(n & 0xFF)
                    {
                        case 0x00: return "Telephony terminal, undefined";
                        case 0x01: return "Phone line";
                        case 0x02: return "Telephone";
                        case 0x03: return "Down line phone";
                    }
                    break;
        case 0x600: switch(n & 0xFF)
                    {
                        case 0x00: return "External undefined";
                        case 0x01: return "Analogue connector";
                        case 0x02: return "Digital audio interface";
                        case 0x03: return "Line connector";
                        case 0x04: return "Legacy audio connector";
                        case 0x05: return "S/PDIF interface";
                        case 0x06: return "1394 DA stream";
                        case 0x07: return "1394 DA stream soundtrack";
                    }
                    break;
        case 0x700: switch(n & 0xFF)
                    {
                        case 0x00: return "Embedded Undefined";
                        case 0x01: return "Level calibration noise source";
                        case 0x02: return "Equalization noise";
                        case 0x03: return "CD player";
                        case 0x04: return "Digital Audio Tape";
                        case 0x05: return "Digital Compact Cassette";
                        case 0x06: return "MiniDisk";
                        case 0x07: return "Analogue Tape";
                        case 0x08: return "Phonograph";
                        case 0x09: return "VCR audio";
                        case 0x0a: return "Video Disk Audio";
                        case 0x0b: return "DVD Audio";
                        case 0x0c: return "TV Tuner Audio";
                        case 0x0d: return "Satellite Receiver Audio";
                        case 0x0e: return "Cable Tuner Audio";
                        case 0x0f: return "DSS Audio";
                        case 0x10: return "Radio Receiver";
                        case 0x11: return "Radio Transmitter";
                        case 0x12: return "Multi-track recorder";
                        case 0x13: return "Synthesizer";
                    }
                    break;
    }
    return "";
}

static const char* featureList[] =
{
    "Mute",
    "Volume",
    "Bass",
    "Mid",
    "Treble",
    "Graphic Equaliser",
    "Automatic Gain",
    "Delay",
    "Base Boost",
    "Loudness"
};

static const char* formatIList[] =
{
    "TYPE_I_UNDEFINED",
    "PCM",
    "PCM8",
    "IEEE_FLOAT",
    "ALAW",
    "MULAW",
};

static const char* formatIIList[] =
{
    "TYPE_II_UNDEFINED",
    "MPEG",
    "AC3",
};

static const char* formatIIIList[] =
{
    "TYPE_III_UNDEFINED",
    "IEC1937_AC3",
    "IEC1937_MPEG-1_Layer1",
    "IEC1937_MPEG-1_Layer2/3 or IEC1937_MPEG-2_NOEXT",
    "IEC1937_MPEG-2_EXT",
    "IEC1937_MPEG-2_Layer1_LS",
    "IEC1937_MPEG-2_Layer2/3_LS"
};

static const char* getAudioType(int n)
{
    switch (n & 0xf000)
    {
        case 0:         return getListValue((n & 0xfff),listArgs(formatIList));
        case 0x1000:    return getListValue((n & 0xfff),listArgs(formatIIList));
        case 0x2000:    return getListValue((n & 0xfff),listArgs(formatIIIList));
    }
    return "";
}

void printChannelConfig(uint32_t n)
{
    char* comma = "";
    for (int i = 0; i <12; i++)
    {
        const char* s = "";
        switch(n & (1<<i))
        {
            case 0x01: s = "Left Front";break;
            case 0x02: s = "Right Front";break;
            case 0x04: s = "Centre Front";break;
            case 0x08: s = "Low Freq Enhance";break;
            case 0x10: s = "Left Surround";break;
            case 0x20: s = "Right Surround";break;
            case 0x30: s = "Left of Centre";break;
            case 0x40: s = "Right of Centre";break;
            case 0x80: s = "Surround";break;
            case 0x100: s = "Side Left";break;
            case 0x200: s = "Side Right";break;
            case 0x400: s = "Top";break;
        }
        if (*s != 0) {pf("%s%s",comma,s);comma = ", ";}
    }
    pf("\n");
}



static bool audioControlInterface(USBDevice* device,uint32_t protocol,const USB_Descriptor* des)
{
    switch (des->bDescriptorSubType)
    {
        case USB_AUDIO_CI_HEADER:
            {
                USBAudio_CI_Header* d = (USBAudio_CI_Header*) des;
                ptitle(Audio Control Interface Header Descriptor,LEAF_OFFSET);
                pfn(bLength);
                pfn(bDescriptorType);
                pfn(bDescriptorSubType);
                pfn(bcdADC);
                if (protocol == 0)
                {
                    pfn(wTotalLength);
                    pfn(bInCollection);
                    char buf[32];
                    for (int i = 0; i < d->bInCollection; i++)
                    {
                        sprintf(buf,"baInterfaceNr[%d]",i);
                        pfnamen(buf,d->baInterfaceNr[i],sizeof(d->baInterfaceNr[i]));
                    }
                }
                else
                {
                    USBAudio2_CI_Header* d = (USBAudio2_CI_Header*) des;
                    pfn(bCategory);
                    pfn(wTotalLength);
                    pfn(bmControls);
                }
                pline;
                pf("\n");
            }
            break;
        case USB_AUDIO_CI_INPUT_TERMINAL:
            {
                USBAudio_CI_InputTerminal* d = (USBAudio_CI_InputTerminal*) des;
                ptitle(Audio Control Interface Input Terminal Descriptor,LEAF_OFFSET);
                pfn(bLength);
                pfn(bDescriptorType);
                pfn(bDescriptorSubType);
                pfn(bTerminalID);
                pfnn(wTerminalType); pf("%s\n",audioTerminalType(d->wTerminalType));
                pfn(bAssocTerminal);
                
                if (protocol == 0)
                {
                    pfn(bNrChannels);
                    pfnn(wChannelConfig); printChannelConfig(d->wChannelConfig);
                    pfs(iChannelNames);
                    pfs(iTerminal);
                }
                else
                {
                    USBAudio2_CI_InputTerminal* d =(USBAudio2_CI_InputTerminal*)des;
                    pfn(bCSourceID);
                    pfn(bNrChannels);
                    pfnn(bmChannelConfig); printChannelConfig(d->bmChannelConfig);
                    pfnn(iChannelNames); 
                        printStringList(device,d->iChannelNames, d->bNrChannels); 
                        pf("\n");
                    pfn(bmControls);
                    pfs(iTerminal);
                }
                pline;
                pf("\n");
            }
            break;
        case USB_AUDIO_CI_OUTPUT_TERMINAL:
            {
                USBAudio_CI_OutputTerminal* d = (USBAudio_CI_OutputTerminal*) des;
                ptitle(Audio Control Interface Output Terminal Descriptor,LEAF_OFFSET);
                pfn(bLength);
                pfn(bDescriptorType);
                pfn(bDescriptorSubType);
                pfn(bTerminalID);
                pfnn(wTerminalType); pf("%s\n",audioTerminalType(d->wTerminalType));
                pfn(bAssocTerminal);
                pfn(bSourceID);
                if (protocol == 0)
                {
                    pfs(iTerminal);
                }
                else
                {
                    USBAudio2_CI_OutputTerminal* d = (USBAudio2_CI_OutputTerminal*) des;
                    pfn(bCSourceID);
                    pfn(bmControls);
                    pfs(iTerminal);
                }
                pline;
                pf("\n");
           }
           break;
        case USB_AUDIO_CI_MIXER_UNIT:
            {
                USBAudio_CI_MixerUnit* d = ( USBAudio_CI_MixerUnit*) des;
                ptitle(Audio Control Interface Mixer Unit Descriptor,LEAF_OFFSET);
                pfn(bLength);
                pfn(bDescriptorType);
                pfn(bDescriptorSubType);
                pfn(bUnitID);
                pfn(bNrInPins);
                char     buf[32];
                for (int i = 0; i < d->bNrInPins; i++)
                {
                    sprintf(buf,"baSourceID[%d]",i);
                    pfnamen(buf,d->baSourceID[i],1);
                }

                {
                    USBAudio_CI_MixerUnitPart2* d = USBAudio_CI_MixerUnit2((USBAudio_CI_MixerUnit*) des);
                    pfn(bNrChannels);
                    pfn(wChannelConfig);
                    pfs(iChannelNames);
                    char     buf[32];
                    int size = USBAudio_CI_sizeof_mu_controls((USBAudio_CI_MixerUnit*)des);
                    for (int i = 0; i < size; i++)
                    {
                        sprintf(buf,"bmControls[%d]",i);
                        pfnamen(buf,d->bmControls[i],1);
                    }
                }

                {
                    USBAudio_CI_MixerUnitPart3* d = USBAudio_CI_MixerUnit3((USBAudio_CI_MixerUnit*) des);
                    pfs(iMixer);
                }

                pline;
                pf("\n");
            }
            break;
        case USB_AUDIO_CI_SELECTOR_UNIT:
            {
                USBAudio_CI_SelectorUnit* d = ( USBAudio_CI_SelectorUnit*) des;
                ptitle(Audio Control Interface Selector Unit Descriptor,LEAF_OFFSET);
                pfn(bLength);
                pfn(bDescriptorType);
                pfn(bDescriptorSubType);
                pfn(bUnitID);
                pfn(bNrInPins);
                char     buf[32];
                for (int i = 0; i < d->bNrInPins; i++)
                {
                    sprintf(buf,"baSourceID[%d]",i);
                    pfnamen(buf,d->baSourceID[i],1);
                }

                {
                    USBAudio_CI_SelectorUnitPart2* d = USBAudio_CI_SelectorUnit2((USBAudio_CI_SelectorUnit*) des);
                    pfs(iSelector);
                }

                pline;
                pf("\n");
            }
            break;
        case USB_AUDIO_CI_FEATURE_UNIT:
            {
                USBAudio_CI_FeatureUnit* d = (USBAudio_CI_FeatureUnit*) des;
                ptitle(Audio Control Interface Feature Unit Descriptor,LEAF_OFFSET);
                pfn(bLength);
                pfn(bDescriptorType);
                pfn(bDescriptorSubType);
                pfn(bUnitID);
                pfn(bSourceID);
                
                if (protocol == 0)
                {
                    pfn(bControlSize);
                    
                    uint32_t bits;
                    char     buf[32];
                    int size = USBAudio_CI_sizeof_fu_controls(d);
                    for (int j = 0; j < size; j += d->bControlSize)
                    {
                        bits = 0;
                        for (int i = 0; i < d->bControlSize; i++)
                        {
                            bits |= (d->bmaControls[i+j] << (i*8));
                        }

                        sprintf(buf,"bmaControls[%d]",j/d->bControlSize);
                        pfnamenn(buf,bits,d->bControlSize);
                        int b = d->bControlSize * 8;
                        if (b >= sizeof(featureList)/sizeof(void*)) 
                                  b = sizeof(featureList)/sizeof(void*);
                       
                        int count = 0;
                        for (int i = 0; i < b; i++)
                        {
                            if (bits & (1<<i)) pf("%s%s",(count++?", ":""),getListValue(i,listArgs(featureList)));
                        }
                        pf("\n");
                    }

                    {
                        USBAudio_CI_FeatureUnitPart2* d = USBAudio_CI_FeatureUnit2(des);
                        pfs(iFeature);
                    }
                }
                else
                {
                    USBAudio2_CI_FeatureUnit* d = (USBAudio2_CI_FeatureUnit*) des;
                    char     buf[32];
                    for (int i = 0; i < USBAudio2_CI_sizeof_fu_controls(d); i++)
                    {
                        sprintf(buf,"bmaControls[%d]",i);
                        pfnamenn(buf,d->bmaControls[i],4);
                        int count = 0;
                        for (int j = 0; j < 30; j+=2)
                        {
                            if (d->bmaControls[i] & (3<<j)) pf("%s%s",(count++?", ":""),getListValue((j>>1),listArgs(featureList)));
                        }
                        pf("\n");
                    }
                    {
                        USBAudio2_CI_FeatureUnitPart1* d = USBAudio2_CI_FeatureUnit1(des);
                        pfs(iFeature);
                    }
                }
                pline;
                pf("\n");
           }
           break;
        case USBAUDIO2_CI_CLOCK_SOURCE:
            {
                USBAudio2_CI_ClockSource* d = (USBAudio2_CI_ClockSource*)des;
                ptitle(Audio Control Interface Clock Source Descriptor,LEAF_OFFSET);  
                pfn(bLength);
                pfn(bDescriptorType);
                pfn(bDescriptorSubType);
                pfn(bClockID);
                pfn(bmAttributes);
                pfn(bmControls);
                pfn(bAssocTerminal);
                pfs(iClockSource);
                pline;
                pf("\n");
            }
            break;
        case USBAUDIO2_CI_CLOCK_SELECTOR:
            {
                USBAudio2_CI_ClockSelector* d = (USBAudio2_CI_ClockSelector*)des;
                ptitle(Audio Control Interface Clock Selector Descriptor,LEAF_OFFSET);  
                pfn(bLength);
                pfn(bDescriptorType);
                pfn(bDescriptorSubType);
                pfn(bClockID);
                pfn(bNrInPins);
                char     buf[32];
                for (int i = 0; i < d->bNrInPins; i++)
                {
                    sprintf(buf,"baCSourceID[%d]",i);
                    pfnamen(buf,d->baCSourceID[i],1);
                }
                
                {
                    USBAudio2_CI_ClockSelectorPart2* d = USBAudio2_CI_ClockSelector2(des);
                    pfn(bmControls);
                    pfs(iClockSelector);
                }
                pline;
                pf("\n");
            }
            break;
        case USBAUDIO2_CI_CLOCK_MULTIPLIER:
            {
                USBAudio2_CI_ClockMultiplier* d = (USBAudio2_CI_ClockMultiplier*)des;
                ptitle(Audio Control Interface Clock Multiplier Descriptor,LEAF_OFFSET);  
                pfn(bLength);
                pfn(bDescriptorType);
                pfn(bDescriptorSubType);
                pfn(bClockID);
                pfn(baCSourceID);
                pfn(bmControls);
                pfs(iClockMultiplier);
                pline;
                pf("\n");
            }
            break;
        default: return true; //unknown 

    }
    return false;
}

static bool audioStreamingInterface(USBDevice* device,uint8_t protocol,const USB_Descriptor* des)
{
    switch (des->bDescriptorSubType)
    {
        case USB_AUDIO_SI_GENERAL:
            {
                USBAudio_SI_General* d = (USBAudio_SI_General*) des;
                ptitle(Audio Streaming Interface General Descriptor,LEAF_OFFSET);
                pfn(bLength);
                pfn(bDescriptorType);
                pfn(bDescriptorSubType);
                pfn(bTerminalLink);
                
                if (protocol == 0)
                {
                    pfn(bDelay);
                    pfnn(wFormatFlag);pf("%s\n",getAudioType(d->wFormatFlag));
                }
                else
                {
                    USBAudio2_SI_General* d = (USBAudio2_SI_General*) des;
                    pfn(bmControls);
                    pfn(bFormatType);
                    pfnn(bmFormats);pf("%s\n",getAudioType(d->bmFormats));
                    pfn(bNrChannels);
                    pfn(bmChannelConfig);
                    pfnn(iChannelNames);
                    printStringList(device,d->iChannelNames,d->bNrChannels);
                    pf("\n");
                }
                pline;
                pf("\n");
            }
            break;
        case USB_AUDIO_SI_FORMAT_TYPE:
            {
                USBAudio_SI_FormatType* d = (USBAudio_SI_FormatType*) des;
                ptitle(Audio Streaming Interface Format Type Descriptor,LEAF_OFFSET);
                pfn(bLength);
                pfn(bDescriptorType);
                pfn(bDescriptorSubType);
                pfn(bFormatType);
                
                if (protocol == 0)
                {
                    uint8_t* samples = NULL;
                    switch (d->bFormatType)
                    {
                        case USB_AUDIO_SI_FORMAT_TYPE_II:
                            {
                                USBAudio_SI_FormatType_II* d = (USBAudio_SI_FormatType_II*) des;
                                pfn(wMaxBitRate);
                                pfn(wSamplesPerFrame);
                                pfn(bSamFreqType);
                                samples = (uint8_t*) &d->bSamFreqType;
                            }
                            break;
                        default:
                            pfn(bNrChannels);
                            pfn(bSubFrameSize);
                            pfn(bBitResolution);
                            pfn(bSamFreqType);
                            samples = (uint8_t*) &d->bSamFreqType;

                    }

                    if (*samples == 0)
                    {
                        samples++;
                        pfnamenn("tLowerSamFreq",USBAudio_sampleFreq(samples),sizeof(d->tSamFreq));pf("Hz\n");
                        samples+=3;
                        pfnamenn("tUpperSamFreq",USBAudio_sampleFreq(samples),sizeof(d->tSamFreq));pf("Hz\n");
                    }
                    else
                    {
                        uint8_t* end = ((uint8_t*)d) + d->bLength;
                        char  buf[16];
                        int i=0;
                        for (++samples;samples < end; samples += 3, i++)
                        {
                            sprintf(buf,"tSamFreq[%d]",i);
                            pfnamenn(buf,USBAudio_sampleFreq(samples),sizeof(d->tSamFreq));pf("Hz\n");
                        }
                    }
                }
                else
                {
                    switch (d->bFormatType)
                    {
                        case USB_AUDIO_SI_FORMAT_TYPE_II:
                        {
                            USBAudio2_SI_FormatType_II* d = (USBAudio2_SI_FormatType_II*) des;     
                            pfn(wMaxBitRate);
                            pfn(wSlotsPerFrame);
                            break;
                        }
                        default:
                        {
                            // type II and III the same
                            USBAudio2_SI_FormatType* d = (USBAudio2_SI_FormatType*) des;     
                            pfn(bSubSlotSize);
                            pfn(bBitResolution);
                            break;
                        }
                    }
                }       
                pline;
                pf("\n");
            }
            break;
        default: return true; //unknown 
    }
    return false;
}

static bool videoStreamingInterface(USBDevice* device,uint8_t protocol,const USB_Descriptor* des)
{
    switch (des->bDescriptorSubType)
    {
        case USB_VIDEO_SI_INPUT_HEADER:
            {
                USBVideo_SI_InputHeader* d = (USBVideo_SI_InputHeader*) des;
                ptitle(Video Streaming Interface Input Header Descriptor,LEAF_OFFSET);
                pfn(bLength);
                pfn(bDescriptorType);
                pfn(bDescriptorSubType);
                pfn(bNumFormats);
                pfn(wTotalLength);
                pfn(bEndpointAddress);
                pfn(bmInfo);
                pfn(bTerminalLink);
                pfn(bStillCaptureMethod);
                pfn(bTriggerSupport);
                pfn(bTriggerUsage);
                pfn(bControlSize);
                int count = USBVideo_SI_IH_bmaControlCount(d);
                int offset = 0;
                char buf[32];
                for (int c = 0; c < count; c++)
                {
                    uint32_t n = 0;
                    for (int i = d->bControlSize; i ; i--)
                    {
                        n <<= 8;
                        n |= d->bmaControls[offset++];
                    }
                    sprintf(buf,"bmaControls[%d]",c);
                    pfnamen(buf,n,d->bControlSize);
                }
                pline;
                pf("\n");
            }
            break;
        case USB_VIDEO_SI_FORMAT_UNCOMPRESSED:
            {
                USBVideo_SI_FormatUncompressed* d = (USBVideo_SI_FormatUncompressed*) des;
                ptitle(Video Streaming Interface Format Uncompressed Descriptor,LEAF_OFFSET);
                pfn(bLength);
                pfn(bDescriptorType);
                pfn(bDescriptorSubType);
                pfn(bFormatIndex);
                pfn(bNumFrameDescriptors);
                pfnamenn("guidFormat[16]",0,16);pf("'%s'\n",&d->guidFormat[0]);
                pfn(bBitsPerPixel);
                pfn(bDefaultFrameIndex);
                pfn(bAspectRatioX);
                pfn(bAspectRatioY);
                pfn(bmInterfaceFlags);
                pfn(bCopyProtect);
                pline;
                pf("\n");
            }
            break;
        case USB_VIDEO_SI_FRAME_UNCOMPRESSED:
            {
                USBVideo_SI_FrameUncompressed* d = (USBVideo_SI_FrameUncompressed*) des;
                ptitle(Video Streaming Interface Frame Uncompressed Descriptor,LEAF_OFFSET);
                pfn(bLength);
                pfn(bDescriptorType);
                pfn(bDescriptorSubType);
                pfn(bFrameIndex);
                pfn(bmCapabilities);
                pfn(wWidth);
                pfn(wHeight);
                pfn(dwMinBitRate);
                pfn(dwMaxBitRate);
                pfn(dwMaxVideoFrameBufferSize);
                pfnn(dwDefaultFrameInterval);pf("100ns units\n");
                pfn(bFrameIntervalType);
                
                if (d->bFrameIntervalType == 0)
                {
                    USBVideo_SI_FrameUncompressedContiguous* d = (USBVideo_SI_FrameUncompressedContiguous*) des;
                    pfn(dwMinFrameInterval);
                    pfn(dwMaxFrameInterval);
                    pfn(dwFrameIntervalStep);
                }
                else
                {
                    char buf[32];
                    for (int c = 0; c < d->bFrameIntervalType; c++)
                    {
                         sprintf(buf,"dwFrameInterval[%d]",c);
                         pfnamenn(buf,d->dwFrameInterval[c],sizeof(d->dwFrameInterval[0]));
                         pf("100ns units\n");
                    }
                }
                
                pline;
                pf("\n");
            }
            break;
        default: return true; //unknown 
    }
    return false;
}

static void unknownDescriptor(const USB_Descriptor* d)
{
    pf("*** Unknown Descriptor ***\n");
    pf("bLength:          %d\n",d->bLength);
    pf("bDescriptorType:  0x%02x (%d)\n",d->bDescriptorType,d->bDescriptorType);

    const uint8_t* data = (uint8_t*)&d->bDescriptorSubType;
    for (int i=0;i<d->bLength-2;i++)
    {
        pf("Byte %3d:  0x%02x (%d)\n",i+2,data[i],data[i]);
    }
    pf("\n");
}

static void printDeviceData(USB_ServiceCall* item)
{
    pf("=============================================\n");
    pf(" Device %s\n",item->deviceName);
    pf("=============================================\n");
    pf(":  0 :  2 : total size of ServiceCall block : %d\n",item->sclen);
    pf(":  2 :  2 : offset to descriptor list       : %#x\n",item->descOffset);
    pf(":  4 : 20 : name                            : %s\n",item->deviceName);
    pf(": 24 :  1 : bus number                      : %d\n",item->busNumber);
    pf(": 25 :  1 : device address                  : %d\n",item->deviceAddress);
    pf(": 26 :  1 : host address                    : %d\n",item->hostAddress);
    pf(": 27 :  1 : host port                       : %d\n",item->hostPort);
    pf(": 28 :  1 : speed                           : %d ",item->speed);
    
    switch (item->speed)
    {
        case 1: pf("low speed");break;
        case 2: pf("full speed");break;
        case 3: printf("high speed");break;
    }
    pf("\n");
    pf("---------------------------------------------\n\n");

}


static void USBPrint_descriptor(USB_ServiceCall* item)
{
    if (item == NULL) return;
#ifdef TEST
    uint32_t        csClass = 0;
    USBDevice*      device = (USBDevice*)"TEST";
    USB_Descriptor* des = (USB_Descriptor*)item;

#else   
    printDeviceData(item);
    uint32_t        csClass = 0;
    USBDevice*      device = (USBDevice*) item->deviceName;
    USB_Descriptor* des = USB_getDescriptorList(item);
#endif
    for (char* pos=(char*)des; des->bLength; pos+=des->bLength,des=(USB_Descriptor*)pos)
    {
        bool unknown = false;
        switch(des->bDescriptorType)
        {
            case USB_DEVICE_DESCRIPTOR:
                {
                    USB_DeviceDescriptor* ddesc = (USB_DeviceDescriptor*)pos;
                    deviceDescriptor(device,ddesc);
                    csClass = ((ddesc->bDeviceClass << 16) | (ddesc->bDeviceSubClass << 8) | ddesc->bDeviceProtocol);
                }
                break;
            case USB_CONFIGURATION_DESCRIPTOR:
                configurationDescriptor(device,(USB_ConfigurationDescriptor*)pos);
                break;
            case USB_STRING_DESCRIPTOR:
                stringDescriptor((USB_StringDescriptor*)pos);
                break;
            case USB_INTERFACE_DESCRIPTOR:
                {
                    USB_InterfaceDescriptor* idesc = (USB_InterfaceDescriptor*)pos;
                    interfaceDescriptor(device,idesc);
                    csClass=((idesc->bInterfaceClass << 16) | (idesc->bInterfaceSubClass << 8) | idesc->bInterfaceProtocol);
                }
                break;
            case USB_ENDPOINT_DESCRIPTOR:
                endpointDescriptor(csClass,(USB_EndpointDescriptor*)pos);
                break;
            case USB_INTERFACE_ASSOCIATION_DESCRIPTOR:
                interfaceAssociationDescriptor(device,(USB_InterfaceAssociationDescriptor*)pos);
                break;
            default: 
                switch (csClass & 0xffff00)
                {
                    case USB_VIDEO_CS_STREAMING:
                        switch (des->bDescriptorType)
                        {
                            case USB_CS_INTERFACE_DESCRIPTOR:
                                unknown = videoStreamingInterface(device,(csClass & 0xFF),des);
                                break;
                        }
                        break;
                    case USB_AUDIO_CS_CONTROL:
                        switch (des->bDescriptorType)
                        {
                            //case USB_CS_DEVICE_DESCRIPTOR:
                            //case USB_CS_ENDPOINT_DESCRIPTOR:
                            case USB_CS_INTERFACE_DESCRIPTOR:
                                unknown = audioControlInterface(device,(csClass & 0xFF),des);
                                break;
                            default:
                                unknown = true;
                                break;
                        }
                        break;
                    case USB_AUDIO_CS_STREAMING:
                        switch (des->bDescriptorType)
                        {
                            case USB_CS_INTERFACE_DESCRIPTOR:
                                unknown = audioStreamingInterface(device,(csClass & 0xFF),des);
                                break;
                            case USB_CS_ENDPOINT_DESCRIPTOR:
                                unknown = audioStreamEndpoint((csClass & 0xFF),des);
                                break;
                            default:
                                unknown = true;
                                break;
                        }
                        break;
                    case USB_HID_CS_BOOT:
                    case USB_HID_CS_NOBOOT:
                        switch (des->bDescriptorType)
                        {
                            case USB_CS_DEVICE_DESCRIPTOR:
                                hidDeviceDescriptor(device, (USB_HIDDeviceDescriptor*)pos);
                                break;
                            default:
                                unknown = true;
                                break;
                        }
                        break;
                    default:
                        unknown = true;
                        break;
                }
                break;
            
        }
        if (unknown) unknownDescriptor((USB_Descriptor*)pos);
    }
}

// Scarlett
char test[] = {0x09,0x02,0x1F,0x01,0x04,0x01,0x00,0x80,0xFA,0x08,0x0B,0x00,0x03,0x01,0x00,0x20,
0x00,0x09,0x04,0x00,0x00,0x01,0x01,0x01,0x20,0x02,0x09,0x24,0x01,0x00,0x02,0x08,
0x77,0x00,0x00,0x08,0x24,0x0A,0x29,0x03,0x07,0x00,0x09,0x08,0x24,0x0B,0x28,0x01,
0x29,0x03,0x08,0x11,0x24,0x02,0x02,0x01,0x01,0x00,0x28,0x02,0x00,0x00,0x00,0x00,
0x0F,0x00,0x00,0x06,0x12,0x24,0x06,0x0A,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x24,0x03,0x14,0x01,0x03,0x00,0x0A,0x28,0x00,
0x00,0x00,0x11,0x24,0x02,0x01,0x01,0x02,0x00,0x28,0x02,0x00,0x00,0x00,0x00,0x21,
0x00,0x00,0x00,0x12,0x24,0x06,0x0B,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x0C,0x24,0x03,0x16,0x01,0x01,0x00,0x0B,0x28,0x00,0x00,
0x07,0x07,0x05,0x84,0x03,0x06,0x00,0x08,0x09,0x04,0x01,0x00,0x00,0x01,0x02,0x20,
0x04,0x09,0x04,0x01,0x01,0x02,0x01,0x02,0x20,0x04,0x10,0x24,0x01,0x02,0x00,0x01,
0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x0F,0x06,0x24,0x02,0x01,0x04,0x18,
0x07,0x05,0x01,0x05,0x00,0x04,0x01,0x08,0x25,0x01,0x00,0x00,0x02,0x08,0x00,0x07,
0x05,0x81,0x11,0x04,0x00,0x04,0x09,0x04,0x02,0x00,0x00,0x01,0x02,0x20,0x05,0x09,
0x04,0x02,0x01,0x01,0x01,0x02,0x20,0x05,0x10,0x24,0x01,0x16,0x00,0x01,0x01,0x00,
0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x21,0x06,0x24,0x02,0x01,0x04,0x18,0x07,0x05,
0x82,0x05,0x00,0x04,0x01,0x08,0x25,0x01,0x00,0x00,0x02,0x08,0x00,0x09,0x04,0x03,
0x00,0x00,0xFE,0x01,0x01,0x0C,0x09,0x21,0x07,0xFA,0x00,0x40,0x00,0x10,0x01,0x00,
0x00};


int main(void)
{
#ifdef TEST
    USBPrint_descriptor((USB_ServiceCall*) test);
    return 0;
#endif
    pf("USBDescriptors v1.03 (09-Oct-2014)\n\n");

    USB_ConnectedDeviceList* list = USB_makeConnectedDeviceList();
    for (USB_ConnectedDeviceList* item=list; item; item=item->next)
    {
        USBPrint_descriptor(&item->svc);
    }
    USB_destroyConnectedDeviceList(list);
}
