This commit was manufactured by cvs2svn to create tag
[opensuse:hwinfo.git] / src / hd / hd.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <stdarg.h>
6 #include <fcntl.h>
7 #include <signal.h>
8 #include <ctype.h>
9 #include <errno.h>
10 #include <dirent.h>
11 #include <sys/stat.h>
12 #include <sys/types.h>
13 #include <sys/wait.h>
14 #include <sys/time.h>
15 #include <sys/ioctl.h>
16 #include <sys/mount.h>
17 #include <linux/pci.h>
18 #include <linux/hdreg.h>
19
20 #ifndef BLKSSZGET
21 #define BLKSSZGET _IO(0x12,104)         /* get block device sector size */
22 #endif
23
24 #include "hd.h"
25 #include "hddb.h"
26 #include "hd_int.h"
27 #include "memory.h"
28 #include "isapnp.h"
29 #include "monitor.h"
30 #include "pci.h"
31 #include "cpu.h"
32 #include "misc.h"
33 #include "mouse.h"
34 #include "floppy.h"
35 #include "ide.h"
36 #include "scsi.h"
37 #include "cdrom.h"
38 #include "bios.h"
39 #include "serial.h"
40 #include "net.h"
41 #include "version.h"
42 #include "usb.h"
43 #include "adb.h"
44 #include "modem.h"
45 #include "parallel.h"
46 #include "isa.h"
47 #include "dac960.h"
48 #include "smart.h"
49 #include "isdn.h"
50 #include "kbd.h"
51 #include "prom.h"
52 #include "sbus.h"
53 #include "int.h"
54 #include "braille.h"
55 #include "sys.h"
56 #include "dasd.h"
57 #include "i2o.h"
58 #include "cciss.h"
59 #include "manual.h"
60 #include "fb.h"
61 #include "veth.h"
62 #include "partition.h"
63 #include "disk.h"
64 #include "ataraid.h"
65
66 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
67  * various functions commmon to all probing modules
68  *
69  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
70  */
71
72 #ifdef __i386__
73 #define HD_ARCH "ia32"
74 #endif
75
76 #ifdef __ia64__
77 #define HD_ARCH "ia64"
78 #endif
79
80 #ifdef __alpha__
81 #define HD_ARCH "axp"
82 #endif
83
84 #ifdef __PPC__
85 #define HD_ARCH "ppc"
86 #endif
87
88 #ifdef __sparc__
89 #define HD_ARCH "sparc"
90 #endif
91
92 #ifdef __s390x__
93 #define HD_ARCH "s390x"
94 #else
95 #ifdef __s390__
96 #define HD_ARCH "s390"
97 #endif
98 #endif
99
100 #ifdef __arm__
101 #define HD_ARCH "arm"
102 #endif
103
104 #ifdef __mips__
105 #define HD_ARCH "mips"
106 #endif
107
108 #ifdef __x86_64__
109 #define HD_ARCH "x86-64"
110 #endif
111
112 typedef struct disk_s {
113   struct disk_s *next;
114   unsigned crc;
115   unsigned crc_match:1;
116   unsigned hd_idx;
117   char *dev_name;
118   unsigned char *data;
119 } disk_t;
120
121 static struct s_pr_flags *get_pr_flags(enum probe_feature feature);
122 static void fix_probe_features(hd_data_t *hd_data);
123 static void set_probe_feature(hd_data_t *hd_data, enum probe_feature feature, unsigned val);
124 static void free_old_hd_entries(hd_data_t *hd_data);
125 static hd_t *free_hd_entry(hd_t *hd);
126 static hd_t *add_hd_entry2(hd_t **hd, hd_t *new_hd);
127 static void timeout_alarm_handler(int signal);
128 static void get_probe_env(hd_data_t *hd_data);
129 static void hd_scan_xtra(hd_data_t *hd_data);
130
131 static void test_read_block0_open(void *arg);
132 static void get_kernel_version(hd_data_t *hd_data);
133 static void assign_hw_class(hd_data_t *hd_data, hd_t *hd);
134 #ifndef LIBHD_TINY
135 static void short_vendor(char *vendor);
136 static void create_model_name(hd_data_t *hd_data, hd_t *hd);
137 #endif
138
139 static int is_pcmcia_ctrl(hd_data_t *hd_data, hd_t *hd);
140
141
142 /*
143  * Names of the probing modules.
144  * Cf. enum mod_idx in hd_int.h.
145  */
146 static struct s_mod_names {
147   unsigned val;
148   char *name;
149 } pr_modules[] = {
150   { mod_none, "none"},
151   { mod_memory, "memory"},
152   { mod_pci, "pci"},
153   { mod_isapnp, "isapnp"},
154   { mod_pnpdump, "pnpdump"},
155   { mod_cdrom, "cdrom"},
156   { mod_net, "net"},
157   { mod_floppy, "floppy"},
158   { mod_misc, "misc" },
159   { mod_bios, "bios"},
160   { mod_cpu, "cpu"},
161   { mod_monitor, "monitor"},
162   { mod_serial, "serial"},
163   { mod_mouse, "mouse"},
164   { mod_ide, "ide"},
165   { mod_scsi, "scsi"},
166   { mod_usb, "usb"},
167   { mod_adb, "adb"},
168   { mod_modem, "modem"},
169   { mod_parallel, "parallel" },
170   { mod_isa, "isa" },
171   { mod_dac960, "dac960" },
172   { mod_smart, "smart" },
173   { mod_isdn, "isdn" },
174   { mod_kbd, "kbd" },
175   { mod_prom, "prom" },
176   { mod_sbus, "sbus" },
177   { mod_int, "int" },
178   { mod_braille, "braille" },
179   { mod_xtra, "hd" },
180   { mod_sys, "sys" },
181   { mod_dasd, "dasd" },
182   { mod_i2o, "i2o" },
183   { mod_cciss, "cciss" },
184   { mod_manual, "manual" },
185   { mod_fb, "fb" },
186   { mod_veth, "veth" },
187   { mod_partition, "partition" },
188   { mod_disk, "disk" },
189   { mod_ataraid, "ataraid" }
190 };
191
192 /*
193  * Names for the probe flags. Used for debugging and command line parsing in
194  * hw.c. Cf. enum probe_feature, hd_data_t.probe.
195  */
196 static struct s_pr_flags {
197   enum probe_feature val, parent;
198   unsigned mask;        /* bit 0: default, bit 1: all, bit 2: max, bit 3: linuxrc */
199   char *name;
200 } pr_flags[] = {
201   { pr_default,     -1,                 1, "default"      },
202   { pr_all,         -1,               2  , "all"          },
203   { pr_max,         -1,             4    , "max"          },
204   { pr_lxrc,        -1,           8      , "lxrc"         },
205   { pr_memory,       0,           8|4|2|1, "memory"       },
206   { pr_pci,          0,           8|4|2|1, "pci"          },
207   { pr_pci_range,    pr_pci,        4|2  , "pci.range"    },
208   { pr_pci_ext,      pr_pci,        4|2  , "pci.ext"      },
209   { pr_isapnp,       0,             4|2|1, "isapnp"       },
210   { pr_isapnp_old,   pr_isapnp,         0, "isapnp.old"   },
211   { pr_isapnp_new,   pr_isapnp,         0, "isapnp.new"   },
212   { pr_isapnp_mod,   0,             4    , "isapnp.mod"   },
213   { pr_isapnp,       0,                 0, "pnpdump"      },    /* alias for isapnp */
214   { pr_cdrom,        0,           8|4|2|1, "cdrom"        },
215   { pr_cdrom_info,   pr_cdrom,    8|4|2|1, "cdrom.info"   },
216   { pr_net,          0,           8|4|2|1, "net"          },
217   { pr_floppy,       0,           8|4|2|1, "floppy"       },
218   { pr_misc,         pr_bios,     8|4|2|1, "misc"         },    // ugly hack!
219   { pr_misc_serial,  pr_misc,     8|4|2|1, "misc.serial"  },
220   { pr_misc_par,     pr_misc,       4|2|1, "misc.par"     },
221   { pr_misc_floppy,  pr_misc,     8|4|2|1, "misc.floppy"  },
222   { pr_bios,         0,           8|4|2|1, "bios"         },
223   { pr_bios_vbe,     pr_bios,       4|2|1, "bios.vbe"     },
224   { pr_bios_vbe2,    pr_bios,           0, "bios.vbe2"    },
225   { pr_cpu,          0,           8|4|2|1, "cpu"          },
226   { pr_monitor,      0,           8|4|2|1, "monitor"      },
227   { pr_serial,       0,             4|2|1, "serial"       },
228 #if defined(__sparc__)
229   /* Probe for mouse on SPARC */
230   { pr_mouse,        0,           8|4|2|1, "mouse"        },
231 #else
232   { pr_mouse,        0,             4|2|1, "mouse"        },
233 #endif
234   { pr_ide,          0,           8|4|2|1, "ide"          },
235   { pr_scsi,         0,           8|4|2|1, "scsi"         },
236   { pr_scsi_geo,     pr_scsi,       4|2  , "scsi.geo"     },
237   { pr_scsi_cache,   pr_scsi,       4|2|1, "scsi.cache"   },
238   { pr_usb,          0,           8|4|2|1, "usb"          },
239   { pr_usb_mods,     0,             4    , "usb.mods"     },
240   { pr_adb,          0,           8|4|2|1, "adb"          },
241   { pr_modem,        0,             4|2|1, "modem"        },
242   { pr_modem_usb,    pr_modem,      4|2|1, "modem.usb"    },
243   { pr_parallel,     0,             4|2|1, "parallel"     },
244   { pr_parallel_lp,  pr_parallel,   4|2|1, "parallel.lp"  },
245   { pr_parallel_zip, pr_parallel,   4|2|1, "parallel.zip" },
246   { pr_isa,          0,             4|2|1, "isa"          },
247   { pr_isa_isdn,     pr_isa,        4|2|1, "isa.isdn"     },
248   { pr_dac960,       0,           8|4|2|1, "dac960"       },
249   { pr_smart,        0,           8|4|2|1, "smart"        },
250   { pr_isdn,         0,             4|2|1, "isdn"         },
251   { pr_kbd,          0,           8|4|2|1, "kbd"          },
252   { pr_prom,         0,           8|4|2|1, "prom"         },
253   { pr_sbus,         0,           8|4|2|1, "sbus"         },
254   { pr_int,          0,           8|4|2|1, "int"          },
255 #if defined(__i386__) || defined (__x86_64__)
256   { pr_braille,      0,             4|2|1, "braille"      },
257   { pr_braille_alva, pr_braille,    4|2|1, "braille.alva" },
258   { pr_braille_fhp,  pr_braille,    4|2|1, "braille.fhp"  },
259   { pr_braille_ht,   pr_braille,    4|2|1, "braille.ht"   },
260   { pr_braille_baum, pr_braille,    4|2|1, "braille.baum" },
261 #else
262   { pr_braille,      0,             4|2  , "braille"      },
263   { pr_braille_alva, pr_braille,        0, "braille.alva" },
264   { pr_braille_fhp,  pr_braille,    4|2  , "braille.fhp"  },
265   { pr_braille_ht,   pr_braille,    4|2  , "braille.ht"   },
266   { pr_braille_baum, pr_braille,    4|2  , "braille.baum" },
267 #endif
268   { pr_ignx11,       0,                 0, "ignx11"       },
269   { pr_sys,          0,           8|4|2|1, "sys"          },
270   { pr_dasd,         0,           8|4|2|1, "dasd"         },
271   { pr_i2o,          0,           8|4|2|1, "i2o"          },
272   { pr_cciss,        0,           8|4|2|1, "cciss"        },
273   { pr_manual,       0,           8|4|2|1, "manual"       },
274   { pr_fb,           0,           8|4|2|1, "fb"           },
275   { pr_veth,         0,           8|4|2|1, "veth"         },
276   { pr_partition,    0,           8|4|2|1, "partition"    },
277   { pr_disk,         0,           8|4|2|1, "disk"         },
278   { pr_ataraid,      0,           8|4|2|1, "ataraid"      }
279 };
280
281 struct s_pr_flags *get_pr_flags(enum probe_feature feature)
282 {
283   int i;
284
285   for(i = 0; i < sizeof pr_flags / sizeof *pr_flags; i++) {
286     if(feature == pr_flags[i].val) return pr_flags + i;
287   }
288
289   return NULL;
290 }
291
292 void fix_probe_features(hd_data_t *hd_data)
293 {
294   int i;
295
296   for(i = 0; i < sizeof hd_data->probe; i++) {
297     hd_data->probe[i] |= hd_data->probe_set[i];
298     hd_data->probe[i] &= ~hd_data->probe_clr[i];
299   }
300 }
301
302 void set_probe_feature(hd_data_t *hd_data, enum probe_feature feature, unsigned val)
303 {
304   unsigned ofs, bit, mask;
305   int i;
306   struct s_pr_flags *pr;
307
308   if(!(pr = get_pr_flags(feature))) return;
309
310   if(pr->parent == -1) {
311     mask = pr->mask;
312     for(i = 0; i < sizeof pr_flags / sizeof *pr_flags; i++) {
313       if(pr_flags[i].parent != -1 && (pr_flags[i].mask & mask))
314         set_probe_feature(hd_data, pr_flags[i].val, val);
315     }
316   }
317   else {
318     ofs = feature >> 3; bit = feature & 7;
319     if(ofs < sizeof hd_data->probe) {
320       if(val) {
321         hd_data->probe_set[ofs] |= 1 << bit;
322         hd_data->probe_clr[ofs] &= ~(1 << bit);
323       }
324       else {
325         hd_data->probe_clr[ofs] |= 1 << bit;
326         hd_data->probe_set[ofs] &= ~(1 << bit);
327       }
328     }
329     if(pr->parent) set_probe_feature(hd_data, pr->parent, val);
330   }
331
332   fix_probe_features(hd_data);
333 }
334
335 void hd_set_probe_feature(hd_data_t *hd_data, enum probe_feature feature)
336 {
337   unsigned ofs, bit, mask;
338   int i;
339   struct s_pr_flags *pr;
340
341 #ifdef LIBHD_MEMCHECK
342   {
343     if(libhd_log)
344       fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_set_probe_feature, hd_data), hd_data);
345   }
346 #endif
347
348   if(!(pr = get_pr_flags(feature))) return;
349
350   if(pr->parent == -1) {
351     mask = pr->mask;
352     for(i = 0; i < sizeof pr_flags / sizeof *pr_flags; i++) {
353       if(pr_flags[i].parent != -1 && (pr_flags[i].mask & mask))
354         hd_set_probe_feature(hd_data, pr_flags[i].val);
355     }
356   }
357   else {
358     ofs = feature >> 3; bit = feature & 7;
359     if(ofs < sizeof hd_data->probe)
360       hd_data->probe[ofs] |= 1 << bit;
361     if(pr->parent) hd_set_probe_feature(hd_data, pr->parent);
362   }
363
364   fix_probe_features(hd_data);
365 }
366
367 void hd_clear_probe_feature(hd_data_t *hd_data, enum probe_feature feature)
368 {
369   unsigned ofs, bit, mask;
370   int i;
371   struct s_pr_flags *pr;
372
373 #ifdef LIBHD_MEMCHECK
374   {
375     if(libhd_log)
376       fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_clear_probe_feature, hd_data), hd_data);
377   }
378 #endif
379
380   if(!(pr = get_pr_flags(feature))) return;
381
382   if(pr->parent == -1) {
383     mask = pr->mask;
384     for(i = 0; i < sizeof pr_flags / sizeof *pr_flags; i++) {
385       if(pr_flags[i].parent != -1 && (pr_flags[i].mask & mask))
386         hd_clear_probe_feature(hd_data, pr_flags[i].val);
387     }
388   }
389   else {
390     ofs = feature >> 3; bit = feature & 7;
391     if(ofs < sizeof hd_data->probe)
392       hd_data->probe[ofs] &= ~(1 << bit);
393   }
394 }
395
396 int hd_probe_feature(hd_data_t *hd_data, enum probe_feature feature)
397 {
398 #ifdef LIBHD_MEMCHECK
399   {
400     if(libhd_log)
401       fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_probe_feature, hd_data), hd_data);
402   }
403 #endif
404
405   if(feature < 0 || feature >= pr_default) return 0;
406
407   return hd_data->probe[feature >> 3] & (1 << (feature & 7)) ? 1 : 0;
408 }
409
410
411 void hd_set_probe_feature_hw(hd_data_t *hd_data, hd_hw_item_t item)
412 {
413   hd_set_probe_feature(hd_data, pr_int);
414   hd_set_probe_feature(hd_data, pr_manual);
415
416   switch(item) {
417     case hw_cdrom:
418       hd_set_probe_feature(hd_data, pr_pci);
419       hd_set_probe_feature(hd_data, pr_usb);
420       hd_set_probe_feature(hd_data, pr_ide);
421       hd_set_probe_feature(hd_data, pr_scsi_cache);
422       hd_set_probe_feature(hd_data, pr_cdrom_info);
423       hd_set_probe_feature(hd_data, pr_partition);
424       break;
425
426     case hw_floppy:
427       hd_set_probe_feature(hd_data, pr_floppy);
428       hd_set_probe_feature(hd_data, pr_ide);
429       hd_set_probe_feature(hd_data, pr_scsi_cache);     // really necessary?
430       hd_set_probe_feature(hd_data, pr_misc_floppy);
431       hd_set_probe_feature(hd_data, pr_prom);
432       hd_set_probe_feature(hd_data, pr_pci);
433       hd_set_probe_feature(hd_data, pr_usb);
434       hd_set_probe_feature(hd_data, pr_partition);
435       break;
436
437     case hw_disk:
438       hd_set_probe_feature(hd_data, pr_pci);
439       hd_set_probe_feature(hd_data, pr_ide);
440       hd_set_probe_feature(hd_data, pr_scsi_cache);
441 //      hd_set_probe_feature(hd_data, pr_scsi_geo);
442       hd_set_probe_feature(hd_data, pr_dac960);
443       hd_set_probe_feature(hd_data, pr_smart);
444 //      hd_set_probe_feature(hd_data, pr_i2o);
445 //      hd_set_probe_feature(hd_data, pr_cciss);
446       hd_set_probe_feature(hd_data, pr_dasd);
447       hd_set_probe_feature(hd_data, pr_partition);
448       hd_set_probe_feature(hd_data, pr_disk);
449       hd_set_probe_feature(hd_data, pr_ataraid);
450       break;
451
452     case hw_network:
453       hd_set_probe_feature(hd_data, pr_net);
454       break;
455
456     case hw_display:
457       hd_set_probe_feature(hd_data, pr_pci);
458       hd_set_probe_feature(hd_data, pr_sbus);
459       hd_set_probe_feature(hd_data, pr_prom);
460       hd_set_probe_feature(hd_data, pr_misc);           /* for isa cards */
461       break;
462
463     case hw_monitor:
464       hd_set_probe_feature(hd_data, pr_misc);
465       hd_set_probe_feature(hd_data, pr_prom);
466       hd_set_probe_feature(hd_data, pr_pci);
467       hd_set_probe_feature(hd_data, pr_bios_vbe);
468       hd_set_probe_feature(hd_data, pr_fb);
469       hd_set_probe_feature(hd_data, pr_monitor);
470       break;
471
472     case hw_framebuffer:
473       hd_set_probe_feature(hd_data, pr_misc);
474       hd_set_probe_feature(hd_data, pr_prom);
475       hd_set_probe_feature(hd_data, pr_pci);
476       hd_set_probe_feature(hd_data, pr_bios_vbe);
477       hd_set_probe_feature(hd_data, pr_fb);
478       break;
479
480     case hw_mouse:
481       hd_set_probe_feature(hd_data, pr_misc);
482       if(!hd_data->flags.fast) {
483         hd_set_probe_feature(hd_data, pr_serial);
484       }
485       hd_set_probe_feature(hd_data, pr_adb);
486       hd_set_probe_feature(hd_data, pr_usb);
487       hd_set_probe_feature(hd_data, pr_kbd);
488       hd_set_probe_feature(hd_data, pr_sys);
489       hd_set_probe_feature(hd_data, pr_bios);
490       hd_set_probe_feature(hd_data, pr_mouse);
491       break;
492
493     case hw_joystick:
494       hd_set_probe_feature(hd_data, pr_usb);
495       break;
496
497     case hw_chipcard:
498       hd_set_probe_feature(hd_data, pr_misc);
499       if(!hd_data->flags.fast) {
500         hd_set_probe_feature(hd_data, pr_serial);
501       }
502       hd_set_probe_feature(hd_data, pr_usb);
503       hd_set_probe_feature(hd_data, pr_mouse);          /* we need the pnp code */
504       break;
505
506     case hw_camera:
507       hd_set_probe_feature(hd_data, pr_usb);
508       break;
509
510     case hw_keyboard:
511       hd_set_probe_feature(hd_data, pr_cpu);
512       hd_set_probe_feature(hd_data, pr_misc);
513       hd_set_probe_feature(hd_data, pr_adb);
514       hd_set_probe_feature(hd_data, pr_usb);
515       hd_set_probe_feature(hd_data, pr_kbd);
516 #ifdef __PPC__
517       hd_set_probe_feature(hd_data, pr_serial);
518 #endif
519       break;
520
521     case hw_sound:
522       hd_set_probe_feature(hd_data, pr_misc);
523       hd_set_probe_feature(hd_data, pr_pci);
524       hd_set_probe_feature(hd_data, pr_isapnp);
525       hd_set_probe_feature(hd_data, pr_isapnp_mod);
526       hd_set_probe_feature(hd_data, pr_sbus);
527 #ifdef __PPC__
528       hd_set_probe_feature(hd_data, pr_prom);
529 #endif
530       break;
531
532     case hw_isdn:
533       hd_set_probe_feature(hd_data, pr_misc);           /* get basic i/o res */
534       hd_set_probe_feature(hd_data, pr_pci);
535       hd_set_probe_feature(hd_data, pr_isapnp);
536       hd_set_probe_feature(hd_data, pr_isapnp_mod);
537       hd_set_probe_feature(hd_data, pr_isa_isdn);
538       hd_set_probe_feature(hd_data, pr_usb);
539       hd_set_probe_feature(hd_data, pr_isdn);
540       break;
541
542     case hw_modem:
543       hd_set_probe_feature(hd_data, pr_misc);
544       hd_set_probe_feature(hd_data, pr_serial);
545       hd_set_probe_feature(hd_data, pr_usb);
546       hd_set_probe_feature(hd_data, pr_modem);
547       hd_set_probe_feature(hd_data, pr_modem_usb);
548       break;
549
550     case hw_storage_ctrl:
551       hd_set_probe_feature(hd_data, pr_floppy);
552       hd_set_probe_feature(hd_data, pr_sys);
553       hd_set_probe_feature(hd_data, pr_pci);
554       hd_set_probe_feature(hd_data, pr_sbus);
555       if(!hd_data->flags.fast) {
556         hd_set_probe_feature(hd_data, pr_misc_par);
557         hd_set_probe_feature(hd_data, pr_parallel_zip);
558       }
559       hd_set_probe_feature(hd_data, pr_dasd);           /* dasd on s390 */
560 #ifdef __PPC__
561       hd_set_probe_feature(hd_data, pr_prom);
562       hd_set_probe_feature(hd_data, pr_misc);
563       hd_set_probe_feature(hd_data, pr_ide);            /* dasd on iseries */
564 #endif
565       break;
566
567     case hw_network_ctrl:
568       hd_set_probe_feature(hd_data, pr_misc);
569       hd_set_probe_feature(hd_data, pr_pci);
570       hd_set_probe_feature(hd_data, pr_isapnp);
571       hd_set_probe_feature(hd_data, pr_isapnp_mod);
572       hd_set_probe_feature(hd_data, pr_sbus);
573       hd_set_probe_feature(hd_data, pr_isdn);
574 #ifdef __PPC__
575       hd_set_probe_feature(hd_data, pr_prom);
576 #endif
577 #if defined(__s390__) || defined(__s390x__)
578       hd_set_probe_feature(hd_data, pr_net);
579 #endif
580       hd_set_probe_feature(hd_data, pr_veth);
581       break;
582
583     case hw_printer:
584       hd_set_probe_feature(hd_data, pr_sys);
585       hd_set_probe_feature(hd_data, pr_bios);
586       hd_set_probe_feature(hd_data, pr_misc_par);
587       hd_set_probe_feature(hd_data, pr_parallel_lp);
588       hd_set_probe_feature(hd_data, pr_usb);
589       break;
590
591     case hw_tv:
592     case hw_dvb:
593       hd_set_probe_feature(hd_data, pr_pci);
594       break;
595
596     case hw_scanner:
597       hd_set_probe_feature(hd_data, pr_usb); 
598       hd_set_probe_feature(hd_data, pr_scsi); 
599       hd_set_probe_feature(hd_data, pr_partition);
600       break;
601
602     case hw_braille:
603       hd_set_probe_feature(hd_data, pr_misc_serial);
604       hd_set_probe_feature(hd_data, pr_serial);
605       hd_set_probe_feature(hd_data, pr_braille_alva);
606       hd_set_probe_feature(hd_data, pr_braille_fhp);
607       hd_set_probe_feature(hd_data, pr_braille_ht);
608       hd_set_probe_feature(hd_data, pr_braille_baum);
609       break;
610
611     case hw_sys:
612       hd_set_probe_feature(hd_data, pr_bios);
613       hd_set_probe_feature(hd_data, pr_prom);
614       hd_set_probe_feature(hd_data, pr_sys);
615       break;
616
617     case hw_cpu:
618       hd_set_probe_feature(hd_data, pr_cpu);
619       break;
620
621     case hw_bios:
622       hd_set_probe_feature(hd_data, pr_bios);
623       break;
624
625     case hw_manual:
626       hd_set_probe_feature(hd_data, pr_manual);
627       break;
628
629     case hw_usb_ctrl:
630     case hw_pcmcia_ctrl:
631     case hw_ieee1394_ctrl:
632     case hw_hotplug_ctrl:
633       hd_set_probe_feature(hd_data, pr_misc);
634       hd_set_probe_feature(hd_data, pr_pci);
635       break;
636
637     case hw_usb:
638       hd_set_probe_feature(hd_data, pr_usb);
639       hd_set_probe_feature(hd_data, pr_isdn);   // need pr_misc, too?
640       hd_set_probe_feature(hd_data, pr_scsi);
641       hd_set_probe_feature(hd_data, pr_partition);
642       hd_data->flags.fast = 1;
643       break;
644
645     case hw_pci:
646       hd_set_probe_feature(hd_data, pr_misc);
647       hd_set_probe_feature(hd_data, pr_pci);
648       hd_set_probe_feature(hd_data, pr_isdn);
649 #ifdef __PPC__
650       hd_set_probe_feature(hd_data, pr_prom);
651 #endif
652       break;
653
654     case hw_isapnp:
655       hd_set_probe_feature(hd_data, pr_isapnp);
656       hd_set_probe_feature(hd_data, pr_isapnp_mod);
657       hd_set_probe_feature(hd_data, pr_misc);
658       hd_set_probe_feature(hd_data, pr_isdn);
659       break;
660
661     case hw_bridge:
662       hd_set_probe_feature(hd_data, pr_misc);
663       hd_set_probe_feature(hd_data, pr_pci);
664       break;
665
666     case hw_hub:
667       hd_set_probe_feature(hd_data, pr_usb); 
668       break;
669
670     case hw_memory:
671       hd_set_probe_feature(hd_data, pr_memory); 
672       break;
673
674     case hw_scsi:
675       hd_set_probe_feature(hd_data, pr_usb);
676       hd_set_probe_feature(hd_data, pr_scsi_cache);
677       hd_set_probe_feature(hd_data, pr_ide);
678       hd_set_probe_feature(hd_data, pr_partition);
679       hd_set_probe_feature(hd_data, pr_cdrom);
680       break;
681
682     case hw_ide:
683       hd_set_probe_feature(hd_data, pr_ide);
684       hd_set_probe_feature(hd_data, pr_scsi);
685       hd_set_probe_feature(hd_data, pr_cdrom);
686       hd_set_probe_feature(hd_data, pr_partition);
687       break;
688
689     case hw_all:
690     case hw_unknown:
691     case hw_partition:
692     case hw_pcmcia:
693     case hw_ieee1394:
694     case hw_hotplug:
695     case hw_zip:
696       break;
697   }
698 }
699
700
701 /*
702  * Free all data associated with a hd_data_t struct. *Not* the struct itself.
703  */
704 hd_data_t *hd_free_hd_data(hd_data_t *hd_data)
705 {
706   hddb_pci_t *p;
707
708 #ifdef LIBHD_MEMCHECK
709   {
710     if(libhd_log)
711       fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_free_hd_data, hd_data), hd_data);
712   }
713 #endif
714
715   add_hd_entry2(&hd_data->old_hd, hd_data->hd); hd_data->hd = NULL;
716   hd_data->log = free_mem(hd_data->log);
717   free_old_hd_entries(hd_data);         /* hd_data->old_hd */
718   /* hd_data->pci is always NULL */
719   /* hd_data->isapnp->card is always NULL */
720   hd_data->isapnp = free_mem(hd_data->isapnp);
721   /* hd_data->cdrom is always NULL */
722   hd_data->net = free_str_list(hd_data->net);
723   hd_data->floppy = free_str_list(hd_data->floppy);
724   hd_data->misc = free_misc(hd_data->misc);
725   /* hd_data->serial is always NULL */
726   /* hd_data->scsi is always NULL */
727   /* hd_data->ser_mouse is always NULL */
728   /* hd_data->ser_modem is always NULL */
729   hd_data->cpu = free_str_list(hd_data->cpu);
730   hd_data->klog = free_str_list(hd_data->klog);
731   hd_data->proc_usb = free_str_list(hd_data->proc_usb);
732   /* hd_data->usb is always NULL */
733
734   if((p = hd_data->hddb_pci)) {
735     for(; p->module; p++) free_mem(p->module);
736   }
737   if(hd_data->hddb2[0]) {
738     free_mem(hd_data->hddb2[0]->list);
739     free_mem(hd_data->hddb2[0]->ids); 
740     free_mem(hd_data->hddb2[0]->strings);
741     hd_data->hddb2[0] = free_mem(hd_data->hddb2[0]);
742   }
743   /* hddb2[1] is the static internal database; don't try to free it! */
744   hd_data->hddb2[1] = NULL;
745
746   hd_data->hddb_pci = free_mem(hd_data->hddb_pci);
747   hd_data->kmods = free_str_list(hd_data->kmods);
748   hd_data->bios_rom.data = free_mem(hd_data->bios_rom.data);
749   hd_data->bios_ram.data = free_mem(hd_data->bios_ram.data);
750   hd_data->bios_ebda.data = free_mem(hd_data->bios_ebda.data);
751   hd_data->cmd_line = free_mem(hd_data->cmd_line);
752   hd_data->xtra_hd = free_str_list(hd_data->xtra_hd);
753   hd_data->devtree = free_devtree(hd_data);
754   hd_data->manual = hd_free_manual(hd_data->manual);
755   hd_data->disks = free_str_list(hd_data->disks);
756   hd_data->partitions = free_str_list(hd_data->partitions);
757
758   hd_data->smbios = free_smbios_list(hd_data->smbios);
759
760   hd_data->last_idx = 0;
761
762   return NULL;
763 }
764
765
766 /*
767  * Free all data associated with a driver_info_t struct. Even the struct itself.
768  */
769 driver_info_t *free_driver_info(driver_info_t *di)
770 {
771   driver_info_t *next;
772
773 #ifdef LIBHD_MEMCHECK
774   {
775     if(libhd_log)
776       fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(free_driver_info, di), di);
777   }
778 #endif
779
780   for(; di; di = next) {
781     next = di->next;
782
783     switch(di->any.type) {
784       case di_any:
785       case di_display:
786         break;
787
788       case di_module:
789         free_str_list(di->module.names);
790         free_str_list(di->module.mod_args);
791         free_mem(di->module.conf);
792         break;
793
794       case di_mouse:
795         free_mem(di->mouse.xf86);
796         free_mem(di->mouse.gpm);
797         break;
798
799       case di_x11:
800         free_mem(di->x11.server);
801         free_mem(di->x11.xf86_ver);
802         free_str_list(di->x11.extensions);
803         free_str_list(di->x11.options);
804         free_str_list(di->x11.raw);
805         free_mem(di->x11.script);
806         break;
807
808       case di_isdn:
809         free_mem(di->isdn.i4l_name);
810         if(di->isdn.params) {
811           isdn_parm_t *p = di->isdn.params, *next;
812           for(; p; p = next) {
813             next = p->next;
814             free_mem(p->name);
815             free_mem(p->alt_value);
816             free_mem(p);
817           }
818         }
819         break;
820
821       case di_kbd:
822         free_mem(di->kbd.XkbRules);
823         free_mem(di->kbd.XkbModel);
824         free_mem(di->kbd.XkbLayout);
825         free_mem(di->kbd.keymap);
826         break;
827     }
828
829     free_str_list(di->any.hddb0);
830     free_str_list(di->any.hddb1);
831
832     free_mem(di);
833   }
834
835   return NULL;
836 }
837
838
839 int exists_hd_entry(hd_data_t *hd_data, hd_t *old_hd, hd_t *hd_ex)
840 {
841   hd_t *hd;
842
843   if(!hd_ex) return 0;
844
845   for(hd = hd_data->hd; hd; hd = hd->next) {
846     if(hd == hd_ex) return 1;
847   }
848   for(hd = old_hd; hd; hd = hd->next) {
849     if(hd == hd_ex) return 1;
850   }
851
852   return 0;
853 }
854
855
856 /*!
857  * \note This may not free it.
858  */
859 hd_t *hd_free_hd_list(hd_t *hd)
860 {
861   hd_t *h;
862
863 #ifdef LIBHD_MEMCHECK
864   {
865     if(libhd_log)
866       fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_free_hd_list, hd), hd);
867   }
868 #endif
869
870   /* Note: hd->next should better be NULL! */
871   if(hd && hd->tag.freeit) {
872     free_hd_entry(hd);
873     return free_mem(hd);
874   }
875
876   /* do nothing unless the list holds only copies of hd_t entries */
877   for(h = hd; h; h = h->next) if(!h->ref) return NULL;
878
879   for(; hd; hd = (h = hd)->next, free_mem(h));
880
881   return NULL;
882 }
883
884 hd_detail_t *free_hd_detail(hd_detail_t *d)
885 {
886   if(!d) return NULL;
887
888   switch(d->type) {
889     case hd_detail_pci: {
890         pci_t *p = d->pci.data;
891
892         free_mem(p->log);
893         free_mem(p);
894       }
895       break;
896
897     case hd_detail_usb:
898       {
899         usb_t *u = d->usb.data;
900
901         free_str_list(u->b);
902         free_str_list(u->c);
903         free_str_list(u->ci);
904         free_str_list(u->d);
905         free_str_list(u->e);
906         free_str_list(u->i);
907         free_str_list(u->p);
908         free_str_list(u->s);
909         free_str_list(u->t);
910
911         free_mem(u->manufact);
912         free_mem(u->product);
913         free_mem(u->serial);
914         free_mem(u->driver);
915
916         free_mem(u);
917       }
918       break;
919
920     case hd_detail_isapnp:
921       {
922         isapnp_dev_t *i = d->isapnp.data;
923         int j;
924
925         if(!i->ref) {
926           free_mem(i->card->serial);
927           free_mem(i->card->card_regs);
928           free_mem(i->card->ldev_regs);
929           for(j = 0; j < i->card->res_len; j++) {
930             free_mem(i->card->res[j].data);
931           }
932           if(i->card->res) free_mem(i->card->res);
933         }
934         free_mem(i->card);
935         free_mem(i);
936       }
937       break;
938
939     case hd_detail_cdrom:
940       {
941         cdrom_info_t *c = d->cdrom.data;
942
943         free_mem(c->name);
944         free_mem(c->iso9660.volume);
945         free_mem(c->iso9660.publisher);
946         free_mem(c->iso9660.preparer);
947         free_mem(c->iso9660.application);
948         free_mem(c->iso9660.creation_date);
949         free_mem(c->el_torito.id_string);
950         free_mem(c->el_torito.label);
951
952         free_mem(c);
953       }
954       break;
955
956     case hd_detail_floppy:
957       free_mem(d->floppy.data);
958       break;
959
960     case hd_detail_bios:
961       {
962         bios_info_t *b = d->bios.data;
963
964         free_mem(b->vbe.oem_name);
965         free_mem(b->vbe.vendor_name);
966         free_mem(b->vbe.product_name);
967         free_mem(b->vbe.product_revision);
968         free_mem(b->vbe.mode);
969         free_mem(b->lcd.vendor);
970         free_mem(b->lcd.name);
971         free_mem(b->mouse.vendor);
972         free_mem(b->mouse.type);
973
974         free_mem(b);
975       }
976       break;
977
978     case hd_detail_cpu:
979       {
980         cpu_info_t *c = d->cpu.data;
981
982         free_mem(c->vend_name);
983         free_mem(c->model_name);
984         free_mem(c->platform);
985         free_str_list(c->features);
986         free_mem(c);
987       }
988       break;
989
990     case hd_detail_prom:
991       free_mem(d->prom.data);
992       break;
993
994     case hd_detail_monitor:
995       {
996         monitor_info_t *m = d->monitor.data;
997
998         free_mem(m->vendor);
999         free_mem(m->name);
1000         free_mem(m->serial);
1001
1002         free_mem(m);
1003       }
1004       break;
1005
1006     case hd_detail_sys:
1007       {
1008         sys_info_t *s = d->sys.data;
1009
1010         free_mem(s->system_type);
1011         free_mem(s->generation);
1012         free_mem(s->vendor);
1013         free_mem(s->model);
1014         free_mem(s->serial);
1015         free_mem(s->lang);
1016
1017         free_mem(s);
1018       }
1019       break;
1020
1021     case hd_detail_scsi:
1022       free_scsi(d->scsi.data, 1);
1023       break;
1024
1025     case hd_detail_devtree:
1026       /* is freed with hd_data->dev_tree */
1027       break;
1028   }
1029
1030   free_mem(d);
1031
1032   return NULL;
1033 }
1034
1035
1036 hd_t *free_hd_entry(hd_t *hd)
1037 {
1038   free_mem(hd->bus.name);
1039   free_mem(hd->base_class.name);
1040   free_mem(hd->sub_class.name);
1041   free_mem(hd->prog_if.name);
1042   free_mem(hd->vendor.name);
1043   free_mem(hd->device.name);
1044   free_mem(hd->sub_vendor.name);
1045   free_mem(hd->sub_device.name);
1046   free_mem(hd->revision.name);
1047   free_mem(hd->serial);
1048   free_mem(hd->compat_vendor.name);
1049   free_mem(hd->compat_device.name);
1050   free_mem(hd->model);
1051   free_mem(hd->unix_dev_name);
1052   free_mem(hd->rom_id);
1053   free_mem(hd->unique_id);
1054   free_mem(hd->block0);
1055   free_mem(hd->driver);
1056   free_mem(hd->old_unique_id);
1057   free_mem(hd->unique_id1);
1058   free_mem(hd->usb_guid);
1059   free_mem(hd->parent_id);
1060   free_mem(hd->config_string);
1061   free_str_list(hd->extra_info);
1062
1063   free_res_list(hd->res);
1064
1065   free_hd_detail(hd->detail);
1066
1067   free_driver_info(hd->driver_info);
1068   free_str_list(hd->requires);
1069
1070   memset(hd, 0, sizeof *hd);
1071
1072   return NULL;
1073 }
1074
1075 misc_t *free_misc(misc_t *m)
1076 {
1077   int i, j;
1078
1079   if(!m) return NULL;
1080
1081   for(i = 0; i < m->io_len; i++) {
1082     free_mem(m->io[i].dev);
1083   }
1084   free_mem(m->io);
1085
1086   for(i = 0; i < m->dma_len; i++) {
1087     free_mem(m->dma[i].dev);
1088   }
1089   free_mem(m->dma);
1090
1091   for(i = 0; i < m->irq_len; i++) {
1092     for(j = 0; j < m->irq[i].devs; j++) {
1093       free_mem(m->irq[i].dev[j]);
1094     }
1095     free_mem(m->irq[i].dev);
1096   }
1097   free_mem(m->irq);
1098
1099   free_str_list(m->proc_io);
1100   free_str_list(m->proc_dma);
1101   free_str_list(m->proc_irq);
1102
1103   free_mem(m);
1104
1105   return NULL;
1106 }
1107
1108 scsi_t *free_scsi(scsi_t *scsi, int free_all)
1109 {
1110   scsi_t *next;
1111
1112   for(; scsi; scsi = next) {
1113     next = scsi->next;
1114
1115     free_mem(scsi->dev_name);
1116     free_mem(scsi->guessed_dev_name);
1117     free_mem(scsi->vendor);
1118     free_mem(scsi->model);
1119     free_mem(scsi->rev);
1120     free_mem(scsi->type_str);
1121     free_mem(scsi->serial);
1122     free_mem(scsi->proc_dir);
1123     free_mem(scsi->driver);
1124     free_mem(scsi->info);
1125     free_mem(scsi->usb_guid);
1126     free_str_list(scsi->host_info);
1127
1128     if(!free_all) {
1129       next = scsi->next;
1130       memset(scsi, 0, sizeof scsi);
1131       scsi->next = next;
1132       break;
1133     }
1134
1135     free_mem(scsi);
1136   }
1137
1138   return NULL;
1139 }
1140
1141
1142 hd_manual_t *hd_free_manual(hd_manual_t *manual)
1143 {
1144   hd_manual_t *next;
1145
1146   if(!manual) return NULL;
1147
1148   for(; manual; manual = next) {
1149     next = manual->next;
1150
1151     free_mem(manual->unique_id);
1152     free_mem(manual->parent_id);
1153     free_mem(manual->model);
1154
1155     free_mem(manual->config_string);
1156
1157     free_str_list(manual->key);
1158     free_str_list(manual->value);
1159
1160     free_mem(manual);
1161   }
1162
1163   return NULL;
1164 }
1165
1166
1167 /*
1168  * Removes all hd_data->old_hd entries and frees their memory.
1169  */
1170 void free_old_hd_entries(hd_data_t *hd_data)
1171 {
1172   hd_t *hd, *next;
1173
1174   for(hd = hd_data->old_hd; hd; hd = next) {
1175     next = hd->next;
1176
1177     if(exists_hd_entry(hd_data, next, hd->ref) && hd->ref->ref_cnt) hd->ref->ref_cnt--;
1178
1179     if(!hd->ref) free_hd_entry(hd);
1180
1181     free_mem(hd);
1182   }
1183
1184   hd_data->old_hd = NULL;
1185 }
1186
1187
1188 void *new_mem(size_t size)
1189 {
1190   void *p;
1191
1192   if(size == 0) return NULL;
1193
1194   p = calloc(size, 1);
1195
1196 #ifdef LIBHD_MEMCHECK
1197   {
1198     if(libhd_log) fprintf(libhd_log, "%p\t%p\t0x%x\n", CALLED_FROM(new_mem, size), p, size);
1199   }
1200 #endif
1201
1202   if(p) return p;
1203
1204   fprintf(stderr, "memory oops 1\n");
1205   exit(11);
1206   /*NOTREACHED*/
1207   return 0;
1208 }
1209
1210 void *resize_mem(void *p, size_t n)
1211 {
1212 #ifdef LIBHD_MEMCHECK
1213   {
1214     if(libhd_log && p) fprintf(libhd_log, "%p\t%p\n", CALLED_FROM(resize_mem, p), p);
1215   }
1216 #endif
1217
1218   p = realloc(p, n);
1219
1220 #ifdef LIBHD_MEMCHECK
1221   {
1222     if(libhd_log) fprintf(libhd_log, "%p\t%p\t0x%x\n", CALLED_FROM(resize_mem, p), p, n);
1223   }
1224 #endif
1225
1226   if(!p) {
1227     fprintf(stderr, "memory oops 7\n");
1228     exit(17);
1229   }
1230
1231   return p;
1232 }
1233
1234 void *add_mem(void *p, size_t elem_size, size_t n)
1235 {
1236 #ifdef LIBHD_MEMCHECK
1237   {
1238     if(libhd_log && p) fprintf(libhd_log, "%p\t%p\n", CALLED_FROM(add_mem, p), p);
1239   }
1240 #endif
1241
1242   p = realloc(p, (n + 1) * elem_size);
1243
1244 #ifdef LIBHD_MEMCHECK
1245   {
1246     if(libhd_log) fprintf(libhd_log, "%p\t%p\t0x%x\n", CALLED_FROM(add_mem, p), p, (n + 1) * elem_size);
1247   }
1248 #endif
1249
1250   if(!p) {
1251     fprintf(stderr, "memory oops 7\n");
1252     exit(17);
1253   }
1254
1255   memset(p + n * elem_size, 0, elem_size);
1256
1257   return p;
1258 }
1259
1260 char *new_str(const char *s)
1261 {
1262   char *t;
1263
1264   if(!s) return NULL;
1265
1266   t = strdup(s);
1267
1268 #ifdef LIBHD_MEMCHECK
1269   {
1270     if(libhd_log) fprintf(libhd_log, "%p\t%p\t0x%x\n", CALLED_FROM(new_str, s), t, strlen(t) + 1);
1271   }
1272 #endif
1273
1274   if(t) return t;
1275
1276   fprintf(stderr, "memory oops 2\n");
1277   /*NOTREACHED*/
1278   exit(12);
1279
1280   return NULL;
1281 }
1282
1283 void *free_mem(void *p)
1284 {
1285 #ifdef LIBHD_MEMCHECK
1286   {
1287     if(libhd_log && p) fprintf(libhd_log, "%p\t%p\n", CALLED_FROM(free_mem, p), p);
1288   }
1289 #endif
1290
1291   if(p) free(p);
1292
1293   return NULL;
1294 }
1295
1296 void join_res_io(hd_res_t **res1, hd_res_t *res2)
1297 {
1298   hd_res_t *res;
1299
1300   /*
1301    * see if we must add an i/o range (tricky...)
1302    *
1303    * We look for identical i/o bases and add a range if one was missing. If
1304    * no matching pair was found, add the i/o resource.
1305    */
1306   for(; res2; res2 = res2->next) {
1307     if(res2->io.type == res_io) {
1308       for(res = *res1; res; res = res->next) {
1309         if(res->io.type == res_io) {
1310           if(res->io.base == res2->io.base) {
1311             /* identical bases: take maximum of both ranges */
1312             if(res2->io.range > res->io.range) {
1313               res->io.range = res2->io.range;
1314             }
1315             break;
1316           }
1317           else if(
1318             res->io.range &&
1319             res2->io.range &&
1320             res->io.base + res->io.range == res2->io.base)
1321           {
1322             /* res2 directly follows res1: extend res1 to cover res2 */
1323             res->io.range += res2->io.range;
1324             break;
1325           }
1326           else if(
1327             res2->io.base >= res->io.base &&
1328             res2->io.base < res->io.base + res->io.range
1329           ) {
1330             /* res2 is totally contained in res1: ignore it */
1331             break;
1332           }
1333         }
1334       }
1335       if(!res) {
1336         res = add_res_entry(res1, new_mem(sizeof *res));
1337         *res = *res2;   /* *copy* the struct */
1338         res->next = NULL;
1339       }
1340     }
1341   }
1342 }
1343
1344 void join_res_irq(hd_res_t **res1, hd_res_t *res2)
1345 {
1346   hd_res_t *res;
1347
1348   /* see if we must add an dma channel */
1349   for(; res2; res2 = res2->next) {
1350     if(res2->irq.type == res_irq) {
1351       for(res = *res1; res; res = res->next) {
1352         if(res->irq.type == res_irq && res->irq.base == res2->irq.base) break;
1353       }
1354       if(!res) {
1355         res = add_res_entry(res1, new_mem(sizeof *res));
1356         *res = *res2;   /* *copy* the struct */
1357         res->next = NULL;
1358       }
1359     }
1360   }
1361 }
1362
1363
1364 void join_res_dma(hd_res_t **res1, hd_res_t *res2)
1365 {
1366   hd_res_t *res;
1367
1368   /* see if we must add an dma channel */
1369   for(; res2; res2 = res2->next) {
1370     if(res2->dma.type == res_dma) {
1371       for(res = *res1; res; res = res->next) {
1372         if(res->dma.type == res_dma && res->dma.base == res2->dma.base) break;
1373       }
1374       if(!res) {
1375         res = add_res_entry(res1, new_mem(sizeof *res));
1376         *res = *res2;   /* *copy* the struct */
1377         res->next = NULL;
1378       }
1379     }
1380   }
1381 }
1382
1383
1384 /*
1385  * Check whether both resource lists have common entries.
1386  */
1387 int have_common_res(hd_res_t *res1, hd_res_t *res2)
1388 {
1389   hd_res_t *res;
1390
1391   for(; res1; res1 = res1->next) {
1392     for(res = res2; res; res = res->next) {
1393       if(res->any.type == res1->any.type) {
1394         switch(res->any.type) {
1395           case res_io:
1396             if(res->io.base == res1->io.base) return 1;
1397             break;
1398
1399           case res_irq:
1400             if(res->irq.base == res1->irq.base) return 1;
1401             break;
1402
1403           case res_dma:
1404             if(res->dma.base == res1->dma.base) return 1;
1405             break;
1406
1407           default: /* gcc -Wall */
1408             break;
1409         }
1410       }
1411     }
1412   }
1413
1414   return 0;
1415 }
1416
1417
1418 /*
1419  * Free the memory allocated by a resource list.
1420  */
1421 hd_res_t *free_res_list(hd_res_t *res)
1422 {
1423   hd_res_t *next;
1424
1425   for(; res; res = next) {
1426     next = res->next;
1427
1428     if(res->any.type == res_init_strings) {
1429       free_mem(res->init_strings.init1);
1430       free_mem(res->init_strings.init2);
1431     }
1432
1433     if(res->any.type == res_pppd_option) {
1434       free_mem(res->pppd_option.option);
1435     }
1436
1437     free_mem(res);
1438   }
1439
1440   return NULL;
1441 }
1442
1443
1444 /*
1445  * Note: new_res is directly inserted into the list, so you *must* make sure
1446  * that new_res points to a malloc'ed pice of memory.
1447  */
1448 hd_res_t *add_res_entry(hd_res_t **res, hd_res_t *new_res)
1449 {
1450   while(*res) res = &(*res)->next;
1451
1452   return *res = new_res;
1453 }
1454
1455
1456 /*
1457  * Free the memory allocated by a smbios list.
1458  */
1459 hd_smbios_t *free_smbios_list(hd_smbios_t *sm)
1460 {
1461   hd_smbios_t *next;
1462   int i;
1463
1464   for(; sm; sm = next) {
1465     next = sm->next;
1466
1467     free_mem(sm->any.data);
1468     free_str_list(sm->any.strings);
1469
1470     switch(sm->any.type) {
1471       case sm_biosinfo:
1472         free_mem(sm->biosinfo.vendor);
1473         free_mem(sm->biosinfo.version);
1474         free_mem(sm->biosinfo.date);
1475         break;
1476
1477       case sm_sysinfo:
1478         free_mem(sm->sysinfo.manuf);
1479         free_mem(sm->sysinfo.product);
1480         free_mem(sm->sysinfo.version);
1481         free_mem(sm->sysinfo.serial);
1482         break;
1483
1484       case sm_boardinfo:
1485         free_mem(sm->boardinfo.manuf);
1486         free_mem(sm->boardinfo.product);
1487         free_mem(sm->boardinfo.version);
1488         free_mem(sm->boardinfo.serial);
1489         break;
1490
1491       case sm_chassis:
1492         free_mem(sm->chassis.manuf);
1493         break;
1494
1495       case sm_processor:
1496         free_mem(sm->processor.socket);
1497         free_mem(sm->processor.manuf);
1498         free_mem(sm->processor.version);
1499         break;
1500
1501       case sm_onboard:
1502         for(i = 0; i < sizeof sm->onboard.descr / sizeof *sm->onboard.descr; i++) {
1503           free_mem(sm->onboard.descr[i]);
1504         }
1505         break;
1506
1507       case sm_lang:
1508         free_mem(sm->lang.current);
1509         break;
1510
1511       case sm_memdevice:
1512         free_mem(sm->memdevice.location);
1513         free_mem(sm->memdevice.bank);
1514         break;
1515
1516       default:
1517         break;
1518     }
1519
1520     free_mem(sm);
1521   }
1522
1523   return NULL;
1524 }
1525
1526
1527 /*
1528  * Note: new_smbios is directly inserted into the list, so you *must* make sure
1529  * that new_smbios points to a malloc'ed pice of memory.
1530  */
1531 hd_smbios_t *add_smbios_entry(hd_smbios_t **sm, hd_smbios_t *new_sm)
1532 {
1533   while(*sm) sm = &(*sm)->next;
1534
1535   return *sm = new_sm;
1536 }
1537
1538
1539 hd_t *add_hd_entry(hd_data_t *hd_data, unsigned line, unsigned count)
1540 {
1541   hd_t *hd;
1542
1543   hd = add_hd_entry2(&hd_data->hd, new_mem(sizeof *hd));
1544
1545   hd->idx = ++(hd_data->last_idx);
1546   hd->module = hd_data->module;
1547   hd->line = line;
1548   hd->count = count;
1549
1550   return hd;
1551 }
1552
1553
1554 hd_t *add_hd_entry2(hd_t **hd, hd_t *new_hd)
1555 {
1556   while(*hd) hd = &(*hd)->next;
1557
1558   return *hd = new_hd;
1559 }
1560
1561
1562 void hd_scan(hd_data_t *hd_data)
1563 {
1564   char *s = NULL;
1565   int i, j;
1566   hd_t *hd;
1567   uint64_t irqs;
1568   str_list_t *sl, *sl0;
1569
1570 #ifdef LIBHD_MEMCHECK
1571   if(!libhd_log) {
1572     char *s = getenv("LIBHD_MEMCHECK");
1573
1574     if(s && *s) {
1575       libhd_log = fopen(s, "w");
1576       if(libhd_log) setlinebuf(libhd_log);
1577     }
1578   }
1579 #endif
1580
1581 #ifdef LIBHD_MEMCHECK
1582   {
1583     if(libhd_log)
1584       fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_scan, hd_data), hd_data);
1585   }
1586 #endif
1587
1588   /* log the debug & probe flags */
1589   if(hd_data->debug && !hd_data->flags.internal) {
1590     ADD2LOG("libhd version %s%s (%s)\n", HD_VERSION_STRING, getuid() ? "u" : "", HD_ARCH);
1591   }
1592
1593   get_kernel_version(hd_data);
1594
1595   /* needed only on 1st call */
1596   if(hd_data->last_idx == 0) {
1597     get_probe_env(hd_data);
1598   }
1599
1600   fix_probe_features(hd_data);
1601
1602   if(hd_data->debug && !hd_data->flags.internal) {
1603     for(i = sizeof hd_data->probe - 1; i >= 0; i--) {
1604       str_printf(&s, -1, "%02x", hd_data->probe[i]);
1605     }
1606     ADD2LOG("debug = 0x%x\nprobe = 0x%s (", hd_data->debug, s);
1607     s = free_mem(s);
1608
1609     for(i = 1; i < pr_default; i++) {           /* 1 because of pr_memory */
1610       if((s = hd_probe_feature_by_value(i))) {
1611         ADD2LOG("%s%c%s", i == 1 ? "" : " ", hd_probe_feature(hd_data, i) ? '+' : '-', s);
1612       }
1613     }
1614
1615     ADD2LOG(")\n");
1616   }
1617
1618   /* init driver info database */
1619   hddb_init(hd_data);
1620
1621 #ifndef LIBHD_TINY
1622   /*
1623    * There might be old 'manual' entries left from an earlier scan. Remove
1624    * them, they will confuse us.
1625    */
1626   if(hd_probe_feature(hd_data, pr_manual)) {
1627     hd_data->module = mod_manual;
1628     remove_hd_entries(hd_data);
1629   }
1630 #endif
1631
1632   /*
1633    * for various reasons, do it befor scan_misc()
1634    */
1635   hd_scan_floppy(hd_data);
1636
1637   /*
1638    * to be able to read the right parport io,
1639    * we have to do this before scan_misc()
1640    */
1641 #if defined(__i386__) || defined (__x86_64__) || defined(__ia64__)
1642   hd_scan_bios(hd_data);
1643 #endif
1644   
1645   /* before hd_scan_misc(): we need some ppc info later */
1646   hd_scan_sys(hd_data);
1647
1648   /* get basic system info */
1649   hd_scan_misc(hd_data);
1650
1651   /* hd_scan_cpu() after hd_scan_misc(): klog needed */
1652   hd_scan_cpu(hd_data);
1653   hd_scan_memory(hd_data);
1654
1655   hd_scan_pci(hd_data);
1656
1657   /* do it _after_ hd_scan_pci() */
1658 #if defined(__PPC__)
1659   hd_scan_prom(hd_data);
1660 #endif
1661
1662   /* after hd_scan_prom() and hd_scan_bios() */
1663   hd_scan_monitor(hd_data);
1664
1665 #ifndef LIBHD_TINY
1666 #if defined(__i386__) || defined(__alpha__)
1667   hd_scan_isapnp(hd_data);
1668 #endif
1669 #endif
1670
1671 #ifndef LIBHD_TINY
1672 #if defined(__i386__)
1673   hd_scan_isa(hd_data);
1674 #endif
1675 #endif
1676
1677   hd_scan_serial(hd_data);
1678
1679   /* merge basic system info & the easy stuff */
1680   hd_scan_misc2(hd_data);
1681
1682 #ifndef LIBHD_TINY
1683   if(!hd_data->flags.no_parport) {
1684     hd_scan_parallel(hd_data);  /* after hd_scan_misc*() */
1685   }
1686 #endif
1687   /* do it rather early */
1688   hd_scan_partition(hd_data);
1689
1690   hd_scan_ide(hd_data);
1691   hd_scan_scsi(hd_data);
1692   hd_scan_dac960(hd_data);
1693   hd_scan_smart(hd_data);
1694   hd_scan_i2o(hd_data);
1695   hd_scan_cciss(hd_data);
1696 #if defined(__s390__) || defined(__s390x__)
1697   hd_scan_dasd(hd_data);
1698 #endif
1699 #if defined(__PPC__)   
1700   hd_scan_veth(hd_data);
1701 #endif
1702   hd_scan_usb(hd_data);
1703 #if defined(__PPC__)
1704   hd_scan_adb(hd_data);
1705 #endif
1706   hd_scan_kbd(hd_data);
1707 #ifndef LIBHD_TINY
1708 #if !defined(__sparc__)
1709   hd_scan_braille(hd_data);
1710 #endif
1711   hd_scan_modem(hd_data);       /* do it before hd_scan_mouse() */
1712   hd_scan_mouse(hd_data);
1713 #endif
1714   hd_scan_sbus(hd_data);
1715
1716   /* must be after hd_scan_monitor() */
1717   hd_scan_fb(hd_data);
1718
1719   /* keep these at the end of the list */
1720   hd_scan_cdrom(hd_data);
1721   hd_scan_net(hd_data);
1722   hd_scan_disk(hd_data);
1723   hd_scan_ataraid(hd_data);
1724
1725   for(hd = hd_data->hd; hd; hd = hd->next) hd_add_id(hd_data, hd);
1726
1727 #ifndef LIBHD_TINY
1728   hd_scan_manual(hd_data);
1729 #endif
1730
1731   /* add test entries */
1732   hd_scan_xtra(hd_data);
1733
1734   /* some final fixup's */
1735 #if WITH_ISDN
1736   hd_scan_isdn(hd_data);
1737 #endif
1738   hd_scan_int(hd_data);
1739
1740   hd_scan_cdrom2(hd_data);
1741
1742   /* and again... */
1743   for(hd = hd_data->hd; hd; hd = hd->next) hd_add_id(hd_data, hd);
1744
1745   /* assign a hw_class & build a useful model string */
1746   for(hd = hd_data->hd; hd; hd = hd->next) {
1747     assign_hw_class(hd_data, hd);
1748 #ifndef LIBHD_TINY
1749     /* create model name _after_ hw_class */
1750     create_model_name(hd_data, hd);
1751 #endif
1752   }
1753
1754 #ifndef LIBHD_TINY
1755   /* must be _after_ we have valid hw_class entries */
1756   hd_scan_manual2(hd_data);
1757 #endif
1758
1759   /* we are done... */
1760   for(hd = hd_data->hd; hd; hd = hd->next) hd->tag.fixed = 1;
1761
1762   hd_data->module = mod_none;
1763
1764   if(hd_data->debug && !hd_data->flags.internal) {
1765     sl0 = read_file(PROC_MODULES, 0, 0);
1766     ADD2LOG("----- /proc/modules -----\n");
1767     for(sl = sl0; sl; sl = sl->next) {
1768       ADD2LOG("  %s", sl->str);
1769     }
1770     ADD2LOG("----- /proc/modules end -----\n");
1771     free_str_list(sl0);
1772   }
1773
1774   update_irq_usage(hd_data);
1775
1776   if(hd_data->debug && !hd_data->flags.internal) {
1777     irqs = hd_data->used_irqs;
1778
1779     ADD2LOG("  used irqs:");
1780     for(i = j = 0; i < 64; i++, irqs >>= 1) {
1781       if((irqs & 1)) {
1782         ADD2LOG("%c%d", j ? ',' : ' ', i);
1783         j = 1;
1784       }
1785     }
1786     ADD2LOG("\n");
1787   }
1788 }
1789
1790
1791 /*
1792  * Note: due to byte order problems decoding the id is really a mess...
1793  * And, we use upper case for hex numbers!
1794  */
1795 char *isa_id2str(unsigned id)
1796 {
1797   char *s = new_mem(8);
1798   unsigned u = ((id & 0xff) << 8) + ((id >> 8) & 0xff);
1799   unsigned v = ((id >> 8) & 0xff00) + ((id >> 24) & 0xff);
1800
1801   s[0] = ((u >> 10) & 0x1f) + 'A' - 1;
1802   s[1] = ((u >>  5) & 0x1f) + 'A' - 1;
1803   s[2] = ( u        & 0x1f) + 'A' - 1;
1804
1805   sprintf(s + 3, "%04X", v);
1806
1807   return s;
1808 }
1809
1810 char *eisa_vendor_str(unsigned v)
1811 {
1812   static char s[4];
1813
1814   s[0] = ((v >> 10) & 0x1f) + 'A' - 1;
1815   s[1] = ((v >>  5) & 0x1f) + 'A' - 1;
1816   s[2] = ( v        & 0x1f) + 'A' - 1;
1817   s[3] = 0;
1818
1819   return s;
1820 }
1821
1822
1823 /*
1824  *  Must _not_ check that s is exactly 3 chars.
1825  */
1826 unsigned name2eisa_id(char *s)
1827 {
1828   int i;
1829   unsigned u = 0;
1830
1831   for(i = 0; i < 3; i++) {
1832     u <<= 5;
1833     if(s[i] < 'A' - 1 || s[i] > 'A' - 1 + 0x1f) return 0;
1834     u += s[i] - 'A' + 1;
1835   }
1836
1837   return MAKE_ID(TAG_EISA, u);
1838 }
1839
1840
1841 /*
1842  * Create a 'canonical' version, i.e. no spaces at start and end.
1843  *
1844  * Note: removes chars >= 0x80 as well (due to (char *))! This
1845  * is currently considered a feature.
1846  */
1847 char *canon_str(char *s, int len)
1848 {
1849   char *m2, *m1, *m0 = new_mem(len + 1);
1850   int i;
1851
1852 #ifdef LIBHD_MEMCHECK
1853   {
1854     if(libhd_log) fprintf(libhd_log, ">%p\n", CALLED_FROM(canon_str, s));
1855   }
1856 #endif
1857
1858   for(m1 = m0, i = 0; i < len; i++) {
1859     if(m1 == m0 && s[i] <= ' ') continue;
1860     *m1++ = s[i];
1861   }
1862   *m1 = 0;
1863   while(m1 > m0 && m1[-1] <= ' ') {
1864     *--m1 = 0;
1865   }
1866
1867   m2 = new_str(m0);
1868   free_mem(m0);
1869
1870 #ifdef LIBHD_MEMCHECK
1871   {
1872     if(libhd_log) fprintf(libhd_log, "<%p\n", CALLED_FROM(canon_str, s));
1873   }
1874 #endif
1875
1876   return m2;
1877 }
1878
1879
1880 /*
1881  * Convert a n-digit hex number to its numerical value.
1882  */
1883 int hex(char *s, int n)
1884 {
1885   int i = 0, j;
1886
1887   while(n--) {
1888     if(sscanf(s++, "%1x", &j) != 1) return -1;
1889     i = (i << 4) + j;
1890   }
1891
1892   return i;
1893 }
1894
1895
1896 /* simple 32 bit fixed point numbers with n decimals */
1897 int str2float(char *s, int n)
1898 {
1899   int i = 0;
1900   int dot = 0;
1901
1902   while(*s) {
1903     if(*s == '.') {
1904       if(dot++) return 0;
1905     }
1906     else if(*s >= '0' && *s <= '9') {
1907       if(dot) {
1908         if(!n) return i;
1909         n--;
1910       }
1911       i *= 10;
1912       i += *s - '0';
1913     }
1914     else {
1915       return 0;
1916     }
1917
1918     s++;
1919   }
1920
1921   while(n--) i *= 10;
1922
1923   return i;
1924 }
1925
1926
1927 /* simple 32 bit fixed point numbers with n decimals */
1928 char *float2str(int f, int n)
1929 {
1930   int i = 1, j, m = n;
1931   static char buf[32];
1932
1933   while(n--) i *= 10;
1934
1935   j = f / i;
1936   i = f % i;
1937
1938   while(i && !(i % 10)) i /= 10, m--;
1939
1940   if(i) {
1941     sprintf(buf, "%d.%0*d", j, m, i);
1942   }
1943   else {
1944     sprintf(buf, "%d", j);
1945   }
1946
1947   return buf;
1948 }
1949
1950
1951 /*
1952  * find hardware entry with given index
1953  */
1954 hd_t *hd_get_device_by_idx(hd_data_t *hd_data, int idx)
1955 {
1956   hd_t *hd;
1957
1958 #ifdef LIBHD_MEMCHECK
1959   {
1960     if(libhd_log)
1961       fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_get_device_by_idx, hd_data), hd_data);
1962   }
1963 #endif
1964
1965   if(!idx) return NULL;         /* early out: idx is always != 0 */
1966
1967   for(hd = hd_data->hd; hd; hd = hd->next) {
1968     if(hd->idx == idx) return hd;
1969   }
1970
1971   return NULL;
1972 }
1973
1974
1975 /*
1976  * Give the actual name of the probing module.
1977  */
1978 char *mod_name_by_idx(unsigned idx)
1979 {
1980   unsigned u;
1981
1982   for(u = 0; u < sizeof pr_modules / sizeof *pr_modules; u++)
1983     if(idx == pr_modules[u].val) return pr_modules[u].name;
1984
1985   return "";
1986 }
1987
1988
1989 /*
1990  * Print to a string.
1991  * Note: *buf must point to a malloc'd memory area (or be NULL).
1992  *
1993  * Use an offset of -1 or -2 to append the new string.
1994  *
1995  * As this function is quite often used to extend our log messages, there
1996  * is a cache that holds the length of the last string we created. This way
1997  * we speed this up somewhat. Use an offset of -2 to use this feature.
1998  * Note: this only works as long as str_printf() is used *exclusively* to
1999  * extend the string.
2000  */
2001 void str_printf(char **buf, int offset, char *format, ...)
2002 {
2003   static char *last_buf = NULL;
2004   static int last_len = 0;
2005   int len, use_cache;
2006   char b[1024];
2007   va_list args;
2008
2009 #ifdef LIBHD_MEMCHECK
2010   {
2011     if(libhd_log) fprintf(libhd_log, ">%p\n", CALLED_FROM(str_printf, buf));
2012   }
2013 #endif
2014
2015   use_cache = offset == -2 ? 1 : 0;
2016
2017   if(*buf) {
2018     if(offset == -1) {
2019       offset = strlen(*buf);
2020     }
2021     else if(offset == -2) {
2022       if(last_buf == *buf && last_len && !(*buf)[last_len])
2023         offset = last_len;
2024       else
2025         offset = strlen(*buf);
2026     }
2027   }
2028   else {
2029     offset = 0;
2030   }
2031
2032   va_start(args, format);
2033   vsnprintf(b, sizeof b, format, args);
2034   va_end(args);
2035
2036   *buf = resize_mem(*buf, (len = offset + strlen(b)) + 1);
2037   strcpy(*buf + offset, b);
2038
2039   if(use_cache) {
2040     last_buf = *buf;
2041     last_len = len;
2042   }
2043
2044 #ifdef LIBHD_MEMCHECK
2045   {
2046     if(libhd_log) fprintf(libhd_log, "<%p\n", CALLED_FROM(str_printf, buf));
2047   }
2048 #endif
2049 }
2050
2051
2052 void hexdump(char **buf, int with_ascii, unsigned data_len, unsigned char *data)
2053 {
2054   unsigned i;
2055
2056   for(i = 0; i < data_len; i++) {
2057     if(i)
2058       str_printf(buf, -2, " %02x", data[i]);
2059     else
2060       str_printf(buf, -2, "%02x", data[i]);
2061   }
2062
2063   if(with_ascii) {
2064     str_printf(buf, -2, "  \"");
2065     for(i = 0; i < data_len; i++) {
2066       str_printf(buf, -2, "%c", data[i] < ' ' || data[i] >= 0x7f ? '.' : data[i]);
2067     }
2068     str_printf(buf, -2, "\"");
2069   }
2070 }
2071
2072
2073 /** \relates s_str_list_t
2074  * Search a string list for a string.
2075  */
2076 str_list_t *search_str_list(str_list_t *sl, char *str)
2077 {
2078   if(!str) return NULL;
2079
2080   for(; sl; sl = sl->next) if(!strcmp(sl->str, str)) return sl;
2081
2082   return NULL;
2083 }
2084
2085
2086 /** \relates s_str_list_t
2087  * Add a string to a string list.
2088  *
2089  * The new string (str) will be *copied*!
2090  */
2091 str_list_t *add_str_list(str_list_t **sl, char *str)
2092 {
2093 #ifdef LIBHD_MEMCHECK
2094   {
2095     if(libhd_log) fprintf(libhd_log, ">%p\n", CALLED_FROM(add_str_list, sl));
2096   }
2097 #endif
2098
2099   while(*sl) sl = &(*sl)->next;
2100
2101   *sl = new_mem(sizeof **sl);
2102   (*sl)->str = new_str(str);
2103
2104 #ifdef LIBHD_MEMCHECK
2105   {
2106     if(libhd_log) fprintf(libhd_log, "<%p\n", CALLED_FROM(add_str_list, sl));
2107   }
2108 #endif
2109
2110   return *sl;
2111 }
2112
2113
2114 /** \relates s_str_list_t
2115  * Free the memory allocated by a string list.
2116  */
2117 str_list_t *free_str_list(str_list_t *list)
2118 {
2119   str_list_t *l;
2120
2121   for(; list; list = (l = list)->next, free_mem(l)) {
2122     free_mem(list->str);
2123   }
2124
2125   return NULL;
2126 }
2127
2128
2129 /*
2130  * Read a file; return a linked list of lines.
2131  *
2132  * start_line is zero-based; lines == 0 -> all lines
2133  */
2134 str_list_t *read_file(char *file_name, unsigned start_line, unsigned lines)
2135 {
2136   FILE *f;
2137   char buf[1024];
2138   int pipe = 0;
2139   str_list_t *sl_start = NULL, *sl_end = NULL, *sl;
2140
2141 #ifdef LIBHD_MEMCHECK
2142   {
2143     if(libhd_log) fprintf(libhd_log, ">%p\n", CALLED_FROM(read_file, file_name));
2144   }
2145 #endif
2146
2147   if(*file_name == '|') {
2148     pipe = 1;
2149     file_name++;
2150     if(!(f = popen(file_name, "r"))) {
2151 #ifdef LIBHD_MEMCHECK
2152       {
2153         if(libhd_log) fprintf(libhd_log, "<%p\n", CALLED_FROM(read_file, file_name));
2154       }
2155 #endif
2156       return NULL;
2157     }
2158   }
2159   else {
2160     if(!(f = fopen(file_name, "r"))) {
2161 #ifdef LIBHD_MEMCHECK
2162       {
2163         if(libhd_log) fprintf(libhd_log, "<%p\n", CALLED_FROM(read_file, file_name));
2164       }
2165 #endif
2166       return NULL;
2167     }
2168   }
2169
2170   while(fgets(buf, sizeof buf, f)) {
2171     if(start_line) {
2172       start_line--;
2173       continue;
2174     }
2175     sl = new_mem(sizeof *sl);
2176     sl->str = new_str(buf);
2177     if(sl_start)
2178       sl_end->next = sl;
2179     else
2180       sl_start = sl;
2181     sl_end = sl;
2182
2183     if(lines == 1) break;
2184     lines--;
2185   }
2186
2187   if(pipe)
2188     pclose(f);
2189   else
2190     fclose(f);
2191
2192 #ifdef LIBHD_MEMCHECK
2193   {
2194     if(libhd_log) fprintf(libhd_log, "<%p\n", CALLED_FROM(read_file, file_name));
2195   }
2196 #endif
2197
2198   return sl_start;
2199 }
2200
2201
2202 /*
2203  * Read directory, return a list of entries with file type 'type'.
2204  */
2205 str_list_t *read_dir(char *dir_name, int type)
2206 {
2207   str_list_t *sl_start = NULL, *sl_end = NULL, *sl;
2208   DIR *dir;
2209   struct dirent *de;
2210   struct stat sbuf;
2211   char *s;
2212   int dir_type;
2213
2214   if(dir_name && (dir = opendir(dir_name))) {
2215     while((de = readdir(dir))) {
2216       if(!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) continue;
2217       dir_type = 0;
2218
2219       if(type) {
2220         s = NULL;
2221         str_printf(&s, 0, "%s/%s", dir_name, de->d_name);
2222
2223         if(!lstat(s, &sbuf)) {
2224           if(S_ISDIR(sbuf.st_mode)) {
2225             dir_type = 'd';
2226           }
2227           else if(S_ISREG(sbuf.st_mode)) {
2228             dir_type = 'r';
2229           }
2230           else if(S_ISLNK(sbuf.st_mode)) {
2231             dir_type = 'l';
2232           }
2233         }
2234
2235         s = free_mem(s);
2236       }
2237
2238       if(dir_type == type) {
2239         sl = new_mem(sizeof *sl);
2240         sl->str = new_str(de->d_name);
2241         if(sl_start)
2242           sl_end->next = sl;
2243         else
2244           sl_start = sl;
2245         sl_end = sl;
2246       }
2247     }
2248     closedir(dir);
2249   }
2250
2251   return sl_start;
2252 }
2253
2254
2255 char *hd_read_symlink(char *link_name)
2256 {
2257   static char buf[256];
2258   int i;
2259
2260   i = readlink(link_name, buf, sizeof buf);
2261   buf[sizeof buf - 1] = 0;
2262   if(i >= 0 && i < sizeof buf) buf[i] = 0;
2263   if(i < 0) *buf = 0;
2264
2265   return buf;
2266 }
2267
2268
2269 /*
2270  * Log the hardware detection progress.
2271  */
2272 void progress(hd_data_t *hd_data, unsigned pos, unsigned count, char *msg)
2273 {
2274   char buf1[32], buf2[32], buf3[128], *fn;
2275
2276   if(!msg) msg = "";
2277
2278   sprintf(buf1, "%u", hd_data->module);
2279   sprintf(buf2, ".%u", count);
2280   fn = mod_name_by_idx(hd_data->module);
2281
2282   sprintf(buf3, "%s.%u%s", *fn ? fn : buf1, pos, count ? buf2 : "");
2283
2284   if((hd_data->debug & HD_DEB_PROGRESS))
2285     ADD2LOG(">> %s: %s\n", buf3, msg);
2286
2287   if(hd_data->progress) hd_data->progress(buf3, msg);
2288 }
2289
2290
2291
2292 /*
2293  * Returns a probe feature suitable for hd_*probe_feature().
2294  * If name is not a valid probe feature, 0 is returned.
2295  *
2296  */
2297 enum probe_feature hd_probe_feature_by_name(char *name)
2298 {
2299   int u;
2300
2301 #ifdef LIBHD_MEMCHECK
2302   {
2303     if(libhd_log)
2304       fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_probe_feature_by_name, name), name);
2305   }
2306 #endif
2307
2308   for(u = 0; u < sizeof pr_flags / sizeof *pr_flags; u++)
2309     if(!strcmp(name, pr_flags[u].name)) return pr_flags[u].val;
2310
2311   return 0;
2312 }
2313
2314
2315 /*
2316  * Coverts a enum probe_feature to a string.
2317  * If it fails, NULL is returned.
2318  */
2319 char *hd_probe_feature_by_value(enum probe_feature feature)
2320 {
2321   int u;
2322
2323 #ifdef LIBHD_MEMCHECK
2324   {
2325     if(libhd_log)
2326       fprintf(libhd_log, "; %s\t%p\t%u\n", __FUNCTION__, CALLED_FROM(hd_probe_feature_by_value, feature), feature);
2327   }
2328 #endif
2329
2330   for(u = 0; u < sizeof pr_flags / sizeof *pr_flags; u++)
2331     if(feature == pr_flags[u].val) return pr_flags[u].name;
2332
2333   return NULL;
2334 }
2335
2336
2337 /*
2338  * Removes all hd_data->hd entries created by the current module from the
2339  * list. The old entries are added to hd_data->old_hd.
2340  */
2341 void remove_hd_entries(hd_data_t *hd_data)
2342 {
2343   hd_t *hd;
2344
2345   for(hd = hd_data->hd; hd; hd = hd->next) {
2346     if(hd->module == hd_data->module) {
2347       hd->tag.remove = 1;
2348     }
2349   }
2350
2351   remove_tagged_hd_entries(hd_data);
2352 }
2353
2354
2355 /*
2356  * Removes all hd_data->hd entries that have the remove tag set from the
2357  * list. The old entries are added to hd_data->old_hd.
2358  */
2359 void remove_tagged_hd_entries(hd_data_t *hd_data)
2360 {
2361   hd_t *hd, **prev, **h;
2362
2363   for(hd = *(prev = &hd_data->hd); hd;) {
2364     if(hd->tag.remove) {
2365       /* find end of the old list... */
2366       h = &hd_data->old_hd;
2367       while(*h) h = &(*h)->next;
2368       *h = hd;          /* ...and append the entry */
2369
2370       hd = *prev = hd->next;
2371       (*h)->next = NULL;
2372     }
2373     else {
2374       hd = *(prev = &hd->next);
2375     }
2376   }
2377 }
2378
2379
2380 int hd_module_is_active(hd_data_t *hd_data, char *mod)
2381 {
2382   str_list_t *sl, *sl0 = read_kmods(hd_data);
2383   int active = 0;
2384 #ifdef __PPC__
2385   char *s1, *s2;
2386 #endif
2387
2388 #ifdef LIBHD_MEMCHECK
2389   {
2390     if(libhd_log)
2391       fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_module_is_active, hd_data), hd_data);
2392   }
2393 #endif
2394
2395   for(sl = sl0; sl; sl = sl->next) {
2396     if(!strcmp(sl->str, mod)) break;
2397   }
2398
2399   free_str_list(sl0);
2400   active = sl ? 1 : 0;
2401
2402   if(active) return active;
2403
2404 #ifdef __PPC__
2405   /* temporary hack for ppc */
2406   if(!strcmp(mod, "gmac")) {
2407     s1 = "<6>eth";
2408     s2 = " GMAC ";
2409   }
2410   else if(!strcmp(mod, "mace")) {
2411     s1 = "<6>eth";
2412     s2 = " MACE ";
2413   }
2414   else if(!strcmp(mod, "bmac")) {
2415     s1 = "<6>eth";
2416     s2 = " BMAC";
2417   }
2418   else if(!strcmp(mod, "mac53c94")) {
2419     s1 = "<4>scsi";
2420     s2 = " 53C94";
2421   }
2422   else if(!strcmp(mod, "mesh")) {
2423     s1 = "<4>scsi";
2424     s2 = " MESH";
2425   }
2426   else if(!strcmp(mod, "swim3")) {
2427     s1 = "<6>fd";
2428     s2 = " SWIM3 ";
2429   }
2430   else {
2431     s1 = s2 = NULL;
2432   }
2433
2434   if(s1) {
2435     for(sl = hd_data->klog; sl; sl = sl->next) {
2436       if(strstr(sl->str, s1) == sl->str && strstr(sl->str, s2)) {
2437         active = 1;
2438         break;
2439       }
2440     }
2441   }
2442 #endif
2443
2444   return active;
2445 }
2446
2447
2448 /*
2449  * cf. /usr/src/linux/drivers/block/ide-pci.c
2450  */
2451 #ifndef PCI_DEVICE_ID_ARTOP_ATP860
2452 #define PCI_DEVICE_ID_ARTOP_ATP860      0x0006
2453 #endif
2454
2455 #ifndef PCI_DEVICE_ID_ARTOP_ATP860R
2456 #define PCI_DEVICE_ID_ARTOP_ATP860R     0x0007
2457 #endif
2458
2459 #ifndef PCI_DEVICE_ID_CMD_649
2460 #define PCI_DEVICE_ID_CMD_649           0x0649
2461 #endif
2462
2463 #ifndef PCI_DEVICE_ID_PROMISE_20267
2464 #define PCI_DEVICE_ID_PROMISE_20267     0x4d30
2465 #endif
2466
2467 #ifndef PCI_DEVICE_ID_INTEL_82443MX_1
2468 #define PCI_DEVICE_ID_INTEL_82443MX_1   0x7199
2469 #endif
2470
2471 #ifndef PCI_DEVICE_ID_INTEL_82372FB_1
2472 #define PCI_DEVICE_ID_INTEL_82372FB_1   0x7601
2473 #endif
2474
2475 #ifndef PCI_DEVICE_ID_INTEL_82820FW_5
2476 #define PCI_DEVICE_ID_INTEL_82820FW_5   0x244b
2477 #endif
2478
2479 #ifndef PCI_DEVICE_ID_AMD_VIPER_7409
2480 #define PCI_DEVICE_ID_AMD_VIPER_7409    0x7409
2481 #endif
2482
2483 #ifndef PCI_DEVICE_ID_CMD_648
2484 #define PCI_DEVICE_ID_CMD_648           0x0648
2485 #endif
2486
2487 #ifndef PCI_DEVICE_ID_TTI_HPT366
2488 #define PCI_DEVICE_ID_TTI_HPT366        0x0004
2489 #endif
2490
2491 #ifndef PCI_DEVICE_ID_PROMISE_20262
2492 #define PCI_DEVICE_ID_PROMISE_20262     0x4d38
2493 #endif
2494
2495 int hd_has_special_eide(hd_data_t *hd_data)
2496 {
2497   int i;
2498   hd_t *hd;
2499   static unsigned ids[][2] = {
2500 /* CONFIG_BLK_DEV_AEC62XX */
2501     { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF },
2502     { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860 },
2503     { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860R },
2504 /* CONFIG_BLK_DEV_ALI15X3 */
2505     { PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229 },
2506 /* CONFIG_BLK_DEV_AMD7409 */
2507     { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7409 },
2508 /* CONFIG_BLK_DEV_CMD64X */
2509     { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_643 },
2510     { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_646 },
2511     { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_648 },
2512     { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_649 },
2513 /* CONFIG_BLK_DEV_CY82C693 */
2514     { PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693 },
2515 /* CONFIG_BLK_DEV_CS5530 */
2516     { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE },
2517 /* CONFIG_BLK_DEV_HPT34X */
2518     { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343 },
2519 /* CONFIG_BLK_DEV_HPT366 */
2520     { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366 },
2521 /* CONFIG_BLK_DEV_NS87415 */
2522     { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410 },
2523     { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415 },
2524 /* CONFIG_BLK_DEV_OPTI621 */
2525     { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621 },
2526     { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558 },
2527     { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C825 },
2528 #if 0
2529 /* CONFIG_BLK_DEV_PIIX */
2530     { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0 },
2531     { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_1 },
2532     { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1 },
2533     { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB },
2534     { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_1 },
2535     { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_1 },
2536     { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_1 },
2537     { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82372FB_1 },
2538     { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX },
2539     { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82820FW_5 },
2540 #endif
2541 /* CONFIG_BLK_DEV_PDC202XX */
2542     { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246 },
2543     { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262 },
2544     { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267 },
2545 /* CONFIG_BLK_DEV_SIS5513 */
2546     { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513 },
2547 /* CONFIG_BLK_DEV_TRM290 */
2548     { PCI_VENDOR_ID_TEKRAM, PCI_DEVICE_ID_TEKRAM_DC290 },
2549 /* CONFIG_BLK_DEV_VIA82CXXX */
2550     { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561 },
2551     { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1 }
2552   };
2553
2554 #ifdef LIBHD_MEMCHECK
2555   {
2556     if(libhd_log)
2557       fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_has_special_eide, hd_data), hd_data);
2558   }
2559 #endif
2560
2561   for(hd = hd_data->hd; hd; hd = hd->next) {
2562     if(hd->bus.id == bus_pci) {
2563       for(i = 0; i < sizeof ids / sizeof *ids; i++) {
2564         if(hd->vendor.id == ids[i][0] && hd->device.id == ids[i][1]) return 1;
2565       }
2566     }
2567   }
2568
2569   return 0;
2570 }
2571
2572
2573 int hd_has_pcmcia(hd_data_t *hd_data)
2574 {
2575   hd_t *hd;
2576
2577   for(hd = hd_data->hd; hd; hd = hd->next) {
2578     if(is_pcmcia_ctrl(hd_data, hd)) return 1;
2579   }
2580
2581   return 0;
2582 }
2583
2584
2585 int hd_apm_enabled(hd_data_t *hd_data)
2586 {
2587   hd_t *hd;
2588
2589 #ifdef LIBHD_MEMCHECK
2590   {
2591     if(libhd_log)
2592       fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_apm_enabled, hd_data), hd_data);
2593   }
2594 #endif
2595
2596   for(hd = hd_data->hd; hd; hd = hd->next) {
2597     if(
2598       hd->base_class.id == bc_internal &&
2599       hd->sub_class.id == sc_int_bios &&
2600       hd->detail &&
2601       hd->detail->type == hd_detail_bios &&
2602       hd->detail->bios.data
2603     ) {
2604       return hd->detail->bios.data->apm_enabled;
2605     }
2606   }
2607
2608   return 0;
2609 }
2610
2611
2612 int hd_usb_support(hd_data_t *hd_data)
2613 {
2614   hd_t *hd;
2615   hd_res_t *res;
2616
2617 #ifdef LIBHD_MEMCHECK
2618   {
2619     if(libhd_log)
2620       fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_usb_support, hd_data), hd_data);
2621   }
2622 #endif
2623
2624   for(hd = hd_data->hd; hd; hd = hd->next) {
2625     if(hd->base_class.id == bc_serial && hd->sub_class.id == sc_ser_usb) {
2626       for(res = hd->res; res; res = res->next) {
2627         if(res->any.type == res_irq)
2628           return hd->prog_if.id == pif_usb_ohci ? 2 : 1;        /* 2: ohci, 1: uhci */
2629       }
2630     }
2631   }
2632
2633   return 0;
2634 }
2635
2636
2637 int hd_smp_support(hd_data_t *hd_data)
2638 {
2639   int is_smp = 0;
2640   unsigned u;
2641   hd_t *hd, *hd0;
2642 #if defined(__i386__) || (!defined(LIBHD_TINY) && defined (__x86_64__))
2643   unsigned cpu_threads = 0;
2644 #endif
2645 #ifdef __i386__
2646   cpu_info_t *ct;
2647 #endif
2648
2649 #ifdef LIBHD_MEMCHECK
2650   {
2651     if(libhd_log)
2652       fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_smp_support, hd_data), hd_data);
2653   }
2654 #endif
2655
2656   u = hd_data->flags.internal;
2657   hd_data->flags.internal = 1;
2658   hd = hd_list(hd_data, hw_cpu, 0, NULL);
2659   if(!hd) hd = hd_list(hd_data, hw_cpu, 1, NULL);
2660   hd_data->flags.internal = u;
2661
2662   for(is_smp = 0, hd0 = hd; hd0; hd0 = hd0->next) is_smp++;
2663   if(is_smp == 1) is_smp = 0;
2664
2665 #if defined(__i386__)
2666   if(
2667     hd &&
2668     hd->detail &&
2669     hd->detail->type == hd_detail_cpu &&
2670     (ct = hd->detail->cpu.data)
2671   ) {
2672     cpu_threads = ct->units;
2673   }
2674 #endif
2675
2676   hd = hd_free_hd_list(hd);
2677
2678 #if !defined(LIBHD_TINY) && (defined(__i386__) || defined (__x86_64__))
2679   if(is_smp < 2) {
2680     if(!hd_data->bios_ram.data) {
2681       hd_free_hd_list(hd_list(hd_data, hw_sys, 1, NULL));
2682     }
2683     is_smp = detect_smp(hd_data);
2684     // at least 2 processors
2685     if(is_smp < 2) is_smp = 0;
2686     if(!is_smp && cpu_threads > 1) is_smp = 2;
2687   }
2688 #endif
2689
2690 #ifdef __PPC__
2691   if(is_smp < 2) {
2692     if(!hd_data->devtree) {
2693       hd_free_hd_list(hd_list(hd_data, hw_sys, 1, NULL));
2694     }
2695     is_smp = detect_smp(hd_data);
2696     if(is_smp < 0) is_smp = 0;
2697   }
2698 #endif
2699
2700 #if defined(__s390__) || defined(__s390x__)
2701   if(!is_smp) is_smp = 1;
2702 #endif
2703
2704   return is_smp;
2705 }
2706
2707
2708 int hd_color(hd_data_t *hd_data)
2709 {
2710 #if 0
2711   hd_t *hd;
2712   prom_info_t *pt;
2713
2714   for(hd = hd_data->hd; hd; hd = hd->next) {
2715     if(
2716       hd->base_class.id == bc_internal && hd->sub_class.id == sc_int_prom &&
2717       hd->detail && hd->detail->type == hd_detail_prom &&
2718       (pt = hd->detail->prom.data) &&
2719       pt->has_color
2720     ) {
2721       return pt->color;
2722     }
2723   }
2724 #endif
2725
2726 #ifdef LIBHD_MEMCHECK
2727   {
2728     if(libhd_log)
2729       fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_color, hd_data), hd_data);
2730   }
2731 #endif
2732
2733   if(hd_data->color_code) return hd_data->color_code & 0xffff;
2734
2735   return -1;
2736 }
2737
2738
2739 int hd_mac_color(hd_data_t *hd_data)
2740 {
2741 #ifdef LIBHD_MEMCHECK
2742   {
2743     if(libhd_log)
2744       fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_mac_color, hd_data), hd_data);
2745   }
2746 #endif
2747
2748   return hd_color(hd_data);
2749 }
2750
2751
2752 unsigned hd_display_adapter(hd_data_t *hd_data)
2753 {
2754   hd_t *hd;
2755   driver_info_t *di;
2756   unsigned disp, disp_sbus, disp_pci, disp_any, disp_di;
2757   unsigned disp_cnt, disp_any_cnt;
2758
2759 #ifdef LIBHD_MEMCHECK
2760   {
2761     if(libhd_log)
2762       fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_display_adapter, hd_data), hd_data);
2763   }
2764 #endif
2765
2766   /* if we know exactly where our primary display is, return it */
2767   if(hd_get_device_by_idx(hd_data, hd_data->display)) return hd_data->display;
2768
2769   disp = disp_sbus = disp_pci = disp_any = disp_di = 0;
2770   disp_cnt = disp_any_cnt = 0;
2771
2772   for(hd = hd_data->hd; hd; hd = hd->next) {
2773     if(hd->base_class.id == bc_display) {
2774       disp_any_cnt++;
2775       if(!disp_any) disp_any = hd->idx;
2776       if(hd->sub_class.id == sc_dis_vga) {
2777         disp_cnt++;
2778         if(!disp) disp = hd->idx;
2779         if(hd->bus.id == bus_pci && !disp_pci) disp_pci = hd->idx;
2780         if(hd->bus.id == bus_sbus && !disp_sbus) disp_sbus = hd->idx;
2781       }
2782       if(!disp_di) {
2783         if(!(di = hd->driver_info)) {
2784           hddb_add_info(hd_data, hd);
2785           di = hd->driver_info;
2786         }
2787         if(di && di->any.type == di_x11 && di->x11.server) {
2788           disp_di = hd->idx;
2789         }
2790       }
2791     }
2792   }
2793
2794   /* if there's only one display adapter, return it */
2795   if(disp_any_cnt == 1) return disp_any;
2796
2797   /* if there's only one vga compatible adapter, return it */
2798   if(disp_cnt == 1) return disp;
2799
2800   /* return 1st (vga compatible) sbus card */
2801   /* note: the sbus code enters display cards as 'vga compatible' */
2802   if(disp_sbus) return disp_sbus;
2803
2804   /* return 1st display adapter that has some x11 info */
2805   if(disp_di) return disp_di;
2806
2807   /* return 1st vga compatible pci card */
2808   if(disp_pci) return disp_pci;
2809
2810   /* return 1st vga compatible card */
2811   if(disp) return disp;
2812
2813   /* return 1st display adapter */
2814   if(disp_any) return disp_any;
2815
2816   /* there were none... */
2817   return 0;
2818 }
2819
2820
2821 enum cpu_arch hd_cpu_arch(hd_data_t *hd_data)
2822 {
2823   hd_t *hd;
2824
2825 #ifdef LIBHD_MEMCHECK
2826   {
2827     if(libhd_log)
2828       fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_cpu_arch, hd_data), hd_data);
2829   }
2830 #endif
2831
2832   for(hd = hd_data->hd; hd; hd = hd->next) {
2833     if(
2834       hd->base_class.id == bc_internal &&
2835       hd->sub_class.id == sc_int_cpu &&
2836       hd->detail &&
2837       hd->detail->type == hd_detail_cpu &&
2838       hd->detail->cpu.data
2839     ) {
2840       return hd->detail->cpu.data->architecture;
2841     }
2842   }
2843
2844 #ifdef __i386__
2845   return arch_intel;
2846 #else
2847 #ifdef __alpha__
2848   return arch_alpha;
2849 #else
2850 #ifdef __PPC__
2851   return arch_ppc;
2852 #else
2853 #ifdef __sparc__
2854   return arch_sparc;
2855 #else
2856 #ifdef __s390x__
2857   return arch_s390x;
2858 #else
2859 #ifdef __s390__
2860   return arch_s390;
2861 #else
2862 #ifdef __ia64__
2863   return arch_ia64;
2864 #else
2865 #ifdef __x86_64__
2866   return arch_x86_64;
2867 #else
2868   return arch_unknown;
2869 #endif
2870 #endif
2871 #endif
2872 #endif
2873 #endif
2874 #endif
2875 #endif
2876 #endif
2877 }
2878
2879
2880 enum boot_arch hd_boot_arch(hd_data_t *hd_data)
2881 {
2882 #ifdef LIBHD_MEMCHECK
2883   {
2884     if(libhd_log)
2885       fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_boot_arch, hd_data), hd_data);
2886   }
2887 #endif
2888
2889   return hd_data->boot;
2890 }
2891
2892 /*
2893  * makes a (shallow) copy; does some magic fixes
2894  */
2895 void hd_copy(hd_t *dst, hd_t *src)
2896 {
2897   hd_t *tmp;
2898 //  unsigned u;
2899
2900   tmp = dst->next;
2901 //  u = dst->idx;
2902
2903   *dst = *src;
2904   src->ref_cnt++;
2905   dst->ref = src;
2906
2907   dst->next = tmp;
2908 //  dst->idx = u;
2909
2910   /* needed to keep in sync with the real device tree */
2911   if(
2912     dst->detail &&
2913     dst->detail->type == hd_detail_devtree
2914   ) {
2915     dst->detail = NULL;         /* ??? was: free_mem(dst->detail); */
2916   }
2917 }
2918
2919
2920 hd_t *hd_list(hd_data_t *hd_data, hd_hw_item_t item, int rescan, hd_t *hd_old)
2921 {
2922   hd_t *hd, *hd1, *hd_list = NULL;
2923   unsigned char probe_save[sizeof hd_data->probe];
2924   unsigned fast_save;
2925
2926 #ifdef LIBHD_MEMCHECK
2927 #ifndef __PPC__
2928   {
2929     if(libhd_log)
2930       fprintf(libhd_log, "; %s\t%p\t%p\t%u\t%u\t%p\n", __FUNCTION__, CALLED_FROM(hd_list, hd_data), hd_data, item, rescan, hd_old);
2931   }
2932 #endif
2933 #endif
2934
2935   if(rescan) {
2936     memcpy(probe_save, hd_data->probe, sizeof probe_save);
2937     fast_save = hd_data->flags.fast;
2938     hd_clear_probe_feature(hd_data, pr_all);
2939 #ifdef __powerpc__
2940     hd_set_probe_feature(hd_data, pr_sys);
2941     hd_scan(hd_data);
2942 #endif
2943     hd_set_probe_feature_hw(hd_data, item);
2944     hd_scan(hd_data);
2945     memcpy(hd_data->probe, probe_save, sizeof hd_data->probe);
2946     hd_data->flags.fast = fast_save;
2947   }
2948
2949   for(hd = hd_data->hd; hd; hd = hd->next) {
2950     if(
2951       (
2952         hd->hw_class == item ||
2953         hd->hw_class2 == item ||
2954         hd->hw_class3 == item ||
2955         item == hw_manual
2956       )
2957 #ifndef LIBHD_TINY
2958 /* with LIBHD_TINY hd->status is not maintained (cf. manual.c) */
2959       && (
2960         hd->status.available == status_yes ||
2961         hd->status.available == status_unknown ||
2962         item == hw_manual ||
2963         hd_data->flags.list_all
2964       )
2965 #endif
2966     ) {
2967       if(hd->is.softraiddisk) continue;         /* don't report them */
2968
2969       /* don't report old entries again */
2970       for(hd1 = hd_old; hd1; hd1 = hd1->next) {
2971         if(!cmp_hd(hd1, hd)) break;
2972       }
2973       if(!hd1) {
2974         hd1 = add_hd_entry2(&hd_list, new_mem(sizeof *hd_list));
2975         hd_copy(hd1, hd);
2976       }
2977     }
2978   }
2979
2980   if(item == hw_manual) {
2981     for(hd = hd_list; hd; hd = hd->next) {
2982       hd->status.available = hd->status.available_orig;
2983     }
2984   }
2985
2986   return hd_list;
2987 }
2988
2989
2990 hd_t *hd_list_with_status(hd_data_t *hd_data, hd_hw_item_t item, hd_status_t status)
2991 {
2992   hd_t *hd, *hd1, *hd_list = NULL;
2993   unsigned char probe_save[sizeof hd_data->probe];
2994
2995 #ifdef LIBHD_MEMCHECK
2996 #ifndef __PPC__
2997   {
2998     if(libhd_log)
2999       fprintf(libhd_log, "; %s\t%p\t%p\t%u\n", __FUNCTION__, CALLED_FROM(hd_list_with_status, hd_data), hd_data, item);
3000   }
3001 #endif
3002 #endif
3003
3004   memcpy(probe_save, hd_data->probe, sizeof probe_save);
3005   hd_clear_probe_feature(hd_data, pr_all);
3006   hd_set_probe_feature(hd_data, pr_manual);
3007   hd_scan(hd_data);
3008   memcpy(hd_data->probe, probe_save, sizeof hd_data->probe);
3009
3010   for(hd = hd_data->hd; hd; hd = hd->next) {
3011     if(hd->hw_class == item || hd->hw_class2 == item || hd->hw_class3 == item) {
3012       if(
3013         (status.configured == 0 || status.configured == hd->status.configured) &&
3014         (status.available == 0 || status.available == hd->status.available) &&
3015         (status.needed == 0 || status.needed == hd->status.needed) &&
3016         (status.reconfig == 0 || status.reconfig == hd->status.reconfig)
3017       ) {
3018         hd1 = add_hd_entry2(&hd_list, new_mem(sizeof *hd_list));
3019         hd_copy(hd1, hd);
3020       }
3021     }
3022   }
3023
3024   return hd_list;
3025 }
3026
3027
3028 hd_t *hd_base_class_list(hd_data_t *hd_data, unsigned base_class)
3029 {
3030   hd_t *hd, *hd1, *hd_list = NULL;
3031 //  hd_t *bridge_hd;
3032
3033 #ifdef LIBHD_MEMCHECK
3034   {
3035     if(libhd_log)
3036       fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_base_class_list, hd_data), hd_data);
3037   }
3038 #endif
3039
3040   for(hd = hd_data->hd; hd; hd = hd->next) {
3041
3042 #if 0
3043     /* ###### fix later: card bus magic */
3044     if((bridge_hd = hd_get_device_by_idx(hd_data, hd->attached_to))) {
3045       if(
3046         bridge_hd->base_class.id == bc_bridge &&
3047         bridge_hd->sub_class.id == sc_bridge_cardbus
3048       ) continue;
3049     }
3050 #endif
3051
3052     /* add multimedia/sc_multi_video to display */
3053     if(
3054       hd->base_class.id == base_class ||
3055       (
3056         base_class == bc_display &&
3057         hd->base_class.id == bc_multimedia &&
3058         hd->sub_class.id == sc_multi_video
3059       )
3060     ) {
3061       hd1 = add_hd_entry2(&hd_list, new_mem(sizeof *hd_list));
3062       hd_copy(hd1, hd);
3063     }
3064   }
3065
3066   return hd_list;
3067 }
3068
3069 hd_t *hd_sub_class_list(hd_data_t *hd_data, unsigned base_class, unsigned sub_class)
3070 {
3071   hd_t *hd, *hd1, *hd_list = NULL;
3072
3073 #ifdef LIBHD_MEMCHECK
3074   {
3075     if(libhd_log)
3076       fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_sub_class_list, hd_data), hd_data);
3077   }
3078 #endif
3079
3080   for(hd = hd_data->hd; hd; hd = hd->next) {
3081     if(hd->base_class.id == base_class && hd->sub_class.id == sub_class) {
3082       hd1 = add_hd_entry2(&hd_list, new_mem(sizeof *hd_list));
3083       hd_copy(hd1, hd);
3084     }
3085   }
3086
3087   return hd_list;
3088 }
3089
3090 hd_t *hd_bus_list(hd_data_t *hd_data, unsigned bus)
3091 {
3092   hd_t *hd, *hd1, *hd_list = NULL;
3093
3094 #ifdef LIBHD_MEMCHECK
3095   {
3096     if(libhd_log)
3097       fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_bus_list, hd_data), hd_data);
3098   }
3099 #endif
3100
3101   for(hd = hd_data->hd; hd; hd = hd->next) {
3102     if(hd->bus.id == bus) {
3103       hd1 = add_hd_entry2(&hd_list, new_mem(sizeof *hd_list));
3104       hd_copy(hd1, hd);
3105     }
3106   }
3107
3108   return hd_list;
3109 }
3110
3111 /*
3112  * Check if the execution of (*func)() takes longer than timeout seconds.
3113  * This is useful to work around long kernel-timeouts as in the floppy
3114  * detection and ps/2 mouse detection.
3115  */
3116 int hd_timeout(void(*func)(void *), void *arg, int timeout)
3117 {
3118   int child1, child2;
3119   int status = 0;
3120
3121   child1 = fork();
3122   if(child1 == -1) return -1;
3123
3124   if(child1) {
3125     if(waitpid(child1, &status, 0) == -1) return -1;
3126 //    fprintf(stderr, ">child1 status: 0x%x\n", status);
3127
3128     if(WIFEXITED(status)) {
3129       status = WEXITSTATUS(status);
3130 //      fprintf(stderr, ">normal child1 status: 0x%x\n", status);
3131       /* != 0 if we timed out */
3132     }
3133     else {
3134       status = 0;
3135     }
3136   }
3137   else {
3138     /* fork again */
3139
3140 #ifdef LIBHD_MEMCHECK
3141     /* stop logging in child process */
3142     if(libhd_log) fclose(libhd_log);
3143     libhd_log = NULL;
3144 #endif
3145
3146     child2 = fork();
3147     if(child2 == -1) return -1;
3148
3149     if(child2) {
3150 //      fprintf(stderr, ">signal\n");
3151       signal(SIGALRM, timeout_alarm_handler);
3152       alarm(timeout);
3153       if(waitpid(child2, &status, 0) == -1) return -1;
3154 //      fprintf(stderr, ">child2 status: 0x%x\n", status);
3155       _exit(0);
3156     }
3157     else {
3158       (*func)(arg);
3159       _exit(0);
3160     }
3161   }
3162
3163   return status ? 1 : 0;
3164 }
3165
3166 void timeout_alarm_handler(int signal)
3167 {
3168   _exit(63);
3169 }
3170
3171
3172 str_list_t *read_kmods(hd_data_t *hd_data)
3173 {
3174   str_list_t *sl, *sl0, *sl1 = NULL;
3175   char *s;
3176
3177   hd_data->kmods = free_str_list(hd_data->kmods);
3178
3179   if(!(sl0 = read_file(PROC_MODULES, 0, 0))) return NULL;
3180
3181   hd_data->kmods = sl0;
3182
3183   for(sl = sl0; sl; sl = sl->next) {
3184     s = sl->str;
3185     add_str_list(&sl1, strsep(&s, " \t"));
3186   }
3187
3188   return sl1;
3189 }
3190
3191
3192 char *get_cmdline(hd_data_t *hd_data, char *key)
3193 {
3194   str_list_t *sl0, *sl1;
3195   char *s, *t, *t0;
3196   int i, l = strlen(key);
3197
3198   if(!hd_data->cmd_line) {
3199     sl0 = read_file(PROC_CMDLINE, 0, 1);
3200     sl1 = read_file(LIB_CMDLINE, 0, 1);
3201
3202     if(sl0) {
3203       i = strlen(sl0->str);
3204       if(i && sl0->str[i - 1] == '\n') sl0->str[i - 1] = 0;
3205       hd_data->cmd_line = new_str(sl0->str);
3206       if(hd_data->debug) {
3207         ADD2LOG("----- " PROC_CMDLINE " -----\n");
3208         ADD2LOG("  %s\n", sl0->str);
3209         ADD2LOG("----- " PROC_CMDLINE " end -----\n");
3210       }
3211     }
3212     if(sl1) {
3213       i = strlen(sl1->str);
3214       if(i && sl1->str[i - 1] == '\n') sl1->str[i - 1] = 0;
3215       str_printf(&hd_data->cmd_line, -1, " %s", sl1->str);
3216       if(hd_data->debug) {
3217         ADD2LOG("----- " LIB_CMDLINE " -----\n");
3218         ADD2LOG("  %s\n", sl1->str);
3219         ADD2LOG("----- " LIB_CMDLINE " end -----\n");
3220       }
3221     }
3222
3223     free_str_list(sl0);
3224     free_str_list(sl1);
3225   }
3226
3227   if(!hd_data->cmd_line) return NULL;
3228
3229   t = t0 = new_str(hd_data->cmd_line);
3230   while((s = strsep(&t, " "))) {
3231     if(!*s) continue;
3232     if(!strncmp(s, key, l) && s[l] == '=') {
3233       s += l + 1;
3234       break;
3235     }
3236   }
3237
3238   s = new_str(s);
3239
3240   free_mem(t0);
3241
3242   return s;
3243 }
3244
3245
3246 /*
3247  * Return field 'field' (starting with 0) from the 'SuSE='
3248  * kernel cmd line parameter.
3249  */
3250 char *get_cmd_param(hd_data_t *hd_data, int field)
3251 {
3252   char *s, *t, *t0;
3253
3254   s = t0 = get_cmdline(hd_data, "SuSE");
3255
3256   if(!t0) return NULL;
3257
3258   t = NULL;
3259
3260   if(s) {
3261     for(; field; field--) {
3262       if(!(s = strchr(s, ','))) break;
3263       s++;
3264     }
3265
3266     if(s && (t = strchr(s, ','))) *t = 0;
3267   }
3268
3269   t = new_str(s);
3270
3271   free_mem(t0);
3272
3273   return t;
3274 }
3275
3276
3277 unsigned get_disk_crc(unsigned char *data, unsigned len)
3278 {
3279   unsigned i, crc;
3280
3281   crc = -1;
3282   for(i = 0; i < len; i++) {
3283     crc += data[i];
3284     crc *= 57;
3285   }
3286
3287   return crc;
3288 }
3289
3290 disk_t *add_disk_entry(disk_t **dl, disk_t *new_dl)
3291 {