~ubuntu-branches/ubuntu/edgy/hwinfo/edgy

« back to all changes in this revision

Viewing changes to src/hd/bios.c

  • Committer: Bazaar Package Importer
  • Author(s): James Vega
  • Date: 2006-09-28 20:56:06 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20060928205606-bgxl69hts04xbx51
Tags: 13.4-1
* New upstream version.
* Switch from dbs to quilt
  - Revamp debian/rules
  - Add quilt and remove dbs from Build-Depends in debian/control
* Remove reference to hwscan(8) from manpage. (closes: #388245)
* Re-wrote manpage from scratch.  Drop docbook-to-man from Build-Depends.
* Remove NEWS.Debian since it is no longer applicable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <stdio.h>
 
2
#include <stdlib.h>
 
3
#include <string.h>
 
4
#include <unistd.h>
 
5
#include <fcntl.h>
 
6
#include <byteswap.h>
 
7
#include <sys/types.h>
 
8
#include <sys/stat.h>
 
9
#if defined(__i386__) || defined (__x86_64__) || defined(__ia64__)
 
10
#include <sys/io.h>
 
11
#endif
 
12
#include <sys/pci.h>
 
13
 
 
14
#include "hd.h"
 
15
#include "hd_int.h"
 
16
#include "bios.h"
 
17
#include "smbios.h"
 
18
#include "klog.h"
 
19
 
 
20
/**
 
21
 * @defgroup BIOSint BIOS information
 
22
 * @ingroup  libhdINFOint
 
23
 * @brief BIOS information scan
 
24
 *
 
25
 * @{
 
26
 */
 
27
 
 
28
#if defined(__i386__) || defined (__x86_64__) || defined (__ia64__)
 
29
 
 
30
#include "ibm-notebooks.h"
 
31
static int tp_lookup(char *key, unsigned *width, unsigned *height, unsigned *xsize, unsigned *ysize);
 
32
 
 
33
static struct {
 
34
  unsigned short xsize; /* mm */
 
35
  unsigned short ysize; /* mm */
 
36
  unsigned short width;
 
37
  unsigned short height;
 
38
  char *vendor;
 
39
  char *name;
 
40
  char *version;
 
41
} __attribute((packed)) panel_data[] = {
 
42
  {   0,   0, 1400, 1050, "IBM", "73geu99", NULL },
 
43
  {   0,   0,  800,  600, "Fujitsu Siemens", "LiteLine", "LF6" },
 
44
  {   0,   0, 1024,  768, "ASUSTEK", "L2000D", NULL },
 
45
  {   0,   0, 1024,  768, "ASUSTeK Computer Inc.", "L8400C series Notebook PC", NULL },
 
46
  {   0,   0, 1024,  768, "ASUSTeK Computer Inc.", "S5N", NULL },
 
47
  {   0,   0, 1024,  768, "Acer", "TravelMate 720", NULL },
 
48
  {   0,   0, 1024,  768, "COMPAL", "N30T5", NULL },
 
49
  {   0,   0, 1024,  768, "Dell Computer Corporation", "Inspiron 5000", NULL },
 
50
  {   0,   0, 1024,  768, "Dell Computer Corporation", "Latitude C400", NULL },
 
51
  {   0,   0, 1024,  768, "Dell Computer Corporation", "Latitude C600", NULL },
 
52
  {   0,   0, 1024,  768, "Dell Computer Corporation", "Latitude CPt C400GT", NULL },
 
53
  {   0,   0, 1024,  768, "Dell Computer Corporation", "Latitude CPx J650GT", NULL },
 
54
  {   0,   0, 1024,  768, "Hewlett-Packard", "HP OmniBook PC", "HP OmniBook 4150 B" },
 
55
  {   0,   0, 1280,  800, "Hewlett-Packard", "hp compaq nx9105 (DU367T#ABD)", "03" },
 
56
  { 330, 210, 1280,  800, "Hewlett-Packard", "hp compaq nx9105 (DU367T#ABD)", "F.21" },
 
57
  {   0,   0, 1280,  800, "Hewlett-Packard", "Pavilion zv5000 (PA456EA#ABD)", "F.11" },
 
58
  {   0,   0, 1024,  768, "KDST", "KDS6KSUMO", NULL  },
 
59
  {   0,   0, 1024,  768, "Sony Corporation", "PCG-F370(UC)", NULL },
 
60
  {   0,   0, 1024,  768, "Sony Corporation", "PCG-N505SN", NULL },
 
61
  {   0,   0, 1024,  768, "TOSHIBA", "S2400-103", NULL },
 
62
  {   0,   0, 1280,  800, "Acer", "Aspire 1520", NULL },
 
63
  {   0,   0, 1440,  900, "FUJITSU SIEMENS", "Amilo M3438 Series", NULL },
 
64
  {   0,   0, 1400, 1050, "Acer", "TravelMate 660", NULL },
 
65
  {   0,   0, 1400, 1050, "Dell Computer Corporation", "Inspiron 8000", NULL },
 
66
  { 286, 214, 1400, 1050, "Dell Computer Corporation", "Latitude D600", NULL },
 
67
  {   0,   0, 1400, 1050, "TOSHIBA", "TECRA 9100", NULL },
 
68
  {   0,   0, 1600, 1200, "Dell Computer Corporation", "Inspiron 8200", NULL },
 
69
  {   0,   0, 1600, 1200, "Dell Computer Corporation", "Latitude C840", NULL },
 
70
  { 190, 110, 1024,  600, "FUJITSU SIEMENS", "LIFEBOOK P1510", NULL },
 
71
  { 285, 215, 1024,  768, "FUJITSU SIEMENS", "LIFEBOOK S7020", NULL },
 
72
  { 305, 230, 1400, 1050, "Samsung Electronics", "SX20S", "Revision PR" },
 
73
  { 290, 200, 1280,  800, "TOSHIBA", "Satellite M30X", "PSA72E-00J020GR" },
 
74
  { 305, 230, 1400, 1050, "ASUSTeK Computer Inc.", "M6V", "1.0" },
 
75
  { 246, 185, 1024,  768, "FUJITSU SIEMENS", "LifeBook T Series", NULL },
 
76
  { 304, 190, 1400, 1050, "Hewlett-Packard", "HP Compaq nc6000 (PN887PA#ABG)", "F.0F" },
 
77
  { 332, 208, 1280,  800, "MICRO-STAR INT'L CO.,LTD.", "MS-1011", "0101" },
 
78
};
 
79
 
 
80
#define BIOS_TEST
 
81
 
 
82
typedef struct {
 
83
  unsigned eax, ebx, ecx, edx, esi, edi, eip, es, iret, cli;
 
84
} bios32_regs_t;
 
85
 
 
86
static void read_memory(hd_data_t *hd_data, memory_range_t *mem);
 
87
static void dump_memory(hd_data_t *hd_data, memory_range_t *mem, int sparse, char *label);
 
88
static void get_pnp_support_status(memory_range_t *mem, bios_info_t *bt);
 
89
static void smbios_get_info(hd_data_t *hd_data, memory_range_t *mem, bios_info_t *bt);
 
90
static void get_fsc_info(hd_data_t *hd_data, memory_range_t *mem, bios_info_t *bt);
 
91
#ifndef LIBHD_TINY
 
92
static void add_panel_info(hd_data_t *hd_data, bios_info_t *bt);
 
93
#endif
 
94
static void add_mouse_info(hd_data_t *hd_data, bios_info_t *bt);
 
95
static unsigned char crc(unsigned char *mem, unsigned len);
 
96
static int get_smp_info(hd_data_t *hd_data, memory_range_t *mem, smp_info_t *smp);
 
97
static void parse_mpconfig(hd_data_t *hd_data, memory_range_t *mem, smp_info_t *smp);
 
98
static int get_bios32_info(hd_data_t *hd_data, memory_range_t *mem, bios32_info_t *bios32);
 
99
 
 
100
int detect_smp_bios(hd_data_t *hd_data)
 
101
{
 
102
  bios_info_t *bt;
 
103
  hd_smbios_t *sm;
 
104
  hd_t *hd;
 
105
  int cpus;
 
106
 
 
107
  if(!hd_data->bios_ram.data) return -1;        /* hd_scan_bios() not called */
 
108
 
 
109
  for(bt = NULL, hd = hd_data->hd; hd; hd = hd->next) {
 
110
    if(
 
111
      hd->base_class.id == bc_internal &&
 
112
      hd->sub_class.id == sc_int_bios &&
 
113
      hd->detail &&
 
114
      hd->detail->type == hd_detail_bios &&
 
115
      (bt = hd->detail->bios.data)
 
116
    ) {
 
117
      break;
 
118
    }
 
119
  }
 
120
 
 
121
  if(!bt) return -1;
 
122
 
 
123
  cpus = 0;
 
124
 
 
125
  /* look at smbios data in case there's no mp table */
 
126
  if(hd_data->smbios) {
 
127
    for(sm = hd_data->smbios; sm; sm = sm->next) {
 
128
      if(
 
129
        sm->any.type == sm_processor &&
 
130
        sm->processor.pr_type.id == 3 &&        /* cpu */
 
131
        sm->processor.cpu_status.id == 1        /* enabled */
 
132
      ) {
 
133
        cpus++;
 
134
      }
 
135
    }
 
136
    ADD2LOG("  smp detect: mp %d cpus, smbios %d cpus\n", bt->smp.ok ? bt->smp.cpus_en : 0, cpus);
 
137
  }
 
138
 
 
139
  if(bt->smp.ok && bt->smp.cpus_en) cpus = bt->smp.cpus_en;
 
140
 
 
141
  return cpus;
 
142
}
 
143
 
 
144
 
 
145
void hd_scan_bios(hd_data_t *hd_data)
 
146
{
 
147
  hd_t *hd;
 
148
  bios_info_t *bt;
 
149
  char *s;
 
150
  unsigned char *bios_ram;
 
151
  unsigned u, u1;
 
152
  memory_range_t mem;
 
153
  unsigned smp_ok;
 
154
#ifndef LIBHD_TINY
 
155
  vbe_info_t *vbe;
 
156
  vbe_mode_info_t *mi;
 
157
  hd_res_t *res;
 
158
  str_list_t *sl;
 
159
#endif
 
160
 
 
161
  if(!hd_probe_feature(hd_data, pr_bios)) return;
 
162
 
 
163
  /* we better do nothing on a SGI Altix machine */
 
164
  if(hd_is_sgi_altix(hd_data)) return;
 
165
 
 
166
  hd_data->module = mod_bios;
 
167
 
 
168
  /* some clean-up */
 
169
  remove_hd_entries(hd_data);
 
170
 
 
171
  PROGRESS(1, 0, "cmdline");
 
172
 
 
173
  hd = add_hd_entry(hd_data, __LINE__, 0);
 
174
  hd->base_class.id = bc_internal;
 
175
  hd->sub_class.id = sc_int_bios;
 
176
  hd->detail = new_mem(sizeof *hd->detail);
 
177
  hd->detail->type = hd_detail_bios;
 
178
  hd->detail->bios.data = bt = new_mem(sizeof *bt);
 
179
 
 
180
  /*
 
181
   * first, look for APM support
 
182
   */
 
183
  if((s = get_cmd_param(hd_data, 1))) {
 
184
    if(strlen(s) >= 10) {
 
185
      bt->apm_supported = 1;
 
186
      bt->apm_ver = hex(s, 1);
 
187
      bt->apm_subver = hex(s + 1, 1);
 
188
      bt->apm_bios_flags = hex(s + 2, 2);
 
189
      /*
 
190
       * Bitfields for APM flags (from Ralf Brown's list):
 
191
       * Bit(s)  Description
 
192
       *  0      16-bit protected mode interface supported
 
193
       *  1      32-bit protected mode interface supported
 
194
       *  2      CPU idle call reduces processor speed
 
195
       *  3      BIOS power management disabled
 
196
       *  4      BIOS power management disengaged (APM v1.1)
 
197
       *  5-7    reserved
 
198
       */
 
199
      bt->apm_enabled = (bt->apm_bios_flags & 8) ? 0 : 1;
 
200
 
 
201
      bt->vbe_ver = hex(s + 4, 2);
 
202
      bt->vbe_ver = (((bt->vbe_ver >> 4) & 0xf) << 8) + (bt->vbe_ver & 0xf);
 
203
      bt->vbe_video_mem = hex(s + 6, 4) << 16;
 
204
    }
 
205
 
 
206
    s = free_mem(s);
 
207
  }
 
208
 
 
209
  if((s = get_cmd_param(hd_data, 2))) {
 
210
    if(strlen(s) > 8) {
 
211
      if(s[8] == '.') bt->lba_support = 1;
 
212
    }
 
213
 
 
214
    s = free_mem(s);
 
215
  }
 
216
 
 
217
  PROGRESS(1, 1, "apm");
 
218
 
 
219
  if(!bt->apm_ver) {
 
220
    str_list_t *sl0, *sl;
 
221
 
 
222
    sl0 = read_file(PROC_APM, 0, 0);
 
223
    if(sl0) {
 
224
      bt->apm_supported = 1;
 
225
      bt->apm_enabled = 1;
 
226
      ADD2LOG("----- %s -----\n", PROC_APM);
 
227
      for(sl = sl0; sl; sl = sl->next) {
 
228
        ADD2LOG("  %s", sl->str);
 
229
      }
 
230
      ADD2LOG("----- %s end -----\n", PROC_APM);
 
231
    }
 
232
    free_str_list(sl0);
 
233
  }
 
234
 
 
235
  /*
 
236
   * get the i/o ports for the parallel & serial interfaces from the BIOS
 
237
   * memory area starting at 0x40:0
 
238
   */
 
239
  PROGRESS(2, 0, "ram");
 
240
 
 
241
  hd_data->bios_ram.start = BIOS_RAM_START;
 
242
  hd_data->bios_ram.size = BIOS_RAM_SIZE;
 
243
  read_memory(hd_data, &hd_data->bios_ram);
 
244
 
 
245
  hd_data->bios_rom.start = BIOS_ROM_START;
 
246
  hd_data->bios_rom.size = BIOS_ROM_SIZE;
 
247
  read_memory(hd_data, &hd_data->bios_rom);
 
248
 
 
249
  if(hd_data->bios_ram.data) {
 
250
    bios_ram = hd_data->bios_ram.data;
 
251
 
 
252
    bt->ser_port0 = (bios_ram[1] << 8) + bios_ram[0];
 
253
    bt->ser_port1 = (bios_ram[3] << 8) + bios_ram[2];
 
254
    bt->ser_port2 = (bios_ram[5] << 8) + bios_ram[4];
 
255
    bt->ser_port3 = (bios_ram[7] << 8) + bios_ram[6];
 
256
 
 
257
    bt->par_port0 = (bios_ram[  9] << 8) + bios_ram[  8];
 
258
    bt->par_port1 = (bios_ram[0xb] << 8) + bios_ram[0xa];
 
259
    bt->par_port2 = (bios_ram[0xd] << 8) + bios_ram[0xc];
 
260
 
 
261
    bt->led.scroll_lock = bios_ram[0x97] & 1;
 
262
    bt->led.num_lock = (bios_ram[0x97] >> 1) & 1;
 
263
    bt->led.caps_lock = (bios_ram[0x97] >> 2) & 1;
 
264
    bt->led.ok = 1;
 
265
 
 
266
    /*
 
267
     * do some consistency checks:
 
268
     *
 
269
     * ports must be < 0x1000 and not appear twice
 
270
     */
 
271
    if(bt->ser_port0 >= 0x1000) bt->ser_port0 = 0;
 
272
 
 
273
    if(
 
274
      bt->ser_port1 >= 0x1000 ||
 
275
      bt->ser_port1 == bt->ser_port0
 
276
    ) bt->ser_port1 = 0;
 
277
 
 
278
    if(
 
279
      bt->ser_port2 >= 0x1000 ||
 
280
      bt->ser_port2 == bt->ser_port0 ||
 
281
      bt->ser_port2 == bt->ser_port1
 
282
    ) bt->ser_port2 = 0;
 
283
 
 
284
    if(
 
285
      bt->ser_port3 >= 0x1000 ||
 
286
      bt->ser_port3 == bt->ser_port0 ||
 
287
      bt->ser_port3 == bt->ser_port1 ||
 
288
      bt->ser_port3 == bt->ser_port2
 
289
    ) bt->ser_port3 = 0;
 
290
 
 
291
    if(bt->par_port0 >= 0x1000) bt->par_port0 = 0;
 
292
 
 
293
    if(
 
294
      bt->par_port1 >= 0x1000 ||
 
295
      bt->par_port1 == bt->par_port0
 
296
    ) bt->par_port1 = 0;
 
297
 
 
298
    if(
 
299
      bt->par_port2 >= 0x1000 ||
 
300
      bt->par_port2 == bt->par_port0 ||
 
301
      bt->par_port2 == bt->par_port1
 
302
    ) bt->par_port2 = 0;
 
303
 
 
304
    ADD2LOG("  bios: %u disks\n", bios_ram[0x75]);
 
305
 
 
306
    bt->low_mem_size = ((bios_ram[0x14] << 8) + bios_ram[0x13]) << 10;
 
307
 
 
308
    if(bt->low_mem_size) {
 
309
      ADD2LOG("  bios: %uk low mem\n", bt->low_mem_size >> 10);
 
310
    }
 
311
 
 
312
    /* too unusual */
 
313
    if(bt->low_mem_size >= (768 << 10) || bt->low_mem_size < (384 << 10)) {
 
314
      bt->low_mem_size = 0;
 
315
    }
 
316
 
 
317
    hd_data->bios_ebda.start = hd_data->bios_ebda.size = 0;
 
318
    hd_data->bios_ebda.data = free_mem(hd_data->bios_ebda.data);
 
319
    u = ((bios_ram[0x0f] << 8) + bios_ram[0x0e]) << 4;
 
320
    if(u) {
 
321
      hd_data->bios_ebda.start = u;
 
322
      hd_data->bios_ebda.size = 1;      /* just one byte */
 
323
      read_memory(hd_data, &hd_data->bios_ebda);
 
324
      if(hd_data->bios_ebda.data) {
 
325
        u1 = hd_data->bios_ebda.data[0];
 
326
        if(u1 > 0 && u1 <= 64) {        /* be sensible, typically only 1k */
 
327
          u1 <<= 10;
 
328
          if(u + u1 <= (1 << 20)) {
 
329
            hd_data->bios_ebda.size = u1;
 
330
            read_memory(hd_data, &hd_data->bios_ebda);
 
331
          }
 
332
        }
 
333
      }
 
334
    }
 
335
 
 
336
    if(hd_data->bios_ebda.data) {
 
337
      ADD2LOG(
 
338
        "  bios: EBDA 0x%05x bytes at 0x%05x\n",
 
339
        hd_data->bios_ebda.size, hd_data->bios_ebda.start
 
340
      );
 
341
    }
 
342
  }
 
343
 
 
344
  /*
 
345
   * read the bios rom and look for useful things there...
 
346
   */
 
347
  PROGRESS(2, 0, "rom");
 
348
 
 
349
  if(hd_data->bios_rom.data) {
 
350
    get_pnp_support_status(&hd_data->bios_rom, bt);
 
351
    smbios_get_info(hd_data, &hd_data->bios_rom, bt);
 
352
    get_fsc_info(hd_data, &hd_data->bios_rom, bt);
 
353
#ifndef LIBHD_TINY
 
354
    add_panel_info(hd_data, bt);
 
355
#endif
 
356
    add_mouse_info(hd_data, bt);
 
357
  }
 
358
 
 
359
  PROGRESS(3, 0, "smp");
 
360
 
 
361
  smp_ok = 0;
 
362
 
 
363
  mem = hd_data->bios_ebda;
 
364
  smp_ok = get_smp_info(hd_data, &mem, &bt->smp);
 
365
 
 
366
  if(!smp_ok) {
 
367
    mem = hd_data->bios_rom;
 
368
    if(mem.data) {
 
369
      mem.size -= 0xf0000 - mem.start;
 
370
      mem.data += 0xf0000 - mem.start;
 
371
      mem.start = 0xf0000;
 
372
      if(mem.size < (1 << 20)) smp_ok = get_smp_info(hd_data, &mem, &bt->smp);
 
373
    }
 
374
  }
 
375
 
 
376
  if(!smp_ok) {
 
377
    mem.size = 1 << 10;
 
378
    mem.start = 639 << 10;
 
379
    mem.data = NULL;
 
380
    read_memory(hd_data, &mem);
 
381
    if(mem.data) smp_ok = get_smp_info(hd_data, &mem, &bt->smp);
 
382
    mem.data = free_mem(mem.data);
 
383
  }
 
384
 
 
385
  if(bt->smp.ok && bt->smp.mpconfig) {
 
386
    mem.start = bt->smp.mpconfig;
 
387
    mem.size = 1 << 16;
 
388
    mem.data = NULL;
 
389
    read_memory(hd_data, &mem);
 
390
    parse_mpconfig(hd_data, &mem, &bt->smp);
 
391
    mem.data = free_mem(mem.data);
 
392
  }
 
393
  
 
394
  if((hd_data->debug & HD_DEB_BIOS)) {
 
395
    dump_memory(hd_data, &hd_data->bios_ram, 0, "BIOS data");
 
396
    dump_memory(hd_data, &hd_data->bios_ebda, hd_data->bios_ebda.size <= (8 << 10) ? 0 : 1, "EBDA");
 
397
    // dump_memory(hd_data, &hd_data->bios_rom, 1, "BIOS ROM");
 
398
 
 
399
    if(bt->smp.ok && bt->smp.mpfp) {
 
400
      mem.start = bt->smp.mpfp;
 
401
      mem.size = 0x10;
 
402
      mem.data = NULL;
 
403
      read_memory(hd_data, &mem);
 
404
      dump_memory(hd_data, &mem, 0, "MP FP");
 
405
      mem.data = free_mem(mem.data);
 
406
    }
 
407
 
 
408
    if(bt->smp.ok && bt->smp.mpconfig && bt->smp.mpconfig_size) {
 
409
      mem.start = bt->smp.mpconfig;
 
410
      mem.size = bt->smp.mpconfig_size;
 
411
      mem.data = NULL;
 
412
      read_memory(hd_data, &mem);
 
413
      dump_memory(hd_data, &mem, 0, "MP config table");
 
414
      mem.data = free_mem(mem.data);
 
415
    }
 
416
  }
 
417
 
 
418
#ifndef LIBHD_TINY
 
419
  if(hd_probe_feature(hd_data, pr_bios_vesa)) {
 
420
    PROGRESS(4, 0, "vbe");
 
421
 
 
422
    vbe = &bt->vbe;
 
423
    vbe->ok = 0;
 
424
 
 
425
    if(!hd_data->klog) read_klog(hd_data);
 
426
    for(sl = hd_data->klog; sl; sl = sl->next) {
 
427
      if(sscanf(sl->str, "<6>PCI: Using configuration type %u", &u) == 1) {
 
428
        hd_data->pci_config_type = u;
 
429
        ADD2LOG("  klog: pci config type %u\n", hd_data->pci_config_type);
 
430
      }
 
431
    }
 
432
 
 
433
    get_vbe_info(hd_data, vbe);
 
434
 
 
435
    if(vbe->ok) {
 
436
      bt->vbe_ver = vbe->version;
 
437
    }
 
438
 
 
439
    if(vbe->ok && vbe->fb_start) {
 
440
      hd = add_hd_entry(hd_data, __LINE__, 0);
 
441
      hd->base_class.id = bc_framebuffer;
 
442
      hd->sub_class.id = sc_fb_vesa;
 
443
 
 
444
      hd_set_hw_class(hd, hw_vbe);
 
445
 
 
446
#if 0
 
447
      hd->detail = new_mem(sizeof *hd->detail);
 
448
      hd->detail->type = hd_detail_bios;
 
449
      hd->detail->bios.data = bt = new_mem(sizeof *bt);
 
450
#endif
 
451
 
 
452
      hd->vendor.name = new_str(vbe->vendor_name);
 
453
      hd->device.name = new_str(vbe->product_name);
 
454
      hd->sub_vendor.name = new_str(vbe->oem_name);
 
455
      hd->revision.name = new_str(vbe->product_revision);
 
456
 
 
457
      res = add_res_entry(&hd->res, new_mem(sizeof *res));
 
458
      res->phys_mem.type = res_phys_mem;
 
459
      res->phys_mem.range = vbe->memory;
 
460
 
 
461
      res = add_res_entry(&hd->res, new_mem(sizeof *res));
 
462
      res->mem.type = res_mem;
 
463
      res->mem.base = vbe->fb_start;
 
464
      res->mem.range = vbe->memory;
 
465
      res->mem.access = acc_rw;
 
466
      res->mem.enabled = 1;
 
467
 
 
468
      if(vbe->mode) {
 
469
        for(u = 0; u < vbe->modes; u++) {
 
470
          mi = vbe->mode + u;
 
471
          if(
 
472
            (mi->attributes & 1) &&     /* mode supported */
 
473
            mi->fb_start &&
 
474
            mi->pixel_size != -1u       /* text mode */
 
475
          ) {
 
476
            res = add_res_entry(&hd->res, new_mem(sizeof *res));
 
477
            res->framebuffer.type = res_framebuffer;
 
478
            res->framebuffer.width = mi->width;
 
479
            res->framebuffer.bytes_p_line = mi->bytes_p_line;
 
480
            res->framebuffer.height = mi->height;
 
481
            res->framebuffer.colorbits = mi->pixel_size;
 
482
            res->framebuffer.mode = mi->number + 0x200;
 
483
          }
 
484
        }
 
485
      }
 
486
 
 
487
#if 0
 
488
      if(
 
489
        hd->vend_name &&
 
490
        !strcmp(hd->vend_name, "Matrox") &&
 
491
        hd->device.name &&
 
492
        (
 
493
          strstr(hd->dev_name, "G200") ||
 
494
          strstr(hd->dev_name, "G400") ||
 
495
          strstr(hd->dev_name, "G450")
 
496
        )
 
497
      ) {
 
498
        hd->broken = 1;
 
499
      }
 
500
#endif
 
501
 
 
502
    }
 
503
  }
 
504
#endif  /* LIBHD_TINY */
 
505
 
 
506
  PROGRESS(5, 0, "32");
 
507
 
 
508
  mem = hd_data->bios_rom;
 
509
  if(mem.data) {
 
510
    mem.size -= 0xe0000 - mem.start;
 
511
    mem.data += 0xe0000 - mem.start;
 
512
    mem.start = 0xe0000;
 
513
    if(mem.size < (1 << 20)) get_bios32_info(hd_data, &mem, &bt->bios32);
 
514
  }
 
515
 
 
516
  if(bt->bios32.ok) {
 
517
    mem = hd_data->bios_rom;
 
518
 
 
519
    if(
 
520
      mem.start <= 0xfffea &&
 
521
      mem.start + mem.size >= 0xfffea + 6 &&
 
522
      !memcmp(mem.data + 0xfffea - mem.start, "COMPAQ", 6)
 
523
    ) {
 
524
      bt->bios32.compaq = 1;
 
525
      ADD2LOG("  bios32: compaq machine\n");
 
526
    }
 
527
  }
 
528
 
 
529
}
 
530
 
 
531
 
 
532
void read_memory(hd_data_t *hd_data, memory_range_t *mem)
 
533
{
 
534
#ifdef BIOS_TEST
 
535
  char *s = getenv("LIBHD_MEM");
 
536
#endif
 
537
 
 
538
#ifdef LIBHD_MEMCHECK
 
539
  {
 
540
    if(libhd_log) fprintf(libhd_log, ">%p\n", CALLED_FROM(read_memory, mem));
 
541
  }
 
542
#endif
 
543
 
 
544
  if(mem->data) free_mem(mem->data);
 
545
  mem->data = new_mem(mem->size);
 
546
#ifdef BIOS_TEST
 
547
  hd_read_mmap(hd_data, s ?: DEV_MEM, mem->data, mem->start, mem->size);
 
548
#else
 
549
  hd_read_mmap(hd_data, DEV_MEM, mem->data, mem->start, mem->size);
 
550
#endif
 
551
 
 
552
#ifdef LIBHD_MEMCHECK
 
553
  {
 
554
    if(libhd_log) fprintf(libhd_log, "<%p\n", CALLED_FROM(read_memory, mem));
 
555
  }
 
556
#endif
 
557
}
 
558
 
 
559
 
 
560
void dump_memory(hd_data_t *hd_data, memory_range_t *mem, int sparse, char *label)
 
561
{
 
562
  unsigned u, step;
 
563
 
 
564
  if(!mem->size || !mem->data) return;
 
565
 
 
566
#if 1
 
567
  step = sparse ? 0x1000 : 0x10;
 
568
#else
 
569
  step = 0x10;
 
570
#endif
 
571
 
 
572
  ADD2LOG("----- %s 0x%05x - 0x%05x -----\n", label, mem->start, mem->start + mem->size - 1);
 
573
  for(u = 0; u < mem->size; u += step) {
 
574
    ADD2LOG("  %03x  ", u + mem->start);
 
575
    hexdump(&hd_data->log, 1, mem->size - u > 0x10 ? 0x10 : mem->size - u, mem->data + u);
 
576
    ADD2LOG("\n");
 
577
  }
 
578
  ADD2LOG("----- %s end -----\n", label);
 
579
}
 
580
 
 
581
 
 
582
void get_pnp_support_status(memory_range_t *mem, bios_info_t *bt)
 
583
{
 
584
  int i;
 
585
  unsigned char pnp[4] = { '$', 'P', 'n', 'P' };
 
586
  unsigned char *t;
 
587
  unsigned l, cs;
 
588
 
 
589
  if(!mem->data) return;
 
590
 
 
591
  for(i = 0xf0000 - mem->start; (unsigned) i < mem->size; i += 0x10) {
 
592
    t = mem->data + i;
 
593
    if(t[0] == pnp[0] && t[1] == pnp[1] && t[2] == pnp[2] && t[3] == pnp[3]) {
 
594
      for(l = cs = 0; l < t[5]; l++) { cs += t[l]; }
 
595
      if((cs & 0xff) == 0) {            // checksum ok
 
596
        bt->is_pnp_bios = 1;
 
597
//        printf("0x%x bytes at 0x%x, cs = 0x%x\n", t[5], i, cs);
 
598
        bt->pnp_id = t[0x17] + (t[0x18] << 8) + (t[0x19] << 16) + (t[0x20] << 24);
 
599
      }
 
600
    }
 
601
  }
 
602
}
 
603
 
 
604
unsigned char crc(unsigned char *mem, unsigned len)
 
605
{
 
606
  unsigned char uc = 0;
 
607
 
 
608
  while(len--) uc += *mem++;
 
609
 
 
610
  return uc;
 
611
}
 
612
 
 
613
 
 
614
void smbios_get_info(hd_data_t *hd_data, memory_range_t *mem, bios_info_t *bt)
 
615
{
 
616
  unsigned u, u1, u2, ok, hlen = 0, ofs;
 
617
  unsigned addr = 0, len = 0, scnt;
 
618
  unsigned structs = 0, type, slen;
 
619
  char *s;
 
620
  memory_range_t memory;
 
621
  hd_smbios_t *sm;
 
622
 
 
623
  if(!mem->data || mem->size < 0x10) return;
 
624
 
 
625
  for(u = ok = 0; u <= mem->size - 0x10; u += 0x10) {
 
626
    if(*(unsigned *) (mem->data + u) == 0x5f4d535f) {   /* "_SM_" */
 
627
      hlen = mem->data[u + 5];
 
628
      if(hlen < 0x1e || u + hlen > mem->size) continue;
 
629
      addr = *(unsigned *) (mem->data + u + 0x18);
 
630
      len = *(unsigned short *) (mem->data + u + 0x16);
 
631
      structs = *(unsigned short *) (mem->data + u + 0x1c);
 
632
      ok = crc(mem->data + u, hlen) == 0 && len;
 
633
      if(ok) {
 
634
        bt->smbios_ver = (mem->data[u + 6] << 8) + mem->data[u + 7];
 
635
        break;
 
636
      }
 
637
    }
 
638
    /* Also look for legacy DMI entry point */
 
639
    if(memcmp(mem->data + u, "_DMI_", 5) == 0) {
 
640
      hlen = 0x0f;
 
641
      addr = *(unsigned *) (mem->data + u + 0x08);
 
642
      len = *(unsigned short *) (mem->data + u + 0x06);
 
643
      structs = *(unsigned short *) (mem->data + u + 0x0c);
 
644
      ok = crc(mem->data + u, hlen) == 0 && len;
 
645
      if(ok) {
 
646
        bt->smbios_ver = ((mem->data[u + 0x0e] & 0xf0) << 4) + (mem->data[u + 0x0e] & 0x0f);
 
647
        break;
 
648
      }
 
649
    }
 
650
  }
 
651
 
 
652
  if(!ok) return;
 
653
 
 
654
  hd_data->smbios = smbios_free(hd_data->smbios);
 
655
 
 
656
  memory.start = mem->start + u;
 
657
  memory.size = hlen;
 
658
  memory.data = mem->data + u;
 
659
  dump_memory(hd_data, &memory, 0, "SMBIOS Entry Point");
 
660
 
 
661
  memory.start = addr;
 
662
  memory.size = len;
 
663
  memory.data = NULL;
 
664
  read_memory(hd_data, &memory);
 
665
  if(len >= 0x4000) {
 
666
    ADD2LOG(
 
667
      "  SMBIOS Structure Table at 0x%05x (size 0x%x)\n",
 
668
      addr, len
 
669
    );
 
670
  }
 
671
  else {
 
672
    dump_memory(hd_data, &memory, 0, "SMBIOS Structure Table");
 
673
  }
 
674
 
 
675
  for(type = 0, u = 0, ofs = 0; u < structs && ofs + 3 < len; u++) {
 
676
    type = memory.data[ofs];
 
677
    slen = memory.data[ofs + 1];
 
678
    if(ofs + slen > len || slen < 4) break;
 
679
    sm = smbios_add_entry(&hd_data->smbios, new_mem(sizeof *sm));
 
680
    sm->any.type = type;
 
681
    sm->any.data_len = slen;
 
682
    sm->any.data = new_mem(slen);
 
683
    memcpy(sm->any.data, memory.data + ofs, slen);
 
684
    sm->any.handle = memory.data[ofs + 2] + (memory.data[ofs + 3] << 8);
 
685
    ADD2LOG("  type 0x%02x [0x%04x]: ", type, sm->any.handle);
 
686
    if(slen) hexdump(&hd_data->log, 0, slen, sm->any.data);
 
687
    ADD2LOG("\n");
 
688
    if(type == sm_end) break;
 
689
    ofs += slen;
 
690
    u1 = ofs;
 
691
    u2 = 1;
 
692
    scnt = 0;
 
693
    while(ofs + 1 < len) {
 
694
      if(!memory.data[ofs]) {
 
695
        if(ofs > u1) {
 
696
          s = canon_str(memory.data + u1, strlen(memory.data + u1));
 
697
          add_str_list(&sm->any.strings, s);
 
698
          scnt++;
 
699
          if(*s) ADD2LOG("       str%d: \"%s\"\n", scnt, s);
 
700
          free_mem(s);
 
701
          u1 = ofs + 1;
 
702
          u2++;
 
703
        }
 
704
        if(!memory.data[ofs + 1]) {
 
705
          ofs += 2;
 
706
          break;
 
707
        }
 
708
      }
 
709
      ofs++;
 
710
    }
 
711
  }
 
712
 
 
713
  if(u != structs) {
 
714
    if(type == sm_end) {
 
715
      ADD2LOG("  smbios: stopped at end tag\n");
 
716
    }
 
717
    else {
 
718
      ADD2LOG("  smbios oops: only %d of %d structs found\n", u, structs);
 
719
    }
 
720
  }
 
721
 
 
722
  memory.data = free_mem(memory.data);
 
723
 
 
724
  smbios_parse(hd_data);
 
725
}
 
726
 
 
727
 
 
728
void get_fsc_info(hd_data_t *hd_data, memory_range_t *mem, bios_info_t *bt)
 
729
{
 
730
  unsigned u, mtype, fsc_id;
 
731
  unsigned x, y;
 
732
  hd_smbios_t *sm;
 
733
  char *vendor = NULL;
 
734
 
 
735
  if(!mem->data || mem->size < 0x20) return;
 
736
 
 
737
  for(sm = hd_data->smbios; sm; sm = sm->next) {
 
738
    if(sm->any.type == sm_sysinfo) {
 
739
      vendor = sm->sysinfo.manuf;
 
740
      break;
 
741
    }
 
742
  }
 
743
 
 
744
  vendor = vendor && !strcasecmp(vendor, "Fujitsu") ? "Fujitsu" : "Fujitsu Siemens";
 
745
 
 
746
  for(u = 0; u <= mem->size - 0x20; u += 0x10) {
 
747
    if(
 
748
      *(unsigned *) (mem->data + u) == 0x696a7546 &&
 
749
      *(unsigned *) (mem->data + u + 4) == 0x20757374
 
750
    ) {
 
751
      mtype = *(unsigned *) (mem->data + u + 0x14);
 
752
      if(!crc(mem->data + u, 0x20) && !(mtype & 0xf0000000)) {
 
753
        fsc_id = (mtype >> 12) & 0xf;
 
754
 
 
755
        switch(fsc_id) {
 
756
          case 1:
 
757
            x = 640; y = 480;
 
758
            break;
 
759
 
 
760
          case 2:
 
761
            x = 800; y = 600;
 
762
            break;
 
763
 
 
764
          case 3:
 
765
            x = 1024; y = 768;
 
766
            break;
 
767
 
 
768
          case 4:
 
769
            x = 1280; y = 1024;
 
770
            break;
 
771
 
 
772
          case 5:
 
773
            x = 1400; y = 1050;
 
774
            break;
 
775
 
 
776
          case 6:
 
777
            x = 1024; y = 512;
 
778
            break;
 
779
 
 
780
          case 7:
 
781
            x = 1280; y = 600;
 
782
            break;
 
783
 
 
784
          case 8:
 
785
            x = 1600; y = 1200;
 
786
            break;
 
787
 
 
788
          default:
 
789
            x = 0; y = 0;
 
790
        }
 
791
 
 
792
        if(x) {
 
793
          bt->lcd.vendor = new_str(vendor);
 
794
          bt->lcd.name = new_str("Notebook LCD");
 
795
          bt->lcd.width = x;
 
796
          bt->lcd.height = y;
 
797
        }
 
798
 
 
799
        ADD2LOG("  found FSC LCD: %d (%ux%u)\n", fsc_id, x, y);
 
800
        break;
 
801
      }
 
802
    }
 
803
  }
 
804
}
 
805
 
 
806
 
 
807
#ifndef LIBHD_TINY
 
808
void add_panel_info(hd_data_t *hd_data, bios_info_t *bt)
 
809
{
 
810
  unsigned width, height, xsize = 0, ysize = 0;
 
811
  char *vendor, *name, *version;
 
812
  hd_smbios_t *sm;
 
813
  unsigned u;
 
814
 
 
815
  if(!hd_data->smbios) return;
 
816
 
 
817
  vendor = name = version = NULL;
 
818
  width = height = 0;
 
819
 
 
820
  for(sm = hd_data->smbios; sm; sm = sm->next) {
 
821
    if(sm->any.type == sm_sysinfo) {
 
822
      vendor = sm->sysinfo.manuf;
 
823
      name = sm->sysinfo.product;
 
824
      version = sm->sysinfo.version;
 
825
      break;
 
826
    }
 
827
  }
 
828
 
 
829
  if(!vendor || !name) return;
 
830
 
 
831
  if(
 
832
    !strcmp(vendor, "IBM") &&
 
833
    tp_lookup(name, &width, &height, &xsize, &ysize)
 
834
  ) {
 
835
    bt->lcd.vendor = new_str(vendor);
 
836
    bt->lcd.name = new_str("Notebook LCD");
 
837
    bt->lcd.width = width;
 
838
    bt->lcd.height = height;
 
839
    bt->lcd.xsize = xsize;
 
840
    bt->lcd.ysize = ysize;
 
841
 
 
842
    return;
 
843
  }
 
844
 
 
845
  for(u = 0; u < sizeof panel_data / sizeof *panel_data; u++) {
 
846
    if(
 
847
      !strcmp(vendor, panel_data[u].vendor) &&
 
848
      !strcmp(name, panel_data[u].name) &&
 
849
      (version || !panel_data[u].version) &&
 
850
      (!version || !panel_data[u].version || !strcmp(version, panel_data[u].version))
 
851
    ) {
 
852
      bt->lcd.vendor = new_str(vendor);
 
853
      bt->lcd.name = new_str("Notebook LCD");
 
854
      bt->lcd.width = panel_data[u].width;
 
855
      bt->lcd.height = panel_data[u].height;
 
856
      bt->lcd.xsize = panel_data[u].xsize;
 
857
      bt->lcd.ysize = panel_data[u].ysize;
 
858
      break;
 
859
    }
 
860
  }
 
861
}
 
862
#endif
 
863
 
 
864
void add_mouse_info(hd_data_t *hd_data, bios_info_t *bt)
 
865
{
 
866
  unsigned compat_vend, compat_dev, bus;
 
867
  char *vendor, *name, *type;
 
868
  hd_smbios_t *sm;
 
869
 
 
870
  if(bt->mouse.compat_vend || !hd_data->smbios) return;
 
871
 
 
872
  vendor = name = type = NULL;
 
873
  compat_vend = compat_dev = bus = 0;
 
874
 
 
875
  for(sm = hd_data->smbios; sm; sm = sm->next) {
 
876
    if(sm->any.type == sm_sysinfo) {
 
877
      vendor = sm->sysinfo.manuf;
 
878
      name = sm->sysinfo.product;
 
879
    }
 
880
    if(
 
881
      sm->any.type == sm_mouse &&
 
882
      !compat_vend      /* take the first entry */
 
883
    ) {
 
884
      compat_vend = compat_dev = bus = 0;
 
885
      type = NULL;
 
886
      
 
887
      switch(sm->mouse.interface.id) {
 
888
        case 4: /* ps/2 */
 
889
        case 7: /* bus mouse (dell notebooks report this) */
 
890
          bus = bus_ps2;
 
891
          compat_vend = MAKE_ID(TAG_SPECIAL, 0x0200);
 
892
          compat_dev = MAKE_ID(TAG_SPECIAL, sm->mouse.buttons == 3 ? 0x0007 : 0x0006);
 
893
          break;
 
894
      }
 
895
      type = sm->mouse.mtype.name;
 
896
      if(sm->mouse.mtype.id == 1) type = "Touch Pad";   /* Why??? */
 
897
      if(sm->mouse.mtype.id == 2) type = NULL;          /* "Other" */
 
898
    }
 
899
  }
 
900
 
 
901
  if(!vendor || !name) return;
 
902
 
 
903
  if(!type) {
 
904
    if(!strcmp(vendor, "Sony Corporation") && strstr(name, "PCG-") == name) {
 
905
      bus = bus_ps2;
 
906
      type = "Touch Pad";
 
907
      compat_vend = MAKE_ID(TAG_SPECIAL, 0x0200);
 
908
      compat_dev = MAKE_ID(TAG_SPECIAL, 0x0006);
 
909
    }
 
910
  }
 
911
 
 
912
  if(!type) return;
 
913
 
 
914
  bt->mouse.vendor = new_str(vendor);
 
915
  bt->mouse.type = new_str(type);
 
916
  bt->mouse.bus = bus;
 
917
  bt->mouse.compat_vend = compat_vend;
 
918
  bt->mouse.compat_dev = compat_dev;
 
919
}
 
920
 
 
921
 
 
922
int get_smp_info(hd_data_t *hd_data, memory_range_t *mem, smp_info_t *smp)
 
923
{
 
924
#ifndef __ia64__
 
925
  unsigned u, ok;
 
926
  unsigned addr = 0, len;
 
927
 
 
928
  if(mem->size < 0x10) return 0;
 
929
 
 
930
  for(u = ok = 0; u <= mem->size - 0x10; u++) {
 
931
    if(*(unsigned *) (mem->data + u) == 0x5f504d5f) {   /* "_MP_" */
 
932
      addr = *(unsigned *) (mem->data + u + 4);
 
933
      len = mem->data[u + 8];
 
934
      ok = len == 1 && crc(mem->data + u, 0x10) == 0 ? 1 : 0;
 
935
      ADD2LOG(
 
936
        "  smp: %svalid MP FP at 0x%05x (size 0x%x, rev %u), MP config at 0x%05x\n",
 
937
        ok ? "" : "in", u + mem->start, len << 4, mem->data[u + 9], addr
 
938
      );
 
939
      if(ok) break;
 
940
    }
 
941
  }
 
942
 
 
943
  if(ok) {
 
944
    smp->ok = 1;
 
945
    smp->mpfp = mem->start + u;
 
946
    smp->rev = mem->data[u + 9];
 
947
    smp->mpconfig = addr;
 
948
    memcpy(smp->feature, mem->data + u + 11, 5);
 
949
  }
 
950
 
 
951
  return ok;
 
952
#else
 
953
  return 0;
 
954
#endif
 
955
}
 
956
 
 
957
 
 
958
void parse_mpconfig(hd_data_t *hd_data, memory_range_t *mem, smp_info_t *smp)
 
959
{
 
960
  unsigned cfg_len, xcfg_len;
 
961
  unsigned char u0, ux0;
 
962
  unsigned u, type, len, entries, entry_cnt;
 
963
  char *s;
 
964
 
 
965
  cfg_len = xcfg_len = 0;
 
966
 
 
967
  if(*(unsigned *) (mem->data) == 0x504d4350) {         /* "PCMP" */
 
968
    cfg_len = mem->data[0x04] + (mem->data[0x05] << 8);
 
969
    smp->mpconfig_size = cfg_len;
 
970
    u0 = crc(mem->data, cfg_len);
 
971
    if(u0) return;
 
972
    smp->mpconfig_ok = 1;
 
973
    smp->cpus = smp->cpus_en = 0;
 
974
    xcfg_len = mem->data[0x28] + (mem->data[0x29] << 8);
 
975
    ux0 = crc(mem->data + cfg_len, xcfg_len) + mem->data[0x2a];
 
976
    if(!ux0) {
 
977
      smp->mpconfig_size += xcfg_len;
 
978
    }
 
979
    else {
 
980
      xcfg_len = 0;
 
981
    }
 
982
  }
 
983
 
 
984
  if(cfg_len) {
 
985
    s = canon_str(mem->data + 8, 8);
 
986
    strcpy(smp->oem_id, s);
 
987
    free_mem(s);
 
988
    s = canon_str(mem->data + 0x10, 12);
 
989
    strcpy(smp->prod_id, s);
 
990
    s = free_mem(s);
 
991
 
 
992
    entries = mem->data[0x22] + (mem->data[0x23] << 8);
 
993
    ADD2LOG("  base MP config table (%u entries):\n", entries);
 
994
    entry_cnt = 0;
 
995
    for(u = 0x2c; u < cfg_len - 1; u += len, entry_cnt++) {
 
996
      type = mem->data[u];
 
997
      len = type == 0 ? 20 : type <= 4 ? 8 : 16;
 
998
      ADD2LOG("  %stype %u, len %u\n    ", type > 4 ? "unknown ": "", type, len);
 
999
      if(len + u > cfg_len) len = cfg_len - u;
 
1000
      hexdump(&hd_data->log, 1, len, mem->data + u);
 
1001
      ADD2LOG("\n");
 
1002
      if(type > 4) break;
 
1003
      if(type == 0) {
 
1004
        smp->cpus++;
 
1005
        if((mem->data[u + 3] & 1)) smp->cpus_en++;
 
1006
      }
 
1007
    }
 
1008
    if(entry_cnt != entries) {
 
1009
      ADD2LOG("  oops: %u entries instead of %u found\n", entry_cnt, entries);
 
1010
    }
 
1011
  }
 
1012
 
 
1013
  if(xcfg_len) {
 
1014
    ADD2LOG("  extended MP config table:\n");
 
1015
    for(u = 0; u < xcfg_len - 2; u += len) {
 
1016
      type = mem->data[u + cfg_len];
 
1017
      len = mem->data[u + cfg_len + 1];
 
1018
      ADD2LOG("  type %u, len %u\n    ", type, len);
 
1019
      if(len + u > xcfg_len) len = xcfg_len - u;
 
1020
      hexdump(&hd_data->log, 1, len, mem->data + cfg_len + u);
 
1021
      ADD2LOG("\n");
 
1022
      if(len < 2) {
 
1023
        ADD2LOG("  oops: invalid record lenght\n");
 
1024
        break;
 
1025
      }
 
1026
    }
 
1027
  }
 
1028
}
 
1029
 
 
1030
 
 
1031
int get_bios32_info(hd_data_t *hd_data, memory_range_t *mem, bios32_info_t *bios32)
 
1032
{
 
1033
  unsigned u, ok;
 
1034
  unsigned addr = 0, len;
 
1035
 
 
1036
  if(mem->size < 0x10) return 0;
 
1037
 
 
1038
  for(u = ok = 0; u <= mem->size - 0x10; u += 0x10) {
 
1039
    if(*(unsigned *) (mem->data + u) == 0x5f32335f) {   /* "_32_" */
 
1040
      addr = *(unsigned *) (mem->data + u + 4);
 
1041
      len = mem->data[u + 9];
 
1042
      ok = len == 1 && crc(mem->data + u, 0x10) == 0 && addr < (1 << 20) ? 1 : 0;
 
1043
      ADD2LOG(
 
1044
        "  bios32: %svalid SD header at 0x%05x (size 0x%x, rev %u), SD at 0x%05x\n",
 
1045
        ok ? "" : "in", u + mem->start, len << 4, mem->data[u + 8], addr
 
1046
      );
 
1047
      if(ok) break;
 
1048
    }
 
1049
  }
 
1050
 
 
1051
  if(ok) {
 
1052
    bios32->ok = 1;
 
1053
    bios32->entry = addr;
 
1054
  }
 
1055
 
 
1056
  return ok;
 
1057
}
 
1058
 
 
1059
/**
 
1060
 * db format (32 bits):
 
1061
 * leaf: 1, last: 1, key: 6, range: 4, ofs: 20
 
1062
 */
 
1063
int tp_lookup(char *key_str, unsigned *width, unsigned *height, unsigned *xsize, unsigned *ysize)
 
1064
{
 
1065
  unsigned u;
 
1066
  unsigned key, range, ofs, last, leaf = 0;
 
1067
 
 
1068
  if(strlen(key_str) != 7) return 0;
 
1069
 
 
1070
  for(u = 0; u < 7; u++) {
 
1071
    if(key_str[u] < '0' || key_str[u] >= '0' + 64) return 0;
 
1072
  }
 
1073
 
 
1074
  for(u = 0; u < sizeof tp_db / sizeof *tp_db; u++) {
 
1075
    key = (tp_db[u] >> 24) & 0x3f;
 
1076
    range = (tp_db[u] >> 20) & 0xf;
 
1077
    ofs = tp_db[u] & ((1 << 20) - 1);
 
1078
    // printf("key = %d, range = %d, ofs = %d, str = %d\n", key, range, ofs, *key_str - '0');
 
1079
    if(*key_str - '0' >= key && *key_str - '0' <= key + range) {
 
1080
      // printf("match\n");
 
1081
      leaf = (tp_db[u] >> 31) & 1;
 
1082
      if(leaf) break;
 
1083
      key_str++;
 
1084
      // printf("%d\n", *key_str);
 
1085
      if(ofs >= sizeof tp_db / sizeof *tp_db || !*key_str) return 0;
 
1086
      u = ofs - 1;
 
1087
      // printf("next1 = %u\n", ofs);
 
1088
      continue;
 
1089
    }
 
1090
    else {
 
1091
      last = (tp_db[u] >> 30) & 1;
 
1092
      if(last) return 0;
 
1093
      // printf("next2 = %u\n", u + 1);
 
1094
    }
 
1095
  }
 
1096
 
 
1097
  if(leaf) {
 
1098
    if(ofs >= sizeof tp_values / sizeof *tp_values) return 0;
 
1099
    *width = tp_values[ofs].width;
 
1100
    *height = tp_values[ofs].height;
 
1101
    *xsize = tp_values[ofs].xsize;
 
1102
    *ysize = tp_values[ofs].ysize;
 
1103
  }
 
1104
 
 
1105
  return 1;
 
1106
}
 
1107
 
 
1108
#endif /* defined(__i386__) || defined (__x86_64__) */
 
1109
 
 
1110
/** @} */
 
1111