DecodeVideoInterfaceDescriptor.m [plain text]
/*
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
//
// DecodeVideoInterfaceDescriptor.m
// IOUSBFamily
//
// Created by Fernando Urbina on Tue Apr 15 2003.
// Copyright (c) 2003 __MyCompanyName__. All rights reserved.
//
#import "DecodeVideoInterfaceDescriptor.h"
@implementation DecodeVideoInterfaceDescriptor
+(void)DecodeVideoInterfaceDescriptor:(UInt8 *)descriptor deviceIntf:(IOUSBDeviceInterface **)deviceIntf forDevice:(UInt16)deviceNumber atDepth:(UInt16)depth forNode:(Node *)node subClass:(UInt8)interfaceSubClass;
{
static unsigned char buf[256];
static unsigned char buf2[256];
auto IOUSBVCInterfaceDescriptor * pVideoControlHeader;
auto IOUSBVCInputTerminalDescriptor * pVideoInTermDesc;
auto IOUSBVCCameraTerminalDescriptor * pCameraTermDesc;
auto IOUSBVCOutputTerminalDescriptor * pVideoOutTermDesc;
auto IOUSBVCSelectorUnitDescriptor * pSelectorUnitDesc = NULL;
auto IOUSBVCSelectorUnit2Descriptor * pSelectorUnit2Desc;
auto IOUSBVCProcessingUnitDescriptor * pProcessingUnitDesc;
auto IOUSBVCProcessingUnit2Descriptor * pProcessingUnit2Desc;
auto IOUSBVCExtensionUnitDescriptor * pExtensionUnitDesc;
auto IOUSBVCExtensionUnit2Descriptor * pExtensionUnit2Desc;
auto IOUSBVCExtensionUnit3Descriptor * pExtensionUnit3Desc;
auto IOUSBVCInterruptEndpointDescriptor * pVCInterruptEndpintDesc;
auto IOUSBVSInputHeaderDescriptor * pVSInputHeaderDesc;
auto IOUSBVSOutputHeaderDescriptor * pVSOutputHeaderDesc;
auto IOUSBVDC_MJPEGFormatDescriptor * pMJPEGFormatDesc;
auto IOUSBVDC_MJPEGFrameDescriptor * pMJPEGFrameDesc;
auto IOUSBVDC_MJPEGDiscreteFrameDescriptor * pMJPEGDiscreteFrameDesc;
UInt16 i;
UInt8 *p;
UInt32 *t;
char *s = NULL;
GenericAudioDescriptorPtr desc = (GenericAudioDescriptorPtr) descriptor;
UInt64 uuidHI;
UInt64 uuidLO;
char str[256];
if ( ((GenericAudioDescriptorPtr)desc)->descType == CS_ENDPOINT )
{
pVCInterruptEndpintDesc = (IOUSBVCInterruptEndpointDescriptor *)desc;
switch ( pVCInterruptEndpintDesc->bDescriptorSubType )
{
case EP_INTERRUPT:
sprintf((char *)buf, "VDC Specific Interrupt Endpoint");
break;
default:
sprintf((char *)buf, "Unknown Endpoint SubType Descriptor");
}
[self PrintKeyVal:buf val:"" forDevice:deviceNumber atDepth:depth forNode:node];
// Print the Length and contents of this class-specific descriptor
//
sprintf(str, " [self PrintKeyVal:"Length (and contents):" val:str forDevice:deviceNumber atDepth:depth+1 forNode:node];
[BusProbeClass DumpRawDescriptor:(Byte*)desc forDevice:deviceNumber atDepth:depth+2];
sprintf((char *)buf, " [self PrintKeyVal:"Max Transfer Size:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
return;
}
if ( ((GenericAudioDescriptorPtr)desc)->descType != CS_INTERFACE )
return;
if( SC_VIDEOCONTROL == interfaceSubClass )
{
switch ( ((GenericAudioDescriptorPtr)desc)->descSubType )
{
case VC_DESCRIPTOR_UNDEFINED:
sprintf((char *)buf, "Video Control Class Unknown Header");
break;
case VC_HEADER:
sprintf((char *)buf, "VDC (Control) Header");
break;
case VC_INPUT_TERMINAL:
sprintf((char *)buf, "VDC (Control) Input Terminal");
break;
case VC_OUTPUT_TERMINAL:
sprintf((char *)buf, "VDC (Control) Output Terminal");
break;
case VC_SELECTOR_UNIT:
sprintf((char *)buf, "VDC (Control) Selector Unit");
break;
case VC_PROCESSING_UNIT:
sprintf((char *)buf, "VDC (Control) Processing Unit");
break;
case VC_EXTENSION_UNIT:
sprintf((char *)buf, "VDC (Control) Extension Unit");
break;
default:
sprintf((char *)buf, "Unknown SC_VIDEOCONTROL SubType Descriptor");
}
}
else if( SC_VIDEOSTREAMING == interfaceSubClass )
{
switch ( ((GenericAudioDescriptorPtr)desc)->descSubType )
{
case VS_UNDEFINED:
sprintf((char *)buf, "VDC (Streaming) Unknown Header");
break;
case VS_INPUT_HEADER:
sprintf((char *)buf, "VDC (Streaming) Input Header");
break;
case VS_OUTPUT_HEADER:
sprintf((char *)buf, "VDC (Streaming) Output Header");
break;
case VS_STILL_IMAGE_FRAME:
sprintf((char *)buf, "VDC (Streaming) Still Image Frame Descriptor");
break;
case VS_FORMAT_UNCOMPRESSED:
sprintf((char *)buf, "VDC (Streaming) Uncompressed Format Descriptor");
break;
case VS_FRAME_UNCOMPRESSED:
sprintf((char *)buf, "VDC (Streaming) Uncompressed Frame Descriptor");
break;
case VS_FORMAT_MJPEG:
sprintf((char *)buf, "VDC (Streaming) MJPEG Format Descriptor");
break;
case VS_FRAME_MJPEG:
sprintf((char *)buf, "VDC (Streaming) MJPEG Frame Descriptor");
break;
case VS_FORMAT_MPEG1:
sprintf((char *)buf, "VDC (Streaming) MPEG1 Format Descriptor");
break;
case VS_FORMAT_MPEG2PS:
sprintf((char *)buf, "VDC (Streaming) MPEG2-PS Format Descriptor");
break;
case VS_FORMAT_MPEG2TS:
sprintf((char *)buf, "VDC (Streaming) MPEG2-TS Format Descriptor");
break;
case VS_FORMAT_MPEG4SL:
sprintf((char *)buf, "VDC (Streaming) MPEG4-SL Format Descriptor");
break;
case VS_FORMAT_DV:
sprintf((char *)buf, "VDC (Streaming) DV Format Descriptor");
break;
default:
sprintf((char *)buf, "Uknown SC_VIDEOSTREAMING SubType Descriptor");
}
}
else
sprintf((char *)buf, "Unknown VDC Interface Subclass Type");
[self PrintKeyVal:buf val:"" forDevice:deviceNumber atDepth:depth forNode:node];
// Print the Length and contents of this class-specific descriptor
//
sprintf(str, " [self PrintKeyVal:"Length (and contents):" val:str forDevice:deviceNumber atDepth:depth+1 forNode:node];
[BusProbeClass DumpRawDescriptor:(Byte*)desc forDevice:deviceNumber atDepth:depth+2];
if( SC_VIDEOCONTROL == interfaceSubClass ) // Video Control Subclass
{
switch ( ((GenericAudioDescriptorPtr)desc)->descSubType )
{
case VC_HEADER:
pVideoControlHeader = (IOUSBVCInterfaceDescriptor *)desc;
i = Swap16(&pVideoControlHeader->bcdVDC);
sprintf((char *)buf, " (i>>12)&0x000f, (i>>8)&0x000f, (i>>4)&0x000f, MapNumberToVersion((i>>0)&0x000f));
[self PrintKeyVal:"Specification Version Number:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
sprintf((char *)buf, "
sprintf((char *)buf, " [self PrintKeyVal:"Device Clock Frequency (Hz):" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
sprintf((char *)buf, " [self PrintKeyVal:"Number of Video Streaming Interfaces:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
// Haven't seen this array filled with more than 1 yet.
//
for (i = 0, p = &pVideoControlHeader->baInterfaceNr[0]; i < pVideoControlHeader->bInCollection; i++, p++ )
{
sprintf((char *)buf, " [self PrintKeyVal:"Video Interface Number:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
}
break;
case VC_INPUT_TERMINAL:
pVideoInTermDesc = (IOUSBVCInputTerminalDescriptor *)desc;
sprintf((char *)buf, " [self PrintKeyVal:"Terminal ID" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
switch ( Swap16(&pVideoInTermDesc->wTerminalType) )
{
case TT_VENDOR_SPECIFIC: s="USB vendor specific"; break;
case TT_STREAMING: s="USB streaming"; break;
case ITT_VENDOR_SPECIFIC: s="Vendor Specific Input Terminal"; break;
case ITT_CAMERA: s="Camera Sensor"; break;
case ITT_MEDIA_TRANSPORT_UNIT: s="Sequential Media"; break;
default: s="Invalid Input Terminal Type";
}
sprintf((char *)buf, "0x [self PrintKeyVal:"Input Terminal Type:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
if( !pVideoInTermDesc->bAssocTerminal )
sprintf((char *)buf, " else
sprintf((char *)buf, "
[self PrintKeyVal:"Input Terminal ID:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
if( !pVideoInTermDesc->iTerminal )
{
sprintf((char *)buf, " [self PrintKeyVal:"Input Terminal String Index:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
}
else
{
[BusProbeClass PrintStr:deviceIntf name:"Input Terminal String:" strIndex:(UInt8)pVideoInTermDesc->iTerminal forDevice:deviceNumber atDepth:depth+1];
}
if ( ITT_CAMERA == pVideoInTermDesc->wTerminalType )
{
pCameraTermDesc = (IOUSBVCCameraTerminalDescriptor *)desc;
sprintf((char *)buf, " [self PrintKeyVal:"Minimum Focal Length" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
sprintf((char *)buf, " [self PrintKeyVal:"Maximum Focal Length" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
sprintf((char *)buf, " [self PrintKeyVal:"Ocular Focal Length" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
if ( pCameraTermDesc->bControlSize != 0 )
{
sprintf((char *)buf, "Description");
[self PrintKeyVal:"Controls Supported" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
}
strcpy((char *)buf, "");
for (i = 0, p = &pCameraTermDesc->bmControls[0]; i < pCameraTermDesc->bControlSize; i++, p++ )
{
// For 0.8, only 18 bits are defined:
//
if ( i > 2 )
{
sprintf((char *)buf, "Unknown");
[self PrintKeyVal:"" val:buf forDevice:deviceNumber atDepth:depth+2 forNode:node];
break;
}
if ( (*p) & (1 << 0) )
{
if ( i == 0 ) sprintf((char *)buf, "Scanning Mode");
else if ( i == 1 ) sprintf((char *)buf, "Iris (Relative)");
else if ( i == 2 ) sprintf((char *)buf, "Iris (Relative)");
if ( strcmp(buf,"") )
[self PrintKeyVal:"" val:buf forDevice:deviceNumber atDepth:depth+2 forNode:node];
}
if ( (*p) & (1 << 1) )
{
if ( i == 0 ) sprintf((char *)buf, "Auto Exposure Mode");
else if ( i == 1 ) sprintf((char *)buf, "Zoom (Absolute)");
else if ( i == 2 ) sprintf((char *)buf, "Tilt (Relative)");
if ( strcmp(buf,"") )
[self PrintKeyVal:"" val:buf forDevice:deviceNumber atDepth:depth+2 forNode:node];
}
if ( (*p) & (1 << 2) )
{
if ( i == 0 ) sprintf((char *)buf, "Auto Exposure Priority");
else if ( i == 1 ) sprintf((char *)buf, "Zoom (Relative)");
else if ( i == 2 ) sprintf((char *)buf, "Focus, Auto");
if ( strcmp(buf,"") )
[self PrintKeyVal:"" val:buf forDevice:deviceNumber atDepth:depth+2 forNode:node];
}
if ( (*p) & (1 << 3) )
{
if ( i == 0 ) sprintf((char *)buf, "Exposure Time (Absolute)");
else if ( i == 1 ) sprintf((char *)buf, "Pan (Absolute)");
else if ( i == 2 ) sprintf((char *)buf, "Unknown");
if ( strcmp(buf,"") )
[self PrintKeyVal:"" val:buf forDevice:deviceNumber atDepth:depth+2 forNode:node];
}
if ( (*p) & (1 << 4) )
{
if ( i == 0 ) sprintf((char *)buf, "Exposure Time (Relative)");
else if ( i == 1 ) sprintf((char *)buf, "Pan (Relative)");
else if ( i == 2 ) sprintf((char *)buf, "Unknown");
if ( strcmp(buf,"") )
[self PrintKeyVal:"" val:buf forDevice:deviceNumber atDepth:depth+2 forNode:node];
}
if ( (*p) & (1 << 5) )
{
if ( i == 0 ) sprintf((char *)buf, "Focus (Absolute)");
else if ( i == 1 ) sprintf((char *)buf, "Roll (Absolute)");
else if ( i == 2 ) sprintf((char *)buf, "Unknown");
if ( strcmp(buf,"") )
[self PrintKeyVal:"" val:buf forDevice:deviceNumber atDepth:depth+2 forNode:node];
}
if ( (*p) & (1 << 6) )
{
if ( i == 0 ) sprintf((char *)buf, "Focus (Relative)");
else if ( i == 1 ) sprintf((char *)buf, "Roll (Relative)");
else if ( i == 2 ) sprintf((char *)buf, "Unknown");
if ( strcmp(buf,"") )
[self PrintKeyVal:"" val:buf forDevice:deviceNumber atDepth:depth+2 forNode:node];
}
if ( (*p) & (1 << 7) )
{
if ( i == 0 ) sprintf((char *)buf, "Iris (Absolute)");
else if ( i == 1 ) sprintf((char *)buf, "Tilt (Absolute)");
else if ( i == 2 ) sprintf((char *)buf, "Unknown");
if ( strcmp(buf,"") )
[self PrintKeyVal:"" val:buf forDevice:deviceNumber atDepth:depth+2 forNode:node];
}
}
}
break;
case VC_OUTPUT_TERMINAL:
pVideoOutTermDesc = (IOUSBVCOutputTerminalDescriptor *)desc;
sprintf((char *)buf, " [self PrintKeyVal:"Terminal ID:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
switch ( Swap16(&pVideoOutTermDesc->wTerminalType) )
{
case TT_VENDOR_SPECIFIC: s="USB vendor specific"; break;
case TT_STREAMING: s="USB streaming"; break;
case OTT_VENDOR_SPECIFIC: s="USB vendor specific"; break;
case OTT_DISPLAY: s="Generic Display"; break;
case OTT_MEDIA_TRANSPORT_OUTPUT: s="Sequential Media Output Terminal"; break;
default: s="Invalid Output Terminal Type";
}
sprintf((char *)buf, "0x [self PrintKeyVal:"Output Terminal Type:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
if( !pVideoOutTermDesc->bAssocTerminal )
sprintf((char *)buf, " else
sprintf((char *)buf, "
[self PrintKeyVal:"Output Terminal ID:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
if( !pVideoOutTermDesc->iTerminal )
{
sprintf((char *)buf, " [self PrintKeyVal:"Output Terminal String Index:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
}
else
{
[BusProbeClass PrintStr:deviceIntf name:"Output Terminal String:" strIndex:(UInt8)pVideoOutTermDesc->iTerminal forDevice:deviceNumber atDepth:depth+1];
}
break;
case VC_SELECTOR_UNIT:
pSelectorUnitDesc = (IOUSBVCSelectorUnitDescriptor *)desc;
sprintf((char *)buf, " [self PrintKeyVal:"Unit ID:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
sprintf((char *)buf, " [self PrintKeyVal:"Number of pins:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
//
for (i = 0, p = &pSelectorUnitDesc->baSourceID[0]; i < pSelectorUnitDesc->bNrInPins; i++, p++ )
{
sprintf((char *)buf2, "Source ID Pin[ sprintf((char *)buf, " [self PrintKeyVal:buf2 val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
}
// Now, p will point to the IOUSBVCSelectorUnit2Descriptor
//
pSelectorUnit2Desc = (IOUSBVCSelectorUnit2Descriptor *) p;
if( !pSelectorUnit2Desc->iSelector )
{
sprintf((char *)buf, " [self PrintKeyVal:"Selector Unit String Index:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
}
else
{
[BusProbeClass PrintStr:deviceIntf name:"Selector Unit String:" strIndex:(UInt8)pSelectorUnit2Desc->iSelector forDevice:deviceNumber atDepth:depth+1];
}
break;
case VC_PROCESSING_UNIT:
pProcessingUnitDesc = ( IOUSBVCProcessingUnitDescriptor *) desc;
sprintf((char *)buf, " [self PrintKeyVal:"Unit ID:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
sprintf((char *)buf, " [self PrintKeyVal:"Source ID:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
sprintf((char *)buf, " [self PrintKeyVal:"Digital Multiplier (100X):" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
if ( pProcessingUnitDesc->bControlSize != 0 )
{
sprintf((char *)buf, "Description");
[self PrintKeyVal:"Controls Supported" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
}
strcpy((char *)buf, "");
for (i = 0, p = &pProcessingUnitDesc->bmControls[0]; i < pProcessingUnitDesc->bControlSize; i++, p++ )
{
// For 0.8, only 16 bits are defined:
//
if ( i > 1 )
{
sprintf((char *)buf, "Unknown");
[self PrintKeyVal:"" val:buf forDevice:deviceNumber atDepth:depth+2 forNode:node];
break;
}
if ( (*p) & (1 << 0) )
{
if ( i == 0 ) sprintf((char *)buf, "Brightness");
else if ( i == 1 ) sprintf((char *)buf, "Backlight Compensation");
if ( strcmp(buf,"") )
[self PrintKeyVal:"" val:buf forDevice:deviceNumber atDepth:depth+2 forNode:node];
}
if ( (*p) & (1 << 1) )
{
if ( i == 0 ) sprintf((char *)buf, "Contrast");
else if ( i == 1 ) sprintf((char *)buf, "Gain");
if ( strcmp(buf,"") )
[self PrintKeyVal:"" val:buf forDevice:deviceNumber atDepth:depth+2 forNode:node];
}
if ( (*p) & (1 << 2) )
{
if ( i == 0 ) sprintf((char *)buf, "Hue");
else if ( i == 1 ) sprintf((char *)buf, "Power Line Frequency");
if ( strcmp(buf,"") )
[self PrintKeyVal:"" val:buf forDevice:deviceNumber atDepth:depth+2 forNode:node];
}
if ( (*p) & (1 << 3) )
{
if ( i == 0 ) sprintf((char *)buf, "Saturation");
else if ( i == 1 ) sprintf((char *)buf, "Hue, Auto");
if ( strcmp(buf,"") )
[self PrintKeyVal:"" val:buf forDevice:deviceNumber atDepth:depth+2 forNode:node];
}
if ( (*p) & (1 << 4) )
{
if ( i == 0 ) sprintf((char *)buf, "Sharpness");
else if ( i == 1 ) sprintf((char *)buf, "White Balance Temperature, Auto");
if ( strcmp(buf,"") )
[self PrintKeyVal:"" val:buf forDevice:deviceNumber atDepth:depth+2 forNode:node];
}
if ( (*p) & (1 << 5) )
{
if ( i == 0 ) sprintf((char *)buf, "Gamma");
else if ( i == 1 ) sprintf((char *)buf, "White Balance Component, Auto");
if ( strcmp(buf,"") )
[self PrintKeyVal:"" val:buf forDevice:deviceNumber atDepth:depth+2 forNode:node];
}
if ( (*p) & (1 << 6) )
{
if ( i == 0 ) sprintf((char *)buf, "White Balance Temperature");
else if ( i == 1 ) sprintf((char *)buf, "Digital Multiplier");
if ( strcmp(buf,"") )
[self PrintKeyVal:"" val:buf forDevice:deviceNumber atDepth:depth+2 forNode:node];
}
if ( (*p) & (1 << 7) )
{
if ( i == 0 ) sprintf((char *)buf, "White Balance Component");
else if ( i == 1 ) sprintf((char *)buf, "Digital Multiplier Limit");
if ( strcmp(buf,"") )
[self PrintKeyVal:"" val:buf forDevice:deviceNumber atDepth:depth+2 forNode:node];
}
}
// At this point, p should be pointing to the iProcessing field:
pProcessingUnit2Desc = (IOUSBVCProcessingUnit2Descriptor *) p;
if( !pProcessingUnit2Desc->iProcessing )
{
sprintf((char *)buf, " [self PrintKeyVal:"Processing Unit String Index:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
}
else
{
[BusProbeClass PrintStr:deviceIntf name:"Selector Unit String:" strIndex:(UInt8)pProcessingUnit2Desc->iProcessing forDevice:deviceNumber atDepth:depth+1];
}
break;
case VC_EXTENSION_UNIT:
pExtensionUnitDesc = (IOUSBVCExtensionUnitDescriptor *)desc;
sprintf((char *)buf, " [self PrintKeyVal:"Unit ID:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
uuidHI = Swap64(&pExtensionUnitDesc->guidExtensionCodeHi);
uuidLO = Swap64(&pExtensionUnitDesc->guidExtensionCodeLo);
sprintf((char *)buf, " [self PrintKeyVal:"Vendor UUID:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
sprintf((char *)buf, " [self PrintKeyVal:"Number of Controls:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
sprintf((char *)buf, " [self PrintKeyVal:"Number of In pins:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
for (i = 0, p = &pExtensionUnitDesc->baSourceID[0]; i < pSelectorUnitDesc->bNrInPins; i++, p++ )
{
sprintf((char *)buf2, "Source ID Pin[ sprintf((char *)buf, " [self PrintKeyVal:buf2 val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
}
// Now, p points to the rest of the Extension Unit descriptor:
//
pExtensionUnit2Desc = ( IOUSBVCExtensionUnit2Descriptor *) p;
if ( pExtensionUnit2Desc->bControlSize != 0 )
{
sprintf((char *)buf, "Description");
[self PrintKeyVal:"Controls Supported" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
}
strcpy((char *)buf, "");
for (i = 0, p = &pExtensionUnit2Desc->bmControls[0]; i < pExtensionUnit2Desc->bControlSize; i++, p++ )
{
// For 0.8, only 1 bits is defined:
//
if ( i == 0 )
{
if ( (*p) & 0x01)
{
sprintf((char *)buf, "Enable Processing");
[self PrintKeyVal:"" val:buf forDevice:deviceNumber atDepth:depth+2 forNode:node];
}
if ( (*p) & 0xfe)
{
sprintf((char *)buf, "Using Reserved Bit!");
[self PrintKeyVal:"" val:buf forDevice:deviceNumber atDepth:depth+2 forNode:node];
}
}
else
if ( i > 1 )
{
sprintf((char *)buf, "Vendor Specific 0x [self PrintKeyVal:"" val:buf forDevice:deviceNumber atDepth:depth+2 forNode:node];
break;
}
}
// At this point, p should be pointing to the iProcessing field:
pExtensionUnit3Desc = ( IOUSBVCExtensionUnit3Descriptor *) p;
if( !pExtensionUnit3Desc->iExtension )
{
sprintf((char *)buf, " [self PrintKeyVal:"Processing Unit String Index:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
}
else
{
[BusProbeClass PrintStr:deviceIntf name:"Selector Unit String:" strIndex:(UInt8)pExtensionUnit3Desc->iExtension forDevice:deviceNumber atDepth:depth+1];
}
break;
case VC_DESCRIPTOR_UNDEFINED:
default:
[self PrintKeyVal:"Undefined Descriptor:" val:"" forDevice:deviceNumber atDepth:depth+1 forNode:node];
}
}
else if( SC_VIDEOSTREAMING == interfaceSubClass ) // Video Streaming Subclass
{
switch ( ((GenericAudioDescriptorPtr)desc)->descSubType )
{
case VS_INPUT_HEADER:
pVSInputHeaderDesc = (IOUSBVSInputHeaderDescriptor *)desc;
sprintf((char *)buf, " [self PrintKeyVal:"Number of Formats:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
sprintf((char *)buf, " [self PrintKeyVal:"Total Length of Descriptor:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
sprintf((char *)buf, "0x [self PrintKeyVal:"Endpoint Address:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
sprintf((char *)buf, "Capabilities (0x [self PrintKeyVal:buf val:"Description" forDevice:deviceNumber atDepth:depth+1 forNode:node];
if (pVSInputHeaderDesc->bmInfo & 0x01)
[self PrintKeyVal:"" val:"Dynamic Format Change supported" forDevice:deviceNumber atDepth:depth+2 forNode:node];
if ( pVSInputHeaderDesc->bmInfo & 0xfe)
[self PrintKeyVal:"" val:"Unknown capabilities" forDevice:deviceNumber atDepth:depth+2 forNode:node];
sprintf((char *)buf, " [self PrintKeyVal:"Terminal ID of Output Terminal:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
switch (pVSInputHeaderDesc->bTerminalLink)
{
case 0: s = "None"; break;
case 1: s = "Method 1"; break;
case 2: s = "Method 2"; break;
case 3: s = "Method 3"; break;
default: s = "Unknown Method";
}
sprintf((char *)buf, " [self PrintKeyVal:"Still Capture Method:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
break;
case VS_OUTPUT_HEADER:
pVSOutputHeaderDesc = (IOUSBVSOutputHeaderDescriptor *)desc;
sprintf((char *)buf, " [self PrintKeyVal:"Number of Formats:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
sprintf((char *)buf, " [self PrintKeyVal:"Total Length of Descriptor:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
sprintf((char *)buf, "0x [self PrintKeyVal:"Endpoint Address:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
sprintf((char *)buf, " [self PrintKeyVal:"Terminal ID of Output Terminal:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
break;
case VS_FORMAT_MJPEG:
pMJPEGFormatDesc = (IOUSBVDC_MJPEGFormatDescriptor *)desc;
sprintf((char *)buf, " [self PrintKeyVal:"Format Index:" val:buf forDevice:deviceNumber atDepth:depth+2 forNode:node];
sprintf((char *)buf, " [self PrintKeyVal:"Number of Frame Descriptors:" val:buf forDevice:deviceNumber atDepth:depth+2 forNode:node];
sprintf((char *)buf, "(0x [self PrintKeyVal:"Characteristics " val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
if (pMJPEGFormatDesc->bmFlags & 0x01)
[self PrintKeyVal:"" val:"Fixed Sample Sizes Supported" forDevice:deviceNumber atDepth:depth+2 forNode:node];
if ( pMJPEGFormatDesc->bmFlags & 0xfe)
[self PrintKeyVal:"" val:"Unknown characteristics" forDevice:deviceNumber atDepth:depth+2 forNode:node];
//sprintf((char *)buf, " //[self PrintKeyVal:"Bits per pixel in frame:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
sprintf((char *)buf, " [self PrintKeyVal:"Optimum Frame Index:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
sprintf((char *)buf, " [self PrintKeyVal:"X Aspect Ratio:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
sprintf((char *)buf, " [self PrintKeyVal:"Y Aspect Ratio:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
sprintf((char *)buf, "(0x [self PrintKeyVal:"Interlace Flags" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
if (pMJPEGFormatDesc->bmInterlaceFlags & 0x01)
[self PrintKeyVal:"Interlaced Stream or Variable" val:"Yes" forDevice:deviceNumber atDepth:depth+2 forNode:node];
else
[self PrintKeyVal:"Interlaced Stream or Variable" val:"No" forDevice:deviceNumber atDepth:depth+2 forNode:node];
if (pMJPEGFormatDesc->bmInterlaceFlags & 0x02)
[self PrintKeyVal:"Fields per frame" val:"2" forDevice:deviceNumber atDepth:depth+2 forNode:node];
else
[self PrintKeyVal:"Fields per frame" val:"1" forDevice:deviceNumber atDepth:depth+2 forNode:node];
if (pMJPEGFormatDesc->bmInterlaceFlags & 0x04)
[self PrintKeyVal:"Field 1 first" val:"Yes" forDevice:deviceNumber atDepth:depth+2 forNode:node];
else
[self PrintKeyVal:"Field 1 first" val:"No" forDevice:deviceNumber atDepth:depth+2 forNode:node];
if (pMJPEGFormatDesc->bmInterlaceFlags & 0x08)
[self PrintKeyVal:"" val:"Reserved field used!" forDevice:deviceNumber atDepth:depth+2 forNode:node];
i = (pMJPEGFormatDesc->bmInterlaceFlags & 0x30) >> 4;
switch (i)
{
case 0: s = "Field 1 only"; break;
case 1: s = "Field 2 only"; break;
case 2: s = "Regular pattern of fields 1 and 2"; break;
case 3: s = "Random pattern of fields 1 and 2"; break;
}
sprintf((char *)buf, " [self PrintKeyVal:"Field Pattern" val:buf forDevice:deviceNumber atDepth:depth+2 forNode:node];
i = (pMJPEGFormatDesc->bmInterlaceFlags & 0xc0) >> 6;
switch (i)
{
case 0: s = "Bob only"; break;
case 1: s = "Weave only"; break;
case 2: s = "Bob or weave"; break;
case 3: s = "Unknown"; break;
}
sprintf((char *)buf, " [self PrintKeyVal:"Display Mode" val:buf forDevice:deviceNumber atDepth:depth+2 forNode:node];
if (pMJPEGFormatDesc->bCopyProtect == 1)
[self PrintKeyVal:"Duplication of Stream:" val:"Restricted" forDevice:deviceNumber atDepth:depth+1 forNode:node];
else
[self PrintKeyVal:"Duplication of Stream" val:"No Restriction" forDevice:deviceNumber atDepth:depth+1 forNode:node];
break;
case VS_FRAME_MJPEG:
pMJPEGFrameDesc = (IOUSBVDC_MJPEGFrameDescriptor *)desc;
sprintf((char *)buf, " [self PrintKeyVal:"Frame Index:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
sprintf((char *)buf, "(0x [self PrintKeyVal:"Capabilities " val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
if (pMJPEGFrameDesc->bmCapabilities & 0x01)
[self PrintKeyVal:"" val:"Still Image supported" forDevice:deviceNumber atDepth:depth+2 forNode:node];
if ( pMJPEGFrameDesc->bmCapabilities & 0xfe)
[self PrintKeyVal:"" val:"Unknown capabilities" forDevice:deviceNumber atDepth:depth+2 forNode:node];
sprintf((char *)buf, " [self PrintKeyVal:"Width:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
sprintf((char *)buf, " [self PrintKeyVal:"Height:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
sprintf((char *)buf, " [self PrintKeyVal:"Minimum Bit Rate (bps):" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
sprintf((char *)buf, " [self PrintKeyVal:"Maximum Bit Rate (bps):" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
//sprintf((char *)buf, " //[self PrintKeyVal:"Average Compress Ratio:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
sprintf((char *)buf, " [self PrintKeyVal:"Maximum frame buffer size (bytes):" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
sprintf((char *)buf, " [self PrintKeyVal:"Default Frame Interval:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
if (pMJPEGFrameDesc->bFrameIntervalType == 0)
{
[self PrintKeyVal:"Frame interval type:" val:"Continuous" forDevice:deviceNumber atDepth:depth+1 forNode:node];
sprintf((char *)buf, " [self PrintKeyVal:"Shortest frame interval supported:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
sprintf((char *)buf, " [self PrintKeyVal:"Longest frame interval supported:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
sprintf((char *)buf, " [self PrintKeyVal:"Frame Interval step:" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
}
else
{
// Need to recast as a IOUSBVDC_MJPEGDiscreteFrameDescriptor
//
pMJPEGDiscreteFrameDesc = (IOUSBVDC_MJPEGDiscreteFrameDescriptor *) pMJPEGFrameDesc;
sprintf((char *)buf, " [self PrintKeyVal:"Discrete Frame Intervals supported" val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
for (i = 0, t = &pMJPEGDiscreteFrameDesc->dwFrameInterval[0]; i < pMJPEGDiscreteFrameDesc->bFrameIntervalType; i++, t++ )
{
UInt32 interval = *t;
sprintf((char *)buf, " sprintf((char *)buf2, "Frame Interval for frame [self PrintKeyVal:buf2 val:buf forDevice:deviceNumber atDepth:depth+1 forNode:node];
}
}
break;
default:
sprintf((char *)buf, "AudioStreaming Subclass" );
[self PrintKeyVal:buf val:"" forDevice:deviceNumber atDepth:depth+1 forNode:node];
}
}
}
char MapNumberToVersion( int i )
{
char rev;
switch (i)
{
case 1:
rev = 'a';
break;
case 2:
rev = 'b';
break;
case 3:
rev = 'c';
break;
case 4:
rev = 'd';
break;
case 5:
rev = 'e';
break;
case 6:
rev = 'f';
break;
case 7:
rev = 'g';
break;
case 8:
rev = 'h';
break;
case 9:
rev = 'i';
break;
default:
rev = 'a';
}
return rev;
}
@end