1/*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <sys/cdefs.h>
25
26#include <mach/mach.h>
27#include <mach/thread_switch.h>
28#include <sys/file.h>
29#include <sys/stat.h>
30#include <sys/mman.h>
31#include <unistd.h>
32#include <string.h>
33#include <stdlib.h>
34#include <libc.h>
35
36#include <CoreFoundation/CoreFoundation.h>
37#include <CoreFoundation/CFBundlePriv.h>
38
39#include <IOKit/IOKitLib.h>
40#include <libkern/OSByteOrder.h>
41#include <IOKit/graphics/IOGraphicsLib.h>
42#include <IOKit/graphics/IOGraphicsLibPrivate.h>
43#include <IOKit/graphics/IOGraphicsTypesPrivate.h>
44#include <IOKit/graphics/IOGraphicsEngine.h>
45
46#include "IOGraphicsLibInternal.h"
47
48#define DEBUGPARAMS             0
49
50
51/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
52
53__private_extern__ IOReturn
54readFile(const char *path, vm_address_t * objAddr, vm_size_t * objSize);
55__private_extern__ CFMutableDictionaryRef
56readPlist( const char * path, UInt32 key );
57__private_extern__ Boolean
58writePlist( const char * path, CFMutableDictionaryRef dict, UInt32 key __unused );
59
60static char gIODisplayBoardID[256] = { 0 };
61
62/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
63
64static void
65setDictionaryDisplayIconValue(CFMutableDictionaryRef dst, CFDictionaryRef src)
66{
67    CFTypeRef value = NULL;
68    if (CFDictionaryGetValueIfPresent(src, CFSTR("display-icon"), (const void**)&value))
69        CFDictionarySetValue(dst, CFSTR("display-icon"), value);
70}
71
72static void
73setDictionaryDisplayResolutionPreviewValues(CFMutableDictionaryRef dst, CFDictionaryRef src)
74{
75    CFTypeRef value = NULL;
76    if (CFDictionaryGetValueIfPresent(src, CFSTR("display-resolution-preview-icon"), (const void**)&value))
77        CFDictionarySetValue(dst, CFSTR("display-resolution-preview-icon"), value);
78    if (CFDictionaryGetValueIfPresent(src, CFSTR("resolution-preview-x"), (const void**)&value))
79        CFDictionarySetValue(dst, CFSTR("resolution-preview-x"), value);
80    if (CFDictionaryGetValueIfPresent(src, CFSTR("resolution-preview-y"), (const void**)&value))
81        CFDictionarySetValue(dst, CFSTR("resolution-preview-y"), value);
82    if (CFDictionaryGetValueIfPresent(src, CFSTR("resolution-preview-width"), (const void**)&value))
83        CFDictionarySetValue(dst, CFSTR("resolution-preview-width"), value);
84    if (CFDictionaryGetValueIfPresent(src, CFSTR("resolution-preview-height"), (const void**)&value))
85        CFDictionarySetValue(dst, CFSTR("resolution-preview-height"), value);
86}
87
88
89static CFMutableDictionaryRef
90IODisplayCreateOverrides( io_service_t framebuffer, IOOptionBits options,
91                            IODisplayVendorID vendor, IODisplayProductID product,
92                            UInt32 serialNumber __unused,
93                            uint32_t manufactureYear,
94                            uint32_t manufactureWeek,
95                            Boolean isDigital )
96{
97
98    char                        path[256];
99    CFTypeRef                   obj = 0;
100    CFMutableDictionaryRef      dict = 0;
101
102    if( 0 == (options & kIODisplayMatchingInfo)) {
103
104        snprintf( path, sizeof(path), "/System/Library/Displays/Overrides"
105                        "/" kDisplayVendorID "-%x"
106                        "/" kDisplayProductID "-%x",
107                        (unsigned) vendor, (unsigned) product );
108
109        obj = readPlist( path, ((vendor & 0xffff) << 16) | (product & 0xffff) );
110
111	if ((!obj) && manufactureYear && manufactureWeek)
112	{
113	    snprintf( path, sizeof(path), "/System/Library/Displays/Overrides"
114			    "/" kDisplayVendorID "-%x"
115			    "/" kDisplayYearOfManufacture "-%d"
116			    "-" kDisplayWeekOfManufacture "-%d",
117			    (unsigned) vendor,
118			    manufactureYear, manufactureWeek );
119	    obj = readPlist( path, ((vendor & 0xffff) << 16) | (product & 0xffff) );
120	}
121        if (obj)
122        {
123            if( CFDictionaryGetTypeID() == CFGetTypeID( obj ))
124            {
125                dict = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, obj);
126            }
127            else if( CFArrayGetTypeID() == CFGetTypeID( obj ))
128            {
129                CFArrayRef      array;
130                CFIndex         count, idx;
131                CFTypeRef       obj2;
132                CFDictionaryRef matching, candidate;
133
134                // look for a matching override
135                array = obj;
136                candidate = 0;
137                count = CFArrayGetCount(array);
138                for (idx = 0; idx < count; idx++, candidate = 0)
139                {
140                    obj2 = CFArrayGetValueAtIndex(array, idx);
141                    if (CFDictionaryGetTypeID() != CFGetTypeID(obj2))
142                        continue;
143                    candidate = obj2;
144                    matching = CFDictionaryGetValue(candidate, CFSTR(kIODisplayOverrideMatchingKey));
145                    if (!matching)
146                        break;
147                    if (CFDictionaryGetTypeID() != CFGetTypeID(matching))
148                        continue;
149
150                    obj2 = CFDictionaryGetValue(matching, CFSTR(kIODisplayIsDigitalKey));
151                    if ((obj2 == kCFBooleanTrue) && !isDigital)
152                        continue;
153                    if ((obj2 == kCFBooleanFalse) && isDigital)
154                        continue;
155
156                    break;
157                }
158                if (candidate)
159                    dict = CFDictionaryCreateMutableCopy( kCFAllocatorDefault, 0, candidate);
160            }
161            CFRelease( obj );
162        }
163    }
164    if( !dict)
165        dict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
166                    &kCFTypeDictionaryKeyCallBacks,
167                    &kCFTypeDictionaryValueCallBacks);
168
169    if( dict) do {
170        CFStringRef string;
171        CFURLRef   url;
172        CFBundleRef bdl;
173
174        if((kIODisplayMatchingInfo | kIODisplayNoProductName) & options)
175            continue;
176
177        snprintf( path, sizeof(path), "/System/Library/Displays/Overrides");
178//                            "/" kDisplayVendorID "-%lx", vendor );
179
180        string = CFStringCreateWithCString( kCFAllocatorDefault, path,
181                                            kCFStringEncodingMacRoman );
182        if( !string)
183            continue;
184        url = CFURLCreateWithFileSystemPath( kCFAllocatorDefault, string,
185        									 kCFURLPOSIXPathStyle, true );
186        CFRelease(string);
187        if( !url)
188            continue;
189        bdl = CFBundleCreate( kCFAllocatorDefault, url);
190        if( bdl) {
191            CFDictionarySetValue( dict, CFSTR(kDisplayBundleKey), bdl);
192            CFRelease(bdl);
193        }
194        CFRelease(url);
195
196    } while( false );
197
198    if (dict) {
199        if (gIODisplayBoardID[0] == 0) {
200            io_registry_entry_t ioRegRoot = IORegistryGetRootEntry(kIOMasterPortDefault);
201            if (ioRegRoot) {
202                CFDataRef boardId = (CFDataRef) IORegistryEntrySearchCFProperty(ioRegRoot,
203                                                                                kIOServicePlane,
204                                                                                CFSTR("board-id"),
205                                                                                kCFAllocatorDefault,
206                                                                                kIORegistryIterateRecursively);
207                IOObjectRelease(ioRegRoot);
208                if (boardId) {
209                	size_t len = CFDataGetLength(boardId);
210                	if (len > sizeof(gIODisplayBoardID)) len = sizeof(gIODisplayBoardID);
211                    strlcpy(gIODisplayBoardID, (const char *) CFDataGetBytePtr(boardId), len);
212                    CFRelease(boardId);
213                }
214            }
215        }
216
217        CFDataRef builtin = (CFDataRef) IORegistryEntryCreateCFProperty(framebuffer,
218                                                                        CFSTR(kIOFBBuiltInKey),
219                                                                        kCFAllocatorDefault, kNilOptions);
220
221        CFMutableDictionaryRef iconDict = NULL;
222        if (access("/System/Library/Displays/Overrides/Icons.plist", F_OK) == 0)
223            iconDict = readPlist("/System/Library/Displays/Overrides/Icons.plist", 0);
224
225        CFStringRef vendorIdString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%x"), vendor);
226        CFStringRef deviceIdString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%x"), product);
227        CFStringRef modelString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s"), gIODisplayBoardID);
228
229        snprintf(path, sizeof(path), "/System/Library/Displays/Overrides"
230                 "/" kDisplayVendorID "-%x"
231                 "/" kDisplayProductID "-%x-%s.icns",
232                 (unsigned)vendor, (unsigned)product, gIODisplayBoardID);
233
234        Boolean foundIcon = false;
235        if (access(path, F_OK) == 0)
236            foundIcon = true;
237
238        if (!foundIcon) {
239            snprintf(path, sizeof(path), "/System/Library/Displays/Overrides"
240                     "/" kDisplayVendorID "-%x"
241                     "/" kDisplayYearOfManufacture "-%d"
242                     "-" kDisplayWeekOfManufacture "-%d-%s.icns",
243                     (unsigned)vendor,
244                     manufactureYear, manufactureWeek, gIODisplayBoardID);
245
246            if (access(path, F_OK) == 0)
247                foundIcon = true;
248        }
249
250        CFStringRef productModelDisplayIconFilePath = NULL;
251        if (foundIcon)
252            productModelDisplayIconFilePath = CFStringCreateWithFileSystemRepresentation(kCFAllocatorDefault, path);
253
254        CFStringRef modelDisplayIconFilePath = NULL;
255        if (builtin) {
256            snprintf(path, sizeof(path), "/System/Library/Displays/Overrides/Models/%s.icns", gIODisplayBoardID);
257
258            if (access(path, F_OK) == 0)
259                modelDisplayIconFilePath = CFStringCreateWithFileSystemRepresentation(kCFAllocatorDefault, path);
260        }
261
262        snprintf(path, sizeof(path), "/System/Library/Displays/Overrides"
263                 "/" kDisplayVendorID "-%x"
264                 "/" kDisplayProductID "-%x.icns",
265                 (unsigned)vendor, (unsigned)product);
266
267        foundIcon = false;
268        if (access(path, F_OK) == 0)
269            foundIcon = true;
270
271        if (!foundIcon) {
272            snprintf(path, sizeof(path), "/System/Library/Displays/Overrides"
273                     "/" kDisplayVendorID "-%x"
274                     "/" kDisplayYearOfManufacture "-%d"
275                     "-" kDisplayWeekOfManufacture "-%d.icns",
276                     (unsigned)vendor,
277                     manufactureYear, manufactureWeek);
278
279            if (access(path, F_OK) == 0)
280                foundIcon = true;
281        }
282
283        CFStringRef productDisplayIconFilePath = NULL;
284        if (foundIcon)
285            productDisplayIconFilePath = CFStringCreateWithFileSystemRepresentation(kCFAllocatorDefault, path);
286
287
288        snprintf(path, sizeof(path), "/System/Library/Displays/Overrides"
289                 "/" kDisplayVendorID "-%x.icns",
290                 (unsigned)vendor);
291
292        CFStringRef vendorDisplayIconFilePath = NULL;
293        if (access(path, F_OK) == 0)
294            vendorDisplayIconFilePath = CFStringCreateWithFileSystemRepresentation(kCFAllocatorDefault, path);
295
296        CFMutableDictionaryRef displayDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
297
298        CFMutableDictionaryRef modelIdsDict = NULL;
299        if (iconDict && builtin && CFDictionaryGetValueIfPresent(iconDict, CFSTR("board-ids"), (const void**)&modelIdsDict)) {
300            CFMutableDictionaryRef modelDict = NULL;
301            if (CFDictionaryGetValueIfPresent(modelIdsDict, modelString, (const void**)&modelDict)) {
302                setDictionaryDisplayIconValue(displayDict, modelDict);
303                setDictionaryDisplayResolutionPreviewValues(displayDict, modelDict);
304            }
305        }
306
307        if (builtin && !CFDictionaryContainsKey(displayDict, CFSTR("display-icon")) && modelDisplayIconFilePath)
308            CFDictionarySetValue(dict, CFSTR("display-icon"), vendorDisplayIconFilePath);
309
310        CFMutableDictionaryRef vendorIdsDict = NULL;
311        if (iconDict && CFDictionaryGetValueIfPresent(iconDict, CFSTR("vendors"), (const void**)&vendorIdsDict)) {
312            CFMutableDictionaryRef vendorDict = NULL;
313            if (CFDictionaryGetValueIfPresent(vendorIdsDict, vendorIdString, (const void**)&vendorDict)) {
314                CFMutableDictionaryRef displayIdsDict = NULL;
315                if (CFDictionaryGetValueIfPresent(vendorDict, CFSTR("products"), (const void**)&displayIdsDict)) {
316                    CFMutableDictionaryRef deviceDict = NULL;
317                    if (CFDictionaryGetValueIfPresent(displayIdsDict, deviceIdString, (const void**)&deviceDict)) {
318                        if (builtin && CFDictionaryGetValueIfPresent(deviceDict, CFSTR("board-ids"), (const void**)&modelIdsDict)) {
319                            CFMutableDictionaryRef modelDict = NULL;
320                            if (CFDictionaryGetValueIfPresent(modelIdsDict, modelString, (const void**)&modelDict)) {
321                                setDictionaryDisplayIconValue(displayDict, modelDict);
322                                setDictionaryDisplayResolutionPreviewValues(displayDict, modelDict);
323
324                                if (!CFDictionaryContainsKey(displayDict, CFSTR("display-icon")) && productModelDisplayIconFilePath)
325                                    CFDictionarySetValue(displayDict, CFSTR("display-icon"), productModelDisplayIconFilePath);
326                            }
327                        }
328
329                        if (!builtin) {
330                            if (!CFDictionaryContainsKey(displayDict, CFSTR("display-icon")))
331                                setDictionaryDisplayIconValue(displayDict, deviceDict);
332
333                            if (!CFDictionaryContainsKey(displayDict, CFSTR("display-icon")) && productDisplayIconFilePath)
334                                CFDictionarySetValue(displayDict, CFSTR("display-icon"), productDisplayIconFilePath);
335
336                            if (!CFDictionaryContainsKey(displayDict, CFSTR("display-resolution-preview-icon")))
337                                setDictionaryDisplayResolutionPreviewValues(displayDict, deviceDict);
338                        }
339                    }
340                }
341
342                if (!builtin) {
343                    if (!CFDictionaryContainsKey(displayDict, CFSTR("display-icon")) && productDisplayIconFilePath)
344                        CFDictionarySetValue(displayDict, CFSTR("display-icon"), productDisplayIconFilePath);
345
346                    if (!CFDictionaryContainsKey(displayDict, CFSTR("display-icon")))
347                        setDictionaryDisplayIconValue(displayDict, vendorDict);
348
349                    if (!CFDictionaryContainsKey(displayDict, CFSTR("display-icon")) && vendorDisplayIconFilePath)
350                        CFDictionarySetValue(displayDict, CFSTR("display-icon"), vendorDisplayIconFilePath);
351
352                    if (!CFDictionaryContainsKey(displayDict, CFSTR("display-resolution-preview-icon")))
353                        setDictionaryDisplayResolutionPreviewValues(displayDict, vendorDict);
354                }
355            }
356
357            if (!builtin) {
358                if (!CFDictionaryContainsKey(displayDict, CFSTR("display-icon")) && productDisplayIconFilePath)
359                    CFDictionarySetValue(displayDict, CFSTR("display-icon"), productDisplayIconFilePath);
360
361                if (!CFDictionaryContainsKey(displayDict, CFSTR("display-icon")) && vendorDisplayIconFilePath)
362                    CFDictionarySetValue(displayDict, CFSTR("display-icon"), vendorDisplayIconFilePath);
363
364                if (!CFDictionaryContainsKey(displayDict, CFSTR("display-icon")))
365                    setDictionaryDisplayIconValue(displayDict, vendorIdsDict);
366            }
367        }
368
369        setDictionaryDisplayIconValue(dict, displayDict);
370        setDictionaryDisplayResolutionPreviewValues(dict, displayDict);
371
372        CFRelease(displayDict);
373
374        if (iconDict)
375          CFRelease(iconDict);
376
377        if (builtin)
378            CFRelease(builtin);
379
380        if (vendorDisplayIconFilePath)
381            CFRelease(vendorDisplayIconFilePath);
382
383        if (productDisplayIconFilePath)
384            CFRelease(productDisplayIconFilePath);
385
386        if (modelDisplayIconFilePath)
387            CFRelease(modelDisplayIconFilePath);
388
389        if (productModelDisplayIconFilePath)
390            CFRelease(productModelDisplayIconFilePath);
391
392        CFRelease(modelString);
393        CFRelease(deviceIdString);
394        CFRelease(vendorIdString);
395    }
396
397    return( dict );
398}
399
400static void
401EDIDInfo( struct EDID * edid,
402            IODisplayVendorID * vendor, IODisplayProductID * product,
403            UInt32 * serialNumber,
404            uint32_t * manufactureYear, uint32_t * manufactureWeek,
405            Boolean * isDigital )
406{
407    SInt32              sint;
408
409    if (vendor)
410        *vendor = (edid->vendorProduct[0] << 8) | edid->vendorProduct[1];
411    if (product)
412        *product = (edid->vendorProduct[3] << 8) | edid->vendorProduct[2];
413    if (isDigital)
414        *isDigital = (0 != (0x80 & edid->displayParams[0]));
415
416    if( serialNumber) {
417        sint = (edid->serialNumber[3] << 24)
418             | (edid->serialNumber[2] << 16)
419             | (edid->serialNumber[1] << 8)
420             | (edid->serialNumber[0]);
421        if( sint == 0x01010101)
422            sint = 0;
423        *serialNumber = sint;
424    }
425
426    if (manufactureYear) *manufactureYear = edid->yearOfManufacture + 1990;
427    if (manufactureWeek) *manufactureWeek = edid->weekOfManufacture;
428}
429
430__private_extern__ Boolean
431IODisplayEDIDName( EDID * edid, char * name )
432{
433    char *      oname = name;
434    EDIDDesc *  desc;
435    int         i,j;
436    Boolean     ok;
437    char        c;
438
439    if( !edid || (edid->version < 1) || (edid->revision < 1))
440        return( false );
441
442    desc = edid->descriptors;
443    for( i = 0; i < 4; i++, desc++) {
444        if( desc->general.flag1 || desc->general.flag2 || desc->general.flag3)
445            continue;
446        if( 0xfc != desc->general.type)
447            continue;
448
449        for( j = 0; j < (int) sizeof(desc->general.data); j++) {
450            c = desc->general.data[j];
451            if( c != 0x0a)
452                *oname++ = c;
453            else
454                break;
455        }
456    }
457    ok = (oname != name);
458    if( ok)
459        *oname++ = 0;
460
461    return( ok );
462}
463
464struct MakeOneLocalContext {
465    CFBundleRef            bdl;
466    CFMutableDictionaryRef dict;
467    CFStringRef            key;
468};
469
470static void MakeOneLocalization( const void * item, void * context )
471{
472    struct MakeOneLocalContext * ctx = (struct MakeOneLocalContext *) context;
473    CFStringRef         value = NULL;
474    CFDictionaryRef     stringTable = NULL;
475    CFURLRef            url;
476    CFDataRef           tableData = NULL;
477    CFStringRef         errStr;
478    SInt32              errCode;
479
480    url = CFBundleCopyResourceURLForLocalization( ctx->bdl,
481                                CFSTR("Localizable"), CFSTR("strings"), NULL, item );
482    if (url && CFURLCreateDataAndPropertiesFromResource( kCFAllocatorDefault,
483                                url, &tableData, NULL, NULL, &errCode)) {
484        stringTable = CFPropertyListCreateFromXMLData( kCFAllocatorDefault,
485                                tableData, kCFPropertyListImmutable, &errStr);
486        if (errStr)
487            CFRelease( errStr);
488        CFRelease( tableData);
489    }
490    if( url)
491        CFRelease(url);
492    if( stringTable)
493        value = CFDictionaryGetValue(stringTable, ctx->key);
494    if (!value)
495        value = ctx->key;
496
497    {
498        SInt32           languageCode, regionCode, scriptCode;
499        CFStringEncoding stringEncoding;
500        if( CFBundleGetLocalizationInfoForLocalization( item, &languageCode, &regionCode,
501                                                        &scriptCode, &stringEncoding )) {
502            item = CFBundleCopyLocalizationForLocalizationInfo( languageCode, regionCode,
503                                                        scriptCode, stringEncoding );
504        } else
505            item = CFRetain(item);
506    }
507
508    CFDictionarySetValue( ctx->dict, item, value );
509    CFRelease( item );
510
511    if( stringTable)
512        CFRelease( stringTable );
513}
514
515static void GenerateProductName( CFMutableDictionaryRef dict,
516                                        EDID * edid, SInt32 displayType, IOOptionBits options )
517{
518    CFStringRef         key;
519    CFBundleRef         bdl;
520    CFArrayRef          localizations;
521    struct MakeOneLocalContext ctx;
522    static const char * type2Name[] = {
523        NULL,                           // 000 kUnknownConnect
524        NULL,                           // 001 kUnknownConnect
525        "Color LCD",                    // 002 kPanelTFTConnect
526        NULL,                           // 003 kFixedModeCRTConnect
527        "Multiple Scan Display",        // 004 kMultiModeCRT1Connect
528        "Multiple Scan Display",        // 005 kMultiModeCRT2Connect
529        "Multiple Scan Display",        // 006 kMultiModeCRT3Connect
530        "Multiple Scan Display",        // 007 kMultiModeCRT4Connect
531        NULL,                           // 008 kModelessConnect
532        "Full-Page Display",            // 009 kFullPageConnect
533        "VGA Display",                  // 010 kVGAConnect
534        "Television",                   // 011 kNTSCConnect
535        "Television",                   // 012 kPALConnect
536        NULL,                           // 013 kHRConnect
537        "Color LCD",                    // 014 kPanelFSTNConnect
538        "Two-Page Display",             // 015 kMonoTwoPageConnect
539        "Two-Page Display",             // 016 kColorTwoPageConnect
540        NULL,                           // 017 kColor16Connect
541        NULL,                           // 018 kColor19Connect
542        NULL,                           // 019 kGenericCRT
543        "Color LCD",                    // 020 kGenericLCD
544        NULL,                           // 021 kDDCConnect
545        NULL                            // 022 kNoConnect
546    };
547
548    key = CFDictionaryGetValue( dict, CFSTR(kDisplayProductName));
549    if( key) {
550        if( CFStringGetTypeID() != CFGetTypeID( key ))
551            return;
552        CFRetain(key);
553    }
554    bdl = (CFBundleRef) CFDictionaryGetValue( dict, CFSTR(kDisplayBundleKey));
555
556    if( !key) {
557        char sbuf[ 128 ];
558        const char * name = NULL;
559
560        if( IODisplayEDIDName(edid, sbuf))
561            name = sbuf;
562        else if (edid)
563            name = "Unknown Display";
564        else {
565
566            if( displayType < (int) (sizeof( type2Name) / sizeof(type2Name[0])))
567                name = type2Name[displayType];
568            if( !name)
569                name = "Unknown Display";
570        }
571
572        key = CFStringCreateWithCString( kCFAllocatorDefault, name,
573                                            kCFStringEncodingMacRoman );
574        if( !key)
575            return;
576    }
577
578    if( bdl) {
579        localizations = CFBundleCopyBundleLocalizations( bdl);
580        if (localizations)
581        {
582            ctx.bdl = bdl;
583            ctx.dict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
584                            &kCFTypeDictionaryKeyCallBacks,
585                            &kCFTypeDictionaryValueCallBacks);
586            ctx.key = key;
587
588            if( kIODisplayOnlyPreferredName & options) {
589                CFArrayRef temp = localizations;
590                localizations = CFBundleCopyPreferredLocalizationsFromArray( temp );
591                CFRelease( temp );
592            }
593
594            CFArrayApplyFunction( localizations,
595                                CFRangeMake(0, CFArrayGetCount(localizations)),
596                                &MakeOneLocalization,
597                                &ctx);
598            CFDictionarySetValue( dict, CFSTR(kDisplayProductName), ctx.dict);
599
600            CFRelease( localizations );
601            CFRelease( ctx.dict );
602        }
603    }
604    CFRelease( key );
605}
606
607static void
608MaxTimingRangeRec( IODisplayTimingRange * range )
609{
610    bzero( range, sizeof( IODisplayTimingRange) );
611
612    range->supportedSyncFlags                   = 0xffffffff;
613    range->supportedSignalLevels                = 0xffffffff;
614    range->supportedSignalConfigs               = 0xffffffff;
615
616    range->maxFrameRate                         = 0xffffffff;
617    range->maxLineRate                          = 0xffffffff;
618    range->maxPixelClock                        = 0xffffffff;
619    range->maxPixelError                        = 0xffffffff;
620
621    range->maxHorizontalTotal                   = 0xffffffff;
622    range->maxVerticalTotal                     = 0xffffffff;
623    range->maxHorizontalActiveClocks            = 0xffffffff;
624    range->maxHorizontalBlankingClocks          = 0xffffffff;
625    range->maxHorizontalSyncOffsetClocks        = 0xffffffff;
626    range->maxHorizontalPulseWidthClocks        = 0xffffffff;
627    range->maxVerticalActiveClocks              = 0xffffffff;
628    range->maxVerticalBlankingClocks            = 0xffffffff;
629    range->maxVerticalSyncOffsetClocks          = 0xffffffff;
630    range->maxVerticalPulseWidthClocks          = 0xffffffff;
631    range->maxHorizontalBorderLeft              = 0xffffffff;
632    range->maxHorizontalBorderRight             = 0xffffffff;
633    range->maxVerticalBorderTop                 = 0xffffffff;
634    range->maxVerticalBorderBottom              = 0xffffffff;
635
636    range->charSizeHorizontalActive             = 1;
637    range->charSizeHorizontalBlanking           = 1;
638    range->charSizeHorizontalSyncOffset         = 1;
639    range->charSizeHorizontalSyncPulse          = 1;
640    range->charSizeVerticalActive               = 1;
641    range->charSizeVerticalBlanking             = 1;
642    range->charSizeVerticalSyncOffset           = 1;
643    range->charSizeVerticalSyncPulse            = 1;
644    range->charSizeHorizontalBorderLeft         = 1;
645    range->charSizeHorizontalBorderRight        = 1;
646    range->charSizeVerticalBorderTop            = 1;
647    range->charSizeVerticalBorderBottom         = 1;
648    range->charSizeHorizontalTotal              = 1;
649    range->charSizeVerticalTotal                = 1;
650}
651
652static Boolean
653EDIDDescToDisplayTimingRangeRec( EDID * edid, EDIDGeneralDesc * desc,
654                                 IODisplayTimingRange * range )
655{
656    UInt8 byte;
657
658    if( !edid || (edid->version < 1) || (edid->revision < 1))
659        return( false );
660
661    if( desc->flag1 || desc->flag2 || desc->flag3)
662        return( false );
663    if( 0xfd != desc->type)
664        return( false );
665
666    MaxTimingRangeRec( range );
667
668    byte = edid->displayParams[0];
669    if (!(0x80 & byte))
670    {
671        range->supportedSignalLevels  = 1 << ((byte >> 5) & 3);
672        range->supportedSyncFlags     = ((byte & 1) ? kIORangeSupportsVSyncSerration : 0)
673                                      | ((byte & 2) ? kIORangeSupportsSyncOnGreen : 0)
674                                      | ((byte & 4) ? kIORangeSupportsCompositeSync : 0)
675                                      | ((byte & 8) ? kIORangeSupportsSeparateSyncs : 0);
676    }
677
678    range->supportedSignalConfigs = kIORangeSupportsInterlacedCEATiming;
679
680    range->minVerticalPulseWidthClocks   = 1;
681    range->minHorizontalPulseWidthClocks = 1;
682
683    range->minFrameRate  = desc->data[0];
684    range->maxFrameRate  = desc->data[1];
685    range->minLineRate   = desc->data[2] * 1000;
686    range->maxLineRate   = desc->data[3] * 1000;
687    range->maxPixelClock = desc->data[4] * 10000000ULL;
688
689    range->minHorizontalActiveClocks = 640;
690    range->minVerticalActiveClocks   = 480;
691
692    if( range->minLineRate)
693        range->maxHorizontalActiveClocks = range->maxPixelClock / range->minLineRate;
694    if( range->minFrameRate)
695        range->maxVerticalActiveClocks   = range->maxPixelClock
696                                            / (range->minHorizontalActiveClocks * range->minFrameRate);
697
698    return( true );
699}
700
701static void
702ParseMonitorDescriptor(IOFBConnectRef connectRef, EDID * edid __unused, EDIDGeneralDesc * desc)
703{
704    UInt8   byte;
705    CFIndex idx;
706    SInt32  vendor;
707
708    if (desc->flag1 || desc->flag2)
709        return;
710
711    if (desc->type >= 0x11)
712    {
713        if (desc->flag3)
714            return;
715        // vesa
716        return;
717    }
718
719    if (kDisplayAppleVendorID != ((desc->data[0] << 8) | desc->data[1]))
720        return;
721
722    // version = desc->flag3
723    switch (desc->type)
724    {
725        case 1:
726            // lvds
727            // link type = desc->data[2];
728            // link bits = desc->data[3] & 15;
729            byte = desc->data[3] >> 4;
730            if (!byte)
731                connectRef->supportedComponentDepths[kAllVendors] |= kIODisplayRGBColorComponentBits6;
732            else if (1 == byte)
733                connectRef->supportedComponentDepths[kAllVendors] |= kIODisplayRGBColorComponentBits8;
734
735            if ((1 << 3) & desc->data[4])
736                connectRef->ditherControl[kAllVendors] = (kIODisplayDitherDisable << kIODisplayDitherRGBShift);
737            break;
738
739        case 2:
740            // dp
741            for (idx = 2; idx < 11; idx += 3)
742            {
743                vendor = desc->data[idx];
744                if (vendor >= kNumVendors)
745                    continue;
746                connectRef->vendorsFound |= (1 << vendor);
747#if DISABLED_7668853
748                byte = desc->data[idx + 1]; // bpp
749                if ((byte >= 6) && (byte <= 16))
750                {
751                    connectRef->supportedComponentDepths[vendor]
752                        = (kIODisplayRGBColorComponentBits6 << ((byte - 6) >> 1));
753                }
754#endif
755                byte = desc->data[idx + 2]; // dither
756                connectRef->ditherControl[vendor] = (byte << kIODisplayDitherRGBShift);
757
758                DEBG(connectRef, "dp vendor 0x%x bpc 0x%x dith 0x%x\n", (int) vendor,
759                    connectRef->supportedComponentDepths[vendor],
760                    connectRef->ditherControl[vendor]);
761            }
762            break;
763    }
764}
765
766
767static kern_return_t
768DecodeStandardTiming( EDID * edid, UInt16 standardTiming,
769                      UInt32 * oWidth, UInt32 * height, float * refreshRate)
770{
771    UInt32 width;
772
773    if( 0x0101 == standardTiming)
774        return (kIOReturnBadArgument);
775
776    width = ((standardTiming >> 8) + 31) << 3;
777    *oWidth = width;
778    switch( (standardTiming >> 6) & 3) {
779        case 0:
780            if ((edid->version > 1) || (edid->revision >= 3))
781                *height = (10 * width) / 16;
782            else
783                *height = width;
784            break;
785        case 2:
786            *height = (4 * width) / 5;
787            break;
788        case 3:
789            *height = (9 * width) / 16;
790            break;
791        default:
792        case 1:
793            *height = (3 * width) / 4;
794            break;
795    }
796
797    if (refreshRate)
798        *refreshRate = (float) ((standardTiming & 63) + 60);
799
800    return (kIOReturnSuccess);
801}
802
803static void
804AdjustTimingForInterlace( IODetailedTimingInformation * timing )
805{
806    timing->signalConfig          |= kIOInterlacedCEATiming;
807    timing->verticalActive         = (timing->verticalActive << 1);
808    timing->verticalBlanking       = (timing->verticalBlanking << 1) | 1;
809    timing->verticalSyncPulseWidth = (timing->verticalSyncPulseWidth << 1);
810    timing->verticalSyncOffset     = (timing->verticalSyncOffset << 1) | 1;
811    timing->verticalBorderTop      = (timing->verticalBorderTop << 1);
812    timing->verticalBorderBottom   = (timing->verticalBorderBottom << 1);
813}
814
815static IOReturn
816EDIDDescToDetailedTiming( EDID * edid, EDIDDetailedTimingDesc * desc,
817                            IODetailedTimingInformation * timing )
818{
819    bool interlaced;
820
821    bzero( timing, sizeof( IODetailedTimingInformation) );
822
823    if( !desc->clock)
824        return( kIOReturnBadArgument );
825
826    timing->signalConfig                = (edid->displayParams[0] & 16)
827                                        ? kIOAnalogSetupExpected : 0;
828    interlaced = (0 != (desc->flags & 0x80));
829
830    timing->signalLevels                = (edid->displayParams[0] >> 5) & 3;
831
832    timing->pixelClock                  = ((UInt64) OSReadLittleInt16(&desc->clock, 0))
833                                        * 10000ULL;
834    timing->maxPixelClock               = timing->pixelClock;
835    timing->minPixelClock               = timing->pixelClock;
836
837    timing->horizontalActive            = desc->horizActive
838                                        | ((desc->horizHigh & 0xf0) << 4);
839    timing->horizontalBlanking          = desc->horizBlanking
840                                        | ((desc->horizHigh & 0x0f) << 8);
841
842    timing->verticalActive              = desc->verticalActive
843                                        | ((desc->verticalHigh & 0xf0) << 4);
844    timing->verticalBlanking            = desc->verticalBlanking
845                                        | ((desc->verticalHigh & 0x0f) << 8);
846
847    timing->horizontalSyncOffset        = desc->horizSyncOffset
848                                        | ((desc->syncHigh & 0xc0) << 2);
849    timing->horizontalSyncPulseWidth    = desc->horizSyncWidth
850                                        | ((desc->syncHigh & 0x30) << 4);
851
852    timing->verticalSyncOffset          = ((desc->verticalSyncOffsetWidth & 0xf0) >> 4)
853                                        | ((desc->syncHigh & 0x0c) << 2);
854    timing->verticalSyncPulseWidth      = ((desc->verticalSyncOffsetWidth & 0x0f) >> 0)
855                                        | ((desc->syncHigh & 0x03) << 4);
856
857    timing->horizontalBorderLeft        = desc->horizBorder;
858    timing->horizontalBorderRight       = desc->horizBorder;
859    timing->verticalBorderTop           = desc->verticalBorder;
860    timing->verticalBorderBottom        = desc->verticalBorder;
861
862    timing->horizontalSyncConfig        = (desc->flags & 2)
863                                        ? kIOSyncPositivePolarity : 0;
864    timing->horizontalSyncLevel         = 0;
865    timing->verticalSyncConfig          = (desc->flags & 4)
866                                        ? kIOSyncPositivePolarity : 0;
867    timing->verticalSyncLevel           = 0;
868
869    if (interlaced)
870        AdjustTimingForInterlace(timing);
871
872    return( kIOReturnSuccess );
873}
874
875static void
876TimingToHost( const IODetailedTimingInformationV2 * _t1, IODetailedTimingInformationV2 * t2 )
877{
878    IODetailedTimingInformationV2 * t1 = (IODetailedTimingInformationV2 *) _t1;
879
880    bcopy(t1, t2, sizeof(IODetailedTimingInformationV2));
881
882    t2->scalerFlags              = OSReadBigInt32(&t1->scalerFlags, 0);
883    t2->horizontalScaled         = OSReadBigInt32(&t1->horizontalScaled, 0);
884    t2->verticalScaled           = OSReadBigInt32(&t1->verticalScaled, 0);
885    t2->signalConfig             = OSReadBigInt32(&t1->signalConfig, 0);
886    t2->signalLevels             = OSReadBigInt32(&t1->signalLevels, 0);
887
888    t2->pixelClock               = OSReadBigInt64(&t1->pixelClock, 0);
889    t2->minPixelClock            = OSReadBigInt64(&t1->minPixelClock, 0);
890    t2->maxPixelClock            = OSReadBigInt64(&t1->maxPixelClock, 0);
891
892    t2->horizontalActive         = OSReadBigInt32(&t1->horizontalActive, 0);
893    t2->horizontalBlanking       = OSReadBigInt32(&t1->horizontalBlanking, 0);
894    t2->horizontalSyncOffset     = OSReadBigInt32(&t1->horizontalSyncOffset, 0);
895    t2->horizontalSyncPulseWidth = OSReadBigInt32(&t1->horizontalSyncPulseWidth, 0);
896
897    t2->verticalActive           = OSReadBigInt32(&t1->verticalActive, 0);
898    t2->verticalBlanking         = OSReadBigInt32(&t1->verticalBlanking, 0);
899    t2->verticalSyncOffset       = OSReadBigInt32(&t1->verticalSyncOffset, 0);
900    t2->verticalSyncPulseWidth   = OSReadBigInt32(&t1->verticalSyncPulseWidth, 0);
901
902    t2->horizontalBorderLeft     = OSReadBigInt32(&t1->horizontalBorderLeft, 0);
903    t2->horizontalBorderRight    = OSReadBigInt32(&t1->horizontalBorderRight, 0);
904    t2->verticalBorderTop        = OSReadBigInt32(&t1->verticalBorderTop, 0);
905    t2->verticalBorderBottom     = OSReadBigInt32(&t1->verticalBorderBottom, 0);
906    t2->horizontalSyncConfig     = OSReadBigInt32(&t1->horizontalSyncConfig, 0);
907    t2->horizontalSyncLevel      = OSReadBigInt32(&t1->horizontalSyncLevel, 0);
908    t2->verticalSyncConfig       = OSReadBigInt32(&t1->verticalSyncConfig, 0);
909    t2->verticalSyncLevel        = OSReadBigInt32(&t1->verticalSyncLevel, 0);
910}
911
912static IOReturn
913StandardResolutionToDetailedTiming( IOFBConnectRef connectRef, EDID * edid __unused,
914                                    IOFBResolutionSpec * spec,
915                                    IOTimingInformation * timing )
916{
917    CFDictionaryRef stdModes, timingIDs, dict;
918    const void *    key;
919    CFDataRef       data;
920
921    if (kResSpecNeedInterlace & spec->flags)
922        return (kIOReturnUnsupportedMode);
923
924    stdModes = CFDictionaryGetValue(connectRef->iographicsProperties, CFSTR("std-modes"));
925    if (!stdModes)
926        return (kIOReturnUnsupportedMode);
927
928    key = (const void *) (uintptr_t) spec->timingID;
929    if (!key)
930    {
931        CFStringRef timingKey;
932        if (kResSpecInternalReducedBlank & spec->flags)
933            timingKey = CFSTR("irb-timing-ids");
934        else
935            timingKey = CFSTR("timing-ids");
936        timingIDs = CFDictionaryGetValue(connectRef->iographicsProperties, timingKey);
937        if (!timingIDs)
938            return (kIOReturnUnsupportedMode);
939        key = (const void *)(uintptr_t)((spec->width << 20) | (spec->height << 8) | ((UInt32)(spec->refreshRate + 0.5)));
940        key = CFDictionaryGetValue(timingIDs, key);
941    }
942    dict = CFDictionaryGetValue(stdModes, key);
943
944    if (!dict)
945        return (kIOReturnUnsupportedMode);
946    data = CFDictionaryGetValue(dict, CFSTR(kIOFBModeTMKey));
947    if (!data)
948        return (kIOReturnUnsupportedMode);
949
950    TimingToHost( (const IODetailedTimingInformationV2 *) CFDataGetBytePtr(data), &timing->detailedInfo.v2 );
951
952    timing->appleTimingID = (UInt32) (uintptr_t) key;
953
954    return (kIOReturnSuccess);
955}
956
957static UInt32
958IODisplayGetCVTSyncWidth( UInt32 horizontalActive, UInt32 verticalActive )
959{
960    // CVT Table 2
961    enum {
962        kCVTAspect4By3    = 4,
963        kCVTAspect16By9   = 5,
964        kCVTAspect16By10  = 6,
965        kCVTAspect5By4    = 7,
966        kCVTAspect15By9   = 7,
967        kCVTAspectUnknown = 10
968    };
969
970    float ratio = ((float) horizontalActive) / ((float) verticalActive);
971
972    if (ratioOver(ratio, 4.0 / 3.0) <= 1.03125)
973        return (kCVTAspect4By3);
974
975    if (ratioOver(ratio, 16.0 / 9.0) <= 1.03125)
976        return (kCVTAspect16By9);
977
978    if (ratioOver(ratio, 16.0 / 10.0) <= 1.03125)
979        return (kCVTAspect16By10);
980
981    if (ratioOver(ratio, 5.0 / 4.0) <= 1.03125)
982        return (kCVTAspect5By4);
983
984    if (ratioOver(ratio, 15.0 / 9.0) <= 1.03125)
985        return (kCVTAspect15By9);
986
987    return (kCVTAspectUnknown);
988}
989
990static IOReturn
991GTFToDetailedTiming( IOFBConnectRef connectRef, EDID * edid,
992                     IOFBResolutionSpec * spec, UInt32 characterSize,
993                     IODetailedTimingInformation * timing )
994{
995    float       interlace       = (kResSpecNeedInterlace & spec->flags) ? 0.5 : 0.0;
996    float       interlaceFactor = (kResSpecNeedInterlace & spec->flags) ? 2.0 : 1.0;
997    float       fieldRate;                                              // V_FIELD_RATE_RQD
998    float       pixelFrequency;                                         // ACT_PIXEL_FREQ
999    int         horizontalTotal;                                        // TOTAL_PIXELS
1000    int         horizontalActive;                                       // TOTAL_ACTIVE_PIXELS
1001    int         horizontalBlanking;                                     // H_BLANK
1002    int         horizontalSyncWidth;                                    // H_SYNC_PIXELS
1003    int         verticalActive;                                         // V_LINES_RND
1004    int         verticalBlanking;                                       // VBI_LINES
1005    int         verticalSyncWidth = 3;                                  // V_SYNC_RND
1006    int         verticalSyncAndBackPorch;                               // V_SYNC_BP
1007    int         verticalSyncFrontPorch;
1008    // 4,5,15,16.
1009    int         topMargin       = 0;
1010    int         bottomMargin    = 0;
1011    int         leftMargin      = 0;
1012    int         rightMargin     = 0;
1013
1014    UInt32      horizontalSyncConfig;
1015    UInt32      verticalSyncConfig;
1016
1017    enum { kGTF, kCVT, kCVTRB } genType;
1018
1019    // 1.
1020    fieldRate = spec->refreshRate; // * interlaceFactor;
1021    // 4.
1022    horizontalActive = roundf(spec->width / characterSize) * characterSize
1023                                    + leftMargin + rightMargin;
1024    // 5.
1025    verticalActive = roundf(spec->height / interlaceFactor);
1026
1027    if (kResSpecReducedBlank & spec->flags)
1028        genType = kCVTRB;
1029    else if (connectRef->gtfDisplay && !connectRef->cvtDisplay)
1030        genType = kGTF;
1031    else
1032        genType = kCVT;
1033
1034    if (kGTF != genType)
1035        verticalSyncWidth = IODisplayGetCVTSyncWidth(horizontalActive, verticalActive * interlaceFactor);
1036
1037    if (kGTF == genType)
1038    {
1039        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * GTF */
1040
1041        float horizontalSyncPercent        = 8.0/100.0;                 // H_SYNC_PER
1042        float verticalSyncAndBackPorchTime = 550e-6;                    // MIN_VSYNC_BP
1043        int   minVerticalFrontPorch        = 1;                         // MIN_V_PORCH_RND
1044        float estimatedHorizontalPeriod;                                // H_PERIOD_EST
1045        float verticalFieldTotal;                                       // TOTAL_V_LINES
1046        float estimatedFieldRate;                                       // V_FIELD_RATE_EST
1047        SInt32 curve;
1048
1049        // 7.
1050        estimatedHorizontalPeriod =
1051            ((1 / fieldRate) - verticalSyncAndBackPorchTime)
1052            / (verticalActive + (2 * topMargin) + minVerticalFrontPorch + interlace);
1053
1054        // 8.
1055        verticalSyncAndBackPorch = roundf(verticalSyncAndBackPorchTime / estimatedHorizontalPeriod);
1056        verticalSyncFrontPorch   = minVerticalFrontPorch;
1057        verticalBlanking         = verticalSyncFrontPorch + verticalSyncAndBackPorch;
1058
1059        // 10.
1060        verticalFieldTotal = verticalActive + topMargin + bottomMargin
1061                            + verticalBlanking + interlace;
1062        // 11.
1063        estimatedFieldRate = 1.0 / estimatedHorizontalPeriod / verticalFieldTotal;
1064
1065        // 12.
1066        float hPeriod = estimatedHorizontalPeriod / (fieldRate / estimatedFieldRate);
1067
1068        for (curve = (connectRef->numGTFCurves - 1); curve >= 0; curve--)
1069        {
1070            if ((1 / hPeriod) > connectRef->gtfCurves[curve].startHFrequency)
1071                break;
1072        }
1073
1074        float cPrime = ((((float) connectRef->gtfCurves[curve].c) - ((float) connectRef->gtfCurves[curve].j))
1075                                    * ((float) connectRef->gtfCurves[curve].k) / 256.0)
1076                                    + ((float) connectRef->gtfCurves[curve].j);
1077        float mPrime = ((float) connectRef->gtfCurves[curve].k) / 256.0 * ((float) connectRef->gtfCurves[curve].m);
1078
1079        // 18.
1080        float idealDutyCycle = cPrime - (mPrime * hPeriod * 1e6 / 1000.0);
1081        // 19.
1082        horizontalBlanking = 2 * characterSize * roundf(
1083                                (horizontalActive * idealDutyCycle / (100.0 - idealDutyCycle)
1084                                / (2 * characterSize)));
1085
1086        // 20.
1087        horizontalTotal = horizontalActive + horizontalBlanking;
1088        // 21.
1089        pixelFrequency  = horizontalTotal / hPeriod;
1090
1091        // gtf 2.17.
1092        horizontalSyncWidth = characterSize *
1093                    roundf(horizontalSyncPercent * horizontalTotal / characterSize);
1094
1095        horizontalSyncConfig    = (curve == 0) ? 0 : kIOSyncPositivePolarity;
1096        verticalSyncConfig      = (curve == 0) ? kIOSyncPositivePolarity : 0;
1097    }
1098    else if (kCVT == genType)
1099    {
1100        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * CVT */
1101
1102        float horizontalSyncPercent        = 8.0/100.0;                 // H_SYNC_PER
1103        float verticalSyncAndBackPorchTime = 550e-6;                    // MIN_VSYNC_BP
1104        int   minVerticalBackPorch         = 6;                         // MIN_VBPORCH
1105        int   minVerticalFrontPorch        = 3;                         // MIN_V_PORCH_RND
1106        float estimatedHorizontalPeriod;                                // H_PERIOD_EST
1107        float verticalFieldTotal;                                       // TOTAL_V_LINES
1108        SInt32 curve = 0;
1109
1110        float cPrime = ((((float) connectRef->gtfCurves[curve].c) - ((float) connectRef->gtfCurves[curve].j))
1111                                    * ((float) connectRef->gtfCurves[curve].k) / 256.0)
1112                                    + ((float) connectRef->gtfCurves[curve].j);
1113        float mPrime = ((float) connectRef->gtfCurves[curve].k) / 256.0 * ((float) connectRef->gtfCurves[curve].m);
1114
1115        // 8.
1116        estimatedHorizontalPeriod =
1117            ((1 / fieldRate) - verticalSyncAndBackPorchTime)
1118            / (verticalActive + (topMargin + bottomMargin) + minVerticalFrontPorch + interlace);
1119        // 9.
1120
1121        verticalSyncAndBackPorch = 1 + truncf(verticalSyncAndBackPorchTime / estimatedHorizontalPeriod);
1122
1123        if (verticalSyncAndBackPorch < (verticalSyncWidth + minVerticalBackPorch))
1124            verticalSyncAndBackPorch = verticalSyncWidth + minVerticalBackPorch;
1125
1126        // 10.
1127
1128        verticalSyncFrontPorch = minVerticalFrontPorch;
1129        verticalBlanking       = verticalSyncFrontPorch + verticalSyncAndBackPorch;
1130
1131        // 11.
1132        verticalFieldTotal = verticalActive + topMargin + bottomMargin
1133                            + verticalBlanking + interlace;
1134        // 12.
1135        float idealDutyCycle = cPrime - (mPrime * estimatedHorizontalPeriod * 1e6 / 1000.0);
1136
1137        // 13.
1138        if (idealDutyCycle < 20.0)
1139            idealDutyCycle = 20.0;
1140
1141        horizontalBlanking = 2 * characterSize * truncf(
1142                            (horizontalActive * idealDutyCycle / (100.0 - idealDutyCycle)
1143                            / (2 * characterSize)));
1144        // 14.
1145        horizontalTotal = horizontalActive + horizontalBlanking;
1146
1147        // 15.
1148        float frequencyStep = 0.25e6;                                   // CLOCK_STEP
1149        pixelFrequency = frequencyStep * truncf(
1150                        (horizontalTotal / estimatedHorizontalPeriod) / frequencyStep);
1151
1152        // gtf 2.17.
1153        horizontalSyncWidth = characterSize * truncf(
1154            horizontalSyncPercent * horizontalTotal / characterSize);
1155
1156        horizontalSyncConfig    = 0 * kIOSyncPositivePolarity;
1157        verticalSyncConfig      = 1 * kIOSyncPositivePolarity;
1158    }
1159    else
1160    {
1161        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * CVT reduced blank */
1162
1163        float minVerticalBlankTime      = 460e-6;                       // RB_MIN_V_BLANK
1164        int   minVerticalBackPorch      = 6;                            // MIN_VBPORCH
1165        float estimatedHorizontalPeriod;                                // H_PERIOD_EST
1166        verticalSyncFrontPorch          = 3;                            // RB_V_FPORCH
1167        horizontalBlanking              = 160;                          // RB_H_BLANK
1168        horizontalSyncWidth             = 32;                           // RB_H_SYNC
1169
1170
1171        // 8.
1172        estimatedHorizontalPeriod = ((1 / fieldRate) - minVerticalBlankTime)
1173                                    / (verticalActive + topMargin + bottomMargin);
1174        // 9.
1175        verticalBlanking = truncf(minVerticalBlankTime / estimatedHorizontalPeriod) + 1; // VBI_LINES
1176
1177        // 10.
1178        if (verticalBlanking < (verticalSyncFrontPorch + verticalSyncWidth + minVerticalBackPorch))
1179            verticalBlanking = (verticalSyncFrontPorch + verticalSyncWidth + minVerticalBackPorch);
1180
1181        verticalSyncAndBackPorch = verticalBlanking - verticalSyncFrontPorch;
1182
1183        // 11.
1184        int verticalFieldTotal = verticalBlanking  + verticalActive
1185                                + topMargin + bottomMargin + interlace;
1186
1187        // 12.
1188        horizontalTotal = horizontalActive + horizontalBlanking;
1189
1190        // 13.
1191        float frequencyStep = 0.25e6;                                   // CLOCK_STEP
1192        pixelFrequency = frequencyStep * truncf(
1193                            (horizontalTotal * verticalFieldTotal * fieldRate) / frequencyStep);
1194
1195        horizontalSyncConfig    = 1 * kIOSyncPositivePolarity;
1196        verticalSyncConfig      = 0 * kIOSyncPositivePolarity;
1197    }
1198    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1199
1200    int horizontalSyncOffset = (horizontalBlanking / 2) - horizontalSyncWidth;
1201
1202    // --
1203    bzero( timing, sizeof(IODetailedTimingInformation) );
1204
1205    if (edid)
1206    {
1207        timing->signalConfig            = (edid->displayParams[0] & 16)
1208                                        ? kIOAnalogSetupExpected : 0;
1209        timing->signalLevels            = (edid->displayParams[0] >> 5) & 3;
1210    }
1211    else
1212    {
1213        timing->signalConfig            = kIOAnalogSetupExpected;
1214        timing->signalLevels            = kIOAnalogSignalLevel_0700_0300;
1215    }
1216
1217    timing->pixelClock                  = pixelFrequency;
1218
1219    timing->horizontalActive            = horizontalActive;
1220    timing->horizontalBlanking          = horizontalBlanking;
1221
1222    timing->verticalActive              = verticalActive;
1223    timing->verticalBlanking            = verticalBlanking;
1224
1225    timing->horizontalSyncOffset        = horizontalSyncOffset;
1226    timing->horizontalSyncPulseWidth    = horizontalSyncWidth;
1227
1228    timing->verticalSyncOffset          = verticalSyncFrontPorch;
1229    timing->verticalSyncPulseWidth      = verticalSyncWidth;
1230
1231    timing->horizontalBorderLeft        = leftMargin;
1232    timing->horizontalBorderRight       = rightMargin;
1233    timing->verticalBorderTop           = topMargin;
1234    timing->verticalBorderBottom        = bottomMargin;
1235
1236    timing->horizontalSyncConfig        = horizontalSyncConfig;
1237    timing->horizontalSyncLevel         = 0;
1238    timing->verticalSyncConfig          = verticalSyncConfig;
1239    timing->verticalSyncLevel           = 0;
1240
1241    if (kResSpecNeedInterlace & spec->flags)
1242        AdjustTimingForInterlace(timing);
1243
1244    return( kIOReturnSuccess );
1245}
1246
1247#if RLOG
1248__private_extern__ void
1249IOFBLogRange(IOFBConnectRef connectRef, const IODisplayTimingRange * range)
1250{
1251    if (!connectRef->logfile || !range)
1252        return;
1253
1254    fprintf(connectRef->logfile, "  minPixelClock                 %qd\n", range->minPixelClock);
1255    fprintf(connectRef->logfile, "  maxPixelClock                 %qd\n", range->maxPixelClock);
1256
1257    fprintf(connectRef->logfile, "  maxPixelError                 %d\n", (int) range->maxPixelError);
1258    fprintf(connectRef->logfile, "  supportedSyncFlags            %x\n", (int) range->supportedSyncFlags);
1259    fprintf(connectRef->logfile, "  supportedSignalLevels         %x\n", (int) range->supportedSignalLevels);
1260    fprintf(connectRef->logfile, "  supportedSignalConfigs        %x\n", (int) range->supportedSignalConfigs);
1261    fprintf(connectRef->logfile, "  minFrameRate                  %d\n", (int) range->minFrameRate);
1262    fprintf(connectRef->logfile, "  maxFrameRate                  %d\n", (int) range->maxFrameRate);
1263    fprintf(connectRef->logfile, "  minLineRate                   %d\n", (int) range->minLineRate);
1264    fprintf(connectRef->logfile, "  maxLineRate                   %d\n", (int) range->maxLineRate);
1265
1266    fprintf(connectRef->logfile, "  maxHorizontalTotal            %d\n", (int) range->maxHorizontalTotal);
1267    fprintf(connectRef->logfile, "  maxVerticalTotal              %d\n", (int) range->maxVerticalTotal);
1268    fprintf(connectRef->logfile, "  charSizeHorizontalActive      %d\n", range->charSizeHorizontalActive);
1269    fprintf(connectRef->logfile, "  charSizeHorizontalBlanking    %d\n", range->charSizeHorizontalBlanking);
1270    fprintf(connectRef->logfile, "  charSizeHorizontalSyncOffset  %d\n", range->charSizeHorizontalSyncOffset);
1271    fprintf(connectRef->logfile, "  charSizeHorizontalSyncPulse   %d\n", range->charSizeHorizontalSyncPulse);
1272    fprintf(connectRef->logfile, "  charSizeVerticalActive        %d\n", range->charSizeVerticalActive);
1273    fprintf(connectRef->logfile, "  charSizeVerticalBlanking      %d\n", range->charSizeVerticalBlanking);
1274    fprintf(connectRef->logfile, "  charSizeVerticalSyncOffset    %d\n", range->charSizeVerticalSyncOffset);
1275    fprintf(connectRef->logfile, "  charSizeVerticalSyncPulse     %d\n", range->charSizeVerticalSyncPulse);
1276    fprintf(connectRef->logfile, "  charSizeHorizontalBorderLeft  %d\n", range->charSizeHorizontalBorderLeft);
1277    fprintf(connectRef->logfile, "  charSizeHorizontalBorderRight %d\n", range->charSizeHorizontalBorderRight);
1278    fprintf(connectRef->logfile, "  charSizeVerticalBorderTop     %d\n", range->charSizeVerticalBorderTop);
1279    fprintf(connectRef->logfile, "  charSizeVerticalBorderBottom  %d\n", range->charSizeVerticalBorderBottom);
1280    fprintf(connectRef->logfile, "  charSizeHorizontalTotal       %d\n", range->charSizeHorizontalTotal);
1281    fprintf(connectRef->logfile, "  charSizeVerticalTotal         %d\n", range->charSizeVerticalTotal);
1282
1283    fprintf(connectRef->logfile, "  minHorizontalActiveClocks     %d\n", (int) range->minHorizontalActiveClocks);
1284    fprintf(connectRef->logfile, "  maxHorizontalActiveClocks     %d\n", (int) range->maxHorizontalActiveClocks);
1285    fprintf(connectRef->logfile, "  minHorizontalBlankingClocks   %d\n", (int) range->minHorizontalBlankingClocks);
1286    fprintf(connectRef->logfile, "  maxHorizontalBlankingClocks   %d\n", (int) range->maxHorizontalBlankingClocks);
1287    fprintf(connectRef->logfile, "  minHorizontalSyncOffsetClocks %d\n", (int) range->minHorizontalSyncOffsetClocks);
1288    fprintf(connectRef->logfile, "  maxHorizontalSyncOffsetClocks %d\n", (int) range->maxHorizontalSyncOffsetClocks);
1289    fprintf(connectRef->logfile, "  minHorizontalPulseWidthClocks %d\n", (int) range->minHorizontalPulseWidthClocks);
1290    fprintf(connectRef->logfile, "  maxHorizontalPulseWidthClocks %d\n", (int) range->maxHorizontalPulseWidthClocks);
1291
1292    fprintf(connectRef->logfile, "  minVerticalActiveClocks       %d\n", (int) range->minVerticalActiveClocks);
1293    fprintf(connectRef->logfile, "  maxVerticalActiveClocks       %d\n", (int) range->maxVerticalActiveClocks);
1294    fprintf(connectRef->logfile, "  minVerticalBlankingClocks     %d\n", (int) range->minVerticalBlankingClocks);
1295    fprintf(connectRef->logfile, "  maxVerticalBlankingClocks     %d\n", (int) range->maxVerticalBlankingClocks);
1296
1297    fprintf(connectRef->logfile, "  minVerticalSyncOffsetClocks   %d\n", (int) range->minVerticalSyncOffsetClocks);
1298    fprintf(connectRef->logfile, "  maxVerticalSyncOffsetClocks   %d\n", (int) range->maxVerticalSyncOffsetClocks);
1299    fprintf(connectRef->logfile, "  minVerticalPulseWidthClocks   %d\n", (int) range->minVerticalPulseWidthClocks);
1300    fprintf(connectRef->logfile, "  maxVerticalPulseWidthClocks   %d\n", (int) range->maxVerticalPulseWidthClocks);
1301
1302    fprintf(connectRef->logfile, "  minHorizontalBorderLeft       %d\n", (int) range->minHorizontalBorderLeft);
1303    fprintf(connectRef->logfile, "  maxHorizontalBorderLeft       %d\n", (int) range->maxHorizontalBorderLeft);
1304    fprintf(connectRef->logfile, "  minHorizontalBorderRight      %d\n", (int) range->minHorizontalBorderRight);
1305    fprintf(connectRef->logfile, "  maxHorizontalBorderRight      %d\n", (int) range->maxHorizontalBorderRight);
1306
1307    fprintf(connectRef->logfile, "  minVerticalBorderTop          %d\n", (int) range->minVerticalBorderTop);
1308    fprintf(connectRef->logfile, "  maxVerticalBorderTop          %d\n", (int) range->maxVerticalBorderTop);
1309    fprintf(connectRef->logfile, "  minVerticalBorderBottom       %d\n", (int) range->minVerticalBorderBottom);
1310    fprintf(connectRef->logfile, "  maxVerticalBorderBottom       %d\n", (int) range->maxVerticalBorderBottom);
1311
1312    fprintf(connectRef->logfile, "  maxNumLinks                   %d\n", (int) range->maxNumLinks);
1313    fprintf(connectRef->logfile, "  minLink0PixelClock            %d\n", (int) range->minLink0PixelClock);
1314    fprintf(connectRef->logfile, "  maxLink0PixelClock            %d\n", (int) range->maxLink0PixelClock);
1315    fprintf(connectRef->logfile, "  minLink1PixelClock            %d\n", (int) range->minLink1PixelClock);
1316    fprintf(connectRef->logfile, "  maxLink1PixelClock            %d\n", (int) range->maxLink1PixelClock);
1317
1318    fflush(connectRef->logfile);
1319}
1320
1321__private_extern__ void
1322IOFBLogTiming(IOFBConnectRef connectRef, const IOTimingInformation * timing)
1323{
1324    if (!connectRef->logfile || !timing)
1325        return;
1326
1327    fprintf(connectRef->logfile, "  pixelClock                    %qd\n", timing->detailedInfo.v2.pixelClock);
1328    fprintf(connectRef->logfile, "  minPixelClock                 %qd\n", timing->detailedInfo.v2.minPixelClock);
1329    fprintf(connectRef->logfile, "  maxPixelClock                 %qd\n", timing->detailedInfo.v2.maxPixelClock);
1330    fprintf(connectRef->logfile, "  signalConfig                  %x\n", (int) timing->detailedInfo.v2.signalConfig);
1331    fprintf(connectRef->logfile, "  signalLevels                  %x\n", (int) timing->detailedInfo.v2.signalLevels);
1332    fprintf(connectRef->logfile, "  horizontalActive              %d\n", (int) timing->detailedInfo.v2.horizontalActive);
1333    fprintf(connectRef->logfile, "  horizontalBlanking            %d\n", (int) timing->detailedInfo.v2.horizontalBlanking);
1334    fprintf(connectRef->logfile, "  horizontalSyncOffset          %d\n", (int) timing->detailedInfo.v2.horizontalSyncOffset);
1335    fprintf(connectRef->logfile, "  horizontalSyncPulseWidth      %d\n", (int) timing->detailedInfo.v2.horizontalSyncPulseWidth);
1336    fprintf(connectRef->logfile, "  verticalActive                %d\n", (int) timing->detailedInfo.v2.verticalActive);
1337    fprintf(connectRef->logfile, "  verticalBlanking              %d\n", (int) timing->detailedInfo.v2.verticalBlanking);
1338    fprintf(connectRef->logfile, "  verticalSyncOffset            %d\n", (int) timing->detailedInfo.v2.verticalSyncOffset);
1339    fprintf(connectRef->logfile, "  verticalSyncPulseWidth        %d\n", (int) timing->detailedInfo.v2.verticalSyncPulseWidth);
1340    fprintf(connectRef->logfile, "  horizontalSyncConfig          %d\n", (int) timing->detailedInfo.v2.horizontalSyncConfig);
1341    fprintf(connectRef->logfile, "  horizontalSyncLevel           %d\n", (int) timing->detailedInfo.v2.horizontalSyncLevel);
1342    fprintf(connectRef->logfile, "  verticalSyncConfig            %d\n", (int) timing->detailedInfo.v2.verticalSyncConfig);
1343    fprintf(connectRef->logfile, "  verticalSyncLevel             %d\n", (int) timing->detailedInfo.v2.verticalSyncLevel);
1344    fprintf(connectRef->logfile, "  numLinks                      %d\n", (int) timing->detailedInfo.v2.numLinks);
1345
1346    fprintf(connectRef->logfile, "  scalerFlags                   %x\n", (int) timing->detailedInfo.v2.scalerFlags);
1347    fprintf(connectRef->logfile, "  horizontalScaled              %d\n", (int) timing->detailedInfo.v2.horizontalScaled);
1348    fprintf(connectRef->logfile, "  verticalScaled                %d\n", (int) timing->detailedInfo.v2.verticalScaled);
1349    fprintf(connectRef->logfile, "  horizontalScaledInset         %d\n", (int) timing->detailedInfo.v2.horizontalScaledInset);
1350    fprintf(connectRef->logfile, "  verticalScaledInset           %d\n", (int) timing->detailedInfo.v2.verticalScaledInset);
1351
1352    fflush(connectRef->logfile);
1353}
1354#endif
1355
1356static void
1357AdjustTimingForRange( IODisplayTimingRange * range,
1358                        IODetailedTimingInformation * timing )
1359{
1360    if( timing->horizontalSyncPulseWidth % range->charSizeHorizontalSyncPulse)
1361    // digital only?
1362#if 0
1363        // round
1364        timing->horizontalSyncPulseWidth += range->charSizeHorizontalSyncPulse
1365                            - (timing->horizontalSyncPulseWidth % range->charSizeHorizontalSyncPulse);
1366#else
1367        // trunc
1368        timing->horizontalSyncPulseWidth -=
1369                            (timing->horizontalSyncPulseWidth % range->charSizeHorizontalSyncPulse);
1370#endif
1371}
1372
1373static UInt32
1374GetAssumedPixelRepetition( IODetailedTimingInformation * timing )
1375{
1376    if (!(kIOInterlacedCEATiming & timing->signalConfig))
1377        return (0);
1378
1379    if ((1440 == timing->horizontalActive)
1380     && ((480 == timing->verticalActive) || (576 == timing->verticalActive)))
1381        return (2);
1382
1383    if ((2880 == timing->horizontalActive)
1384     && ((480 == timing->verticalActive) || (576 == timing->verticalActive)))
1385        return (4);     // 1 - 10
1386
1387    return (0);
1388}
1389
1390static int
1391CheckTimingWithRange( IOFBConnectRef connectRef __unused,
1392                      IODisplayTimingRange * range, IODetailedTimingInformation * timing )
1393{
1394    UInt64      pixelClock;
1395    UInt64      rate;
1396    UInt64      hTotal, vTotal;
1397
1398    if( kIODigitalSignal & timing->signalConfig)
1399        return(1);
1400
1401    if ((kIOInterlacedCEATiming & timing->signalConfig)
1402     && !((kIORangeSupportsInterlacedCEATiming | kIORangeSupportsInterlacedCEATimingWithConfirm)
1403            & range->supportedSignalConfigs))
1404        return(34);
1405
1406    if ((timing->numLinks > 1)
1407        && range->maxNumLinks
1408        && (timing->numLinks > range->maxNumLinks))
1409        return(35);
1410
1411//    if( 0 == (range->supportedSyncFlags & (1 << (timing->signalLevels))))
1412//        return(2);
1413//    if( 0 == (range->supportedSignalLevels & (1 << (timing->signalLevels))))
1414//        return(3);
1415
1416    pixelClock = timing->pixelClock;
1417    hTotal  = timing->horizontalActive;
1418    hTotal += timing->horizontalBlanking;
1419    vTotal  = timing->verticalActive;
1420    vTotal += timing->verticalBlanking;
1421
1422    if (!hTotal || !vTotal)
1423        return(36);
1424
1425    if( (pixelClock > range->maxPixelClock)
1426     || (pixelClock < range->minPixelClock))
1427        return(4);
1428
1429    // line rate
1430    rate = pixelClock / hTotal;
1431    if( (rate > range->maxLineRate)
1432     || (rate < range->minLineRate))
1433        return(5);
1434
1435    // frame rate
1436    rate = pixelClock;
1437    if (kIOInterlacedCEATiming & timing->signalConfig)
1438        rate *= 2;
1439    rate /= (hTotal * vTotal);
1440    if( (rate > range->maxFrameRate)
1441     || (rate < range->minFrameRate))
1442        return(6);
1443
1444    if( hTotal > range->maxHorizontalTotal)
1445        return(7);
1446    if( vTotal > range->maxVerticalTotal)
1447        return(8);
1448
1449    if( (timing->horizontalActive > range->maxHorizontalActiveClocks)
1450     || (timing->horizontalActive < range->minHorizontalActiveClocks))
1451        return(9);
1452    if( (timing->verticalActive > range->maxVerticalActiveClocks)
1453     || (timing->verticalActive < range->minVerticalActiveClocks))
1454        return(10);
1455
1456/*
1457    if( (timing->horizontalBlanking > range->maxHorizontalBlankingClocks)
1458     || (timing->horizontalBlanking < range->minHorizontalBlankingClocks))
1459        return(11);
1460    if( (timing->verticalBlanking > range->maxVerticalBlankingClocks)
1461     || (timing->verticalBlanking < range->minVerticalBlankingClocks))
1462        return(12);
1463*/
1464    if( (timing->horizontalSyncOffset > range->maxHorizontalSyncOffsetClocks)
1465     || (timing->horizontalSyncOffset < range->minHorizontalSyncOffsetClocks))
1466        return(13);
1467    if( (timing->horizontalSyncPulseWidth > range->maxHorizontalPulseWidthClocks)
1468     || (timing->horizontalSyncPulseWidth < range->minHorizontalPulseWidthClocks))
1469        return(14);
1470
1471    if( (timing->verticalSyncOffset > range->maxVerticalSyncOffsetClocks)
1472     || (timing->verticalSyncOffset < range->minVerticalSyncOffsetClocks))
1473        return(15);
1474    if( (timing->verticalSyncPulseWidth > range->maxVerticalPulseWidthClocks)
1475     || (timing->verticalSyncPulseWidth < range->minVerticalPulseWidthClocks))
1476        return(16);
1477
1478    if( (timing->horizontalBorderLeft > range->maxHorizontalBorderLeft)
1479     || (timing->horizontalBorderLeft < range->minHorizontalBorderLeft))
1480        return(17);
1481    if( (timing->horizontalBorderRight > range->maxHorizontalBorderRight)
1482     || (timing->horizontalBorderRight < range->minHorizontalBorderRight))
1483        return(18);
1484    if( (timing->verticalBorderTop > range->maxVerticalBorderTop)
1485     || (timing->verticalBorderTop < range->minVerticalBorderTop))
1486        return(19);
1487    if( (timing->verticalBorderBottom > range->maxVerticalBorderBottom)
1488     || (timing->verticalBorderBottom < range->minVerticalBorderBottom))
1489        return(20);
1490
1491    if( timing->horizontalActive % range->charSizeHorizontalActive)
1492        return(21);
1493    if( timing->horizontalBlanking % range->charSizeHorizontalBlanking)
1494        return(22);
1495    if( timing->horizontalSyncOffset % range->charSizeHorizontalSyncOffset)
1496        return(23);
1497    if( timing->horizontalSyncPulseWidth % range->charSizeHorizontalSyncPulse)
1498        return(24);
1499    if( timing->verticalActive % range->charSizeVerticalActive)
1500        return(34);
1501    if( timing->verticalBlanking % range->charSizeVerticalBlanking)
1502        return(25);
1503    if( timing->verticalSyncOffset % range->charSizeVerticalSyncOffset)
1504        return(26);
1505    if( timing->verticalSyncPulseWidth % range->charSizeVerticalSyncPulse)
1506        return(27);
1507    if( timing->horizontalBorderLeft % range->charSizeHorizontalBorderLeft)
1508        return(28);
1509    if( timing->horizontalBorderRight % range->charSizeHorizontalBorderRight)
1510        return(29);
1511    if( timing->verticalBorderTop % range->charSizeVerticalBorderTop)
1512        return(30);
1513    if( timing->verticalBorderBottom % range->charSizeVerticalBorderBottom)
1514        return(31);
1515    if( hTotal % range->charSizeHorizontalTotal)
1516        return(32);
1517    if( vTotal % range->charSizeVerticalTotal)
1518        return(33);
1519
1520    return (0);
1521}
1522
1523static Boolean
1524HasEstablishedTiming( IOFBConnectRef connectRef, UInt32 appleTimingID )
1525{
1526    CFDataRef data;
1527    UInt32 *  establishedIDs;
1528    UInt32    i;
1529
1530    if (kIOTimingIDInvalid == appleTimingID)
1531        return (false);
1532
1533    data = CFDictionaryGetValue(connectRef->iographicsProperties, CFSTR("established-ids"));
1534    if (data)
1535        establishedIDs = (UInt32 *) CFDataGetBytePtr(data);
1536    else
1537        establishedIDs = 0;
1538
1539    for( i = 0;
1540         establishedIDs && (i < 24) && (appleTimingID != OSReadBigInt32(&establishedIDs[i], 0));
1541         i++ )  {}
1542
1543    return( i < 24 );
1544}
1545
1546__private_extern__ IOReturn
1547IOCheckTimingWithDisplay( IOFBConnectRef connectRef,
1548                          IOFBDisplayModeDescription * desc,
1549                          IOOptionBits modeGenFlags )
1550{
1551    IOTimingInformation * timing = &desc->timingInfo;
1552    IOReturn              result;
1553    CFDataRef             edidData;
1554    CFDataRef             data;
1555    int                   diag;
1556
1557    do
1558    {
1559        if (connectRef->fbRange && !(kIOFBDriverMode & modeGenFlags))
1560        {
1561            AdjustTimingForRange(connectRef->fbRange,  &timing->detailedInfo.v2);
1562
1563            if ((diag = CheckTimingWithRange(connectRef, connectRef->fbRange, &timing->detailedInfo.v2)))
1564            {
1565#if RLOG
1566                DEBG(connectRef, "out of cards range(%d) %d x %d\n", diag,
1567                                (int) timing->detailedInfo.v2.horizontalActive,
1568                                (int) timing->detailedInfo.v2.verticalActive );
1569                IOFBLogTiming(connectRef, timing);
1570#endif
1571                result = kIOReturnUnsupportedMode;
1572                continue;
1573            }
1574
1575            result = IOFBDriverPreflight(connectRef, desc);
1576            if (kIOReturnSuccess != result)
1577                continue;
1578        }
1579
1580        result = kIOReturnNotFound;
1581        if(!connectRef->overrides)
1582            continue;
1583
1584        if (!(kIOFBEDIDStdEstMode & modeGenFlags))
1585        {
1586            edidData = CFDictionaryGetValue(connectRef->overrides, CFSTR(kIODisplayEDIDKey));
1587            if (edidData && HasEstablishedTiming(connectRef, timing->appleTimingID))
1588            {
1589                result = kIOReturnUnsupportedMode;
1590                continue;
1591            }
1592        }
1593
1594        if (connectRef->hasCEAExt
1595            && !((kIOFBScaledMode | kIOFBEDIDDetailedMode | kIOFBEDIDStdEstMode) & modeGenFlags))
1596        {
1597            result = kIOReturnUnsupportedMode;
1598            continue;
1599        }
1600
1601        if (kIODetailedTimingValid & timing->flags)
1602        {
1603            CFNumberRef num;
1604
1605            num = CFDictionaryGetValue( connectRef->overrides, CFSTR("sync") );
1606            if( num)
1607            {
1608                UInt32 hSyncMask, hSyncValue, vSyncMask, vSyncValue;
1609
1610                CFNumberGetValue( num, kCFNumberSInt32Type, &vSyncValue );
1611                hSyncMask  = 0xff & (vSyncValue >> 24);
1612                hSyncValue = 0xff & (vSyncValue >> 16);
1613                vSyncMask  = 0xff & (vSyncValue >> 8);
1614                vSyncValue = 0xff & (vSyncValue >> 0);
1615                if ((hSyncValue != (timing->detailedInfo.v2.horizontalSyncConfig & hSyncMask))
1616                 || (vSyncValue != (timing->detailedInfo.v2.verticalSyncConfig   & vSyncMask)))
1617                {
1618                    result = kIOReturnUnsupportedMode;
1619                    continue;
1620                }
1621            }
1622
1623            if ((timing->detailedInfo.v2.numLinks > 1)
1624                && connectRef->maxDisplayLinks
1625                && (timing->detailedInfo.v2.numLinks > connectRef->maxDisplayLinks))
1626            {
1627#if RLOG
1628                DEBG(connectRef, "out display maxDisplayLinks\n");
1629                IOFBLogTiming(connectRef, timing);
1630#endif
1631                result = kIOReturnUnsupportedMode;
1632                continue;
1633            }
1634
1635            uint64_t maxClock = 0;
1636            if (connectRef->dpcdData
1637             && ((size_t) CFDataGetLength(connectRef->dpcdData)) >= sizeof(DPCD))
1638            do
1639            {
1640                const DPCD * dpcd = (typeof(dpcd)) CFDataGetBytePtr(connectRef->dpcdData);
1641
1642                if ((kDownStreamPortDetailed|kDownStreamPortPresent)
1643                 != ((kDownStreamPortDetailed|kDownStreamPortPresent) & dpcd->downStreamPortPresent))
1644                    continue;
1645
1646                switch (kDownStreamPortType & dpcd->downstreamPorts.detailed[0].type)
1647                {
1648                    case kDownStreamPortTypeHDMI:
1649                    case kDownStreamPortTypeDPP:
1650                        maxClock = dpcd->downstreamPorts.detailed[0].maxClock;
1651                        maxClock *= 2500000ULL;
1652                        break;
1653                    default:
1654                        break;
1655                }
1656            }
1657            while (false);
1658
1659            if (maxClock && (timing->detailedInfo.v2.pixelClock > maxClock))
1660            {
1661#if RLOG
1662                DEBG(connectRef, "out transport clock(%qd)\n", timing->detailedInfo.v2.pixelClock);
1663                IOFBLogTiming(connectRef, timing);
1664#endif
1665                result = kIOReturnUnsupportedMode;
1666                continue;
1667            }
1668
1669            data = CFDictionaryGetValue(connectRef->overrides, CFSTR("trng"));
1670            if (data && ((kIOFBGTFMode | kIOFBStdMode | kIOFBDriverMode) & modeGenFlags))
1671            {
1672                if ((diag = CheckTimingWithRange(connectRef, (IODisplayTimingRange *) CFDataGetBytePtr(data),
1673                                              (IODetailedTimingInformation *) &timing->detailedInfo.v2)))
1674                {
1675#if RLOG
1676                    DEBG(connectRef, "out display range(%d)\n", diag);
1677                    IOFBLogTiming(connectRef, timing);
1678#endif
1679                    result = kIOReturnUnsupportedMode;
1680                    continue;
1681                }
1682                if (kIOFBDriverMode & modeGenFlags)
1683                {
1684                    if (ratioOver(
1685                        ((float) timing->detailedInfo.v2.horizontalActive)
1686                                / ((float) timing->detailedInfo.v2.verticalActive),
1687                        connectRef->nativeAspect) > 1.2)
1688                    {
1689#if RLOG
1690                        DEBG(connectRef, "aspect too different\n");
1691                        IOFBLogTiming(connectRef, timing);
1692#endif
1693                        continue;
1694                    }
1695                }
1696                result = kIOReturnSuccess;
1697            }
1698        }
1699    }
1700    while (false);
1701
1702    return (result);
1703}
1704
1705static kern_return_t
1706InstallTiming( IOFBConnectRef                connectRef,
1707                IOFBDisplayModeDescription * desc,
1708                IOOptionBits                 modeGenFlags )
1709{
1710    IOReturn                    err;
1711    IOOptionBits                dmFlags;
1712    IOTimingInformation *       timing = &desc->timingInfo;
1713
1714    if (connectRef->dualLinkCrossover)
1715    {
1716        if (timing->detailedInfo.v2.pixelClock > connectRef->dualLinkCrossover)
1717            timing->detailedInfo.v2.numLinks = 2;
1718        else
1719            timing->detailedInfo.v2.numLinks = 1;
1720    }
1721    else
1722        timing->detailedInfo.v2.numLinks = 0;
1723
1724    UpdateTimingInfoForTransform(connectRef, desc, 0);
1725
1726    if (InvalidTiming(connectRef, timing))
1727        return (kIOReturnUnsupportedMode);
1728
1729    if ((kIOFBEDIDStdEstMode | kIOFBEDIDDetailedMode) & modeGenFlags)
1730    {
1731        if ((0xffffffff == connectRef->dimensions.width)
1732         || (timing->detailedInfo.v2.horizontalActive > connectRef->dimensions.width))
1733            connectRef->dimensions.width = timing->detailedInfo.v2.horizontalActive;
1734        if ((0xffffffff == connectRef->dimensions.height)
1735         || (timing->detailedInfo.v2.verticalActive > connectRef->dimensions.height))
1736            connectRef->dimensions.height = timing->detailedInfo.v2.verticalActive;
1737    }
1738
1739    err = IOCheckTimingWithDisplay( connectRef, desc, modeGenFlags );
1740    if (kIOReturnUnsupportedMode == err)
1741        return( err );
1742
1743	dmFlags = desc->info.flags;
1744
1745    if (0 == ((kIOFBEDIDStdEstMode | kIOFBEDIDDetailedMode) & modeGenFlags))
1746    {
1747        if( (timing->detailedInfo.v2.horizontalActive > connectRef->dimensions.width)
1748            || (timing->detailedInfo.v2.verticalActive > connectRef->dimensions.height)) {
1749            dmFlags |= connectRef->dimensions.setFlags;
1750            dmFlags &= ~connectRef->dimensions.clearFlags;
1751        }
1752        if (kIOReturnSuccess != err)
1753            dmFlags &= ~kDisplayModeSafeFlag;
1754    }
1755
1756    if (timing->detailedInfo.v2.signalConfig & kIOInterlacedCEATiming)
1757    {
1758        dmFlags |= (kDisplayModeInterlacedFlag /*| kDisplayModeTelevisionFlag*/);
1759        if (connectRef->fbRange && (kIORangeSupportsInterlacedCEATimingWithConfirm & connectRef->fbRange->supportedSignalConfigs))
1760            dmFlags &= ~kDisplayModeSafeFlag;
1761    }
1762
1763    desc->info.flags = dmFlags;
1764
1765    err = IOFBInstallMode( connectRef, 0xffffffff, desc, 0, modeGenFlags );
1766
1767#if RLOG
1768    if (timing->detailedInfo.v2.signalConfig & kIOInterlacedCEATiming)
1769    {
1770        DEBG(connectRef, "interlaced: %x\n", (int) modeGenFlags);
1771        IOFBLogTiming(connectRef, timing);
1772    }
1773#endif
1774
1775    return( err );
1776}
1777
1778static kern_return_t
1779InstallFromCEAShortVideoDesc( IOFBConnectRef connectRef, UInt8 * bytes )
1780{
1781    IOReturn     err = kIOReturnSuccess;
1782    int          length;
1783    int          offset;
1784    IOOptionBits flags;
1785    uint8_t      code;
1786	CFArrayRef   array;
1787	CFDataRef    data;
1788
1789    IOFBDisplayModeDescription modeDesc;
1790    IOTimingInformation * timing = &modeDesc.timingInfo;
1791
1792	array = CFDictionaryGetValue( gIOGraphicsProperties, CFSTR("cea-modes") );
1793	if (!array) return (kIOReturnUnsupported);
1794
1795    bzero( &modeDesc, sizeof( modeDesc ));
1796    timing->flags = kIODetailedTimingValid;
1797
1798    length = (bytes[0] & 0x1f);
1799    for (offset = 1; offset < (length + 1); offset++)
1800    {
1801        code = bytes[offset] & 0x7F;
1802		if (code >= CFArrayGetCount(array)) continue;
1803		data = CFArrayGetValueAtIndex(array, code);
1804		if (CFDataGetTypeID() != CFGetTypeID(data)) continue;
1805		if (CFDataGetLength(data) != sizeof(timing->detailedInfo.v2)) continue;
1806		CFDataGetBytes(data, CFRangeMake(0, sizeof(timing->detailedInfo.v2)),
1807							(UInt8 *) &timing->detailedInfo.v2);
1808
1809		flags = kDisplayModeValidFlag | kDisplayModeSafeFlag;
1810		if (false && connectRef->hasHDMI && (bytes[offset] & 0x80))
1811			flags |= kDisplayModeDefaultFlag;
1812
1813        // If VIC code is between 1 and 64 and the most significant bit is 1,
1814        // then this is a native mode
1815        if ((bytes[offset] >= 129) && (bytes[offset] <= 192))
1816            flags |= kDisplayModeNativeFlag;
1817
1818		modeDesc.info.flags = flags;
1819		err = InstallTiming( connectRef, &modeDesc, kIOFBEDIDDetailedMode );
1820    }
1821
1822    return err;
1823}
1824
1825static kern_return_t
1826InstallFromHDMIVIC( IOFBConnectRef connectRef, uint32_t count, uint8_t * vics )
1827{
1828    IOReturn     err = kIOReturnSuccess;
1829	uint32_t     idx;
1830    uint8_t      code;
1831    IOOptionBits flags;
1832	CFArrayRef   array;
1833	CFDataRef    data;
1834
1835    IOFBDisplayModeDescription modeDesc;
1836    IOTimingInformation *      timing = &modeDesc.timingInfo;
1837
1838	array = CFDictionaryGetValue( gIOGraphicsProperties, CFSTR("hdmi-vic-modes") );
1839	if (!array) return (kIOReturnUnsupported);
1840
1841    bzero( &modeDesc, sizeof( modeDesc ));
1842    timing->flags = kIODetailedTimingValid;
1843
1844	for (idx = 0; idx < count; idx++)
1845    {
1846		code = vics[idx];
1847		if (code > CFArrayGetCount(array)) continue;
1848		data = CFArrayGetValueAtIndex(array, code);
1849		if (CFDataGetTypeID() != CFGetTypeID(data)) continue;
1850		if (CFDataGetLength(data) != sizeof(timing->detailedInfo.v2)) continue;
1851		CFDataGetBytes(data, CFRangeMake(0, sizeof(timing->detailedInfo.v2)),
1852							(UInt8 *) &timing->detailedInfo.v2);
1853		flags = kDisplayModeValidFlag | kDisplayModeSafeFlag;
1854		modeDesc.info.flags = flags;
1855		err = InstallTiming( connectRef, &modeDesc, kIOFBEDIDDetailedMode );
1856    }
1857
1858    return err;
1859}
1860
1861static kern_return_t
1862InstallFromEDIDDesc( IOFBConnectRef connectRef,
1863                     EDID * edid, EDIDDetailedTimingDesc * desc,
1864                     IOOptionBits dmFlags)
1865{
1866    IOReturn            err;
1867    UInt32              pixelRep;
1868    IOFBDisplayModeDescription modeDesc;
1869    IOTimingInformation *      timing = &modeDesc.timingInfo;
1870
1871    bzero( &modeDesc, sizeof( modeDesc ));
1872    timing->flags = kIODetailedTimingValid;
1873
1874    err = EDIDDescToDetailedTiming( edid, desc, (IODetailedTimingInformation *) &timing->detailedInfo.v2 );
1875    if( kIOReturnSuccess != err)
1876        return (err);
1877
1878    if ((connectRef->defaultIndex != -1)
1879        && !bcmp(desc, &edid->descriptors[connectRef->defaultIndex].timing,
1880        sizeof(EDIDDetailedTimingDesc)))
1881    {
1882        DEBG(connectRef, "edid default\n");
1883        dmFlags |= kDisplayModeDefaultFlag;
1884    }
1885    if (kIOInterlacedCEATiming & timing->detailedInfo.v2.signalConfig)
1886    {
1887        connectRef->hasInterlaced = true;
1888        DEBG(connectRef, "hasInterlaced\n");
1889    }
1890#if 1
1891    // internal reduced blank timing switch
1892    else if (
1893        (kDisplayModeDefaultFlag & dmFlags)
1894        && connectRef->fbRange
1895        && CFDictionaryGetValue(connectRef->overrides, CFSTR(kIODisplayIsDigitalKey))
1896        && ((timing->detailedInfo.v2.pixelClock > connectRef->fbRange->maxPixelClock)
1897         || (connectRef->fbRange->maxLink0PixelClock
1898                && (timing->detailedInfo.v2.pixelClock > (connectRef->fbRange->maxLink0PixelClock * 1000ULL)))))
1899    {
1900        IOTimingInformation   _newTiming;
1901        IOTimingInformation * newTiming = &_newTiming;
1902        IOFBResolutionSpec    spec;
1903
1904        spec.timingID    = kIOTimingIDInvalid;
1905        spec.width       = timing->detailedInfo.v2.horizontalActive;
1906        spec.height      = timing->detailedInfo.v2.verticalActive;
1907        spec.refreshRate = RefreshRateFromDetailedTiming( &timing->detailedInfo.v2 );
1908        spec.flags       = kResSpecInternalReducedBlank;
1909
1910        err = StandardResolutionToDetailedTiming( connectRef, edid, &spec, newTiming );
1911        if (kIOReturnSuccess == err)
1912        {
1913#if RLOG
1914            DEBG(connectRef, "switching:\n");
1915            IOFBLogTiming(connectRef, timing);
1916#endif
1917            timing->detailedInfo.v2.pixelClock               = newTiming->detailedInfo.v2.pixelClock;
1918            timing->detailedInfo.v2.maxPixelClock            = newTiming->detailedInfo.v2.pixelClock;
1919            timing->detailedInfo.v2.minPixelClock            = newTiming->detailedInfo.v2.pixelClock;
1920            timing->detailedInfo.v2.horizontalActive         = newTiming->detailedInfo.v2.horizontalActive;
1921            timing->detailedInfo.v2.horizontalBlanking       = newTiming->detailedInfo.v2.horizontalBlanking;
1922            timing->detailedInfo.v2.verticalActive           = newTiming->detailedInfo.v2.verticalActive;
1923            timing->detailedInfo.v2.verticalBlanking         = newTiming->detailedInfo.v2.verticalBlanking;
1924            timing->detailedInfo.v2.horizontalSyncOffset     = newTiming->detailedInfo.v2.horizontalSyncOffset;
1925            timing->detailedInfo.v2.horizontalSyncPulseWidth = newTiming->detailedInfo.v2.horizontalSyncPulseWidth;
1926            timing->detailedInfo.v2.verticalSyncOffset       = newTiming->detailedInfo.v2.verticalSyncOffset;
1927            timing->detailedInfo.v2.verticalSyncPulseWidth   = newTiming->detailedInfo.v2.verticalSyncPulseWidth;
1928            timing->detailedInfo.v2.horizontalBorderLeft     = newTiming->detailedInfo.v2.horizontalBorderLeft;
1929            timing->detailedInfo.v2.horizontalBorderRight    = newTiming->detailedInfo.v2.horizontalBorderRight;
1930            timing->detailedInfo.v2.verticalBorderTop        = newTiming->detailedInfo.v2.verticalBorderTop;
1931            timing->detailedInfo.v2.verticalBorderBottom     = newTiming->detailedInfo.v2.verticalBorderBottom;
1932#if RLOG
1933            DEBG(connectRef, "switching to:\n");
1934            IOFBLogTiming(connectRef, timing);
1935#endif
1936        }
1937    }
1938#endif
1939
1940    if ((pixelRep = GetAssumedPixelRepetition((IODetailedTimingInformation *) &timing->detailedInfo.v2)))
1941    {
1942        enum { kNeedFeatures = (kIOScaleCanUpSamplePixels | kIOScaleCanScaleInterlaced) };
1943
1944        if (2 != pixelRep || !connectRef->scalerInfo)
1945            return (kIOReturnUnsupported);
1946
1947        if (kNeedFeatures != (kNeedFeatures & connectRef->scalerInfo->scalerFeatures))
1948            return (kIOReturnUnsupported);
1949
1950        if (timing->detailedInfo.v2.verticalActive > connectRef->scalerInfo->maxVerticalPixels)
1951            return (kIOReturnUnsupported);
1952        if ((timing->detailedInfo.v2.horizontalActive >> 1) > connectRef->scalerInfo->maxHorizontalPixels)
1953            return (kIOReturnUnsupported);
1954
1955        timing->detailedInfo.v2.scalerFlags      = kIOScaleStretchToFit;
1956        timing->detailedInfo.v2.horizontalScaled = timing->detailedInfo.v2.horizontalActive >> 1;
1957        timing->detailedInfo.v2.verticalScaled   = timing->detailedInfo.v2.verticalActive;
1958#if RLOG
1959        DEBG(connectRef, "pixel rep: %d\n", (int) pixelRep);
1960        IOFBLogTiming(connectRef, timing);
1961#endif
1962    }
1963
1964	uint16_t imageWidth = desc->horizImageSize    | ((desc->imageSizeHigh & 0xf0) << 4);
1965	uint16_t imageHeight = desc->verticalImageSize | ((desc->imageSizeHigh & 0x0f) << 8);
1966
1967	// sanity checks against display size
1968	if (imageWidth && connectRef->displayImageWidth)
1969	{
1970		if (((8 * imageWidth) < (5 * connectRef->displayImageWidth))
1971	     || (imageWidth > (connectRef->displayImageWidth + 9)))
1972		{
1973			imageWidth = 0;
1974		}
1975	}
1976	if (imageHeight && connectRef->displayImageHeight)
1977	{
1978		if (((8 * imageHeight) < (5 * connectRef->displayImageHeight))
1979	     || (imageHeight > (connectRef->displayImageHeight + 9)))
1980		{
1981			imageHeight = 0;
1982		}
1983	}
1984
1985	if ((!imageWidth) || (!imageHeight)) imageWidth = imageHeight = 0;
1986
1987    if (!connectRef->defaultWidth)
1988    {
1989    	// this mode is default
1990        connectRef->defaultWidth       = timing->detailedInfo.v2.horizontalActive;
1991        connectRef->defaultHeight      = timing->detailedInfo.v2.verticalActive;
1992        connectRef->defaultImageWidth  = imageWidth;
1993        connectRef->defaultImageHeight = imageHeight;
1994		if (!imageWidth)
1995		{
1996			imageWidth  = connectRef->displayImageWidth;
1997			imageHeight = connectRef->displayImageHeight;
1998		}
1999    }
2000	modeDesc.info.imageWidth  = imageWidth;
2001	modeDesc.info.imageHeight = imageHeight;
2002	modeDesc.info.flags       = dmFlags;
2003    err = InstallTiming( connectRef, &modeDesc, kIOFBEDIDDetailedMode );
2004
2005    return( err );
2006}
2007
2008static kern_return_t
2009InstallFromTimingOverride( IOFBConnectRef connectRef,
2010                           IODetailedTimingInformation * desc,
2011                           IOOptionBits dmFlags)
2012{
2013    IOReturn            err;
2014    IOFBDisplayModeDescription modeDesc;
2015    IOTimingInformation *      timing = &modeDesc.timingInfo;
2016
2017    bzero( &modeDesc, sizeof( modeDesc ));
2018    timing->flags = kIODetailedTimingValid;
2019
2020    TimingToHost( desc, &timing->detailedInfo.v2 );
2021
2022    if (!connectRef->defaultWidth)
2023    {
2024        connectRef->defaultWidth       = timing->detailedInfo.v2.horizontalActive;
2025        connectRef->defaultHeight      = timing->detailedInfo.v2.verticalActive;
2026        // doh!:
2027        connectRef->defaultImageWidth  = timing->detailedInfo.v2.horizontalActive;
2028        connectRef->defaultImageHeight = timing->detailedInfo.v2.verticalActive;
2029    }
2030	modeDesc.info.flags = dmFlags;
2031    err = InstallTiming( connectRef, &modeDesc, kIOFBEDIDDetailedMode );
2032
2033    return( err );
2034}
2035
2036static IOReturn
2037InstallTimingForResolution( IOFBConnectRef connectRef, EDID * edid,
2038                            IOFBResolutionSpec * spec,
2039                            IOOptionBits dmFlags, IOOptionBits modeGenFlags )
2040{
2041    IOReturn                   err;
2042    CFNumberRef                num;
2043    IOFBDisplayModeDescription modeDesc;
2044    IOTimingInformation *      timing = &modeDesc.timingInfo;
2045    bool                       isDigital;
2046
2047    bzero( &modeDesc, sizeof( modeDesc ));
2048    timing->flags = kIODetailedTimingValid;
2049
2050    do
2051    {
2052        err = StandardResolutionToDetailedTiming( connectRef, edid, spec, timing );
2053
2054        DEBG(connectRef, "%s std-mode for %dx%d@%d, id %d, genFlags 0x%x\n",
2055                (kIOReturnSuccess == err) ? "Have" : "No",
2056                (int) spec->width, (int) spec->height, (int)(spec->refreshRate + 0.5),
2057                (int) timing->appleTimingID, (int) modeGenFlags);
2058
2059        isDigital = (connectRef->overrides
2060                && CFDictionaryGetValue(connectRef->overrides, CFSTR(kIODisplayIsDigitalKey)));
2061
2062        if (kIOReturnSuccess == err)
2063        {
2064            if (kIOFBGTFMode & modeGenFlags)
2065            {
2066                modeGenFlags = kIOFBStdMode;
2067                dmFlags      = kDisplayModeValidFlag;
2068            }
2069        }
2070        else
2071        {
2072            if (!(kIOFBCVTEstMode & modeGenFlags)
2073#if GTF_ON_TV
2074                && !(connectRef->hasInterlaced)
2075#endif
2076                && isDigital)
2077            {
2078                err = kIOReturnUnsupportedMode;
2079                continue;
2080            }
2081            err = GTFToDetailedTiming( connectRef, edid, spec, 8,
2082                                          (IODetailedTimingInformation *) &timing->detailedInfo.v2 );
2083
2084            if( kIOReturnSuccess != err)
2085                continue;
2086        }
2087
2088        if( connectRef->overrides
2089         && (num = CFDictionaryGetValue( connectRef->overrides, CFSTR("sync") )))
2090         {
2091            UInt32 hSyncMask, hSyncValue, vSyncMask, vSyncValue;
2092
2093            CFNumberGetValue( num, kCFNumberSInt32Type, &vSyncValue );
2094            hSyncMask  = 0xff & (vSyncValue >> 24);
2095            hSyncValue = 0xff & (vSyncValue >> 16);
2096            vSyncMask  = 0xff & (vSyncValue >> 8);
2097            vSyncValue = 0xff & (vSyncValue >> 0);
2098            if ((hSyncValue != (timing->detailedInfo.v2.horizontalSyncConfig & hSyncMask))
2099             || (vSyncValue != (timing->detailedInfo.v2.verticalSyncConfig   & vSyncMask)))
2100            {
2101                err = kIOReturnUnsupportedMode;
2102                continue;
2103            }
2104        }
2105		modeDesc.info.flags = dmFlags;
2106        err = InstallTiming( connectRef, &modeDesc, modeGenFlags );
2107    }
2108    while (false);
2109
2110    DEBG(connectRef, "%x\n", err);
2111
2112    return (err);
2113}
2114
2115static IOReturn
2116InstallGTFResolution( IOFBConnectRef connectRef, EDID * edid,
2117                      float h, float v )
2118{
2119    IOReturn            err = kIOReturnSuccess;
2120    CFArrayRef          array;
2121    CFTypeRef           obj;
2122    CFIndex             count, i;
2123    IOOptionBits        dmFlags;
2124    IOFBResolutionSpec  spec;
2125    UInt32              width  = (UInt32) h;
2126    UInt32              height = (UInt32) v;                // rounding?
2127
2128    memset(&spec, 0, sizeof(spec));
2129    if (width > connectRef->dimensions.width)
2130        return (kIOReturnNoSpace);
2131    if (height > connectRef->dimensions.height)
2132        return (kIOReturnNoSpace);
2133
2134    array = CFDictionaryGetValue( connectRef->iographicsProperties, CFSTR("gtf-refresh-rates") );
2135    count = array ? CFArrayGetCount(array) : 0;
2136
2137    dmFlags = kDisplayModeValidFlag;
2138    if (connectRef->gtfDisplay)
2139        dmFlags |= kDisplayModeSafeFlag;
2140    if( !connectRef->gtfDisplay || (ratioOver(connectRef->nativeAspect, h / v) > 1.03125))
2141        dmFlags |= kDisplayModeNotPresetFlag;
2142
2143    spec.width         = width;
2144    spec.height        = height;
2145    spec.flags         = 0;
2146    if (connectRef->supportsReducedBlank)
2147        spec.flags |= kResSpecReducedBlank;
2148
2149    for (i = 0; i < count; i++)
2150    {
2151        obj = CFArrayGetValueAtIndex(array, i);
2152        if( CFNumberGetTypeID() != CFGetTypeID(obj))
2153            continue;
2154        CFNumberGetValue( (CFNumberRef) obj, kCFNumberFloatType, &spec.refreshRate );
2155
2156        err = InstallTimingForResolution( connectRef, edid,
2157                                          &spec, dmFlags, kIOFBGTFMode );
2158
2159        if ((kIOReturnSuccess != err)
2160          && connectRef->hasInterlaced)
2161        {
2162            spec.flags |= kResSpecNeedInterlace;
2163            err = InstallTimingForResolution( connectRef, edid,
2164                                              &spec, dmFlags, kIOFBGTFMode );
2165            spec.flags &= ~kResSpecNeedInterlace;
2166        }
2167    }
2168
2169    return (err);
2170}
2171
2172static void
2173InstallStandardEstablishedTiming(
2174                    IOFBConnectRef connectRef, EDID * edid,
2175                    IOFBResolutionSpec * spec )
2176
2177{
2178    InstallTimingForResolution( connectRef, edid, spec,
2179                                kDisplayModeValidFlag | kDisplayModeSafeFlag, kIOFBEDIDStdEstMode );
2180}
2181
2182static void
2183InstallStandardEstablishedTimings( IOFBConnectRef connectRef, EDID * edid  )
2184{
2185    CFDataRef           data;
2186    IOFBResolutionSpec  spec;
2187    UInt32 *            establishedIDs;
2188    UInt32              i;
2189
2190    memset(&spec, 0, sizeof(spec));
2191
2192    data = CFDictionaryGetValue(connectRef->iographicsProperties, CFSTR("established-ids"));
2193    if (data)
2194        establishedIDs = (UInt32 *) CFDataGetBytePtr(data);
2195    else
2196        establishedIDs = 0;
2197
2198    spec.flags = 0;
2199
2200    for( i = 7; establishedIDs && (i < 24); i++ )
2201    {
2202        if (0 != (edid->establishedTimings[ 2 - (i / 8) ] & (1 << (i % 8))))
2203        {
2204            spec.timingID = OSReadBigInt32(&establishedIDs[i], 0);
2205            if (spec.timingID != kIOTimingIDInvalid)
2206                InstallStandardEstablishedTiming(connectRef, edid, &spec);
2207        }
2208    }
2209
2210    for( i = 0; i < 8; i++ )
2211    {
2212        spec.timingID = kIOTimingIDInvalid;
2213        if (kIOReturnSuccess != DecodeStandardTiming(edid, OSReadBigInt16(&edid->standardTimings[i], 0),
2214                                                        &spec.width, &spec.height, &spec.refreshRate))
2215            continue;
2216        InstallStandardEstablishedTiming(connectRef, edid, &spec);
2217    }
2218}
2219
2220static void
2221InstallCVTStandardTimings( IOFBConnectRef connectRef, EDID * edid  )
2222{
2223    EDIDGeneralDesc *   desc;
2224    CFDataRef           data;
2225    CFArrayRef          array;
2226    CFIndex             i, count;
2227    IOFBResolutionSpec  spec;
2228    UInt8 *             bits;
2229
2230    memset(&spec, 0, sizeof(spec));
2231
2232    connectRef->gtfDisplay = (0 != (edid->featureSupport & 1));
2233
2234    data = CFDictionaryGetValue(connectRef->overrides, CFSTR("drng"));
2235    if (!data)
2236        return;
2237    desc = (EDIDGeneralDesc *) CFDataGetBytePtr(data);
2238
2239    if (0x04 == desc->data[5])
2240    {
2241        connectRef->cvtDisplay = true;
2242        connectRef->gtfDisplay = true;
2243    }
2244
2245    if (!connectRef->cvtDisplay)
2246        return;
2247
2248    array = CFDictionaryGetValue(connectRef->iographicsProperties, CFSTR("cvt-established-ids"));
2249    if (!array)
2250        return;
2251
2252    count = CFArrayGetCount(array);
2253    if (count > (7 * 8))
2254        count = 7 * 8;
2255    bits = &desc->data[6];
2256    for (i = 0; i < count; i++)
2257    {
2258        if (0 != (bits[i / 8] & (0x80 >> (i % 8))))
2259        {
2260            UInt32 * rec;
2261            CFIndex  num;
2262
2263            data = CFArrayGetValueAtIndex(array, i);
2264            rec = (UInt32 *) CFDataGetBytePtr(data);
2265            num = CFDataGetLength(data) / sizeof(UInt32);
2266            if (num < 4)
2267                continue;
2268
2269            spec.width         = OSReadBigInt32(rec, 0);
2270            spec.height        = OSReadBigInt32(rec, 4);
2271            spec.refreshRate   = OSReadBigInt32(rec, 8);
2272            spec.flags         = OSReadBigInt32(rec, 12);
2273            if (num >= 5)
2274                spec.timingID  = OSReadBigInt32(rec, 16);
2275            else
2276                spec.timingID  = kIOTimingIDInvalid;
2277
2278            connectRef->supportsReducedBlank |= (0 != (kResSpecReducedBlank & spec.flags));
2279
2280            InstallTimingForResolution(connectRef, edid, &spec,
2281                                        kDisplayModeValidFlag | kDisplayModeSafeFlag, kIOFBCVTEstMode);
2282        }
2283    }
2284}
2285
2286static Boolean
2287IODisplayConsiderAspect( float w, float h, float * aspectWidth, float * aspectHeight )
2288{
2289    float ratio;
2290
2291    if (!w || !h)
2292        return (false);
2293
2294    ratio = w / h;
2295
2296    if ((ratio > 1.85) || (ratio < 1.2))
2297    {
2298        *aspectWidth = w;
2299        *aspectHeight = h;
2300        return (true);
2301    }
2302
2303    if (ratio > 1.65)
2304    {
2305        *aspectWidth = 16.0;
2306        *aspectHeight = 9.0;
2307        return (true);
2308    }
2309
2310    if (ratio > 1.55)
2311    {
2312        *aspectWidth = 16.0;
2313        *aspectHeight = 10.0;
2314        return (true);
2315    }
2316
2317    if (ratio > 1.45)
2318    {
2319        *aspectWidth = 3.0;
2320        *aspectHeight = 2.0;
2321        return (true);
2322    }
2323
2324    return (false);
2325}
2326
2327static void
2328IODisplayGetAspect( IOFBConnectRef connectRef )
2329{
2330    CFDictionaryRef ovr;
2331    CFNumberRef     imageH, imageV;
2332    float           aspectWidth, aspectHeight;
2333    float           w, h;
2334
2335    aspectWidth    = 4.0;
2336    aspectHeight   = 3.0;
2337
2338    ovr = connectRef->overrides;
2339    do
2340    {
2341        if (IODisplayConsiderAspect(connectRef->defaultWidth, connectRef->defaultHeight,
2342                                    &aspectWidth, &aspectHeight))
2343            break;
2344
2345        if (IODisplayConsiderAspect(connectRef->defaultImageWidth, connectRef->defaultImageHeight,
2346                                    &aspectWidth, &aspectHeight))
2347            break;
2348
2349        if( ovr)
2350        {
2351            imageH = CFDictionaryGetValue( ovr, CFSTR(kDisplayHorizontalImageSize) );
2352            imageV = CFDictionaryGetValue( ovr, CFSTR(kDisplayVerticalImageSize) );
2353            if (imageH && imageV)
2354            {
2355                CFNumberGetValue( imageH, kCFNumberFloatType, &w );
2356                CFNumberGetValue( imageV, kCFNumberFloatType, &h );
2357                if (IODisplayConsiderAspect(w, h, &aspectWidth, &aspectHeight))
2358                    break;
2359            }
2360        }
2361    }
2362    while (false);
2363
2364    connectRef->nativeAspect = aspectWidth / aspectHeight;
2365}
2366
2367
2368static kern_return_t
2369InstallGTFTimings( IOFBConnectRef connectRef, EDID * edid )
2370{
2371    IOReturn            err = kIOReturnSuccess;
2372    CFArrayRef          array;
2373    CFIndex             i, count;
2374    CFStringRef         key;
2375    float               h, v, nativeAspect;
2376    Boolean             wide, displayNot4By3;
2377
2378    // arb timings
2379
2380    nativeAspect = connectRef->nativeAspect;
2381    wide = (nativeAspect > 1.45);
2382    displayNot4By3 = (ratioOver(nativeAspect, 4.0 / 3.0) > 1.03125);
2383
2384    key = wide ? CFSTR("gtf-resolutions-wide") : CFSTR("gtf-resolutions");
2385    array = CFDictionaryGetValue( connectRef->iographicsProperties, key );
2386    count = array ? CFArrayGetCount(array) : 0;
2387
2388    for( i = 0; i < count; i++)
2389    {
2390        CFTypeRef obj;
2391
2392        obj = CFArrayGetValueAtIndex(array, i);
2393        if( CFNumberGetTypeID() == CFGetTypeID(obj)) {
2394            SInt32      value;
2395            CFNumberGetValue( (CFNumberRef) obj, kCFNumberSInt32Type, &value );
2396            h = (float) (value & 0xffff);
2397            v = (float) (value >> 16);
2398
2399        } else
2400            continue;
2401
2402        if (v)
2403        {
2404            err = InstallGTFResolution( connectRef, edid, h, v );
2405        }
2406        else
2407        {
2408            if (displayNot4By3)
2409            {
2410                err = InstallGTFResolution( connectRef, edid, h, (h * 3.0) / 4.0 );
2411            }
2412            err = InstallGTFResolution( connectRef, edid, h, h / nativeAspect );
2413        }
2414    }
2415
2416    return( err );
2417}
2418
2419static void
2420InstallDIEXT( IOFBConnectRef connectRef, EDID *edid __unused, DIEXT * ext, Boolean installModes )
2421{
2422    UInt16 minPixelClockPerLink, maxPixelClockPerLink, crossover;
2423
2424    if (installModes)
2425        return;
2426
2427    minPixelClockPerLink = ext->minPixelClockPerLink;
2428    maxPixelClockPerLink = (ext->maxPixelClockPerLink[1] << 16) | ext->maxPixelClockPerLink[0];
2429    crossover = (ext->crossoverFreq[1] << 16) | ext->crossoverFreq[0];
2430
2431    if ((3 == ext->standardSupported) || (4 == ext->standardSupported))
2432    {
2433        connectRef->dualLinkCrossover = ((UInt64) crossover) * 1000000ULL;
2434        connectRef->maxDisplayLinks = 2;
2435    }
2436    else
2437        connectRef->maxDisplayLinks = 1;
2438
2439    switch (ext->dataFormats)
2440    {
2441        case 0x24:
2442        case 0x48:
2443            connectRef->supportedComponentDepths[kAllVendors] |= kIODisplayRGBColorComponentBits8;
2444            break;
2445        case 0x49:
2446            connectRef->supportedComponentDepths[kAllVendors] |= kIODisplayRGBColorComponentBits16;
2447            break;
2448    }
2449
2450    DEBG(connectRef, "(%d) minPixelClockPerLink %d, maxPixelClockPerLink %d, cross %qd\n",
2451            ext->standardSupported,
2452            minPixelClockPerLink, maxPixelClockPerLink, connectRef->dualLinkCrossover);
2453}
2454
2455static void
2456InstallVTBEXT( IOFBConnectRef connectRef, EDID * edid, VTBEXT * ext, Boolean installModes )
2457{
2458    IOByteCount        offset = 0;
2459    IOItemCount        idx, count;
2460    IOFBResolutionSpec spec;
2461    Boolean            malformed = false;
2462
2463    if (!installModes)
2464        return;
2465
2466    do
2467    {
2468        count = ext->numDetailedTimings;
2469        for (idx = 0; idx < count; idx++)
2470        {
2471            malformed = (offset > (sizeof(ext->data) - sizeof(EDIDDetailedTimingDesc)));
2472            if (malformed)
2473                break;
2474            InstallFromEDIDDesc( connectRef,
2475                                    edid, (EDIDDetailedTimingDesc *) &ext->data[offset],
2476                                    kDisplayModeValidFlag | kDisplayModeSafeFlag );
2477            offset += sizeof(EDIDDetailedTimingDesc);
2478        }
2479        if (malformed)
2480            break;
2481
2482        // --
2483        count = ext->numCVTTimings;
2484        for (idx = 0; idx < count; idx++)
2485        {
2486            SInt32              refreshBit;
2487            UInt32              vsize;
2488            VTBCVTTimingDesc *  desc;
2489            static const UInt32 cvtRefreshRates[] = { 60, 85, 75, 60, 50 };
2490
2491            malformed = (offset > (sizeof(ext->data) - sizeof(VTBCVTTimingDesc)));
2492            if (malformed)
2493                break;
2494
2495            desc = (VTBCVTTimingDesc *) &ext->data[offset];
2496            vsize = ((desc->verticalSizeHigh & 0xf0) << 4) | desc->verticalSize;
2497            vsize = 2 * (vsize + 1);
2498            spec.height = vsize;
2499            switch (kVTBCVTAspectRatioMask & desc->verticalSizeHigh)
2500            {
2501                case kVTBCVTAspectRatio16By10:
2502                    spec.width = (vsize * 16) / 10;
2503                    break;
2504                case kVTBCVTAspectRatio16By9:
2505                    spec.width = (vsize * 16) / 9;
2506                    break;
2507                case kVTBCVTAspectRatio4By3:
2508                default:
2509                    spec.width = (vsize * 4) / 3;
2510                    break;
2511            }
2512            spec.timingID      = kIOTimingIDInvalid;
2513            spec.width &= ~7;
2514            for (refreshBit = 4; refreshBit >= 0; refreshBit--)
2515            {
2516                if ((1 << refreshBit) & desc->refreshRates)
2517                {
2518                    spec.refreshRate   = cvtRefreshRates[refreshBit];
2519                    spec.flags = (kVTBCVTRefresh60RBlank == (1 << refreshBit)) ? kResSpecReducedBlank : kNilOptions;
2520                    InstallTimingForResolution(connectRef, edid, &spec,
2521                                            kDisplayModeValidFlag | kDisplayModeSafeFlag, kIOFBCVTEstMode);
2522                    DEBG(connectRef, "VTB cvt: %dx%d @ %f (%x)\n",
2523                            (int) spec.width, (int) spec.height, spec.refreshRate, (int) spec.flags);
2524                }
2525            }
2526            offset += sizeof(VTBCVTTimingDesc);
2527        }
2528
2529        // --
2530        count = ext->numStandardTimings;
2531        for (idx = 0; idx < count; idx++)
2532        {
2533            UInt16 stdTiming;
2534
2535            malformed = (offset > (sizeof(ext->data) - sizeof(UInt16)));
2536            if (malformed)
2537                break;
2538
2539            spec.flags    = 0;
2540            spec.timingID = kIOTimingIDInvalid;
2541            stdTiming = (ext->data[offset] << 8) | ext->data[offset + 1];
2542
2543            DEBG(connectRef, "VTB st: %04x\n", stdTiming);
2544            if (kIOReturnSuccess != DecodeStandardTiming(edid, stdTiming,
2545                                                            &spec.width, &spec.height, &spec.refreshRate))
2546                continue;
2547            DEBG(connectRef, "VTB st: %dx%d @ %f (%x)\n",
2548                    (int) spec.width, (int) spec.height, spec.refreshRate, (int) spec.flags);
2549            InstallStandardEstablishedTiming(connectRef, edid, &spec);
2550            offset += sizeof(UInt16);
2551        }
2552    }
2553    while (false);
2554}
2555
2556enum {
2557    // flags
2558    kCEASupportUnderscan    = 0x80,
2559    kCEASupportBasicAudio   = 0x40,
2560    kCEASupportYCbCr444     = 0x20,
2561    kCEASupportYCbCr422     = 0x10,
2562    kCEASupportNativeCount  = 0x0F,
2563};
2564enum {
2565    kHDMISupportFlagAI      = 0x80,
2566    kHDMISupportFlagDC48    = 0x40,
2567    kHDMISupportFlagDC36    = 0x20,
2568    kHDMISupportFlagDC30    = 0x10,
2569    kHDMISupportFlagDCY444  = 0x08,
2570    kHDMISupportFlagDVIDual = 0x01,
2571};
2572
2573static void
2574InstallCEA861EXTColor( IOFBConnectRef connectRef, EDID * edid __unused, CEA861EXT * ext )
2575{
2576    IOByteCount offset = ext->detailedTimingsOffset;
2577
2578    if( offset < 4 )
2579        return;
2580    offset -= 4;
2581
2582    if (0x03 <= ext->version)
2583    {
2584        // Start by looking for the HDMI Identifier.  We need to know this before processing
2585        // the short video descriptor block.
2586        IOByteCount index;
2587        IOByteCount length;
2588
2589        connectRef->supportedComponentDepths[kAllVendors] |= kIODisplayRGBColorComponentBits8;
2590        if (kCEASupportYCbCr444 & ext->flags)
2591        {
2592            connectRef->supportedColorModes[kAllVendors] |= kIODisplayColorModeYCbCr444;
2593            connectRef->supportedComponentDepths[kAllVendors] |= kIODisplayYCbCr444ColorComponentBits8;
2594        }
2595        if (kCEASupportYCbCr422 & ext->flags)
2596        {
2597            connectRef->supportedColorModes[kAllVendors]      |= kIODisplayColorModeYCbCr422;
2598            connectRef->supportedComponentDepths[kAllVendors] |= kIODisplayYCbCr422ColorComponentBits8;
2599        }
2600
2601        index = 0;
2602        while( index < offset )
2603        {
2604            length = (ext->data[index] & 0x1f) + 1;
2605            switch( (ext->data[index] & 0xE0) )
2606            {
2607                // HDMI Vendor Specific Data Block (HDMI 1.3a, p.119)
2608                case 0x60:
2609                {
2610					if (length < 4) break;
2611
2612					if (connectRef->displayAttributes)
2613					{
2614						CFMutableDataRef data;
2615						CFStringRef key;
2616						char name[strlen("IODisplayVSDB") + 10];
2617						sprintf(name, "IODisplayVSDB%02X%02X%02X",
2618								ext->data[index+1], ext->data[index+2], ext->data[index+3]);
2619						key = CFStringCreateWithCString(kCFAllocatorDefault, name,
2620														kCFStringEncodingMacRoman);
2621						if (key)
2622						{
2623							data = (CFMutableDataRef) CFDictionaryGetValue(connectRef->displayAttributes, key);
2624							if (!data)
2625							{
2626								data = CFDataCreateMutable(kCFAllocatorDefault, 0);
2627								if (data)
2628								{
2629									CFDictionarySetValue(connectRef->displayAttributes, key, data);
2630									CFRelease(data);
2631								}
2632							}
2633							if (data) CFDataAppendBytes(data, &ext->data[index + 4], length - 4);
2634							CFRelease(key);
2635						}
2636					}
2637                    DEBG( connectRef, "Found 24-bit IEEE Registration Identifier (0x%02x%02x%02x)\n",
2638                            ext->data[index+3], ext->data[index+2], ext->data[index+1] );
2639
2640                    if ((ext->data[index+1] != 0x03)
2641                      || (ext->data[index+2] != 0x0C)
2642                      || (ext->data[index+3] != 0x00))
2643                        break;
2644
2645                    DEBG( connectRef, "Found HDMI VSDB: offset=%d\n", (int) (index + 4) );
2646                    connectRef->hasHDMI = true;
2647
2648                    if (length < 7) break;
2649
2650                    uint32_t depths;
2651                    uint8_t byte;
2652                    byte = ext->data[index+6];
2653                    depths = kIODisplayRGBColorComponentBits8;
2654#if 0
2655                    if (kHDMISupportFlagDC30 & byte)
2656                        depths |= kIODisplayRGBColorComponentBits10;
2657                    if (kHDMISupportFlagDC36 & byte)
2658                        depths |= kIODisplayRGBColorComponentBits12;
2659                    if (kHDMISupportFlagDC48 & byte)
2660                        depths |= kIODisplayRGBColorComponentBits16;
2661#endif
2662                    if (kHDMISupportFlagDCY444 & byte)
2663                        depths |= (depths * kIODisplayYCbCr444ColorComponentBits6);
2664                    connectRef->supportedComponentDepths[kAllVendors] |= depths;
2665                    break;
2666                }
2667            }
2668            index += length;
2669        }
2670    }
2671}
2672
2673static void
2674InstallCEA861EXT( IOFBConnectRef connectRef, EDID * edid, CEA861EXT * ext, Boolean installModes )
2675{
2676    IOReturn err;
2677    IOByteCount offset = ext->detailedTimingsOffset;
2678
2679    connectRef->useScalerUnderscan = (connectRef->scalerInfo
2680        && (kIOScaleCanSupportInset & connectRef->scalerInfo->scalerFeatures));
2681    connectRef->addTVFlag = true;
2682
2683    if( offset < 4 )
2684        return;
2685    offset -= 4;
2686
2687    if (0x03 <= ext->version)
2688    {
2689        IOByteCount index;
2690        IOByteCount length;
2691
2692        // Now we look for the short video descriptor block.
2693        index = 0;
2694        while( index < offset )
2695        {
2696            length = (ext->data[index] & 0x1f) + 1;
2697            switch( (ext->data[index] & 0xE0) )
2698            {
2699                // Short Video Descriptors (CEA-861-E p.59).
2700                case 0x40:
2701                    DEBG( connectRef, "Found Video Data Block: offset=%d\n", (int) (index + 4) );
2702                    if (installModes)
2703                        InstallFromCEAShortVideoDesc( connectRef, &ext->data[index] );
2704                    connectRef->hasShortVideoDescriptors = true;
2705                    break;
2706
2707                // HDMI Vendor Specific Data Block (HDMI 1.3a, p.119)
2708                case 0x60:
2709                {
2710					uint32_t vicOffset, vicCount;
2711
2712					if (length < 8) break;
2713                    if ((ext->data[index+1] != 0x03)
2714                     || (ext->data[index+2] != 0x0C)
2715                     || (ext->data[index+3] != 0x00)) break;
2716
2717                    if (ext->data[index+7])
2718                    {
2719                    	connectRef->dualLinkCrossover = ext->data[index+7] * 5000000ULL;
2720  				    }
2721
2722                    if (!installModes) break;
2723					if (length < 9)    break;
2724					// hdmi video present?
2725					if (!(0x20 & ext->data[index + 8])) break;
2726					vicOffset = 10;
2727					// latency fields present?
2728					if (0x80 & ext->data[index + 8]) vicOffset += 2;
2729					if (0x40 & ext->data[index + 8]) vicOffset += 2;
2730
2731					if (vicOffset >= length) break;
2732                    vicCount = ext->data[index + vicOffset];
2733					vicCount >>= 5;
2734					vicOffset++;
2735					if ((vicOffset + vicCount) > length) vicCount = length - vicOffset;
2736					vicOffset += index;
2737                    DEBG( connectRef, "Found HDMI VICs %d@%d\n", vicCount, vicOffset );
2738					InstallFromHDMIVIC(connectRef, vicCount, &ext->data[vicOffset]);
2739				}
2740            }
2741            index += length;
2742        }
2743
2744        if ((kCEASupportUnderscan & ext->flags) && !connectRef->hasShortVideoDescriptors)
2745        {
2746            // version 3 requires CEA modes to have short video descriptors,
2747            // so no CEA modes on this display
2748            connectRef->useScalerUnderscan = false;
2749            connectRef->addTVFlag = false;
2750        }
2751    }
2752
2753    if ((1 == (kCEASupportNativeCount & ext->flags))
2754        && (kDisplayAppleVendorID == connectRef->displayVendor))
2755    {
2756        connectRef->defaultOnly = true;
2757    }
2758
2759    if (!installModes)
2760    {
2761        InstallCEA861EXTColor(connectRef, edid, ext);
2762        return;
2763    }
2764
2765    // Process the CEA Detailed Timing Descriptor.
2766    while (offset <= (sizeof(ext->data) - sizeof(EDIDDetailedTimingDesc)))
2767    {
2768        DEBG(connectRef, "FromCEA:\n");
2769        err = InstallFromEDIDDesc( connectRef,
2770                                   edid, (EDIDDetailedTimingDesc *) &ext->data[offset],
2771                                   kDisplayModeValidFlag | kDisplayModeSafeFlag );
2772        if (connectRef->defaultOnly
2773         && ((kIOReturnSuccess == err) || (kIOReturnPortExists == err)))
2774            break;
2775        offset += sizeof(EDIDDetailedTimingDesc);
2776    }
2777}
2778
2779static kern_return_t
2780InstallFromDisplayIDDetailedType1(IOFBConnectRef connectRef, EDID * edid,
2781                                  const DisplayIDDetailedType1 * desc,
2782                                  IOOptionBits dmFlags)
2783{
2784    kern_return_t                 err;
2785    IOFBDisplayModeDescription    modeDesc;
2786    IODetailedTimingInformation * timing = (IODetailedTimingInformation *) &modeDesc.timingInfo.detailedInfo.v2;
2787
2788    DEBG(connectRef, "FromDIDType1\n");
2789
2790    bzero(&modeDesc, sizeof( modeDesc));
2791    modeDesc.timingInfo.flags = kIODetailedTimingValid;
2792
2793    timing->signalConfig                = (edid->displayParams[0] & 16)
2794                                        ? kIOAnalogSetupExpected : 0;
2795    timing->signalLevels                = (edid->displayParams[0] >> 5) & 3;
2796
2797    timing->pixelClock                  = (1+ ((((UInt64)desc->pixelClock[2]) << 16)
2798                                            | (((UInt64)desc->pixelClock[1]) << 8)
2799                                            | desc->pixelClock[0]))
2800                                        * 10000ULL;
2801    timing->maxPixelClock               = timing->pixelClock;
2802    timing->minPixelClock               = timing->pixelClock;
2803
2804    if (!timing->pixelClock)            return( kIOReturnBadArgument );
2805
2806    timing->horizontalActive            = (1+ ((((UInt32)desc->horizActive[1]) << 8)
2807                                        | desc->horizActive[0]));
2808    timing->horizontalBlanking          = (1+ ((((UInt32)desc->horizBlanking[1]) << 8)
2809                                        | desc->horizBlanking[0]));
2810    timing->horizontalSyncOffset        = (1+ ((((UInt32)(0x7F & desc->horizSyncOffset[1])) << 8)
2811                                        | desc->horizSyncOffset[0]));
2812    timing->horizontalSyncPulseWidth    = (1+ ((((UInt32)desc->horizSyncWidth[1]) << 8)
2813                                        | desc->horizSyncWidth[0]));
2814    timing->horizontalSyncConfig        = (0x80 & desc->horizSyncOffset[1])
2815                                        ? kIOSyncPositivePolarity : 0;
2816    timing->horizontalSyncLevel         = 0;
2817
2818    timing->verticalActive            = (1+ ((((UInt32)desc->verticalActive[1]) << 8)
2819                                        | desc->verticalActive[0]));
2820    timing->verticalBlanking          = (1+ ((((UInt32)desc->verticalBlanking[1]) << 8)
2821                                        | desc->verticalBlanking[0]));
2822    timing->verticalSyncOffset        = (1+ ((((UInt32)(0x7F & desc->verticalSyncOffset[1])) << 8)
2823                                        | desc->verticalSyncOffset[0]));
2824    timing->verticalSyncPulseWidth    = (1+ ((((UInt32)desc->verticalSyncWidth[1]) << 8)
2825                                        | desc->verticalSyncWidth[0]));
2826    timing->verticalSyncConfig        = (0x80 & desc->verticalSyncOffset[1])
2827                                        ? kIOSyncPositivePolarity : 0;
2828    timing->verticalSyncLevel         = 0;
2829
2830    timing->horizontalBorderLeft        = 0;
2831    timing->horizontalBorderRight       = 0;
2832    timing->verticalBorderTop           = 0;
2833    timing->verticalBorderBottom        = 0;
2834
2835    bool interlaced = (0 != (desc->flags & 0x10));
2836    if (interlaced)
2837        AdjustTimingForInterlace(timing);
2838
2839    if (0 != (desc->flags & 0x80))
2840    {
2841        DEBG(connectRef, "default\n");
2842        dmFlags |= kDisplayModeDefaultFlag;
2843    }
2844
2845	modeDesc.info.imageWidth  = connectRef->displayImageWidth;
2846	modeDesc.info.imageHeight = connectRef->displayImageHeight;
2847	modeDesc.info.flags       = dmFlags;
2848
2849    err = InstallTiming(connectRef, &modeDesc, kIOFBEDIDDetailedMode);
2850
2851    return (err);
2852}
2853
2854static void
2855InstallDisplayIDEXT(IOFBConnectRef connectRef, EDID * edid, DisplayIDEXT * ext, Boolean installModes)
2856{
2857    if (!installModes) return;
2858
2859    const DisplayIDBlock * block;
2860    uint32_t               bytes, offset;
2861
2862    bytes = ext->sectionSize;
2863
2864    const   uint8_t * byte = &ext->version;
2865    const   uint8_t * end  = byte + bytes + 5;
2866    uint8_t sum = 0;
2867
2868    while (byte < end) sum += *byte++;
2869    if (sum) return;
2870
2871    offset = 0;
2872    while (bytes >= sizeof(DisplayIDBlock))
2873    {
2874        block  = (typeof(block)) &ext->section[offset];
2875        bytes -= sizeof(DisplayIDBlock);
2876        if (bytes < block->size) break;
2877        switch (block->type)
2878        {
2879            case kDIDBlockTypeDetailedType1:
2880            {
2881                const DisplayIDBlockDetailedType1 * detailedBlock = (typeof(detailedBlock)) block;
2882                uint32_t                            count, idx;
2883
2884                count = block->size / sizeof(DisplayIDDetailedType1);
2885                for (idx = 0; idx < count; idx++)
2886                {
2887                    InstallFromDisplayIDDetailedType1(connectRef, edid, &detailedBlock->detailed[idx],
2888                                                kDisplayModeValidFlag | kDisplayModeSafeFlag);
2889                }
2890                break;
2891            }
2892            default:
2893                break;
2894        }
2895        bytes -= block->size;
2896        offset += block->size;
2897    }
2898}
2899
2900static void
2901LookExtensions( IOFBConnectRef connectRef,
2902                EDID * edid, UInt8 * blocks, IOByteCount length, Boolean installModes)
2903{
2904    UInt8 tag;
2905
2906    while (length >= 128)
2907    {
2908        tag = blocks[0];
2909        switch (tag)
2910        {
2911            case kExtTagDI:
2912                InstallDIEXT( connectRef, edid, (DIEXT *) blocks, installModes);
2913                connectRef->hasDIEXT = true;
2914                break;
2915            case kExtTagVTB:
2916                InstallVTBEXT( connectRef, edid, (VTBEXT *) blocks, installModes);
2917                break;
2918            case kExtTagCEA:
2919                connectRef->hasCEAExt = true;
2920                InstallCEA861EXT( connectRef, edid, (CEA861EXT *) blocks, installModes);
2921                break;
2922            case kExtTagDID:
2923                InstallDisplayIDEXT(connectRef, edid, (DisplayIDEXT *) blocks, installModes);
2924                break;
2925        }
2926        length -= 128;
2927        blocks += 128;
2928    }
2929}
2930
2931__private_extern__ void
2932IODisplayInstallTimings( IOFBConnectRef connectRef )
2933{
2934    int                         i;
2935    io_service_t                service = connectRef->framebuffer;
2936    EDID *                      edid = 0;
2937    CFDataRef                   fbRange;
2938    CFDataRef                   edidData;
2939    CFDataRef                   data;
2940    CFArrayRef                  array;
2941    CFIndex                     count;
2942    bool                        checkDI = false;
2943
2944    static const GTFTimingCurve defaultGTFCurves[] = {
2945        { 0,          40, 600, 128, 20 },
2946        { 0xffffffff,  0,   0,   0,  0 }
2947    };
2948
2949    // controller timing range
2950    fbRange = (CFDataRef) IORegistryEntryCreateCFProperty( service,
2951                                                            CFSTR(kIOFBTimingRangeKey),
2952                                                            kCFAllocatorDefault, kNilOptions);
2953    if (fbRange && (size_t) CFDataGetLength(fbRange) >= sizeof(IODisplayTimingRange))
2954        connectRef->fbRange = (IODisplayTimingRange *) CFDataGetBytePtr(fbRange);
2955
2956
2957    // dpcd
2958    connectRef->dpcdData = (CFDataRef) IORegistryEntrySearchCFProperty(service, kIOServicePlane,
2959                                                            CFSTR(kIOFBDisplayPortConfigurationDataKey),
2960                                                            kCFAllocatorDefault,
2961                                                            kIORegistryIterateParents|kIORegistryIterateRecursively);
2962    // hdmi dongle
2963    connectRef->hdmiData = (CFDataRef) IORegistryEntrySearchCFProperty(service, kIOServicePlane,
2964                                                            CFSTR(kIOFBHDMIDongleROMKey),
2965                                                            kCFAllocatorDefault,
2966                                                            kIORegistryIterateParents|kIORegistryIterateRecursively);
2967
2968    connectRef->vendorsFound = (1 << kAllVendors);
2969    for (i = 0; i < kNumVendors; i++)
2970    {
2971        connectRef->supportedComponentDepths[i] = kIODisplayRGBColorComponentBitsUnknown;
2972        if (i == kAllVendors)
2973            connectRef->supportedColorModes[i]  = kIODisplayColorModeRGB;
2974        else
2975            connectRef->supportedColorModes[i]  = kIODisplayColorModeReserved;
2976        connectRef->ditherControl[i]            = kIODisplayDitherControlDefault;
2977    }
2978
2979    connectRef->defaultIndex         = 0;
2980    connectRef->defaultOnly          = false;
2981    connectRef->gtfDisplay           = false;
2982    connectRef->cvtDisplay           = false;
2983    connectRef->supportsReducedBlank = false;
2984    connectRef->hasInterlaced        = false;
2985    connectRef->hasDIEXT             = false;
2986    connectRef->hasCEAExt            = false;
2987    connectRef->hasHDMI              = false;
2988    connectRef->hasShortVideoDescriptors = false;
2989    connectRef->numGTFCurves         = 1;
2990    bcopy(&defaultGTFCurves, &connectRef->gtfCurves, sizeof(connectRef->gtfCurves));
2991
2992	if (connectRef->displayAttributes) CFRelease(connectRef->displayAttributes);
2993	connectRef->displayAttributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
2994													&kCFTypeDictionaryKeyCallBacks,
2995													&kCFTypeDictionaryValueCallBacks);
2996
2997    // defaults for no DIEXT
2998    if (CFDictionaryGetValue(connectRef->overrides, CFSTR(kIODisplayIsDigitalKey)))
2999    {
3000        connectRef->dualLinkCrossover = 165000000ULL;
3001        connectRef->maxDisplayLinks   = 2;
3002    }
3003    else
3004    {
3005        connectRef->dualLinkCrossover = 0;
3006        connectRef->maxDisplayLinks   = 0;
3007    }
3008
3009#if RLOG
3010    DEBG(connectRef, "FB range:\n");
3011    IOFBLogRange(connectRef, connectRef->fbRange);
3012
3013    DEBG(connectRef, "Display range:\n");
3014    data = CFDictionaryGetValue(connectRef->overrides, CFSTR("trng"));
3015    if (data && (((size_t)CFDataGetLength(data)) >= sizeof(IODisplayTimingRange)))
3016        IOFBLogRange(connectRef, (IODisplayTimingRange *) CFDataGetBytePtr(data));
3017#endif
3018
3019    do
3020    {
3021        // EDID timings
3022
3023        edidData = CFDictionaryGetValue( connectRef->overrides, CFSTR(kIODisplayEDIDKey) );
3024        if( !edidData || ((size_t) CFDataGetLength(edidData) < sizeof( EDID)) )
3025            continue;
3026#if RLOG
3027        if (connectRef->logfile)
3028        {
3029            DEBG(connectRef, "EDID\n");
3030            fprintf(connectRef->logfile, "/*          0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F */");
3031            for (i = 0; i < CFDataGetLength(edidData); i++)
3032            {
3033                if( 0 == (i & 15))
3034                    fprintf(connectRef->logfile, "\n/* %02X */ ", i);
3035                fprintf(connectRef->logfile, "0x%02x,", CFDataGetBytePtr( edidData )[i]);
3036            }
3037            fprintf(connectRef->logfile, "\n");
3038            fflush(connectRef->logfile);
3039        }
3040#endif
3041        edid = (EDID *) CFDataGetBytePtr( edidData );
3042
3043        static const uint8_t checkHeader[] = { 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0x00 };
3044        if (bcmp(&checkHeader[0], &edid->header[0], sizeof(checkHeader)))
3045        {
3046            edid = 0;
3047            continue;
3048        }
3049
3050        if (2 & edid->featureSupport)
3051        {}
3052        else if ((kDisplayAppleVendorID == connectRef->displayVendor)
3053        	  && ((edid->version > 1) || (edid->revision >= 3)))
3054        {
3055            checkDI = true;
3056        }
3057        else
3058            connectRef->defaultIndex = -1;
3059
3060        DEBG(connectRef, "EDID default idx %d, only %d\n",
3061                connectRef->defaultIndex, connectRef->defaultOnly);
3062
3063        connectRef->displayImageWidth  = edid->displayParams[1] * 10;
3064        connectRef->displayImageHeight = edid->displayParams[2] * 10;
3065
3066        uint8_t videoInput = edid->displayParams[0];
3067        if ((0x80 & videoInput) && ((edid->version > 1) || (edid->revision >= 4)))
3068        {
3069            static const uint32_t depths[8] = {
3070                kIODisplayRGBColorComponentBitsUnknown, kIODisplayRGBColorComponentBits6,
3071                kIODisplayRGBColorComponentBits8,       kIODisplayRGBColorComponentBits10,
3072                kIODisplayRGBColorComponentBits12,      kIODisplayRGBColorComponentBits14,
3073                kIODisplayRGBColorComponentBits16,      kIODisplayRGBColorComponentBitsUnknown
3074            };
3075            static const uint32_t modes[4] = {
3076                kIODisplayColorModeRGB,
3077                kIODisplayColorModeRGB | kIODisplayColorModeYCbCr444,
3078                kIODisplayColorModeRGB | kIODisplayColorModeYCbCr422,
3079                kIODisplayColorModeRGB | kIODisplayColorModeYCbCr444 | kIODisplayColorModeYCbCr422,
3080            };
3081            uint32_t supportedModes, supportedDepths;
3082
3083            /* feature support */
3084            supportedModes  = modes[(edid->displayParams[4] >> 3) & 3];
3085            supportedDepths = depths[(videoInput >> 4) & 7];
3086            if ((0x9236 == connectRef->displayProduct)
3087                && (kDisplayAppleVendorID == connectRef->displayVendor))
3088            {
3089                supportedModes = kIODisplayColorModeRGB;
3090            }
3091            connectRef->supportedColorModes[kAllVendors]      |= supportedModes;
3092            connectRef->supportedComponentDepths[kAllVendors] |= supportedDepths;
3093            if (kIODisplayColorModeYCbCr444 & supportedModes)
3094            {
3095                connectRef->supportedComponentDepths[kAllVendors] |= supportedDepths *
3096                                    (kIODisplayYCbCr444ColorComponentBits6 / kIODisplayRGBColorComponentBits6);
3097            }
3098            if (kIODisplayColorModeYCbCr422 & supportedModes)
3099            {
3100                connectRef->supportedComponentDepths[kAllVendors] |= supportedDepths *
3101                                    (kIODisplayYCbCr422ColorComponentBits6 / kIODisplayRGBColorComponentBits6);
3102            }
3103        }
3104
3105        count = CFDataGetLength(edidData);
3106        if ((size_t) count > sizeof(EDID))
3107        {
3108            LookExtensions(connectRef, edid, (UInt8 *)(edid + 1), count - sizeof(EDID), false);
3109        }
3110
3111		if (!connectRef->hasHDMI)
3112		{
3113            connectRef->supportedColorModes[kAllVendors] = kIODisplayColorModeRGB;
3114            connectRef->supportedComponentDepths[kAllVendors] &=
3115													  (kIODisplayRGBColorComponentBits6
3116													 | kIODisplayRGBColorComponentBits8
3117													 | kIODisplayRGBColorComponentBits10
3118													 | kIODisplayRGBColorComponentBits12
3119													 | kIODisplayRGBColorComponentBits14
3120													 | kIODisplayRGBColorComponentBits16);
3121        }
3122
3123        if ((edid->version > 1) || edid->revision) for (i = 1; i < 4; i++)
3124        {
3125            ParseMonitorDescriptor(connectRef, edid, &edid->descriptors[i].general);
3126        }
3127
3128        array = (CFArrayRef) CFDictionaryGetValue(connectRef->overrides, CFSTR("mdes"));
3129        if (array && (CFArrayGetTypeID() == CFGetTypeID(array)))
3130            count = CFArrayGetCount(array);
3131        else
3132            count = 0;
3133        for (i = 0; i < count; i++)
3134        {
3135            data = CFArrayGetValueAtIndex(array, i);
3136            if (!data
3137              || (CFDataGetTypeID() != CFGetTypeID(data))
3138              || (sizeof(EDIDGeneralDesc) > (size_t) CFDataGetLength(data)))
3139                continue;
3140
3141            ParseMonitorDescriptor(connectRef, edid, (EDIDGeneralDesc *) CFDataGetBytePtr(data));
3142        }
3143
3144        // send display attributes
3145        IOFBSetKernelDisplayConfig(connectRef);
3146
3147        if (checkDI && connectRef->hasDIEXT)
3148        {
3149            connectRef->defaultIndex = 1;
3150            connectRef->defaultOnly = true;
3151        }
3152
3153        DEBG(connectRef, "Display maxLinks %d, crossover %qd\n",
3154                        (int) connectRef->maxDisplayLinks, connectRef->dualLinkCrossover);
3155
3156        // max dimensions
3157        connectRef->dimensions.setFlags = kDisplayModeNotPresetFlag;
3158        if( CFDictionaryGetValue( connectRef->overrides, CFSTR(kIODisplayIsDigitalKey)))
3159            connectRef->dimensions.clearFlags =
3160                kDisplayModeValidFlag | kDisplayModeSafeFlag | kDisplayModeDefaultFlag;
3161        else
3162            connectRef->dimensions.clearFlags =
3163                kDisplayModeSafeFlag | kDisplayModeDefaultFlag;
3164
3165        // override timing recs (18-byte)
3166        array = (CFArrayRef) CFDictionaryGetValue( connectRef->overrides, CFSTR("dspc"));
3167        if( array)
3168            count = CFArrayGetCount(array);
3169        else
3170            count = 0;
3171        for( i = 0; i < count; i++ ) {
3172            data = CFArrayGetValueAtIndex(array, i);
3173            if( !data || (sizeof(EDIDDetailedTimingDesc) != CFDataGetLength(data)))
3174                continue;
3175
3176            InstallFromEDIDDesc( connectRef,
3177                                 edid, (EDIDDetailedTimingDesc *) CFDataGetBytePtr(data),
3178                                 kDisplayModeValidFlag | kDisplayModeSafeFlag );
3179        }
3180
3181        if (connectRef->defaultOnly
3182         && (-1 != connectRef->defaultIndex)
3183         && !CFDictionaryGetValue(connectRef->overrides, CFSTR("trng")))
3184        {
3185            // just install the default for scaling, if it works
3186            IOReturn
3187            err = InstallFromEDIDDesc(connectRef,
3188                                 edid,
3189                                 &edid->descriptors[connectRef->defaultIndex].timing,
3190                                 kDisplayModeValidFlag | kDisplayModeSafeFlag | kDisplayModeDefaultFlag
3191                                 | ((0 == connectRef->defaultIndex) ? kDisplayModeNativeFlag : 0));
3192            if ((kIOReturnSuccess == err) || (kIOReturnPortExists == err))
3193                continue;
3194        }
3195
3196        // EDID timing recs
3197        for( i = 0; i < 4; i++ )
3198        {
3199            if( i && (0 == bcmp(&edid->descriptors[0].timing,
3200                                &edid->descriptors[i].timing,
3201                                sizeof( EDIDDetailedTimingDesc))))
3202                continue;
3203
3204            InstallFromEDIDDesc(connectRef,
3205                                edid,
3206                                &edid->descriptors[i].timing,
3207                                kDisplayModeValidFlag | kDisplayModeSafeFlag
3208                                | ((i == connectRef->defaultIndex) ? kDisplayModeDefaultFlag : 0)
3209                                | (((i == 0) && (i == connectRef->defaultIndex)) ? kDisplayModeNativeFlag : 0));
3210        }
3211
3212        if( !connectRef->hasHDMI )
3213        {
3214            InstallCVTStandardTimings( connectRef, edid );
3215            InstallStandardEstablishedTimings( connectRef, edid );
3216        }
3217    }
3218    while( false );
3219
3220    // override timing recs
3221    array = (CFArrayRef) CFDictionaryGetValue( connectRef->overrides, CFSTR("tspc"));
3222    if (array)
3223        count = CFArrayGetCount(array);
3224    else
3225        count = 0;
3226    for (i = 0; i < count; i++ ) {
3227        data = CFArrayGetValueAtIndex(array, i);
3228        if( !data || (sizeof(IODetailedTimingInformation) != CFDataGetLength(data)))
3229            continue;
3230
3231        InstallFromTimingOverride(connectRef,
3232                (IODetailedTimingInformation *) CFDataGetBytePtr(data),
3233                kDisplayModeValidFlag | kDisplayModeSafeFlag);
3234    }
3235
3236    IODisplayGetAspect( connectRef );
3237
3238    if (edidData && edid)
3239    {
3240	count = CFDataGetLength(edidData);
3241	if ((size_t) count > sizeof(EDID))
3242	{
3243	    LookExtensions(connectRef, edid, (UInt8 *)(edid + 1), count - sizeof(EDID), true);
3244	}
3245    }
3246
3247    if (!connectRef->hasHDMI)
3248    {
3249        if (CFDictionaryGetValue(connectRef->overrides, CFSTR("trng"))
3250        || ((!CFDictionaryGetValue(connectRef->overrides, CFSTR(kIODisplayIsDigitalKey)))
3251            && ((connectRef->displayVendor != kDisplayVendorIDUnknown)
3252             || (connectRef->displayProduct == kDisplayProductIDGeneric))
3253            && (!edid || ((0xffffffff != connectRef->dimensions.width)
3254                        && (0xffffffff != connectRef->dimensions.height)))))
3255        {
3256            // have range limits, or analog-VGA/nonsensed
3257            InstallGTFTimings( connectRef, edid );
3258        }
3259    }
3260
3261    connectRef->fbRange = 0;
3262    if (fbRange)
3263        CFRelease(fbRange);
3264
3265    if (connectRef->dpcdData)
3266    {
3267        CFRelease(connectRef->dpcdData);
3268        connectRef->dpcdData = NULL;
3269    }
3270    if (connectRef->hdmiData)
3271    {
3272        CFRelease(connectRef->hdmiData);
3273        connectRef->hdmiData = NULL;
3274    }
3275}
3276
3277SInt32
3278IODisplayMatchDictionaries(
3279        CFDictionaryRef         matching1,
3280        CFDictionaryRef         matching2,
3281        IOOptionBits    options __unused )
3282{
3283    CFNumberRef         num1, num2;
3284    CFStringRef         str1, str2;
3285    SInt32              matches = 0;
3286
3287    if( !matching1 || !matching2)
3288        return( -1 );
3289
3290    do {
3291        num1 = CFDictionaryGetValue( matching1, CFSTR(kDisplayVendorID) );
3292        num2 = CFDictionaryGetValue( matching2, CFSTR(kDisplayVendorID) );
3293        if( !num1 || !num2)
3294            continue;
3295        if( !CFEqual( num1, num2))
3296            continue;
3297
3298        num1 = CFDictionaryGetValue( matching1, CFSTR(kDisplayProductID) );
3299        num2 = CFDictionaryGetValue( matching2, CFSTR(kDisplayProductID) );
3300        if( !num1 || !num2)
3301            continue;
3302        if( !CFEqual( num1, num2))
3303            continue;
3304
3305        num1 = CFDictionaryGetValue( matching1, CFSTR(kDisplaySerialNumber) );
3306        num2 = CFDictionaryGetValue( matching2, CFSTR(kDisplaySerialNumber) );
3307        if( num1 && num2 && (!CFEqual( num1, num2)))
3308            continue;
3309
3310        str1 = CFDictionaryGetValue( matching1, CFSTR(kIODisplayLocationKey) );
3311        str2 = CFDictionaryGetValue( matching2, CFSTR(kIODisplayLocationKey) );
3312        if( str1 && str2 && (!CFEqual( str1, str2)))
3313            continue;
3314
3315        matches = 1000;
3316
3317    } while( false );
3318
3319    return( matches );
3320}
3321
3322io_service_t
3323IODisplayForFramebuffer(
3324        io_service_t            framebuffer,
3325        IOOptionBits    options __unused )
3326{
3327    IOReturn            kr;
3328    io_iterator_t       iter;
3329    io_service_t        service = 0;
3330
3331    if( IOObjectConformsTo( framebuffer, "IODisplay"))
3332    {
3333        IOObjectRetain(framebuffer);
3334        return( framebuffer );
3335    }
3336
3337    kr = IORegistryEntryCreateIterator( framebuffer, kIOServicePlane,
3338                                        kIORegistryIterateRecursively, &iter);
3339    if( kr != kIOReturnSuccess )
3340        return( 0 );
3341
3342    do
3343    {
3344        for( ;
3345            (service = IOIteratorNext( iter));
3346            IOObjectRelease(service)) {
3347
3348            if( IOObjectConformsTo( service, "IODisplay"))
3349                break;
3350        }
3351    }
3352    while (!service && !IOIteratorIsValid(iter) && (IOIteratorReset(iter), true));
3353    IOObjectRelease( iter );
3354
3355    return( service );
3356}
3357
3358enum {
3359    /* Used by default calibrator (should we show brightness panel) */
3360    kDisplayGestaltBrightnessAffectsGammaMask   = (1 << 0),
3361    kDisplayGestaltViewAngleAffectsGammaMask    = (1 << 1)
3362};
3363
3364static void
3365IODisplayDictAddValues(const void *key, const void *value, void *context)
3366{
3367    CFMutableDictionaryRef dict = context;
3368	// add if not exists
3369    CFDictionaryAddValue(dict, key, value);
3370}
3371
3372CFDictionaryRef
3373_IODisplayCreateInfoDictionary(
3374    IOFBConnectRef      connectRef __unused,
3375    io_service_t                framebuffer,
3376    IOOptionBits                options )
3377{
3378    IOReturn                    kr;
3379    io_service_t                service = 0;
3380    Boolean                     isDigital = false;
3381    CFDataRef                   data = 0;
3382    CFNumberRef                 num;
3383    CFMutableDictionaryRef      dict = 0;
3384    CFMutableDictionaryRef      regDict;
3385    CFMutableDictionaryRef      fbRegDict;
3386    CFTypeRef                   obj;
3387    SInt32                      sint;
3388    UInt8                       low;
3389    float                       fnum;
3390    EDID *                      edid = 0;
3391    IODisplayVendorID           vendor = 0;
3392    IODisplayProductID          product = 0;
3393    SInt32                      displayType = 0;
3394    UInt32                      serialNumber = 0;
3395    uint32_t                    manufactureYear = 0;
3396    uint32_t                    manufactureWeek = 0;
3397    io_string_t                 path;
3398    int                         i;
3399    IODisplayTimingRange        displayRange;
3400
3401    if( !(service = IODisplayForFramebuffer( framebuffer, options))) {
3402        dict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
3403                                            &kCFTypeDictionaryKeyCallBacks,
3404                                            &kCFTypeDictionaryValueCallBacks );
3405        if( dict)
3406            CFDictionarySetValue( dict, CFSTR(kIODisplayLocationKey), CFSTR("unknown"));
3407        return( dict );
3408    }
3409
3410    do {
3411
3412        regDict = 0;
3413        kr = IORegistryEntryCreateCFProperties( service, &regDict,
3414                                                kCFAllocatorDefault, kNilOptions );
3415        if( kr != kIOReturnSuccess)
3416            continue;
3417
3418        num = CFDictionaryGetValue( regDict, CFSTR(kDisplayVendorID) );
3419        if( num)
3420            CFNumberGetValue( num, kCFNumberSInt32Type, &vendor );
3421        num = CFDictionaryGetValue( regDict, CFSTR(kDisplayProductID) );
3422        if( num)
3423            CFNumberGetValue( num, kCFNumberSInt32Type, &product );
3424
3425        num = CFDictionaryGetValue( regDict, CFSTR(kAppleDisplayTypeKey) );
3426        if( num) {
3427            CFNumberGetValue( num, kCFNumberSInt32Type, &displayType );
3428            if( (vendor == kDisplayVendorIDUnknown) && (displayType == 10))
3429                product = kDisplayProductIDGeneric;
3430        }
3431
3432        data = CFDictionaryGetValue( regDict, CFSTR(kIODisplayEDIDKey) );
3433
3434#if SPOOF_EDID
3435#warning             ****************
3436#warning             ** SPOOF_EDID **
3437#warning             ****************
3438		if (data)
3439		{
3440            EDIDInfo( (EDID *) CFDataGetBytePtr(data), &vendor, &product, NULL, NULL, NULL, NULL);
3441			if (0x10ac == vendor)
3442			{
3443				data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
3444												   spoofEDID, sizeof(spoofEDID), kCFAllocatorNull);
3445			}
3446			vendor = product = 0;
3447        }
3448#endif
3449        if( !data)
3450            continue;
3451        edid = (EDID *) CFDataGetBytePtr( data );
3452        if( vendor && product)
3453            EDIDInfo( edid, 0, 0, &serialNumber, &manufactureYear, &manufactureWeek, &isDigital );
3454        else
3455            EDIDInfo( edid, &vendor, &product, &serialNumber, &manufactureYear, &manufactureWeek, &isDigital );
3456
3457    } while( false );
3458
3459    // <hack>
3460    if( !vendor && !product) {
3461        vendor = kDisplayVendorIDUnknown;
3462        product = kDisplayProductIDGeneric;
3463    } // </hack>
3464
3465    dict = IODisplayCreateOverrides( framebuffer, options, vendor, product,
3466                                        serialNumber, manufactureYear, manufactureWeek,
3467                                        isDigital );
3468
3469#define makeInt( key, value )   \
3470        num = CFNumberCreate( kCFAllocatorDefault, kCFNumberSInt32Type, &value );       \
3471        CFDictionaryAddValue( dict, key,  num );                                        \
3472        CFRelease( num );
3473
3474#define addFloat( key ) \
3475        num = CFNumberCreate( kCFAllocatorDefault, kCFNumberFloatType, &fnum  );        \
3476        CFDictionaryAddValue( dict, key, num );                                         \
3477        CFRelease( num );
3478
3479    do {
3480        if( !dict)
3481            continue;
3482
3483        makeInt( CFSTR( kDisplayVendorID ), vendor );
3484        makeInt( CFSTR( kDisplayProductID ), product );
3485
3486        if( serialNumber) {
3487            makeInt( CFSTR( kDisplaySerialNumber ), serialNumber );
3488        }
3489
3490        kr = IORegistryEntryGetPath( service, kIOServicePlane, path );
3491        if( KERN_SUCCESS == kr) {
3492            CFStringRef string;
3493            string = CFStringCreateWithCString( kCFAllocatorDefault, path,
3494                                        kCFStringEncodingMacRoman );
3495            if( string) {
3496                CFDictionaryAddValue( dict, CFSTR(kIODisplayLocationKey), string);
3497                CFRelease(string);
3498            }
3499        }
3500
3501        if ((kIODisplayNoProductName | kIODisplayMatchingInfo) & options)
3502            // the raw override form is not what clients expect
3503            CFDictionaryRemoveValue( dict, CFSTR(kDisplayProductName) );
3504
3505        // -- that's all for matching --
3506        if( options & kIODisplayMatchingInfo)
3507            continue;
3508
3509        if (data)
3510        {
3511			// if !exist add display edid
3512            CFDictionaryAddValue(dict, CFSTR(kIODisplayEDIDKey), data);
3513            CFDictionaryAddValue(dict, CFSTR(kIODisplayEDIDOriginalKey), data);
3514        }
3515        // get final edid
3516        data = CFDictionaryGetValue(dict, CFSTR(kIODisplayEDIDKey));
3517        if (data)
3518            edid = (EDID *) CFDataGetBytePtr(data);
3519            // no point in serial# / manufacture date from override
3520        else
3521            edid = 0;
3522
3523		if (regDict)
3524		{
3525			obj = CFDictionaryGetValue( regDict, CFSTR(kIODisplayConnectFlagsKey) );
3526			if( obj)
3527				CFDictionarySetValue( dict, CFSTR(kIODisplayConnectFlagsKey), obj );
3528
3529			obj = CFDictionaryGetValue( regDict, CFSTR(kIODisplayPrefKeyKey) );
3530			if( obj)
3531				CFDictionarySetValue( dict, CFSTR(kIODisplayPrefKeyKey), obj );
3532
3533			CFDictionaryRef attrDict;
3534			attrDict = CFDictionaryGetValue(regDict, CFSTR(kIODisplayAttributesKey));
3535            if (attrDict && (CFDictionaryGetTypeID() == CFGetTypeID(attrDict)))
3536				CFDictionaryApplyFunction(attrDict, &IODisplayDictAddValues, dict);
3537		}
3538
3539        if( IOObjectConformsTo( service, "IOBacklightDisplay"))
3540            CFDictionarySetValue( dict, CFSTR(kIODisplayHasBacklightKey), kCFBooleanTrue );
3541
3542        kr = IORegistryEntryCreateCFProperties(framebuffer, &fbRegDict,
3543                                                kCFAllocatorDefault, kNilOptions );
3544        if (kIOReturnSuccess == kr)
3545        {
3546            if( (obj = CFDictionaryGetValue(fbRegDict, CFSTR(kIOFBTransformKey))))
3547            {
3548                CFNumberGetValue(obj, kCFNumberSInt32Type, &sint);
3549                sint = (sint & kIOFBRotateFlags) | ((sint >> 4) & kIOFBRotateFlags);
3550                makeInt( CFSTR(kIOFBTransformKey), sint );
3551            }
3552            if( (obj = CFDictionaryGetValue(fbRegDict, CFSTR("graphic-options"))))
3553                CFDictionaryAddValue(dict, CFSTR("graphic-options"), obj);
3554            CFRelease(fbRegDict);
3555        }
3556
3557        data = CFDictionaryGetValue( dict, CFSTR("dmdg") );
3558        if( data)
3559            sint = OSReadBigInt32((void *) CFDataGetBytePtr(data), 0);
3560        else
3561            sint = kDisplayGestaltBrightnessAffectsGammaMask;
3562
3563        if( kDisplayGestaltBrightnessAffectsGammaMask & sint)
3564            CFDictionaryAddValue( dict, CFSTR(kDisplayBrightnessAffectsGamma), kCFBooleanTrue );
3565        if( kDisplayGestaltViewAngleAffectsGammaMask & sint)
3566            CFDictionaryAddValue( dict, CFSTR(kDisplayViewAngleAffectsGamma), kCFBooleanTrue );
3567
3568        if (!(kIODisplayNoProductName & options))
3569            GenerateProductName( dict, edid, displayType, options );
3570
3571        if( !edid)
3572            continue;
3573
3574        if( 0x80 & edid->displayParams[0]) {
3575            CFDictionarySetValue( dict, CFSTR(kIODisplayIsDigitalKey), kCFBooleanTrue );
3576
3577            if( kDisplayAppleVendorID == vendor) {
3578                CFDictionaryAddValue( dict, CFSTR(kDisplayFixedPixelFormat), kCFBooleanTrue );
3579                sint = kDisplaySubPixelLayoutRGB;
3580                makeInt( CFSTR( kDisplaySubPixelLayout ), sint );
3581
3582                CFDictionaryRemoveValue( dict, CFSTR(kDisplayBrightnessAffectsGamma) );
3583                CFDictionarySetValue( dict, CFSTR(kDisplayViewAngleAffectsGamma), kCFBooleanTrue );
3584            }
3585        }
3586
3587        // EDID timing range
3588        for( i = 0; i < 4; i++ ) {
3589            if( EDIDDescToDisplayTimingRangeRec( edid,
3590                                &edid->descriptors[i].general,
3591                                &displayRange )) {
3592
3593                if( !CFDictionaryGetValue( dict, CFSTR("drng"))) {
3594                    data = CFDataCreate( kCFAllocatorDefault,
3595                                (UInt8 *) &edid->descriptors[i].general, sizeof(EDIDGeneralDesc));
3596                    if( data) {
3597                        CFDictionarySetValue(dict, CFSTR("drng"), data);
3598                        CFRelease(data);
3599                    }
3600                }
3601
3602                if( !CFDictionaryGetValue( dict, CFSTR("trng"))) {
3603                    data = CFDataCreate( kCFAllocatorDefault,
3604                                (UInt8 *) &displayRange, sizeof(displayRange));
3605                    if( data) {
3606                        CFDictionarySetValue(dict, CFSTR("trng"), data);
3607                        CFRelease(data);
3608                    }
3609                }
3610                break;
3611            }
3612        }
3613
3614        sint = edid->weekOfManufacture;
3615        makeInt( CFSTR( kDisplayWeekOfManufacture ), sint );
3616        sint = edid->yearOfManufacture + 1990;
3617        makeInt( CFSTR( kDisplayYearOfManufacture ), sint );
3618
3619        sint = edid->displayParams[1] * 10;
3620        makeInt( CFSTR( kDisplayHorizontalImageSize ), sint );
3621        sint = edid->displayParams[2] * 10;
3622        makeInt( CFSTR( kDisplayVerticalImageSize ), sint );
3623
3624        // color info
3625        low = edid->colorCharacteristics[0];
3626
3627        fnum = (edid->colorCharacteristics[2] << 2) | ((low >> 6) & 3);
3628        fnum /= (1 << 10);
3629        addFloat( CFSTR( kDisplayRedPointX ) );
3630        fnum = (edid->colorCharacteristics[3] << 2) | ((low >> 4) & 3);
3631        fnum /= (1 << 10);
3632        addFloat( CFSTR( kDisplayRedPointY ) );
3633
3634        fnum = (edid->colorCharacteristics[4] << 2) | ((low >> 2) & 3);
3635        fnum /= (1 << 10);
3636        addFloat( CFSTR( kDisplayGreenPointX ) );
3637        fnum = (edid->colorCharacteristics[5] << 2) | ((low >> 0) & 3);
3638        fnum /= (1 << 10);
3639        addFloat( CFSTR( kDisplayGreenPointY ) );
3640
3641        low = edid->colorCharacteristics[1];
3642
3643        fnum = (edid->colorCharacteristics[6] << 2) | ((low >> 6) & 3);
3644        fnum /= (1 << 10);
3645        addFloat( CFSTR( kDisplayBluePointX ) );
3646        fnum = (edid->colorCharacteristics[7] << 2) | ((low >> 4) & 3);
3647        fnum /= (1 << 10);
3648        addFloat( CFSTR( kDisplayBluePointY ) );
3649
3650        fnum = (edid->colorCharacteristics[8] << 2) | ((low >> 2) & 3);
3651        fnum /= (1 << 10);
3652        addFloat( CFSTR( kDisplayWhitePointX ) );
3653        fnum = (edid->colorCharacteristics[9] << 2) | ((low >> 0) & 3);
3654        fnum /= (1 << 10);
3655        addFloat( CFSTR( kDisplayWhitePointY ) );
3656
3657        fnum = edid->displayParams[3];
3658        fnum = (fnum + 100.0) / 100.0;
3659        addFloat( CFSTR( kDisplayWhiteGamma ) );
3660
3661    } while( false );
3662
3663    if (service)
3664        IOObjectRelease(service);
3665
3666    if( regDict)
3667        CFRelease( regDict );
3668
3669    return( dict );
3670}
3671
3672IOReturn
3673IODisplayCopyParameters(
3674        io_service_t      service,
3675        IOOptionBits      options,
3676        CFDictionaryRef * params )
3677{
3678    if( (service = IODisplayForFramebuffer( service, options)))
3679    {
3680        *params = IORegistryEntryCreateCFProperty( service, CFSTR(kIODisplayParametersKey),
3681                                                    kCFAllocatorDefault, kNilOptions );
3682        IOObjectRelease(service);
3683    }
3684    else
3685        *params = 0;
3686
3687    return( *params ? kIOReturnSuccess : kIOReturnUnsupported );
3688}
3689
3690IOReturn
3691IODisplayCopyFloatParameters(
3692        io_service_t  service __unused,
3693        IOOptionBits  options __unused,
3694        CFDictionaryRef * params __unused )
3695{
3696    return( kIOReturnUnsupported );
3697}
3698
3699IOReturn
3700IODisplayGetIntegerRangeParameter(
3701        io_service_t    service,
3702        IOOptionBits    options,
3703        CFStringRef     parameterName,
3704        SInt32 *        value,
3705        SInt32 *        min,
3706        SInt32 *        max )
3707{
3708    IOReturn            err;
3709    CFDictionaryRef     params;
3710    CFDictionaryRef     param;
3711    CFNumberRef         num;
3712
3713#if DEBUGPARAMS
3714    const char *        cStr = 0;
3715
3716    if( (cStr = CFStringGetCStringPtr( parameterName, kCFStringEncodingMacRoman))
3717    && (cStr = getenv(cStr)))
3718        parameterName =  CFStringCreateWithCString( kCFAllocatorDefault, cStr,
3719                                                    kCFStringEncodingMacRoman );
3720#endif
3721
3722    do {
3723        err = IODisplayCopyParameters( service, options, &params );
3724        if( err != kIOReturnSuccess)
3725            continue;
3726
3727        param = CFDictionaryGetValue( params, parameterName );
3728
3729        if( !param) {
3730            err = kIOReturnUnsupported;
3731            continue;
3732        }
3733        if( value && (num = CFDictionaryGetValue( param, CFSTR(kIODisplayValueKey))))
3734            CFNumberGetValue( num, kCFNumberSInt32Type, value );
3735        if( min && (num = CFDictionaryGetValue( param, CFSTR(kIODisplayMinValueKey))))
3736            CFNumberGetValue( num, kCFNumberSInt32Type, min );
3737        if( max && (num = CFDictionaryGetValue( param, CFSTR(kIODisplayMaxValueKey))))
3738            CFNumberGetValue( num, kCFNumberSInt32Type, max );
3739
3740    } while( false );
3741
3742    if( params)
3743        CFRelease(params);
3744
3745#if DEBUGPARAMS
3746    if( cStr)
3747        CFRelease(parameterName);
3748#endif
3749
3750    return( err );
3751}
3752
3753IOReturn
3754IODisplayGetFloatParameter(
3755        io_service_t    service,
3756        IOOptionBits    options,
3757        CFStringRef     parameterName,
3758        float *         value )
3759{
3760    IOReturn    err;
3761    SInt32      ivalue, min, max;
3762
3763    err = IODisplayGetIntegerRangeParameter( service, options, parameterName,
3764                                             &ivalue, &min, &max );
3765    if( err)
3766        return( err);
3767
3768    if( min == max)
3769        *value = 0;
3770    else
3771        *value = (((float) ivalue) - ((float) min)) / (((float) max) - ((float) min));
3772
3773    return( err );
3774}
3775
3776
3777IOReturn
3778IODisplaySetParameters(
3779        io_service_t    service,
3780        IOOptionBits    options,
3781        CFDictionaryRef params )
3782{
3783    IOReturn err;
3784
3785    if( !(service = IODisplayForFramebuffer( service, options)))
3786        return( kIOReturnUnsupported );
3787
3788    err = IORegistryEntrySetCFProperties( service, params );
3789
3790    IOObjectRelease(service);
3791
3792    return( err );
3793}
3794
3795IOReturn
3796IODisplaySetIntegerParameter(
3797        io_service_t    service,
3798        IOOptionBits options __unused,
3799        CFStringRef     parameterName,
3800        SInt32          value )
3801{
3802    IOReturn            err;
3803    CFDictionaryRef     dict;
3804    CFNumberRef         num;
3805
3806#if DEBUGPARAMS
3807    const char *        cStr;
3808
3809    if( (cStr = CFStringGetCStringPtr( parameterName, kCFStringEncodingMacRoman))
3810     && (cStr = getenv(cStr)))
3811        parameterName =  CFStringCreateWithCString( kCFAllocatorDefault, cStr,
3812                                                    kCFStringEncodingMacRoman );
3813#endif
3814
3815    num = CFNumberCreate( kCFAllocatorDefault, kCFNumberSInt32Type, &value );
3816    if( !num)
3817        return( kIOReturnNoMemory );
3818
3819    dict = CFDictionaryCreate( kCFAllocatorDefault,
3820                                (const void **) &parameterName, (const void **) &num, 1,
3821                                &kCFTypeDictionaryKeyCallBacks,
3822                                &kCFTypeDictionaryValueCallBacks );
3823    CFRelease(num);
3824    if( !dict)
3825        return( kIOReturnNoMemory );
3826
3827    err = IODisplaySetParameters( service, kNilOptions, dict );
3828
3829    CFRelease(dict);
3830
3831#if DEBUGPARAMS
3832    if( cStr)
3833        CFRelease(parameterName);
3834#endif
3835
3836    return( err );
3837}
3838
3839IOReturn
3840IODisplaySetFloatParameter(
3841        io_service_t    service,
3842        IOOptionBits    options,
3843        CFStringRef     parameterName,
3844        float           value )
3845{
3846    IOReturn    err;
3847    SInt32      ivalue, min, max;
3848
3849    err = IODisplayGetIntegerRangeParameter( service, options, parameterName,
3850                                             NULL, &min, &max );
3851    if( err)
3852        return( err);
3853
3854    ivalue = roundf((value * (((float) max) - ((float) min)) + ((float) min)));
3855
3856    err = IODisplaySetIntegerParameter( service, options, parameterName, ivalue );
3857
3858    return( err );
3859}
3860
3861IOReturn
3862IODisplayCommitParameters(
3863        io_service_t    service,
3864        IOOptionBits    options )
3865{
3866    return( IODisplaySetIntegerParameter( service, options,
3867                CFSTR(kIODisplayParametersCommitKey), 1));
3868}
3869
3870#undef IOCreateDisplayInfoDictionary
3871CFDictionaryRef
3872IOCreateDisplayInfoDictionary(
3873        io_service_t            framebuffer,
3874        IOOptionBits            options )
3875{
3876    return( _IODisplayCreateInfoDictionary( NULL, framebuffer, options));
3877}
3878
3879CFDictionaryRef
3880IODisplayCreateInfoDictionary(
3881        io_service_t            framebuffer,
3882        IOOptionBits            options )
3883{
3884    return( _IODisplayCreateInfoDictionary( NULL, framebuffer, options));
3885}
3886