]>
git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/hwinfo/src/hd/monitor.c
10 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
13 * Read the info out of the 'SuSE=' entry in /proc/cmdline. It contains
14 * (among others) info from the EDID record got by our syslinux extension.
16 * We will try to look up our monitor id in the id file to get additional
18 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
22 static void add_old_mac_monitor(hd_data_t
*hd_data
);
23 static void add_monitor(hd_data_t
*hd_data
, devtree_t
*dt
);
25 static int chk_edid_info(hd_data_t
*hd_data
, unsigned char *edid
);
27 static void add_lcd_info(hd_data_t
*hd_data
, hd_t
*hd
, bios_info_t
*bt
);
29 static void add_edid_info(hd_data_t
*hd_data
, hd_t
*hd
, unsigned char *edid
);
30 static void add_monitor_res(hd_t
*hd
, unsigned x
, unsigned y
, unsigned hz
, unsigned il
);
31 static void fix_edid_info(hd_data_t
*hd_data
, unsigned char *edid
);
34 void hd_scan_monitor(hd_data_t
*hd_data
)
38 char *s
, *s0
, *s1
, *se
, m
[8], *t
;
41 monitor_info_t
*mi
= NULL
;
44 if(!hd_probe_feature(hd_data
, pr_monitor
)) return;
46 hd_data
->module
= mod_monitor
;
49 remove_hd_entries(hd_data
);
51 PROGRESS(1, 0, "ddc");
53 for(hd
= hd_data
->hd
; hd
; hd
= hd
->next
) {
54 if(hd
->base_class
.id
== bc_internal
&& hd
->sub_class
.id
== sc_int_bios
) break;
57 /* first, see if we got the full edid record from bios */
61 /* for testing: LIBHD_EDID points to a file with valid edid record */
63 char *s
= getenv("LIBHD_EDID");
64 unsigned char edid
[0x80];
67 if(s
&& (f
= fopen(s
, "r"))) {
68 if(fread(edid
, sizeof edid
, 1, f
) == 1) {
69 hd
= add_hd_entry(hd_data
, __LINE__
, 0);
70 hd
->base_class
.id
= bc_monitor
;
71 add_edid_info(hd_data
, hd
, edid
);
82 hd
->detail
->type
== hd_detail_bios
&&
83 (bt
= hd
->detail
->bios
.data
) &&
86 if(chk_edid_info(hd_data
, bt
->vbe
.ddc
)) {
87 hd
= add_hd_entry(hd_data
, __LINE__
, 0);
88 hd
->base_class
.id
= bc_monitor
;
90 hd_set_hw_class(hd
, hw_vbe
);
92 add_edid_info(hd_data
, hd
, bt
->vbe
.ddc
);
98 /* Maybe a LCD panel? */
99 if(bt
&& bt
->lcd
.width
) {
100 hd
= add_hd_entry(hd_data
, __LINE__
, 0);
101 hd
->base_class
.id
= bc_monitor
;
102 hd
->sub_class
.id
= sc_mon_lcd
;
104 hd_set_hw_class(hd
, hw_vbe
);
106 add_lcd_info(hd_data
, hd
, bt
);
111 /* Maybe we have hidden edid info here? */
112 if(!(s
= s0
= t
= get_cmd_param(hd_data
, 0))) return; /* no :-( */
118 if(se
- s
< 7 + 2 * 4) {
123 /* Ok, we've got it. Now we split the fields. */
125 memcpy(m
, s
, 7); m
[7] = 0; s
+= 7;
127 hd
= add_hd_entry(hd_data
, __LINE__
, 0);
129 hd
->base_class
.id
= bc_monitor
;
130 hd
->vendor
.id
= name2eisa_id(m
);
131 if(sscanf(m
+ 3, "%x", &u
) == 1) hd
->device
.id
= MAKE_ID(TAG_EISA
, u
);
132 if((u
= device_class(hd_data
, hd
->vendor
.id
, hd
->device
.id
))) {
133 if((u
>> 8) == bc_monitor
) hd
->sub_class
.id
= u
& 0xff;
136 i
= hex(s
, 2); j
= hex(s
+ 2, 2); s
+= 4;
138 res
= add_res_entry(&hd
->res
, new_mem(sizeof *res
));
139 res
->size
.type
= res_size
;
140 res
->size
.unit
= size_unit_cm
;
141 res
->size
.val1
= i
; /* width */
142 res
->size
.val2
= j
; /* height */
145 i
= hex(s
, 2); s
+= 2;
146 if(i
& (1 << 7)) add_monitor_res(hd
, 720, 400, 70, 0);
147 if(i
& (1 << 6)) add_monitor_res(hd
, 720, 400, 88, 0);
148 if(i
& (1 << 5)) add_monitor_res(hd
, 640, 480, 60, 0);
149 if(i
& (1 << 4)) add_monitor_res(hd
, 640, 480, 67, 0);
150 if(i
& (1 << 3)) add_monitor_res(hd
, 640, 480, 72, 0);
151 if(i
& (1 << 2)) add_monitor_res(hd
, 640, 480, 75, 0);
152 if(i
& (1 << 1)) add_monitor_res(hd
, 800, 600, 56, 0);
153 if(i
& (1 << 0)) add_monitor_res(hd
, 800, 600, 60, 0);
155 i
= hex(s
, 2); s
+= 2;
156 if(i
& (1 << 7)) add_monitor_res(hd
, 800, 600, 72, 0);
157 if(i
& (1 << 6)) add_monitor_res(hd
, 800, 600, 75, 0);
158 if(i
& (1 << 5)) add_monitor_res(hd
, 832, 624, 75, 0);
159 if(i
& (1 << 4)) add_monitor_res(hd
, 1024, 768, 87, 1);
160 if(i
& (1 << 3)) add_monitor_res(hd
, 1024, 768, 60, 0);
161 if(i
& (1 << 2)) add_monitor_res(hd
, 1024, 768, 70, 0);
162 if(i
& (1 << 1)) add_monitor_res(hd
, 1024, 768, 75, 0);
163 if(i
& (1 << 0)) add_monitor_res(hd
, 1280, 1024, 75, 0);
165 if(((se
- s
) & 1) || se
- s
> 8 * 4 + 2) {
166 ADD2LOG(" ddc oops: %d bytes left?\n", (int) (se
- s
));
172 i
= (hex(s
, 2) + 31) * 8; j
= hex(s
+ 2, 2); s
+= 4;
174 switch((j
>> 6) & 3) {
175 case 1: k
= (i
* 3) / 4; break;
176 case 2: k
= (i
* 4) / 5; break;
177 case 3: k
= (i
* 9) / 16; break;
179 if(k
) add_monitor_res(hd
, i
, k
, (j
& 0x3f) + 60, 0);
183 if(se
- s
== 2) u
= hex(s
, 2) + 1990;
186 mi
= new_mem(sizeof *mi
);
187 if(u
) mi
->manu_year
= u
;
188 while((s
= strsep(&t
, "^"))) {
189 for(s1
= s
; *s1
++; ) if(*s1
== '_') *s1
= ' ';
192 if(!mi
->name
&& s
[1]) mi
->name
= canon_str(s
+ 1, strlen(s
+ 1));
199 if(i
> j
|| !i
) u
= 1;
204 if(i
> j
|| !i
) u
= 1;
212 mi
->min_vsync
= mi
->max_vsync
= mi
->min_hsync
= mi
->max_hsync
= 0;
213 ADD2LOG(" ddc oops: invalid freq data\n");
217 if(!mi
->vendor
&& s
[1]) mi
->vendor
= canon_str(s
+ 1, strlen(s
+ 1));
220 if(!mi
->serial
&& s
[1]) mi
->serial
= canon_str(s
+ 1, strlen(s
+ 1));
223 ADD2LOG(" ddc oops: invalid tag 0x%02x\n", *s
);
229 hd
->detail
= new_mem(sizeof *hd
->detail
);
230 hd
->detail
->type
= hd_detail_monitor
;
231 hd
->detail
->monitor
.data
= mi
;
233 hd
->serial
= new_str(mi
->serial
);
239 ID_VALUE(hd
->vendor
.id
) &&
240 !hd_vendor_name(hd_data
, hd
->vendor
.id
)
242 add_vendor_name(hd_data
, hd
->vend
, mi
->vendor
);
250 (ID_VALUE(hd
->vendor
.id
) || ID_VALUE(hd
->device
.id
)) &&
251 !hd_device_name(hd_data
, hd
->vend
, hd
->device
.id
)
253 add_device_name(hd_data
, hd
->vend
, hd
->dev
, mi
->name
);
258 ADD2LOG("----- DDC info -----\n");
260 ADD2LOG(" vendor: \"%s\"\n", mi
->vendor
);
263 ADD2LOG(" model: \"%s\"\n", mi
->name
);
266 ADD2LOG(" serial: \"%s\"\n", mi
->serial
);
269 ADD2LOG(" hsync: %u-%u kHz\n", mi
->min_hsync
, mi
->max_hsync
);
272 ADD2LOG(" vsync: %u-%u Hz\n", mi
->min_vsync
, mi
->max_vsync
);
275 ADD2LOG(" manu. year: %u\n", mi
->manu_year
);
277 ADD2LOG("----- DDC info end -----\n");
283 #endif /* !defined(__PPC__) */
286 void hd_scan_monitor(hd_data_t
*hd_data
)
291 if(!hd_probe_feature(hd_data
, pr_monitor
)) return;
293 hd_data
->module
= mod_monitor
;
296 remove_hd_entries(hd_data
);
298 PROGRESS(1, 0, "prom");
301 for(dt
= hd_data
->devtree
; dt
; dt
= dt
->next
) {
303 add_monitor(hd_data
, dt
);
309 add_old_mac_monitor(hd_data
);
313 void add_old_mac_monitor(hd_data_t
*hd_data
)
319 unsigned width
, height
, vfreq
, interlaced
;
334 { 1024, 768, 60, 0 },
335 { 1024, 768, 70, 0 },
336 { 1024, 768, 75, 0 },
337 { 1024, 768, 75, 0 },
338 { 1152, 870, 75, 0 },
339 { 1280, 960, 75, 0 },
340 { 1280, 1024, 75, 0 }
343 for(sl
= hd_data
->klog
; sl
; sl
= sl
->next
) {
344 if(sscanf(sl
->str
, "<%*d>Monitor sense value = %i, using video mode %i", &u1
, &u2
) == 2) {
346 hd
= add_hd_entry(hd_data
, __LINE__
, 0);
347 hd
->base_class
.id
= bc_monitor
;
349 hd
->vendor
.id
= MAKE_ID(TAG_SPECIAL
, 0x0401);
350 hd
->device
.id
= MAKE_ID(TAG_SPECIAL
, (u1
& 0xfff) + 0x1000);
352 if((u1
= hd_display_adapter(hd_data
))) {
353 hd
->attached_to
= u1
;
356 if(u2
< sizeof mode_list
/ sizeof *mode_list
) {
357 add_monitor_res(hd
, mode_list
[u2
].width
, mode_list
[u2
].height
, mode_list
[u2
].vfreq
, mode_list
[u2
].interlaced
);
366 void add_monitor(hd_data_t
*hd_data
, devtree_t
*dt
)
369 unsigned char *edid
= dt
->edid
;
371 if(!chk_edid_info(hd_data
, edid
)) return;
373 hd
= add_hd_entry(hd_data
, __LINE__
, 0);
375 hd
->base_class
.id
= bc_monitor
;
377 for(hd2
= hd_data
->hd
; hd2
; hd2
= hd2
->next
) {
380 hd2
->detail
->type
== hd_detail_devtree
&&
381 hd2
->detail
->devtree
.data
== dt
383 hd
->attached_to
= hd2
->idx
;
388 add_edid_info(hd_data
, hd
, edid
);
391 #endif /* defined(__PPC__) */
393 /* do some checks to ensure we got a reasonable block */
394 int chk_edid_info(hd_data_t
*hd_data
, unsigned char *edid
)
396 // no vendor or model info
397 if(!(edid
[0x08] || edid
[0x09] || edid
[0x0a] || edid
[0x0b])) return 0;
399 // no edid version or revision
400 if(!(edid
[0x12] || edid
[0x13])) return 0;
405 #if !defined(__PPC__)
406 void add_lcd_info(hd_data_t
*hd_data
, hd_t
*hd
, bios_info_t
*bt
)
408 monitor_info_t
*mi
= NULL
;
410 hd
->vendor
.name
= new_str(bt
->lcd
.vendor
);
411 hd
->device
.name
= new_str(bt
->lcd
.name
);
413 add_monitor_res(hd
, bt
->lcd
.width
, bt
->lcd
.height
, 60, 0);
415 mi
= new_mem(sizeof *mi
);
416 hd
->detail
= new_mem(sizeof *hd
->detail
);
417 hd
->detail
->type
= hd_detail_monitor
;
418 hd
->detail
->monitor
.data
= mi
;
423 mi
->max_hsync
= (mi
->max_vsync
* bt
->lcd
.height
* 12) / 10000;
427 void add_edid_info(hd_data_t
*hd_data
, hd_t
*hd
, unsigned char *edid
)
430 monitor_info_t
*mi
= NULL
;
434 fix_edid_info(hd_data
, edid
);
436 u
= (edid
[8] << 8) + edid
[9];
437 hd
->vendor
.id
= MAKE_ID(TAG_EISA
, u
);
438 u
= (edid
[0xb] << 8) + edid
[0xa];
439 hd
->device
.id
= MAKE_ID(TAG_EISA
, u
);
440 if((u
= device_class(hd_data
, hd
->vendor
.id
, hd
->device
.id
))) {
441 if((u
>> 8) == bc_monitor
) hd
->sub_class
.id
= u
& 0xff;
444 if(edid
[0x15] > 0 && edid
[0x16] > 0) {
445 res
= add_res_entry(&hd
->res
, new_mem(sizeof *res
));
446 res
->size
.type
= res_size
;
447 res
->size
.unit
= size_unit_cm
;
448 res
->size
.val1
= edid
[0x15]; /* width */
449 res
->size
.val2
= edid
[0x16]; /* height */
453 if(u
& (1 << 7)) add_monitor_res(hd
, 720, 400, 70, 0);
454 if(u
& (1 << 6)) add_monitor_res(hd
, 720, 400, 88, 0);
455 if(u
& (1 << 5)) add_monitor_res(hd
, 640, 480, 60, 0);
456 if(u
& (1 << 4)) add_monitor_res(hd
, 640, 480, 67, 0);
457 if(u
& (1 << 3)) add_monitor_res(hd
, 640, 480, 72, 0);
458 if(u
& (1 << 2)) add_monitor_res(hd
, 640, 480, 75, 0);
459 if(u
& (1 << 1)) add_monitor_res(hd
, 800, 600, 56, 0);
460 if(u
& (1 << 0)) add_monitor_res(hd
, 800, 600, 60, 0);
463 if(u
& (1 << 7)) add_monitor_res(hd
, 800, 600, 72, 0);
464 if(u
& (1 << 6)) add_monitor_res(hd
, 800, 600, 75, 0);
465 if(u
& (1 << 5)) add_monitor_res(hd
, 832, 624, 75, 0);
466 if(u
& (1 << 4)) add_monitor_res(hd
, 1024, 768, 87, 1);
467 if(u
& (1 << 3)) add_monitor_res(hd
, 1024, 768, 60, 0);
468 if(u
& (1 << 2)) add_monitor_res(hd
, 1024, 768, 70, 0);
469 if(u
& (1 << 1)) add_monitor_res(hd
, 1024, 768, 75, 0);
470 if(u
& (1 << 0)) add_monitor_res(hd
, 1280, 1024, 75, 0);
472 for(i
= 0; i
< 4; i
++) {
473 u1
= (edid
[0x26 + 2 * i
] + 31) * 8;
474 u2
= edid
[0x27 + 2 * i
];
476 switch((u2
>> 6) & 3) {
477 case 1: u
= (u1
* 3) / 4; break;
478 case 2: u
= (u1
* 4) / 5; break;
479 case 3: u
= (u1
* 9) / 16; break;
481 if(u
) add_monitor_res(hd
, u1
, u
, (u2
& 0x3f) + 60, 0);
484 mi
= new_mem(sizeof *mi
);
485 mi
->manu_year
= 1990 + edid
[0x11];
487 for(i
= 0x36; i
< 0x36 + 4 * 0x12; i
+= 0x12) {
488 if(!(edid
[i
] || edid
[i
+ 1] || edid
[i
+ 2])) {
489 switch(edid
[i
+ 3]) {
492 /* the name entry is splitted some times */
493 str_printf(&mi
->name
, -1, "%s%s", mi
->name
? " " : "", canon_str(edid
+ i
+ 5, 0xd));
501 if(u1
> u2
|| !u1
) u
= 1;
506 if(u1
> u2
|| !u1
) u
= 1;
510 mi
->min_vsync
= mi
->max_vsync
= mi
->min_hsync
= mi
->max_hsync
= 0;
511 ADD2LOG(" ddc oops: invalid freq data\n");
516 if(!mi
->vendor
&& edid
[i
+ 5]) mi
->vendor
= canon_str(edid
+ i
+ 5, 0xd);
520 if(!mi
->serial
&& edid
[i
+ 5]) mi
->serial
= canon_str(edid
+ i
+ 5, 0xd);
524 ADD2LOG(" ddc oops: invalid tag 0x%02x\n", edid
[i
+ 3]);
530 hd
->detail
= new_mem(sizeof *hd
->detail
);
531 hd
->detail
->type
= hd_detail_monitor
;
532 hd
->detail
->monitor
.data
= mi
;
534 hd
->serial
= new_str(mi
->serial
);
535 hd
->vendor
.name
= new_str(mi
->vendor
);
536 hd
->device
.name
= new_str(mi
->name
);
539 ADD2LOG("----- DDC info -----\n");
541 ADD2LOG(" vendor: \"%s\"\n", mi
->vendor
);
544 ADD2LOG(" model: \"%s\"\n", mi
->name
);
547 ADD2LOG(" serial: \"%s\"\n", mi
->serial
);
550 ADD2LOG(" hsync: %u-%u kHz\n", mi
->min_hsync
, mi
->max_hsync
);
553 ADD2LOG(" vsync: %u-%u Hz\n", mi
->min_vsync
, mi
->max_vsync
);
556 ADD2LOG(" manu. year: %u\n", mi
->manu_year
);
558 ADD2LOG("----- DDC info end -----\n");
563 void add_monitor_res(hd_t
*hd
, unsigned width
, unsigned height
, unsigned vfreq
, unsigned il
)
567 res
= add_res_entry(&hd
->res
, new_mem(sizeof *res
));
568 res
->monitor
.type
= res_monitor
;
569 res
->monitor
.width
= width
;
570 res
->monitor
.height
= height
;
571 res
->monitor
.vfreq
= vfreq
;
572 res
->monitor
.interlaced
= il
;
576 * This looks evil, but some Mac displays really lie at us.
578 void fix_edid_info(hd_data_t
*hd_data
, unsigned char *edid
)
584 vend
= (edid
[8] << 8) + edid
[9];
585 dev
= (edid
[0xb] << 8) + edid
[0xa];
587 timing
= (edid
[0x24] << 8) + edid
[0x23];
589 /* APP9214: Apple Studio Display */
590 if(vend
== 0x0610 && dev
== 0x9214 && timing
== 0x0800) {
596 edid
[0x23] = timing
& 0xff;
597 edid
[0x24] = (timing
>> 8) & 0xff;