17bdf92f3SAxel Dörfler /* 20ed07650SAxel Dörfler * Copyright 2007-2014, Axel Dörfler, axeld@pinc-software.de. 37bdf92f3SAxel Dörfler * Distributed under the terms of the MIT License. 47bdf92f3SAxel Dörfler */ 57bdf92f3SAxel Dörfler 67bdf92f3SAxel Dörfler 77bdf92f3SAxel Dörfler #include <create_display_modes.h> 87bdf92f3SAxel Dörfler 97bdf92f3SAxel Dörfler #include <math.h> 107bdf92f3SAxel Dörfler #include <stdlib.h> 117bdf92f3SAxel Dörfler #include <string.h> 127bdf92f3SAxel Dörfler 1395009aeeSAxel Dörfler #include <compute_display_timing.h> 147bdf92f3SAxel Dörfler #include <video_overlay.h> 157bdf92f3SAxel Dörfler 167bdf92f3SAxel Dörfler 177bdf92f3SAxel Dörfler #define POSITIVE_SYNC \ 187bdf92f3SAxel Dörfler (B_POSITIVE_HSYNC | B_POSITIVE_VSYNC) 197bdf92f3SAxel Dörfler #define MODE_FLAGS \ 2079566892SAxel Dörfler (B_8_BIT_DAC | B_HARDWARE_CURSOR | B_PARALLEL_ACCESS | B_DPMS \ 2179566892SAxel Dörfler | B_SUPPORTS_OVERLAYS) 227bdf92f3SAxel Dörfler 237bdf92f3SAxel Dörfler // TODO: move this list into the app_server 247bdf92f3SAxel Dörfler static const display_mode kBaseModeList[] = { 257bdf92f3SAxel Dörfler {{25175, 640, 656, 752, 800, 350, 387, 389, 449, B_POSITIVE_HSYNC}, B_CMAP8, 640, 350, 0, 0, MODE_FLAGS}, /* 640x350 - www.epanorama.net/documents/pc/vga_timing.html) */ 26f54507d7SAxel Dörfler 277bdf92f3SAxel Dörfler {{25175, 640, 656, 752, 800, 400, 412, 414, 449, B_POSITIVE_VSYNC}, B_CMAP8, 640, 400, 0, 0, MODE_FLAGS}, /* 640x400 - www.epanorama.net/documents/pc/vga_timing.html) */ 28f54507d7SAxel Dörfler 297bdf92f3SAxel Dörfler {{25175, 640, 656, 752, 800, 480, 490, 492, 525, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(640X480X8.Z1) */ 307bdf92f3SAxel Dörfler {{31500, 640, 664, 704, 832, 480, 489, 492, 520, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(640X480X8.Z1) */ 317bdf92f3SAxel Dörfler {{31500, 640, 656, 720, 840, 480, 481, 484, 500, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(640X480X8.Z1) */ 327bdf92f3SAxel Dörfler {{36000, 640, 696, 752, 832, 480, 481, 484, 509, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(640X480X8.Z1) */ 33f54507d7SAxel Dörfler 346c398600SAxel Dörfler {{29580, 800, 816, 896, 992, 480, 481, 484, 497, B_POSITIVE_VSYNC}, B_CMAP8, 800, 480, 0, 0, MODE_FLAGS}, /* 800x480x60Hz */ 35f54507d7SAxel Dörfler 367bdf92f3SAxel Dörfler {{38100, 800, 832, 960, 1088, 600, 602, 606, 620, 0}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* SVGA_800X600X56HzNI */ 377bdf92f3SAxel Dörfler {{40000, 800, 840, 968, 1056, 600, 601, 605, 628, POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(800X600X8.Z1) */ 387bdf92f3SAxel Dörfler {{49500, 800, 816, 896, 1056, 600, 601, 604, 625, POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(800X600X8.Z1) */ 397bdf92f3SAxel Dörfler {{50000, 800, 856, 976, 1040, 600, 637, 643, 666, POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(800X600X8.Z1) */ 407bdf92f3SAxel Dörfler {{56250, 800, 832, 896, 1048, 600, 601, 604, 631, POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(800X600X8.Z1) */ 41f54507d7SAxel Dörfler 427bdf92f3SAxel Dörfler {{65000, 1024, 1048, 1184, 1344, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1024X768X8.Z1) */ 437bdf92f3SAxel Dörfler {{75000, 1024, 1048, 1184, 1328, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(1024X768X8.Z1) */ 447bdf92f3SAxel Dörfler {{78750, 1024, 1040, 1136, 1312, 768, 769, 772, 800, POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1024X768X8.Z1) */ 457bdf92f3SAxel Dörfler {{94500, 1024, 1072, 1168, 1376, 768, 769, 772, 808, POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1024X768X8.Z1) */ 46f54507d7SAxel Dörfler 47f54507d7SAxel Dörfler {{81640, 1152, 1216, 1336, 1520, 864, 865, 868, 895, POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* 1152x864x60Hz */ 487bdf92f3SAxel Dörfler {{94200, 1152, 1184, 1280, 1472, 864, 865, 868, 914, POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */ 497bdf92f3SAxel Dörfler {{108000, 1152, 1216, 1344, 1600, 864, 865, 868, 900, POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1152X864X8.Z1) */ 507bdf92f3SAxel Dörfler {{121500, 1152, 1216, 1344, 1568, 864, 865, 868, 911, POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1152X864X8.Z1) */ 51f54507d7SAxel Dörfler 524165dff9SAxel Dörfler {{74520, 1280, 1368, 1424, 1656, 720, 724, 730, 750, POSITIVE_SYNC}, B_CMAP8, 1280, 720, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X720) */ 53f54507d7SAxel Dörfler 546c398600SAxel Dörfler {{83460, 1280, 1344, 1480, 1680, 800, 801, 804, 828, B_POSITIVE_VSYNC}, B_CMAP8, 1280, 800, 0, 0, MODE_FLAGS}, /* WXGA (1280x800x60) */ 55f54507d7SAxel Dörfler 567bdf92f3SAxel Dörfler {{108000, 1280, 1328, 1440, 1688, 1024, 1025, 1028, 1066, POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X1024X8.Z1) */ 577bdf92f3SAxel Dörfler {{135000, 1280, 1296, 1440, 1688, 1024, 1025, 1028, 1066, POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1280X1024X8.Z1) */ 587bdf92f3SAxel Dörfler {{157500, 1280, 1344, 1504, 1728, 1024, 1025, 1028, 1072, POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1280X1024X8.Z1) */ 59f54507d7SAxel Dörfler 60*564aac42SAdrien Destugues {{85500, 1360, 1424, 1536, 1792, 768, 771, 778, 795, POSITIVE_SYNC}, B_CMAP8, 1360, 768, 0, 0, MODE_FLAGS}, /* 1360x768 60Hz */ 61*564aac42SAdrien Destugues 62*564aac42SAdrien Destugues {{85765, 1366, 1494, 1624, 1798, 768, 770, 776, 795, POSITIVE_SYNC}, B_CMAP8, 1366, 768, 0, 0, MODE_FLAGS}, /* 1366x768 60Hz */ 630ed07650SAxel Dörfler 644165dff9SAxel Dörfler {{122600, 1400, 1488, 1640, 1880, 1050, 1051, 1054, 1087, POSITIVE_SYNC}, B_CMAP8, 1400, 1050, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1400X1050) */ 65f54507d7SAxel Dörfler {{155800, 1400, 1464, 1784, 1912, 1050, 1052, 1064, 1090, POSITIVE_SYNC}, B_CMAP8, 1400, 1050, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1400X1050) */ 667bdf92f3SAxel Dörfler 677bdf92f3SAxel Dörfler {{106500, 1440, 1520, 1672, 1904, 900, 901, 904, 932, POSITIVE_SYNC}, B_CMAP8, 1440, 900, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1440X900) */ 687bdf92f3SAxel Dörfler 690ed07650SAxel Dörfler {{120420, 1600, 1632, 2088, 2120, 900, 918, 927, 946, POSITIVE_SYNC}, B_CMAP8, 1600, 900, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1600X900) */ 701d5e2248SIthamar R. Adema 717bdf92f3SAxel Dörfler {{162000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1600X1200X8.Z1) */ 727bdf92f3SAxel Dörfler {{175500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@65Hz_(1600X1200X8.Z1) */ 737bdf92f3SAxel Dörfler {{189000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70Hz_(1600X1200X8.Z1) */ 747bdf92f3SAxel Dörfler {{202500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(1600X1200X8.Z1) */ 757bdf92f3SAxel Dörfler {{216000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@80Hz_(1600X1200X8.Z1) */ 767bdf92f3SAxel Dörfler {{229500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(1600X1200X8.Z1) */ 777bdf92f3SAxel Dörfler 787bdf92f3SAxel Dörfler {{147100, 1680, 1784, 1968, 2256, 1050, 1051, 1054, 1087, POSITIVE_SYNC}, B_CMAP8, 1680, 1050, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1680X1050) */ 797bdf92f3SAxel Dörfler 808a0a741dSAxel Dörfler {{172000, 1920, 2040, 2248, 2576, 1080, 1081, 1084, 1118, POSITIVE_SYNC}, B_CMAP8, 1920, 1080, 0, 0, MODE_FLAGS}, /* 1920x1080 60Hz */ 81258ca318SAxel Dörfler //{{160000, 1920, 2010, 2060, 2110, 1200, 1202, 1208, 1235, POSITIVE_SYNC}, B_CMAP8, 1920, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1920X1200) */ 82258ca318SAxel Dörfler {{193160, 1920, 2048, 2256, 2592, 1200, 1201, 1204, 1242, POSITIVE_SYNC}, B_CMAP8, 1920, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1920X1200) */ 837bdf92f3SAxel Dörfler }; 847bdf92f3SAxel Dörfler static const uint32 kNumBaseModes = sizeof(kBaseModeList) / sizeof(display_mode); 857bdf92f3SAxel Dörfler 867bdf92f3SAxel Dörfler 877bdf92f3SAxel Dörfler namespace BPrivate { 887bdf92f3SAxel Dörfler 897bdf92f3SAxel Dörfler class ModeList { 907bdf92f3SAxel Dörfler public: 917bdf92f3SAxel Dörfler ModeList(); 927bdf92f3SAxel Dörfler ~ModeList(); 937bdf92f3SAxel Dörfler 947bdf92f3SAxel Dörfler bool AddModes(edid1_info* info); 9595009aeeSAxel Dörfler bool AddModes(const display_mode* modes, 9695009aeeSAxel Dörfler uint32 count); 977bdf92f3SAxel Dörfler 9895009aeeSAxel Dörfler bool CreateColorSpaces(const color_space* spaces, 9995009aeeSAxel Dörfler uint32 count); 1007bdf92f3SAxel Dörfler void Filter(check_display_mode_hook hook); 1017bdf92f3SAxel Dörfler void Clean(); 1027bdf92f3SAxel Dörfler 1037bdf92f3SAxel Dörfler const display_mode* Modes() const { return fModes; } 1047bdf92f3SAxel Dörfler uint32 Count() const { return fCount; } 1057bdf92f3SAxel Dörfler 1067bdf92f3SAxel Dörfler private: 1077bdf92f3SAxel Dörfler bool _MakeSpace(uint32 count); 10895009aeeSAxel Dörfler bool _AddMode(const display_mode& mode); 1097bdf92f3SAxel Dörfler void _RemoveModeAt(uint32 index); 11095009aeeSAxel Dörfler void _AddBaseMode(uint16 width, uint16 height, 11195009aeeSAxel Dörfler uint32 refresh); 1127badc72cSAxel Dörfler display_mode* _FindMode(uint16 width, uint16 height) const; 1137bdf92f3SAxel Dörfler 11495009aeeSAxel Dörfler private: 1157bdf92f3SAxel Dörfler display_mode* fModes; 1167bdf92f3SAxel Dörfler uint32 fCount; 1177bdf92f3SAxel Dörfler uint32 fCapacity; 1187bdf92f3SAxel Dörfler }; 1197bdf92f3SAxel Dörfler 1207bdf92f3SAxel Dörfler } // namespace BPrivate 1217bdf92f3SAxel Dörfler 1227bdf92f3SAxel Dörfler using namespace BPrivate; 1237bdf92f3SAxel Dörfler 1247bdf92f3SAxel Dörfler 1257bdf92f3SAxel Dörfler static float 1267bdf92f3SAxel Dörfler get_refresh_rate(const display_mode& mode) 1277bdf92f3SAxel Dörfler { 1287badc72cSAxel Dörfler return float(mode.timing.pixel_clock * 1000) 1297badc72cSAxel Dörfler / float(mode.timing.h_total * mode.timing.v_total); 1307bdf92f3SAxel Dörfler } 1317bdf92f3SAxel Dörfler 1327bdf92f3SAxel Dörfler 1337bdf92f3SAxel Dörfler static int 1347bdf92f3SAxel Dörfler compare_mode(const void* _mode1, const void* _mode2) 1357bdf92f3SAxel Dörfler { 1367bdf92f3SAxel Dörfler display_mode *mode1 = (display_mode *)_mode1; 1377bdf92f3SAxel Dörfler display_mode *mode2 = (display_mode *)_mode2; 1387bdf92f3SAxel Dörfler uint16 width1, width2, height1, height2; 1397bdf92f3SAxel Dörfler 1407bdf92f3SAxel Dörfler width1 = mode1->virtual_width; 1417bdf92f3SAxel Dörfler height1 = mode1->virtual_height; 1427bdf92f3SAxel Dörfler width2 = mode2->virtual_width; 1437bdf92f3SAxel Dörfler height2 = mode2->virtual_height; 1447bdf92f3SAxel Dörfler 1457bdf92f3SAxel Dörfler if (width1 != width2) 1467bdf92f3SAxel Dörfler return width1 - width2; 1477bdf92f3SAxel Dörfler 1487bdf92f3SAxel Dörfler if (height1 != height2) 1497bdf92f3SAxel Dörfler return height1 - height2; 1507bdf92f3SAxel Dörfler 1517bdf92f3SAxel Dörfler if (mode1->space != mode2->space) 1527bdf92f3SAxel Dörfler return mode1->space - mode2->space; 1537bdf92f3SAxel Dörfler 154c54a6536SAxel Dörfler return (int)(100 * (get_refresh_rate(*mode1) - get_refresh_rate(*mode2))); 1557bdf92f3SAxel Dörfler } 1567bdf92f3SAxel Dörfler 1577bdf92f3SAxel Dörfler 1587bdf92f3SAxel Dörfler // #pragma mark - 1597bdf92f3SAxel Dörfler 1607bdf92f3SAxel Dörfler 1617bdf92f3SAxel Dörfler ModeList::ModeList() 1627bdf92f3SAxel Dörfler : 1637bdf92f3SAxel Dörfler fModes(NULL), 1647bdf92f3SAxel Dörfler fCount(0), 1657bdf92f3SAxel Dörfler fCapacity(0) 1667bdf92f3SAxel Dörfler { 1677bdf92f3SAxel Dörfler } 1687bdf92f3SAxel Dörfler 1697bdf92f3SAxel Dörfler 1707bdf92f3SAxel Dörfler ModeList::~ModeList() 1717bdf92f3SAxel Dörfler { 1727bdf92f3SAxel Dörfler free(fModes); 1737bdf92f3SAxel Dörfler } 1747bdf92f3SAxel Dörfler 1757bdf92f3SAxel Dörfler 1767bdf92f3SAxel Dörfler bool 1777bdf92f3SAxel Dörfler ModeList::AddModes(edid1_info* info) 1787bdf92f3SAxel Dörfler { 1797bdf92f3SAxel Dörfler if (info->established_timing.res_720x400x70) 1807bdf92f3SAxel Dörfler _AddBaseMode(720, 400, 70); 1817bdf92f3SAxel Dörfler if (info->established_timing.res_720x400x88) 1827bdf92f3SAxel Dörfler _AddBaseMode(720, 400, 88); 1837bdf92f3SAxel Dörfler 1847bdf92f3SAxel Dörfler if (info->established_timing.res_640x480x60) 1857bdf92f3SAxel Dörfler _AddBaseMode(640, 480, 60); 1867bdf92f3SAxel Dörfler if (info->established_timing.res_640x480x67) 1877bdf92f3SAxel Dörfler _AddBaseMode(640, 480, 67); 1887bdf92f3SAxel Dörfler if (info->established_timing.res_640x480x72) 1897bdf92f3SAxel Dörfler _AddBaseMode(640, 480, 72); 1907bdf92f3SAxel Dörfler if (info->established_timing.res_640x480x75) 1917bdf92f3SAxel Dörfler _AddBaseMode(640, 480, 75); 1927bdf92f3SAxel Dörfler 1937bdf92f3SAxel Dörfler if (info->established_timing.res_800x600x56) 1947bdf92f3SAxel Dörfler _AddBaseMode(800, 600, 56); 1957bdf92f3SAxel Dörfler if (info->established_timing.res_800x600x60) 1967bdf92f3SAxel Dörfler _AddBaseMode(800, 600, 60); 1977bdf92f3SAxel Dörfler if (info->established_timing.res_800x600x72) 1987bdf92f3SAxel Dörfler _AddBaseMode(800, 600, 72); 1997bdf92f3SAxel Dörfler if (info->established_timing.res_800x600x75) 2007bdf92f3SAxel Dörfler _AddBaseMode(800, 600, 75); 2017bdf92f3SAxel Dörfler 2027bdf92f3SAxel Dörfler #if 0 2037bdf92f3SAxel Dörfler if (info->established_timing.res_832x624x75) 2047bdf92f3SAxel Dörfler _AddBaseMode(832, 624, 75); 2057bdf92f3SAxel Dörfler 2067bdf92f3SAxel Dörfler if (info->established_timing.res_1024x768x87i) 2077bdf92f3SAxel Dörfler _AddBaseMode(1024, 768, 87); 2087bdf92f3SAxel Dörfler #endif 2097bdf92f3SAxel Dörfler if (info->established_timing.res_1024x768x60) 2107bdf92f3SAxel Dörfler _AddBaseMode(1024, 768, 60); 2117bdf92f3SAxel Dörfler if (info->established_timing.res_1024x768x70) 2127bdf92f3SAxel Dörfler _AddBaseMode(1024, 768, 70); 2137bdf92f3SAxel Dörfler if (info->established_timing.res_1024x768x75) 2147bdf92f3SAxel Dörfler _AddBaseMode(1024, 768, 75); 2157bdf92f3SAxel Dörfler 2167bdf92f3SAxel Dörfler if (info->established_timing.res_1152x870x75) 2177bdf92f3SAxel Dörfler _AddBaseMode(1152, 870, 75); 2187bdf92f3SAxel Dörfler if (info->established_timing.res_1280x1024x75) 2197bdf92f3SAxel Dörfler _AddBaseMode(1280, 1024, 75); 2207bdf92f3SAxel Dörfler 2217bdf92f3SAxel Dörfler for (uint32 i = 0; i < EDID1_NUM_STD_TIMING; ++i) { 2227bdf92f3SAxel Dörfler if (info->std_timing[i].h_size <= 256) 2237bdf92f3SAxel Dörfler continue; 2247bdf92f3SAxel Dörfler 2257bdf92f3SAxel Dörfler _AddBaseMode(info->std_timing[i].h_size, info->std_timing[i].v_size, 2267bdf92f3SAxel Dörfler info->std_timing[i].refresh); 2277bdf92f3SAxel Dörfler } 2287bdf92f3SAxel Dörfler 2297badc72cSAxel Dörfler bool hasRanges = false; 2307badc72cSAxel Dörfler uint32 minHorizontalFrequency = 0; 2317badc72cSAxel Dörfler uint32 maxHorizontalFrequency = 0; 2327badc72cSAxel Dörfler uint32 minVerticalFrequency = 0; 2337badc72cSAxel Dörfler uint32 maxVerticalFrequency = 0; 2347badc72cSAxel Dörfler uint32 maxPixelClock = 0; 2357badc72cSAxel Dörfler 2367bdf92f3SAxel Dörfler for (uint32 i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i) { 23779566892SAxel Dörfler if (info->detailed_monitor[i].monitor_desc_type 2387badc72cSAxel Dörfler == EDID1_MONITOR_RANGES) { 2397badc72cSAxel Dörfler edid1_monitor_range& range 2407badc72cSAxel Dörfler = info->detailed_monitor[i].data.monitor_range; 2417badc72cSAxel Dörfler 2427badc72cSAxel Dörfler hasRanges = true; 2437badc72cSAxel Dörfler minHorizontalFrequency = range.min_h; 2447badc72cSAxel Dörfler maxHorizontalFrequency = range.max_h; 2457badc72cSAxel Dörfler minVerticalFrequency = range.min_v; 2467badc72cSAxel Dörfler maxVerticalFrequency = range.max_v; 2477badc72cSAxel Dörfler maxPixelClock = range.max_clock * 10000; 2487badc72cSAxel Dörfler continue; 2497badc72cSAxel Dörfler } else if (info->detailed_monitor[i].monitor_desc_type 25079566892SAxel Dörfler != EDID1_IS_DETAILED_TIMING) 2517bdf92f3SAxel Dörfler continue; 2527bdf92f3SAxel Dörfler 253c54a6536SAxel Dörfler // TODO: handle flags correctly! 25479566892SAxel Dörfler const edid1_detailed_timing& timing 25579566892SAxel Dörfler = info->detailed_monitor[i].data.detailed_timing; 2567bdf92f3SAxel Dörfler display_mode mode; 257c54a6536SAxel Dörfler 25879566892SAxel Dörfler if (timing.pixel_clock <= 0/* || timing.sync != 3*/) 259c54a6536SAxel Dörfler continue; 260c54a6536SAxel Dörfler 2617bdf92f3SAxel Dörfler mode.timing.pixel_clock = timing.pixel_clock * 10; 2627bdf92f3SAxel Dörfler mode.timing.h_display = timing.h_active; 263fe2aaee7SAxel Dörfler mode.timing.h_sync_start = timing.h_active + timing.h_sync_off; 264fe2aaee7SAxel Dörfler mode.timing.h_sync_end = mode.timing.h_sync_start + timing.h_sync_width; 265fe2aaee7SAxel Dörfler mode.timing.h_total = timing.h_active + timing.h_blank; 2667bdf92f3SAxel Dörfler mode.timing.v_display = timing.v_active; 267fe2aaee7SAxel Dörfler mode.timing.v_sync_start = timing.v_active + timing.v_sync_off; 268fe2aaee7SAxel Dörfler mode.timing.v_sync_end = mode.timing.v_sync_start + timing.v_sync_width; 269fe2aaee7SAxel Dörfler mode.timing.v_total = timing.v_active + timing.v_blank; 270c54a6536SAxel Dörfler mode.timing.flags = 0; 271c54a6536SAxel Dörfler if (timing.sync == 3) { 272c54a6536SAxel Dörfler if (timing.misc & 1) 273c54a6536SAxel Dörfler mode.timing.flags |= B_POSITIVE_HSYNC; 274c54a6536SAxel Dörfler if (timing.misc & 2) 275c54a6536SAxel Dörfler mode.timing.flags |= B_POSITIVE_VSYNC; 276c54a6536SAxel Dörfler } 277fe2aaee7SAxel Dörfler if (timing.interlaced) 278fe2aaee7SAxel Dörfler mode.timing.flags |= B_TIMING_INTERLACED; 2797bdf92f3SAxel Dörfler mode.space = B_RGB32; 2807bdf92f3SAxel Dörfler mode.virtual_width = timing.h_active; 2817bdf92f3SAxel Dörfler mode.virtual_height = timing.v_active; 2827bdf92f3SAxel Dörfler mode.h_display_start = 0; 2837bdf92f3SAxel Dörfler mode.v_display_start = 0; 2847bdf92f3SAxel Dörfler mode.flags = MODE_FLAGS; 285c54a6536SAxel Dörfler 28695009aeeSAxel Dörfler _AddMode(mode); 2877bdf92f3SAxel Dörfler } 2887bdf92f3SAxel Dörfler 2897badc72cSAxel Dörfler // Add other modes from the base list that satisfy the display's 2907badc72cSAxel Dörfler // requirements 2917badc72cSAxel Dörfler 2927badc72cSAxel Dörfler for (uint32 i = 0; i < kNumBaseModes; i++) { 2937badc72cSAxel Dörfler const display_mode& mode = kBaseModeList[i]; 2947badc72cSAxel Dörfler 2957badc72cSAxel Dörfler // Check if a mode with this resolution already exists 2967badc72cSAxel Dörfler 2977badc72cSAxel Dörfler if (_FindMode(mode.timing.h_display, mode.timing.v_display) != NULL) 2987badc72cSAxel Dörfler continue; 2997badc72cSAxel Dörfler 3007badc72cSAxel Dörfler // Check monitor limits 3017badc72cSAxel Dörfler 3027badc72cSAxel Dörfler if (hasRanges) { 3037badc72cSAxel Dörfler uint32 verticalFrequency = 1000 * mode.timing.pixel_clock 3047badc72cSAxel Dörfler / (mode.timing.h_total * mode.timing.v_total); 3057badc72cSAxel Dörfler uint32 horizontalFrequency = mode.timing.h_total * verticalFrequency 3067badc72cSAxel Dörfler / 1000; 3077badc72cSAxel Dörfler 3087badc72cSAxel Dörfler if (minHorizontalFrequency > horizontalFrequency 3097badc72cSAxel Dörfler || maxHorizontalFrequency < horizontalFrequency 3107badc72cSAxel Dörfler || minVerticalFrequency > verticalFrequency 3117badc72cSAxel Dörfler || maxVerticalFrequency < verticalFrequency 3127badc72cSAxel Dörfler || maxPixelClock < mode.timing.pixel_clock) 3137badc72cSAxel Dörfler continue; 3147badc72cSAxel Dörfler } 3157badc72cSAxel Dörfler 31695009aeeSAxel Dörfler _AddMode(mode); 3177badc72cSAxel Dörfler } 3187bdf92f3SAxel Dörfler 3197bdf92f3SAxel Dörfler return true; 3207bdf92f3SAxel Dörfler } 3217bdf92f3SAxel Dörfler 3227bdf92f3SAxel Dörfler 3237bdf92f3SAxel Dörfler bool 3247bdf92f3SAxel Dörfler ModeList::AddModes(const display_mode* modes, uint32 count) 3257bdf92f3SAxel Dörfler { 3267bdf92f3SAxel Dörfler if (!_MakeSpace(count)) 3277bdf92f3SAxel Dörfler return false; 3287bdf92f3SAxel Dörfler 3297bdf92f3SAxel Dörfler for (uint32 i = 0; i < count; i++) { 3307bdf92f3SAxel Dörfler fModes[fCount++] = modes[i]; 3317bdf92f3SAxel Dörfler } 3327bdf92f3SAxel Dörfler 3337bdf92f3SAxel Dörfler return true; 3347bdf92f3SAxel Dörfler } 3357bdf92f3SAxel Dörfler 3367bdf92f3SAxel Dörfler 3377bdf92f3SAxel Dörfler bool 3387bdf92f3SAxel Dörfler ModeList::CreateColorSpaces(const color_space* spaces, uint32 count) 3397bdf92f3SAxel Dörfler { 340b5cc636fSMichael Lotz uint32 baseModeCount = fCount; 341b5cc636fSMichael Lotz size_t baseModesSize = baseModeCount * sizeof(display_mode); 342b5cc636fSMichael Lotz display_mode* baseModes = (display_mode*)malloc(baseModesSize); 343b5cc636fSMichael Lotz if (baseModes == NULL) 3447bdf92f3SAxel Dörfler return false; 3457bdf92f3SAxel Dörfler 346b5cc636fSMichael Lotz memcpy(baseModes, fModes, baseModesSize); 347b5cc636fSMichael Lotz 348b5cc636fSMichael Lotz for (uint32 i = 0; i < count; i++) { 349b5cc636fSMichael Lotz if (i > 0 && !AddModes(baseModes, baseModeCount)) { 350b5cc636fSMichael Lotz free(baseModes); 351b5cc636fSMichael Lotz return false; 352b5cc636fSMichael Lotz } 353b5cc636fSMichael Lotz 354b5cc636fSMichael Lotz for (uint32 j = 0; j < baseModeCount; j++) { 355b5cc636fSMichael Lotz fModes[j + fCount - baseModeCount].space = spaces[i]; 3567bdf92f3SAxel Dörfler } 3577bdf92f3SAxel Dörfler } 3587bdf92f3SAxel Dörfler 359b5cc636fSMichael Lotz free(baseModes); 3607bdf92f3SAxel Dörfler return true; 3617bdf92f3SAxel Dörfler } 3627bdf92f3SAxel Dörfler 3637bdf92f3SAxel Dörfler 3647bdf92f3SAxel Dörfler void 3657bdf92f3SAxel Dörfler ModeList::Filter(check_display_mode_hook hook) 3667bdf92f3SAxel Dörfler { 3677bdf92f3SAxel Dörfler if (hook == NULL) 3687bdf92f3SAxel Dörfler return; 3697bdf92f3SAxel Dörfler 3707bdf92f3SAxel Dörfler for (uint32 i = fCount; i-- > 0;) { 3717bdf92f3SAxel Dörfler if (!hook(&fModes[i])) 3727bdf92f3SAxel Dörfler _RemoveModeAt(i); 3737bdf92f3SAxel Dörfler } 3747bdf92f3SAxel Dörfler } 3757bdf92f3SAxel Dörfler 3767bdf92f3SAxel Dörfler 3777bdf92f3SAxel Dörfler void 3787bdf92f3SAxel Dörfler ModeList::Clean() 3797bdf92f3SAxel Dörfler { 3807bdf92f3SAxel Dörfler // sort mode list 3817bdf92f3SAxel Dörfler qsort(fModes, fCount, sizeof(display_mode), compare_mode); 3827bdf92f3SAxel Dörfler 3837bdf92f3SAxel Dörfler // remove duplicates 3847bdf92f3SAxel Dörfler for (uint32 i = fCount; i-- > 1;) { 3857bdf92f3SAxel Dörfler if (compare_mode(&fModes[i], &fModes[i - 1]) == 0) 3867bdf92f3SAxel Dörfler _RemoveModeAt(i); 3877bdf92f3SAxel Dörfler } 3887bdf92f3SAxel Dörfler } 3897bdf92f3SAxel Dörfler 3907bdf92f3SAxel Dörfler 3917bdf92f3SAxel Dörfler void 3927bdf92f3SAxel Dörfler ModeList::_AddBaseMode(uint16 width, uint16 height, uint32 refresh) 3937bdf92f3SAxel Dörfler { 39495009aeeSAxel Dörfler // Check the manually tweaked list first 39595009aeeSAxel Dörfler 3967bdf92f3SAxel Dörfler for (uint32 i = 0; i < kNumBaseModes; i++) { 3977bdf92f3SAxel Dörfler const display_mode& mode = kBaseModeList[i]; 3987bdf92f3SAxel Dörfler 399c54a6536SAxel Dörfler // Add mode if width and height match, and the computed refresh rate of 400c54a6536SAxel Dörfler // the mode is within 1.2 percent of the refresh rate specified by the 401c54a6536SAxel Dörfler // caller. Note that refresh rates computed from mode parameters is 402c54a6536SAxel Dörfler // not exact; thus, the tolerance of 1.2% was obtained by testing the 403c54a6536SAxel Dörfler // various established modes that can be selected by the EDID info. 404c54a6536SAxel Dörfler 4057bdf92f3SAxel Dörfler if (mode.timing.h_display == width && mode.timing.v_display == height 406c54a6536SAxel Dörfler && fabs(get_refresh_rate(mode) - refresh) < refresh * 0.012) { 40795009aeeSAxel Dörfler _AddMode(mode); 40895009aeeSAxel Dörfler return; 4097bdf92f3SAxel Dörfler } 4107bdf92f3SAxel Dörfler } 41195009aeeSAxel Dörfler 41295009aeeSAxel Dörfler // If that didn't have any entries, compute the entry 41395009aeeSAxel Dörfler display_mode mode; 41495009aeeSAxel Dörfler if (compute_display_timing(width, height, refresh, false, &mode.timing) 41595009aeeSAxel Dörfler != B_OK) 41695009aeeSAxel Dörfler return; 41795009aeeSAxel Dörfler 418d3d53515SAxel Dörfler fill_display_mode(width, height, &mode); 41995009aeeSAxel Dörfler 42095009aeeSAxel Dörfler _AddMode(mode); 4217bdf92f3SAxel Dörfler } 4227bdf92f3SAxel Dörfler 4237bdf92f3SAxel Dörfler 4247badc72cSAxel Dörfler display_mode* 4257badc72cSAxel Dörfler ModeList::_FindMode(uint16 width, uint16 height) const 4267badc72cSAxel Dörfler { 4277badc72cSAxel Dörfler for (uint32 i = 0; i < fCount; i++) { 4287badc72cSAxel Dörfler const display_mode& mode = fModes[i]; 4297badc72cSAxel Dörfler 4307badc72cSAxel Dörfler if (mode.timing.h_display == width && mode.timing.v_display == height) 4317badc72cSAxel Dörfler return &fModes[i]; 4327badc72cSAxel Dörfler } 4337badc72cSAxel Dörfler 4347badc72cSAxel Dörfler return NULL; 4357badc72cSAxel Dörfler } 4367badc72cSAxel Dörfler 4377badc72cSAxel Dörfler 4387bdf92f3SAxel Dörfler bool 4397bdf92f3SAxel Dörfler ModeList::_MakeSpace(uint32 count) 4407bdf92f3SAxel Dörfler { 4417bdf92f3SAxel Dörfler if (fCount + count <= fCapacity) 4427bdf92f3SAxel Dörfler return true; 4437bdf92f3SAxel Dörfler 4447bdf92f3SAxel Dörfler uint32 capacity = (fCapacity + count + 0xf) & ~0xf; 4457bdf92f3SAxel Dörfler display_mode* modes = (display_mode*)realloc(fModes, 4467bdf92f3SAxel Dörfler capacity * sizeof(display_mode)); 4477bdf92f3SAxel Dörfler if (modes == NULL) 4487bdf92f3SAxel Dörfler return false; 4497bdf92f3SAxel Dörfler 4507bdf92f3SAxel Dörfler fModes = modes; 4517bdf92f3SAxel Dörfler fCapacity = capacity; 4527bdf92f3SAxel Dörfler return true; 4537bdf92f3SAxel Dörfler } 4547bdf92f3SAxel Dörfler 4557bdf92f3SAxel Dörfler 4567bdf92f3SAxel Dörfler bool 45795009aeeSAxel Dörfler ModeList::_AddMode(const display_mode& mode) 4587bdf92f3SAxel Dörfler { 4590ba65dceSAxel Dörfler // TODO: filter by monitor timing constraints! 4600ba65dceSAxel Dörfler // TODO: remove double entries 4617bdf92f3SAxel Dörfler if (!_MakeSpace(1)) 4627bdf92f3SAxel Dörfler return false; 4637bdf92f3SAxel Dörfler 46495009aeeSAxel Dörfler fModes[fCount++] = mode; 4657bdf92f3SAxel Dörfler return true; 4667bdf92f3SAxel Dörfler } 4677bdf92f3SAxel Dörfler 4687bdf92f3SAxel Dörfler 4697bdf92f3SAxel Dörfler void 4707bdf92f3SAxel Dörfler ModeList::_RemoveModeAt(uint32 index) 4717bdf92f3SAxel Dörfler { 4727bdf92f3SAxel Dörfler if (index < fCount - 1) { 4737bdf92f3SAxel Dörfler memmove(&fModes[index], &fModes[index + 1], 4747bdf92f3SAxel Dörfler (fCount - 1 - index) * sizeof(display_mode)); 4757bdf92f3SAxel Dörfler } 4767bdf92f3SAxel Dörfler 4777bdf92f3SAxel Dörfler fCount--; 4787bdf92f3SAxel Dörfler } 4797bdf92f3SAxel Dörfler 4807bdf92f3SAxel Dörfler 4817bdf92f3SAxel Dörfler // #pragma mark - 4827bdf92f3SAxel Dörfler 4837bdf92f3SAxel Dörfler 4847bdf92f3SAxel Dörfler extern "C" area_id 4857bdf92f3SAxel Dörfler create_display_modes(const char* name, edid1_info* edid, 4867bdf92f3SAxel Dörfler const display_mode* initialModes, uint32 initialModeCount, 4877bdf92f3SAxel Dörfler const color_space *spaces, uint32 spacesCount, 4887bdf92f3SAxel Dörfler check_display_mode_hook hook, display_mode** _modes, uint32* _count) 4897bdf92f3SAxel Dörfler { 4907bdf92f3SAxel Dörfler if (_modes == NULL || _count == NULL) 4917bdf92f3SAxel Dörfler return B_BAD_VALUE; 4927bdf92f3SAxel Dörfler 4937bdf92f3SAxel Dörfler // compile initial mode list from the different sources 4947bdf92f3SAxel Dörfler 4957bdf92f3SAxel Dörfler ModeList modes; 496b2a77322SAxel Dörfler if (initialModes != NULL) 4977bdf92f3SAxel Dörfler modes.AddModes(initialModes, initialModeCount); 4987bdf92f3SAxel Dörfler 4997bdf92f3SAxel Dörfler if (edid != NULL) 5007bdf92f3SAxel Dörfler modes.AddModes(edid); 5017bdf92f3SAxel Dörfler else 5027bdf92f3SAxel Dörfler modes.AddModes(kBaseModeList, kNumBaseModes); 5037bdf92f3SAxel Dörfler 5047bdf92f3SAxel Dörfler // filter out modes the caller doesn't like, and multiply modes for 5057bdf92f3SAxel Dörfler // every color space 5067bdf92f3SAxel Dörfler 5077bdf92f3SAxel Dörfler if (spaces == NULL) { 5087bdf92f3SAxel Dörfler const color_space kDefaultSpaces[] = {B_RGB32_LITTLE, B_RGB16_LITTLE, 5097bdf92f3SAxel Dörfler B_RGB15_LITTLE, B_CMAP8}; 5107bdf92f3SAxel Dörfler modes.CreateColorSpaces(kDefaultSpaces, 5117bdf92f3SAxel Dörfler sizeof(kDefaultSpaces) / sizeof(kDefaultSpaces[0])); 5127bdf92f3SAxel Dörfler } else 5137bdf92f3SAxel Dörfler modes.CreateColorSpaces(spaces, spacesCount); 5147bdf92f3SAxel Dörfler 5157bdf92f3SAxel Dörfler modes.Filter(hook); 5167bdf92f3SAxel Dörfler modes.Clean(); 5177bdf92f3SAxel Dörfler 5187bdf92f3SAxel Dörfler // create area for output modes 5197bdf92f3SAxel Dörfler 5207bdf92f3SAxel Dörfler size_t size = (sizeof(display_mode) * modes.Count() + B_PAGE_SIZE - 1) 5217bdf92f3SAxel Dörfler & ~(B_PAGE_SIZE - 1); 5227bdf92f3SAxel Dörfler display_mode *list; 5237bdf92f3SAxel Dörfler area_id area = create_area(name, (void **)&list, B_ANY_ADDRESS, 5247bdf92f3SAxel Dörfler size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); 5257bdf92f3SAxel Dörfler if (area < B_OK) 5267bdf92f3SAxel Dörfler return area; 5277bdf92f3SAxel Dörfler 5287bdf92f3SAxel Dörfler memcpy(list, modes.Modes(), sizeof(display_mode) * modes.Count()); 5297bdf92f3SAxel Dörfler *_modes = list; 5307bdf92f3SAxel Dörfler *_count = modes.Count(); 5317bdf92f3SAxel Dörfler 5327bdf92f3SAxel Dörfler return area; 5337bdf92f3SAxel Dörfler } 5347bdf92f3SAxel Dörfler 53595009aeeSAxel Dörfler 53695009aeeSAxel Dörfler void 537d3d53515SAxel Dörfler fill_display_mode(uint32 width, uint32 height, display_mode* mode) 53895009aeeSAxel Dörfler { 53995009aeeSAxel Dörfler mode->space = B_CMAP8; 540d3d53515SAxel Dörfler mode->virtual_width = width; 541d3d53515SAxel Dörfler mode->virtual_height = height; 54295009aeeSAxel Dörfler mode->h_display_start = 0; 54395009aeeSAxel Dörfler mode->v_display_start = 0; 54495009aeeSAxel Dörfler mode->flags = MODE_FLAGS; 54595009aeeSAxel Dörfler } 546