/****************************************************************
	dump_descriptor.c
    (c) 2013 Suwa-Koubou
****************************************************************/

#include <stdio.h>

void	dump_descriptor(unsigned char *p, short len)
{
	int	 i, j;
    int  n;
    int  interface_subclass,interface_class ;

	n = 0;
	while(n < len){
		switch(p[n +1]){
		case 0x01:
			printf("*** Device Descriptor\n");
			printf("\tbLength=%d\n", p[n+0]);
			printf("\tbDescriptor=%d\n", p[n+1]);
			printf("\tbcdUSB=0x%02X%02X\n", p[n+3], p[n+2]);
			printf("\tbDeviceClass=%d\n", p[n+4]);
			printf("\tbDeviceSubClass=%d\n", p[n+5]);
			printf("\tbDeviceProtocol=%d\n",p[n+6]);
			printf("\tbMaxPacketSize=%d\n",p[n+7]);
			printf("\tidVendor=0x%02X%02X\n",p[n+9],p[n+8]);
			printf("\tidProduct=0x%02X%02X\n",p[n+11], p[n+10]);
			printf("\tbcdDevice=0x%02X%02X\n",p[n+13], p[n+12]);
			printf("\tiManufacture=%d\n", p[n+14]);
			printf("\tiProduct=%d\n", p[n+15]);
			printf("\tiSerialNumber=%d\n", p[n+16]);
			printf("\tbNumConfigurations=%d\n", p[n+17]);
			n += p[n];
			break;

		case 0x02: // configuration descriptor
			printf("*** ConfigurationDescriptor\n");
			printf("\tbLength=%d\n", p[n+0]); 
			printf("\tbDescriptor=%d\n", p[n+1]); 
			printf("\twTotalLength=%d\n", (unsigned int)(p[n+3])*256 + p[n+2]); 
			printf("\tbNumInterfaces=%d\n", p[n+4]); 
			printf("\tbConfigurationValue=%d\n",p[n+5]); 
			printf("\tiConfiguration=%d\n", p[n+6]); 
			printf("\tbmAttributes=0x%02X\n", p[n+7]); 
			printf("\tbMaxPower=%d\n", p[n+8]); 
			n += p[n];
			break;

		case 0x04: // interface descriptor
			printf("*** InterfaceDescriptor\n");
			printf("\tbLength=%d\n", p[n+0]); 
			printf("\tbDescriptorType=%d\n", p[n+1]); 
			printf("\tbInterfaceNumber=%d\n", p[n+2]); 
			printf("\tbAlternateSetting=%d\n", p[n+3]); 
			printf("\tbNumEndPoints=%d\n", p[n+4]); 
			printf("\tbInterfaceClass=%d\n", p[n+5]);
			printf("\tbInterfaceSubClass=%d\n", p[n+6]); 
			printf("\tbInterfaceProtocol=%d\n",p[n+7]); 
			printf("\tiInterface=%d\n", p[n+8]); 
			interface_subclass = p[n+6];
			interface_class = p[n+5];
			n += p[n];
			break;

		case 0x05:	// endpoint descriptor
			printf("*** EndpointDescriptor\n");
			printf("\tbLength=%d\n", p[n+0]); 
			printf("\tbDescriptorType=%d\n", p[n+1]); 
			printf("\tbEndPointAddress=0x%02X\n", p[n+2]); 
			printf("\tbmAttributes=%d\n", p[n+3]);
            printf("\t   (%s)\n", (p[n+3]&3)==3? "interrupt": ((p[n+3]&3)==2? "bulk": (p[n+3]&3)==1? "isocronus": "control"));
			printf("\twMaxPacketSize=%d\n",(unsigned int)(p[n+5]) * 256 + p[n+4]); 
			printf("\tbInterval=%d\n", p[n+6]); 
			n += p[n];
			break;

		case 0x03:	// string descriptor
			printf("*** StringDescriptor\n"); n += p[n];
			break;
           
		case 0x06:	// device qualifier
			printf("\t*** DeviceQualifierDescriptor\n"); n += p[n];
			break;
		case 0x07:	// other speed configuration
			printf("\t*** OtherSpeedConfigurationDescriptor\n"); n += p[n];
			break;

		case 0x0b: // INTERFACE ASSOCIATION descriptor
			printf("\t*** Interface Association Descriptor\n");
			printf("\tbLength=%d\n", p[n+0]); 
			printf("\tbDescriptorType=%d\n", p[n+1]); 
			printf("\tbFirstInterface=%d\n", p[n+2]); 
			printf("\tbInterfaceCount=%d\n", p[n+3]); 
			printf("\tbFunctionClass=%d\n", p[n+4]); 
			printf("\tbFunctionSubClass=%d\n", p[n+5]); 
			printf("\tbFunctionProtocol=%d\n", p[n+6]); 
			printf("\tiFunction=%d\n", p[n+7]); 
			n += p[n];
			break;

		case 0x24:	// CS_INTERFACE
			if(interface_class == 0x0e && interface_subclass == 0x01){ // Video Control
				printf("\t*** Video Control Interface Descriptor\n");
				printf("\tbLength=%d\n", p[n+0]); 
				printf("\tbDescriptorType=%d\n", p[n+1]); 
				printf("\tbDescriptorSubType=%d  ", p[n+2]);
				switch(p[n+2]){
                case 0x01:  // VC_HEADER
                    printf(" [VC_HEADER]\n");           
                    printf("\tbcdUVC=%02X%02X\n", p[n+4], p[n+3]);
                    printf("\twTotalLength=%d\n", (unsigned int)(p[n+6]) * 256 + p[n+5]);
                    printf("\tdwClockFrequency=%ld\n" , (p[n+10] << 24) | (p[n+9]<<16) | (p[n+8]<< 8) | p[n+7]);
                    printf("\tbInCollection=%d\n", p[n+11]);
                    for(i = 0; i < p[n+11]; i++){
                        printf("\tbaInterfaceNr=%d\n", p[n+12+i]);
                    }
                    break;

                case 0x02:  // VC_INPUT_TERMINAL
                    printf(" [VC_INPUT_TERMINAL]\n");           
                    printf("\tbTerminalID=%d\n", p[n+3]);
                    printf("\twTerminalType=0x%02X%02X\n", p[n+5], p[n+4]);
                    printf("\tbAssocTerminal=%d\n", p[n+6]);
                    printf("\tiTerminal=%d\n", p[n+7]);
                    if(p[n+4] != 0x01 || p[n+5] != 0x02){   // !CAMERA
                        for(i = 8; i < p[n]; i++){
                            printf("\t ..... =%d\n", p[n+i]);
                        }
                        break;
                    }
                    // CAMERA
                    printf("\twObjectiveFocalLengthMin=%d\n", (p[n+9]<<8)| p[n+8]);
                    printf("\twObjectiveFocalLengthMax=%d\n", (p[n+11]<<8)| p[n+10]);
                    printf("\twOcularFocalLength=%d\n", (p[n+13]<<8)| p[n+12]);
                    printf("\tbControlSize=%d\n", p[n+14]);
                    printf("\tbmControls=0x");
                    for(i = p[n+14]; i > 0; i--){
                        printf("%02X", p[n+14+i]);
                    }
                    printf("\n");
                    break;

                case 0x03:  // VC_OUTPUT_TERMINAL
                    printf(" [VC_OUTPUT_TERMINAL]\n");          
                    printf("\tbTerminalID=%d\n", p[n+3]);
                    printf("\twTerminalType=0x%02X%02X\n", p[n+5], p[n+4]);
                    printf("\tbAssocTerminal=%d\n", p[n+6]);
                    printf("\tbSourceID=%d\n", p[n+7]);
                    printf("\tiTerminal=%d\n", p[n+8]);
                    break;

                case 0x04:  // VC_SELECTOR_UNIT
                    printf(" [VC_SELECTOR_UNIT]\n");
                    printf("\tbUnitID=0x%02X\n", p[n+3]);
                    printf("\tbNrInPins=0x%02X\n", p[n+4]);
                    for(i = 0; i < p[n+4]; i++){
                        printf("\tbaSourceID=0x%02X\n",p[n+5+i]);
                    }
                    printf("\tiSelector=0x%02X\n", p[n+5+p[n+4]]);
                    break;

                case 0x05:  // VC_PROCESSING_UNIT
                    printf(" [VC_PROCESSING_UNIT]\n");          
                    printf("\tbUnitID=%d\n",p[n+3]);
                    printf("\tbSourceID=%d\n",p[n+4]);
                    printf("\twMaxMuliplier=%d\n",(p[n+6]<<8)|p[n+5]);
                    printf("\tbControlSize=%d\n",p[n+7]);
                    printf("\tbmControls=0x"); for(i = p[n+7]; i > 0; i--) printf("%02X", p[n+7+i]); printf("\n");
                    printf("\tiProcessing=%d\n",p[n+8+p[n+7]]);
                    printf("\tbmVideoStandards=0x%02X\n", p[n+9+p[n+7]]);
                    break;

                case 0x06:  // VC_EXTENSION_UNIT
                    printf(" [VC_EXTENSION_UNIT]\n");
                    printf("\tbUnitID=%d\n",p[n+3]);
                    printf("\tguidExtensionCode=0x"); for(i = 0; i < 16; i++) printf("%02X", p[n+4+i]); printf("\n");
                    printf("\tbNumControls=%d\n",p[n+20]);
                    printf("\tbNrInPins=%d\n",p[n+21]);
                    for(i = 0; i < p[n+21]; i++){
                        printf("\tbaSourceID(%d)=%d\n",i, p[n+22+i]); 
                    }
                    printf("\tbControlSize=%d\n",p[n+22+p[n+21]]);
                    for(i =0; i< p[n+22+p[n+21]]; i++) {
                        printf("\tbmControls(%d)=0x%02X\n", i, p[ n+23+p[n+21] +i]);
                    }
                    printf("\tiExtension=%d\n", p[n+23+p[n+21]+p[n+22+p[n+21]]]);
                    break;

                default:
                    printf(" [VC_UNDEFINED]\n");
                    for(i = 3; i < p[n];i++){
                        printf("\t ..... =0x%02X\n", p[n+i]);
                    }
                    break;
                }

			}else if(interface_class == 0x0e && interface_subclass == 0x02){ // Video Streaming

                printf("\t*** Video Streaming Interface Descriptor\n");
                printf("\tbLength=%d\n", p[n+0]);
                printf("\tbDescriptorType=%d\n", p[n+1]);
                printf("\tbDescriptorSubType=%d", p[n+2]);

                switch(p[n+2]){
                case 0x01:  // VS_INPUT_HEADER
                    printf(" [VS_INPUT_HEADER]\n");         
                    printf("\tbNumFormats=%d\n", p[n+3]);
                    printf("\twTotalLength=0x%02X%02x\n", p[n+5], p[n+4]);
                    printf("\tbEndpointAddress=0x%02X\n", p[n+6]);
                    printf("\tbmInfo=%d\n", p[n+7]);
                    printf("\tbTerminalLink=%d\n", p[n+8]);
                    printf("\tbStillCaptureMethod=%d\n", p[n+9]);
                    printf("\tbTriggerSupport=%d\n", p[n+10]);
                    printf("\tbTriggerUsage=%d\n", p[n+11]);
                    printf("\tbControlSize=%d\n", p[n+12]);
                    for(i = 0; i < p[n+12]*p[n+3]; i++){
                        printf("\tbmaControls(%d)=%d\n", i , p[n+13 +i]); 
                    }
                    break;

                case 0x02:  // VS_OUTPUT_HEADER
                    printf(" [VS_OUTPUT_HEADER]\n");            
                    printf("\tbNumFormats=%d\n",p[n+3]);
                    printf("\twTotalLength=0x%02X%02X\n", p[n+5], p[n+4]);
                    printf("\tbEndpointAddress=0x%02X\n", p[n+6]);
                    printf("\tbTerminalLink=%d\n", p[n+7]);
                    printf("\tbControlSize=%d\n", p[n+8]);
                    for(i = 0; i < p[n+8]; i++){
                        printf("\tbmaControls(%d)=%d\n", i, p[n+9 +i]);
                    }
                    break;

                case 0x03:  // VS_STILL_IMAGE_FRAME
                    printf(" [VS_STILL_IMAGE_FRAME]\n");
                    printf("\tbEndpointAddress=0x%02X\n",p[n+3]);
                    printf("\tbNumImageSizePatterns=0x%02X\n", p[n+4]);
                    for(i = 0; i < p[n+4]; i++){
                        printf("\twWidth=%d\n", (unsigned int)(p[n+6+i*4]) * 256 + p[n+5+i*4]);
                        printf("\twHeight=%d\n", (unsigned int)(p[n+8+i*4]) * 256 + p[n+7+i*4]);
                    }
                    printf("\tbNumCompressionPattern=0x%02X\n", p[n+9+p[n+4]*4-4]);
                    for(i = 0; i < p[n+9+p[n+4]*4-4]; i++){
                        printf("\tbCompression=0x%02X\n", p[n+10+p[n+4]*4-4+i]);
                    }
                    break;
                
                case 0x04:  // VS_FORMAT_UNCOMPRESSED
                    printf(" [VS_FORMAT_UNCOMPRESSED]\n");
                    printf("\tbFormatIndex=%d\n", p[n+3]);
                    printf("\tbNumFrameDescriptor=%d\n", p[n+4]);
                    printf("\tguidFormat=0x"); for(i = 0; i < 16; i++) printf("%02X", p[n+5+i]); printf("\n");
                    printf("\tbBitsPerPixel=%d\n", p[n+21]);
                    printf("\tbDefaultFrameIndex=%d\n", p[n+22]);
                    printf("\tbAspectRatioX=%d\n", p[n+23]);
                    printf("\tbAspectRatioY=%d\n", p[n+24]);
                    printf("\tbmInterfaceFlags=0x%02X\n", p[n+25]);
                    printf("\tbCopyProtect=%d\n", p[n+26]);
                    break;

                case 0x05:  // VS_FRAME_UNCOMPRESSD
                    printf(" [VS_FRAME_UNCOMPRESSED]\n");
                    printf("\tbFrameIndex=%d\n", p[n+3]);
                    printf("\tbmCapabilities=0x%02X\n", p[n+4]);
                    printf("\twWidth=%d\n", (int)(p[n+6]) * 256 + p[n+5]);
                    printf("\twHeight=%d\n", (int)(p[n+8]) * 256 + p[n+7]);
                    printf("\tdwMinBitRate=%d\n", (p[n+12]<<24) | (p[n+11]<<16) | (p[n+10]<<8) | p[n+9]);
                    printf("\tdwMaxBitRate=%d\n",  (p[n+16]<<24) | (p[n+15]<<16) | (p[n+14]<<8) | p[n+13]);
                    printf("\tdwMaxVideoFrameBufferSize=%d\n", (p[n+20]<<24) | (p[n+19]<<16) | (p[n+18]<<8) | p[n+17]);
                    printf("\tdwDefaultFrameInterval=%d\n", (p[n+24]<<24) | (p[n+23]<<16) | (p[n+22]<<8) | p[n+21]);
                    printf("\tbFrameIntervalType=%d\n", p[n+25]);
                    for(i = 0; i < p[n+25]; i++){
                        printf("\tdwFrameInterval(%d)=%d\n", i, (p[n+29+i*4]<<24) | (p[n+28+i*4]<<16) | (p[n+27+i*4]<<8) | p[n+26+i*4]);
                    }
                    break;          

                case 0x06:  // VS_FORMAT_MJPEG
                    printf(" [VS_FORMAT_MJPEG]\n");
                    printf("\tbFormatIndex=%d\n", p[n+3]);
                    printf("\tbNumFrameDescriptors=%d\n", p[n+4]);
                    printf("\tbFlags=%d\n", p[n+5]);
                    printf("\tbDefaultFrameIndex=%d\n", p[n+6]);
                    printf("\tbAspectRatioX=%d\n", p[n+7]);
                    printf("\tbAspectRatioY=%d\n", p[n+8]);
                    printf("\tbmInterlaceFlags=0x%02X\n", p[n+9]);
                    printf("\tbCopyProtect=%d\n", p[n+10]);
                    break;

                case 0x07:  // VS_FRAME_MJPEG
                    printf(" [VS_FRAME_MJPEG]\n");
                    printf("\tbFrameIndex=%d\n", p[n+3]);
                    printf("\tbmCapabilities=0x%02X\n", p[n+4]);
                    printf("\twWidth=%d\n", (int)(p[n+6]) * 256 + p[n+5]);
                    printf("\twHeight=%d\n", (int)(p[n+8]) * 256 + p[n+7]);
                    printf("\tdwMinBitRate=%d\n", (p[n+12]<<24) | (p[n+11]<<16) | (p[n+10]<<8) | p[n+9]);
                    printf("\tdwMaxBitRate=%d\n",  (p[n+16]<<24) | (p[n+15]<<16) | (p[n+14]<<8) | p[n+13]);
                    printf("\tdwMaxVideoFrameBufferSize=%d\n", (p[n+20]<<24) | (p[n+19]<<16) | (p[n+18]<<8) | p[n+17]);
                    printf("\tdwDefaultFrameInterval=%d\n", (p[n+24]<<24) | (p[n+23]<<16) | (p[n+22]<<8) | p[n+21]);
                    printf("\tbFrameIntervalType=%d\n", p[n+25]);
                    if(p[n+25] == 0){   // Continuous frame interval
                        printf("\tdwMinFrameInterval=%d\n", (p[n+29]<<24) | (p[n+28]<<16) | (p[n+27]<<8) | p[n+26]);
                        printf("\tdwMaxFrameInterval=%d\n", (p[n+33]<<24) | (p[n+32]<<16) | (p[n+31]<<8) | p[n+30]);
                        printf("\tdwFrameIntervalStep=%d\n", (p[n+37]<<24) | (p[n+36]<<16) | (p[n+35]<<8) | p[n+34]);
                    }else{  // Discrete frame intervals supported
                        for(i = 0; i < p[n+25]; i++){
                            printf("\tdwFrameInterval(%d)=%d\n", i, (p[n+29+i*4]<<24) | (p[n+28+i*4]<<16) | (p[n+27+i*4]<<8) | p[n+26+i*4]);
                        }
                    }
                    break;  

                case 0x08:  // Reserved
                case 0x09:  // Reserved
                    break;

                case 0x0a:  // VS_FORMAT_MPEG2TS
                    printf(" [VS_FORMAT_MPEG2TS]\n");
                    printf("\tbFormatIndex=%d\n", p[n+3]);
                    printf("\tbDataOffset=%d\n", p[n+4]);
                    printf("\tbPacketLength=%d\n", p[n+5]);
                    printf("\tbStrideLength=%d\n", p[n+6]);
                    printf("\tguidFormat=0x"); for(i = 0; i < 16; i++) printf("%02X", p[n+7+i]); printf("\n");
                    break;

                case 0x0b:  // Reserved
                    break;

                case 0x0d:  // VS_COLORFORMAT
                    printf(" [VS_COLOR_FORMAT]\n");
                    printf("\tbColorPrimaries=%d\n", p[n+3]);
                    printf("\tbTransferCharacteristics=%d\n", p[n+4]);
                    printf("\tbMatrixCoefficients=%d\n", p[n+5]);
                    break;

                case 0x0e:  // Reserved
                case 0x0f:  // Reserved
                    break;

                case 0x10:  // VS_FORMAT_FRAME_BASED
                    printf(" [VS_FORMAT_FRAME_BASED]\n");
                    printf("\tbFormatIndex=%d\n", p[n+3]);
                    printf("\tbNumFrameDescriptors=%d\n", p[n+4]);
                    printf("\tguidFormat=0x"); for(i = 0; i < 16; i++) printf("%02X", p[n+5+i]); printf("\n");
                    printf("\tbBitsPerPixel=%d\n", p[n+21]);
                    printf("\tbDefaultFrameIndex=%d\n", p[n+22]);
                    printf("\tbAspectRatioX=%d\n", p[n+23]);
                    printf("\tbAspectRatioY=%d\n", p[n+24]);
                    printf("\tbmInterlaceFlags=%d\n", p[n+25]);
                    printf("\tbCopyProtect=%d\n", p[n+26]);
                    printf("\tbVariableSize=%d\n", p[n+27]);
                    break;

                case 0x11:  // VS_FRAME_FRAME_BASED
                    printf(" [VS_FRAME_FRAME_BASED]\n");
                    printf("\tbFrameIndex=0x%02X\n", p[n+3]);
                    printf("\tbmCapabilities=0x%02X\n", p[n+4]);
                    printf("\twWidth=%d\n", (int)(p[n+6]) * 256 + p[n+5]);
                    printf("\twHeight=%d\n", (int)(p[n+8]) * 256 + p[n+7]);
                    printf("\tdwMinBitRate=%d\n", (p[n+12]<<24) | (p[n+11]<<16) | (p[n+10]<<8) | p[n+9]);
                    printf("\tdwMaxBitRate=%d\n",  (p[n+16]<<24) | (p[n+15]<<16) | (p[n+14]<<8) | p[n+13]);
                    printf("\tdwDefaultFrameInterval=%d\n", (p[n+20]<<24) | (p[n+19]<<16) | (p[n+18]<<8) | p[n+17]);
                    printf("\tbFrameIntervalType=0x%02X\n", p[n+21]);
                    printf("\tdwBytesPerLine=%d\n",  (p[n+25]<<24) | (p[n+24]<<16) | (p[n+23]<<8) | p[n+22]);

                    if(p[n+21] == 0){   // Continuous frame interval
                        printf("\tdwMinFrameInterval=%d\n", (p[n+29]<<24) | (p[n+28]<<16) | (p[n+27]<<8) | p[n+26]);
                        printf("\tdwMaxFrameInterval=%d\n", (p[n+33]<<24) | (p[n+32]<<16) | (p[n+31]<<8) | p[n+30]);
                        printf("\tdwFrameIntervalStep=%d\n", (p[n+37]<<24) | (p[n+36]<<16) | (p[n+35]<<8) | p[n+34]);
                    }else{  // Discrete frame intervals supported
                        for(i = 0; i < p[n+21]; i++){
                            printf("\tdwFrameInterval=%d\n", (p[n+29+i*4]<<24) | (p[n+28+i*4]<<16) | (p[n+27+i*4]<<8) | p[n+26+i*4]);
                        }
                    }
                    break;


                case 0x12:  // VS_FORMAT_STREAM_BASED
                    printf(" [VS_FORMAT_STREAM_BASED]\n");
                    printf("\tbFormatIndex=%d\n", p[n+3]);
                    printf("\tguidFormat=0x"); for(i = 0; i < 16; i++) printf("%02X", p[n+4+i]);
                    printf("\tdwPacketLength=%d\n", (p[n+23]<<24) | (p[n+22]<<16) | (p[n+21]<<8) | p[n+20]);
                    break;

                default:
                    printf(" [VS_UNDEFINED]\n");
                    //for(i = 3; i < p[n];i++){
                    //    printf("\t ..... =0x%02X\n", p[n+i]);
                    //}
                    break;
                }

			}else{
                printf("\t*** Unknown Interface Descriptor\n");
                printf("\tbLength=%d\n", p[n+0]);
                printf("\tbDescriptorType=%d\n", p[n+1]);
                //for(i = 2; i < p[n];i++){
                //    printf("\t ..... =0x%02X\n", p[n+i]);
                //}
			}
			n += p[n];
			break;

		//case 0x25:	// Class Specific ENDPOINT
        //    printf("\t*** CS EndpointDescriptor\n");
        //    printf("\tbLength=%d\n", p[n+0]);
        //    printf("\tbDescriptorType=%d\n", p[n+1]);
        //    printf("\tbDescriptorSubType=%d\n",p[n+2]);
        //    printf("\twMaxTransferSize=%d\n", (p[n+4]<<8) | p[n+3]);
        //    n += p[n];
		//	break;

		default:
           printf("\t*** UnknownDescriptor\n");
            printf("\tbLength=%d\n", p[n+0]);
            printf("\tbDescriptorType=%d\n", p[n+1]);
            //for(i = 2; i < p[n];i++){
            //    printf("\t ..... =0x%02X\n",p[n+i]);
            //}
            n+= p[n];
			break;
		}
	}// while()
}

/*** end of dump_descriptor.c ********************************************/


