/*
**************************************************************************************************************
*                                                 NXP USB Host Stack
*
*                                     (c) Copyright 2008, NXP SemiConductors
*                                     (c) Copyright 2008, OnChip  Technologies LLC
*                                                 All Rights Reserved
*
*                                                  www.nxp.com
*                                               www.onchiptech.com
*
* File           : usbhost_ms.c
* Programmer(s)  : Ravikanth.P
* Version        :
*
**************************************************************************************************************
*/

#define USB_DEVICE_CLASS_RESERVED              0x00
#define USB_DEVICE_CLASS_AUDIO                 0x01
#define USB_DEVICE_CLASS_COMMUNICATIONS        0x02
#define USB_DEVICE_CLASS_HUMAN_INTERFACE       0x03
#define USB_DEVICE_CLASS_MONITOR               0x04
#define USB_DEVICE_CLASS_PHYSICAL_INTERFACE    0x05
#define USB_DEVICE_CLASS_POWER                 0x06
#define USB_DEVICE_CLASS_PRINTER               0x07
#define USB_DEVICE_CLASS_STORAGE               0x08
#define USB_DEVICE_CLASS_HUB                   0x09
#define USB_DEVICE_CLASS_VENDOR_SPECIFIC       0xFF

#define AUDIO_SUBCLASS_UNDEFINED               0x00
#define AUDIO_SUBCLASS_AUDIOCONTROL            0x01
#define AUDIO_SUBCLASS_AUDIOSTREAMING          0x02
#define AUDIO_SUBCLASS_MIDISTREAMING           0x03

#define USB_ENDPOINT_TYPE_MASK                 0x03
#define USB_ENDPOINT_TYPE_CONTROL              0x00
#define USB_ENDPOINT_TYPE_ISOCHRONOUS          0x01
#define USB_ENDPOINT_TYPE_BULK                 0x02
#define USB_ENDPOINT_TYPE_INTERRUPT            0x03

/*
**************************************************************************************************************
*                                         PARSE THE CONFIGURATION
*
* Description: This function is used to parse the configuration
*
* Arguments  : None
*
* Returns    : OK		              if Success
*              ERR_INVALID_BOOTSIG    if Failed
*
**************************************************************************************************************
*/

USB_INT32S  Audio_ParseConfiguration (void)
{
    volatile  USB_INT08U  *desc_ptr, *dp;
              USB_INT08U   audio_int_found;
    int i, nb;


    desc_ptr     = TDBuffer;
    audio_int_found = 0;

    if (desc_ptr[1] != USB_DESCRIPTOR_TYPE_CONFIGURATION) {
        return (ERR_BAD_CONFIGURATION);
    }
    desc_ptr += desc_ptr[0];

    dp = desc_ptr;
    while (dp != TDBuffer + *((USB_INT16U *) &TDBuffer[2])) {
        nb = dp[0];
        switch (dp[1]) {
        case USB_DESCRIPTOR_TYPE_ENDPOINT:
            cons_printf("E ");
            break;
        case USB_DESCRIPTOR_TYPE_INTERFACE:
            cons_printf("I ");
            break;
        case USB_DESCRIPTOR_TYPE_AUDIO_INTERFACE:
            cons_printf("AI");
            break;
        case USB_DESCRIPTOR_TYPE_AUDIO_DEVICE:
            cons_printf("AD");
            break;
        case USB_DESCRIPTOR_TYPE_AUDIO_ENDPOINT:
            cons_printf("AE");
            break;
        default:
            cons_printf("* ");
            break;
        }
        for (i = 1; i < nb; i++) {
            cons_printf(" %02x", dp[i]);
        }
        cons_printf("\n");
        dp += nb;     /* Move to next descriptor start      */
    }

    while (desc_ptr != TDBuffer + *((USB_INT16U *) &TDBuffer[2])) {
        switch (desc_ptr[1]) {
            case USB_DESCRIPTOR_TYPE_INTERFACE:
                /* If it is an interface descriptor   */
#ifdef notdef
cons_printf("IF: #%d, alt %d, class: %x, subclass: %x\n",
        desc_ptr[2], desc_ptr[3], desc_ptr[5], desc_ptr[6]);
#endif
                /* check if the class is audio device
                     and the subclass is audio stream */
cons_printf("IF #%d, alt %d", desc_ptr[2], desc_ptr[3]);
                switch (desc_ptr[5]) {
                case USB_DEVICE_CLASS_AUDIO:
                    switch (desc_ptr[6]) {
                    case AUDIO_SUBCLASS_AUDIOSTREAMING:
                        cons_printf(" is audio streaming.\n");
                        audio_int_found = 1;
                        break;
                    case AUDIO_SUBCLASS_AUDIOCONTROL:
                        cons_printf(" is audio control.\n");
                        break;
                    default:
                        cons_printf(" is unknown audio interface.\n");
                    }
                    break;
                case USB_DEVICE_CLASS_HUMAN_INTERFACE:
                    cons_printf(" is HID.\n");
                    break;
                default:
                    cons_printf(" is unknown interface.\n");
                    break;
                }
                desc_ptr    += desc_ptr[0];      /* Move to next descriptor start      */
                break;
            case USB_DESCRIPTOR_TYPE_ENDPOINT:    /* If it is an endpoint descriptor    */
                cons_printf("-- Endpoint %d", desc_ptr[2] & 0x7f);
                if (desc_ptr[2] & 0x80) {
                    cons_printf("-IN");
                } else {
                    cons_printf("-OUT");
                }
                cons_printf(" (%d) is type ", desc_ptr[4]);
                switch (desc_ptr[3] & USB_ENDPOINT_TYPE_MASK) {
                case USB_ENDPOINT_TYPE_CONTROL:
                    cons_printf("CONTROL");
                    break;
                case USB_ENDPOINT_TYPE_ISOCHRONOUS:
                    cons_printf("ISOCHRONOUS");
#ifdef notdef
                    if ((desc_ptr[2] & 0x80) == 0) {
                        EDIsoOut->Control = 1  |      /* USB address  */
                              ((desc_ptr[2] & 0x7F) << 7) |      /* Endpoint address  */
                              (1 << 11) |   /* direction */
                              (ReadLE16U(&desc_ptr[4]) << 16);     /* MaxPkt Size     */
                    }
#endif
                    break;
                case USB_ENDPOINT_TYPE_BULK:
                    cons_printf("BULK");
                    break;
                case USB_ENDPOINT_TYPE_INTERRUPT:
                    cons_printf("INTERRUPT");
                    break;
                }
                cons_printf("\n");
#ifdef XXX
                if ((desc_ptr[3] & 0x03) == 0x02) {            /* If it is Bulk endpoint   */
                     if (desc_ptr[2] & 0x80) {   /* If it is In endpoint */
                         EDBulkIn->Control =  1   |      /* USB address */
                              ((desc_ptr[2] & 0x7F) << 7) |      /* Endpoint address */
                              (2 << 11) |      /* direction */
                              (ReadLE16U(&desc_ptr[4]) << 16); /* MaxPkt Size */
                     } else {                  /* If it is Out endpoint */
                         EDBulkOut->Control = 1  |      /* USB address  */
                              ((desc_ptr[2] & 0x7F) << 7) |      /* Endpoint address  */
                              (1 << 11) |   /* direction */
                              (ReadLE16U(&desc_ptr[4]) << 16);     /* MaxPkt Size     */
                     }
                 }
#endif
                 desc_ptr += desc_ptr[0];    /* Move to next descriptor start      */
                 break;

            default:          /* If the descriptor is neither interface nor endpoint */
                 desc_ptr += desc_ptr[0];     /* Move to next descriptor start      */
                 break;
        }
    }
    if (audio_int_found) {
        PRINT_Log("Audio device connected\n\r");
        return (OK);
    } else {
        PRINT_Log("Not a Audio device\n\r");
        return (ERR_NO_MS_INTERFACE);
    }
}
