/*
* Copyright (c) 2002 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@
*/
#import "BusProbeClass.h"
#import <stdio.h>
#import <unistd.h>
#import <CoreServices/CoreServices.h>
#import <IOKit/IOKitLib.h>
#import <IOKit/usb/IOUSBLib.h>
#import <IOKit/IOCFPlugIn.h>
#import <mach/mach_port.h>
static Node *busprobeRootNode = nil;
static NSMutableDictionary *vendorNamesDictionary = nil;
static NSMutableDictionary *videoClassDevicesDictionary = nil; // add this line
@implementation BusProbeClass
+(Node *)busprobeRootNode
{
return busprobeRootNode;
}
// ________________________________________________________________________________________________
// USBProbe
//
// Scan all USB devices
+(void)USBProbe
{
NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
CFDictionaryRef matchingDict = NULL;
mach_port_t mMasterDevicePort = NULL;
io_iterator_t devIter = NULL;
io_service_t ioDeviceObj = NULL;
int outlineViewDeviceNumber = 0; //used to iterate through devices
[busprobeRootNode clearNode];
[busprobeRootNode setItemName: @"USB Bus Devices"];
[busprobeRootNode setItemValue: NULL];
outlineViewDeviceNumber = 0;
// This gets the master device mach port through which all messages
// to the kernel go, and initiates communication with IOKit.
require_noerr(IOMasterPort(MACH_PORT_NULL, &mMasterDevicePort), errexit);
// Create matching dictionary for IOUSBDevice's
matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
require(matchingDict != NULL, errexit);
// Get device iterator
require_noerr(
IOServiceGetMatchingServices(
mMasterDevicePort,
matchingDict, // reference consumed
&devIter), errexit);
// Walk through devices
while ((ioDeviceObj = IOIteratorNext(devIter)) != NULL) {
IOCFPlugInInterface **ioPlugin;
IOUSBDeviceInterface **deviceIntf = NULL;
IOReturn kr;
SInt32 score;
UInt32 locationID;
// Get self pointer to device
require_noerr(IOCreatePlugInInterfaceForService(
ioDeviceObj, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID,
&ioPlugin, &score), nextDevice);
kr = (*ioPlugin)->QueryInterface(ioPlugin, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID *)&deviceIntf);
(*ioPlugin)->Release(ioPlugin);
ioPlugin = NULL;
require_string(kr == kIOReturnSuccess, nextDevice, "QueryInterface failed");
verify_noerr((*deviceIntf)->GetLocationID(deviceIntf, &locationID));
[self outputDevice:deviceIntf locationID:locationID deviceNumber:outlineViewDeviceNumber];
outlineViewDeviceNumber++;
nextDevice:
if (deviceIntf != NULL)
(*deviceIntf)->Release(deviceIntf);
IOObjectRelease(ioDeviceObj);
}
errexit:
if (devIter != NULL)
IOObjectRelease(devIter);
if (mMasterDevicePort)
mach_port_deallocate(mach_task_self(), mMasterDevicePort);
[pool release];
}
// ________________________________________________________________________________________________
// outputDevice
//
// Output all of a device's descriptors
+(void)outputDevice:(IOUSBDeviceInterface **)deviceIntf locationID:(UInt32)locationID deviceNumber:(int)deviceNumber
{
Node *newNode;
char str[500];
int len;
USBClass *deviceClass = NULL;
USBClass *interfaceClass = NULL;
NSString *tempString1, *tempString2, *tempString3, *tempString4;
UInt8 lastInterfaceClass = 0;
int currentInterfaceNum = 0;
UInt8 lastInterfaceSubClass = 0;
IOUSBDeviceDescriptor dev;
UInt8 speed = 0;
USBDeviceAddress address = 0;
int iconfig;
NSString *aTempString;
char tempCString[500];
// Get the connection Speed for this device
GetDeviceSpeed( deviceIntf, &speed );
// Get the connection Speed for this device
GetDeviceAddress( deviceIntf, &address );
len = GetDescriptor(deviceIntf, kUSBDeviceDesc, 0, &dev, sizeof(dev));
if (len > 0) {
Swap16(&dev.bcdUSB);
Swap16(&dev.idVendor);
Swap16(&dev.idProduct);
Swap16(&dev.bcdDevice);
// Create a new child node for this device
newNode = [[Node alloc] init];
// Set the node's name to be the device's location
[newNode setItemName:[NSString stringWithFormat:@"
[newNode setItemValue:NULL]; // since I'm not actually gathering anything yet
[busprobeRootNode addChild:newNode];
[newNode release];
[self PrintKeyVal:"Device Descriptor" val:"" forDevice:deviceNumber atDepth:DEVICE_DESCRIPTOR_LEVEL-1 forNode:busprobeRootNode];
NUM(dev, "Descriptor Version Number:", bcdUSB, deviceNumber, DEVICE_DESCRIPTOR_LEVEL, 0);
deviceClass = [self DeviceClassAndSubClass:"Device" devDescriptor:&dev forDevice:deviceNumber atDepth:1];
NUM(dev, "Device Protocol", bDeviceProtocol, deviceNumber, DEVICE_DESCRIPTOR_LEVEL, 1);
NUM(dev, "Device MaxPacketSize:", bMaxPacketSize0, deviceNumber, DEVICE_DESCRIPTOR_LEVEL, 1);
aTempString = RETURNNUM(dev, idVendor, 0);
sprintf(tempCString," aTempString = RETURNNUM(dev, idProduct, 0);
strcat(tempCString,[aTempString cString]);
tempString1 = RETURNNUM(dev, idVendor, 0);
tempString2 = RETURNNUM(dev, idProduct, 0);
tempString3 = RETURNNUM(dev, idVendor, 1);
aTempString = [NSString stringWithFormat:@"
[self PrintKeyVal:"Device VendorID/ProductID:" val:(char *)[aTempString cString] forDevice:deviceNumber atDepth:1 forNode:busprobeRootNode];
//[self PrintKeyVal:"Device VendorID/ProductID:" val:tempCString forDevice:deviceNumber atDepth:1 forNode:busprobeRootNode];
NUM(dev, "Device Version Number:", bcdDevice, deviceNumber, DEVICE_DESCRIPTOR_LEVEL, 0);
NUM(dev, "Number of Configurations:", bNumConfigurations, deviceNumber, DEVICE_DESCRIPTOR_LEVEL, 1);
STR(dev, "Manufacturer String:", iManufacturer, deviceNumber, 1);
STR(dev, "Product String:", iProduct, deviceNumber, 1);
STR(dev, "Serial Number String:", iSerialNumber, deviceNumber, 1);
// Add the string for the kind of device that it is. We look at the class of the device
// and then add the product name. If the product name is blank (iProduct is 0), then we
// put the vendor name from the database in the string
//
// Examples:
//
// Composite Device: "Apple Extended USB Keyboard"
// Hub device from Atmel Corporation
// Vendor-specific device from unknown vendor
//
tempString1 = [deviceClass className];
// If our subclass name is different than our class name, then add the sub class to the description
// following a "/"
//
if( ! [[deviceClass subClassName] isEqualToString:@""] &&
! [[deviceClass subClassName] isEqualToString:[deviceClass className]] ) {
tempString1 = [[tempString1 stringByAppendingString:@"/"] stringByAppendingString:[deviceClass subClassName]];
}
tempString2 = RETURNSTR(dev, iProduct);
tempString3 = [tempString1 stringByAppendingString:@" device: "];
tempString4 = RETURNNUM(dev, idVendor, 1);
if ([tempString2 isEqualToString:@"0x00"])
{
tempString2 = [NSString stringWithFormat:@" if ([tempString2 isEqualToString:@"0x00"])
tempString2 = @"(unnamed)";
else
tempString3 = [tempString1 stringByAppendingString:@" device from "];
}
[[busprobeRootNode childAtIndex:deviceNumber] setItemValue:[tempString3 stringByAppendingString:tempString2]];
for (iconfig = 0; iconfig < dev.bNumConfigurations; ++iconfig) {
IOUSBConfigurationDescriptor cfg;
len = GetDescriptor(deviceIntf, kUSBConfDesc, iconfig, &cfg, sizeof(cfg));
if (len > 0) {
/* struct IOUSBConfigurationDescriptor {
UInt8 bLength;
UInt8 bDescriptorType;
UInt16 wTotalLength;
UInt8 bNumInterfaces;
UInt8 bConfigurationValue;
UInt8 iConfiguration;
UInt8 bmAttributes;
UInt8 MaxPower;
}; */
Byte *configBuf;
Byte *p, *pend;
char configHeading[500];
aTempString = RETURNSTR(cfg, iConfiguration);
if (strcmp([aTempString cString], "0x00") != 0) {
sprintf(configHeading, "Configuration Descriptor: .......................................");
sprintf(tempCString, [aTempString cString]);
[self PrintKeyVal:configHeading val:tempCString forDevice:deviceNumber atDepth:CONFIGURATION_DESCRIPTOR_LEVEL-1 forNode:busprobeRootNode];
}
else {
sprintf(configHeading, "Configuration Descriptor");
[self PrintKeyVal:configHeading val:"" forDevice:deviceNumber atDepth:CONFIGURATION_DESCRIPTOR_LEVEL-1 forNode:busprobeRootNode];
}
Swap16(&cfg.wTotalLength);
NUM(cfg, "Total Length of Descriptor:", wTotalLength, deviceNumber, CONFIGURATION_DESCRIPTOR_LEVEL, 1);
NUM(cfg, "Number of Interfaces:", bNumInterfaces, deviceNumber, CONFIGURATION_DESCRIPTOR_LEVEL, 1);
NUM(cfg, "Configuration Value:", bConfigurationValue, deviceNumber, CONFIGURATION_DESCRIPTOR_LEVEL, 1);
sprintf(str, "0x if (cfg.bmAttributes & 0x40) {
strcat(str, " (self-powered");
}
else {
strcat(str, " (bus-powered");
}
if (cfg.bmAttributes & 0x20) {
strcat(str, ", remote wakeup");
}
strcat(str, ")");
[self PrintKeyVal:"Attributes:" val:str forDevice:deviceNumber atDepth:CONFIGURATION_DESCRIPTOR_LEVEL forNode:busprobeRootNode];
aTempString = RETURNNUM(cfg, MaxPower, 1);
sprintf(tempCString, " [self PrintKeyVal:"MaxPower:" val:tempCString forDevice:deviceNumber atDepth:CONFIGURATION_DESCRIPTOR_LEVEL forNode:busprobeRootNode];
configBuf = malloc(cfg.wTotalLength*sizeof(Byte));
if ( GetDescriptor(deviceIntf, kUSBConfDesc, iconfig, configBuf, cfg.wTotalLength) < 0 )
continue;
p = configBuf;
pend = p + cfg.wTotalLength;
p += cfg.bLength;
// Dump the descriptors in the Configuration Descriptor
//
while (p < pend)
{
UInt8 descLen = p[0];
UInt8 descType = p[1];
// If this is an interface descriptor, save the interface class and subclass
//
if ( descType == kUSBInterfaceDesc )
{
lastInterfaceClass = ((IOUSBInterfaceDescriptor *)p)->bInterfaceClass;
lastInterfaceSubClass = ((IOUSBInterfaceDescriptor *)p)->bInterfaceSubClass;
currentInterfaceNum = (int) ((IOUSBInterfaceDescriptor *)p)->bInterfaceNumber;
}
[self DumpDescriptor:deviceIntf dev:dev p:p forDevice:deviceNumber lastInterfaceClass:lastInterfaceClass lastInterfaceSubClass:lastInterfaceSubClass currentInterfaceNum:currentInterfaceNum];
p += descLen;
}
}
}
}
else
{
// Create a new child node for this device
newNode = [[Node alloc] init];
//[newNode setItemName:[NSString stringWithFormat:@"USB device @ 0x [newNode setItemName:[NSString stringWithFormat:@"
[newNode setItemValue: @"Unknown device (did not respond do inquiry)"];
[busprobeRootNode addChild:newNode];
[newNode release];
}
// If the device is a hub, then dump the Hub descriptor
//
if ( dev.bDeviceClass == kUSBHubClass )
{
IOUSBHubDescriptor cfg;
len = GetClassDescriptor(deviceIntf, kUSBHUBDesc, 0, &cfg, sizeof(cfg));
if (len > 0)
{
[self DumpDescriptor:deviceIntf dev:dev p:(Byte *)&cfg forDevice:deviceNumber lastInterfaceClass:lastInterfaceClass lastInterfaceSubClass:lastInterfaceSubClass currentInterfaceNum:currentInterfaceNum];
}
}
// Check to see if the device has the "Device Qualifier" descriptor
//
IOUSBDeviceQualifierDescriptor desc;
if ( dev.bcdUSB >= 0x0200 )
{
len = GetDescriptor(deviceIntf, kUSBDeviceQualifierDesc, 0, &desc, sizeof(desc));
if ( len > 0)
{
[self DumpDescriptor:deviceIntf dev:dev p:(Byte *)&desc forDevice:deviceNumber lastInterfaceClass:lastInterfaceClass lastInterfaceSubClass:lastInterfaceSubClass currentInterfaceNum:currentInterfaceNum];
// Since we have a Device Qualifier Descriptor, we can get a "Other Speed Configuration Descriptor" (It's the same as a
// regular configuration descriptor)
//
for (iconfig = 0; iconfig < desc.bNumConfigurations; ++iconfig)
{
IOUSBConfigurationDescriptor cfg;
len = GetDescriptor(deviceIntf, kUSBOtherSpeedConfDesc, iconfig, &cfg, sizeof(cfg));
if (len > 0) {
/* struct IOUSBConfigurationDescriptor {
UInt8 bLength;
UInt8 bDescriptorType;
UInt16 wTotalLength;
UInt8 bNumInterfaces;
UInt8 bConfigurationValue;
UInt8 iConfiguration;
UInt8 bmAttributes;
UInt8 MaxPower;
}; */
Byte *configBuf;
Byte *p, *pend;
char configHeading[500];
aTempString = RETURNSTR(cfg, iConfiguration);
if (strcmp([aTempString cString], "0x00") != 0) {
sprintf(configHeading, "Other Speed Configuration Descriptor: .......................................");
sprintf(tempCString, [aTempString cString]);
[self PrintKeyVal:configHeading val:tempCString forDevice:deviceNumber atDepth:CONFIGURATION_DESCRIPTOR_LEVEL-1 forNode:busprobeRootNode];
}
else {
sprintf(configHeading, "Other Speed Configuration Descriptor");
[self PrintKeyVal:configHeading val:"" forDevice:deviceNumber atDepth:CONFIGURATION_DESCRIPTOR_LEVEL-1 forNode:busprobeRootNode];
}
Swap16(&cfg.wTotalLength);
NUM(cfg, "Total Length of Descriptor:", wTotalLength, deviceNumber, CONFIGURATION_DESCRIPTOR_LEVEL, 1);
NUM(cfg, "Number of Interfaces:", bNumInterfaces, deviceNumber, CONFIGURATION_DESCRIPTOR_LEVEL, 1);
NUM(cfg, "Configuration Value:", bConfigurationValue, deviceNumber, CONFIGURATION_DESCRIPTOR_LEVEL, 1);
sprintf(str, "0x if (cfg.bmAttributes & 0x40) {
strcat(str, " (self-powered");
}
else {
strcat(str, " (bus-powered");
}
if (cfg.bmAttributes & 0x20) {
strcat(str, ", remote wakeup");
}
strcat(str, ")");
[self PrintKeyVal:"Attributes:" val:str forDevice:deviceNumber atDepth:CONFIGURATION_DESCRIPTOR_LEVEL forNode:busprobeRootNode];
aTempString = RETURNNUM(cfg, MaxPower, 1);
sprintf(tempCString, " [self PrintKeyVal:"MaxPower:" val:tempCString forDevice:deviceNumber atDepth:CONFIGURATION_DESCRIPTOR_LEVEL forNode:busprobeRootNode];
configBuf = malloc(cfg.wTotalLength*sizeof(Byte));
if ( GetDescriptor(deviceIntf, kUSBOtherSpeedConfDesc, iconfig, configBuf, cfg.wTotalLength) < 0 )
continue;
p = configBuf;
pend = p + cfg.wTotalLength;
p += cfg.bLength;
// Dump the descriptors in the Configuration Descriptor
//
while (p < pend)
{
UInt8 descLen = p[0];
UInt8 descType = p[1];
// If this is an interface descriptor, save the interface class and subclass
//
if ( descType == kUSBInterfaceDesc )
{
lastInterfaceClass = ((IOUSBInterfaceDescriptor *)p)->bInterfaceClass;
lastInterfaceSubClass = ((IOUSBInterfaceDescriptor *)p)->bInterfaceSubClass;
currentInterfaceNum = (int) ((IOUSBInterfaceDescriptor *)p)->bInterfaceNumber;
}
[self DumpDescriptor:deviceIntf dev:dev p:p forDevice:deviceNumber lastInterfaceClass:lastInterfaceClass lastInterfaceSubClass:lastInterfaceSubClass currentInterfaceNum:currentInterfaceNum];
p += descLen;
}
}
}
}
}
[deviceClass release];
[interfaceClass release];
}
int GetClassDescriptor(IOUSBDeviceInterface **deviceIntf, UInt8 descType, UInt8 descIndex, void *buf, UInt16 len)
{
IOUSBDevRequest req;
IOReturn err;
req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBClass, kUSBDevice);
req.bRequest = kUSBRqGetDescriptor;
req.wValue = (descType << 8) | descIndex;
req.wIndex = 0;
req.wLength = len;
req.pData = buf;
verify_noerr(err = (*deviceIntf)->DeviceRequest(deviceIntf, &req));
if (err) return -1;
return req.wLenDone;
}
int GetDescriptor(IOUSBDeviceInterface **deviceIntf, UInt8 descType, UInt8 descIndex, void *buf, UInt16 len)
{
IOUSBDevRequest req;
IOReturn err;
req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
req.bRequest = kUSBRqGetDescriptor;
req.wValue = (descType << 8) | descIndex;
req.wIndex = 0;
req.wLength = len;
req.pData = buf;
verify_noerr(err = (*deviceIntf)->DeviceRequest(deviceIntf, &req));
if (err)
return -1;
return req.wLenDone;
}
int GetDescriptorFromInterface(IOUSBDeviceInterface **deviceIntf, UInt8 descType, UInt8 descIndex, UInt16 wIndex, void *buf, UInt16 len)
{
IOUSBDevRequest req;
IOReturn err;
req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBInterface);
req.bRequest = kUSBRqGetDescriptor;
req.wValue = (descType << 8) | descIndex;
req.wIndex = wIndex;
req.wLength = len;
req.pData = buf;
verify_noerr(err = (*deviceIntf)->DeviceRequest(deviceIntf, &req));
if (err) return -1;
return req.wLenDone;
}
int GetDeviceSpeed( IOUSBDeviceInterface **deviceIntf, UInt8 * speed )
{
IOReturn err;
verify_noerr(err = (*deviceIntf)->GetDeviceSpeed(deviceIntf, speed));
if (err) return -1;
return 0;
}
int GetDeviceAddress( IOUSBDeviceInterface **deviceIntf, USBDeviceAddress * address )
{
IOReturn err;
verify_noerr(err = (*deviceIntf)->GetDeviceAddress(deviceIntf, address));
if (err) return -1;
return 0;
}
// ________________________________________________________________________________________________
// GetStringDescriptor
//
// Get a string descriptor from the device. First, we get the length by getting 2 bytes, and then
// we use that information to get the actual string.
//
int GetStringDescriptor(IOUSBDeviceInterface **deviceIntf, UInt8 descIndex, void *buf, UInt16 len, UInt16 lang)
{
IOUSBDevRequest req;
UInt8 desc[256]; // Max possible descriptor length
int stringLen;
IOReturn err;
if (lang == NULL) // set default langID
lang=0x0409;
req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
req.bRequest = kUSBRqGetDescriptor;
req.wValue = (kUSBStringDesc << 8) | descIndex;
req.wIndex = lang; // English
req.wLength = 2;
req.pData = &desc;
verify_noerr(err = (*deviceIntf)->DeviceRequest(deviceIntf, &req));
if ( (err != kIOReturnSuccess) && (err != kIOReturnOverrun) )
return -1;
// If the string is 0 (it happens), then just return 0 as the length
//
stringLen = desc[0];
if(stringLen == 0)
{
return 0;
}
// OK, now that we have the string length, make a request for the full length
//
req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
req.bRequest = kUSBRqGetDescriptor;
req.wValue = (kUSBStringDesc << 8) | descIndex;
req.wIndex = lang; // English
req.wLength = stringLen;
req.pData = buf;
verify_noerr(err = (*deviceIntf)->DeviceRequest(deviceIntf, &req));
return req.wLenDone;
}
+(USBClass *)DeviceClassAndSubClass:(const char *)scope devDescriptor:(IOUSBDeviceDescriptor *)devDescriptor forDevice:(int)deviceNumber atDepth:(int)depth
{
USBClass *usbc = NULL;
char *cls = "", *sub = "";
char name[500];
switch (devDescriptor->bDeviceClass)
{
case kUSBCompositeClass:
cls = "Composite";
break;
case kUSBAudioClass:
cls = "Audio";
switch (devDescriptor->bDeviceSubClass)
{
case 0x01:
sub = "Audio Control";
break;
case 0x02:
sub = "Audio Streaming";
break;
case 0x03:
sub = "MIDI Streaming";
break;
default:
sub = "Unknown";
break;
}
break;
case kUSBCommClass:
cls = "Comm";
break;
case kUSBHIDClass:
cls = "HID";
switch (devDescriptor->bDeviceSubClass)
{
case kUSBHIDBootInterfaceSubClass:
sub = "Boot Interface";
break;
default:
sub = "";
break;
}
break;
case kUSBDisplayClass:
cls = "Display";
break;
case kUSBPrintingClass:
cls = "Printing";
break;
case kUSBMassStorageClass:
cls = "Mass Storage";
switch (devDescriptor->bDeviceSubClass)
{
case kUSBMassStorageRBCSubClass: sub = "Reduced Block Commands"; break;
case kUSBMassStorageATAPISubClass: sub = "ATAPI"; break;
case kUSBMassStorageQIC157SubClass: sub = "QIC-157"; break;
case kUSBMassStorageUFISubClass: sub = "UFI"; break;
case kUSBMassStorageSFF8070iSubClass: sub = "SFF-8070i"; break;
case kUSBMassStorageSCSISubClass: sub = "SCSI"; break;
default: sub = "Unknown"; break;
}
break;
case kUSBHubClass:
cls = "Hub";
break;
case kUSBDataClass:
cls = "Data";
break;
case 0xE0:
cls = "Bluetooth Wireless Controller";
break;
case kUSBApplicationSpecificClass:
cls = "Application Specific";
switch (devDescriptor->bDeviceSubClass)
{
case kUSBDFUSubClass: sub = "Device Firmware Upgrade"; break;
case kUSBIrDABridgeSubClass: sub = "IrDA Bridge"; break;
default: sub = "Unknown"; break;
}
break;
case kUSBVendorSpecificClass:
cls = sub = "Vendor-specific";
break;
default:
cls = "Unknown";
break;
}
sprintf(name, " [self PrintNumStr:name value:devDescriptor->bDeviceClass size:1 interpret:cls forDevice:deviceNumber atDepth:depth asInt:1];
sprintf(name, " [self PrintNumStr:name value:devDescriptor->bDeviceSubClass size:1 interpret:sub forDevice:deviceNumber atDepth:depth asInt:1];
if (usbc == NULL)
{
usbc = [[USBClass alloc] init];
[usbc setClassName:[NSString stringWithCString:cls]];
[usbc setSubClassName:[NSString stringWithCString:sub]];
}
return usbc;
}
+(USBClass *)InterfaceClassAndSubClass:(const char *)scope devDescriptor:(IOUSBDeviceDescriptor *)devDescriptor intfceDescriptor:(IOUSBInterfaceDescriptor *)intfceDescriptor forDevice:(int)deviceNumber atDepth:(int)depth
{
USBClass *usbc = NULL;
char *cls = "", *sub = "";
char name[500];
UInt32 productID = devDescriptor->idProduct;
UInt32 vendorID = devDescriptor->idVendor;
switch (intfceDescriptor->bInterfaceClass)
{
case kUSBCompositeClass:
cls = "Composite";
break;
case kUSBAudioClass:
cls = "Audio";
switch (intfceDescriptor->bInterfaceSubClass)
{
case 0x01:
sub = "Audio Control";
break;
case 0x02:
sub = "Audio Streaming";
break;
case 0x03:
sub = "MIDI Streaming";
break;
default:
sub = "Unknown";
break;
}
break;
case kUSBCommClass:
cls = "Comm";
break;
case kUSBHIDClass:
cls = "HID";
switch (intfceDescriptor->bInterfaceSubClass)
{
case kUSBHIDBootInterfaceSubClass:
sub = "Boot Interface";
break;
default:
sub = "";
break;
}
break;
case kUSBDisplayClass:
cls = "Display";
break;
case kUSBPrintingClass:
cls = "Printing";
break;
case kUSBMassStorageClass:
cls = "Mass Storage";
switch (intfceDescriptor->bInterfaceSubClass)
{
case kUSBMassStorageRBCSubClass: sub = "Reduced Block Commands"; break;
case kUSBMassStorageATAPISubClass: sub = "ATAPI"; break;
case kUSBMassStorageQIC157SubClass: sub = "QIC-157"; break;
case kUSBMassStorageUFISubClass: sub = "UFI"; break;
case kUSBMassStorageSFF8070iSubClass: sub = "SFF-8070i"; break;
case kUSBMassStorageSCSISubClass: sub = "SCSI"; break;
default: sub = "Unknown"; break;
}
break;
case kUSBHubClass:
cls = "Hub";
break;
case kUSBDataClass:
cls = "Data";
break;
case 0xE0:
cls = "Bluetooth Wireless Controller";
break;
case kUSBApplicationSpecificClass:
cls = "Application Specific";
switch (intfceDescriptor->bInterfaceSubClass)
{
case kUSBDFUSubClass: sub = "Device Firmware Upgrade"; break;
case kUSBIrDABridgeSubClass: sub = "IrDA Bridge"; break;
default: sub = "Unknown"; break;
}
break;
case kUSBVendorSpecificClass:
if ( [self isInterfaceVDC:vendorID idProduct:productID ] )
{
cls = "Vendor-specific";
switch (intfceDescriptor->bInterfaceSubClass)
{
case SC_VIDEOCONTROL: sub = "Video Control"; break;
case SC_VIDEOSTREAMING: sub = "Video Streaming"; break;
default: sub = "unknown"; break;
}
}
else
cls = sub = "Vendor-specific";
break;
default:
cls = "Unknown";
break;
}
sprintf(name, " [self PrintNumStr:name value:intfceDescriptor->bInterfaceClass size:1 interpret:cls forDevice:deviceNumber atDepth:depth asInt:1];
sprintf(name, " [self PrintNumStr:name value:intfceDescriptor->bInterfaceSubClass size:1 interpret:sub forDevice:deviceNumber atDepth:depth asInt:1];
if (usbc == NULL)
{
usbc = [[USBClass alloc] init];
[usbc setClassName:[NSString stringWithCString:cls]];
[usbc setSubClassName:[NSString stringWithCString:sub]];
}
return usbc;
}
// ________________________________________________________________________________________________
// PrintDescLenAndType
//
// Print the length and type fields of a USB descriptor.
+(void)PrintDescLenAndType:(void *)desc forDevice:(int)deviceNumber atDepth:(int)depth
{
Byte *p = (Byte *)desc;
char *str;
[self printNum:"bLength" value:p[0] size:1 forDevice:(int)deviceNumber atDepth:depth asInt:0];
switch (p[1])
{
case kUSBDeviceDesc: str = "Device"; break;
case kUSBConfDesc: str = "Configuration"; break;
case kUSBStringDesc: str = "String"; break;
case kUSBInterfaceDesc: str = "Interface"; break;
case kUSBEndpointDesc: str = "Endpoint"; break;
case kUSBHIDDesc: str = "HID"; break;
case kUSBReportDesc: str = "Report"; break;
case kUSBPhysicalDesc: str = "Physical"; break;
case kUSBHUBDesc: str = "Hub"; break;
case CS_INTERFACE: str = "CS Interface"; break;
case CS_ENDPOINT: str = "CS Endpoint"; break;
default: str = "(unknown)"; break;
}
[self PrintNumStr:"bDescriptorType" value:p[1] size:1 interpret:str forDevice:(int)deviceNumber atDepth:depth asInt:0];
}
// ________________________________________________________________________________________________
// printNum
//
// Print a numeric field's name and value
+(void)printNum:(char *)name value:(UInt32)value size:(int)sizeInBytes forDevice:(int)deviceNumber atDepth:(int)depth asInt:(int)asInt
{
char format[32], valstr[32];
if (asInt==1){
sprintf(valstr, " [self PrintKeyVal:name val:valstr forDevice:deviceNumber atDepth:depth forNode:busprobeRootNode];
return;
}
else {
sprintf(format, "0x sprintf(valstr, format, value);
[self PrintKeyVal:name val:valstr forDevice:deviceNumber atDepth:depth forNode:busprobeRootNode];
return;
}
}
// ________________________________________________________________________________________________
// returnNum
//
// Print a numeric field's name and value
+(NSString *)returnNum:(UInt32)value size:(int)sizeInBytes asInt:(int)asInt
{
char format[32], valstr[32];
if (asInt==1){
sprintf(valstr, " return [NSString stringWithCString:valstr];
}
else {
sprintf(format, "0x sprintf(valstr, format, value);
return [NSString stringWithCString:valstr];
}
}
// ________________________________________________________________________________________________
// PrintNumStr
//
// Print a numeric field's name, value, and interpretation
+(void)PrintNumStr:(char *)name value:(UInt32)value size:(int)sizeInBytes interpret:(char *)interpret forDevice:(int)deviceNumber atDepth:(int)depth asInt:(int)asInt
{
char format[32], valstr[256];
if (asInt==1) {
if (strcmp(interpret,"")==0)
sprintf(valstr, " else
sprintf(valstr, " }
else {
if (strcmp(interpret,"")==0)
sprintf(format, "0x else
sprintf(format, "0x sprintf(valstr, format, value, interpret);
}
[self PrintKeyVal:name val:valstr forDevice:deviceNumber atDepth:depth forNode:busprobeRootNode];
}
UInt16 Swap16(void *p)
{
* (UInt16 *) p = CFSwapInt16LittleToHost(*(UInt16 *)p);
return * (UInt16 *) p;
}
UInt32 Swap32(void *p)
{
* (UInt32 *) p = CFSwapInt32LittleToHost(*(UInt32 *)p);
return * (UInt32 *) p;
}
UInt64 Swap64(void *p)
{
UInt32 hiDW = (UInt32) (( *(UInt64 *)p) >> 32);
UInt32 loDW = (UInt32) ( ( *(UInt64 *)p) & 0xffffffff);
// Swap the 2 32 bit quantities
//
hiDW = Swap32(&hiDW);
loDW = Swap32(&loDW);
* (UInt64 *) p = (( (UInt64)hiDW ) << 32) | ( (UInt64) loDW);
return * (UInt64 *) p;
}
// ________________________________________________________________________________________________
// PrintStr
//
// For a descriptor field which is a string reference, fetch the string from
// device and print the field.
+(void)PrintStr:(IOUSBDeviceInterface **)deviceIntf name:(char *)name strIndex:(UInt8)strIndex forDevice:(int)deviceNumber atDepth:(int)depth
{
Byte buf[256];
char str2[500];
if (strIndex > 0)
{
int len;
buf[0] = 0;
len = GetStringDescriptor(deviceIntf, strIndex, buf, sizeof(buf),NULL);
if (len > 2)
{
Byte *p;
CFStringRef str;
for (p = buf + 2; p < buf + len; p += 2)
{
Swap16(p);
}
str = CFStringCreateWithCharacters(NULL, (const UniChar *)(buf+2), (len-2)/2);
CFStringGetCString(str, (char *)buf, 256, kCFStringEncodingNonLossyASCII);
CFRelease(str);
sprintf(str2, " [self PrintKeyVal:name val:str2 forDevice:deviceNumber atDepth:depth forNode:busprobeRootNode];
}
else
{
char str[20];
buf[0] = 0;
sprintf(str," [self PrintKeyVal:name val:str forDevice:deviceNumber atDepth:depth forNode:busprobeRootNode];
}
}
else
{
char str[20];
sprintf(str," [self PrintKeyVal:name val:str forDevice:deviceNumber atDepth:depth forNode:busprobeRootNode];
}
}
+(NSString *)ReturnStr:(IOUSBDeviceInterface **)deviceIntf strIndex:(UInt8)strIndex
{
Byte buf[256];
char str2[500];
if (strIndex > 0)
{
int len;
buf[0] = 0;
len = GetStringDescriptor(deviceIntf, strIndex, buf, sizeof(buf),NULL);
if (len > 2)
{
Byte *p;
CFStringRef str;
for (p = buf + 2; p < buf + len; p += 2)
{
Swap16(p);
}
str = CFStringCreateWithCharacters(NULL, (const UniChar *)(buf+2), (len-2)/2);
CFStringGetCString(str, (char *)buf, 256, kCFStringEncodingNonLossyASCII);
CFRelease(str);
sprintf(str2, "\"
return [NSString stringWithCString:str2];
}
else
{
buf[0] = 0;
return @"0x00";
}
}
else
return @"0x00";
}
// ________________________________________________________________________________________________
// dump
+(void)dump:(int)n byte:(Byte *)p forDevice:(int)deviceNumber atDepth:(int)depth
{
#define BYTESPERLINE 16
int lineCount = 0;
int runningCount = 0;
int lastLine = 0;
char str1[BYTESPERLINE * 6] = ""; // 0xXX + 2 spaces
char str2[10];
char descriptor[40];
strcat( str1, "0000: ");
sprintf(descriptor, "Raw Descriptor (hex) ");
while (--n >= 0)
{
sprintf(str2, " strcat(str1, str2);
lineCount++;
runningCount++;
// Add a space in between BYTESPERLINE / 2 and the next one
//
if ( (runningCount strcat(str1, " ");
// Add the index to the bytes (should they be in hex?) to the text
//
// Split the descriptor into BYTESPERLINE bytes each line so that it's more readabale
//
if ( lineCount == BYTESPERLINE )
{
[self PrintKeyVal:descriptor val:str1 forDevice:deviceNumber atDepth:depth forNode:busprobeRootNode];
lastLine = runningCount;
lineCount = 0;
sprintf(str1, " strcpy(descriptor, "");
// strcpy(str1,"");
}
}
if ( lineCount != 0 )
{
// Don't add an index for descriptors that only occupy one line
//
if ( lastLine == 0 )
strcpy(descriptor,"Raw Descriptor (hex)");
[self PrintKeyVal:descriptor val:str1 forDevice:deviceNumber atDepth:depth forNode:busprobeRootNode];
}
else
[self PrintKeyVal:"Unknown Descriptor" val:str1 forDevice:deviceNumber atDepth:depth forNode:busprobeRootNode];
return;
}
// ________________________________________________________________________________________________
// DumpDescriptor
//
+(void)DumpDescriptor:(IOUSBDeviceInterface **)deviceIntf dev:(IOUSBDeviceDescriptor)dev p:(Byte *)p forDevice:(int)deviceNumber lastInterfaceClass:(UInt8)lastInterfaceClass lastInterfaceSubClass:(UInt8)lastInterfaceSubClass currentInterfaceNum:(int)currentInterfaceNum
{
UInt8 descType = p[1];
char * xferTypes[] = { "Control", "Isochronous", "Bulk", "Interrupt" };
int xferTypes2[] = { 0, 1, 2, 3 };
USBClass * interfaceClass = NULL;
int tempInt1, tempInt2;
NSString * tempString1;
char str[500];
char temporaryString[500];
switch (descType)
{
case kUSBInterfaceDesc:
{
/* struct IOUSBInterfaceDescriptor {
UInt8 bLength;
UInt8 bDescriptorType;
UInt8 bInterfaceNumber;
UInt8 bAlternateSetting;
UInt8 bNumEndpoints;
UInt8 bInterfaceClass;
UInt8 bInterfaceSubClass;
UInt8 bInterfaceProtocol;
UInt8 iInterface;
}; */
IOUSBInterfaceDescriptor interfaceDescriptor;
char interfaceHeading[500];
interfaceDescriptor = *(IOUSBInterfaceDescriptor *)p;
sprintf(interfaceHeading, "Interface #
[self PrintKeyVal:interfaceHeading val:"" forDevice:deviceNumber atDepth:INTERFACE_LEVEL-1 forNode:busprobeRootNode];
NUM(interfaceDescriptor, "Alternate Setting", bAlternateSetting, deviceNumber, INTERFACE_LEVEL, 1);
NUM(interfaceDescriptor, "Number of Endpoints", bNumEndpoints, deviceNumber, INTERFACE_LEVEL, 1);
interfaceClass = [self InterfaceClassAndSubClass:"Interface" devDescriptor:&dev intfceDescriptor:&interfaceDescriptor forDevice:deviceNumber atDepth:INTERFACE_LEVEL];
tempInt1 = [[busprobeRootNode childAtIndex:deviceNumber] childrenCount];
tempInt2 = [[[busprobeRootNode childAtIndex:deviceNumber] childAtIndex:tempInt1-1] childrenCount];
tempString1 = [interfaceClass className];
// If our subclass name is different than our class name, then add the sub class to the description
// following a "/"
//
if( ! [[interfaceClass subClassName] isEqualToString:@""] &&
! [[interfaceClass subClassName] isEqualToString:[interfaceClass className]] )
{
tempString1 = [[tempString1 stringByAppendingString:@"/"] stringByAppendingString:[interfaceClass subClassName]];
}
if ( interfaceDescriptor.bAlternateSetting != 0 )
[[[[busprobeRootNode childAtIndex:deviceNumber] childAtIndex:tempInt1-1] childAtIndex:tempInt2-1] setItemName:[NSString stringWithFormat:@"Interface # else
[[[[busprobeRootNode childAtIndex:deviceNumber] childAtIndex:tempInt1-1] childAtIndex:tempInt2-1] setItemName:[NSString stringWithFormat:@"Interface #
NUM(interfaceDescriptor, "Interface Protocol", bInterfaceProtocol, deviceNumber, INTERFACE_LEVEL, 1);
lastInterfaceClass = interfaceDescriptor.bInterfaceClass;
lastInterfaceSubClass = interfaceDescriptor.bInterfaceSubClass;
}
break;
case kUSBEndpointDesc:
{
/* struct IOUSBEndpointDescriptor {
UInt8 bLength;
UInt8 bDescriptorType;
UInt8 bEndpointAddress;
UInt8 bmAttributes;
UInt16 wMaxPacketSize;
UInt8 bInterval;
}; */
IOUSBEndpointDescriptor endpointDescriptor;
char endpointHeading[500];
endpointDescriptor = *(IOUSBEndpointDescriptor *)p;
Swap16(&endpointDescriptor.wMaxPacketSize);
switch (xferTypes2[endpointDescriptor.bmAttributes & 3])
{
case 0:
sprintf(endpointHeading, "Endpoint 0x [self PrintKeyVal:endpointHeading val:"" forDevice:deviceNumber atDepth:ENDPOINT_LEVEL-1 forNode:busprobeRootNode];
break;
case 1:
if ( (endpointDescriptor.bEndpointAddress & kEndpointAddressMask ) == 0 )
sprintf(endpointHeading, "Endpoint 0x else
sprintf(endpointHeading, "Endpoint 0x [self PrintKeyVal:endpointHeading val:"" forDevice:deviceNumber atDepth:ENDPOINT_LEVEL-1 forNode:busprobeRootNode];
break;
case 2:
if ( (endpointDescriptor.bEndpointAddress & kEndpointAddressMask ) == 0 )
sprintf(endpointHeading, "Endpoint 0x else
sprintf(endpointHeading, "Endpoint 0x [self PrintKeyVal:endpointHeading val:"" forDevice:deviceNumber atDepth:ENDPOINT_LEVEL-1 forNode:busprobeRootNode];
break;
case 3:
if ( (endpointDescriptor.bEndpointAddress & kEndpointAddressMask ) == 0 )
sprintf(endpointHeading, "Endpoint 0x else
sprintf(endpointHeading, "Endpoint 0x [self PrintKeyVal:endpointHeading val:"" forDevice:deviceNumber atDepth:ENDPOINT_LEVEL-1 forNode:busprobeRootNode];
break;
default:
sprintf(endpointHeading, "Endpoint 0x [self PrintKeyVal:endpointHeading val:"" forDevice:deviceNumber atDepth:ENDPOINT_LEVEL-1 forNode:busprobeRootNode];
break;
}
if (!(xferTypes2[endpointDescriptor.bmAttributes & 3] == 0))
{
// we dont need to show direction for Control Endpoints
//
if ( (endpointDescriptor.bEndpointAddress & kEndpointAddressMask ) == 0 )
sprintf(temporaryString, "0x else
sprintf(temporaryString, "0x [self PrintKeyVal:"Attributes:" val:temporaryString forDevice:deviceNumber atDepth:ENDPOINT_LEVEL forNode:busprobeRootNode];
}
sprintf(str, "0x [self PrintKeyVal:"Attributes:" val:str forDevice:deviceNumber atDepth:ENDPOINT_LEVEL forNode:busprobeRootNode];
sprintf(temporaryString, " [self PrintKeyVal:"Max Packet Size:" val:temporaryString forDevice:deviceNumber atDepth:ENDPOINT_LEVEL forNode:busprobeRootNode];
sprintf(temporaryString, " [self PrintKeyVal:"Polling Interval:" val:temporaryString forDevice:deviceNumber atDepth:ENDPOINT_LEVEL forNode:busprobeRootNode];
}
break;
/* case CS_INTERFACE:
switch (lastInterfaceClass)
{
case 1: // audio class
if( AC_CONTROL_SUBCLASS == lastInterfaceSubClass )
{
switch ( ((GenericAudioDescriptorPtr)p)->descSubType )
{
case ACS_HEADER:
sprintf((char *)temporaryString, "Audio Control Class Specific Header Descriptor");
break;
case ACS_INPUT_TERMINAL:
sprintf((char *)temporaryString, "Audio Class Specific Input Terminal Descriptor");
break;
case ACS_OUTPUT_TERMINAL:
sprintf((char *)temporaryString, "Audio Class Specific Ouput Terminal Descriptor");
break;
case ACS_MIXER_UNIT:
sprintf((char *)temporaryString, "Audio Class Specific Mixer Unit Descriptor");
break;
case ACS_SELECTOR_UNIT:
sprintf((char *)temporaryString, "Audio Class Specific Selector Unit Descriptor");
break;
case ACS_FEATURE_UNIT:
sprintf((char *)temporaryString, "Audio Class Specific Feature Descriptor");
break;
case ACS_PROCESSING_UNIT:
sprintf((char *)temporaryString, "Audio Class Specific Processing Unit Descriptor");
break;
case ACS_EXTENSION_UNIT:
sprintf((char *)temporaryString, "Audio Class Specific Extension Descriptor");
break;
}
}
else if( AC_STREAM_SUBCLASS == lastInterfaceSubClass )
{
switch ( ((GenericAudioDescriptorPtr)p)->descSubType )
{
case ACS_HEADER:
sprintf((char *)temporaryString, "Audio Control Class Specific Header Descriptor");
break;
case ACS_FORMAT_TYPE:
sprintf((char *)temporaryString, "Audio Class Specific Audio Data Format Descriptor");
break;
}
}
break;
default:
sprintf((char *)temporaryString, "Type 0x break;
}
[self PrintKeyVal:temporaryString val:"" forDevice:deviceNumber
atDepth:CONFIGURATION_DESCRIPTOR_LEVEL+2 forNode:busprobeRootNode];
break;
case CS_ENDPOINT:
[self DoRegularCSEndpoint:p deviceClass:interfaceClass forDevice:deviceNumber atDepth:ENDPOINT_LEVEL-1];
break;
*/
case HID_DESCRIPTOR:
// case DFU_FUNCTIONAL_DESCRIPTOR: - same value, compiler complains
{
if (lastInterfaceClass == kUSBApplicationSpecificClass && lastInterfaceSubClass == kUSBDFUSubClass)
{
IOUSBDFUDescriptor dfuDescriptor;
dfuDescriptor = *(IOUSBDFUDescriptor *)p;
[self PrintKeyVal:"DFU Functional Descriptor" val:"" forDevice:deviceNumber
atDepth:DFU_DESCRIPTOR_LEVEL-1 forNode:busprobeRootNode];
sprintf(temporaryString, "0x "Reserved bits: 0x dfuDescriptor.bmAttributes,
dfuDescriptor.bmAttributes & (1 << kUSBDFUCanDownloadBit) ? "" : "No ",
dfuDescriptor.bmAttributes & ( 1 << kUSBDFUCanUploadBit) ? "" : "No ",
dfuDescriptor.bmAttributes & ( 1 << kUSBDFUManifestationTolerantBit) ? "" : "Not ",
dfuDescriptor.bmAttributes & ~kUSBDFUAttributesMask);
[self PrintKeyVal:"bmAttributes:" val:temporaryString forDevice:deviceNumber
atDepth:DFU_DESCRIPTOR_LEVEL forNode:busprobeRootNode];
sprintf(temporaryString, "
[self PrintKeyVal:"wDetachTimeout:" val:temporaryString forDevice:deviceNumber
atDepth:DFU_DESCRIPTOR_LEVEL forNode:busprobeRootNode];
sprintf(temporaryString, "
[self PrintKeyVal:"wTransferSize:" val:temporaryString forDevice:deviceNumber
atDepth:DFU_DESCRIPTOR_LEVEL forNode:busprobeRootNode];
}
else if (lastInterfaceClass == kUSBHIDClass)
{
IOUSBHIDDescriptor hidDescriptor;
int descriptorIncrement=0;
hidDescriptor = *(IOUSBHIDDescriptor *)p;
[self PrintKeyVal:"HID Descriptor" val:"" forDevice:deviceNumber atDepth:HID_DESCRIPTOR_LEVEL-1 forNode:busprobeRootNode];
Swap16(&hidDescriptor.descVersNum);
NUM(hidDescriptor, "Descriptor Version Number:", descVersNum, deviceNumber, HID_DESCRIPTOR_LEVEL, 0);
NUM(hidDescriptor, "Country Code:", hidCountryCode, deviceNumber, HID_DESCRIPTOR_LEVEL, 1);
NUM(hidDescriptor, "Descriptor Count:", hidNumDescriptors, deviceNumber, HID_DESCRIPTOR_LEVEL, 1);
for(descriptorIncrement=1; descriptorIncrement <= hidDescriptor.hidNumDescriptors; descriptorIncrement++)
{
char tempCString[20], descriptorHeading[20];
NSString *tempString;
sprintf(descriptorHeading, "Descriptor [self PrintKeyVal:descriptorHeading val:"" forDevice:deviceNumber atDepth:HID_DESCRIPTOR_LEVEL forNode:busprobeRootNode];
tempString = RETURNNUM(hidDescriptor, hidDescriptorType, 0);
if ( hidDescriptor.hidDescriptorType == kUSBHIDDesc)
{
UInt16 hidDescriptorLength = ( hidDescriptor.hidDescriptorLengthHi << 8 ) | hidDescriptor.hidDescriptorLengthLo;
sprintf(tempCString, " [self PrintKeyVal:"Type:" val:tempCString forDevice:deviceNumber atDepth:HID_DESCRIPTOR_LEVEL+1 forNode:busprobeRootNode];
sprintf(tempCString, " [self PrintKeyVal:"Length:" val:tempCString forDevice:deviceNumber atDepth:HID_DESCRIPTOR_LEVEL+1 forNode:busprobeRootNode];
}
else if (hidDescriptor.hidDescriptorType == kUSBReportDesc)
{
unsigned char *reportdesc;
UInt16 hidlen, hidDescriptorLength = ( hidDescriptor.hidDescriptorLengthHi << 8 ) | hidDescriptor.hidDescriptorLengthLo;
sprintf(tempCString, " [self PrintKeyVal:"Type:" val:tempCString forDevice:deviceNumber atDepth:HID_DESCRIPTOR_LEVEL+1 forNode:busprobeRootNode];
sprintf(tempCString, " [self PrintKeyVal:"Length (and contents):" val:tempCString forDevice:deviceNumber atDepth:HID_DESCRIPTOR_LEVEL+1 forNode:busprobeRootNode];
reportdesc = malloc(hidDescriptorLength);
if (reportdesc)
{
hidlen = GetDescriptorFromInterface(deviceIntf, kUSBReportDesc, 0 /*desc index*/, currentInterfaceNum, reportdesc, hidDescriptorLength);
if (hidlen == hidDescriptorLength)
{
[self dump:hidlen byte:reportdesc forDevice:deviceNumber atDepth:HID_DESCRIPTOR_LEVEL+2];
[DecodeHIDReport DecodeHIDReport:reportdesc forDevice:deviceNumber atDepth:HID_DESCRIPTOR_LEVEL+1 reportLen:hidlen forNode:busprobeRootNode];
}
free(reportdesc);
}
}
else if (hidDescriptor.hidDescriptorType == kUSBPhysicalDesc)
{
UInt16 hidDescriptorLength = ( hidDescriptor.hidDescriptorLengthHi << 8 ) | hidDescriptor.hidDescriptorLengthLo;
sprintf(tempCString, " [self PrintKeyVal:"Type:" val:tempCString forDevice:deviceNumber atDepth:HID_DESCRIPTOR_LEVEL+1 forNode:busprobeRootNode];
sprintf(tempCString, " [self PrintKeyVal:"Length:" val:tempCString forDevice:deviceNumber atDepth:HID_DESCRIPTOR_LEVEL+1 forNode:busprobeRootNode];
}
else
{
UInt16 hidDescriptorLength = ( hidDescriptor.hidDescriptorLengthHi << 8 ) | hidDescriptor.hidDescriptorLengthLo;
sprintf(tempCString, " [self PrintKeyVal:"Type:" val:tempCString forDevice:deviceNumber atDepth:HID_DESCRIPTOR_LEVEL+1 forNode:busprobeRootNode];
sprintf(tempCString, " [self PrintKeyVal:"Length:" val:tempCString forDevice:deviceNumber atDepth:HID_DESCRIPTOR_LEVEL+1 forNode:busprobeRootNode];
}
}
}
else
{
// Descriptor 21 for an unknown class. Just dump it out
//
[self DumpRawDescriptor:p forDevice:deviceNumber atDepth:CONFIGURATION_DESCRIPTOR_LEVEL+1];
}
}
break;
case kUSBHUBDesc:
{
IOUSBHubDescriptor hubDescriptor;
UInt16 hubChar;
hubDescriptor = *(IOUSBHubDescriptor *)p;
[self PrintKeyVal:"Hub Descriptor" val:"" forDevice:deviceNumber atDepth:HUB_DESCRIPTOR_LEVEL-1 forNode:busprobeRootNode];
NUM(hubDescriptor, "Number of Ports:", numPorts, deviceNumber, HUB_DESCRIPTOR_LEVEL, 0);
hubChar = Swap16(&hubDescriptor.characteristics);
sprintf(temporaryString, "0x (((hubChar & 3) == 0) ? "Gang " :
((hubChar & 3) == 1) ? "Individually " : "Non-"),
((hubChar & 4) == 4) ? "compound" : "standalone",
((hubChar & 0x18) == 0) ? "global" :
((hubChar & 0x18) == 0x8) ? "individual port" : "no");
[self PrintKeyVal:"Hub Characteristics:" val:temporaryString forDevice:deviceNumber
atDepth:HUB_DESCRIPTOR_LEVEL forNode:busprobeRootNode];
sprintf(temporaryString, " [self PrintKeyVal:"PowerOnToGood time:" val:temporaryString forDevice:deviceNumber
atDepth:HUB_DESCRIPTOR_LEVEL forNode:busprobeRootNode];
sprintf(temporaryString, " [self PrintKeyVal:"Controller current:" val:temporaryString forDevice:deviceNumber
atDepth:HUB_DESCRIPTOR_LEVEL forNode:busprobeRootNode];
if (hubDescriptor.numPorts < 8)
{
sprintf(temporaryString, "0x [self PrintKeyVal:"Device Removeable (byte):" val:temporaryString forDevice:deviceNumber
atDepth:HUB_DESCRIPTOR_LEVEL forNode:busprobeRootNode];
sprintf(temporaryString, "0x [self PrintKeyVal:"Port Power Control Mask (byte):" val:temporaryString forDevice:deviceNumber
atDepth:HUB_DESCRIPTOR_LEVEL forNode:busprobeRootNode];
}
else if (hubDescriptor.numPorts < 16)
{
sprintf(temporaryString, "0x [self PrintKeyVal:"Device Removeable (byte):" val:temporaryString forDevice:deviceNumber
atDepth:HUB_DESCRIPTOR_LEVEL forNode:busprobeRootNode];
sprintf(temporaryString, "0x [self PrintKeyVal:"Port Power Control Mask (byte):" val:temporaryString forDevice:deviceNumber
atDepth:HUB_DESCRIPTOR_LEVEL forNode:busprobeRootNode];
}
}
break;
case kUSBDeviceQualifierDesc:
{
IOUSBDeviceQualifierDescriptor devQualDescriptor;
USBClass * deviceClass = NULL;
devQualDescriptor = *(IOUSBDeviceQualifierDescriptor *)p;
Swap16(&devQualDescriptor.bcdUSB);
[self PrintKeyVal:"Device Qualifier Descriptor" val:"" forDevice:deviceNumber atDepth:DEVICE_QUAL_DESCRIPTOR_LEVEL-1 forNode:busprobeRootNode];
NUM(devQualDescriptor, "Descriptor Version Number:", bcdUSB, deviceNumber, DEVICE_QUAL_DESCRIPTOR_LEVEL, 0);
deviceClass = [self DeviceClassAndSubClass:"Device" devDescriptor:(IOUSBDeviceDescriptor *)&devQualDescriptor forDevice:deviceNumber atDepth:1];
NUM(devQualDescriptor, "Device Protocol", bDeviceProtocol, deviceNumber, DEVICE_QUAL_DESCRIPTOR_LEVEL, 1);
NUM(devQualDescriptor, "Device MaxPacketSize:", bMaxPacketSize0, deviceNumber, DEVICE_QUAL_DESCRIPTOR_LEVEL, 1);
NUM(devQualDescriptor, "Number of Configurations:", bNumConfigurations, deviceNumber, DEVICE_DESCRIPTOR_LEVEL, 1);
NUM(devQualDescriptor, "bReserved:", bReserved, deviceNumber, DEVICE_DESCRIPTOR_LEVEL, 1);
[deviceClass release];
}
break;
case kUSBInterfaceAssociationDesc:
{
IOUSBInterfaceAssociationDescriptor interfaceAssocDescriptor;
interfaceAssocDescriptor = *(IOUSBInterfaceAssociationDescriptor *)p;
[self PrintKeyVal:"Interface Association Descriptor" val:"" forDevice:deviceNumber atDepth:DEVICE_QUAL_DESCRIPTOR_LEVEL forNode:busprobeRootNode];
NUM(interfaceAssocDescriptor, "First Interface:", bFirstInterface, deviceNumber, DEVICE_QUAL_DESCRIPTOR_LEVEL+1, 0);
NUM(interfaceAssocDescriptor, "Interface Count:", bInterfaceCount, deviceNumber, DEVICE_QUAL_DESCRIPTOR_LEVEL+1, 0);
NUM(interfaceAssocDescriptor, "Function Class:", bFunctionClass, deviceNumber, DEVICE_QUAL_DESCRIPTOR_LEVEL+1, 0);
NUM(interfaceAssocDescriptor, "Function SubClass:", bFunctionSubClass, deviceNumber, DEVICE_QUAL_DESCRIPTOR_LEVEL+1, 0);
NUM(interfaceAssocDescriptor, "Function Protocol:", bFunctionProtocol, deviceNumber, DEVICE_QUAL_DESCRIPTOR_LEVEL+1, 0);
}
break;
default:
switch(lastInterfaceClass)
{
case 1: /* audio class */
[DecodeAudioInterfaceDescriptor DecodeAudioInterfaceDescriptor:p forDevice:deviceNumber atDepth:CONFIGURATION_DESCRIPTOR_LEVEL+1 forNode:busprobeRootNode subClass:lastInterfaceSubClass ];
break;
case 2: /* communication class */
// DecodeCommClassDescriptor( desc, myItem, curSubClass, curProtocol);
switch ( ((GenericAudioDescriptorPtr)p)->descSubType )
{
case 0:
sprintf((char *)temporaryString, "Comm Class Header Functional Descriptor");
break;
case 1:
sprintf((char *)temporaryString, "Comm Class Call Management Functional Descriptor");
break;
case 2:
sprintf((char *)temporaryString, "Comm Class Abstract Control Management Functional Descriptor");
break;
case 3:
sprintf((char *)temporaryString, "Comm Class Direct Line Management Functional Descriptor");
break;
case 4:
sprintf((char *)temporaryString, "Comm Class Telephone Ringer Functional Descriptor");
break;
case 5:
sprintf((char *)temporaryString, "Comm Class Call and LIne State Reporting Functional Descriptor");
break;
case 6:
sprintf((char *)temporaryString, "Comm Class Union Functional Descriptor");
break;
case 7:
sprintf((char *)temporaryString, "Comm Class Country Selection Functional Descriptor");
break;
case 8:
sprintf((char *)temporaryString, "Comm Class Telephone Operational Modes Functional Descriptor");
break;
case 9:
sprintf((char *)temporaryString, "Comm Class USB Terminal Functional Descriptor");
break;
case 10:
sprintf((char *)temporaryString, "Comm Class Network Channel Terminal Functional Descriptor");
break;
case 11:
sprintf((char *)temporaryString, "Comm Class Protocol Unit Functional Descriptor");
break;
case 12:
sprintf((char *)temporaryString, "Comm Class Extension Unit Functional Descriptor");
break;
case 13:
sprintf((char *)temporaryString, "Comm Class Multi-Channel Management Functional Descriptor");
break;
case 14:
sprintf((char *)temporaryString, "Comm Class CAPI Control Management Functional Descriptor");
break;
case 15:
sprintf((char *)temporaryString, "Comm Class Ethernet Networking Functional Descriptor");
break;
case 16:
sprintf((char *)temporaryString, "Comm Class ATM Networking Functional Descriptor");
break;
default:
sprintf((char *)temporaryString, "Comm Class Reserved Functional Descriptor ( break;
}
[self PrintKeyVal:temporaryString val:"" forDevice:deviceNumber atDepth:CONFIGURATION_DESCRIPTOR_LEVEL+1 forNode:busprobeRootNode];
[self DumpRawDescriptor:p forDevice:deviceNumber atDepth:CONFIGURATION_DESCRIPTOR_LEVEL+2];
break;
case 0xff:
if ( [self isInterfaceVDC:dev.idVendor idProduct:dev.idProduct])
{
[DecodeVideoInterfaceDescriptor DecodeVideoInterfaceDescriptor:p deviceIntf:deviceIntf forDevice:deviceNumber atDepth:CONFIGURATION_DESCRIPTOR_LEVEL+1 forNode:busprobeRootNode subClass:lastInterfaceSubClass ];
break;
}
// Fall thru.
default:
[self DumpRawDescriptor:p forDevice:deviceNumber atDepth:CONFIGURATION_DESCRIPTOR_LEVEL+1];
break;
}
break;
}
[interfaceClass release];
}
// ________________________________________________________________________________________________
// DumpRawDescriptor
//
// When we don't know any better...
+(void)DumpRawDescriptor:(Byte *)p forDevice:(int)deviceNumber atDepth:(int)depth
{
[self dump:p[0] byte:p forDevice:deviceNumber atDepth:depth];
}
+(void)DoRegularCSInterface:(Byte *)p deviceClass:(USBClass *)interfaceClass forDevice:(int)deviceNumber atDepth:(int)depth
{
NSString *compositedString;
char compositedCString[500];
if ([[interfaceClass subClassName] isEqualToString:@""])
compositedString = [NSString stringWithFormat:@" else
compositedString = [NSString stringWithFormat:@"
sprintf(compositedCString," [self PrintKeyVal:compositedCString val:"" forDevice:deviceNumber atDepth:depth forNode:busprobeRootNode];
[self DumpRawDescriptor:p forDevice:deviceNumber atDepth:depth+1];
}
+(void)DoRegularCSEndpoint:(Byte *)p deviceClass:(USBClass *)interfaceClass forDevice:(int)deviceNumber atDepth:(int)depth;
{
NSString *compositedString;
char compositedCString[500];
if ([[interfaceClass subClassName] isEqualToString:@""])
compositedString = [NSString stringWithFormat:@" else
compositedString = [NSString stringWithFormat:@"
sprintf(compositedCString," [self PrintKeyVal:compositedCString val:"" forDevice:deviceNumber atDepth:depth forNode:busprobeRootNode];
[self DumpRawDescriptor:p forDevice:deviceNumber atDepth:depth+1];
}
- (void)loadVendorNamesFromFile
{
NSString *vendorListString = [NSString stringWithContentsOfFile:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"USBVendors.txt"]];
if (vendorListString == nil) { return; }
else {
NSArray *vendorsAndIDs = [vendorListString componentsSeparatedByString:@"\n"];
if (vendorsAndIDs == nil) { return; }
else {
NSEnumerator *enumerator = [vendorsAndIDs objectEnumerator];
NSString *vendorIDCombo;
NSArray *aVendor;
while ((vendorIDCombo = [enumerator nextObject])) {
aVendor = [vendorIDCombo componentsSeparatedByString:@"|"];
if (aVendor == nil || [aVendor count] < 2) { continue; }
[vendorNamesDictionary setObject:[aVendor objectAtIndex:1] forKey:[aVendor objectAtIndex:0]];
}
}
}
}
- (void)loadVDCListFromFile
{
// read the text file into a string
NSString *vdcListString = [NSString stringWithContentsOfFile:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"USBVDCList.txt"]];
// make sure we actually found and read the file properly
if (vdcListString == nil) { return; }
else {
// create an array that is filled with the lines of the file
NSArray *vendorsAndProducts = [vdcListString componentsSeparatedByString:@"\n"];
// make sure the file actually had some lines that could be separated
if (vendorsAndProducts == nil) { return; }
else {
NSEnumerator *enumerator = [vendorsAndProducts objectEnumerator];
NSString *thisLine;
NSArray *lineComponents;
while ((thisLine = [enumerator nextObject])) {
// split the line up into idVendor/idProduct
lineComponents = [thisLine componentsSeparatedByString:@"|"];
// just to make sure the line actually had 2 items in it (idVendor/idProduct)
if (lineComponents == nil || [lineComponents count] < 2) { continue; }
// basically, we will put the entire line from the file, into the dictionary as a key. as the
// corresponding value, we just use a dummy NSObject. That way, we just need to check for a non-nil
// value to see if the idVendor/idProduct combo was in the file.
[videoClassDevicesDictionary setObject:[[NSObject new] autorelease] forKey:thisLine];
}
}
}
}
+ (NSString *)vendorNameFromVendorID:(NSString *)intValueAsString
{
NSString *vendorName = [vendorNamesDictionary objectForKey:intValueAsString];
if (vendorName != nil)
return vendorName;
else
return @"unknown vendor";
}
+ (BOOL)isInterfaceVDC:(UInt32)vendorID idProduct:(UInt32)productID
{
NSString *hashString = [NSString stringWithFormat:@" return ([videoClassDevicesDictionary objectForKey:hashString] != nil);
}
// init is like a constructor
- init
{
self = [super init];
busprobeRootNode = [[Node alloc] init];
vendorNamesDictionary = [[NSMutableDictionary alloc] init];
videoClassDevicesDictionary = [[NSMutableDictionary alloc] init]; // add this line
[self loadVendorNamesFromFile];
[self loadVDCListFromFile]; // this line
return self;
}
// Data source methods get called automatically
// This method is called repeatedly when the table view is displaying it self.
- (id)outlineView:(NSOutlineView *)ov child:(int)index ofItem:(id)item
{
// is the parent non-nil?
if (item)
// Return the child
return [item childAtIndex:index];
else
// Else return the root
return busprobeRootNode;
}
// Called repeatedly to find out if there should be an
// "expand triangle" next to the label
- (BOOL)outlineView:(NSOutlineView *)ov isItemExpandable:(id)item
{
// Returns YES if the node has children
return [item expandable];
}
// Called repeatedly when the table view is displaying itself
- (int)outlineView:(NSOutlineView *)ov numberOfChildrenOfItem:(id)item
{
if (item == nil) {
// The root object;
return 1;
}
return [item childrenCount];
}
// This method gets called repeatedly when the outline view is trying
// to display it self.
- (id)outlineView:(NSOutlineView *)ov
objectValueForTableColumn:(NSTableColumn *)tableColumn
byItem:(id)item
{
// What is returned depends upon which column it is
// going to appear.
if ([[tableColumn identifier] isEqual:@"itemValue"]){
// NSLog([item itemValue]);
return [item itemValue];
} else {
// NSLog([item itemName]);
return [item itemName];
}
}
- (void)dealloc
{
[busprobeRootNode release];
[super dealloc];
}
@end