]>
git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/hwinfo/src/hd/bios.c
9 #if defined(__i386__) || defined (__x86_64__) || defined(__ia64__)
12 typedef unsigned long kernel_ulong_t
;
13 #include <linux/types.h>
15 #include <linux/pci.h>
26 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
29 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
32 #if defined(__i386__) || defined (__x86_64__) || defined (__ia64__)
41 { 800, 600, "Fujitsu Siemens", "LiteLine", "LF6" },
42 { 1024, 768, "ASUSTEK", "L2000D", NULL
},
43 { 1024, 768, "ASUSTeK Computer Inc.", "L8400C series Notebook PC", NULL
},
44 { 1024, 768, "ASUSTeK Computer Inc.", "S5N", NULL
},
45 { 1024, 768, "Acer", "TravelMate 720", NULL
},
46 { 1024, 768, "COMPAL", "N30T5", NULL
},
47 { 1024, 768, "Dell Computer Corporation", "Inspiron 5000", NULL
},
48 { 1024, 768, "Dell Computer Corporation", "Latitude C400", NULL
},
49 { 1024, 768, "Dell Computer Corporation", "Latitude C600", NULL
},
50 { 1024, 768, "Dell Computer Corporation", "Latitude CPt C400GT", NULL
},
51 { 1024, 768, "Hewlett-Packard", "HP OmniBook PC", "HP OmniBook 4150 B" },
52 { 1280, 800, "Hewlett-Packard", "hp compaq nx9105 (DU367T#ABD)", "03" },
53 { 1280, 800, "Hewlett-Packard", "Pavilion zv5000 (PA456EA#ABD)", "F.11" },
54 #include "ibm-notebooks.h"
55 { 1400, 1050, "IBM", "73geu99", NULL
},
56 { 1024, 768, "KDST", "KDS6KSUMO", NULL
},
57 { 1024, 768, "Sony Corporation", "PCG-F370(UC)", NULL
},
58 { 1024, 768, "Sony Corporation", "PCG-N505SN", NULL
},
59 { 1024, 768, "TOSHIBA", "S2400-103", NULL
},
60 { 1280, 800, "Acer", "Aspire 1520", NULL
},
61 { 1400, 1050, "Acer", "TravelMate 660", NULL
},
62 { 1400, 1050, "Dell Computer Corporation", "Inspiron 8000", NULL
},
63 { 1600, 1200, "Dell Computer Corporation", "Inspiron 8200", NULL
},
64 { 1600, 1200, "Dell Computer Corporation", "Latitude C840", NULL
}
70 unsigned eax
, ebx
, ecx
, edx
, esi
, edi
, eip
, es
, iret
, cli
;
73 static void read_memory(hd_data_t
*hd_data
, memory_range_t
*mem
);
74 static void dump_memory(hd_data_t
*hd_data
, memory_range_t
*mem
, int sparse
, char *label
);
75 static void get_pnp_support_status(memory_range_t
*mem
, bios_info_t
*bt
);
76 static void smbios_get_info(hd_data_t
*hd_data
, memory_range_t
*mem
, bios_info_t
*bt
);
77 static void get_fsc_info(hd_data_t
*hd_data
, memory_range_t
*mem
, bios_info_t
*bt
);
78 static void add_panel_info(hd_data_t
*hd_data
, bios_info_t
*bt
);
79 static void add_mouse_info(hd_data_t
*hd_data
, bios_info_t
*bt
);
80 static unsigned char crc(unsigned char *mem
, unsigned len
);
81 static int get_smp_info(hd_data_t
*hd_data
, memory_range_t
*mem
, smp_info_t
*smp
);
82 static void parse_mpconfig(hd_data_t
*hd_data
, memory_range_t
*mem
, smp_info_t
*smp
);
83 static int get_bios32_info(hd_data_t
*hd_data
, memory_range_t
*mem
, bios32_info_t
*bios32
);
85 int detect_smp_bios(hd_data_t
*hd_data
)
92 if(!hd_data
->bios_ram
.data
) return -1; /* hd_scan_bios() not called */
94 for(bt
= NULL
, hd
= hd_data
->hd
; hd
; hd
= hd
->next
) {
96 hd
->base_class
.id
== bc_internal
&&
97 hd
->sub_class
.id
== sc_int_bios
&&
99 hd
->detail
->type
== hd_detail_bios
&&
100 (bt
= hd
->detail
->bios
.data
)
110 /* look at smbios data in case there's no mp table */
111 if(hd_data
->smbios
) {
112 for(sm
= hd_data
->smbios
; sm
; sm
= sm
->next
) {
114 sm
->any
.type
== sm_processor
&&
115 sm
->processor
.pr_type
.id
== 3 && /* cpu */
116 sm
->processor
.cpu_status
.id
== 1 /* enabled */
121 ADD2LOG(" smp detect: mp %d cpus, smbios %d cpus\n", bt
->smp
.ok
? bt
->smp
.cpus_en
: 0, cpus
);
124 if(bt
->smp
.ok
&& bt
->smp
.cpus_en
) cpus
= bt
->smp
.cpus_en
;
130 void hd_scan_bios(hd_data_t
*hd_data
)
135 unsigned char *bios_ram
;
146 if(!hd_probe_feature(hd_data
, pr_bios
)) return;
148 /* we better do nothing on a SGI Altix machine */
149 if(hd_is_sgi_altix(hd_data
)) return;
151 hd_data
->module
= mod_bios
;
154 remove_hd_entries(hd_data
);
156 PROGRESS(1, 0, "cmdline");
158 hd
= add_hd_entry(hd_data
, __LINE__
, 0);
159 hd
->base_class
.id
= bc_internal
;
160 hd
->sub_class
.id
= sc_int_bios
;
161 hd
->detail
= new_mem(sizeof *hd
->detail
);
162 hd
->detail
->type
= hd_detail_bios
;
163 hd
->detail
->bios
.data
= bt
= new_mem(sizeof *bt
);
166 * first, look for APM support
168 if((s
= get_cmd_param(hd_data
, 1))) {
169 if(strlen(s
) >= 10) {
170 bt
->apm_supported
= 1;
171 bt
->apm_ver
= hex(s
, 1);
172 bt
->apm_subver
= hex(s
+ 1, 1);
173 bt
->apm_bios_flags
= hex(s
+ 2, 2);
175 * Bitfields for APM flags (from Ralf Brown's list):
177 * 0 16-bit protected mode interface supported
178 * 1 32-bit protected mode interface supported
179 * 2 CPU idle call reduces processor speed
180 * 3 BIOS power management disabled
181 * 4 BIOS power management disengaged (APM v1.1)
184 bt
->apm_enabled
= (bt
->apm_bios_flags
& 8) ? 0 : 1;
186 bt
->vbe_ver
= hex(s
+ 4, 2);
187 bt
->vbe_ver
= (((bt
->vbe_ver
>> 4) & 0xf) << 8) + (bt
->vbe_ver
& 0xf);
188 bt
->vbe_video_mem
= hex(s
+ 6, 4) << 16;
194 if((s
= get_cmd_param(hd_data
, 2))) {
196 if(s
[8] == '.') bt
->lba_support
= 1;
202 PROGRESS(1, 1, "apm");
205 str_list_t
*sl0
, *sl
;
207 sl0
= read_file(PROC_APM
, 0, 0);
209 bt
->apm_supported
= 1;
211 ADD2LOG("----- %s -----\n", PROC_APM
);
212 for(sl
= sl0
; sl
; sl
= sl
->next
) {
213 ADD2LOG(" %s", sl
->str
);
215 ADD2LOG("----- %s end -----\n", PROC_APM
);
221 * get the i/o ports for the parallel & serial interfaces from the BIOS
222 * memory area starting at 0x40:0
224 PROGRESS(2, 0, "ram");
226 hd_data
->bios_ram
.start
= BIOS_RAM_START
;
227 hd_data
->bios_ram
.size
= BIOS_RAM_SIZE
;
228 read_memory(hd_data
, &hd_data
->bios_ram
);
230 hd_data
->bios_rom
.start
= BIOS_ROM_START
;
231 hd_data
->bios_rom
.size
= BIOS_ROM_SIZE
;
232 read_memory(hd_data
, &hd_data
->bios_rom
);
234 if(hd_data
->bios_ram
.data
) {
235 bios_ram
= hd_data
->bios_ram
.data
;
237 bt
->ser_port0
= (bios_ram
[1] << 8) + bios_ram
[0];
238 bt
->ser_port1
= (bios_ram
[3] << 8) + bios_ram
[2];
239 bt
->ser_port2
= (bios_ram
[5] << 8) + bios_ram
[4];
240 bt
->ser_port3
= (bios_ram
[7] << 8) + bios_ram
[6];
242 bt
->par_port0
= (bios_ram
[ 9] << 8) + bios_ram
[ 8];
243 bt
->par_port1
= (bios_ram
[0xb] << 8) + bios_ram
[0xa];
244 bt
->par_port2
= (bios_ram
[0xd] << 8) + bios_ram
[0xc];
246 bt
->led
.scroll_lock
= bios_ram
[0x97] & 1;
247 bt
->led
.num_lock
= (bios_ram
[0x97] >> 1) & 1;
248 bt
->led
.caps_lock
= (bios_ram
[0x97] >> 2) & 1;
252 * do some consistency checks:
254 * ports must be < 0x1000 and not appear twice
256 if(bt
->ser_port0
>= 0x1000) bt
->ser_port0
= 0;
259 bt
->ser_port1
>= 0x1000 ||
260 bt
->ser_port1
== bt
->ser_port0
264 bt
->ser_port2
>= 0x1000 ||
265 bt
->ser_port2
== bt
->ser_port0
||
266 bt
->ser_port2
== bt
->ser_port1
270 bt
->ser_port3
>= 0x1000 ||
271 bt
->ser_port3
== bt
->ser_port0
||
272 bt
->ser_port3
== bt
->ser_port1
||
273 bt
->ser_port3
== bt
->ser_port2
276 if(bt
->par_port0
>= 0x1000) bt
->par_port0
= 0;
279 bt
->par_port1
>= 0x1000 ||
280 bt
->par_port1
== bt
->par_port0
284 bt
->par_port2
>= 0x1000 ||
285 bt
->par_port2
== bt
->par_port0
||
286 bt
->par_port2
== bt
->par_port1
289 ADD2LOG(" bios: %u disks\n", bios_ram
[0x75]);
291 bt
->low_mem_size
= ((bios_ram
[0x14] << 8) + bios_ram
[0x13]) << 10;
293 if(bt
->low_mem_size
) {
294 ADD2LOG(" bios: %uk low mem\n", bt
->low_mem_size
>> 10);
298 if(bt
->low_mem_size
>= (768 << 10) || bt
->low_mem_size
< (384 << 10)) {
299 bt
->low_mem_size
= 0;
302 hd_data
->bios_ebda
.start
= hd_data
->bios_ebda
.size
= 0;
303 hd_data
->bios_ebda
.data
= free_mem(hd_data
->bios_ebda
.data
);
304 u
= ((bios_ram
[0x0f] << 8) + bios_ram
[0x0e]) << 4;
306 hd_data
->bios_ebda
.start
= u
;
307 hd_data
->bios_ebda
.size
= 1; /* just one byte */
308 read_memory(hd_data
, &hd_data
->bios_ebda
);
309 if(hd_data
->bios_ebda
.data
) {
310 u1
= hd_data
->bios_ebda
.data
[0];
311 if(u1
> 0 && u1
<= 64) { /* be sensible, typically only 1k */
313 if(u
+ u1
<= (1 << 20)) {
314 hd_data
->bios_ebda
.size
= u1
;
315 read_memory(hd_data
, &hd_data
->bios_ebda
);
321 if(hd_data
->bios_ebda
.data
) {
323 " bios: EBDA 0x%05x bytes at 0x%05x\n",
324 hd_data
->bios_ebda
.size
, hd_data
->bios_ebda
.start
330 * read the bios rom and look for useful things there...
332 PROGRESS(2, 0, "rom");
334 if(hd_data
->bios_rom
.data
) {
335 get_pnp_support_status(&hd_data
->bios_rom
, bt
);
336 smbios_get_info(hd_data
, &hd_data
->bios_rom
, bt
);
337 get_fsc_info(hd_data
, &hd_data
->bios_rom
, bt
);
338 add_panel_info(hd_data
, bt
);
339 add_mouse_info(hd_data
, bt
);
342 PROGRESS(3, 0, "smp");
346 mem
= hd_data
->bios_ebda
;
347 smp_ok
= get_smp_info(hd_data
, &mem
, &bt
->smp
);
350 mem
= hd_data
->bios_rom
;
352 mem
.size
-= 0xf0000 - mem
.start
;
353 mem
.data
+= 0xf0000 - mem
.start
;
355 if(mem
.size
< (1 << 20)) smp_ok
= get_smp_info(hd_data
, &mem
, &bt
->smp
);
361 mem
.start
= 639 << 10;
363 read_memory(hd_data
, &mem
);
364 if(mem
.data
) smp_ok
= get_smp_info(hd_data
, &mem
, &bt
->smp
);
365 mem
.data
= free_mem(mem
.data
);
368 if(bt
->smp
.ok
&& bt
->smp
.mpconfig
) {
369 mem
.start
= bt
->smp
.mpconfig
;
372 read_memory(hd_data
, &mem
);
373 parse_mpconfig(hd_data
, &mem
, &bt
->smp
);
374 mem
.data
= free_mem(mem
.data
);
377 if((hd_data
->debug
& HD_DEB_BIOS
)) {
378 dump_memory(hd_data
, &hd_data
->bios_ram
, 0, "BIOS data");
379 dump_memory(hd_data
, &hd_data
->bios_ebda
, hd_data
->bios_ebda
.size
<= (8 << 10) ? 0 : 1, "EBDA");
380 // dump_memory(hd_data, &hd_data->bios_rom, 1, "BIOS ROM");
382 if(bt
->smp
.ok
&& bt
->smp
.mpfp
) {
383 mem
.start
= bt
->smp
.mpfp
;
386 read_memory(hd_data
, &mem
);
387 dump_memory(hd_data
, &mem
, 0, "MP FP");
388 mem
.data
= free_mem(mem
.data
);
391 if(bt
->smp
.ok
&& bt
->smp
.mpconfig
&& bt
->smp
.mpconfig_size
) {
392 mem
.start
= bt
->smp
.mpconfig
;
393 mem
.size
= bt
->smp
.mpconfig_size
;
395 read_memory(hd_data
, &mem
);
396 dump_memory(hd_data
, &mem
, 0, "MP config table");
397 mem
.data
= free_mem(mem
.data
);
402 if(hd_probe_feature(hd_data
, pr_bios_vesa
)) {
403 PROGRESS(4, 0, "vbe");
408 if(!hd_data
->klog
) read_klog(hd_data
);
409 for(sl
= hd_data
->klog
; sl
; sl
= sl
->next
) {
410 if(sscanf(sl
->str
, "<6>PCI: Using configuration type %u", &u
) == 1) {
411 hd_data
->pci_config_type
= u
;
412 ADD2LOG(" klog: pci config type %u\n", hd_data
->pci_config_type
);
416 get_vbe_info(hd_data
, vbe
);
419 bt
->vbe_ver
= vbe
->version
;
422 if(vbe
->ok
&& vbe
->fb_start
) {
423 hd
= add_hd_entry(hd_data
, __LINE__
, 0);
424 hd
->base_class
.id
= bc_framebuffer
;
425 hd
->sub_class
.id
= sc_fb_vesa
;
427 hd_set_hw_class(hd
, hw_vbe
);
430 hd
->detail
= new_mem(sizeof *hd
->detail
);
431 hd
->detail
->type
= hd_detail_bios
;
432 hd
->detail
->bios
.data
= bt
= new_mem(sizeof *bt
);
435 hd
->vendor
.name
= new_str(vbe
->vendor_name
);
436 hd
->device
.name
= new_str(vbe
->product_name
);
437 hd
->sub_vendor
.name
= new_str(vbe
->oem_name
);
438 hd
->revision
.name
= new_str(vbe
->product_revision
);
440 res
= add_res_entry(&hd
->res
, new_mem(sizeof *res
));
441 res
->phys_mem
.type
= res_phys_mem
;
442 res
->phys_mem
.range
= vbe
->memory
;
444 res
= add_res_entry(&hd
->res
, new_mem(sizeof *res
));
445 res
->mem
.type
= res_mem
;
446 res
->mem
.base
= vbe
->fb_start
;
447 res
->mem
.range
= vbe
->memory
;
448 res
->mem
.access
= acc_rw
;
449 res
->mem
.enabled
= 1;
452 for(u
= 0; u
< vbe
->modes
; u
++) {
455 (mi
->attributes
& 1) && /* mode supported */
457 mi
->pixel_size
!= -1u /* text mode */
459 res
= add_res_entry(&hd
->res
, new_mem(sizeof *res
));
460 res
->framebuffer
.type
= res_framebuffer
;
461 res
->framebuffer
.width
= mi
->width
;
462 res
->framebuffer
.bytes_p_line
= mi
->bytes_p_line
;
463 res
->framebuffer
.height
= mi
->height
;
464 res
->framebuffer
.colorbits
= mi
->pixel_size
;
465 res
->framebuffer
.mode
= mi
->number
+ 0x200;
473 !strcmp(hd
->vend_name
, "Matrox") &&
476 strstr(hd
->dev_name
, "G200") ||
477 strstr(hd
->dev_name
, "G400") ||
478 strstr(hd
->dev_name
, "G450")
487 #endif /* LIBHD_TINY */
489 PROGRESS(5, 0, "32");
491 mem
= hd_data
->bios_rom
;
493 mem
.size
-= 0xe0000 - mem
.start
;
494 mem
.data
+= 0xe0000 - mem
.start
;
496 if(mem
.size
< (1 << 20)) get_bios32_info(hd_data
, &mem
, &bt
->bios32
);
500 mem
= hd_data
->bios_rom
;
503 mem
.start
<= 0xfffea &&
504 mem
.start
+ mem
.size
>= 0xfffea + 6 &&
505 !memcmp(mem
.data
+ 0xfffea - mem
.start
, "COMPAQ", 6)
507 bt
->bios32
.compaq
= 1;
508 ADD2LOG(" bios32: compaq machine\n");
515 void read_memory(hd_data_t
*hd_data
, memory_range_t
*mem
)
518 char *s
= getenv("LIBHD_MEM");
521 #ifdef LIBHD_MEMCHECK
523 if(libhd_log
) fprintf(libhd_log
, ">%p\n", CALLED_FROM(read_memory
, mem
));
527 if(mem
->data
) free_mem(mem
->data
);
528 mem
->data
= new_mem(mem
->size
);
530 hd_read_mmap(hd_data
, s
?: DEV_MEM
, mem
->data
, mem
->start
, mem
->size
);
532 hd_read_mmap(hd_data
, DEV_MEM
, mem
->data
, mem
->start
, mem
->size
);
535 #ifdef LIBHD_MEMCHECK
537 if(libhd_log
) fprintf(libhd_log
, "<%p\n", CALLED_FROM(read_memory
, mem
));
543 void dump_memory(hd_data_t
*hd_data
, memory_range_t
*mem
, int sparse
, char *label
)
547 if(!mem
->size
|| !mem
->data
) return;
550 step
= sparse
? 0x1000 : 0x10;
555 ADD2LOG("----- %s 0x%05x - 0x%05x -----\n", label
, mem
->start
, mem
->start
+ mem
->size
- 1);
556 for(u
= 0; u
< mem
->size
; u
+= step
) {
557 ADD2LOG(" %03x ", u
+ mem
->start
);
558 hexdump(&hd_data
->log
, 1, mem
->size
- u
> 0x10 ? 0x10 : mem
->size
- u
, mem
->data
+ u
);
561 ADD2LOG("----- %s end -----\n", label
);
565 void get_pnp_support_status(memory_range_t
*mem
, bios_info_t
*bt
)
568 unsigned char pnp
[4] = { '$', 'P', 'n', 'P' };
572 if(!mem
->data
) return;
574 for(i
= 0xf0000 - mem
->start
; (unsigned) i
< mem
->size
; i
+= 0x10) {
576 if(t
[0] == pnp
[0] && t
[1] == pnp
[1] && t
[2] == pnp
[2] && t
[3] == pnp
[3]) {
577 for(l
= cs
= 0; l
< t
[5]; l
++) { cs
+= t
[l
]; }
578 if((cs
& 0xff) == 0) { // checksum ok
580 // printf("0x%x bytes at 0x%x, cs = 0x%x\n", t[5], i, cs);
581 bt
->pnp_id
= t
[0x17] + (t
[0x18] << 8) + (t
[0x19] << 16) + (t
[0x20] << 24);
587 unsigned char crc(unsigned char *mem
, unsigned len
)
589 unsigned char uc
= 0;
591 while(len
--) uc
+= *mem
++;
597 void smbios_get_info(hd_data_t
*hd_data
, memory_range_t
*mem
, bios_info_t
*bt
)
599 unsigned u
, u1
, u2
, ok
, hlen
= 0, ofs
;
600 unsigned addr
= 0, len
= 0, scnt
;
601 unsigned structs
= 0, type
, slen
;
603 memory_range_t memory
;
606 if(!mem
->data
|| mem
->size
< 0x100) return;
608 for(u
= ok
= 0; u
<= mem
->size
- 0x100; u
+= 0x10) {
609 if(*(unsigned *) (mem
->data
+ u
) == 0x5f4d535f) { /* "_SM_" */
610 hlen
= mem
->data
[u
+ 5];
611 addr
= *(unsigned *) (mem
->data
+ u
+ 0x18);
612 len
= *(unsigned short *) (mem
->data
+ u
+ 0x16);
613 structs
= *(unsigned short *) (mem
->data
+ u
+ 0x1c);
614 if(hlen
< 0x1e) continue;
615 ok
= crc(mem
->data
+ u
, hlen
) == 0 && addr
< (1 << 20) && len
;
622 bt
->smbios_ver
= (mem
->data
[u
+ 6] << 8) + mem
->data
[u
+ 7];
624 hd_data
->smbios
= smbios_free(hd_data
->smbios
);
626 memory
.start
= mem
->start
+ u
;
628 memory
.data
= mem
->data
+ u
;
629 dump_memory(hd_data
, &memory
, 0, "SMBIOS Entry Point");
634 read_memory(hd_data
, &memory
);
637 " SMBIOS Structure Table at 0x%05x (size 0x%x)\n",
642 dump_memory(hd_data
, &memory
, 0, "SMBIOS Structure Table");
645 for(type
= 0, u
= 0, ofs
= 0; u
< structs
&& ofs
+ 3 < len
; u
++) {
646 type
= memory
.data
[ofs
];
647 slen
= memory
.data
[ofs
+ 1];
648 if(ofs
+ slen
> len
|| slen
< 4) break;
649 sm
= smbios_add_entry(&hd_data
->smbios
, new_mem(sizeof *sm
));
651 sm
->any
.data_len
= slen
;
652 sm
->any
.data
= new_mem(slen
);
653 memcpy(sm
->any
.data
, memory
.data
+ ofs
, slen
);
654 sm
->any
.handle
= memory
.data
[ofs
+ 2] + (memory
.data
[ofs
+ 3] << 8);
655 ADD2LOG(" type 0x%02x [0x%04x]: ", type
, sm
->any
.handle
);
656 if(slen
) hexdump(&hd_data
->log
, 0, slen
, sm
->any
.data
);
658 if(type
== sm_end
) break;
663 while(ofs
+ 1 < len
) {
664 if(!memory
.data
[ofs
]) {
666 s
= canon_str(memory
.data
+ u1
, strlen(memory
.data
+ u1
));
667 add_str_list(&sm
->any
.strings
, s
);
669 if(*s
) ADD2LOG(" str%d: \"%s\"\n", scnt
, s
);
674 if(!memory
.data
[ofs
+ 1]) {
685 ADD2LOG(" smbios: stopped at end tag\n");
688 ADD2LOG(" smbios oops: only %d of %d structs found\n", u
, structs
);
692 memory
.data
= free_mem(memory
.data
);
694 smbios_parse(hd_data
);
698 void get_fsc_info(hd_data_t
*hd_data
, memory_range_t
*mem
, bios_info_t
*bt
)
700 unsigned u
, mtype
, fsc_id
;
705 if(!mem
->data
|| mem
->size
< 0x20) return;
707 for(sm
= hd_data
->smbios
; sm
; sm
= sm
->next
) {
708 if(sm
->any
.type
== sm_sysinfo
) {
709 vendor
= sm
->sysinfo
.manuf
;
714 vendor
= vendor
&& !strcasecmp(vendor
, "Fujitsu") ? "Fujitsu" : "Fujitsu Siemens";
716 for(u
= 0; u
<= mem
->size
- 0x20; u
+= 0x10) {
718 *(unsigned *) (mem
->data
+ u
) == 0x696a7546 &&
719 *(unsigned *) (mem
->data
+ u
+ 4) == 0x20757374
721 mtype
= *(unsigned *) (mem
->data
+ u
+ 0x14);
722 if(!crc(mem
->data
+ u
, 0x20) && !(mtype
& 0xf0000000)) {
723 fsc_id
= (mtype
>> 12) & 0xf;
763 bt
->lcd
.vendor
= new_str(vendor
);
764 bt
->lcd
.name
= new_str("Notebook LCD");
769 ADD2LOG(" found FSC LCD: %d (%ux%u)\n", fsc_id
, x
, y
);
777 void add_panel_info(hd_data_t
*hd_data
, bios_info_t
*bt
)
779 unsigned width
, height
;
780 char *vendor
, *name
, *version
;
784 if(bt
->lcd
.width
|| !hd_data
->smbios
) return;
786 vendor
= name
= version
= NULL
;
789 for(sm
= hd_data
->smbios
; sm
; sm
= sm
->next
) {
790 if(sm
->any
.type
== sm_sysinfo
) {
791 vendor
= sm
->sysinfo
.manuf
;
792 name
= sm
->sysinfo
.product
;
793 version
= sm
->sysinfo
.version
;
798 if(!vendor
|| !name
) return;
800 for(u
= 0; u
< sizeof panel_data
/ sizeof *panel_data
; u
++) {
802 !strcmp(vendor
, panel_data
[u
].vendor
) &&
803 !strcmp(name
, panel_data
[u
].name
) &&
804 (version
|| !panel_data
[u
].version
) &&
805 (!version
|| !panel_data
[u
].version
|| !strcmp(version
, panel_data
[u
].version
))
807 bt
->lcd
.vendor
= new_str(vendor
);
808 bt
->lcd
.name
= new_str("Notebook LCD");
809 bt
->lcd
.width
= panel_data
[u
].width
;
810 bt
->lcd
.height
= panel_data
[u
].height
;
817 void add_mouse_info(hd_data_t
*hd_data
, bios_info_t
*bt
)
819 unsigned compat_vend
, compat_dev
, bus
;
820 char *vendor
, *name
, *type
;
823 if(bt
->mouse
.compat_vend
|| !hd_data
->smbios
) return;
825 vendor
= name
= type
= NULL
;
826 compat_vend
= compat_dev
= bus
= 0;
828 for(sm
= hd_data
->smbios
; sm
; sm
= sm
->next
) {
829 if(sm
->any
.type
== sm_sysinfo
) {
830 vendor
= sm
->sysinfo
.manuf
;
831 name
= sm
->sysinfo
.product
;
834 sm
->any
.type
== sm_mouse
&&
835 !compat_vend
/* take the first entry */
837 compat_vend
= compat_dev
= bus
= 0;
840 switch(sm
->mouse
.interface
.id
) {
842 case 7: /* bus mouse (dell notebooks report this) */
844 compat_vend
= MAKE_ID(TAG_SPECIAL
, 0x0200);
845 compat_dev
= MAKE_ID(TAG_SPECIAL
, sm
->mouse
.buttons
== 3 ? 0x0007 : 0x0006);
848 type
= sm
->mouse
.mtype
.name
;
849 if(sm
->mouse
.mtype
.id
== 1) type
= "Touch Pad"; /* Why??? */
850 if(sm
->mouse
.mtype
.id
== 2) type
= NULL
; /* "Other" */
854 if(!vendor
|| !name
) return;
857 if(!strcmp(vendor
, "Sony Corporation") && strstr(name
, "PCG-") == name
) {
860 compat_vend
= MAKE_ID(TAG_SPECIAL
, 0x0200);
861 compat_dev
= MAKE_ID(TAG_SPECIAL
, 0x0006);
867 bt
->mouse
.vendor
= new_str(vendor
);
868 bt
->mouse
.type
= new_str(type
);
870 bt
->mouse
.compat_vend
= compat_vend
;
871 bt
->mouse
.compat_dev
= compat_dev
;
875 int get_smp_info(hd_data_t
*hd_data
, memory_range_t
*mem
, smp_info_t
*smp
)
879 unsigned addr
= 0, len
;
881 if(mem
->size
< 0x10) return 0;
883 for(u
= ok
= 0; u
<= mem
->size
- 0x10; u
++) {
884 if(*(unsigned *) (mem
->data
+ u
) == 0x5f504d5f) { /* "_MP_" */
885 addr
= *(unsigned *) (mem
->data
+ u
+ 4);
886 len
= mem
->data
[u
+ 8];
887 ok
= len
== 1 && crc(mem
->data
+ u
, 0x10) == 0 && addr
< (1 << 20) ? 1 : 0;
889 " smp: %svalid MP FP at 0x%05x (size 0x%x, rev %u), MP config at 0x%05x\n",
890 ok
? "" : "in", u
+ mem
->start
, len
<< 4, mem
->data
[u
+ 9], addr
898 smp
->mpfp
= mem
->start
+ u
;
899 smp
->rev
= mem
->data
[u
+ 9];
900 smp
->mpconfig
= addr
;
901 memcpy(smp
->feature
, mem
->data
+ u
+ 11, 5);
911 void parse_mpconfig(hd_data_t
*hd_data
, memory_range_t
*mem
, smp_info_t
*smp
)
913 unsigned cfg_len
, xcfg_len
;
914 unsigned char u0
, ux0
;
915 unsigned u
, type
, len
, entries
, entry_cnt
;
918 cfg_len
= xcfg_len
= 0;
920 if(*(unsigned *) (mem
->data
) == 0x504d4350) { /* "PCMP" */
921 cfg_len
= mem
->data
[0x04] + (mem
->data
[0x05] << 8);
922 smp
->mpconfig_size
= cfg_len
;
923 u0
= crc(mem
->data
, cfg_len
);
925 smp
->mpconfig_ok
= 1;
926 smp
->cpus
= smp
->cpus_en
= 0;
927 xcfg_len
= mem
->data
[0x28] + (mem
->data
[0x29] << 8);
928 ux0
= crc(mem
->data
+ cfg_len
, xcfg_len
) + mem
->data
[0x2a];
930 smp
->mpconfig_size
+= xcfg_len
;
938 s
= canon_str(mem
->data
+ 8, 8);
939 strcpy(smp
->oem_id
, s
);
941 s
= canon_str(mem
->data
+ 0x10, 12);
942 strcpy(smp
->prod_id
, s
);
945 entries
= mem
->data
[0x22] + (mem
->data
[0x23] << 8);
946 ADD2LOG(" base MP config table (%u entries):\n", entries
);
948 for(u
= 0x2c; u
< cfg_len
- 1; u
+= len
, entry_cnt
++) {
950 len
= type
== 0 ? 20 : type
<= 4 ? 8 : 16;
951 ADD2LOG(" %stype %u, len %u\n ", type
> 4 ? "unknown ": "", type
, len
);
952 if(len
+ u
> cfg_len
) len
= cfg_len
- u
;
953 hexdump(&hd_data
->log
, 1, len
, mem
->data
+ u
);
958 if((mem
->data
[u
+ 3] & 1)) smp
->cpus_en
++;
961 if(entry_cnt
!= entries
) {
962 ADD2LOG(" oops: %u entries instead of %u found\n", entry_cnt
, entries
);
967 ADD2LOG(" extended MP config table:\n");
968 for(u
= 0; u
< xcfg_len
- 2; u
+= len
) {
969 type
= mem
->data
[u
+ cfg_len
];
970 len
= mem
->data
[u
+ cfg_len
+ 1];
971 ADD2LOG(" type %u, len %u\n ", type
, len
);
972 if(len
+ u
> xcfg_len
) len
= xcfg_len
- u
;
973 hexdump(&hd_data
->log
, 1, len
, mem
->data
+ cfg_len
+ u
);
976 ADD2LOG(" oops: invalid record lenght\n");
984 int get_bios32_info(hd_data_t
*hd_data
, memory_range_t
*mem
, bios32_info_t
*bios32
)
987 unsigned addr
= 0, len
;
989 if(mem
->size
< 0x10) return 0;
991 for(u
= ok
= 0; u
<= mem
->size
- 0x10; u
+= 0x10) {
992 if(*(unsigned *) (mem
->data
+ u
) == 0x5f32335f) { /* "_32_" */
993 addr
= *(unsigned *) (mem
->data
+ u
+ 4);
994 len
= mem
->data
[u
+ 9];
995 ok
= len
== 1 && crc(mem
->data
+ u
, 0x10) == 0 && addr
< (1 << 20) ? 1 : 0;
997 " bios32: %svalid SD header at 0x%05x (size 0x%x, rev %u), SD at 0x%05x\n",
998 ok
? "" : "in", u
+ mem
->start
, len
<< 4, mem
->data
[u
+ 8], addr
1006 bios32
->entry
= addr
;
1013 #endif /* defined(__i386__) || defined (__x86_64__) */