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