#include <stdio.h>
#include <stdbool.h>
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/storage/IOStorageDeviceCharacteristics.h>
#include <IOKit/scsi/IOSCSIMultimediaCommandsDevice.h>
#define DEBUG 0
#define DEBUG_ASSERT_COMPONENT_NAME_STRING "FeatureFlags"
#define DEBUG_ASSERT_MESSAGE(componentNameString, \
assertionString, \
exceptionLabelString, \
errorString, \
fileName, \
lineNumber, \
errorCode) \
DebugAssert(componentNameString, \
assertionString, \
exceptionLabelString, \
errorString, \
fileName, \
lineNumber, \
errorCode) \
static void
DebugAssert ( const char * componentNameString,
const char * assertionString,
const char * exceptionLabelString,
const char * errorString,
const char * fileName,
long lineNumber,
int errorCode )
{
if ( ( assertionString != NULL ) && ( *assertionString != '\0' ) )
printf ( "Assertion failed: %s: %s\n", componentNameString, assertionString );
else
printf ( "Check failed: %s:\n", componentNameString );
if ( exceptionLabelString != NULL )
printf ( " %s\n", exceptionLabelString );
if ( errorString != NULL )
printf ( " %s\n", errorString );
if ( fileName != NULL )
printf ( " file: %s\n", fileName );
if ( lineNumber != 0 )
printf ( " line: %ld\n", lineNumber );
if ( errorCode != 0 )
printf ( " error: %d\n", errorCode );
}
#include <AssertMacros.h>
#define kIOCDBlockStorageDeviceClassString "IOCDBlockStorageDevice"
static io_iterator_t
GetDeviceIterator ( const char * deviceClass );
static void
GetFeaturesFlagsForDrive ( CFDictionaryRef dict,
UInt32 * cdFlags,
UInt32 * dvdFlags );
static void
PrintFeaturesForEachDevice ( io_iterator_t iter );
static CFMutableDictionaryRef
GetRegistryEntryProperties ( io_service_t service );
static CFStringRef
GetDriveDescription ( CFDictionaryRef dict );
static void
PrintCDFeatures ( UInt32 cdFlags );
static void
PrintDVDFeatures ( UInt32 dvdFlags );
static __inline__ bool IsBitSet ( UInt32 flags, UInt32 mask );
int
main ( int argc, const char * argv[] )
{
io_iterator_t iter = MACH_PORT_NULL;
int result = -1;
iter = GetDeviceIterator ( kIOCDBlockStorageDeviceClassString );
require ( ( iter != MACH_PORT_NULL ), ErrorExit );
PrintFeaturesForEachDevice ( iter );
IOObjectRelease ( iter );
iter = MACH_PORT_NULL;
result = 0;
ErrorExit:
return 0;
}
static io_iterator_t
GetDeviceIterator ( const char * deviceClass )
{
IOReturn err = kIOReturnSuccess;
io_iterator_t iterator = MACH_PORT_NULL;
err = IOServiceGetMatchingServices ( kIOMasterPortDefault,
IOServiceMatching ( deviceClass ),
&iterator );
check ( err == kIOReturnSuccess );
return iterator;
}
static void
GetFeaturesFlagsForDrive ( CFDictionaryRef dict,
UInt32 * cdFlags,
UInt32 * dvdFlags )
{
CFDictionaryRef propertiesDict = 0;
CFNumberRef flagsNumberRef = 0;
*cdFlags = 0;
*dvdFlags = 0;
propertiesDict = ( CFDictionaryRef ) CFDictionaryGetValue ( dict, CFSTR ( kIOPropertyDeviceCharacteristicsKey ) );
require ( ( propertiesDict != 0 ), ErrorExit );
flagsNumberRef = ( CFNumberRef ) CFDictionaryGetValue ( propertiesDict, CFSTR ( kIOPropertySupportedCDFeatures ) );
if ( flagsNumberRef != 0 )
{
CFNumberGetValue ( flagsNumberRef, kCFNumberLongType, cdFlags );
}
flagsNumberRef = ( CFNumberRef ) CFDictionaryGetValue ( propertiesDict, CFSTR ( kIOPropertySupportedDVDFeatures ) );
if ( flagsNumberRef != 0 )
{
CFNumberGetValue ( flagsNumberRef, kCFNumberLongType, dvdFlags );
}
ErrorExit:
return;
}
static void
PrintFeaturesForEachDevice ( io_iterator_t iter )
{
UInt32 cdFlags = 0;
UInt32 dvdFlags = 0;
io_service_t service = MACH_PORT_NULL;
CFDictionaryRef properties = NULL;
CFStringRef description = NULL;
while ( ( service = IOIteratorNext ( iter ) ) != MACH_PORT_NULL )
{
properties = GetRegistryEntryProperties ( service );
description = GetDriveDescription ( properties );
printf ( "\nDevice: " );
fflush ( stdout );
CFShow ( description );
CFRelease ( description );
printf ( "----------------------------------\n" );
GetFeaturesFlagsForDrive ( properties, &cdFlags, &dvdFlags );
PrintCDFeatures ( cdFlags );
PrintDVDFeatures ( dvdFlags );
CFRelease ( properties );
IOObjectRelease ( service );
printf ( "\n\n" );
}
}
static CFMutableDictionaryRef
GetRegistryEntryProperties ( io_service_t service )
{
IOReturn err = kIOReturnSuccess;
CFMutableDictionaryRef dict = 0;
err = IORegistryEntryCreateCFProperties ( service,
&dict,
kCFAllocatorDefault,
0 );
check ( err == kIOReturnSuccess );
return dict;
}
static CFStringRef
GetDriveDescription ( CFDictionaryRef dict )
{
CFMutableStringRef description = NULL;
CFDictionaryRef deviceDict = NULL;
CFStringRef vendor = NULL;
CFStringRef product = NULL;
require ( ( dict != 0 ), Exit );
deviceDict = ( CFDictionaryRef ) CFDictionaryGetValue ( dict, CFSTR ( kIOPropertyDeviceCharacteristicsKey ) );
require ( ( deviceDict != 0 ), Exit );
vendor = ( CFStringRef ) CFDictionaryGetValue ( deviceDict, CFSTR ( kIOPropertyVendorNameKey ) );
product = ( CFStringRef ) CFDictionaryGetValue ( deviceDict, CFSTR ( kIOPropertyProductNameKey ) );
description = CFStringCreateMutable ( kCFAllocatorDefault, 0 );
require ( ( description != 0 ), Exit );
CFStringAppend ( description, vendor );
CFStringAppend ( description, CFSTR ( " " ) );
CFStringAppend ( description, product );
check ( description );
Exit:
return description;
}
static void
PrintCDFeatures ( UInt32 cdFlags )
{
require ( ( cdFlags != 0 ), Exit );
if ( IsBitSet ( cdFlags, kCDFeaturesAnalogAudioMask ) )
{
printf ( "Drive supports analog audio\n" );
}
if ( IsBitSet ( cdFlags, kCDFeaturesReadStructuresMask ) )
{
printf ( "CD-ROM\n" );
}
if ( IsBitSet ( cdFlags, kCDFeaturesWriteOnceMask ) )
{
printf ( "CD-R\n" );
}
if ( IsBitSet ( cdFlags, kCDFeaturesReWriteableMask ) )
{
printf ( "CD-RW\n" );
}
if ( IsBitSet ( cdFlags, kCDFeaturesCDDAStreamAccurateMask ) )
{
printf ( "Drive is CD-DA Stream Accurate\n" );
}
if ( IsBitSet ( cdFlags, kCDFeaturesPacketWriteMask ) )
{
printf ( "Drive supports packet writing\n" );
}
if ( IsBitSet ( cdFlags, kCDFeaturesTAOWriteMask ) )
{
printf ( "Drive supports TAO writing\n" );
}
if ( IsBitSet ( cdFlags, kCDFeaturesSAOWriteMask ) )
{
printf ( "Drive supports SAO writing\n" );
}
if ( IsBitSet ( cdFlags, kCDFeaturesRawWriteMask ) )
{
printf ( "Drive supports RAW writing\n" );
}
if ( IsBitSet ( cdFlags, kCDFeaturesTestWriteMask ) )
{
printf ( "Drive supports Test Write writing\n" );
}
if ( IsBitSet ( cdFlags, kCDFeaturesBUFWriteMask ) )
{
printf ( "Drive supports BUF Write writing\n" );
}
Exit:
return;
}
static void
PrintDVDFeatures ( UInt32 dvdFlags )
{
require ( ( dvdFlags != 0 ), Exit );
if ( IsBitSet ( dvdFlags, kDVDFeaturesCSSMask ) )
{
printf ( "Drive supports CSS\n" );
}
if ( IsBitSet ( dvdFlags, kDVDFeaturesReadStructuresMask ) )
{
printf ( "DVD-ROM\n" );
}
if ( IsBitSet ( dvdFlags, kDVDFeaturesWriteOnceMask ) )
{
printf ( "DVD-R\n" );
}
if ( IsBitSet ( dvdFlags, kDVDFeaturesRandomWriteableMask ) )
{
printf ( "DVD-RAM\n" );
}
if ( IsBitSet ( dvdFlags, kDVDFeaturesReWriteableMask ) )
{
printf ( "DVD-RW\n" );
}
if ( IsBitSet ( dvdFlags, kDVDFeaturesTestWriteMask ) )
{
printf ( "Drive supports Test Write writing\n" );
}
if ( IsBitSet ( dvdFlags, kDVDFeaturesBUFWriteMask ) )
{
printf ( "Drive supports BUF Write writing\n" );
}
if ( IsBitSet ( dvdFlags, kDVDFeaturesPlusRMask ) )
{
printf ( "Drive supports DVD+R\n" );
}
if ( IsBitSet ( dvdFlags, kDVDFeaturesPlusRWMask ) )
{
printf ( "Drive supports DVD+RW\n" );
}
Exit:
return;
}
static __inline__ bool
IsBitSet ( UInt32 flags, UInt32 mask )
{
return ( ( flags & mask ) != 0 );
}