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