modesuck.c   [plain text]


// cc -o /tmp/modesuck -g modesuck.c -framework ApplicationServices -framework IOKit -Wall


#include <mach/mach.h>
#include <mach/thread_switch.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <math.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include <IOKit/IOKitLib.h>
#include <IOKit/graphics/IOGraphicsTypesPrivate.h>
#include <ApplicationServices/ApplicationServices.h>


__private_extern__ IOReturn
readFile(const char *path, vm_offset_t * objAddr, vm_size_t * objSize)
{
    int fd;
    int err;
    struct stat stat_buf;

    *objAddr = 0;
    *objSize = 0;

    if((fd = open(path, O_RDONLY)) == -1)
        return errno;

    do {
        if(fstat(fd, &stat_buf) == -1) {
            err = errno;
            continue;
        }
        if (0 == (stat_buf.st_mode & S_IFREG)) 
        {
            *objAddr = 0;
            *objSize = 0;
            err = kIOReturnNotReadable;
            continue;
        }
        *objSize = stat_buf.st_size;

        if( KERN_SUCCESS != map_fd(fd, 0, objAddr, TRUE, *objSize)) {
            *objAddr = 0;
            *objSize = 0;
            err = errno;
            continue;
        }

        err = kIOReturnSuccess;

    } while( false );

    close(fd);

    return( err );
}

__private_extern__ CFMutableDictionaryRef
readPlist( const char * path, UInt32 key )
{
    IOReturn                    err;
    vm_offset_t                 bytes;
    vm_size_t                   byteLen;
    CFDataRef                   data;
    CFMutableDictionaryRef      obj = 0;

    err = readFile( path, &bytes, &byteLen );

    if( kIOReturnSuccess != err) 
        return (0);
    
    data = CFDataCreateWithBytesNoCopy( kCFAllocatorDefault,
                                (const UInt8 *) bytes, byteLen, kCFAllocatorNull );
    if( data) {
        obj = (CFMutableDictionaryRef) CFPropertyListCreateFromXMLData( kCFAllocatorDefault, data,
                                            kCFPropertyListMutableContainers,
                                            (CFStringRef *) NULL );
        CFRelease( data );
    }
    vm_deallocate( mach_task_self(), bytes, byteLen );

    return (obj);
}

int main(int argc, char * argv[])
{
    io_service_t                framebuffer;
    CGError                     err;
    int                         i;
    CGDisplayCount              max;
    CGDirectDisplayID           displayIDs[8];
    IODisplayModeInformation *  modeInfo;
    IODetailedTimingInformationV2 *timingInfo;

    CFDictionaryRef             dict;
    CFArrayRef                  modes;
    CFIndex                     count;
    CFDictionaryRef             mode;
    CFMutableDictionaryRef      result, stdModes, timingIDs;
    CFDataRef                   data;
    CFNumberRef                 num;
    CFStringRef                 cfStr;
    char                        key[64];
    const void *                keys[2];
    const void *                values[2];

    err = CGGetOnlineDisplayList(8, displayIDs, &max);
    if(err != kCGErrorSuccess)
        exit(1);
    if(max > 8)
        max = 8;

    for(i = 0; i < max; i++ ) {

        framebuffer = CGDisplayIOServicePort(displayIDs[i]);

        dict = IORegistryEntryCreateCFProperty(framebuffer, CFSTR(kIOFBConfigKey),
                                                kCFAllocatorDefault, kNilOptions);
        assert(dict);

        modes = CFDictionaryGetValue(dict, CFSTR(kIOFBModesKey));
        assert(modes);


        result = readPlist("/System/Library/Frameworks/IOKit.framework/"
                                    "Resources/IOGraphicsProperties.plist", 0);

        if (result)
        {
            stdModes = (CFMutableDictionaryRef) CFDictionaryGetValue(result, CFSTR("std-modes"));
            assert(stdModes);
            timingIDs = (CFMutableDictionaryRef) CFDictionaryGetValue(result, CFSTR("timing-ids"));
            assert(timingIDs);

            data = CFDictionaryGetValue(result, CFSTR("apple-edid"));
            if (data)
            {
                UInt32 ids[24] = { 0 };

                UInt32 * p = (UInt32 *) CFDataGetBytePtr(data);
                int i;

                for( i = 0; i < (CFDataGetLength(data)/4); i+=2)
                {
                    UInt32 bit, id;
                    id = p[i];
                    bit = p[i + 1] >> 16;
                    if( bit < 24)
                    {
                        bit = (0x10 - (bit & 0xf8)) | (bit & 7);

                        if( ids[bit])
                            printf("bit %ld, id %ld dup\n", bit, id);
                        else
                            ids[bit] = id;
                    }
                }

                data = CFDataCreate( kCFAllocatorDefault,
                                            (const UInt8 *) ids, sizeof(ids) );
                CFDictionarySetValue( result, CFSTR("established-ids"), data);
                CFRelease(data);
            }
        }
        else
        {
            result = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
                                        &kCFTypeDictionaryKeyCallBacks,
                                        &kCFTypeDictionaryValueCallBacks );
            assert(result);
    
            stdModes = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
                                        &kCFTypeDictionaryKeyCallBacks,
                                        &kCFTypeDictionaryValueCallBacks );
            assert(stdModes);
            timingIDs = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
                                        &kCFTypeDictionaryKeyCallBacks,
                                        &kCFTypeDictionaryValueCallBacks );
            assert(timingIDs);
        }

        count = CFArrayGetCount(modes);
        for (i = 0; i < count; i++)
        {
            SInt32 aid;

            mode = CFArrayGetValueAtIndex(modes, i);

            num = CFDictionaryGetValue(mode, CFSTR(kIOFBModeAIDKey));
            if (num)
                CFNumberGetValue( num, kCFNumberSInt32Type, &aid );
            else
                aid = timingInvalid;

            data = CFDictionaryGetValue(mode, CFSTR(kIOFBModeDMKey));
            if (!data)
                continue;
            modeInfo = (IODisplayModeInformation *) CFDataGetBytePtr(data);

            data = CFDictionaryGetValue(mode, CFSTR(kIOFBModeTMKey));
            if (!data)
                continue;
            timingInfo = (IODetailedTimingInformationV2 *) CFDataGetBytePtr(data);

            printf("%ldx%ld@%ld, %ld\n", modeInfo->nominalWidth, modeInfo->nominalHeight, ((modeInfo->refreshRate + 0x8000) >> 16), aid);

if( timingInfo->horizontalActive & 7) printf("horizontalActive & 7\n");
if( timingInfo->horizontalBlanking & 7) printf("horizontalBlanking & 7\n");
if( timingInfo->horizontalSyncOffset & 7) printf("horizontalSyncOffset & 7\n");
if( timingInfo->horizontalSyncPulseWidth & 7) printf("horizontalSyncPulseWidth & 7\n");


            if( (aid == timingInvalid)
             || (aid == timingInvalid_SM_T24)
             || (aid == timingApple_FixedRateLCD)
             || (aid == timingGTF_640x480_120hz)
             || (aid == timingAppleNTSC_ST)
             || (aid == timingAppleNTSC_FF)
             || (aid == timingAppleNTSC_STconv)
             || (aid == timingAppleNTSC_FFconv)
             || (aid == timingApplePAL_ST)
             || (aid == timingApplePAL_FF)
             || (aid == timingApplePAL_STconv)
             || (aid == timingApplePAL_FFconv)
             || (aid == timingSMPTE240M_60hz)
             || (aid == timingFilmRate_48hz)
             || (aid == timingApple_0x0_0hz_Offline))
             continue;

if(modeInfo->flags & (1<<kModeShowNever)) 
{
    printf("nv!\n");
    continue;
}

            if( true
             && (aid != timingApple_1024x768_75hz)
             )
            {

                if( aid == timingVESA_640x480_72hz)
                    modeInfo->refreshRate = 72 << 16;   // from 72.8

                sprintf(key, "%ld", ((modeInfo->nominalWidth << 20) | (modeInfo->nominalHeight << 8) | ((modeInfo->refreshRate + 0x8000) >> 16)));

                cfStr =  CFStringCreateWithCString( kCFAllocatorDefault, key,
                                                            kCFStringEncodingMacRoman );
                if (CFDictionaryGetValue( timingIDs, cfStr ))
                    printf("%ld timing id dup\n", aid);
                else
                {
                    printf("ADDING\n");
                    CFDictionarySetValue( timingIDs, cfStr, num );
                }
            }

            sprintf(key, "%ld", aid);

            cfStr =  CFStringCreateWithCString( kCFAllocatorDefault, key,
                                                        kCFStringEncodingMacRoman );

            keys  [0] = CFSTR(kIOFBModeTMKey);
            values[0] = data;
            keys  [1] = CFSTR(kIOFBModeAIDKey);
            values[1] = num;

            dict = CFDictionaryCreate( kCFAllocatorDefault, keys, values, 1, 
                                        &kCFTypeDictionaryKeyCallBacks,
                                        &kCFTypeDictionaryValueCallBacks );

            assert(dict);

            if (CFDictionaryGetValue( stdModes, cfStr ))
                printf("%ld timing id dup\n", aid);
            else
            {
                printf("ADDING\n");
                CFDictionarySetValue( stdModes, cfStr, dict );
            }
            CFRelease(dict);

        }

        CFDictionarySetValue(result, CFSTR("std-modes"), stdModes);
        CFDictionarySetValue(result, CFSTR("timing-ids"), timingIDs);

        data = CFPropertyListCreateXMLData( kCFAllocatorDefault, result );
        if (data)
        {
            char * str = (char *) CFDataGetBytePtr(data);
            str[CFDataGetLength(data)] = 0;
            printf( str );
        }

    }
    
    exit(0);
    return(0);
}