1// cc -o /tmp/modesuck -g modesuck.c -framework ApplicationServices -framework IOKit -Wall
2
3
4#include <mach/mach.h>
5#include <mach/thread_switch.h>
6#include <sys/file.h>
7#include <sys/stat.h>
8#include <math.h>
9#include <unistd.h>
10#include <string.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <assert.h>
14
15#include <IOKit/IOKitLib.h>
16#include <IOKit/graphics/IOGraphicsTypesPrivate.h>
17#include <ApplicationServices/ApplicationServices.h>
18
19
20__private_extern__ IOReturn
21readFile(const char *path, vm_offset_t * objAddr, vm_size_t * objSize)
22{
23    int fd;
24    int err;
25    struct stat stat_buf;
26
27    *objAddr = 0;
28    *objSize = 0;
29
30    if((fd = open(path, O_RDONLY)) == -1)
31        return errno;
32
33    do {
34        if(fstat(fd, &stat_buf) == -1) {
35            err = errno;
36            continue;
37        }
38        if (0 == (stat_buf.st_mode & S_IFREG))
39        {
40            *objAddr = 0;
41            *objSize = 0;
42            err = kIOReturnNotReadable;
43            continue;
44        }
45        *objSize = stat_buf.st_size;
46
47        if( KERN_SUCCESS != map_fd(fd, 0, objAddr, TRUE, *objSize)) {
48            *objAddr = 0;
49            *objSize = 0;
50            err = errno;
51            continue;
52        }
53
54        err = kIOReturnSuccess;
55
56    } while( false );
57
58    close(fd);
59
60    return( err );
61}
62
63__private_extern__ CFMutableDictionaryRef
64readPlist( const char * path, UInt32 key )
65{
66    IOReturn                    err;
67    vm_offset_t                 bytes;
68    vm_size_t                   byteLen;
69    CFDataRef                   data;
70    CFMutableDictionaryRef      obj = 0;
71
72    err = readFile( path, &bytes, &byteLen );
73
74    if( kIOReturnSuccess != err)
75        return (0);
76
77    data = CFDataCreateWithBytesNoCopy( kCFAllocatorDefault,
78                                (const UInt8 *) bytes, byteLen, kCFAllocatorNull );
79    if( data) {
80        obj = (CFMutableDictionaryRef) CFPropertyListCreateFromXMLData( kCFAllocatorDefault, data,
81                                            kCFPropertyListMutableContainers,
82                                            (CFStringRef *) NULL );
83        CFRelease( data );
84    }
85    vm_deallocate( mach_task_self(), bytes, byteLen );
86
87    return (obj);
88}
89
90int main(int argc, char * argv[])
91{
92    io_service_t                framebuffer;
93    CGError                     err;
94    int                         i;
95    CGDisplayCount              max;
96    CGDirectDisplayID           displayIDs[8];
97    IODisplayModeInformation *  modeInfo;
98    IODetailedTimingInformationV2 *timingInfo;
99
100    CFDictionaryRef             dict;
101    CFArrayRef                  modes;
102    CFIndex                     count;
103    CFDictionaryRef             mode;
104    CFMutableDictionaryRef      result, stdModes, timingIDs;
105    CFDataRef                   data;
106    CFNumberRef                 num;
107    CFStringRef                 cfStr;
108    char                        key[64];
109    const void *                keys[2];
110    const void *                values[2];
111
112    err = CGGetOnlineDisplayList(8, displayIDs, &max);
113    if(err != kCGErrorSuccess)
114        exit(1);
115    if(max > 8)
116        max = 8;
117
118    for(i = 0; i < max; i++ ) {
119
120        framebuffer = CGDisplayIOServicePort(displayIDs[i]);
121
122        dict = IORegistryEntryCreateCFProperty(framebuffer, CFSTR(kIOFBConfigKey),
123                                                kCFAllocatorDefault, kNilOptions);
124        assert(dict);
125
126        modes = CFDictionaryGetValue(dict, CFSTR(kIOFBModesKey));
127        assert(modes);
128
129
130        result = readPlist("/System/Library/Frameworks/IOKit.framework/"
131                                    "Resources/IOGraphicsProperties.plist", 0);
132
133        if (result)
134        {
135            stdModes = (CFMutableDictionaryRef) CFDictionaryGetValue(result, CFSTR("std-modes"));
136            assert(stdModes);
137            timingIDs = (CFMutableDictionaryRef) CFDictionaryGetValue(result, CFSTR("timing-ids"));
138            assert(timingIDs);
139
140            data = CFDictionaryGetValue(result, CFSTR("apple-edid"));
141            if (data)
142            {
143                UInt32 ids[24] = { 0 };
144
145                UInt32 * p = (UInt32 *) CFDataGetBytePtr(data);
146                int i;
147
148                for( i = 0; i < (CFDataGetLength(data)/4); i+=2)
149                {
150                    UInt32 bit, id;
151                    id = p[i];
152                    bit = p[i + 1] >> 16;
153                    if( bit < 24)
154                    {
155                        bit = (0x10 - (bit & 0xf8)) | (bit & 7);
156
157                        if( ids[bit])
158                            printf("bit %ld, id %ld dup\n", bit, id);
159                        else
160                            ids[bit] = id;
161                    }
162                }
163
164                data = CFDataCreate( kCFAllocatorDefault,
165                                            (const UInt8 *) ids, sizeof(ids) );
166                CFDictionarySetValue( result, CFSTR("established-ids"), data);
167                CFRelease(data);
168            }
169        }
170        else
171        {
172            result = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
173                                        &kCFTypeDictionaryKeyCallBacks,
174                                        &kCFTypeDictionaryValueCallBacks );
175            assert(result);
176
177            stdModes = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
178                                        &kCFTypeDictionaryKeyCallBacks,
179                                        &kCFTypeDictionaryValueCallBacks );
180            assert(stdModes);
181            timingIDs = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
182                                        &kCFTypeDictionaryKeyCallBacks,
183                                        &kCFTypeDictionaryValueCallBacks );
184            assert(timingIDs);
185        }
186
187        count = CFArrayGetCount(modes);
188        for (i = 0; i < count; i++)
189        {
190            SInt32 aid;
191
192            mode = CFArrayGetValueAtIndex(modes, i);
193
194            num = CFDictionaryGetValue(mode, CFSTR(kIOFBModeAIDKey));
195            if (num)
196                CFNumberGetValue( num, kCFNumberSInt32Type, &aid );
197            else
198                aid = timingInvalid;
199
200            data = CFDictionaryGetValue(mode, CFSTR(kIOFBModeDMKey));
201            if (!data)
202                continue;
203            modeInfo = (IODisplayModeInformation *) CFDataGetBytePtr(data);
204
205            data = CFDictionaryGetValue(mode, CFSTR(kIOFBModeTMKey));
206            if (!data)
207                continue;
208            timingInfo = (IODetailedTimingInformationV2 *) CFDataGetBytePtr(data);
209
210            printf("%ldx%ld@%ld, %ld\n", modeInfo->nominalWidth, modeInfo->nominalHeight, ((modeInfo->refreshRate + 0x8000) >> 16), aid);
211
212if( timingInfo->horizontalActive & 7) printf("horizontalActive & 7\n");
213if( timingInfo->horizontalBlanking & 7) printf("horizontalBlanking & 7\n");
214if( timingInfo->horizontalSyncOffset & 7) printf("horizontalSyncOffset & 7\n");
215if( timingInfo->horizontalSyncPulseWidth & 7) printf("horizontalSyncPulseWidth & 7\n");
216
217
218            if( (aid == timingInvalid)
219             || (aid == timingInvalid_SM_T24)
220             || (aid == timingApple_FixedRateLCD)
221             || (aid == timingGTF_640x480_120hz)
222             || (aid == timingAppleNTSC_ST)
223             || (aid == timingAppleNTSC_FF)
224             || (aid == timingAppleNTSC_STconv)
225             || (aid == timingAppleNTSC_FFconv)
226             || (aid == timingApplePAL_ST)
227             || (aid == timingApplePAL_FF)
228             || (aid == timingApplePAL_STconv)
229             || (aid == timingApplePAL_FFconv)
230             || (aid == timingSMPTE240M_60hz)
231             || (aid == timingFilmRate_48hz)
232             || (aid == timingApple_0x0_0hz_Offline))
233             continue;
234
235if(modeInfo->flags & (1<<kModeShowNever))
236{
237    printf("nv!\n");
238    continue;
239}
240
241            if( true
242             && (aid != timingApple_1024x768_75hz)
243             )
244            {
245
246                if( aid == timingVESA_640x480_72hz)
247                    modeInfo->refreshRate = 72 << 16;   // from 72.8
248
249                sprintf(key, "%ld", ((modeInfo->nominalWidth << 20) | (modeInfo->nominalHeight << 8) | ((modeInfo->refreshRate + 0x8000) >> 16)));
250
251                cfStr =  CFStringCreateWithCString( kCFAllocatorDefault, key,
252                                                            kCFStringEncodingMacRoman );
253                if (CFDictionaryGetValue( timingIDs, cfStr ))
254                    printf("%ld timing id dup\n", aid);
255                else
256                {
257                    printf("ADDING\n");
258                    CFDictionarySetValue( timingIDs, cfStr, num );
259                }
260            }
261
262            sprintf(key, "%ld", aid);
263
264            cfStr =  CFStringCreateWithCString( kCFAllocatorDefault, key,
265                                                        kCFStringEncodingMacRoman );
266
267            keys  [0] = CFSTR(kIOFBModeTMKey);
268            values[0] = data;
269            keys  [1] = CFSTR(kIOFBModeAIDKey);
270            values[1] = num;
271
272            dict = CFDictionaryCreate( kCFAllocatorDefault, keys, values, 1,
273                                        &kCFTypeDictionaryKeyCallBacks,
274                                        &kCFTypeDictionaryValueCallBacks );
275
276            assert(dict);
277
278            if (CFDictionaryGetValue( stdModes, cfStr ))
279                printf("%ld timing id dup\n", aid);
280            else
281            {
282                printf("ADDING\n");
283                CFDictionarySetValue( stdModes, cfStr, dict );
284            }
285            CFRelease(dict);
286
287        }
288
289        CFDictionarySetValue(result, CFSTR("std-modes"), stdModes);
290        CFDictionarySetValue(result, CFSTR("timing-ids"), timingIDs);
291
292        data = CFPropertyListCreateXMLData( kCFAllocatorDefault, result );
293        if (data)
294        {
295            char * str = (char *) CFDataGetBytePtr(data);
296            str[CFDataGetLength(data)] = 0;
297            printf( str );
298        }
299
300    }
301
302    exit(0);
303    return(0);
304}
305