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 \
211e0fdd6dSRudolf Cornelissen | B_SUPPORTS_OVERLAYS | B_SCROLL)
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
60564aac42SAdrien Destugues {{85500, 1360, 1424, 1536, 1792, 768, 771, 778, 795, POSITIVE_SYNC}, B_CMAP8, 1360, 768, 0, 0, MODE_FLAGS}, /* 1360x768 60Hz */
61564aac42SAdrien Destugues
62564aac42SAdrien 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
8063bd351fSRudolf Cornelissen //{{172000, 1920, 2040, 2248, 2576, 1080, 1081, 1084, 1118, POSITIVE_SYNC}, B_CMAP8, 1920, 1080, 0, 0, MODE_FLAGS}, /* 1920x1080 60Hz */
8163bd351fSRudolf Cornelissen {{148500, 1920, 2008, 2052, 2200, 1080, 1084, 1089, 1125, POSITIVE_SYNC}, B_CMAP8, 1920, 1080, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1920X1080) */
82258ca318SAxel 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) */
83258ca318SAxel 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) */
847bdf92f3SAxel Dörfler };
857bdf92f3SAxel Dörfler static const uint32 kNumBaseModes = sizeof(kBaseModeList) / sizeof(display_mode);
867bdf92f3SAxel Dörfler
877bdf92f3SAxel Dörfler
887bdf92f3SAxel Dörfler namespace BPrivate {
897bdf92f3SAxel Dörfler
907bdf92f3SAxel Dörfler class ModeList {
917bdf92f3SAxel Dörfler public:
927bdf92f3SAxel Dörfler ModeList();
937bdf92f3SAxel Dörfler ~ModeList();
947bdf92f3SAxel Dörfler
957bdf92f3SAxel Dörfler bool AddModes(edid1_info* info);
9695009aeeSAxel Dörfler bool AddModes(const display_mode* modes,
9795009aeeSAxel Dörfler uint32 count);
987bdf92f3SAxel Dörfler
9995009aeeSAxel Dörfler bool CreateColorSpaces(const color_space* spaces,
10095009aeeSAxel Dörfler uint32 count);
1017bdf92f3SAxel Dörfler void Filter(check_display_mode_hook hook);
1027bdf92f3SAxel Dörfler void Clean();
1037bdf92f3SAxel Dörfler
Modes() const1047bdf92f3SAxel Dörfler const display_mode* Modes() const { return fModes; }
Count() const1057bdf92f3SAxel Dörfler uint32 Count() const { return fCount; }
1067bdf92f3SAxel Dörfler
1077bdf92f3SAxel Dörfler private:
1087bdf92f3SAxel Dörfler bool _MakeSpace(uint32 count);
10995009aeeSAxel Dörfler bool _AddMode(const display_mode& mode);
1107bdf92f3SAxel Dörfler void _RemoveModeAt(uint32 index);
11195009aeeSAxel Dörfler void _AddBaseMode(uint16 width, uint16 height,
11295009aeeSAxel Dörfler uint32 refresh);
1137badc72cSAxel Dörfler display_mode* _FindMode(uint16 width, uint16 height) const;
1147bdf92f3SAxel Dörfler
11595009aeeSAxel Dörfler private:
1167bdf92f3SAxel Dörfler display_mode* fModes;
1177bdf92f3SAxel Dörfler uint32 fCount;
1187bdf92f3SAxel Dörfler uint32 fCapacity;
1197bdf92f3SAxel Dörfler };
1207bdf92f3SAxel Dörfler
1217bdf92f3SAxel Dörfler } // namespace BPrivate
1227bdf92f3SAxel Dörfler
1237bdf92f3SAxel Dörfler using namespace BPrivate;
1247bdf92f3SAxel Dörfler
1257bdf92f3SAxel Dörfler
1267bdf92f3SAxel Dörfler static float
get_refresh_rate(const display_mode & mode)1277bdf92f3SAxel Dörfler get_refresh_rate(const display_mode& mode)
1287bdf92f3SAxel Dörfler {
1297badc72cSAxel Dörfler return float(mode.timing.pixel_clock * 1000)
1307badc72cSAxel Dörfler / float(mode.timing.h_total * mode.timing.v_total);
1317bdf92f3SAxel Dörfler }
1327bdf92f3SAxel Dörfler
1337bdf92f3SAxel Dörfler
1347bdf92f3SAxel Dörfler static int
compare_mode(const void * _mode1,const void * _mode2)1357bdf92f3SAxel Dörfler compare_mode(const void* _mode1, const void* _mode2)
1367bdf92f3SAxel Dörfler {
1377bdf92f3SAxel Dörfler display_mode *mode1 = (display_mode *)_mode1;
1387bdf92f3SAxel Dörfler display_mode *mode2 = (display_mode *)_mode2;
1397bdf92f3SAxel Dörfler uint16 width1, width2, height1, height2;
1407bdf92f3SAxel Dörfler
1417bdf92f3SAxel Dörfler width1 = mode1->virtual_width;
1427bdf92f3SAxel Dörfler height1 = mode1->virtual_height;
1437bdf92f3SAxel Dörfler width2 = mode2->virtual_width;
1447bdf92f3SAxel Dörfler height2 = mode2->virtual_height;
1457bdf92f3SAxel Dörfler
1467bdf92f3SAxel Dörfler if (width1 != width2)
1477bdf92f3SAxel Dörfler return width1 - width2;
1487bdf92f3SAxel Dörfler
1497bdf92f3SAxel Dörfler if (height1 != height2)
1507bdf92f3SAxel Dörfler return height1 - height2;
1517bdf92f3SAxel Dörfler
1527bdf92f3SAxel Dörfler if (mode1->space != mode2->space)
1537bdf92f3SAxel Dörfler return mode1->space - mode2->space;
1547bdf92f3SAxel Dörfler
155c54a6536SAxel Dörfler return (int)(100 * (get_refresh_rate(*mode1) - get_refresh_rate(*mode2)));
1567bdf92f3SAxel Dörfler }
1577bdf92f3SAxel Dörfler
1587bdf92f3SAxel Dörfler
1597bdf92f3SAxel Dörfler // #pragma mark -
1607bdf92f3SAxel Dörfler
1617bdf92f3SAxel Dörfler
ModeList()1627bdf92f3SAxel Dörfler ModeList::ModeList()
1637bdf92f3SAxel Dörfler :
1647bdf92f3SAxel Dörfler fModes(NULL),
1657bdf92f3SAxel Dörfler fCount(0),
1667bdf92f3SAxel Dörfler fCapacity(0)
1677bdf92f3SAxel Dörfler {
1687bdf92f3SAxel Dörfler }
1697bdf92f3SAxel Dörfler
1707bdf92f3SAxel Dörfler
~ModeList()1717bdf92f3SAxel Dörfler ModeList::~ModeList()
1727bdf92f3SAxel Dörfler {
1737bdf92f3SAxel Dörfler free(fModes);
1747bdf92f3SAxel Dörfler }
1757bdf92f3SAxel Dörfler
1767bdf92f3SAxel Dörfler
1777bdf92f3SAxel Dörfler bool
AddModes(edid1_info * info)1787bdf92f3SAxel Dörfler ModeList::AddModes(edid1_info* info)
1797bdf92f3SAxel Dörfler {
1807bdf92f3SAxel Dörfler if (info->established_timing.res_720x400x70)
1817bdf92f3SAxel Dörfler _AddBaseMode(720, 400, 70);
1827bdf92f3SAxel Dörfler if (info->established_timing.res_720x400x88)
1837bdf92f3SAxel Dörfler _AddBaseMode(720, 400, 88);
1847bdf92f3SAxel Dörfler
1857bdf92f3SAxel Dörfler if (info->established_timing.res_640x480x60)
1867bdf92f3SAxel Dörfler _AddBaseMode(640, 480, 60);
1877bdf92f3SAxel Dörfler if (info->established_timing.res_640x480x67)
1887bdf92f3SAxel Dörfler _AddBaseMode(640, 480, 67);
1897bdf92f3SAxel Dörfler if (info->established_timing.res_640x480x72)
1907bdf92f3SAxel Dörfler _AddBaseMode(640, 480, 72);
1917bdf92f3SAxel Dörfler if (info->established_timing.res_640x480x75)
1927bdf92f3SAxel Dörfler _AddBaseMode(640, 480, 75);
1937bdf92f3SAxel Dörfler
1947bdf92f3SAxel Dörfler if (info->established_timing.res_800x600x56)
1957bdf92f3SAxel Dörfler _AddBaseMode(800, 600, 56);
1967bdf92f3SAxel Dörfler if (info->established_timing.res_800x600x60)
1977bdf92f3SAxel Dörfler _AddBaseMode(800, 600, 60);
1987bdf92f3SAxel Dörfler if (info->established_timing.res_800x600x72)
1997bdf92f3SAxel Dörfler _AddBaseMode(800, 600, 72);
2007bdf92f3SAxel Dörfler if (info->established_timing.res_800x600x75)
2017bdf92f3SAxel Dörfler _AddBaseMode(800, 600, 75);
2027bdf92f3SAxel Dörfler
2037bdf92f3SAxel Dörfler #if 0
2047bdf92f3SAxel Dörfler if (info->established_timing.res_832x624x75)
2057bdf92f3SAxel Dörfler _AddBaseMode(832, 624, 75);
2067bdf92f3SAxel Dörfler
2077bdf92f3SAxel Dörfler if (info->established_timing.res_1024x768x87i)
2087bdf92f3SAxel Dörfler _AddBaseMode(1024, 768, 87);
2097bdf92f3SAxel Dörfler #endif
2107bdf92f3SAxel Dörfler if (info->established_timing.res_1024x768x60)
2117bdf92f3SAxel Dörfler _AddBaseMode(1024, 768, 60);
2127bdf92f3SAxel Dörfler if (info->established_timing.res_1024x768x70)
2137bdf92f3SAxel Dörfler _AddBaseMode(1024, 768, 70);
2147bdf92f3SAxel Dörfler if (info->established_timing.res_1024x768x75)
2157bdf92f3SAxel Dörfler _AddBaseMode(1024, 768, 75);
2167bdf92f3SAxel Dörfler
2177bdf92f3SAxel Dörfler if (info->established_timing.res_1152x870x75)
2187bdf92f3SAxel Dörfler _AddBaseMode(1152, 870, 75);
2197bdf92f3SAxel Dörfler if (info->established_timing.res_1280x1024x75)
2207bdf92f3SAxel Dörfler _AddBaseMode(1280, 1024, 75);
2217bdf92f3SAxel Dörfler
2227bdf92f3SAxel Dörfler for (uint32 i = 0; i < EDID1_NUM_STD_TIMING; ++i) {
2237bdf92f3SAxel Dörfler if (info->std_timing[i].h_size <= 256)
2247bdf92f3SAxel Dörfler continue;
2257bdf92f3SAxel Dörfler
2267bdf92f3SAxel Dörfler _AddBaseMode(info->std_timing[i].h_size, info->std_timing[i].v_size,
2277bdf92f3SAxel Dörfler info->std_timing[i].refresh);
2287bdf92f3SAxel Dörfler }
2297bdf92f3SAxel Dörfler
2307badc72cSAxel Dörfler bool hasRanges = false;
2317badc72cSAxel Dörfler uint32 minHorizontalFrequency = 0;
2327badc72cSAxel Dörfler uint32 maxHorizontalFrequency = 0;
2337badc72cSAxel Dörfler uint32 minVerticalFrequency = 0;
2347badc72cSAxel Dörfler uint32 maxVerticalFrequency = 0;
2357badc72cSAxel Dörfler uint32 maxPixelClock = 0;
2367badc72cSAxel Dörfler
2377bdf92f3SAxel Dörfler for (uint32 i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i) {
23879566892SAxel Dörfler if (info->detailed_monitor[i].monitor_desc_type
2397badc72cSAxel Dörfler == EDID1_MONITOR_RANGES) {
2407badc72cSAxel Dörfler edid1_monitor_range& range
2417badc72cSAxel Dörfler = info->detailed_monitor[i].data.monitor_range;
2427badc72cSAxel Dörfler
2437badc72cSAxel Dörfler hasRanges = true;
2447badc72cSAxel Dörfler minHorizontalFrequency = range.min_h;
2457badc72cSAxel Dörfler maxHorizontalFrequency = range.max_h;
2467badc72cSAxel Dörfler minVerticalFrequency = range.min_v;
2477badc72cSAxel Dörfler maxVerticalFrequency = range.max_v;
2487badc72cSAxel Dörfler maxPixelClock = range.max_clock * 10000;
2497badc72cSAxel Dörfler continue;
2507badc72cSAxel Dörfler } else if (info->detailed_monitor[i].monitor_desc_type
25179566892SAxel Dörfler != EDID1_IS_DETAILED_TIMING)
2527bdf92f3SAxel Dörfler continue;
2537bdf92f3SAxel Dörfler
254c54a6536SAxel Dörfler // TODO: handle flags correctly!
25579566892SAxel Dörfler const edid1_detailed_timing& timing
25679566892SAxel Dörfler = info->detailed_monitor[i].data.detailed_timing;
2577bdf92f3SAxel Dörfler display_mode mode;
258c54a6536SAxel Dörfler
25979566892SAxel Dörfler if (timing.pixel_clock <= 0/* || timing.sync != 3*/)
260c54a6536SAxel Dörfler continue;
261c54a6536SAxel Dörfler
2627bdf92f3SAxel Dörfler mode.timing.pixel_clock = timing.pixel_clock * 10;
2637bdf92f3SAxel Dörfler mode.timing.h_display = timing.h_active;
264fe2aaee7SAxel Dörfler mode.timing.h_sync_start = timing.h_active + timing.h_sync_off;
265fe2aaee7SAxel Dörfler mode.timing.h_sync_end = mode.timing.h_sync_start + timing.h_sync_width;
266fe2aaee7SAxel Dörfler mode.timing.h_total = timing.h_active + timing.h_blank;
2677bdf92f3SAxel Dörfler mode.timing.v_display = timing.v_active;
268fe2aaee7SAxel Dörfler mode.timing.v_sync_start = timing.v_active + timing.v_sync_off;
269fe2aaee7SAxel Dörfler mode.timing.v_sync_end = mode.timing.v_sync_start + timing.v_sync_width;
270fe2aaee7SAxel Dörfler mode.timing.v_total = timing.v_active + timing.v_blank;
271c54a6536SAxel Dörfler mode.timing.flags = 0;
272c54a6536SAxel Dörfler if (timing.sync == 3) {
273c54a6536SAxel Dörfler if (timing.misc & 1)
274c54a6536SAxel Dörfler mode.timing.flags |= B_POSITIVE_HSYNC;
275c54a6536SAxel Dörfler if (timing.misc & 2)
276c54a6536SAxel Dörfler mode.timing.flags |= B_POSITIVE_VSYNC;
277c54a6536SAxel Dörfler }
278fe2aaee7SAxel Dörfler if (timing.interlaced)
279fe2aaee7SAxel Dörfler mode.timing.flags |= B_TIMING_INTERLACED;
2807bdf92f3SAxel Dörfler mode.space = B_RGB32;
2817bdf92f3SAxel Dörfler mode.virtual_width = timing.h_active;
2827bdf92f3SAxel Dörfler mode.virtual_height = timing.v_active;
2837bdf92f3SAxel Dörfler mode.h_display_start = 0;
2847bdf92f3SAxel Dörfler mode.v_display_start = 0;
2857bdf92f3SAxel Dörfler mode.flags = MODE_FLAGS;
286c54a6536SAxel Dörfler
28795009aeeSAxel Dörfler _AddMode(mode);
2887bdf92f3SAxel Dörfler }
2897bdf92f3SAxel Dörfler
2907badc72cSAxel Dörfler // Add other modes from the base list that satisfy the display's
2917badc72cSAxel Dörfler // requirements
2927badc72cSAxel Dörfler
2937badc72cSAxel Dörfler for (uint32 i = 0; i < kNumBaseModes; i++) {
2947badc72cSAxel Dörfler const display_mode& mode = kBaseModeList[i];
2957badc72cSAxel Dörfler
2967badc72cSAxel Dörfler // Check if a mode with this resolution already exists
2977badc72cSAxel Dörfler
2987badc72cSAxel Dörfler if (_FindMode(mode.timing.h_display, mode.timing.v_display) != NULL)
2997badc72cSAxel Dörfler continue;
3007badc72cSAxel Dörfler
3017badc72cSAxel Dörfler // Check monitor limits
3027badc72cSAxel Dörfler
3037badc72cSAxel Dörfler if (hasRanges) {
3047badc72cSAxel Dörfler uint32 verticalFrequency = 1000 * mode.timing.pixel_clock
3057badc72cSAxel Dörfler / (mode.timing.h_total * mode.timing.v_total);
3067badc72cSAxel Dörfler uint32 horizontalFrequency = mode.timing.h_total * verticalFrequency
3077badc72cSAxel Dörfler / 1000;
3087badc72cSAxel Dörfler
3097badc72cSAxel Dörfler if (minHorizontalFrequency > horizontalFrequency
3107badc72cSAxel Dörfler || maxHorizontalFrequency < horizontalFrequency
3117badc72cSAxel Dörfler || minVerticalFrequency > verticalFrequency
3127badc72cSAxel Dörfler || maxVerticalFrequency < verticalFrequency
3137badc72cSAxel Dörfler || maxPixelClock < mode.timing.pixel_clock)
3147badc72cSAxel Dörfler continue;
3157badc72cSAxel Dörfler }
3167badc72cSAxel Dörfler
31795009aeeSAxel Dörfler _AddMode(mode);
3187badc72cSAxel Dörfler }
3197bdf92f3SAxel Dörfler
3207bdf92f3SAxel Dörfler return true;
3217bdf92f3SAxel Dörfler }
3227bdf92f3SAxel Dörfler
3237bdf92f3SAxel Dörfler
3247bdf92f3SAxel Dörfler bool
AddModes(const display_mode * modes,uint32 count)3257bdf92f3SAxel Dörfler ModeList::AddModes(const display_mode* modes, uint32 count)
3267bdf92f3SAxel Dörfler {
3277bdf92f3SAxel Dörfler if (!_MakeSpace(count))
3287bdf92f3SAxel Dörfler return false;
3297bdf92f3SAxel Dörfler
3307bdf92f3SAxel Dörfler for (uint32 i = 0; i < count; i++) {
3317bdf92f3SAxel Dörfler fModes[fCount++] = modes[i];
3327bdf92f3SAxel Dörfler }
3337bdf92f3SAxel Dörfler
3347bdf92f3SAxel Dörfler return true;
3357bdf92f3SAxel Dörfler }
3367bdf92f3SAxel Dörfler
3377bdf92f3SAxel Dörfler
3387bdf92f3SAxel Dörfler bool
CreateColorSpaces(const color_space * spaces,uint32 count)3397bdf92f3SAxel Dörfler ModeList::CreateColorSpaces(const color_space* spaces, uint32 count)
3407bdf92f3SAxel Dörfler {
341b5cc636fSMichael Lotz uint32 baseModeCount = fCount;
342b5cc636fSMichael Lotz size_t baseModesSize = baseModeCount * sizeof(display_mode);
343b5cc636fSMichael Lotz display_mode* baseModes = (display_mode*)malloc(baseModesSize);
344b5cc636fSMichael Lotz if (baseModes == NULL)
3457bdf92f3SAxel Dörfler return false;
3467bdf92f3SAxel Dörfler
347b5cc636fSMichael Lotz memcpy(baseModes, fModes, baseModesSize);
348b5cc636fSMichael Lotz
349b5cc636fSMichael Lotz for (uint32 i = 0; i < count; i++) {
350b5cc636fSMichael Lotz if (i > 0 && !AddModes(baseModes, baseModeCount)) {
351b5cc636fSMichael Lotz free(baseModes);
352b5cc636fSMichael Lotz return false;
353b5cc636fSMichael Lotz }
354b5cc636fSMichael Lotz
355b5cc636fSMichael Lotz for (uint32 j = 0; j < baseModeCount; j++) {
356b5cc636fSMichael Lotz fModes[j + fCount - baseModeCount].space = spaces[i];
3577bdf92f3SAxel Dörfler }
3587bdf92f3SAxel Dörfler }
3597bdf92f3SAxel Dörfler
360b5cc636fSMichael Lotz free(baseModes);
3617bdf92f3SAxel Dörfler return true;
3627bdf92f3SAxel Dörfler }
3637bdf92f3SAxel Dörfler
3647bdf92f3SAxel Dörfler
3657bdf92f3SAxel Dörfler void
Filter(check_display_mode_hook hook)3667bdf92f3SAxel Dörfler ModeList::Filter(check_display_mode_hook hook)
3677bdf92f3SAxel Dörfler {
3687bdf92f3SAxel Dörfler if (hook == NULL)
3697bdf92f3SAxel Dörfler return;
3707bdf92f3SAxel Dörfler
3717bdf92f3SAxel Dörfler for (uint32 i = fCount; i-- > 0;) {
3727bdf92f3SAxel Dörfler if (!hook(&fModes[i]))
3737bdf92f3SAxel Dörfler _RemoveModeAt(i);
3747bdf92f3SAxel Dörfler }
3757bdf92f3SAxel Dörfler }
3767bdf92f3SAxel Dörfler
3777bdf92f3SAxel Dörfler
3787bdf92f3SAxel Dörfler void
Clean()3797bdf92f3SAxel Dörfler ModeList::Clean()
3807bdf92f3SAxel Dörfler {
3817bdf92f3SAxel Dörfler // sort mode list
3827bdf92f3SAxel Dörfler qsort(fModes, fCount, sizeof(display_mode), compare_mode);
3837bdf92f3SAxel Dörfler
3847bdf92f3SAxel Dörfler // remove duplicates
3857bdf92f3SAxel Dörfler for (uint32 i = fCount; i-- > 1;) {
3867bdf92f3SAxel Dörfler if (compare_mode(&fModes[i], &fModes[i - 1]) == 0)
3877bdf92f3SAxel Dörfler _RemoveModeAt(i);
3887bdf92f3SAxel Dörfler }
3897bdf92f3SAxel Dörfler }
3907bdf92f3SAxel Dörfler
3917bdf92f3SAxel Dörfler
3927bdf92f3SAxel Dörfler void
_AddBaseMode(uint16 width,uint16 height,uint32 refresh)3937bdf92f3SAxel Dörfler ModeList::_AddBaseMode(uint16 width, uint16 height, uint32 refresh)
3947bdf92f3SAxel Dörfler {
39595009aeeSAxel Dörfler // Check the manually tweaked list first
39695009aeeSAxel Dörfler
3977bdf92f3SAxel Dörfler for (uint32 i = 0; i < kNumBaseModes; i++) {
3987bdf92f3SAxel Dörfler const display_mode& mode = kBaseModeList[i];
3997bdf92f3SAxel Dörfler
400c54a6536SAxel Dörfler // Add mode if width and height match, and the computed refresh rate of
401c54a6536SAxel Dörfler // the mode is within 1.2 percent of the refresh rate specified by the
402c54a6536SAxel Dörfler // caller. Note that refresh rates computed from mode parameters is
403c54a6536SAxel Dörfler // not exact; thus, the tolerance of 1.2% was obtained by testing the
404c54a6536SAxel Dörfler // various established modes that can be selected by the EDID info.
405c54a6536SAxel Dörfler
4067bdf92f3SAxel Dörfler if (mode.timing.h_display == width && mode.timing.v_display == height
407c54a6536SAxel Dörfler && fabs(get_refresh_rate(mode) - refresh) < refresh * 0.012) {
40895009aeeSAxel Dörfler _AddMode(mode);
40995009aeeSAxel Dörfler return;
4107bdf92f3SAxel Dörfler }
4117bdf92f3SAxel Dörfler }
41295009aeeSAxel Dörfler
41395009aeeSAxel Dörfler // If that didn't have any entries, compute the entry
41495009aeeSAxel Dörfler display_mode mode;
41595009aeeSAxel Dörfler if (compute_display_timing(width, height, refresh, false, &mode.timing)
41695009aeeSAxel Dörfler != B_OK)
41795009aeeSAxel Dörfler return;
41895009aeeSAxel Dörfler
419d3d53515SAxel Dörfler fill_display_mode(width, height, &mode);
42095009aeeSAxel Dörfler
42195009aeeSAxel Dörfler _AddMode(mode);
4227bdf92f3SAxel Dörfler }
4237bdf92f3SAxel Dörfler
4247bdf92f3SAxel Dörfler
4257badc72cSAxel Dörfler display_mode*
_FindMode(uint16 width,uint16 height) const4267badc72cSAxel Dörfler ModeList::_FindMode(uint16 width, uint16 height) const
4277badc72cSAxel Dörfler {
4287badc72cSAxel Dörfler for (uint32 i = 0; i < fCount; i++) {
4297badc72cSAxel Dörfler const display_mode& mode = fModes[i];
4307badc72cSAxel Dörfler
4317badc72cSAxel Dörfler if (mode.timing.h_display == width && mode.timing.v_display == height)
4327badc72cSAxel Dörfler return &fModes[i];
4337badc72cSAxel Dörfler }
4347badc72cSAxel Dörfler
4357badc72cSAxel Dörfler return NULL;
4367badc72cSAxel Dörfler }
4377badc72cSAxel Dörfler
4387badc72cSAxel Dörfler
4397bdf92f3SAxel Dörfler bool
_MakeSpace(uint32 count)4407bdf92f3SAxel Dörfler ModeList::_MakeSpace(uint32 count)
4417bdf92f3SAxel Dörfler {
4427bdf92f3SAxel Dörfler if (fCount + count <= fCapacity)
4437bdf92f3SAxel Dörfler return true;
4447bdf92f3SAxel Dörfler
4457bdf92f3SAxel Dörfler uint32 capacity = (fCapacity + count + 0xf) & ~0xf;
4467bdf92f3SAxel Dörfler display_mode* modes = (display_mode*)realloc(fModes,
4477bdf92f3SAxel Dörfler capacity * sizeof(display_mode));
4487bdf92f3SAxel Dörfler if (modes == NULL)
4497bdf92f3SAxel Dörfler return false;
4507bdf92f3SAxel Dörfler
4517bdf92f3SAxel Dörfler fModes = modes;
4527bdf92f3SAxel Dörfler fCapacity = capacity;
4537bdf92f3SAxel Dörfler return true;
4547bdf92f3SAxel Dörfler }
4557bdf92f3SAxel Dörfler
4567bdf92f3SAxel Dörfler
4577bdf92f3SAxel Dörfler bool
_AddMode(const display_mode & mode)45895009aeeSAxel Dörfler ModeList::_AddMode(const display_mode& mode)
4597bdf92f3SAxel Dörfler {
4600ba65dceSAxel Dörfler // TODO: filter by monitor timing constraints!
4610ba65dceSAxel Dörfler // TODO: remove double entries
4627bdf92f3SAxel Dörfler if (!_MakeSpace(1))
4637bdf92f3SAxel Dörfler return false;
4647bdf92f3SAxel Dörfler
46595009aeeSAxel Dörfler fModes[fCount++] = mode;
4667bdf92f3SAxel Dörfler return true;
4677bdf92f3SAxel Dörfler }
4687bdf92f3SAxel Dörfler
4697bdf92f3SAxel Dörfler
4707bdf92f3SAxel Dörfler void
_RemoveModeAt(uint32 index)4717bdf92f3SAxel Dörfler ModeList::_RemoveModeAt(uint32 index)
4727bdf92f3SAxel Dörfler {
4737bdf92f3SAxel Dörfler if (index < fCount - 1) {
4747bdf92f3SAxel Dörfler memmove(&fModes[index], &fModes[index + 1],
4757bdf92f3SAxel Dörfler (fCount - 1 - index) * sizeof(display_mode));
4767bdf92f3SAxel Dörfler }
4777bdf92f3SAxel Dörfler
4787bdf92f3SAxel Dörfler fCount--;
4797bdf92f3SAxel Dörfler }
4807bdf92f3SAxel Dörfler
4817bdf92f3SAxel Dörfler
4827bdf92f3SAxel Dörfler // #pragma mark -
4837bdf92f3SAxel Dörfler
4847bdf92f3SAxel Dörfler
4857bdf92f3SAxel Dörfler extern "C" area_id
create_display_modes(const char * name,edid1_info * edid,const display_mode * initialModes,uint32 initialModeCount,const color_space * spaces,uint32 spacesCount,check_display_mode_hook hook,display_mode ** _modes,uint32 * _count)4867bdf92f3SAxel Dörfler create_display_modes(const char* name, edid1_info* edid,
4877bdf92f3SAxel Dörfler const display_mode* initialModes, uint32 initialModeCount,
4887bdf92f3SAxel Dörfler const color_space *spaces, uint32 spacesCount,
4897bdf92f3SAxel Dörfler check_display_mode_hook hook, display_mode** _modes, uint32* _count)
4907bdf92f3SAxel Dörfler {
4917bdf92f3SAxel Dörfler if (_modes == NULL || _count == NULL)
4927bdf92f3SAxel Dörfler return B_BAD_VALUE;
4937bdf92f3SAxel Dörfler
4947bdf92f3SAxel Dörfler // compile initial mode list from the different sources
4957bdf92f3SAxel Dörfler
4967bdf92f3SAxel Dörfler ModeList modes;
497b2a77322SAxel Dörfler if (initialModes != NULL)
4987bdf92f3SAxel Dörfler modes.AddModes(initialModes, initialModeCount);
4997bdf92f3SAxel Dörfler
5007bdf92f3SAxel Dörfler if (edid != NULL)
5017bdf92f3SAxel Dörfler modes.AddModes(edid);
5027bdf92f3SAxel Dörfler else
5037bdf92f3SAxel Dörfler modes.AddModes(kBaseModeList, kNumBaseModes);
5047bdf92f3SAxel Dörfler
5057bdf92f3SAxel Dörfler // filter out modes the caller doesn't like, and multiply modes for
5067bdf92f3SAxel Dörfler // every color space
5077bdf92f3SAxel Dörfler
5087bdf92f3SAxel Dörfler if (spaces == NULL) {
5097bdf92f3SAxel Dörfler const color_space kDefaultSpaces[] = {B_RGB32_LITTLE, B_RGB16_LITTLE,
5107bdf92f3SAxel Dörfler B_RGB15_LITTLE, B_CMAP8};
5117bdf92f3SAxel Dörfler modes.CreateColorSpaces(kDefaultSpaces,
5127bdf92f3SAxel Dörfler sizeof(kDefaultSpaces) / sizeof(kDefaultSpaces[0]));
5137bdf92f3SAxel Dörfler } else
5147bdf92f3SAxel Dörfler modes.CreateColorSpaces(spaces, spacesCount);
5157bdf92f3SAxel Dörfler
5167bdf92f3SAxel Dörfler modes.Filter(hook);
5177bdf92f3SAxel Dörfler modes.Clean();
5187bdf92f3SAxel Dörfler
5197bdf92f3SAxel Dörfler // create area for output modes
5207bdf92f3SAxel Dörfler
5217bdf92f3SAxel Dörfler size_t size = (sizeof(display_mode) * modes.Count() + B_PAGE_SIZE - 1)
5227bdf92f3SAxel Dörfler & ~(B_PAGE_SIZE - 1);
5237bdf92f3SAxel Dörfler display_mode *list;
5247bdf92f3SAxel Dörfler area_id area = create_area(name, (void **)&list, B_ANY_ADDRESS,
525*eb2b3762SRudolf Cornelissen size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA | B_CLONEABLE_AREA);
5267bdf92f3SAxel Dörfler if (area < B_OK)
5277bdf92f3SAxel Dörfler return area;
5287bdf92f3SAxel Dörfler
5297bdf92f3SAxel Dörfler memcpy(list, modes.Modes(), sizeof(display_mode) * modes.Count());
5307bdf92f3SAxel Dörfler *_modes = list;
5317bdf92f3SAxel Dörfler *_count = modes.Count();
5327bdf92f3SAxel Dörfler
5337bdf92f3SAxel Dörfler return area;
5347bdf92f3SAxel Dörfler }
5357bdf92f3SAxel Dörfler
53695009aeeSAxel Dörfler
53795009aeeSAxel Dörfler void
fill_display_mode(uint32 width,uint32 height,display_mode * mode)538d3d53515SAxel Dörfler fill_display_mode(uint32 width, uint32 height, display_mode* mode)
53995009aeeSAxel Dörfler {
54095009aeeSAxel Dörfler mode->space = B_CMAP8;
541d3d53515SAxel Dörfler mode->virtual_width = width;
542d3d53515SAxel Dörfler mode->virtual_height = height;
54395009aeeSAxel Dörfler mode->h_display_start = 0;
54495009aeeSAxel Dörfler mode->v_display_start = 0;
54595009aeeSAxel Dörfler mode->flags = MODE_FLAGS;
54695009aeeSAxel Dörfler }
547