1 | /*␊ |
2 | * edid.c␊ |
3 | * ␊ |
4 | *␊ |
5 | * Created by Evan Lojewski on 12/1/09.␊ |
6 | * Copyright 2009. All rights reserved.␊ |
7 | * ␊ |
8 | *␉Slice 2010, based on Joblo works␊ |
9 | */␊ |
10 | ␊ |
11 | ␊ |
12 | //#include "libsaio.h"␊ |
13 | #include "edid.h"␊ |
14 | #include "vbe.h"␊ |
15 | #include "graphics.h"␊ |
16 | #include "boot.h"␊ |
17 | //----------------------------------------------------------------------------------␊ |
18 | ␊ |
19 | #define FBMON_FIX_HEADER 1␊ |
20 | #define FBMON_FIX_INPUT 2␊ |
21 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))␊ |
22 | ␊ |
23 | //----------------------------------------------------------------------------------␊ |
24 | /*␊ |
25 | struct broken_edid {␊ |
26 | ␉const char manufacturer[4];␊ |
27 | ␉UInt32 model;␊ |
28 | ␉UInt32 fix;␊ |
29 | };␊ |
30 | ␊ |
31 | //----------------------------------------------------------------------------------␊ |
32 | ␊ |
33 | broken_edid brokendb[] = {␊ |
34 | ␉// DEC FR-PCXAV-YZ *␊ |
35 | ␉{ "DEC", 0x073a, FBMON_FIX_HEADER,},␊ |
36 | ␉// ViewSonic PF775a *␊ |
37 | ␉{ "VSC", 0x5a44, FBMON_FIX_INPUT,␉}␊ |
38 | };␊ |
39 | //----------------------------------------------------------------------------------␊ |
40 | */␊ |
41 | const unsigned char edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00␉};␊ |
42 | ␊ |
43 | //----------------------------------------------------------------------------------␊ |
44 | int edid_compare(unsigned char *edid1, unsigned char *edid2)␊ |
45 | {␊ |
46 | ␉int result = 0;␊ |
47 | ␉unsigned char *block = edid1 + ID_MANUFACTURER_NAME, manufacturer1[4], manufacturer2[4];;␊ |
48 | ␉manufacturer1[0] = ((block[0] & 0x7c) >> 2) + '@';␊ |
49 | ␉manufacturer1[1] = ((block[0] & 0x03) << 3) + ((block[1] & 0xe0) >> 5) + '@';␊ |
50 | ␉manufacturer1[2] = (block[1] & 0x1f) + '@';␊ |
51 | ␉manufacturer1[3] = 0;␊ |
52 | ␉␊ |
53 | ␉block = edid2 + ID_MANUFACTURER_NAME;␊ |
54 | ␉manufacturer2[0] = ((block[0] & 0x7c) >> 2) + '@';␊ |
55 | ␉manufacturer2[1] = ((block[0] & 0x03) << 3) + ((block[1] & 0xe0) >> 5) + '@';␊ |
56 | ␉manufacturer2[2] = (block[1] & 0x1f) + '@';␊ |
57 | ␉manufacturer2[3] = 0;␊ |
58 | ␉int x;␊ |
59 | ␉for(x = 0; x < 4; x++)␊ |
60 | ␉{␊ |
61 | ␉␉if(manufacturer1[x] == manufacturer2[x])␊ |
62 | ␉␉␉result++;␊ |
63 | ␉}␊ |
64 | ␉␊ |
65 | ␉return result;␊ |
66 | }␊ |
67 | ␊ |
68 | int check_edid(unsigned char *edid)␊ |
69 | {␊ |
70 | ␉unsigned char *block = edid + ID_MANUFACTURER_NAME, manufacturer[4];␊ |
71 | ␉//unsigned char *b;␊ |
72 | ␉UInt32 model;␊ |
73 | ␉//int i, fix = 0, ret = 0;␊ |
74 | ␉␊ |
75 | ␉manufacturer[0] = ((block[0] & 0x7c) >> 2) + '@';␊ |
76 | ␉manufacturer[1] = ((block[0] & 0x03) << 3) +␊ |
77 | ␉((block[1] & 0xe0) >> 5) + '@';␊ |
78 | ␉manufacturer[2] = (block[1] & 0x1f) + '@';␊ |
79 | ␉manufacturer[3] = 0;␊ |
80 | ␉model = block[2] + (block[3] << 8);␊ |
81 | /*␉␊ |
82 | ␉for (i = 0; i < (int)ARRAY_SIZE(brokendb); i++) {␊ |
83 | ␉␉if (!strncmp((const char *)manufacturer, brokendb[i].manufacturer, 4) &&␊ |
84 | ␉␉␉brokendb[i].model == model) {␊ |
85 | ␉␉␉DEBG("ATIFB: The EDID Block of "␊ |
86 | ␉␉␉␉ "Manufacturer: %s Model: 0x%08lx is known to "␊ |
87 | ␉␉␉␉ "be broken,\n", manufacturer, model);␊ |
88 | ␉␉␉fix = brokendb[i].fix;␊ |
89 | ␉␉␉break;␊ |
90 | ␉␉}␊ |
91 | ␉}␊ |
92 | ␉␊ |
93 | ␉switch (fix) {␊ |
94 | ␉␉case FBMON_FIX_HEADER:␊ |
95 | ␉␉␉for (i = 0; i < 8; i++) {␊ |
96 | ␉␉␉␉if (edid[i] != edid_v1_header[i])␊ |
97 | ␉␉␉␉␉ret = fix;␊ |
98 | ␉␉␉}␊ |
99 | ␉␉␉break;␊ |
100 | ␉␉case FBMON_FIX_INPUT:␊ |
101 | ␉␉␉b = edid + EDID_STRUCT_DISPLAY;␊ |
102 | ␉␉␉/// Only if display is GTF capable will␊ |
103 | ␉␉␉ //the input type be reset to analog *␊ |
104 | ␉␉␉if (b[4] & 0x01 && b[0] & 0x80)␊ |
105 | ␉␉␉␉ret = fix;␊ |
106 | ␉␉␉break;␊ |
107 | ␉}␊ |
108 | */␉␊ |
109 | ␉return 0; //ret;␊ |
110 | }␊ |
111 | ␊ |
112 | //----------------------------------------------------------------------------------␊ |
113 | ␊ |
114 | static void fix_edid(unsigned char *edid, int fix)␊ |
115 | {␊ |
116 | ␉unsigned char *b;␊ |
117 | ␉␊ |
118 | ␉switch (fix) {␊ |
119 | ␉␉case FBMON_FIX_HEADER:␊ |
120 | ␉␉␉msglog("EDID: trying a header reconstruct\n");␊ |
121 | ␉␉␉memcpy(edid, edid_v1_header, 8);␊ |
122 | ␉␉␉break;␊ |
123 | ␉␉case FBMON_FIX_INPUT:␊ |
124 | ␉␉␉msglog("EDID: trying to fix input type\n");␊ |
125 | ␉␉␉b = edid + EDID_STRUCT_DISPLAY;␊ |
126 | ␉␉␉b[0] &= ~0x80;␊ |
127 | ␉␉␉edid[127] += 0x80;␊ |
128 | ␉}␊ |
129 | }␊ |
130 | ␊ |
131 | //----------------------------------------------------------------------------------␊ |
132 | ␊ |
133 | int edid_checksum(unsigned char *edid)␊ |
134 | {␊ |
135 | ␉unsigned char i, csum = 0, all_null = 0;␊ |
136 | ␉int err = 0, fix = check_edid(edid);␊ |
137 | ␉␊ |
138 | ␉if (fix)␊ |
139 | ␉␉fix_edid(edid, fix);␊ |
140 | ␉␊ |
141 | ␉for (i = 0; i < EDID_LENGTH; i++) {␊ |
142 | ␉␉csum += edid[i];␊ |
143 | ␉␉all_null |= edid[i];␊ |
144 | ␉}␊ |
145 | ␉␊ |
146 | ␉if (csum == 0x00 && all_null) {␊ |
147 | ␉␉/* checksum passed, everything's good */␊ |
148 | ␉␉err = 1;␊ |
149 | ␉}␊ |
150 | ␉else␊ |
151 | ␉{␊ |
152 | ␉␉msglog(" edid_checksum error ");␊ |
153 | ␉}␊ |
154 | ␉␊ |
155 | ␉return err;␊ |
156 | }␊ |
157 | ␊ |
158 | //----------------------------------------------------------------------------------␊ |
159 | ␊ |
160 | static int edid_check_header(unsigned char *edid)␊ |
161 | {␊ |
162 | ␉int i, err = 1, fix = check_edid(edid);␊ |
163 | ␉␊ |
164 | ␉if (fix)␊ |
165 | ␉␉fix_edid(edid, fix);␊ |
166 | ␉␊ |
167 | ␉for (i = 0; i < 8; i++) {␊ |
168 | ␉␉if (edid[i] != edid_v1_header[i])␊ |
169 | ␉␉␉err = 0;␊ |
170 | ␉}␊ |
171 | ␉␊ |
172 | ␉if (err == 0)␊ |
173 | ␉{␊ |
174 | ␉␉msglog(" edid_check_header error ");␊ |
175 | ␉}␊ |
176 | ␊ |
177 | ␉return err;␊ |
178 | }␊ |
179 | //------------------------------------------------------------------------␊ |
180 | bool verifyEDID(unsigned char *edid)␊ |
181 | {␊ |
182 | ␉if (edid == NULL || !edid_checksum(edid) ||␉!edid_check_header(edid)) ␊ |
183 | ␉{␊ |
184 | ␉␉return false;␊ |
185 | ␉}␊ |
186 | ␉return true;␊ |
187 | }␊ |
188 | ␊ |
189 | int edid_is_timing_block(unsigned char *block)␊ |
190 | {␊ |
191 | ␉if ((block[0] != 0x00) || (block[1] != 0x00) || (block[2] != 0x00) || (block[4] != 0x00))␊ |
192 | ␉{␊ |
193 | ␉␉return 1;␊ |
194 | ␉} else {␊ |
195 | ␉␉return 0;␊ |
196 | ␉}␊ |
197 | }␊ |
198 | //----------------------------------------------------------------------------------␊ |
199 | ␊ |
200 | int fb_parse_edid(struct EDID *edid, edid_mode* var) //(struct EDID *edid, UInt32* x, UInt32* y)␊ |
201 | {␊ |
202 | ␉int i;␊ |
203 | ␉unsigned char *block;␊ |
204 | ␊ |
205 | ␉msglog(" Parse Edid:");␊ |
206 | ␉if(!verifyEDID((unsigned char *)edid))␊ |
207 | ␉{␊ |
208 | ␉␉msglog(" error\n");␊ |
209 | ␉␉return 0;␊ |
210 | ␉}␊ |
211 | ␉␊ |
212 | ␉block = (unsigned char *)edid + DETAILED_TIMING_DESCRIPTIONS_START; //54␊ |
213 | ␉␊ |
214 | ␉for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {␊ |
215 | ␉␉if (edid_is_timing_block(block)) {␊ |
216 | ␉␉␉msglog(" descriptor block %d is timing descriptor ", i);␊ |
217 | ␉␉␉var->h_active = H_ACTIVE;␊ |
218 | ␉␉␉var->v_active = V_ACTIVE;␊ |
219 | ␉␉␉var->h_sync_offset = H_SYNC_OFFSET;␊ |
220 | ␉␉␉var->h_sync_width = H_SYNC_WIDTH;␊ |
221 | ␉␉␉var->h_blanking = H_BLANKING;␊ |
222 | ␉␉␉var->v_blanking = V_BLANKING;␊ |
223 | ␉␉␉var->pixel_clock = PIXEL_CLOCK;␊ |
224 | ␉␉␉var->v_sync_offset = V_SYNC_OFFSET;␊ |
225 | ␉␉␉var->v_sync_width = V_SYNC_WIDTH;␊ |
226 | ␉␉␉/*␊ |
227 | ␉␉␉var->xres = var->xres_virtual = H_ACTIVE;␊ |
228 | ␉␉␉var->yres = var->yres_virtual = V_ACTIVE;␊ |
229 | ␉␉␉var->height = var->width = -1;␊ |
230 | ␉␉␉var->right_margin = H_SYNC_OFFSET;␊ |
231 | ␉␉␉var->left_margin = (H_ACTIVE + H_BLANKING) -␊ |
232 | ␉␉␉(H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);␊ |
233 | ␉␉␉var->upper_margin = V_BLANKING - V_SYNC_OFFSET -␊ |
234 | ␉␉␉V_SYNC_WIDTH;␊ |
235 | ␉␉␉var->lower_margin = V_SYNC_OFFSET;␊ |
236 | ␉␉␉var->hsync_len = H_SYNC_WIDTH;␊ |
237 | ␉␉␉var->vsync_len = V_SYNC_WIDTH;␊ |
238 | ␉␉␉var->pixclock = PIXEL_CLOCK;␊ |
239 | ␉␉␉var->pixclock /= 1000;␊ |
240 | ␉␉␉var->pixclock = KHZ2PICOS(var->pixclock);␊ |
241 | ␉␉␉␊ |
242 | ␉␉␉if (HSYNC_POSITIVE)␊ |
243 | ␉␉␉␉var->sync |= FB_SYNC_HOR_HIGH_ACT;␊ |
244 | ␉␉␉if (VSYNC_POSITIVE)␊ |
245 | ␉␉␉␉var->sync |= FB_SYNC_VERT_HIGH_ACT;␊ |
246 | ␉␉␉ */␊ |
247 | ␉␉␉return 1;␊ |
248 | ␉␉}␊ |
249 | ␉}␊ |
250 | ␉return 0;␊ |
251 | }␊ |
252 | ␊ |
253 | void getResolution(UInt32* x, UInt32* y, UInt32* bp)␊ |
254 | {␊ |
255 | //␉int val;␊ |
256 | ␉static UInt32 xResolution, yResolution, bpResolution = 32;␉// assume 32bits␊ |
257 | /*␊ |
258 | ␉if(getIntForKey(kScreenWidth, &val, &bootInfo->chameleonConfig))␊ |
259 | ␉{␊ |
260 | ␉␉xResolution = val;␊ |
261 | ␉}␊ |
262 | ␉␊ |
263 | ␉if(getIntForKey(kScreenHeight, &val, &bootInfo->chameleonConfig))␊ |
264 | ␉{␊ |
265 | ␉␉yResolution = val;␊ |
266 | ␉}␊ |
267 | */␊ |
268 | ␉if(!xResolution || !yResolution || !bpResolution)␊ |
269 | ␉{␊ |
270 | ␉␉char* edidInfo = readEDID();␊ |
271 | ␉␉␊ |
272 | ␉␉if(!edidInfo)␊ |
273 | ␉␉{␊ |
274 | ␉␉␉return;␊ |
275 | ␉␉}␊ |
276 | ␊ |
277 | ␉␉edid_mode mode;␊ |
278 | ␉␉// TODO: check *all* resolutions reported and either use the highest, or the native resolution (if there is a flag for that)␊ |
279 | ␉␉//xResolution = edidInfo[56] | ((edidInfo[58] & 0xF0) << 4); ␊ |
280 | ␉␉//yResolution = edidInfo[59] | ((edidInfo[61] & 0xF0) << 4); ␊ |
281 | ␉␉//Slice - done here␊ |
282 | ␉␉␊ |
283 | ␉␉if(fb_parse_edid((struct EDID *)edidInfo, &mode) == 0)␊ |
284 | ␉␉{␊ |
285 | ␉␉␉xResolution = DEFAULT_SCREEN_WIDTH;␊ |
286 | ␉␉␉yResolution = DEFAULT_SCREEN_HEIGHT;␊ |
287 | ␉␉}␊ |
288 | ␉␉else␊ |
289 | ␉␉{␊ |
290 | ␉␉␉xResolution = mode.h_active;␊ |
291 | ␉␉␉yResolution = mode.v_active;␊ |
292 | ␉␉}␊ |
293 | ␊ |
294 | ␉␉/*␊ |
295 | ␉␉ 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x32 0x0C␊ |
296 | ␉␉ 0x00 0xDF 0x00 0x00 0x00 0x00 0xFF 0xFF 0xFF 0x00␊ |
297 | ␉␉ 0x0C 0xDF 0x00 0x00 0x12 0x03 0x21 0x78 0xE9 0x99 ␊ |
298 | ␉␉ 0x53 0x28 0xFF 0xFF 0x32 0xDF 0x00 0x12 0x80 0x78 ␊ |
299 | ␉␉ 0xD5 0x53 0x26 0x00 0x01 0x01 0x01 0x01 0xFF 0x00 ␊ |
300 | ␉␉ 0xDF 0x00 0x03 0x78 0x99 0x28 0x00 0x01 0x01 0x01 ␊ |
301 | ␉␉ 0x01 0x21 0x84 0x20 0xFF 0x0C 0x00 0x03 0x0A 0x53 ␊ |
302 | ␉␉ 0x54 0x01 0x01 0x01 0xDE 0x84 0x56 0x00 0xA0 0x30␊ |
303 | ␉␉ 0xFF 0xDF 0x12 0x78 0x53 0x00 0x01 0x01 0x01 0x84 ␊ |
304 | ␉␉ 0x00 0x18 0x84 0x00 0x00 0x57 0xFF 0x00 0x80 0x99␊ |
305 | ␉␉ 0x54 0x01 0x01 0x21 0x20 0x00 0x50 0x00 0x00 0x35␊ |
306 | ␉␉ 0x57 0xFE 0x00 0x00 0x78 0x28 0x01 0x01 0x21 0x20␊ |
307 | ␉␉ 0x18 0x30 0x00 0x57 0x34 0xFE 0xAA 0x9A ␊ |
308 | ␊ |
309 | ␉␉ */␊ |
310 | ␉␉␊ |
311 | ␉␉//msglog("H Active = %d ", edidInfo[56] | ((edidInfo[58] & 0xF0) << 4) );␊ |
312 | ␉␉//msglog("V Active = %d \n", edidInfo[59] | ((edidInfo[61] & 0xF0) << 4) );␊ |
313 | ␉␉␊ |
314 | ␉␉free( edidInfo );␊ |
315 | ␉␉␊ |
316 | ␉␉//if(!xResolution) xResolution = DEFAULT_SCREEN_WIDTH;␊ |
317 | ␉␉//if(!yResolution) yResolution = DEFAULT_SCREEN_HEIGHT;␊ |
318 | ␊ |
319 | ␉}␊ |
320 | ␊ |
321 | ␉*x = xResolution;␊ |
322 | ␉*y = yResolution;␊ |
323 | ␉*bp = bpResolution;␊ |
324 | ␊ |
325 | ␉msglog("Best mode: %dx%dx%d\n", *x, *y, *bp);␊ |
326 | }␊ |
327 | ␊ |
328 | char* readEDID()␊ |
329 | {␊ |
330 | ␉SInt16 last_reported = -1;␊ |
331 | ␉UInt8 edidInfo[EDID_BLOCK_SIZE];␊ |
332 | ␊ |
333 | ␉UInt8 header1[] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00};␊ |
334 | ␉UInt8 header2[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};␊ |
335 | ␉␊ |
336 | ␉SInt16 status;␊ |
337 | ␉UInt16 blocks_left = 1;␊ |
338 | //␉msglog("readEDID\n");␊ |
339 | ␉do␊ |
340 | ␉{␊ |
341 | ␉␉// TODO: This currently only retrieves the *last* block, make the block buffer expand as needed / calculated from the first block␊ |
342 | ␊ |
343 | ␉␉bzero( edidInfo, EDID_BLOCK_SIZE);␊ |
344 | ␊ |
345 | ␉␉status = getEDID(edidInfo, blocks_left);␊ |
346 | ␊ |
347 | ␉␉/*␊ |
348 | ␉␉msglog("Buffer location: 0x%X status: %d\n", SEG(edidInfo) << 16 | OFF(edidInfo), status);␊ |
349 | ␊ |
350 | ␉␉int j, i;␊ |
351 | ␉␉for (j = 0; j < 8; j++)␊ |
352 | ␉␉{␊ |
353 | ␉␉␉for(i = 0; i < 16; i++) msglog(" 0x%02X", edidInfo[((i+1) * (j + 1)) - 1]);␊ |
354 | ␉␉␉msglog("\n");␊ |
355 | ␉␉}␊ |
356 | ␉␉*/␊ |
357 | ␊ |
358 | ␉␉if(status == 0)␊ |
359 | ␉␉{␊ |
360 | ␉␉␉//if( edidInfo[0] == 0x00 || edidInfo[0] == 0xFF)␊ |
361 | ␉␉␉if((memcmp(edidInfo, header1, sizeof(header1)) != 0) ||␊ |
362 | ␉␉␉ (memcmp(edidInfo, header2, sizeof(header2)) != 0) )␊ |
363 | ␉␉␉{␊ |
364 | ␉␉␉␉blocks_left--;␊ |
365 | ␉␉␉␉int reported = edidInfo[ EDID_V1_BLOCKS_TO_GO_OFFSET ];␊ |
366 | ␊ |
367 | ␉␉␉␉if ( reported > blocks_left )␊ |
368 | ␉␉␉␉{␊ |
369 | ␉␉␉␉␉msglog("EDID claims %d more blocks left\n", reported);␊ |
370 | ␉␉␉␉}␊ |
371 | ␉␉␉␉␊ |
372 | ␉␉␉␉if ( (last_reported <= reported && last_reported != -1)␊ |
373 | ␉␉␉␉␉|| reported == 0xff␊ |
374 | ␉␉␉␉␉/* 0xff frequently comes up in corrupt edids */␊ |
375 | ␉␉␉␉␉//|| reported == MAGIC␊ |
376 | ␉␉␉␉␉)␊ |
377 | ␉␉␉␉{␊ |
378 | ␉␉␉␉␉msglog("Last reported %d\n", last_reported);␊ |
379 | ␉␉␉␉␉msglog("EDID blocks left is wrong.\n"␊ |
380 | ␉␉␉␉␉␉ "Your EDID is probably invalid.\n");␊ |
381 | ␉␉␉␉␉return 0;␊ |
382 | ␉␉␉␉}␊ |
383 | ␉␉␉␉else␊ |
384 | ␉␉␉␉{␊ |
385 | ␉␉␉␉␉//printf("Reading EDID block\n");␊ |
386 | ␉␉␉␉␉//printf("H Active = %d", ebiosInfo[56] | ((ebiosInfo[58] & 0xF0) << 4) );␊ |
387 | ␉␉␉␉␉//printf("V Active = %d", ebiosInfo[59] | ((ebiosInfo[61] & 0xF0) << 4) );␊ |
388 | ␊ |
389 | ␉␉␉␉␉last_reported = reported;␊ |
390 | ␉␉␉␉␉blocks_left = reported;␊ |
391 | ␉␉␉␉}␊ |
392 | ␉␉␉} ␊ |
393 | ␉␉␉else␊ |
394 | ␉␉␉{␊ |
395 | ␉␉␉␉msglog("Invalid block %d\n", blocks_left);␊ |
396 | ␉␉␉␉msglog("Header1 = %d", memcmp(edidInfo, header1, sizeof(header1)) );␊ |
397 | ␉␉␉␉msglog("Header2 = %d", memcmp(edidInfo, header2, sizeof(header2)) );␊ |
398 | ␉␉␉␉return 0;␊ |
399 | ␉␉␉}␊ |
400 | ␉␉}␊ |
401 | ␉␉blocks_left = 0;␊ |
402 | ␉} while(blocks_left);␊ |
403 | ␊ |
404 | ␉char* ret = malloc(sizeof(edidInfo));␊ |
405 | ␉if (!ret)␊ |
406 | ␉{␊ |
407 | ␉␉return 0;␊ |
408 | ␉}␊ |
409 | ␉memcpy(ret, edidInfo, sizeof(edidInfo));␊ |
410 | ␉return ret;␊ |
411 | }␊ |
412 | ␊ |
413 | int getEDID( void * edidBlock, UInt8 block)␊ |
414 | {␊ |
415 | ␉biosBuf_t bb;␊ |
416 | ␉bzero(&bb, sizeof(bb));␊ |
417 | ␉bb.intno = 0x10;␊ |
418 | ␉bb.eax.rr = 0x4F15;␊ |
419 | ␉bb.ebx.r.l= 0x01;␊ |
420 | ␉bb.edx.rr = block;␊ |
421 | ␉bb.es = SEG( edidBlock );␊ |
422 | ␉bb.edi.rr = OFF( edidBlock );␊ |
423 | ␉bios( &bb );␊ |
424 | ␉return(bb.eax.r.h);␊ |
425 | }␊ |
426 | |