]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blame - src/hwinfo/src/hd/hd.c
Signierten GPG-Schluessel importiert.
[people/pmueller/ipfire-2.x.git] / src / hwinfo / src / hd / hd.c
CommitLineData
93afd047
MT
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <unistd.h>
5#include <stdarg.h>
6#include <fcntl.h>
7#include <signal.h>
8#include <ctype.h>
9#include <errno.h>
10#include <dirent.h>
11#include <time.h>
12#include <sys/stat.h>
13#include <sys/types.h>
14#include <sys/wait.h>
15#include <sys/time.h>
16#include <sys/ioctl.h>
17#include <sys/mount.h>
18#include <sys/ipc.h>
19#include <sys/shm.h>
20#include <sys/mman.h>
21typedef unsigned long kernel_ulong_t;
22#include <linux/types.h>
23#include <linux/pci.h>
24#include <linux/hdreg.h>
25#define _LINUX_AUDIT_H_
26#include <linux/fs.h>
27
28#define u64 uint64_t
29
30#ifndef BLKSSZGET
31#define BLKSSZGET _IO(0x12,104) /* get block device sector size */
32#endif
33
34#include "hd.h"
35#include "hddb.h"
36#include "hd_int.h"
37#include "smbios.h"
38#include "memory.h"
39#include "isapnp.h"
40#include "monitor.h"
41#include "cpu.h"
42#include "misc.h"
43#include "mouse.h"
44#include "floppy.h"
45#include "bios.h"
46#include "serial.h"
47#include "net.h"
48#include "version.h"
49#include "usb.h"
50#include "adb.h"
51#include "modem.h"
52#include "parallel.h"
53#include "isa.h"
54#include "isdn.h"
55#include "kbd.h"
56#include "prom.h"
57#include "sbus.h"
58#include "int.h"
59#include "braille.h"
60#include "sys.h"
61#include "manual.h"
62#include "fb.h"
63#include "pppoe.h"
64#include "pcmcia.h"
65#include "s390.h"
66#include "pci.h"
67#include "block.h"
68#include "edd.h"
69#include "input.h"
70#include "wlan.h"
71
72/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
73 * various functions commmon to all probing modules
74 *
75 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
76 */
77
78#ifdef __i386__
79#define HD_ARCH "ia32"
80#endif
81
82#ifdef __ia64__
83#define HD_ARCH "ia64"
84#endif
85
86#ifdef __alpha__
87#define HD_ARCH "axp"
88#endif
89
90#ifdef __PPC__
91#define HD_ARCH "ppc"
92#endif
93
94#ifdef __sparc__
95#define HD_ARCH "sparc"
96#endif
97
98#ifdef __s390x__
99#define HD_ARCH "s390x"
100#else
101#ifdef __s390__
102#define HD_ARCH "s390"
103#endif
104#endif
105
106#ifdef __arm__
107#define HD_ARCH "arm"
108#endif
109
110#ifdef __mips__
111#define HD_ARCH "mips"
112#endif
113
114#ifdef __x86_64__
115#define HD_ARCH "x86-64"
116#endif
117
118#ifdef __hppa__
119#define HD_ARCH "hppa"
120#endif
121
122typedef struct disk_s {
123 struct disk_s *next;
124 unsigned crc;
125 unsigned crc_match:1;
126 unsigned hd_idx;
127 char *dev_name;
128 unsigned char *data;
129} disk_t;
130
131static struct s_pr_flags *get_pr_flags(enum probe_feature feature);
132static void fix_probe_features(hd_data_t *hd_data);
133static void set_probe_feature(hd_data_t *hd_data, enum probe_feature feature, unsigned val);
134static void free_old_hd_entries(hd_data_t *hd_data);
135static hd_t *free_hd_entry(hd_t *hd);
136static hd_t *add_hd_entry2(hd_t **hd, hd_t *new_hd);
137static void timeout_alarm_handler(int signal);
138static void get_probe_env(hd_data_t *hd_data);
139static void hd_scan_xtra(hd_data_t *hd_data);
140static hd_t *hd_get_device_by_id(hd_data_t *hd_data, char *id);
141static int has_item(hd_hw_item_t *items, hd_hw_item_t item);
142static int has_hw_class(hd_t *hd, hd_hw_item_t *items);
143
144static void test_read_block0_open(void *arg);
145static void get_kernel_version(hd_data_t *hd_data);
146static int is_modem(hd_data_t *hd_data, hd_t *hd);
147static int is_audio(hd_data_t *hd_data, hd_t *hd);
148static void assign_hw_class(hd_data_t *hd_data, hd_t *hd);
149static void short_vendor(char *vendor);
150static void create_model_name(hd_data_t *hd_data, hd_t *hd);
151
152static void sigchld_handler(int);
153static pid_t child_id;
154static volatile pid_t child;
155static char *hd_shm_add_str(hd_data_t *hd_data, char *str);
156static str_list_t *hd_shm_add_str_list(hd_data_t *hd_data, str_list_t *sl);
157
158static hd_udevinfo_t *hd_free_udevinfo(hd_udevinfo_t *ui);
159static hd_sysfsdrv_t *hd_free_sysfsdrv(hd_sysfsdrv_t *sf);
160
161
162/*
163 * Names of the probing modules.
164 * Cf. enum mod_idx in hd_int.h.
165 */
166static struct s_mod_names {
167 unsigned val;
168 char *name;
169} pr_modules[] = {
170 { mod_none, "none"},
171 { mod_memory, "memory"},
172 { mod_pci, "pci"},
173 { mod_isapnp, "isapnp"},
174 { mod_pnpdump, "pnpdump"},
175 { mod_net, "net"},
176 { mod_floppy, "floppy"},
177 { mod_misc, "misc" },
178 { mod_bios, "bios"},
179 { mod_cpu, "cpu"},
180 { mod_monitor, "monitor"},
181 { mod_serial, "serial"},
182 { mod_mouse, "mouse"},
183 { mod_scsi, "scsi"},
184 { mod_usb, "usb"},
185 { mod_adb, "adb"},
186 { mod_modem, "modem"},
187 { mod_parallel, "parallel" },
188 { mod_isa, "isa" },
189 { mod_isdn, "isdn" },
190 { mod_kbd, "kbd" },
191 { mod_prom, "prom" },
192 { mod_sbus, "sbus" },
193 { mod_int, "int" },
194 { mod_braille, "braille" },
195 { mod_xtra, "hd" },
196 { mod_sys, "sys" },
197 { mod_manual, "manual" },
198 { mod_fb, "fb" },
199 { mod_pppoe, "pppoe" },
200 { mod_pcmcia, "pcmcia" },
201 { mod_s390, "s390" },
202 { mod_sysfs, "sysfs" },
203 { mod_dsl, "dsl" },
204 { mod_block, "block" },
205 { mod_edd, "edd" },
206 { mod_input, "input" }
207};
208
209/*
210 * Names for the probe flags. Used for debugging and command line parsing in
211 * hw.c. Cf. enum probe_feature, hd_data_t.probe.
212 */
213static struct s_pr_flags {
214 enum probe_feature val, parent;
215 unsigned mask; /* bit 0: default, bit 1: all, bit 2: max, bit 3: linuxrc */
216 char *name;
217} pr_flags[] = {
218 { pr_default, -1, 1, "default" },
219 { pr_all, -1, 2 , "all" },
220 { pr_max, -1, 4 , "max" },
221 { pr_lxrc, -1, 8 , "lxrc" },
222 { pr_memory, 0, 8|4|2|1, "memory" },
223 { pr_pci, 0, 8|4|2|1, "pci" },
224 { pr_s390, 0, 8|4|2|1, "s390" },
225 { pr_s390disks, 0, 0, "s390disks" },
226 { pr_isapnp, 0, 4|2|1, "isapnp" },
227 { pr_isapnp_old, pr_isapnp, 0, "isapnp.old" },
228 { pr_isapnp_new, pr_isapnp, 0, "isapnp.new" },
229 { pr_isapnp_mod, 0, 4 , "isapnp.mod" },
230 { pr_isapnp, 0, 0, "pnpdump" }, /* alias for isapnp */
231 { pr_net, 0, 8|4|2|1, "net" },
232 { pr_floppy, 0, 8|4|2|1, "floppy" },
233 { pr_misc, pr_bios, 8|4|2|1, "misc" }, // ugly hack!
234 { pr_misc_serial, pr_misc, 8|4|2|1, "misc.serial" },
235 { pr_misc_par, pr_misc, 4|2|1, "misc.par" },
236 { pr_misc_floppy, pr_misc, 8|4|2|1, "misc.floppy" },
237 { pr_bios, 0, 8|4|2|1, "bios" },
238 { pr_bios_vesa, pr_bios, 4|2|1, "bios.vesa" },
239 { pr_bios_ddc, pr_bios_vesa, 0, "bios.ddc" },
240 { pr_bios_fb, pr_bios_vesa, 0, "bios.fb" },
241 { pr_bios_mode, pr_bios_vesa, 0, "bios.mode" },
242 { pr_bios_vbe, pr_bios_mode, 0, "bios.vbe" }, // just an alias
243 { pr_cpu, 0, 8|4|2|1, "cpu" },
244 { pr_monitor, 0, 8|4|2|1, "monitor" },
245 { pr_serial, 0, 4|2|1, "serial" },
246#if defined(__sparc__)
247 /* Probe for mouse on SPARC */
248 { pr_mouse, 0, 8|4|2|1, "mouse" },
249#else
250 { pr_mouse, 0, 4|2|1, "mouse" },
251#endif
252 { pr_scsi, 0, 8|4|2|1, "scsi" },
253 { pr_scsi_noserial, 0, 0, "scsi.noserial" },
254 { pr_usb, 0, 8|4|2|1, "usb" },
255 { pr_usb_mods, 0, 4 , "usb.mods" },
256 { pr_adb, 0, 8|4|2|1, "adb" },
257 { pr_modem, 0, 4|2|1, "modem" },
258 { pr_modem_usb, pr_modem, 4|2|1, "modem.usb" },
259 { pr_parallel, 0, 4|2|1, "parallel" },
260 { pr_parallel_lp, pr_parallel, 4|2|1, "parallel.lp" },
261 { pr_parallel_zip, pr_parallel, 4|2|1, "parallel.zip" },
262 { pr_parallel_imm, 0, 0, "parallel.imm" },
263 { pr_isa, 0, 4|2|1, "isa" },
264 { pr_isa_isdn, pr_isa, 4|2|1, "isa.isdn" },
265 { pr_isdn, 0, 4|2|1, "isdn" },
266 { pr_kbd, 0, 8|4|2|1, "kbd" },
267 { pr_prom, 0, 8|4|2|1, "prom" },
268 { pr_sbus, 0, 8|4|2|1, "sbus" },
269 { pr_int, 0, 8|4|2|1, "int" },
270#if defined(__i386__) || defined (__x86_64__)
271 { pr_braille, 0, 4|2|1, "braille" },
272 { pr_braille_alva, pr_braille, 4|2|1, "braille.alva" },
273 { pr_braille_fhp, pr_braille, 4|2|1, "braille.fhp" },
274 { pr_braille_ht, pr_braille, 4|2|1, "braille.ht" },
275 { pr_braille_baum, pr_braille, 4|2|1, "braille.baum" },
276#else
277 { pr_braille, 0, 4|2 , "braille" },
278 { pr_braille_alva, pr_braille, 0, "braille.alva" },
279 { pr_braille_fhp, pr_braille, 4|2 , "braille.fhp" },
280 { pr_braille_ht, pr_braille, 4|2 , "braille.ht" },
281 { pr_braille_baum, pr_braille, 4|2 , "braille.baum" },
282#endif
283 { pr_ignx11, 0, 0, "ignx11" },
284 { pr_sys, 0, 8|4|2|1, "sys" },
285 { pr_manual, 0, 8|4|2|1, "manual" },
286 { pr_fb, 0, 8|4|2|1, "fb" },
287 { pr_pppoe, 0, 8|4|2|1, "pppoe" },
288 /* dummy, used to turn off hwscan */
289 { pr_scan, 0, 0, "scan" },
290 { pr_pcmcia, 0, 8|4|2|1, "pcmcia" },
291 { pr_fork, 0, 0, "fork" },
292 { pr_cpuemu, 0, 0, "cpuemu" },
293 { pr_cpuemu_debug, pr_cpuemu, 0, "cpuemu.debug" },
294 { pr_sysfs, 0, 0, "sysfs" },
295 { pr_dsl, 0, 4|2|1, "dsl" },
296 { pr_udev, 0, 8|4|2|1, "udev" },
297 { pr_block, 0, 8|4|2|1, "block" },
298 { pr_block_cdrom, pr_block, 8|4|2|1, "block.cdrom" },
299 { pr_block_part, pr_block, 8|4|2|1, "block.part" },
300 { pr_block_mods, pr_block, 8|4|2|1, "block.mods" },
301 { pr_edd, 0, 8|4|2|1, "edd" },
302 { pr_edd_mod, pr_edd, 8|4|2|1, "edd.mod" },
303 { pr_input, 0, 8|4|2|1, "input" },
304 { pr_wlan, 0, 8|4|2|1, "wlan" }
305};
306
307struct s_pr_flags *get_pr_flags(enum probe_feature feature)
308{
309 int i;
310
311 for(i = 0; (unsigned) i < sizeof pr_flags / sizeof *pr_flags; i++) {
312 if(feature == pr_flags[i].val) return pr_flags + i;
313 }
314
315 return NULL;
316}
317
318void fix_probe_features(hd_data_t *hd_data)
319{
320 int i;
321
322 for(i = 0; (unsigned) i < sizeof hd_data->probe; i++) {
323 hd_data->probe[i] |= hd_data->probe_set[i];
324 hd_data->probe[i] &= ~hd_data->probe_clr[i];
325 }
326}
327
328void set_probe_feature(hd_data_t *hd_data, enum probe_feature feature, unsigned val)
329{
330 unsigned ofs, bit, mask;
331 int i;
332 struct s_pr_flags *pr;
333
334 if(!(pr = get_pr_flags(feature))) return;
335
336 if(pr->parent == -1u) {
337 mask = pr->mask;
338 for(i = 0; (unsigned) i < sizeof pr_flags / sizeof *pr_flags; i++) {
339 if(pr_flags[i].parent != -1u && (pr_flags[i].mask & mask))
340 set_probe_feature(hd_data, pr_flags[i].val, val);
341 }
342 }
343 else {
344 ofs = feature >> 3; bit = feature & 7;
345 if(ofs < sizeof hd_data->probe) {
346 if(val) {
347 hd_data->probe_set[ofs] |= 1 << bit;
348 hd_data->probe_clr[ofs] &= ~(1 << bit);
349 }
350 else {
351 hd_data->probe_clr[ofs] |= 1 << bit;
352 hd_data->probe_set[ofs] &= ~(1 << bit);
353 }
354 }
355 if(pr->parent) set_probe_feature(hd_data, pr->parent, val);
356 }
357
358 fix_probe_features(hd_data);
359}
360
361void hd_set_probe_feature(hd_data_t *hd_data, enum probe_feature feature)
362{
363 unsigned ofs, bit, mask;
364 int i;
365 struct s_pr_flags *pr;
366
367#ifdef LIBHD_MEMCHECK
368 {
369 if(libhd_log)
370 fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_set_probe_feature, hd_data), hd_data);
371 }
372#endif
373
374 if(!(pr = get_pr_flags(feature))) return;
375
376 if(pr->parent == -1u) {
377 mask = pr->mask;
378 for(i = 0; (unsigned) i < sizeof pr_flags / sizeof *pr_flags; i++) {
379 if(pr_flags[i].parent != -1u && (pr_flags[i].mask & mask))
380 hd_set_probe_feature(hd_data, pr_flags[i].val);
381 }
382 }
383 else {
384 ofs = feature >> 3; bit = feature & 7;
385 if(ofs < sizeof hd_data->probe)
386 hd_data->probe[ofs] |= 1 << bit;
387 if(pr->parent) hd_set_probe_feature(hd_data, pr->parent);
388 }
389
390 fix_probe_features(hd_data);
391}
392
393void hd_clear_probe_feature(hd_data_t *hd_data, enum probe_feature feature)
394{
395 unsigned ofs, bit, mask;
396 int i;
397 struct s_pr_flags *pr;
398
399#ifdef LIBHD_MEMCHECK
400 {
401 if(libhd_log)
402 fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_clear_probe_feature, hd_data), hd_data);
403 }
404#endif
405
406 if(!(pr = get_pr_flags(feature))) return;
407
408 if(pr->parent == -1u) {
409 mask = pr->mask;
410 for(i = 0; (unsigned) i < sizeof pr_flags / sizeof *pr_flags; i++) {
411 if(pr_flags[i].parent != -1u && (pr_flags[i].mask & mask))
412 hd_clear_probe_feature(hd_data, pr_flags[i].val);
413 }
414 }
415 else {
416 ofs = feature >> 3; bit = feature & 7;
417 if(ofs < sizeof hd_data->probe)
418 hd_data->probe[ofs] &= ~(1 << bit);
419 }
420}
421
422int hd_probe_feature(hd_data_t *hd_data, enum probe_feature feature)
423{
424#ifdef LIBHD_MEMCHECK
425 {
426 if(libhd_log)
427 fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_probe_feature, hd_data), hd_data);
428 }
429#endif
430
431 if(feature < 0 || feature >= pr_default) return 0;
432
433 return hd_data->probe[feature >> 3] & (1 << (feature & 7)) ? 1 : 0;
434}
435
436
437void hd_set_probe_feature_hw(hd_data_t *hd_data, hd_hw_item_t item)
438{
439 hd_set_probe_feature(hd_data, pr_int);
440 hd_set_probe_feature(hd_data, pr_manual);
441
442 switch(item) {
443 case hw_cdrom:
444 hd_set_probe_feature(hd_data, pr_pci);
445 hd_set_probe_feature(hd_data, pr_usb);
446 hd_set_probe_feature(hd_data, pr_block_mods);
447 hd_set_probe_feature(hd_data, pr_scsi);
448 if(!hd_data->flags.fast) {
449 hd_set_probe_feature(hd_data, pr_block_cdrom);
450 }
451 break;
452
453 case hw_floppy:
454 hd_set_probe_feature(hd_data, pr_floppy);
455 hd_set_probe_feature(hd_data, pr_misc_floppy);
456 hd_set_probe_feature(hd_data, pr_prom);
457 hd_set_probe_feature(hd_data, pr_pci);
458 hd_set_probe_feature(hd_data, pr_usb);
459 hd_set_probe_feature(hd_data, pr_block);
460 hd_set_probe_feature(hd_data, pr_block_mods);
461 hd_set_probe_feature(hd_data, pr_scsi);
462 break;
463
464 case hw_partition:
465 hd_set_probe_feature(hd_data, pr_block_part);
466
467 case hw_disk:
468 hd_set_probe_feature(hd_data, pr_s390disks);
469 hd_set_probe_feature(hd_data, pr_bios); // bios disk order
470 hd_set_probe_feature(hd_data, pr_pci);
471 hd_set_probe_feature(hd_data, pr_usb);
472 hd_set_probe_feature(hd_data, pr_block);
473 hd_set_probe_feature(hd_data, pr_block_mods);
474 hd_set_probe_feature(hd_data, pr_edd_mod);
475 hd_set_probe_feature(hd_data, pr_scsi);
476 break;
477
478 case hw_block:
479 hd_set_probe_feature(hd_data, pr_prom);
480 hd_set_probe_feature(hd_data, pr_s390disks);
481 hd_set_probe_feature(hd_data, pr_bios); // bios disk order
482 hd_set_probe_feature(hd_data, pr_pci);
483 hd_set_probe_feature(hd_data, pr_usb);
484 hd_set_probe_feature(hd_data, pr_block);
485 hd_set_probe_feature(hd_data, pr_block_mods);
486 hd_set_probe_feature(hd_data, pr_edd_mod);
487 hd_set_probe_feature(hd_data, pr_scsi);
488 if(!hd_data->flags.fast) {
489 hd_set_probe_feature(hd_data, pr_floppy);
490 hd_set_probe_feature(hd_data, pr_misc_floppy);
491 hd_set_probe_feature(hd_data, pr_block_cdrom);
492 }
493 hd_set_probe_feature(hd_data, pr_block_part);
494 break;
495
496 case hw_network:
497 hd_set_probe_feature(hd_data, pr_net);
498 hd_set_probe_feature(hd_data, pr_pci);
499 hd_set_probe_feature(hd_data, pr_prom);
500 hd_set_probe_feature(hd_data, pr_usb);
501 break;
502
503 case hw_display:
504 hd_set_probe_feature(hd_data, pr_pci);
505 hd_set_probe_feature(hd_data, pr_sbus);
506 hd_set_probe_feature(hd_data, pr_prom);
507 hd_set_probe_feature(hd_data, pr_misc); /* for isa cards */
508 break;
509
510 case hw_monitor:
511 hd_set_probe_feature(hd_data, pr_misc);
512 hd_set_probe_feature(hd_data, pr_prom);
513 hd_set_probe_feature(hd_data, pr_pci);
514 hd_set_probe_feature(hd_data, pr_bios_ddc);
515 hd_set_probe_feature(hd_data, pr_fb);
516 hd_set_probe_feature(hd_data, pr_monitor);
517 break;
518
519 case hw_framebuffer:
520 hd_set_probe_feature(hd_data, pr_misc);
521 hd_set_probe_feature(hd_data, pr_prom);
522 hd_set_probe_feature(hd_data, pr_pci);
523 hd_set_probe_feature(hd_data, pr_bios_fb);
524 hd_set_probe_feature(hd_data, pr_fb);
525 break;
526
527 case hw_mouse:
528 hd_set_probe_feature(hd_data, pr_misc);
529 if(!hd_data->flags.fast) {
530 hd_set_probe_feature(hd_data, pr_serial);
531 }
532 hd_set_probe_feature(hd_data, pr_adb);
533 hd_set_probe_feature(hd_data, pr_usb);
534 hd_set_probe_feature(hd_data, pr_kbd);
535 hd_set_probe_feature(hd_data, pr_sys);
536 hd_set_probe_feature(hd_data, pr_bios);
537 hd_set_probe_feature(hd_data, pr_mouse);
538 hd_set_probe_feature(hd_data, pr_input);
539 break;
540
541 case hw_joystick:
542 hd_set_probe_feature(hd_data, pr_usb);
543 hd_set_probe_feature(hd_data, pr_input);
544 break;
545
546 case hw_chipcard:
547 hd_set_probe_feature(hd_data, pr_misc);
548 if(!hd_data->flags.fast) {
549 hd_set_probe_feature(hd_data, pr_serial);
550 }
551 hd_set_probe_feature(hd_data, pr_usb);
552 hd_set_probe_feature(hd_data, pr_mouse); /* we need the pnp code */
553 break;
554
555 case hw_camera:
556 hd_set_probe_feature(hd_data, pr_usb);
557 break;
558
559 case hw_keyboard:
560 hd_set_probe_feature(hd_data, pr_cpu);
561 hd_set_probe_feature(hd_data, pr_misc);
562 hd_set_probe_feature(hd_data, pr_adb);
563 hd_set_probe_feature(hd_data, pr_usb);
564 hd_set_probe_feature(hd_data, pr_kbd);
565 hd_set_probe_feature(hd_data, pr_input);
566#ifdef __PPC__
567 hd_set_probe_feature(hd_data, pr_serial);
568#endif
569 break;
570
571 case hw_sound:
572 hd_set_probe_feature(hd_data, pr_misc);
573 hd_set_probe_feature(hd_data, pr_pci);
574 hd_set_probe_feature(hd_data, pr_isapnp);
575 hd_set_probe_feature(hd_data, pr_isapnp_mod);
576 hd_set_probe_feature(hd_data, pr_sbus);
577 hd_set_probe_feature(hd_data, pr_prom);
578 break;
579
580 case hw_isdn:
581 hd_set_probe_feature(hd_data, pr_misc); /* get basic i/o res */
582 hd_set_probe_feature(hd_data, pr_pci);
583 hd_set_probe_feature(hd_data, pr_pcmcia);
584 hd_set_probe_feature(hd_data, pr_isapnp);
585 hd_set_probe_feature(hd_data, pr_isapnp_mod);
586 hd_set_probe_feature(hd_data, pr_isa_isdn);
587 hd_set_probe_feature(hd_data, pr_usb);
588 hd_set_probe_feature(hd_data, pr_isdn);
589 break;
590
591 case hw_modem:
592 hd_set_probe_feature(hd_data, pr_misc);
593 hd_set_probe_feature(hd_data, pr_serial);
594 hd_set_probe_feature(hd_data, pr_usb);
595 hd_set_probe_feature(hd_data, pr_pci);
596 hd_set_probe_feature(hd_data, pr_modem);
597 hd_set_probe_feature(hd_data, pr_modem_usb);
598 break;
599
600 case hw_storage_ctrl:
601 hd_set_probe_feature(hd_data, pr_floppy);
602 hd_set_probe_feature(hd_data, pr_sys);
603 hd_set_probe_feature(hd_data, pr_pci);
604 hd_set_probe_feature(hd_data, pr_sbus);
605 if(!hd_data->flags.fast) {
606 hd_set_probe_feature(hd_data, pr_misc_par);
607 hd_set_probe_feature(hd_data, pr_parallel_zip);
608 }
609 hd_set_probe_feature(hd_data, pr_s390);
610 hd_set_probe_feature(hd_data, pr_prom);
611#ifdef __PPC__
612 hd_set_probe_feature(hd_data, pr_misc);
613#endif
614 break;
615
616 case hw_network_ctrl:
617 hd_set_probe_feature(hd_data, pr_misc);
618 hd_set_probe_feature(hd_data, pr_usb);
619 hd_set_probe_feature(hd_data, pr_pci);
620 hd_set_probe_feature(hd_data, pr_net);
621 hd_set_probe_feature(hd_data, pr_pcmcia);
622 hd_set_probe_feature(hd_data, pr_isapnp);
623 hd_set_probe_feature(hd_data, pr_isapnp_mod);
624 hd_set_probe_feature(hd_data, pr_sbus);
625 hd_set_probe_feature(hd_data, pr_isdn);
626 hd_set_probe_feature(hd_data, pr_dsl);
627 hd_set_probe_feature(hd_data, pr_prom);
628 hd_set_probe_feature(hd_data, pr_s390);
629 hd_set_probe_feature(hd_data, pr_wlan);
630 break;
631
632 case hw_printer:
633 hd_set_probe_feature(hd_data, pr_sys);
634 hd_set_probe_feature(hd_data, pr_bios);
635 hd_set_probe_feature(hd_data, pr_misc_par);
636 hd_set_probe_feature(hd_data, pr_parallel_lp);
637 hd_set_probe_feature(hd_data, pr_usb);
638 break;
639
640 case hw_wlan:
641 hd_set_probe_feature(hd_data, pr_pcmcia);
642 hd_set_probe_feature(hd_data, pr_wlan);
643 hd_set_probe_feature(hd_data, pr_pci);
644 hd_set_probe_feature(hd_data, pr_usb);
645 hd_set_probe_feature(hd_data, pr_net);
646 break;
647
648 case hw_tv:
649 case hw_dvb:
650 hd_set_probe_feature(hd_data, pr_pci);
651 break;
652
653 case hw_scanner:
654 hd_set_probe_feature(hd_data, pr_pci);
655 hd_set_probe_feature(hd_data, pr_usb);
656 hd_set_probe_feature(hd_data, pr_scsi);
657 break;
658
659 case hw_braille:
660 hd_set_probe_feature(hd_data, pr_misc_serial);
661 hd_set_probe_feature(hd_data, pr_serial);
662 hd_set_probe_feature(hd_data, pr_braille_alva);
663 hd_set_probe_feature(hd_data, pr_braille_fhp);
664 hd_set_probe_feature(hd_data, pr_braille_ht);
665 hd_set_probe_feature(hd_data, pr_braille_baum);
666 hd_set_probe_feature(hd_data, pr_usb);
667 break;
668
669 case hw_sys:
670 hd_set_probe_feature(hd_data, pr_bios);
671 hd_set_probe_feature(hd_data, pr_prom);
672 hd_set_probe_feature(hd_data, pr_s390);
673 hd_set_probe_feature(hd_data, pr_sys);
674 break;
675
676 case hw_cpu:
677 hd_set_probe_feature(hd_data, pr_cpu);
678 break;
679
680 case hw_bios:
681 hd_set_probe_feature(hd_data, pr_bios);
682 hd_set_probe_feature(hd_data, pr_edd_mod);
683 break;
684
685 case hw_vbe:
686 hd_set_probe_feature(hd_data, pr_bios_ddc);
687 hd_set_probe_feature(hd_data, pr_bios_fb);
688 hd_set_probe_feature(hd_data, pr_bios_mode);
689 hd_set_probe_feature(hd_data, pr_monitor);
690 break;
691
692 case hw_manual:
693 hd_set_probe_feature(hd_data, pr_manual);
694 break;
695
696 case hw_usb_ctrl:
697 case hw_pcmcia_ctrl:
698 case hw_ieee1394_ctrl:
699 case hw_hotplug_ctrl:
700 hd_set_probe_feature(hd_data, pr_misc);
701 hd_set_probe_feature(hd_data, pr_pci);
702 break;
703
704 case hw_usb:
705 hd_set_probe_feature(hd_data, pr_usb);
706 hd_set_probe_feature(hd_data, pr_isdn); // need pr_misc, too?
707 hd_set_probe_feature(hd_data, pr_dsl);
708 hd_set_probe_feature(hd_data, pr_block);
709 hd_set_probe_feature(hd_data, pr_block_mods);
710 hd_set_probe_feature(hd_data, pr_scsi);
711 hd_set_probe_feature(hd_data, pr_net);
712 hd_data->flags.fast = 1;
713 break;
714
715 case hw_pci:
716 hd_set_probe_feature(hd_data, pr_misc);
717 hd_set_probe_feature(hd_data, pr_pci);
718 hd_set_probe_feature(hd_data, pr_net);
719 hd_set_probe_feature(hd_data, pr_isdn);
720 hd_set_probe_feature(hd_data, pr_dsl);
721 hd_set_probe_feature(hd_data, pr_prom);
722 break;
723
724 case hw_isapnp:
725 hd_set_probe_feature(hd_data, pr_isapnp);
726 hd_set_probe_feature(hd_data, pr_isapnp_mod);
727 hd_set_probe_feature(hd_data, pr_misc);
728 hd_set_probe_feature(hd_data, pr_isdn);
729 break;
730
731 case hw_bridge:
732 hd_set_probe_feature(hd_data, pr_misc);
733 hd_set_probe_feature(hd_data, pr_pci);
734 break;
735
736 case hw_hub:
737 hd_set_probe_feature(hd_data, pr_usb);
738 break;
739
740 case hw_memory:
741 hd_set_probe_feature(hd_data, pr_memory);
742 break;
743
744 case hw_scsi:
745 case hw_tape:
746 hd_set_probe_feature(hd_data, pr_pci);
747 hd_set_probe_feature(hd_data, pr_block);
748 hd_set_probe_feature(hd_data, pr_block_mods);
749 hd_set_probe_feature(hd_data, pr_scsi);
750 break;
751
752 case hw_ide:
753 hd_set_probe_feature(hd_data, pr_pci);
754 hd_set_probe_feature(hd_data, pr_block);
755 hd_set_probe_feature(hd_data, pr_block_mods);
756 break;
757
758 case hw_pppoe:
759 hd_set_probe_feature(hd_data, pr_net);
760 hd_set_probe_feature(hd_data, pr_pppoe);
761 break;
762
763 case hw_dsl:
764 hd_set_probe_feature(hd_data, pr_net);
765 hd_set_probe_feature(hd_data, pr_pci);
766 hd_set_probe_feature(hd_data, pr_pppoe);
767 hd_set_probe_feature(hd_data, pr_usb);
768 break;
769
770 case hw_pcmcia:
771 hd_set_probe_feature(hd_data, pr_pci);
772 hd_set_probe_feature(hd_data, pr_pcmcia);
773 hd_set_probe_feature(hd_data, pr_wlan);
774 hd_set_probe_feature(hd_data, pr_net);
775 hd_set_probe_feature(hd_data, pr_isdn);
776 break;
777
778 case hw_bluetooth:
779 hd_set_probe_feature(hd_data, pr_usb);
780 hd_set_probe_feature(hd_data, pr_isdn); // need pr_misc, too?
781 hd_set_probe_feature(hd_data, pr_dsl);
782 break;
783
784 case hw_all:
785 hd_set_probe_feature(hd_data, pr_default);
786 break;
787
788 case hw_redasd:
789 hd_set_probe_feature(hd_data, pr_block);
790 hd_set_probe_feature(hd_data, pr_block_mods);
791 break;
792
793 case hw_unknown:
794 case hw_ieee1394:
795 case hw_hotplug:
796 case hw_zip:
797 break;
798 }
799}
800
801
802/*
803 * Free all data associated with a hd_data_t struct. *Not* the struct itself.
804 */
805hd_data_t *hd_free_hd_data(hd_data_t *hd_data)
806{
807 hddb_pci_t *p;
808 unsigned u;
809
810#ifdef LIBHD_MEMCHECK
811 {
812 if(libhd_log)
813 fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_free_hd_data, hd_data), hd_data);
814 }
815#endif
816
817 add_hd_entry2(&hd_data->old_hd, hd_data->hd); hd_data->hd = NULL;
818 hd_data->log = free_mem(hd_data->log);
819 free_old_hd_entries(hd_data); /* hd_data->old_hd */
820 /* hd_data->pci is always NULL */
821 /* hd_data->isapnp->card is always NULL */
822 hd_data->isapnp = free_mem(hd_data->isapnp);
823 /* hd_data->cdrom is always NULL */
824 hd_data->net = free_str_list(hd_data->net);
825 hd_data->floppy = free_str_list(hd_data->floppy);
826 hd_data->misc = free_misc(hd_data->misc);
827 /* hd_data->serial is always NULL */
828 /* hd_data->scsi is always NULL */
829 /* hd_data->ser_mouse is always NULL */
830 /* hd_data->ser_modem is always NULL */
831 hd_data->cpu = free_str_list(hd_data->cpu);
832 hd_data->klog = free_str_list(hd_data->klog);
833 hd_data->proc_usb = free_str_list(hd_data->proc_usb);
834 /* hd_data->usb is always NULL */
835
836 if((p = hd_data->hddb_pci)) {
837 for(; p->module; p++) free_mem(p->module);
838 }
839 if(hd_data->hddb2[0]) {
840 free_mem(hd_data->hddb2[0]->list);
841 free_mem(hd_data->hddb2[0]->ids);
842 free_mem(hd_data->hddb2[0]->strings);
843 hd_data->hddb2[0] = free_mem(hd_data->hddb2[0]);
844 }
845 /* hddb2[1] is the static internal database; don't try to free it! */
846 hd_data->hddb2[1] = NULL;
847
848 hd_data->hddb_pci = free_mem(hd_data->hddb_pci);
849 hd_data->kmods = free_str_list(hd_data->kmods);
850 hd_data->bios_rom.data = free_mem(hd_data->bios_rom.data);
851 hd_data->bios_ram.data = free_mem(hd_data->bios_ram.data);
852 hd_data->bios_ebda.data = free_mem(hd_data->bios_ebda.data);
853 hd_data->cmd_line = free_mem(hd_data->cmd_line);
854 hd_data->xtra_hd = free_str_list(hd_data->xtra_hd);
855 hd_data->devtree = free_devtree(hd_data);
856 hd_data->manual = hd_free_manual(hd_data->manual);
857 hd_data->disks = free_str_list(hd_data->disks);
858 hd_data->partitions = free_str_list(hd_data->partitions);
859 hd_data->cdroms = free_str_list(hd_data->cdroms);
860
861 hd_data->smbios = smbios_free(hd_data->smbios);
862
863 hd_data->udevinfo = hd_free_udevinfo(hd_data->udevinfo);
864 hd_data->sysfsdrv = hd_free_sysfsdrv(hd_data->sysfsdrv);
865
866 hd_data->only = free_str_list(hd_data->only);
867 hd_data->scanner_db = free_str_list(hd_data->scanner_db);
868
869 for(u = 0; u < sizeof hd_data->edd / sizeof *hd_data->edd; u++) {
870 hd_data->edd[u].sysfs_id = free_mem(hd_data->edd[u].sysfs_id);
871 }
872
873 hd_data->last_idx = 0;
874
875 hd_shm_done(hd_data);
876
877 memset(hd_data, 0, sizeof *hd_data);
878
879 return NULL;
880}
881
882
883/*
884 * Free all data associated with a driver_info_t struct. Even the struct itself.
885 */
886driver_info_t *free_driver_info(driver_info_t *di)
887{
888 driver_info_t *next;
889
890#ifdef LIBHD_MEMCHECK
891 {
892 if(libhd_log)
893 fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(free_driver_info, di), di);
894 }
895#endif
896
897 for(; di; di = next) {
898 next = di->next;
899
900 switch(di->any.type) {
901 case di_any:
902 case di_display:
903 break;
904
905 case di_module:
906 free_str_list(di->module.names);
907 free_str_list(di->module.mod_args);
908 free_mem(di->module.conf);
909 break;
910
911 case di_mouse:
912 free_mem(di->mouse.xf86);
913 free_mem(di->mouse.gpm);
914 break;
915
916 case di_x11:
917 free_mem(di->x11.server);
918 free_mem(di->x11.xf86_ver);
919 free_str_list(di->x11.extensions);
920 free_str_list(di->x11.options);
921 free_str_list(di->x11.raw);
922 free_mem(di->x11.script);
923 break;
924
925 case di_isdn:
926 free_mem(di->isdn.i4l_name);
927 if(di->isdn.params) {
928 isdn_parm_t *p = di->isdn.params, *next;
929 for(; p; p = next) {
930 next = p->next;
931 free_mem(p->name);
932 free_mem(p->alt_value);
933 free_mem(p);
934 }
935 }
936 break;
937
938 case di_dsl:
939 free_mem(di->dsl.name);
940 free_mem(di->dsl.mode);
941 break;
942
943 case di_kbd:
944 free_mem(di->kbd.XkbRules);
945 free_mem(di->kbd.XkbModel);
946 free_mem(di->kbd.XkbLayout);
947 free_mem(di->kbd.keymap);
948 break;
949 }
950
951 free_str_list(di->any.hddb0);
952 free_str_list(di->any.hddb1);
953
954 free_mem(di);
955 }
956
957 return NULL;
958}
959
960
961int exists_hd_entry(hd_data_t *hd_data, hd_t *old_hd, hd_t *hd_ex)
962{
963 hd_t *hd;
964
965 if(!hd_ex) return 0;
966
967 for(hd = hd_data->hd; hd; hd = hd->next) {
968 if(hd == hd_ex) return 1;
969 }
970 for(hd = old_hd; hd; hd = hd->next) {
971 if(hd == hd_ex) return 1;
972 }
973
974 return 0;
975}
976
977
978/*!
979 * \note This may not free it.
980 */
981hd_t *hd_free_hd_list(hd_t *hd)
982{
983 hd_t *h;
984
985#ifdef LIBHD_MEMCHECK
986 {
987 if(libhd_log)
988 fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_free_hd_list, hd), hd);
989 }
990#endif
991
992 /* Note: hd->next should better be NULL! */
993 if(hd && hd->tag.freeit) {
994 free_hd_entry(hd);
995 return free_mem(hd);
996 }
997
998 /* do nothing unless the list holds only copies of hd_t entries */
999 for(h = hd; h; h = h->next) if(!h->ref) return NULL;
1000
1001 for(; hd; hd = (h = hd)->next, free_mem(h));
1002
1003 return NULL;
1004}
1005
1006hd_detail_t *free_hd_detail(hd_detail_t *d)
1007{
1008 if(!d) return NULL;
1009
1010 switch(d->type) {
1011 case hd_detail_pci: {
1012 pci_t *p = d->pci.data;
1013
1014 free_mem(p->log);
1015 free_mem(p->sysfs_id);
1016 free_mem(p->sysfs_bus_id);
1017 free_mem(p);
1018 }
1019 break;
1020
1021 case hd_detail_usb:
1022 {
1023 usb_t *u = d->usb.data;
1024
1025 if(!u->cloned) {
1026 free_str_list(u->c);
1027 free_str_list(u->e);
1028 }
1029 free_str_list(u->d);
1030 free_str_list(u->p);
1031 free_str_list(u->s);
1032 free_str_list(u->t);
1033 free_str_list(u->i);
1034
1035 free_mem(u->manufact);
1036 free_mem(u->product);
1037 free_mem(u->serial);
1038 free_mem(u->driver);
1039 free_mem(u->raw_descr.data);
1040
1041 free_mem(u);
1042 }
1043 break;
1044
1045 case hd_detail_isapnp:
1046 {
1047 isapnp_dev_t *i = d->isapnp.data;
1048 int j;
1049
1050 if(!i->ref) {
1051 free_mem(i->card->serial);
1052 free_mem(i->card->card_regs);
1053 free_mem(i->card->ldev_regs);
1054 for(j = 0; j < i->card->res_len; j++) {
1055 free_mem(i->card->res[j].data);
1056 }
1057 if(i->card->res) free_mem(i->card->res);
1058 }
1059 free_mem(i->card);
1060 free_mem(i);
1061 }
1062 break;
1063
1064 case hd_detail_cdrom:
1065 {
1066 cdrom_info_t *c = d->cdrom.data;
1067
1068 if(c) {
1069 free_mem(c->name);
1070 free_mem(c->iso9660.volume);
1071 free_mem(c->iso9660.publisher);
1072 free_mem(c->iso9660.preparer);
1073 free_mem(c->iso9660.application);
1074 free_mem(c->iso9660.creation_date);
1075 free_mem(c->el_torito.id_string);
1076 free_mem(c->el_torito.label);
1077
1078 free_mem(c);
1079 }
1080 }
1081 break;
1082
1083 case hd_detail_floppy:
1084 free_mem(d->floppy.data);
1085 break;
1086
1087 case hd_detail_bios:
1088 {
1089 bios_info_t *b = d->bios.data;
1090
1091 free_mem(b->vbe.oem_name);
1092 free_mem(b->vbe.vendor_name);
1093 free_mem(b->vbe.product_name);
1094 free_mem(b->vbe.product_revision);
1095 free_mem(b->vbe.mode);
1096 free_mem(b->lcd.vendor);
1097 free_mem(b->lcd.name);
1098 free_mem(b->mouse.vendor);
1099 free_mem(b->mouse.type);
1100
1101 free_mem(b);
1102 }
1103 break;
1104
1105 case hd_detail_cpu:
1106 {
1107 cpu_info_t *c = d->cpu.data;
1108
1109 free_mem(c->vend_name);
1110 free_mem(c->model_name);
1111 free_mem(c->platform);
1112 free_str_list(c->features);
1113 free_mem(c);
1114 }
1115 break;
1116
1117 case hd_detail_prom:
1118 free_mem(d->prom.data);
1119 break;
1120
1121 case hd_detail_monitor:
1122 {
1123 monitor_info_t *m = d->monitor.data;
1124
1125 free_mem(m->vendor);
1126 free_mem(m->name);
1127 free_mem(m->serial);
1128
1129 free_mem(m);
1130 }
1131 break;
1132
1133 case hd_detail_sys:
1134 {
1135 sys_info_t *s = d->sys.data;
1136
1137 free_mem(s->system_type);
1138 free_mem(s->generation);
1139 free_mem(s->vendor);
1140 free_mem(s->model);
1141 free_mem(s->serial);
1142 free_mem(s->lang);
1143
1144 free_mem(s);
1145 }
1146 break;
1147
1148 case hd_detail_scsi:
1149 free_scsi(d->scsi.data, 1);
1150 break;
1151
1152 case hd_detail_devtree:
1153 /* is freed with hd_data->dev_tree */
1154 break;
1155
1156 case hd_detail_ccw:
1157 free_mem(d->ccw.data);
1158 break;
1159 }
1160
1161 free_mem(d);
1162
1163 return NULL;
1164}
1165
1166
1167hd_t *free_hd_entry(hd_t *hd)
1168{
1169 free_mem(hd->bus.name);
1170 free_mem(hd->base_class.name);
1171 free_mem(hd->sub_class.name);
1172 free_mem(hd->prog_if.name);
1173 free_mem(hd->vendor.name);
1174 free_mem(hd->device.name);
1175 free_mem(hd->sub_vendor.name);
1176 free_mem(hd->sub_device.name);
1177 free_mem(hd->revision.name);
1178 free_mem(hd->serial);
1179 free_mem(hd->compat_vendor.name);
1180 free_mem(hd->compat_device.name);
1181 free_mem(hd->model);
1182 free_mem(hd->sysfs_id);
1183 free_mem(hd->sysfs_bus_id);
1184 free_mem(hd->sysfs_device_link);
1185 free_str_list(hd->unix_dev_names);
1186 free_mem(hd->unix_dev_name);
1187 free_mem(hd->unix_dev_name2);
1188 free_mem(hd->rom_id);
1189 free_mem(hd->unique_id);
1190 free_mem(hd->block0);
1191 free_mem(hd->driver);
1192 free_str_list(hd->drivers);
1193 free_mem(hd->old_unique_id);
1194 free_mem(hd->unique_id1);
1195 free_mem(hd->usb_guid);
1196 free_mem(hd->parent_id);
1197 free_str_list(hd->child_ids);
1198 free_mem(hd->config_string);
1199 free_str_list(hd->extra_info);
1200
1201 free_res_list(hd->res);
1202
1203 free_hd_detail(hd->detail);
1204
1205 free_driver_info(hd->driver_info);
1206 free_str_list(hd->requires);
1207
1208 memset(hd, 0, sizeof *hd);
1209
1210 return NULL;
1211}
1212
1213misc_t *free_misc(misc_t *m)
1214{
1215 int i, j;
1216
1217 if(!m) return NULL;
1218
1219 for(i = 0; (unsigned) i < m->io_len; i++) {
1220 free_mem(m->io[i].dev);
1221 }
1222 free_mem(m->io);
1223
1224 for(i = 0; (unsigned) i < m->dma_len; i++) {
1225 free_mem(m->dma[i].dev);
1226 }
1227 free_mem(m->dma);
1228
1229 for(i = 0; (unsigned) i < m->irq_len; i++) {
1230 for(j = 0; j < m->irq[i].devs; j++) {
1231 free_mem(m->irq[i].dev[j]);
1232 }
1233 free_mem(m->irq[i].dev);
1234 }
1235 free_mem(m->irq);
1236
1237 free_str_list(m->proc_io);
1238 free_str_list(m->proc_dma);
1239 free_str_list(m->proc_irq);
1240
1241 free_mem(m);
1242
1243 return NULL;
1244}
1245
1246scsi_t *free_scsi(scsi_t *scsi, int free_all)
1247{
1248 scsi_t *next;
1249
1250 for(; scsi; scsi = next) {
1251 next = scsi->next;
1252
1253 free_mem(scsi->dev_name);
1254 free_mem(scsi->guessed_dev_name);
1255 free_mem(scsi->vendor);
1256 free_mem(scsi->model);
1257 free_mem(scsi->rev);
1258 free_mem(scsi->type_str);
1259 free_mem(scsi->serial);
1260 free_mem(scsi->proc_dir);
1261 free_mem(scsi->driver);
1262 free_mem(scsi->info);
1263 free_mem(scsi->usb_guid);
1264 free_str_list(scsi->host_info);
1265 free_mem(scsi->controller_id);
1266
1267 if(!free_all) {
1268 next = scsi->next;
1269 memset(scsi, 0, sizeof scsi);
1270 scsi->next = next;
1271 break;
1272 }
1273
1274 free_mem(scsi);
1275 }
1276
1277 return NULL;
1278}
1279
1280
1281hd_manual_t *hd_free_manual(hd_manual_t *manual)
1282{
1283 hd_manual_t *next;
1284
1285 if(!manual) return NULL;
1286
1287 for(; manual; manual = next) {
1288 next = manual->next;
1289
1290 free_mem(manual->unique_id);
1291 free_mem(manual->parent_id);
1292 free_mem(manual->child_ids);
1293 free_mem(manual->model);
1294
1295 free_mem(manual->config_string);
1296
1297 free_str_list(manual->key);
1298 free_str_list(manual->value);
1299
1300 free_mem(manual);
1301 }
1302
1303 return NULL;
1304}
1305
1306
1307/*
1308 * Removes all hd_data->old_hd entries and frees their memory.
1309 */
1310void free_old_hd_entries(hd_data_t *hd_data)
1311{
1312 hd_t *hd, *next;
1313
1314 for(hd = hd_data->old_hd; hd; hd = next) {
1315 next = hd->next;
1316
1317 if(exists_hd_entry(hd_data, next, hd->ref) && hd->ref->ref_cnt) hd->ref->ref_cnt--;
1318
1319 if(!hd->ref) free_hd_entry(hd);
1320
1321 free_mem(hd);
1322 }
1323
1324 hd_data->old_hd = NULL;
1325}
1326
1327
1328void *new_mem(size_t size)
1329{
1330 void *p;
1331
1332 if(size == 0) return NULL;
1333
1334 p = calloc(size, 1);
1335
1336#ifdef LIBHD_MEMCHECK
1337 {
1338 if(libhd_log) fprintf(libhd_log, "%p\t%p\t0x%x\n", CALLED_FROM(new_mem, size), p, size);
1339 }
1340#endif
1341
1342 if(p) return p;
1343
1344 fprintf(stderr, "memory oops 1\n");
1345 exit(11);
1346 /*NOTREACHED*/
1347 return 0;
1348}
1349
1350void *resize_mem(void *p, size_t n)
1351{
1352#ifdef LIBHD_MEMCHECK
1353 {
1354 if(libhd_log && p) fprintf(libhd_log, "%p\t%p\n", CALLED_FROM(resize_mem, p), p);
1355 }
1356#endif
1357
1358 p = realloc(p, n);
1359
1360#ifdef LIBHD_MEMCHECK
1361 {
1362 if(libhd_log) fprintf(libhd_log, "%p\t%p\t0x%x\n", CALLED_FROM(resize_mem, p), p, n);
1363 }
1364#endif
1365
1366 if(!p) {
1367 fprintf(stderr, "memory oops 7\n");
1368 exit(17);
1369 }
1370
1371 return p;
1372}
1373
1374void *add_mem(void *p, size_t elem_size, size_t n)
1375{
1376#ifdef LIBHD_MEMCHECK
1377 {
1378 if(libhd_log && p) fprintf(libhd_log, "%p\t%p\n", CALLED_FROM(add_mem, p), p);
1379 }
1380#endif
1381
1382 p = realloc(p, (n + 1) * elem_size);
1383
1384#ifdef LIBHD_MEMCHECK
1385 {
1386 if(libhd_log) fprintf(libhd_log, "%p\t%p\t0x%x\n", CALLED_FROM(add_mem, p), p, (n + 1) * elem_size);
1387 }
1388#endif
1389
1390 if(!p) {
1391 fprintf(stderr, "memory oops 7\n");
1392 exit(17);
1393 }
1394
1395 memset(p + n * elem_size, 0, elem_size);
1396
1397 return p;
1398}
1399
1400char *new_str(const char *s)
1401{
1402 char *t;
1403
1404 if(!s) return NULL;
1405
1406 t = strdup(s);
1407
1408#ifdef LIBHD_MEMCHECK
1409 {
1410 if(libhd_log) fprintf(libhd_log, "%p\t%p\t0x%x\n", CALLED_FROM(new_str, s), t, strlen(t) + 1);
1411 }
1412#endif
1413
1414 if(t) return t;
1415
1416 fprintf(stderr, "memory oops 2\n");
1417 /*NOTREACHED*/
1418 exit(12);
1419
1420 return NULL;
1421}
1422
1423void *free_mem(void *p)
1424{
1425#ifdef LIBHD_MEMCHECK
1426 {
1427 if(libhd_log && p) fprintf(libhd_log, "%p\t%p\n", CALLED_FROM(free_mem, p), p);
1428 }
1429#endif
1430
1431 if(p) free(p);
1432
1433 return NULL;
1434}
1435
1436void join_res_io(hd_res_t **res1, hd_res_t *res2)
1437{
1438 hd_res_t *res;
1439
1440 /*
1441 * see if we must add an i/o range (tricky...)
1442 *
1443 * We look for identical i/o bases and add a range if one was missing. If
1444 * no matching pair was found, add the i/o resource.
1445 */
1446 for(; res2; res2 = res2->next) {
1447 if(res2->io.type == res_io) {
1448 for(res = *res1; res; res = res->next) {
1449 if(res->io.type == res_io) {
1450 if(res->io.base == res2->io.base) {
1451 /* identical bases: take maximum of both ranges */
1452 if(res2->io.range > res->io.range) {
1453 res->io.range = res2->io.range;
1454 }
1455 break;
1456 }
1457 else if(
1458 res->io.range &&
1459 res2->io.range &&
1460 res->io.base + res->io.range == res2->io.base)
1461 {
1462 /* res2 directly follows res1: extend res1 to cover res2 */
1463 res->io.range += res2->io.range;
1464 break;
1465 }
1466 else if(
1467 res2->io.base >= res->io.base &&
1468 res2->io.base < res->io.base + res->io.range
1469 ) {
1470 /* res2 is totally contained in res1: ignore it */
1471 break;
1472 }
1473 }
1474 }
1475 if(!res) {
1476 res = add_res_entry(res1, new_mem(sizeof *res));
1477 *res = *res2; /* *copy* the struct */
1478 res->next = NULL;
1479 }
1480 }
1481 }
1482}
1483
1484void join_res_irq(hd_res_t **res1, hd_res_t *res2)
1485{
1486 hd_res_t *res;
1487
1488 /* see if we must add an dma channel */
1489 for(; res2; res2 = res2->next) {
1490 if(res2->irq.type == res_irq) {
1491 for(res = *res1; res; res = res->next) {
1492 if(res->irq.type == res_irq && res->irq.base == res2->irq.base) break;
1493 }
1494 if(!res) {
1495 res = add_res_entry(res1, new_mem(sizeof *res));
1496 *res = *res2; /* *copy* the struct */
1497 res->next = NULL;
1498 }
1499 }
1500 }
1501}
1502
1503
1504void join_res_dma(hd_res_t **res1, hd_res_t *res2)
1505{
1506 hd_res_t *res;
1507
1508 /* see if we must add an dma channel */
1509 for(; res2; res2 = res2->next) {
1510 if(res2->dma.type == res_dma) {
1511 for(res = *res1; res; res = res->next) {
1512 if(res->dma.type == res_dma && res->dma.base == res2->dma.base) break;
1513 }
1514 if(!res) {
1515 res = add_res_entry(res1, new_mem(sizeof *res));
1516 *res = *res2; /* *copy* the struct */
1517 res->next = NULL;
1518 }
1519 }
1520 }
1521}
1522
1523
1524/*
1525 * Check whether both resource lists have common entries.
1526 */
1527int have_common_res(hd_res_t *res1, hd_res_t *res2)
1528{
1529 hd_res_t *res;
1530
1531 for(; res1; res1 = res1->next) {
1532 for(res = res2; res; res = res->next) {
1533 if(res->any.type == res1->any.type) {
1534 switch(res->any.type) {
1535 case res_io:
1536 if(res->io.base == res1->io.base) return 1;
1537 break;
1538
1539 case res_irq:
1540 if(res->irq.base == res1->irq.base) return 1;
1541 break;
1542
1543 case res_dma:
1544 if(res->dma.base == res1->dma.base) return 1;
1545 break;
1546
1547 default: /* gcc -Wall */
1548 break;
1549 }
1550 }
1551 }
1552 }
1553
1554 return 0;
1555}
1556
1557
1558/*
1559 * Free the memory allocated by a resource list.
1560 */
1561hd_res_t *free_res_list(hd_res_t *res)
1562{
1563 hd_res_t *next;
1564
1565 for(; res; res = next) {
1566 next = res->next;
1567
1568 if(res->any.type == res_init_strings) {
1569 free_mem(res->init_strings.init1);
1570 free_mem(res->init_strings.init2);
1571 }
1572
1573 if(res->any.type == res_pppd_option) {
1574 free_mem(res->pppd_option.option);
1575 }
1576
1577 if(res->any.type == res_hwaddr) {
1578 free_mem(res->hwaddr.addr);
1579 }
1580
1581 free_mem(res);
1582 }
1583
1584 return NULL;
1585}
1586
1587
1588/*
1589 * Note: new_res is directly inserted into the list, so you *must* make sure
1590 * that new_res points to a malloc'ed pice of memory.
1591 */
1592hd_res_t *add_res_entry(hd_res_t **res, hd_res_t *new_res)
1593{
1594 while(*res) res = &(*res)->next;
1595
1596 return *res = new_res;
1597}
1598
1599
1600hd_t *add_hd_entry(hd_data_t *hd_data, unsigned line, unsigned count)
1601{
1602 hd_t *hd;
1603
1604 hd = add_hd_entry2(&hd_data->hd, new_mem(sizeof *hd));
1605
1606 hd->idx = ++(hd_data->last_idx);
1607 hd->module = hd_data->module;
1608 hd->line = line;
1609 hd->count = count;
1610
1611 return hd;
1612}
1613
1614
1615hd_t *add_hd_entry2(hd_t **hd, hd_t *new_hd)
1616{
1617 while(*hd) hd = &(*hd)->next;
1618
1619 return *hd = new_hd;
1620}
1621
1622
1623void hd_scan(hd_data_t *hd_data)
1624{
1625 char *s = NULL;
1626 int i, j;
1627 hd_t *hd, *hd2;
1628 uint64_t irqs;
1629 str_list_t *sl, *sl0;
1630
1631#ifdef LIBHD_MEMCHECK
1632 if(!libhd_log) {
1633 char *s = getenv("LIBHD_MEMCHECK");
1634
1635 if(s && *s) {
1636 libhd_log = fopen(s, "w");
1637 if(libhd_log) setlinebuf(libhd_log);
1638 }
1639 }
1640#endif
1641
1642#ifdef LIBHD_MEMCHECK
1643 {
1644 if(libhd_log)
1645 fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_scan, hd_data), hd_data);
1646 }
1647#endif
1648
1649 /* log the debug & probe flags */
1650 if(hd_data->debug && !hd_data->flags.internal) {
1651 ADD2LOG("libhd version %s%s (%s)\n", HD_VERSION_STRING, getuid() ? "u" : "", HD_ARCH);
1652 }
1653
1654 get_kernel_version(hd_data);
1655
1656 /* needed only on 1st call */
1657 if(hd_data->last_idx == 0) {
1658 get_probe_env(hd_data);
1659 }
1660
1661 fix_probe_features(hd_data);
1662
1663 if(hd_data->debug && !hd_data->flags.internal) {
1664 for(i = sizeof hd_data->probe - 1; i >= 0; i--) {
1665 str_printf(&s, -1, "%02x", hd_data->probe[i]);
1666 }
1667 ADD2LOG("debug = 0x%x\nprobe = 0x%s (", hd_data->debug, s);
1668 s = free_mem(s);
1669
1670 for(i = 1; i < pr_default; i++) { /* 1 because of pr_memory */
1671 if((s = hd_probe_feature_by_value(i))) {
1672 ADD2LOG("%s%c%s", i == 1 ? "" : " ", hd_probe_feature(hd_data, i) ? '+' : '-', s);
1673 }
1674 }
1675
1676 ADD2LOG(")\n");
1677 }
1678
1679 /* init driver info database */
1680 hddb_init(hd_data);
1681
1682 /* only first time */
1683 if(hd_data->last_idx == 0) {
1684 hd_set_probe_feature(hd_data, pr_fork);
1685 if(!hd_probe_feature(hd_data, pr_fork)) hd_data->flags.nofork = 1;
1686// hd_set_probe_feature(hd_data, pr_sysfs);
1687 if(!hd_probe_feature(hd_data, pr_sysfs)) hd_data->flags.nosysfs = 1;
1688 if(hd_probe_feature(hd_data, pr_cpuemu)) hd_data->flags.cpuemu = 1;
1689 if(hd_probe_feature(hd_data, pr_udev)) hd_data->flags.udev = 1;
1690 }
1691
1692 /* get shm segment, if we didn't do it already */
1693 hd_shm_init(hd_data);
1694
1695 if(!hd_data->shm.ok && !hd_data->flags.nofork) {
1696 hd_data->flags.nofork = 1;
1697 ADD2LOG("shm: failed to get shm segment; will not fork\n");
1698 }
1699
1700 if(hd_data->only) {
1701 s = hd_join(", ", hd_data->only);
1702 ADD2LOG("only: %s\n", s);
1703 s = free_mem(s);
1704 }
1705
1706#ifndef LIBHD_TINY
1707 /*
1708 * There might be old 'manual' entries left from an earlier scan. Remove
1709 * them, they will confuse us.
1710 */
1711 if(hd_probe_feature(hd_data, pr_manual)) {
1712 hd_data->module = mod_manual;
1713 remove_hd_entries(hd_data);
1714 }
1715#endif
1716
1717 /*
1718 * for various reasons, do it befor scan_misc()
1719 */
1720 hd_scan_floppy(hd_data);
1721
1722 /*
1723 * to be able to read the right parport io,
1724 * we have to do this before scan_misc()
1725 */
1726#if defined(__i386__) || defined (__x86_64__) || defined (__ia64__)
1727 hd_scan_bios(hd_data);
1728#endif
1729
1730 /* before hd_scan_misc(): we need some ppc info later */
1731 hd_scan_sys(hd_data);
1732
1733 /* get basic system info */
1734 hd_scan_misc(hd_data);
1735
1736 /* hd_scan_cpu() after hd_scan_misc(): klog needed */
1737 hd_scan_cpu(hd_data);
1738 hd_scan_memory(hd_data);
1739
1740 hd_scan_sysfs_pci(hd_data);
1741
1742 /* do it _after_ hd_scan_sysfs_pci() */
1743#if defined(__PPC__)
1744 hd_scan_prom(hd_data);
1745#endif
1746
1747#if defined(__s390__) || defined(__s390x__)
1748 hd_scan_s390disks(hd_data);
1749 hd_scan_s390(hd_data);
1750#endif
1751
1752 /* after hd_scan_prom() and hd_scan_bios() */
1753 hd_scan_monitor(hd_data);
1754
1755#ifndef LIBHD_TINY
1756#if defined(__i386__) || defined(__alpha__)
1757 hd_scan_isapnp(hd_data);
1758#endif
1759#endif
1760
1761#ifndef LIBHD_TINY
1762#if defined(__i386__)
1763 hd_scan_isa(hd_data);
1764#endif
1765#endif
1766
1767 /* after pci & isa */
1768 hd_scan_pcmcia(hd_data);
1769
1770 hd_scan_serial(hd_data);
1771
1772 /* merge basic system info & the easy stuff */
1773 hd_scan_misc2(hd_data);
1774
1775#ifndef LIBHD_TINY
1776 if(!hd_data->flags.no_parport) {
1777 hd_scan_parallel(hd_data); /* after hd_scan_misc*() */
1778 }
1779#endif
1780
1781 hd_scan_sysfs_block(hd_data);
1782 hd_scan_sysfs_scsi(hd_data);
1783 hd_scan_sysfs_usb(hd_data);
1784 hd_scan_sysfs_edd(hd_data);
1785
1786#if defined(__PPC__)
1787 hd_scan_adb(hd_data);
1788#endif
1789
1790#ifndef LIBHD_TINY
1791#if !defined(__sparc__)
1792 hd_scan_braille(hd_data);
1793#endif
1794 hd_scan_modem(hd_data); /* do it before hd_scan_mouse() */
1795 hd_scan_mouse(hd_data);
1796#endif
1797 hd_scan_sbus(hd_data);
1798
1799 hd_scan_input(hd_data);
1800
1801#if !defined(__s390__) && !defined(__s390x__)
1802 hd_scan_kbd(hd_data);
1803#endif
1804
1805 /* must be after hd_scan_monitor() */
1806 hd_scan_fb(hd_data);
1807
1808 /* keep these at the end of the list */
1809 hd_scan_net(hd_data);
1810
1811 hd_scan_pppoe(hd_data);
1812
1813#ifndef LIBHD_TINY
1814 hd_scan_wlan(hd_data);
1815#endif
1816
1817 for(hd = hd_data->hd; hd; hd = hd->next) hd_add_id(hd_data, hd);
1818
1819#ifndef LIBHD_TINY
1820 hd_scan_manual(hd_data);
1821#endif
1822
1823 /* add test entries */
1824 hd_scan_xtra(hd_data);
1825
1826 /* some final fixup's */
1827#if WITH_ISDN
1828 hd_scan_isdn(hd_data);
1829 hd_scan_dsl(hd_data);
1830#endif
1831 hd_scan_int(hd_data);
1832
1833 /* and again... */
1834 for(hd = hd_data->hd; hd; hd = hd->next) hd_add_id(hd_data, hd);
1835
1836 /* assign parent & child ids */
1837 for(hd = hd_data->hd; hd; hd = hd->next) {
1838 hd->child_ids = free_str_list(hd->child_ids);
1839 if((hd2 = hd_get_device_by_idx(hd_data, hd->attached_to))) {
1840 free_mem(hd->parent_id);
1841 hd->parent_id = new_str(hd2->unique_id);
1842 }
1843 else if((hd2 = hd_get_device_by_id(hd_data, hd->parent_id))) {
1844 hd->attached_to = hd2->idx;
1845 }
1846 else {
1847 hd->attached_to = 0;
1848 }
1849 }
1850
1851 for(hd = hd_data->hd; hd; hd = hd->next) {
1852 if((hd2 = hd_get_device_by_idx(hd_data, hd->attached_to))) {
1853 add_str_list(&hd2->child_ids, hd->unique_id);
1854 }
1855 }
1856
1857 /* assign a hw_class & build a useful model string */
1858 for(hd = hd_data->hd; hd; hd = hd->next) {
1859 assign_hw_class(hd_data, hd);
1860
1861 /* create model name _after_ hw_class */
1862 create_model_name(hd_data, hd);
1863 }
1864
1865#ifndef LIBHD_TINY
1866 /* must be _after_ we have valid hw_class entries */
1867 hd_scan_manual2(hd_data);
1868#endif
1869
1870 /* we are done... */
1871 for(hd = hd_data->hd; hd; hd = hd->next) hd->tag.fixed = 1;
1872
1873 /* for compatibility */
1874 for(hd = hd_data->hd; hd; hd = hd->next) {
1875 hd->driver = free_mem(hd->driver);
1876 if(hd->drivers && hd->drivers->str) hd->driver = new_str(hd->drivers->str);
1877 }
1878
1879 hd_data->module = mod_none;
1880
1881 if(
1882 hd_data->debug &&
1883 !hd_data->flags.internal &&
1884 (
1885 hd_data->kmods ||
1886 hd_probe_feature(hd_data, pr_int /* arbitrary; just avoid /proc/modules for -pr_all */)
1887 )
1888 ) {
1889 sl0 = read_file(PROC_MODULES, 0, 0);
1890 ADD2LOG("----- /proc/modules -----\n");
1891 for(sl = sl0; sl; sl = sl->next) {
1892 ADD2LOG(" %s", sl->str);
1893 }
1894 ADD2LOG("----- /proc/modules end -----\n");
1895 free_str_list(sl0);
1896 }
1897
1898 update_irq_usage(hd_data);
1899
1900 if(hd_data->debug && !hd_data->flags.internal) {
1901 irqs = hd_data->used_irqs;
1902
1903 ADD2LOG(" used irqs:");
1904 for(i = j = 0; i < 64; i++, irqs >>= 1) {
1905 if((irqs & 1)) {
1906 ADD2LOG("%c%d", j ? ',' : ' ', i);
1907 j = 1;
1908 }
1909 }
1910 ADD2LOG("\n");
1911 }
1912}
1913
1914
1915/*
1916 * Note: due to byte order problems decoding the id is really a mess...
1917 * And, we use upper case for hex numbers!
1918 */
1919char *isa_id2str(unsigned id)
1920{
1921 char *s = new_mem(8);
1922 unsigned u = ((id & 0xff) << 8) + ((id >> 8) & 0xff);
1923 unsigned v = ((id >> 8) & 0xff00) + ((id >> 24) & 0xff);
1924
1925 s[0] = ((u >> 10) & 0x1f) + 'A' - 1;
1926 s[1] = ((u >> 5) & 0x1f) + 'A' - 1;
1927 s[2] = ( u & 0x1f) + 'A' - 1;
1928
1929 sprintf(s + 3, "%04X", v);
1930
1931 return s;
1932}
1933
1934char *eisa_vendor_str(unsigned v)
1935{
1936 static char s[4];
1937
1938 s[0] = ((v >> 10) & 0x1f) + 'A' - 1;
1939 s[1] = ((v >> 5) & 0x1f) + 'A' - 1;
1940 s[2] = ( v & 0x1f) + 'A' - 1;
1941 s[3] = 0;
1942
1943 return s;
1944}
1945
1946
1947/*
1948 * Must _not_ check that s is exactly 3 chars.
1949 */
1950unsigned name2eisa_id(char *s)
1951{
1952 int i;
1953 unsigned u = 0;
1954
1955 for(i = 0; i < 3; i++) {
1956 u <<= 5;
1957 if(s[i] < 'A' - 1 || s[i] > 'A' - 1 + 0x1f) return 0;
1958 u += s[i] - 'A' + 1;
1959 }
1960
1961 return MAKE_ID(TAG_EISA, u);
1962}
1963
1964
1965/*
1966 * Create a 'canonical' version, i.e. no spaces at start and end.
1967 *
1968 * Note: removes chars >= 0x80 as well (due to (char *))! This
1969 * is currently considered a feature.
1970 */
1971char *canon_str(char *s, int len)
1972{
1973 char *m2, *m1, *m0;
1974 int i;
1975
1976#ifdef LIBHD_MEMCHECK
1977 {
1978 if(libhd_log) fprintf(libhd_log, ">%p\n", CALLED_FROM(canon_str, s));
1979 }
1980#endif
1981
1982 if(len < 0) len = 0; /* just to be safe */
1983
1984 m0 = new_mem(len + 1);
1985
1986 for(m1 = m0, i = 0; i < len; i++) {
1987 if(m1 == m0 && s[i] <= ' ') continue;
1988 *m1++ = s[i];
1989 }
1990 *m1 = 0;
1991 while(m1 > m0 && m1[-1] <= ' ') {
1992 *--m1 = 0;
1993 }
1994
1995 m2 = new_str(m0);
1996 free_mem(m0);
1997
1998#ifdef LIBHD_MEMCHECK
1999 {
2000 if(libhd_log) fprintf(libhd_log, "<%p\n", CALLED_FROM(canon_str, s));
2001 }
2002#endif
2003
2004 return m2;
2005}
2006
2007
2008/*
2009 * Convert a n-digit hex number to its numerical value.
2010 */
2011int hex(char *s, int n)
2012{
2013 int i = 0, j;
2014
2015 while(n--) {
2016 if(sscanf(s++, "%1x", &j) != 1) return -1;
2017 i = (i << 4) + j;
2018 }
2019
2020 return i;
2021}
2022
2023
2024/* simple 32 bit fixed point numbers with n decimals */
2025int str2float(char *s, int n)
2026{
2027 int i = 0;
2028 int dot = 0;
2029
2030 while(*s) {
2031 if(*s == '.') {
2032 if(dot++) return 0;
2033 }
2034 else if(*s >= '0' && *s <= '9') {
2035 if(dot) {
2036 if(!n) return i;
2037 n--;
2038 }
2039 i *= 10;
2040 i += *s - '0';
2041 }
2042 else {
2043 return 0;
2044 }
2045
2046 s++;
2047 }
2048
2049 while(n--) i *= 10;
2050
2051 return i;
2052}
2053
2054
2055/* simple 32 bit fixed point numbers with n decimals */
2056char *float2str(int f, int n)
2057{
2058 int i = 1, j, m = n;
2059 static char buf[32];
2060
2061 while(n--) i *= 10;
2062
2063 j = f / i;
2064 i = f % i;
2065
2066 while(i && !(i % 10)) i /= 10, m--;
2067
2068 if(i) {
2069 sprintf(buf, "%d.%0*d", j, m, i);
2070 }
2071 else {
2072 sprintf(buf, "%d", j);
2073 }
2074
2075 return buf;
2076}
2077
2078
2079/*
2080 * find hardware entry with given index
2081 */
2082hd_t *hd_get_device_by_idx(hd_data_t *hd_data, unsigned idx)
2083{
2084 hd_t *hd;
2085
2086#ifdef LIBHD_MEMCHECK
2087 {
2088 if(libhd_log)
2089 fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_get_device_by_idx, hd_data), hd_data);
2090 }
2091#endif
2092
2093 if(!idx) return NULL; /* early out: idx is always != 0 */
2094
2095 for(hd = hd_data->hd; hd; hd = hd->next) {
2096 if(hd->idx == idx) return hd;
2097 }
2098
2099 return NULL;
2100}
2101
2102
2103/*
2104 * find hardware entry with given unique id
2105 */
2106hd_t *hd_get_device_by_id(hd_data_t *hd_data, char *id)
2107{
2108 hd_t *hd;
2109
2110 if(!id) return NULL;
2111
2112 for(hd = hd_data->hd; hd; hd = hd->next) {
2113 if(hd->unique_id && !strcmp(hd->unique_id, id)) return hd;
2114 }
2115
2116 return NULL;
2117}
2118
2119
2120/*
2121 * Give the actual name of the probing module.
2122 */
2123char *mod_name_by_idx(unsigned idx)
2124{
2125 unsigned u;
2126
2127 for(u = 0; u < sizeof pr_modules / sizeof *pr_modules; u++)
2128 if(idx == pr_modules[u].val) return pr_modules[u].name;
2129
2130 return "";
2131}
2132
2133
2134/*
2135 * Print to a string.
2136 * Note: *buf must point to a malloc'd memory area (or be NULL).
2137 *
2138 * Use an offset of -1 or -2 to append the new string.
2139 *
2140 * As this function is quite often used to extend our log messages, there
2141 * is a cache that holds the length of the last string we created. This way
2142 * we speed this up somewhat. Use an offset of -2 to use this feature.
2143 * Note: this only works as long as str_printf() is used *exclusively* to
2144 * extend the string.
2145 */
2146void str_printf(char **buf, int offset, char *format, ...)
2147{
2148 static char *last_buf = NULL;
2149 static int last_len = 0;
2150 int len, use_cache;
2151 char b[0x10000];
2152 va_list args;
2153
2154#ifdef LIBHD_MEMCHECK
2155 {
2156 if(libhd_log) fprintf(libhd_log, ">%p\n", CALLED_FROM(str_printf, buf));
2157 }
2158#endif
2159
2160 use_cache = offset == -2 ? 1 : 0;
2161
2162 if(*buf) {
2163 if(offset == -1) {
2164 offset = strlen(*buf);
2165 }
2166 else if(offset == -2) {
2167 if(last_buf == *buf && last_len && !(*buf)[last_len])
2168 offset = last_len;
2169 else
2170 offset = strlen(*buf);
2171 }
2172 }
2173 else {
2174 offset = 0;
2175 }
2176
2177 va_start(args, format);
2178 vsnprintf(b, sizeof b, format, args);
2179 va_end(args);
2180
2181 *buf = resize_mem(*buf, (len = offset + strlen(b)) + 1);
2182 strcpy(*buf + offset, b);
2183
2184 if(use_cache) {
2185 last_buf = *buf;
2186 last_len = len;
2187 }
2188
2189#ifdef LIBHD_MEMCHECK
2190 {
2191 if(libhd_log) fprintf(libhd_log, "<%p\n", CALLED_FROM(str_printf, buf));
2192 }
2193#endif
2194}
2195
2196
2197void hexdump(char **buf, int with_ascii, unsigned data_len, unsigned char *data)
2198{
2199 unsigned i;
2200
2201 for(i = 0; i < data_len; i++) {
2202 if(i)
2203 str_printf(buf, -2, " %02x", data[i]);
2204 else
2205 str_printf(buf, -2, "%02x", data[i]);
2206 }
2207
2208 if(with_ascii) {
2209 str_printf(buf, -2, " \"");
2210 for(i = 0; i < data_len; i++) {
2211 str_printf(buf, -2, "%c", data[i] < ' ' || data[i] >= 0x7f ? '.' : data[i]);
2212 }
2213 str_printf(buf, -2, "\"");
2214 }
2215}
2216
2217
2218/** \relates s_str_list_t
2219 * Search a string list for a string.
2220 */
2221str_list_t *search_str_list(str_list_t *sl, char *str)
2222{
2223 if(!str) return NULL;
2224
2225 for(; sl; sl = sl->next) if(sl->str && !strcmp(sl->str, str)) return sl;
2226
2227 return NULL;
2228}
2229
2230
2231/** \relates s_str_list_t
2232 * Add a string to a string list.
2233 *
2234 * The new string (str) will be *copied*!
2235 */
2236str_list_t *add_str_list(str_list_t **sl, char *str)
2237{
2238#ifdef LIBHD_MEMCHECK
2239 {
2240 if(libhd_log) fprintf(libhd_log, ">%p\n", CALLED_FROM(add_str_list, sl));
2241 }
2242#endif
2243
2244 while(*sl) sl = &(*sl)->next;
2245
2246 *sl = new_mem(sizeof **sl);
2247 (*sl)->str = new_str(str);
2248
2249#ifdef LIBHD_MEMCHECK
2250 {
2251 if(libhd_log) fprintf(libhd_log, "<%p\n", CALLED_FROM(add_str_list, sl));
2252 }
2253#endif
2254
2255 return *sl;
2256}
2257
2258
2259/** \relates s_str_list_t
2260 * Free the memory allocated by a string list.
2261 */
2262str_list_t *free_str_list(str_list_t *list)
2263{
2264 str_list_t *l;
2265
2266 for(; list; list = (l = list)->next, free_mem(l)) {
2267 free_mem(list->str);
2268 }
2269
2270 return NULL;
2271}
2272
2273
2274/*
2275 * Read a file; return a linked list of lines.
2276 *
2277 * start_line is zero-based; lines == 0 -> all lines
2278 */
2279str_list_t *read_file(char *file_name, unsigned start_line, unsigned lines)
2280{
2281 FILE *f;
2282 char buf[0x10000];
2283 int pipe = 0;
2284 str_list_t *sl_start = NULL, *sl_end = NULL, *sl;
2285
2286#ifdef LIBHD_MEMCHECK
2287 {
2288 if(libhd_log) fprintf(libhd_log, ">%p\n", CALLED_FROM(read_file, file_name));
2289 }
2290#endif
2291
2292 if(*file_name == '|') {
2293 pipe = 1;
2294 file_name++;
2295 if(!(f = popen(file_name, "r"))) {
2296#ifdef LIBHD_MEMCHECK
2297 {
2298 if(libhd_log) fprintf(libhd_log, "<%p\n", CALLED_FROM(read_file, file_name));
2299 }
2300#endif
2301 return NULL;
2302 }
2303 }
2304 else {
2305 if(!(f = fopen(file_name, "r"))) {
2306#ifdef LIBHD_MEMCHECK
2307 {
2308 if(libhd_log) fprintf(libhd_log, "<%p\n", CALLED_FROM(read_file, file_name));
2309 }
2310#endif
2311 return NULL;
2312 }
2313 }
2314
2315 while(fgets(buf, sizeof buf, f)) {
2316 if(start_line) {
2317 start_line--;
2318 continue;
2319 }
2320 sl = new_mem(sizeof *sl);
2321 sl->str = new_str(buf);
2322 if(sl_start)
2323 sl_end->next = sl;
2324 else
2325 sl_start = sl;
2326 sl_end = sl;
2327
2328 if(lines == 1) break;
2329 lines--;
2330 }
2331
2332 if(pipe)
2333 pclose(f);
2334 else
2335 fclose(f);
2336
2337#ifdef LIBHD_MEMCHECK
2338 {
2339 if(libhd_log) fprintf(libhd_log, "<%p\n", CALLED_FROM(read_file, file_name));
2340 }
2341#endif
2342
2343 return sl_start;
2344}
2345
2346
2347/*
2348 * Read directory, return a list of entries with file type 'type'.
2349 */
2350str_list_t *read_dir(char *dir_name, int type)
2351{
2352 str_list_t *sl_start = NULL, *sl_end = NULL, *sl;
2353 DIR *dir;
2354 struct dirent *de;
2355 struct stat sbuf;
2356 char *s;
2357 int dir_type;
2358
2359 if(dir_name && (dir = opendir(dir_name))) {
2360 while((de = readdir(dir))) {
2361 if(!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) continue;
2362 dir_type = 0;
2363
2364 if(type) {
2365 s = NULL;
2366 str_printf(&s, 0, "%s/%s", dir_name, de->d_name);
2367
2368 if(!lstat(s, &sbuf)) {
2369 if(S_ISDIR(sbuf.st_mode)) {
2370 dir_type = 'd';
2371 }
2372 else if(S_ISREG(sbuf.st_mode)) {
2373 dir_type = 'r';
2374 }
2375 else if(S_ISLNK(sbuf.st_mode)) {
2376 dir_type = 'l';
2377 }
2378 }
2379
2380 s = free_mem(s);
2381 }
2382
2383 if(dir_type == type) {
2384 sl = new_mem(sizeof *sl);
2385 sl->str = new_str(de->d_name);
2386 if(sl_start)
2387 sl_end->next = sl;
2388 else
2389 sl_start = sl;
2390 sl_end = sl;
2391 }
2392 }
2393 closedir(dir);
2394 }
2395
2396 return sl_start;
2397}
2398
2399
2400char *hd_read_symlink(char *link_name)
2401{
2402 static char buf[256];
2403 int i;
2404
2405 i = readlink(link_name, buf, sizeof buf);
2406 buf[sizeof buf - 1] = 0;
2407 if(i >= 0 && (unsigned) i < sizeof buf) buf[i] = 0;
2408 if(i < 0) *buf = 0;
2409
2410 return buf;
2411}
2412
2413
2414/*
2415 * Log the hardware detection progress.
2416 */
2417void progress(hd_data_t *hd_data, unsigned pos, unsigned count, char *msg)
2418{
2419 char buf1[32], buf2[32], buf3[128], *fn;
2420
2421 if(hd_data->shm.ok && hd_data->flags.forked) {
2422 ((hd_data_t *) (hd_data->shm.data))->shm.updated++;
2423 }
2424
2425 if(!msg) msg = "";
2426
2427 sprintf(buf1, "%u", hd_data->module);
2428 sprintf(buf2, ".%u", count);
2429 fn = mod_name_by_idx(hd_data->module);
2430
2431 sprintf(buf3, "%s.%u%s", *fn ? fn : buf1, pos, count ? buf2 : "");
2432
2433 if((hd_data->debug & HD_DEB_PROGRESS))
2434 ADD2LOG(">> %s: %s\n", buf3, msg);
2435
2436 if(hd_data->progress) hd_data->progress(buf3, msg);
2437}
2438
2439
2440
2441/*
2442 * Returns a probe feature suitable for hd_*probe_feature().
2443 * If name is not a valid probe feature, 0 is returned.
2444 *
2445 */
2446enum probe_feature hd_probe_feature_by_name(char *name)
2447{
2448 unsigned u;
2449
2450#ifdef LIBHD_MEMCHECK
2451 {
2452 if(libhd_log)
2453 fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_probe_feature_by_name, name), name);
2454 }
2455#endif
2456
2457 for(u = 0; u < sizeof pr_flags / sizeof *pr_flags; u++)
2458 if(!strcmp(name, pr_flags[u].name)) return pr_flags[u].val;
2459
2460 return 0;
2461}
2462
2463
2464/*
2465 * Coverts a enum probe_feature to a string.
2466 * If it fails, NULL is returned.
2467 */
2468char *hd_probe_feature_by_value(enum probe_feature feature)
2469{
2470 unsigned u;
2471
2472#ifdef LIBHD_MEMCHECK
2473 {
2474 if(libhd_log)
2475 fprintf(libhd_log, "; %s\t%p\t%u\n", __FUNCTION__, CALLED_FROM(hd_probe_feature_by_value, feature), feature);
2476 }
2477#endif
2478
2479 for(u = 0; u < sizeof pr_flags / sizeof *pr_flags; u++)
2480 if(feature == pr_flags[u].val) return pr_flags[u].name;
2481
2482 return NULL;
2483}
2484
2485
2486/*
2487 * Removes all hd_data->hd entries created by the current module from the
2488 * list. The old entries are added to hd_data->old_hd.
2489 */
2490void remove_hd_entries(hd_data_t *hd_data)
2491{
2492 hd_t *hd;
2493
2494 for(hd = hd_data->hd; hd; hd = hd->next) {
2495 if(hd->module == hd_data->module) {
2496 hd->tag.remove = 1;
2497 }
2498 }
2499
2500 remove_tagged_hd_entries(hd_data);
2501}
2502
2503
2504/*
2505 * Removes all hd_data->hd entries that have the remove tag set from the
2506 * list. The old entries are added to hd_data->old_hd.
2507 */
2508void remove_tagged_hd_entries(hd_data_t *hd_data)
2509{
2510 hd_t *hd, **prev, **h;
2511
2512 for(hd = *(prev = &hd_data->hd); hd;) {
2513 if(hd->tag.remove) {
2514 /* find end of the old list... */
2515 h = &hd_data->old_hd;
2516 while(*h) h = &(*h)->next;
2517 *h = hd; /* ...and append the entry */
2518
2519 hd = *prev = hd->next;
2520 (*h)->next = NULL;
2521 }
2522 else {
2523 hd = *(prev = &hd->next);
2524 }
2525 }
2526}
2527
2528
2529int hd_module_is_active(hd_data_t *hd_data, char *mod)
2530{
2531 str_list_t *sl, *sl0 = read_kmods(hd_data);
2532 int active = 0;
2533 char *s;
2534#ifdef __PPC__
2535 char *s1, *s2;
2536#endif
2537
2538#ifdef LIBHD_MEMCHECK
2539 {
2540 if(libhd_log)
2541 fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_module_is_active, hd_data), hd_data);
2542 }
2543#endif
2544
2545 mod = new_str(mod);
2546
2547 /* convert '-' to '_' */
2548 for(s = mod; *s; s++) if(*s == '-') *s = '_';
2549
2550 for(sl = sl0; sl; sl = sl->next) {
2551 if(!strcmp(sl->str, mod)) break;
2552 }
2553
2554 free_str_list(sl0);
2555 active = sl ? 1 : 0;
2556
2557 if(active) {
2558 free_mem(mod);
2559
2560 return active;
2561 }
2562
2563#ifdef __PPC__
2564 /* temporary hack for ppc */
2565 if(!strcmp(mod, "gmac")) {
2566 s1 = "<6>eth";
2567 s2 = " GMAC ";
2568 }
2569 else if(!strcmp(mod, "mace")) {
2570 s1 = "<6>eth";
2571 s2 = " MACE ";
2572 }
2573 else if(!strcmp(mod, "bmac")) {
2574 s1 = "<6>eth";
2575 s2 = " BMAC";
2576 }
2577 else if(!strcmp(mod, "mac53c94")) {
2578 s1 = "<4>scsi";
2579 s2 = " 53C94";
2580 }
2581 else if(!strcmp(mod, "mesh")) {
2582 s1 = "<4>scsi";
2583 s2 = " MESH";
2584 }
2585 else if(!strcmp(mod, "swim3")) {
2586 s1 = "<6>fd";
2587 s2 = " SWIM3 ";
2588 }
2589 else {
2590 s1 = s2 = NULL;
2591 }
2592
2593 if(s1) {
2594 for(sl = hd_data->klog; sl; sl = sl->next) {
2595 if(strstr(sl->str, s1) == sl->str && strstr(sl->str, s2)) {
2596 active = 1;
2597 break;
2598 }
2599 }
2600 }
2601#endif
2602
2603 free_mem(mod);
2604
2605 return active;
2606}
2607
2608
2609int hd_has_pcmcia(hd_data_t *hd_data)
2610{
2611 hd_t *hd;
2612
2613 for(hd = hd_data->hd; hd; hd = hd->next) {
2614 if(is_pcmcia_ctrl(hd_data, hd)) return 1;
2615 }
2616
2617 return 0;
2618}
2619
2620
2621int hd_apm_enabled(hd_data_t *hd_data)
2622{
2623 hd_t *hd;
2624
2625#ifdef LIBHD_MEMCHECK
2626 {
2627 if(libhd_log)
2628 fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_apm_enabled, hd_data), hd_data);
2629 }
2630#endif
2631
2632 for(hd = hd_data->hd; hd; hd = hd->next) {
2633 if(
2634 hd->base_class.id == bc_internal &&
2635 hd->sub_class.id == sc_int_bios &&
2636 hd->detail &&
2637 hd->detail->type == hd_detail_bios &&
2638 hd->detail->bios.data
2639 ) {
2640 return hd->detail->bios.data->apm_enabled;
2641 }
2642 }
2643
2644 return 0;
2645}
2646
2647
2648int hd_usb_support(hd_data_t *hd_data)
2649{
2650 hd_t *hd;
2651 hd_res_t *res;
2652
2653#ifdef LIBHD_MEMCHECK
2654 {
2655 if(libhd_log)
2656 fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_usb_support, hd_data), hd_data);
2657 }
2658#endif
2659
2660 for(hd = hd_data->hd; hd; hd = hd->next) {
2661 if(hd->base_class.id == bc_serial && hd->sub_class.id == sc_ser_usb) {
2662 for(res = hd->res; res; res = res->next) {
2663 if(res->any.type == res_irq)
2664 return hd->prog_if.id == pif_usb_ohci ? 2 : 1; /* 2: ohci, 1: uhci */
2665 }
2666 }
2667 }
2668
2669 return 0;
2670}
2671
2672
2673int hd_smp_support(hd_data_t *hd_data)
2674{
2675 int is_smp = 0;
2676 unsigned u;
2677 hd_t *hd, *hd0;
2678#if defined(__i386__) || defined (__x86_64__)
2679 unsigned cpu_threads = 0;
2680 cpu_info_t *ct;
2681#endif
2682
2683#ifdef LIBHD_MEMCHECK
2684 {
2685 if(libhd_log)
2686 fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_smp_support, hd_data), hd_data);
2687 }
2688#endif
2689
2690 u = hd_data->flags.internal;
2691 hd_data->flags.internal = 1;
2692 hd = hd_list(hd_data, hw_cpu, 0, NULL);
2693 if(!hd) hd = hd_list(hd_data, hw_cpu, 1, NULL);
2694 hd_data->flags.internal = u;
2695
2696 for(is_smp = 0, hd0 = hd; hd0; hd0 = hd0->next) is_smp++;
2697 if(is_smp == 1) is_smp = 0;
2698
2699#if defined(__i386__) || defined (__x86_64__)
2700 if(
2701 hd &&
2702 hd->detail &&
2703 hd->detail->type == hd_detail_cpu &&
2704 (ct = hd->detail->cpu.data)
2705 ) {
2706 cpu_threads = ct->units;
2707 }
2708#endif
2709
2710 hd = hd_free_hd_list(hd);
2711
2712#if !defined(LIBHD_TINY) && (defined(__i386__) || defined (__x86_64__))
2713 if(is_smp < 2) {
2714 if(!hd_data->bios_ram.data) {
2715 hd_free_hd_list(hd_list(hd_data, hw_sys, 1, NULL));
2716 }
2717 is_smp = detect_smp_bios(hd_data);
2718 // at least 2 processors
2719 if(is_smp < 2) is_smp = 0;
2720 if(!is_smp && cpu_threads > 1) is_smp = 2;
2721 }
2722#endif
2723
2724#ifdef __PPC__
2725 if(is_smp < 2) {
2726 if(!hd_data->devtree) {
2727 hd_free_hd_list(hd_list(hd_data, hw_sys, 1, NULL));
2728 }
2729 is_smp = detect_smp_prom(hd_data);
2730 if(is_smp < 0) is_smp = 0;
2731 }
2732#endif
2733
2734#if defined(__s390__) || defined(__s390x__)
2735 if(!is_smp) is_smp = 1;
2736#endif
2737
2738 return is_smp;
2739}
2740
2741
2742int hd_color(hd_data_t *hd_data)
2743{
2744#if 0
2745 hd_t *hd;
2746 prom_info_t *pt;
2747
2748 for(hd = hd_data->hd; hd; hd = hd->next) {
2749 if(
2750 hd->base_class.id == bc_internal && hd->sub_class.id == sc_int_prom &&
2751 hd->detail && hd->detail->type == hd_detail_prom &&
2752 (pt = hd->detail->prom.data) &&
2753 pt->has_color
2754 ) {
2755 return pt->color;
2756 }
2757 }
2758#endif
2759
2760#ifdef LIBHD_MEMCHECK
2761 {
2762 if(libhd_log)
2763 fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_color, hd_data), hd_data);
2764 }
2765#endif
2766
2767 if(hd_data->color_code) return hd_data->color_code & 0xffff;
2768
2769 return -1;
2770}
2771
2772
2773int hd_mac_color(hd_data_t *hd_data)
2774{
2775#ifdef LIBHD_MEMCHECK
2776 {
2777 if(libhd_log)
2778 fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_mac_color, hd_data), hd_data);
2779 }
2780#endif
2781
2782 return hd_color(hd_data);
2783}
2784
2785
2786unsigned hd_display_adapter(hd_data_t *hd_data)
2787{
2788 hd_t *hd;
2789 driver_info_t *di;
2790 unsigned disp, disp_sbus, disp_pci, disp_any, disp_di;
2791 unsigned disp_cnt, disp_any_cnt;
2792
2793#ifdef LIBHD_MEMCHECK
2794 {
2795 if(libhd_log)
2796 fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_display_adapter, hd_data), hd_data);
2797 }
2798#endif
2799
2800 /* if we know exactly where our primary display is, return it */
2801 if(hd_get_device_by_idx(hd_data, hd_data->display)) return hd_data->display;
2802
2803 disp = disp_sbus = disp_pci = disp_any = disp_di = 0;
2804 disp_cnt = disp_any_cnt = 0;
2805
2806 for(hd = hd_data->hd; hd; hd = hd->next) {
2807 if(hd->base_class.id == bc_display) {
2808 disp_any_cnt++;
2809 if(!disp_any) disp_any = hd->idx;
2810 if(hd->sub_class.id == sc_dis_vga) {
2811 disp_cnt++;
2812 if(!disp) disp = hd->idx;
2813 if(hd->bus.id == bus_pci && !disp_pci) disp_pci = hd->idx;
2814 if(hd->bus.id == bus_sbus && !disp_sbus) disp_sbus = hd->idx;
2815 }
2816 if(!disp_di) {
2817 if(!(di = hd->driver_info)) {
2818 hddb_add_info(hd_data, hd);
2819 di = hd->driver_info;
2820 }
2821 if(di && di->any.type == di_x11 && di->x11.server) {
2822 disp_di = hd->idx;
2823 }
2824 }
2825 }
2826 }
2827
2828 /* if there's only one display adapter, return it */
2829 if(disp_any_cnt == 1) return disp_any;
2830
2831 /* if there's only one vga compatible adapter, return it */
2832 if(disp_cnt == 1) return disp;
2833
2834 /* return 1st (vga compatible) sbus card */
2835 /* note: the sbus code enters display cards as 'vga compatible' */
2836 if(disp_sbus) return disp_sbus;
2837
2838 /* return 1st display adapter that has some x11 info */
2839 if(disp_di) return disp_di;
2840
2841 /* return 1st vga compatible pci card */
2842 if(disp_pci) return disp_pci;
2843
2844 /* return 1st vga compatible card */
2845 if(disp) return disp;
2846
2847 /* return 1st display adapter */
2848 if(disp_any) return disp_any;
2849
2850 /* there were none... */
2851 return 0;
2852}
2853
2854
2855enum cpu_arch hd_cpu_arch(hd_data_t *hd_data)
2856{
2857 hd_t *hd;
2858
2859#ifdef LIBHD_MEMCHECK
2860 {
2861 if(libhd_log)
2862 fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_cpu_arch, hd_data), hd_data);
2863 }
2864#endif
2865
2866 for(hd = hd_data->hd; hd; hd = hd->next) {
2867 if(
2868 hd->base_class.id == bc_internal &&
2869 hd->sub_class.id == sc_int_cpu &&
2870 hd->detail &&
2871 hd->detail->type == hd_detail_cpu &&
2872 hd->detail->cpu.data
2873 ) {
2874 return hd->detail->cpu.data->architecture;
2875 }
2876 }
2877
2878#ifdef __i386__
2879 return arch_intel;
2880#else
2881#ifdef __alpha__
2882 return arch_alpha;
2883#else
2884#ifdef __PPC__
2885 return arch_ppc;
2886#else
2887#ifdef __sparc__
2888 return arch_sparc;
2889#else
2890#ifdef __s390x__
2891 return arch_s390x;
2892#else
2893#ifdef __s390__
2894 return arch_s390;
2895#else
2896#ifdef __ia64__
2897 return arch_ia64;
2898#else
2899#ifdef __x86_64__
2900 return arch_x86_64;
2901#else
2902 return arch_unknown;
2903#endif
2904#endif
2905#endif
2906#endif
2907#endif
2908#endif
2909#endif
2910#endif
2911}
2912
2913
2914enum boot_arch hd_boot_arch(hd_data_t *hd_data)
2915{
2916#ifdef LIBHD_MEMCHECK
2917 {
2918 if(libhd_log)
2919 fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_boot_arch, hd_data), hd_data);
2920 }
2921#endif
2922
2923 return hd_data->boot;
2924}
2925
2926
2927int hd_is_uml(hd_data_t *hd_data)
2928{
2929 int is_uml = 0;
2930 hd_t *hd;
2931 cpu_info_t *ct;
2932 unsigned u;
2933 unsigned saved_mod = hd_data->module;
2934 unsigned char probe_save[sizeof hd_data->probe];
2935
2936 u = hd_data->flags.internal;
2937 hd_data->flags.internal = 1;
2938 hd = hd_list(hd_data, hw_cpu, 0, NULL);
2939 if(!hd) {
2940 /* Do *not* run hd_list(,, 1,) here! */
2941 memcpy(probe_save, hd_data->probe, sizeof probe_save);
2942 hd_set_probe_feature(hd_data, pr_cpu);
2943 hd_scan_cpu(hd_data);
2944 memcpy(hd_data->probe, probe_save, sizeof hd_data->probe);
2945 for(hd = hd_data->hd; hd; hd = hd->next) {
2946 if(hd->base_class.id == bc_internal && hd->sub_class.id == sc_int_cpu) break;
2947 }
2948 }
2949 hd_data->flags.internal = u;
2950
2951 if(
2952 hd &&
2953 hd->detail &&
2954 hd->detail->type == hd_detail_cpu &&
2955 (ct = hd->detail->cpu.data) &&
2956 ct->model_name &&
2957 !strcmp(ct->model_name, "UML")
2958 ) {
2959 is_uml = 1;
2960 }
2961
2962 hd = hd_free_hd_list(hd);
2963
2964 hd_data->module = saved_mod;
2965
2966 return is_uml;
2967}
2968
2969
2970int hd_is_sgi_altix(hd_data_t *hd_data)
2971{
2972 struct stat sbuf;
2973
2974 return stat("/proc/sgi_sn", &sbuf) ? 0 : 1;
2975}
2976
2977
2978int hd_is_iseries(hd_data_t *hd_data)
2979{
2980 struct stat sbuf;
2981
2982 return stat(PROC_ISERIES, &sbuf) ? 0 : 1;
2983}
2984
2985
2986/*
2987 * makes a (shallow) copy; does some magic fixes
2988 */
2989void hd_copy(hd_t *dst, hd_t *src)
2990{
2991 hd_t *tmp;
2992// unsigned u;
2993
2994 tmp = dst->next;
2995// u = dst->idx;
2996
2997 *dst = *src;
2998 src->ref_cnt++;
2999 dst->ref = src;
3000
3001 dst->next = tmp;
3002// dst->idx = u;
3003
3004 /* needed to keep in sync with the real device tree */
3005 if(
3006 dst->detail &&
3007 dst->detail->type == hd_detail_devtree
3008 ) {
3009 dst->detail = NULL; /* ??? was: free_mem(dst->detail); */
3010 }
3011}
3012
3013
3014hd_t *hd_list(hd_data_t *hd_data, hd_hw_item_t item, int rescan, hd_t *hd_old)
3015{
3016 hd_t *hd, *hd1, *hd_list = NULL;
3017 unsigned char probe_save[sizeof hd_data->probe];
3018 unsigned fast_save;
3019
3020#ifdef LIBHD_MEMCHECK
3021#ifndef __PPC__
3022 {
3023 if(libhd_log)
3024 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);
3025 }
3026#endif
3027#endif
3028
3029 if(rescan) {
3030 memcpy(probe_save, hd_data->probe, sizeof probe_save);
3031 fast_save = hd_data->flags.fast;
3032 hd_clear_probe_feature(hd_data, pr_all);
3033#ifdef __powerpc__
3034 hd_set_probe_feature(hd_data, pr_sys);
3035 hd_scan(hd_data);
3036#endif
3037 hd_set_probe_feature_hw(hd_data, item);
3038 hd_scan(hd_data);
3039 memcpy(hd_data->probe, probe_save, sizeof hd_data->probe);
3040 hd_data->flags.fast = fast_save;
3041 }
3042
3043 for(hd = hd_data->hd; hd; hd = hd->next) {
3044 if(!hd_report_this(hd_data, hd)) continue;
3045
3046 if(
3047 (
3048 item == hw_manual || hd_is_hw_class(hd, item)
3049 )
3050#ifndef LIBHD_TINY
3051/* with LIBHD_TINY hd->status is not maintained (cf. manual.c) */
3052 && (
3053 hd->status.available == status_yes ||
3054 hd->status.available == status_unknown ||
3055 item == hw_manual ||
3056 hd_data->flags.list_all
3057 )
3058#endif
3059 ) {
3060// if(hd->is.softraiddisk) continue; /* don't report them */
3061
3062 /* don't report old entries again */
3063 for(hd1 = hd_old; hd1; hd1 = hd1->next) {
3064 if(!cmp_hd(hd1, hd)) break;
3065 }
3066 if(!hd1) {
3067 hd1 = add_hd_entry2(&hd_list, new_mem(sizeof *hd_list));
3068 hd_copy(hd1, hd);
3069 }
3070 }
3071 }
3072
3073 if(item == hw_manual) {
3074 for(hd = hd_list; hd; hd = hd->next) {
3075 hd->status.available = hd->status.available_orig;
3076 }
3077 }
3078
3079 return hd_list;
3080}
3081
3082
3083hd_t *hd_list_with_status(hd_data_t *hd_data, hd_hw_item_t item, hd_status_t status)
3084{
3085 hd_t *hd, *hd1, *hd_list = NULL;
3086 unsigned char probe_save[sizeof hd_data->probe];
3087
3088#ifdef LIBHD_MEMCHECK
3089#ifndef __PPC__
3090 {
3091 if(libhd_log)
3092 fprintf(libhd_log, "; %s\t%p\t%p\t%u\n", __FUNCTION__, CALLED_FROM(hd_list_with_status, hd_data), hd_data, item);
3093 }
3094#endif
3095#endif
3096
3097 memcpy(probe_save, hd_data->probe, sizeof probe_save);
3098 hd_clear_probe_feature(hd_data, pr_all);
3099 hd_set_probe_feature(hd_data, pr_manual);
3100 hd_scan(hd_data);
3101 memcpy(hd_data->probe, probe_save, sizeof hd_data->probe);
3102
3103 for(hd = hd_data->hd; hd; hd = hd->next) {
3104 if(hd_is_hw_class(hd, item)) {
3105 if(
3106 (status.configured == 0 || status.configured == hd->status.configured) &&
3107 (status.available == 0 || status.available == hd->status.available) &&
3108 (status.needed == 0 || status.needed == hd->status.needed) &&
3109 (status.reconfig == 0 || status.reconfig == hd->status.reconfig)
3110 ) {
3111 hd1 = add_hd_entry2(&hd_list, new_mem(sizeof *hd_list));
3112 hd_copy(hd1, hd);
3113 }
3114 }
3115 }
3116
3117 return hd_list;
3118}
3119
3120
3121/* check if item is in items */
3122int has_item(hd_hw_item_t *items, hd_hw_item_t item)
3123{
3124 while(*items) if(*items++ == item) return 1;
3125
3126 return 0;
3127}
3128
3129
3130/* check if one of items is in hw_class */
3131int has_hw_class(hd_t *hd, hd_hw_item_t *items)
3132{
3133 while(*items) if(hd_is_hw_class(hd, *items++)) return 1;
3134
3135 return 0;
3136}
3137
3138
3139/*
3140 * items must be a 0 terminated list
3141 */
3142hd_t *hd_list2(hd_data_t *hd_data, hd_hw_item_t *items, int rescan)
3143{
3144 hd_t *hd, *hd1, *hd_list = NULL;
3145 unsigned char probe_save[sizeof hd_data->probe];
3146 unsigned fast_save;
3147 hd_hw_item_t *item_ptr;
3148 int is_manual;
3149
3150 if(!items) return NULL;
3151
3152 is_manual = has_item(items, hw_manual);
3153
3154 if(rescan) {
3155 memcpy(probe_save, hd_data->probe, sizeof probe_save);
3156 fast_save = hd_data->flags.fast;
3157 hd_clear_probe_feature(hd_data, pr_all);
3158#ifdef __powerpc__
3159 hd_set_probe_feature(hd_data, pr_sys);
3160 hd_scan(hd_data);
3161#endif
3162 for(item_ptr = items; *item_ptr; item_ptr++) {
3163 hd_set_probe_feature_hw(hd_data, *item_ptr);
3164 }
3165 hd_scan(hd_data);
3166 memcpy(hd_data->probe, probe_save, sizeof hd_data->probe);
3167 hd_data->flags.fast = fast_save;
3168 }
3169
3170 for(hd = hd_data->hd; hd; hd = hd->next) {
3171 if(!hd_report_this(hd_data, hd)) continue;
3172 if(
3173 (
3174 is_manual || has_hw_class(hd, items)
3175 )
3176#ifndef LIBHD_TINY
3177/* with LIBHD_TINY hd->status is not maintained (cf. manual.c) */
3178 && (
3179 hd->status.available == status_yes ||
3180 hd->status.available == status_unknown ||
3181 is_manual ||
3182 hd_data->flags.list_all
3183 )
3184#endif
3185 ) {
3186// if(hd->is.softraiddisk) continue; /* don't report them */
3187
3188 /* don't report old entries again */
3189 hd1 = add_hd_entry2(&hd_list, new_mem(sizeof *hd_list));
3190 hd_copy(hd1, hd);
3191 }
3192 }
3193
3194 if(is_manual) {
3195 for(hd = hd_list; hd; hd = hd->next) {
3196 hd->status.available = hd->status.available_orig;
3197 }
3198 }
3199
3200 return hd_list;
3201}
3202
3203
3204/*
3205 * items must be a 0 terminated list
3206 */
3207hd_t *hd_list_with_status2(hd_data_t *hd_data, hd_hw_item_t *items, hd_status_t status)
3208{
3209 hd_t *hd, *hd1, *hd_list = NULL;
3210 unsigned char probe_save[sizeof hd_data->probe];
3211
3212 if(!items) return NULL;
3213
3214 memcpy(probe_save, hd_data->probe, sizeof probe_save);
3215 hd_clear_probe_feature(hd_data, pr_all);
3216 hd_set_probe_feature(hd_data, pr_manual);
3217 hd_scan(hd_data);
3218 memcpy(hd_data->probe, probe_save, sizeof hd_data->probe);
3219
3220 for(hd = hd_data->hd; hd; hd = hd->next) {
3221 if(has_hw_class(hd, items)) {
3222 if(
3223 (status.configured == 0 || status.configured == hd->status.configured) &&
3224 (status.available == 0 || status.available == hd->status.available) &&
3225 (status.needed == 0 || status.needed == hd->status.needed) &&
3226 (status.reconfig == 0 || status.reconfig == hd->status.reconfig)
3227 ) {
3228 hd1 = add_hd_entry2(&hd_list, new_mem(sizeof *hd_list));
3229 hd_copy(hd1, hd);
3230 }
3231 }
3232 }
3233
3234 return hd_list;
3235}
3236
3237
3238hd_t *hd_base_class_list(hd_data_t *hd_data, unsigned base_class)
3239{
3240 hd_t *hd, *hd1, *hd_list = NULL;
3241// hd_t *bridge_hd;
3242
3243#ifdef LIBHD_MEMCHECK
3244 {
3245 if(libhd_log)
3246 fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_base_class_list, hd_data), hd_data);
3247 }
3248#endif
3249
3250 for(hd = hd_data->hd; hd; hd = hd->next) {
3251
3252#if 0
3253 /* ###### fix later: card bus magic */
3254 if((bridge_hd = hd_get_device_by_idx(hd_data, hd->attached_to))) {
3255 if(
3256 bridge_hd->base_class.id == bc_bridge &&
3257 bridge_hd->sub_class.id == sc_bridge_cardbus
3258 ) continue;
3259 }
3260#endif
3261
3262 /* add multimedia/sc_multi_video to display */
3263 if(
3264 hd->base_class.id == base_class ||
3265 (
3266 base_class == bc_display &&
3267 hd->base_class.id == bc_multimedia &&
3268 hd->sub_class.id == sc_multi_video
3269 )
3270 ) {
3271 hd1 = add_hd_entry2(&hd_list, new_mem(sizeof *hd_list));
3272 hd_copy(hd1, hd);
3273 }
3274 }
3275
3276 return hd_list;
3277}
3278
3279hd_t *hd_sub_class_list(hd_data_t *hd_data, unsigned base_class, unsigned sub_class)
3280{
3281 hd_t *hd, *hd1, *hd_list = NULL;
3282
3283#ifdef LIBHD_MEMCHECK
3284 {
3285 if(libhd_log)
3286 fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_sub_class_list, hd_data), hd_data);
3287 }
3288#endif
3289
3290 for(hd = hd_data->hd; hd; hd = hd->next) {
3291 if(hd->base_class.id == base_class && hd->sub_class.id == sub_class) {
3292 hd1 = add_hd_entry2(&hd_list, new_mem(sizeof *hd_list));
3293 hd_copy(hd1, hd);
3294 }
3295 }
3296
3297 return hd_list;
3298}
3299
3300hd_t *hd_bus_list(hd_data_t *hd_data, unsigned bus)
3301{
3302 hd_t *hd, *hd1, *hd_list = NULL;
3303
3304#ifdef LIBHD_MEMCHECK
3305 {
3306 if(libhd_log)
3307 fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_bus_list, hd_data), hd_data);
3308 }
3309#endif
3310
3311 for(hd = hd_data->hd; hd; hd = hd->next) {
3312 if(hd->bus.id == bus) {
3313 hd1 = add_hd_entry2(&hd_list, new_mem(sizeof *hd_list));
3314 hd_copy(hd1, hd);
3315 }
3316 }
3317
3318 return hd_list;
3319}
3320
3321/* Convert libhd bus IDs to hwcfg bus names */
3322const char* hd_busid_to_hwcfg(int busid)
3323{
3324 const char* const ids1[]={"none","isa","eisa","mc","pci","pcmcia","nubus","cardbus","other"};
3325 const char* const ids2[]={"ps2","serial","parallel","floppy","scsi","ide","usb","adb","raid","sbus","i2o","vio","ccw","iucv"};
3326 if(busid <9)
3327 return ids1[busid];
3328 else if(busid >=0x80 && busid <0x8e)
3329 return ids2[busid-0x80];
3330 else
3331 return 0;
3332}
3333
3334/*
3335 * Check if the execution of (*func)() takes longer than timeout seconds.
3336 * This is useful to work around long kernel-timeouts as in the floppy
3337 * detection and ps/2 mouse detection.
3338 */
3339int hd_timeout(void(*func)(void *), void *arg, int timeout)
3340{
3341 int child1, child2;
3342 int status = 0;
3343
3344 child1 = fork();
3345 if(child1 == -1) return -1;
3346
3347 if(child1) {
3348 if(waitpid(child1, &status, 0) == -1) return -1;
3349// fprintf(stderr, ">child1 status: 0x%x\n", status);
3350
3351 if(WIFEXITED(status)) {
3352 status = WEXITSTATUS(status);
3353// fprintf(stderr, ">normal child1 status: 0x%x\n", status);
3354 /* != 0 if we timed out */
3355 }
3356 else {
3357 status = 0;
3358 }
3359 }
3360 else {
3361 /* fork again */
3362
3363#ifdef LIBHD_MEMCHECK
3364 /* stop logging in child process */
3365 if(libhd_log) fclose(libhd_log);
3366 libhd_log = NULL;
3367#endif
3368
3369 child2 = fork();
3370 if(child2 == -1) return -1;
3371
3372 if(child2) {
3373// fprintf(stderr, ">signal\n");
3374 signal(SIGALRM, timeout_alarm_handler);
3375 alarm(timeout);
3376 if(waitpid(child2, &status, 0) == -1) return -1;
3377// fprintf(stderr, ">child2 status: 0x%x\n", status);
3378 _exit(0);
3379 }
3380 else {
3381 (*func)(arg);
3382 _exit(0);
3383 }
3384 }
3385
3386 return status ? 1 : 0;
3387}
3388
3389void timeout_alarm_handler(int signal)
3390{
3391 _exit(63);
3392}
3393
3394
3395/*
3396 * Return list of loaded modules. Converts '-' to '_'.
3397 */
3398str_list_t *read_kmods(hd_data_t *hd_data)
3399{
3400 str_list_t *sl, *sl0, *sl1 = NULL;
3401 char *s;
3402
3403 if(!hd_data->kmods || hd_data->flags.keep_kmods != 2) {
3404 hd_data->kmods = free_str_list(hd_data->kmods);
3405 if(!(sl0 = read_file(PROC_MODULES, 0, 0))) return NULL;
3406 hd_data->kmods = sl0;
3407 if(hd_data->flags.keep_kmods == 1) hd_data->flags.keep_kmods = 2;
3408 }
3409
3410 for(sl = hd_data->kmods; sl; sl = sl->next) {
3411 s = sl->str;
3412 add_str_list(&sl1, strsep(&s, " \t"));
3413 }
3414
3415 for(sl = sl1; sl; sl = sl->next) {
3416 for(s = sl->str; *s; s++) if(*s == '-') *s = '_';
3417 }
3418
3419 return sl1;
3420}
3421
3422
3423str_list_t *get_cmdline(hd_data_t *hd_data, char *key)
3424{
3425 str_list_t *sl0, *sl1, *cmd = NULL;
3426 char *s, *t, *t0;
3427 int i, l = strlen(key);
3428
3429 if(!hd_data->cmd_line) {
3430 sl0 = read_file(PROC_CMDLINE, 0, 1);
3431 sl1 = read_file(LIB_CMDLINE, 0, 1);
3432
3433 if(sl0) {
3434 i = strlen(sl0->str);
3435 if(i && sl0->str[i - 1] == '\n') sl0->str[i - 1] = 0;
3436 hd_data->cmd_line = new_str(sl0->str);
3437 if(hd_data->debug) {
3438 ADD2LOG("----- " PROC_CMDLINE " -----\n");
3439 ADD2LOG(" %s\n", sl0->str);
3440 ADD2LOG("----- " PROC_CMDLINE " end -----\n");
3441 }
3442 }
3443 if(sl1) {
3444 i = strlen(sl1->str);
3445 if(i && sl1->str[i - 1] == '\n') sl1->str[i - 1] = 0;
3446 str_printf(&hd_data->cmd_line, -1, " %s", sl1->str);
3447 if(hd_data->debug) {
3448 ADD2LOG("----- " LIB_CMDLINE " -----\n");
3449 ADD2LOG(" %s\n", sl1->str);
3450 ADD2LOG("----- " LIB_CMDLINE " end -----\n");
3451 }
3452 }
3453
3454 free_str_list(sl0);
3455 free_str_list(sl1);
3456 }
3457
3458 if(!hd_data->cmd_line) return NULL;
3459
3460 t = t0 = new_str(hd_data->cmd_line);
3461 while((s = strsep(&t, " "))) {
3462 if(!*s) continue;
3463 if(!strncmp(s, key, l) && s[l] == '=') {
3464 add_str_list(&cmd, s + l + 1);
3465 }
3466 }
3467
3468 free_mem(t0);
3469
3470 return cmd;
3471}
3472
3473
3474/*
3475 * Return field 'field' (starting with 0) from the 'SuSE='
3476 * kernel cmd line parameter.
3477 */
3478char *get_cmd_param(hd_data_t *hd_data, int field)
3479{
3480 char *s, *t;
3481 str_list_t *cmd;
3482
3483 if(!(cmd = get_cmdline(hd_data, "SuSE"))) return NULL;
3484
3485 s = cmd->str;
3486
3487 t = NULL;
3488
3489 if(s) {
3490 for(; field; field--) {
3491 if(!(s = strchr(s, ','))) break;
3492 s++;
3493 }
3494
3495 if(s && (t = strchr(s, ','))) *t = 0;
3496 }
3497
3498 t = new_str(s);
3499
3500 free_str_list(cmd);
3501
3502 return t;
3503}
3504
3505
3506unsigned get_disk_crc(unsigned char *data, unsigned len)
3507{
3508 unsigned i, crc;
3509
3510 crc = -1;
3511 for(i = 0; i < len; i++) {
3512 crc += data[i];
3513 crc *= 57;
3514 }
3515
3516 return crc;
3517}
3518
3519disk_t *add_disk_entry(disk_t **dl, disk_t *new_dl)
3520{
3521 while(*dl) dl = &(*dl)->next;
3522 return *dl = new_dl;
3523}
3524
3525disk_t *free_disk_list(disk_t *dl)
3526{
3527 disk_t *l;
3528
3529 for(; dl; dl = (l = dl)->next, free_mem(l));
3530
3531 return NULL;
3532}
3533
3534int dev_name_duplicate(disk_t *dl, char *dev_name)
3535{
3536 for(; dl; dl = dl->next) {
3537 if(!strcmp(dl->dev_name, dev_name)) return 1;
3538 }
3539
3540 return 0;
3541}
3542
3543unsigned hd_boot_disk(hd_data_t *hd_data, int *matches)
3544{
3545 hd_t *hd;
3546 unsigned crc, hd_idx = 0;
3547 char *s;
3548 int i, j;
3549 disk_t *dl, *dl0 = NULL, *dl1 = NULL;
3550
3551#ifdef LIBHD_MEMCHECK
3552 {
3553 if(libhd_log)
3554 fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_boot_disk, hd_data), hd_data);
3555 }
3556#endif
3557
3558 if(matches) *matches = 0;
3559
3560 if(!(s = get_cmd_param(hd_data, 2))) return 0;
3561
3562 i = strlen(s);
3563
3564 if(i >= 8) {
3565 crc = hex(s, 8);
3566 }
3567 else {
3568 free_mem(s);
3569 return 0;
3570 }
3571
3572 s = free_mem(s);
3573
3574 if((hd_data->debug & HD_DEB_BOOT)) {
3575 ADD2LOG(" boot dev crc 0x%x\n", crc);
3576 }
3577
3578 for(hd = hd_data->hd; hd; hd = hd->next) {
3579 if(
3580 hd->base_class.id == bc_storage_device &&
3581 hd->sub_class.id == sc_sdev_disk &&
3582 hd->block0
3583 ) {
3584 if(dev_name_duplicate(dl0, hd->unix_dev_name)) continue;
3585 dl = add_disk_entry(&dl0, new_mem(sizeof *dl0));
3586 dl->dev_name = hd->unix_dev_name;
3587 dl->hd_idx = hd->idx;
3588 dl->crc = get_disk_crc(dl->data = hd->block0, 512);
3589 }
3590 }
3591
3592 if(!dl0) return 0;
3593
3594 if((hd_data->debug & HD_DEB_BOOT)) {
3595 for(dl = dl0; dl; dl = dl->next) {
3596 ADD2LOG(" crc %s 0x%08x\n", dl->dev_name, dl->crc);
3597 }
3598 }
3599
3600 for(i = 0, dl = dl0; dl; dl = dl->next) {
3601 if(crc == dl->crc) {
3602 dl->crc_match = 1;
3603 dl1 = dl;
3604 if(!i++) hd_idx = dl->hd_idx;
3605 }
3606 }
3607
3608 if(i == 1 && dl1 && (hd_data->debug & HD_DEB_BOOT)) {
3609 ADD2LOG("----- MBR -----\n");
3610 for(j = 0; j < 512; j += 0x10) {
3611 ADD2LOG(" %03x ", j);
3612 hexdump(&hd_data->log, 1, 0x10, dl1->data + j);
3613 ADD2LOG("\n");
3614 }
3615 ADD2LOG("----- MBR end -----\n");
3616 }
3617
3618 free_disk_list(dl0);
3619
3620 if(matches) *matches = i;
3621
3622 hd_data->debug &= ~HD_DEB_BOOT;
3623
3624 return hd_idx;
3625}
3626
3627void update_irq_usage(hd_data_t *hd_data)
3628{
3629 hd_t *hd;
3630 misc_irq_t *mi;
3631 unsigned u, v;
3632 uint64_t irqs = 0;
3633 hd_res_t *res;
3634
3635 if(hd_data->misc) {
3636 mi = hd_data->misc->irq;
3637 for(u = 0; u < hd_data->misc->irq_len; u++) {
3638 v = mi[u].irq;
3639 irqs |= 1ull << v;
3640 }
3641 }
3642
3643 for(hd = hd_data->hd; hd; hd = hd->next) {
3644 for(res = hd->res; res; res = res->next) {
3645 if(res->any.type == res_irq) {
3646 irqs |= 1ull << res->irq.base;
3647 }
3648 }
3649 }
3650
3651 hd_data->used_irqs = irqs;
3652}
3653
3654int run_cmd(hd_data_t *hd_data, char *cmd)
3655{
3656 char *xcmd = NULL;
3657 str_list_t *sl, *sl0;
3658
3659 ADD2LOG("----- exec: \"%s\" -----\n", cmd);
3660
3661 if(*cmd == '/') {
3662 str_printf(&xcmd, 0, "|%s 2>&1", cmd);
3663 sl0 = read_file(xcmd, 0, 0);
3664 for(sl = sl0; sl; sl = sl->next) ADD2LOG(" %s", sl->str);
3665 sl0 = free_str_list(sl0);
3666 }
3667
3668 ADD2LOG("----- return code: ? -----\n");
3669
3670 free_mem(xcmd);
3671
3672 return 0;
3673}
3674
3675int probe_module(hd_data_t *hd_data, char *module)
3676{
3677 char *cmd = NULL;
3678 int i;
3679 struct stat sbuf;
3680
3681 if(hd_module_is_active(hd_data, module)) return 0;
3682
3683 if(stat(PROG_MODPROBE, &sbuf)) return 127;
3684
3685 str_printf(&cmd, 0, PROG_MODPROBE " %s", module);
3686
3687 i = run_cmd(hd_data, cmd);
3688
3689 free_mem(cmd);
3690
3691 return i;
3692}
3693
3694int load_module_with_params(hd_data_t *hd_data, char *module, char *params)
3695{
3696 char *cmd = NULL;
3697 int i;
3698 struct stat sbuf;
3699
3700 if(hd_module_is_active(hd_data, module)) return 0;
3701
3702 if(stat(PROG_MODPROBE, &sbuf)) return 127;
3703
3704 str_printf(&cmd, 0, PROG_MODPROBE " %s %s", module, params ? params : "");
3705
3706 i = run_cmd(hd_data, cmd);
3707
3708 free_mem(cmd);
3709
3710 return i;
3711}
3712
3713int load_module(hd_data_t *hd_data, char *module)
3714{
3715 return load_module_with_params(hd_data, module, NULL);
3716}
3717
3718int unload_module(hd_data_t *hd_data, char *module)
3719{
3720 char *cmd = NULL;
3721 int i;
3722
3723 if(!hd_module_is_active(hd_data, module)) return 0;
3724
3725 str_printf(&cmd, 0, PROG_RMMOD " %s", module);
3726
3727 i = run_cmd(hd_data, cmd);
3728
3729 free_mem(cmd);
3730
3731 return i;
3732}
3733
3734/*
3735 * Compare two hd entries and return 0 if they are identical.
3736 */
3737int cmp_hd(hd_t *hd1, hd_t *hd2)
3738{
3739 if(!hd1 || !hd2) return 1;
3740
3741 if(
3742 hd1->bus.id != hd2->bus.id ||
3743 hd1->slot != hd2->slot ||
3744 hd1->func != hd2->func ||
3745 hd1->base_class.id != hd2->base_class.id ||
3746 hd1->sub_class.id != hd2->sub_class.id ||
3747 hd1->prog_if.id != hd2->prog_if.id ||
3748 hd1->device.id != hd2->device.id ||
3749 hd1->vendor.id != hd2->vendor.id ||
3750 hd1->sub_vendor.id != hd2->sub_vendor.id ||
3751 hd1->revision.id != hd2->revision.id ||
3752 hd1->compat_device.id != hd2->compat_device.id ||
3753 hd1->compat_vendor.id != hd2->compat_vendor.id ||
3754
3755 hd1->module != hd2->module ||
3756 hd1->line != hd2->line
3757 ) {
3758 return 1;
3759 }
3760
3761 if(hd1->unix_dev_name || hd2->unix_dev_name) {
3762 if(hd1->unix_dev_name && hd2->unix_dev_name) {
3763 if(strcmp(hd1->unix_dev_name, hd2->unix_dev_name)) return 1;
3764 }
3765 else {
3766 return 1;
3767 }
3768 }
3769
3770 return 0;
3771}
3772
3773
3774void get_probe_env(hd_data_t *hd_data)
3775{
3776 char *s, *t, *env;
3777 str_list_t *cmd = NULL;
3778 int j, k;
3779 char buf[10];
3780
3781 env = getenv("hwprobe");
3782 if(!env) {
3783 cmd = get_cmdline(hd_data, "hwprobe");
3784 if(cmd) env = cmd->str;
3785 }
3786 s = env = new_str(env);
3787
3788 free_str_list(cmd);
3789
3790 if(!env) return;
3791
3792 hd_data->xtra_hd = free_str_list(hd_data->xtra_hd);
3793
3794 while((t = strsep(&s, ","))) {
3795 if(*t == '+') {
3796 k = 1; t++;
3797 }
3798 else if(*t == '-') {
3799 k = 0; t++;
3800 }
3801 else {
3802 k = 2;
3803// ADD2LOG("hwprobe: +/- missing before \"%s\"\n", t);
3804// return;
3805 }
3806
3807 if((j = hd_probe_feature_by_name(t))) {
3808 set_probe_feature(hd_data, j, k ? 1 : 0);
3809 }
3810 else if(sscanf(t, "%8[^:]:%8[^:]:%8[^:]", buf, buf, buf) == 3) {
3811 add_str_list(&hd_data->xtra_hd, t - (k == 2 ? 0 : 1));
3812 }
3813 else {
3814 if(*t) ADD2LOG("hwprobe: what is \"%s\"?\n", t);
3815 return;
3816 }
3817 }
3818
3819 free_mem(env);
3820}
3821
3822void hd_scan_xtra(hd_data_t *hd_data)
3823{
3824 str_list_t *sl;
3825 hd_t *hd, *hd_tmp;
3826 unsigned u0, u1, u2, tag;
3827 int i, err;
3828 char buf0[10], buf1[10], buf2[10], buf3[64], *s, k;
3829
3830 hd_data->module = mod_xtra;
3831
3832 remove_hd_entries(hd_data);
3833
3834 for(sl = hd_data->xtra_hd; sl; sl = sl->next) {
3835 s = sl->str;
3836 err = 0;
3837 switch(*s) {
3838 case '+': k = 1; s++; break;
3839 case '-': k = 0; s++; break;
3840 default: k = 2;
3841 }
3842 if(
3843 (i = sscanf(s, "%8[^:]:%8[^:]:%8[^:]:%60s", buf0, buf1, buf2, buf3)) >= 3
3844 ) {
3845 if(i < 4) *buf3 = 0;
3846
3847 u0 = strtoul(buf0, &s, 16);
3848 if(*s) err |= 1;
3849 if(strlen(buf1) == 3) {
3850 u1 = name2eisa_id(buf1);
3851 }
3852 else {
3853 tag = TAG_PCI;
3854 s = buf1;
3855 switch(*s) {
3856 case 'p': tag = TAG_PCI; s++; break;
3857 case 'r': tag = 0; s++; break;
3858 case 's': tag = TAG_SPECIAL; s++; break;
3859 case 'u': tag = TAG_USB; s++; break;
3860 case 'P': tag = TAG_PCMCIA; s++; break;
3861 }
3862 u1 = strtoul(s, &s, 16);
3863 if(*s) err |= 2;
3864 u1 = MAKE_ID(tag, u1);
3865 }
3866 u2 = strtoul(buf2, &s, 16);
3867 if(*s) err |= 4;
3868 u2 = MAKE_ID(ID_TAG(u1), ID_VALUE(u2));
3869 if((err & 1) && !strcmp(buf0, "*")) {
3870 u0 = -1;
3871 err &= ~1;
3872 }
3873 if((err & 2) && !strcmp(buf1, "*")) {
3874 u1 = 0;
3875 err &= ~2;
3876 }
3877 if((err & 4) && !strcmp(buf2, "*")) {
3878 u2 = 0;
3879 err &= ~4;
3880 }
3881 if(!err) {
3882 if(k) {
3883 if(k == 2) {
3884 /* insert at top */
3885 hd_tmp = hd_data->hd;
3886 hd_data->hd = NULL;
3887 hd = add_hd_entry(hd_data, __LINE__, 0);
3888 hd->next = hd_tmp;
3889 hd_tmp = NULL;
3890 }
3891 else {
3892 hd = add_hd_entry(hd_data, __LINE__, 0);
3893 }
3894 hd->base_class.id = u0 >> 8;
3895 hd->sub_class.id = u0 & 0xff;
3896 hd->vendor.id = u1;
3897 hd->device.id = u2;
3898 if(ID_TAG(hd->vendor.id) == TAG_PCI) hd->bus.id = bus_pci;
3899 if(ID_TAG(hd->vendor.id) == TAG_USB) hd->bus.id = bus_usb;
3900 if(ID_TAG(hd->vendor.id) == TAG_PCMCIA) {
3901 hd->bus.id = bus_pcmcia;
3902 hd->hotplug = hp_pcmcia;
3903 }
3904 if(*buf3) hd->unix_dev_name = new_str(buf3);
3905 hd->status.available = status_yes;
3906 hd->status.configured = status_new;
3907 hd->status.needed = status_no;
3908 }
3909 else {
3910 for(hd = hd_data->hd; hd; hd = hd->next) {
3911 if(
3912 (u0 == -1u || (
3913 hd->base_class.id == (u0 >> 8) &&
3914 hd->sub_class.id == (u0 & 0xff)
3915 )) &&
3916 (u1 == 0 || hd->vendor.id == u1) &&
3917 (u2 == 0 || hd->device.id == u2) &&
3918 (*buf3 == 0 || (
3919 hd->unix_dev_name &&
3920 !strcmp(hd->unix_dev_name, buf3)
3921 ))
3922 ) {
3923 hd->tag.remove = 1;
3924 }
3925 }
3926 remove_tagged_hd_entries(hd_data);
3927 }
3928 }
3929 }
3930 }
3931}
3932
3933unsigned has_something_attached(hd_data_t *hd_data, hd_t *hd)
3934{
3935 hd_t *hd1;
3936
3937 for(hd1 = hd_data->hd; hd1; hd1 = hd1->next) {
3938 if(hd1->attached_to == hd->idx) return hd1->idx;
3939 }
3940
3941 return 0;
3942}
3943
3944
3945/* ##### FIX: replace with a real crc later ##### */
3946void crc64(uint64_t *id, void *p, int len)
3947{
3948 unsigned char uc;
3949
3950 for(; len; len--, p++) {
3951 uc = *(unsigned char *) p;
3952 *id += uc + ((uc + 57) << 27);
3953 *id *= 73;
3954 *id *= 65521;
3955 }
3956}
3957
3958char *numid2str(uint64_t id, int len)
3959{
3960 static char buf[32];
3961
3962#ifdef NUMERIC_UNIQUE_ID
3963 /* numeric */
3964
3965 if(len < (sizeof id << 3)) id &= ~(-1LL << len);
3966 sprintf(buf, "%0*"PRIx64, len >> 2, id);
3967
3968#else
3969 /* base64 like */
3970
3971 int i;
3972 unsigned char u;
3973
3974 memset(buf, 0, sizeof buf);
3975 for(i = 0; len > 0 && i < (int) sizeof buf - 1; i++, len -= 6, id >>= 6) {
3976 u = id & 0x3f;
3977 if(u < 10) {
3978 u += '0'; /* 0..9 */
3979 }
3980 else if(u < 10 + 26) {
3981 u += 'A' - 10; /* A..Z */
3982 }
3983 else if(u < 10 + 26 + 26) {
3984 u += 'a' - 10 - 26; /* a..z */
3985 }
3986 else if(u == 63) {
3987 u = '+';
3988 }
3989 else {
3990 u = '_';
3991 }
3992 buf[i] = u;
3993 }
3994
3995#endif
3996
3997 return buf;
3998}
3999
4000/*
4001 * calculate unique ids
4002 */
4003#define INT_CRC(a, b) crc64(&a, &hd->b, sizeof hd->b);
4004#define STR_CRC(a, b) if(hd->b) crc64(&a, hd->b, strlen(hd->b) + 1);
4005
4006
4007// old method
4008void hd_add_old_id(hd_t *hd)
4009{
4010 uint64_t id0 = 0, id1 = 0;
4011
4012 if(hd->unique_id) return;
4013
4014 INT_CRC(id0, bus.id);
4015 INT_CRC(id0, slot);
4016 INT_CRC(id0, func);
4017 INT_CRC(id0, base_class.id);
4018 INT_CRC(id0, sub_class.id);
4019 INT_CRC(id0, prog_if.id);
4020 STR_CRC(id0, unix_dev_name);
4021 STR_CRC(id0, rom_id);
4022
4023 INT_CRC(id1, base_class.id);
4024 INT_CRC(id1, sub_class.id);
4025 INT_CRC(id1, prog_if.id);
4026 INT_CRC(id1, device.id);
4027 INT_CRC(id1, vendor.id);
4028 INT_CRC(id1, sub_device.id);
4029 INT_CRC(id1, sub_vendor.id);
4030 INT_CRC(id1, revision.id);
4031 INT_CRC(id1, compat_device.id);
4032 INT_CRC(id1, compat_vendor.id);
4033 STR_CRC(id1, device.name);
4034 STR_CRC(id1, vendor.name);
4035 STR_CRC(id1, sub_device.name);
4036 STR_CRC(id1, sub_vendor.name);
4037 STR_CRC(id1, revision.name);
4038 STR_CRC(id1, serial);
4039
4040 id0 += (id0 >> 32);
4041 str_printf(&hd->unique_id, 0, "%s", numid2str(id0, 24));
4042 str_printf(&hd->unique_id, -1, ".%s", numid2str(id1, 64));
4043}
4044
4045void hd_add_id(hd_data_t *hd_data, hd_t *hd)
4046{
4047 uint64_t id0 = 0, id1 = 0;
4048
4049 if(hd->unique_id) return;
4050
4051 hd_add_old_id(hd);
4052 hd->old_unique_id = hd->unique_id;
4053 hd->unique_id = NULL;
4054
4055 INT_CRC(id1, base_class.id);
4056 INT_CRC(id1, sub_class.id);
4057 INT_CRC(id1, prog_if.id);
4058 INT_CRC(id1, device.id);
4059 INT_CRC(id1, vendor.id);
4060 INT_CRC(id1, sub_device.id);
4061 INT_CRC(id1, sub_vendor.id);
4062 INT_CRC(id1, revision.id);
4063 if(
4064 hd->detail &&
4065 hd->detail->type == hd_detail_ccw &&
4066 hd->detail->ccw.data
4067 ) INT_CRC(id1, detail->ccw.data->cu_model);
4068 INT_CRC(id1, compat_device.id);
4069 INT_CRC(id1, compat_vendor.id);
4070 // make sure we get the same id even if, say, the pci name list changes
4071 if(!hd->device.id) STR_CRC(id1, device.name);
4072 if(!hd->vendor.id) STR_CRC(id1, vendor.name);
4073 if(!hd->sub_device.name) STR_CRC(id1, sub_device.name);
4074 if(!hd->sub_vendor.name) STR_CRC(id1, sub_vendor.name);
4075 if(!hd->revision.name) STR_CRC(id1, revision.name);
4076 STR_CRC(id1, serial);
4077
4078 hd->unique_id1 = new_str(numid2str(id1, 64));
4079
4080 INT_CRC(id0, bus.id);
4081
4082 if(
4083 (hd->bus.id == bus_usb ||
4084 hd->bus.id == bus_ccw) &&
4085 hd->sysfs_bus_id
4086 ) {
4087 STR_CRC(id0, sysfs_bus_id);
4088 }
4089 else if(
4090 hd->bus.id != bus_usb &&
4091 hd->bus.id != bus_pci &&
4092 hd->sysfs_id
4093 ) {
4094 STR_CRC(id0, sysfs_id);
4095 }
4096 else if(hd->unix_dev_name) {
4097 STR_CRC(id0, unix_dev_name);
4098 }
4099 else {
4100 INT_CRC(id0, slot);
4101 INT_CRC(id0, func);
4102 }
4103
4104 STR_CRC(id0, rom_id);
4105
4106 id0 += (id0 >> 32);
4107
4108 str_printf(&hd->unique_id, 0, "%s.%s", numid2str(id0, 24), hd->unique_id1);
4109}
4110#undef INT_CRC
4111#undef STR_CRC
4112
4113
4114devtree_t *free_devtree(hd_data_t *hd_data)
4115{
4116 hd_t *hd;
4117 devtree_t *dt, *next;
4118
4119 /*
4120 * first, remove all references in the current device tree
4121 * (refs in hd_old can remain)
4122 */
4123 for(hd = hd_data->hd; hd; hd = hd->next) {
4124 if(hd->detail && hd->detail->type == hd_detail_devtree) {
4125 hd->detail = free_mem(hd->detail);
4126 }
4127 }
4128
4129 for(dt = hd_data->devtree; dt; dt = next) {
4130 next = dt->next;
4131
4132 free_mem(dt->path);
4133 free_mem(dt->filename);
4134 free_mem(dt->name);
4135 free_mem(dt->model);
4136 free_mem(dt->device_type);
4137 free_mem(dt->compatible);
4138 free_mem(dt->edid);
4139
4140 free_mem(dt);
4141 }
4142
4143 return hd_data->devtree = NULL;
4144}
4145
4146
4147void test_read_block0_open(void *arg)
4148{
4149 open((char *) arg, O_RDONLY);
4150}
4151
4152unsigned char *read_block0(hd_data_t *hd_data, char *dev, int *timeout)
4153{
4154 int fd, len, buf_size = 512, k, sel;
4155 unsigned char *buf = NULL;
4156 struct timeval to;
4157 fd_set set, set0;
4158
4159 if(hd_timeout(test_read_block0_open, dev, *timeout) > 0) {
4160 ADD2LOG(" read_block0: open(%s) timed out\n", dev);
4161 *timeout = -1;
4162 fd = -2;
4163 }
4164 else {
4165 fd = open(dev, O_RDONLY);
4166 if(fd < 0) ADD2LOG(" read_block0: open(%s) failed\n", dev);
4167 }
4168 if(fd >= 0) {
4169 buf = new_mem(buf_size);
4170 len = k = 0;
4171
4172 FD_ZERO(&set0);
4173 FD_SET(fd, &set0);
4174
4175 to.tv_sec = *timeout; to.tv_usec = 0;
4176 for(;;) {
4177 set = set0;
4178 if((sel = select(fd + 1, &set, NULL, NULL, &to)) > 0) {
4179 if((k = read(fd, buf + len, buf_size - len)) > 0) len += k;
4180 ADD2LOG(" read_block0: %d bytes (%ds, %dus)\n", k, (int) to.tv_sec, (int) to.tv_usec);
4181 if(k <= 0 || buf_size == len) break;
4182 }
4183 if(sel == 0) {
4184 *timeout = -2; break;
4185 }
4186 }
4187
4188 if(k < 0) {
4189 ADD2LOG(" read_block0: read error(%s, %d, %d): errno %d\n", dev, len, buf_size - len, errno);
4190 buf = free_mem(buf);
4191 }
4192 close(fd);
4193 }
4194
4195 return buf;
4196}
4197
4198
4199void get_kernel_version(hd_data_t *hd_data)
4200{
4201 unsigned u1, u2;
4202 str_list_t *sl;
4203
4204 if(hd_data->kernel_version) return;
4205
4206 hd_data->kernel_version = KERNEL_24;
4207
4208 sl = read_file(PROC_VERSION, 0, 1);
4209
4210 if(!sl || !sl->str) return;
4211
4212 if(sscanf(sl->str, "Linux version %u.%u.", &u1, &u2) == 2) {
4213 if(hd_data->debug) {
4214 ADD2LOG("kernel version is %u.%u\n", u1, u2);
4215 }
4216 u1 = (u1 << 16) + (u2 << 8);
4217
4218 if(u1 <= KERNEL_22) {
4219 hd_data->kernel_version = KERNEL_22;
4220 }
4221 else if(u1 <= KERNEL_24) {
4222 hd_data->kernel_version = KERNEL_24;
4223 }
4224 else if(u1 <= KERNEL_26) {
4225 hd_data->kernel_version = KERNEL_26;
4226 }
4227 }
4228
4229 free_str_list(sl);
4230}
4231
4232
4233char *vend_id2str(unsigned vend)
4234{
4235 static char buf[32];
4236 char *s;
4237
4238 *(s = buf) = 0;
4239
4240 if(ID_TAG(vend) == TAG_EISA) {
4241 strcpy(s, eisa_vendor_str(vend));
4242 }
4243 else {
4244 if(ID_TAG(vend) == TAG_USB) *s++ = 'u', *s = 0;
4245 if(ID_TAG(vend) == TAG_SPECIAL) *s++ = 's', *s = 0;
4246 if(ID_TAG(vend) == TAG_PCMCIA) *s++ = 'P', *s = 0;
4247 sprintf(s, "%04x", ID_VALUE(vend));
4248 }
4249
4250 return buf;
4251}
4252
4253
4254int is_modem(hd_data_t *hd_data, hd_t *hd)
4255{
4256 if(
4257 hd->base_class.id == bc_modem ||
4258 (
4259 hd->base_class.id == bc_comm &&
4260 hd->sub_class.id == sc_com_modem
4261 )
4262 ) return 1;
4263
4264 return 0;
4265}
4266
4267
4268int is_audio(hd_data_t *hd_data, hd_t *hd)
4269{
4270 /* ISA-PnP sound cards: just one entry per card */
4271 if(
4272 hd->bus.id == bus_isa &&
4273 hd->is.isapnp &&
4274 hd->func
4275 ) return 0;
4276
4277 if(
4278 hd->base_class.id == bc_multimedia &&
4279 (
4280 hd->sub_class.id == sc_multi_audio ||
4281 hd->sub_class.id == 3
4282 )
4283 ) return 1;
4284
4285 return 0;
4286}
4287
4288
4289void assign_hw_class(hd_data_t *hd_data, hd_t *hd)
4290{
4291 int sc; /* compare sub_class too */
4292 unsigned base_class, sub_class;
4293 hd_hw_item_t item;
4294 int (*test_func)(hd_data_t *, hd_t *);
4295
4296 if(!hd) return;
4297
4298 // ###### FIXME: maybe just return here?
4299 if(!hd->hw_class) { /* skip if we've already done it */
4300 for(item = 1; item < hw_all; item++) {
4301
4302 test_func = NULL;
4303
4304 sc = 0;
4305 sub_class = 0;
4306
4307 base_class = -1;
4308 switch(item) {
4309 case hw_cdrom:
4310 base_class = bc_storage_device;
4311 sub_class = sc_sdev_cdrom;
4312 sc = 1;
4313 break;
4314
4315 case hw_floppy:
4316 base_class = bc_storage_device;
4317 sub_class = sc_sdev_floppy;
4318 sc = 1;
4319 break;
4320
4321 case hw_disk:
4322 base_class = bc_storage_device;
4323 sub_class = sc_sdev_disk;
4324 sc = 1;
4325 break;
4326
4327 case hw_network:
4328 base_class = bc_network_interface;
4329 break;
4330
4331 case hw_display:
4332 base_class = bc_display;
4333 break;
4334
4335 case hw_monitor:
4336 base_class = bc_monitor;
4337 break;
4338
4339 case hw_mouse:
4340 base_class = bc_mouse;
4341 break;
4342
4343 case hw_joystick:
4344 base_class = bc_joystick;
4345 break;
4346
4347 case hw_keyboard:
4348 base_class = bc_keyboard;
4349 break;
4350
4351 case hw_camera:
4352 base_class = bc_camera;
4353 break;
4354
4355 case hw_framebuffer:
4356 base_class = bc_framebuffer;
4357 break;
4358
4359 case hw_chipcard:
4360 base_class = bc_chipcard;
4361 break;
4362
4363 case hw_sound:
4364 test_func = is_audio;
4365 break;
4366
4367 case hw_isdn:
4368 base_class = bc_isdn;
4369 break;
4370
4371 case hw_dsl:
4372 base_class = bc_dsl;
4373 break;
4374
4375 case hw_modem:
4376 test_func = is_modem;
4377 break;
4378
4379 case hw_storage_ctrl:
4380 base_class = bc_storage;
4381 break;
4382
4383 case hw_network_ctrl:
4384 base_class = bc_network;
4385 break;
4386
4387 case hw_printer:
4388 base_class = bc_printer;
4389 break;
4390
4391 case hw_tv:
4392 base_class = bc_tv;
4393 break;
4394
4395 case hw_dvb:
4396 base_class = bc_dvb;
4397 break;
4398
4399 case hw_scanner:
4400 base_class = bc_scanner;
4401 break;
4402
4403 case hw_braille:
4404 base_class = bc_braille;
4405 break;
4406
4407 case hw_sys:
4408 base_class = bc_internal;
4409 sub_class = sc_int_sys;
4410 sc = 1;
4411 break;
4412
4413 case hw_cpu:
4414 base_class = bc_internal;
4415 sub_class = sc_int_cpu;
4416 sc = 1;
4417 break;
4418
4419 case hw_bios:
4420 base_class = bc_internal;
4421 sub_class = sc_int_bios;
4422 sc = 1;
4423 break;
4424
4425 case hw_usb_ctrl:
4426 base_class = bc_serial;
4427 sub_class = sc_ser_usb;
4428 sc = 1;
4429 break;
4430
4431 case hw_bridge:
4432 base_class = bc_bridge;
4433 break;
4434
4435 case hw_hub:
4436 base_class = bc_hub;
4437 break;
4438
4439 case hw_memory:
4440 base_class = bc_internal;
4441 sub_class = sc_int_main_mem;
4442 sc = 1;
4443 break;
4444
4445 case hw_ieee1394_ctrl:
4446 base_class = bc_serial;
4447 sub_class = sc_ser_fire;
4448 sc = 1;
4449 break;
4450
4451 case hw_pcmcia_ctrl:
4452 test_func = is_pcmcia_ctrl;
4453 break;
4454
4455 case hw_pppoe:
4456 base_class = bc_network_interface;
4457 break;
4458
4459 case hw_partition:
4460 base_class = bc_partition;
4461 break;
4462
4463 case hw_bluetooth:
4464 base_class = bc_bluetooth;
4465 break;
4466
4467 case hw_wlan:
4468 case hw_block:
4469 case hw_tape:
4470 case hw_vbe:
4471 break;
4472
4473 case hw_unknown:
4474 case hw_all:
4475 case hw_manual: /* special */
4476
4477 /* bus types */
4478 case hw_usb:
4479 case hw_pci:
4480 case hw_isapnp:
4481 case hw_scsi:
4482 case hw_ide:
4483
4484 case hw_pcmcia: /* special */
4485
4486 case hw_ieee1394: /* not handled */
4487 case hw_hotplug: /* not handled */
4488 case hw_hotplug_ctrl: /* not handled */
4489 case hw_zip: /* not handled */
4490 case hw_redasd:
4491 break;
4492 }
4493
4494 if(test_func) {
4495 if(test_func(hd_data, hd)) {
4496 hd->hw_class = item;
4497 break;
4498 }
4499 }
4500 else if(
4501 (
4502 hd->base_class.id == base_class &&
4503 (sc == 0 || hd->sub_class.id == sub_class)
4504 )
4505 ||
4506 ( /* list other display adapters, too */
4507 base_class == bc_display &&
4508 hd->base_class.id == bc_multimedia &&
4509 hd->sub_class.id == sc_multi_video
4510 )
4511 ||
4512 ( /* make i2o storage controllers */
4513 item == hw_storage_ctrl &&
4514 hd->base_class.id == bc_i2o
4515 )
4516 ||
4517 ( /* add fibre channel to storage ctrl list */
4518 item == hw_storage_ctrl &&
4519 hd->base_class.id == bc_serial &&
4520 hd->sub_class.id == sc_ser_fiber
4521 )
4522 ) {
4523 hd->hw_class = item;
4524 break;
4525 }
4526 }
4527
4528 if(!hd->hw_class) hd->hw_class = hw_unknown;
4529 }
4530
4531 hd_set_hw_class(hd, hd->hw_class);
4532
4533 if(hd->bus.id == bus_usb) {
4534 hd_set_hw_class(hd, hw_usb);
4535 }
4536 else if(hd->bus.id == bus_pci) {
4537 hd_set_hw_class(hd, hw_pci);
4538 }
4539 else if(hd->bus.id == bus_scsi) {
4540 hd_set_hw_class(hd, hw_scsi);
4541 }
4542 else if(hd->bus.id == bus_ide) {
4543 hd_set_hw_class(hd, hw_ide);
4544 }
4545 else if(hd->bus.id == bus_isa && hd->is.isapnp) {
4546 hd_set_hw_class(hd, hw_isapnp);
4547 }
4548
4549 if(hd->hw_class == hw_network && hd->is.pppoe) {
4550 hd_set_hw_class(hd, hw_pppoe);
4551 }
4552
4553 if(hd->usb_guid) {
4554 hd_set_hw_class(hd, hw_usb); // ###### maybe only if(hd->bus.id == bus_scsi)?
4555 }
4556
4557 if(hd->hotplug == hp_pcmcia || hd->hotplug == hp_cardbus) {
4558 hd_set_hw_class(hd, hw_pcmcia);
4559 }
4560
4561 if(hd->is.wlan) {
4562 hd_set_hw_class(hd, hw_wlan);
4563 }
4564
4565 if(hd_is_hw_class(hd, hw_bios)) {
4566 hd_set_hw_class(hd, hw_vbe);
4567 }
4568
4569 if(
4570 hd->base_class.id == bc_storage_device ||
4571 hd->base_class.id == bc_partition
4572 ) {
4573 hd_set_hw_class(hd, hw_block);
4574 }
4575
4576 if(
4577 hd->base_class.id == bc_storage_device &&
4578 hd->sub_class.id == sc_sdev_tape
4579 ) {
4580 hd_set_hw_class(hd, hw_tape);
4581 }
4582
4583 if(
4584 hd->base_class.id == bc_storage_device &&
4585 hd->sub_class.id == sc_sdev_disk
4586 ) {
4587 hd_set_hw_class(hd, hw_redasd);
4588 }
4589}
4590
4591
4592void short_vendor(char *vendor)
4593{
4594 static char *remove[] = {
4595 ".", ",", "-", "&", " inc", "corporation", " corp", " system",
4596 " systems", "technology", "technologies", "multimedia", "communications",
4597 "computer", " ltd", "(formerly ncr)", " group", " labs", "research",
4598 "equipment", " ag", "personal", " canada", "data", "products",
4599 " america", " co", " of", "solutions", " as", "publishing", "(old)",
4600 " usa", " gmbh", "electronic", "components", "(matsushita)", " ab",
4601 " pte", " north", " japan", "limited", "microcomputer", " kg",
4602 "incorporated", "semiconductor", "sem", "graphics"
4603 };
4604 int i, j;
4605 int len, len1, len2;
4606
4607 if(!vendor) return;
4608
4609 len2 = strlen(vendor);
4610
4611 if(!len2) return;
4612
4613 do {
4614 len = len2;
4615 for(i = 0; (unsigned) i < sizeof remove / sizeof *remove; i++) {
4616 len1 = strlen(remove[i]);
4617 if(len > len1 && !strcasecmp(vendor + len - len1, remove[i])) {
4618 vendor[j = len - len1] = 0;
4619 for(j--; j >= 0; vendor[j--] = 0) {
4620 if(!isspace(vendor[j])) break;
4621 }
4622 }
4623 }
4624 len2 = strlen(vendor);
4625 } while(len2 != len);
4626
4627}
4628
4629
4630void create_model_name(hd_data_t *hd_data, hd_t *hd)
4631{
4632 char *vend, *dev;
4633 char *compat, *dev_class, *hw_class;
4634 char *part1, *part2;
4635 cpu_info_t *ct;
4636
4637 /* early out */
4638 if(!hd || hd->model) return;
4639
4640 part1 = part2 = NULL;
4641
4642 vend = dev = compat = dev_class = hw_class = NULL;
4643
4644 if(
4645 hd->hw_class == hw_cpu &&
4646 hd->detail &&
4647 hd->detail->type == hd_detail_cpu &&
4648 (ct = hd->detail->cpu.data) &&
4649 ct->model_name
4650 ) {
4651 /* cpu entry */
4652
4653 part1 = new_str(ct->model_name);
4654 if(ct->clock) str_printf(&part1, -1, ", %u MHz", ct->clock);
4655 }
4656 else {
4657 /* normal entry */
4658
4659 vend = new_str(hd->sub_vendor.name);
4660
4661 dev = new_str(hd->sub_device.name);
4662
4663 if(!vend) vend = new_str(hd->vendor.name);
4664
4665 if(!dev) dev = new_str(hd->device.name);
4666
4667 if(dev) {
4668 if(vend) {
4669 part1 = vend; part2 = dev;
4670 }
4671 else {
4672 part1 = dev;
4673 }
4674 }
4675
4676 if(!part1 && !part2) {
4677 compat = new_str(hd->compat_device.name);
4678
4679 dev_class = new_str(hd->sub_class.name ?: hd->base_class.name);
4680
4681 hw_class = new_str(hd_hw_item_name(hd->hw_class));
4682
4683 if(vend) {
4684 if(compat) {
4685 part1 = vend; part2 = compat;
4686 }
4687 else if(dev_class) {
4688 part1 = vend; part2 = dev_class;
4689 }
4690 }
4691 else {
4692 if(
4693 compat &&
4694 dev_class &&
4695 hd->base_class.id != bc_internal /* avoid things like 'Notebook *System*' */
4696 ) {
4697 part1 = compat; part2 = dev_class;
4698 }
4699 else if(compat) {
4700 part1 = compat;
4701 }
4702 else if(dev_class) {
4703 part1 = dev_class;
4704 if(hw_class && !strchr(part1, ' ') && strchr(hw_class, ' ')) {
4705 part2 = hw_class;
4706 }
4707 }
4708 }
4709 }
4710 }
4711
4712 if(part1 && part2) {
4713 short_vendor(part1);
4714 }
4715
4716 if(part1 && !strcasecmp(part1, "unknown")) {
4717 part1 = part2;
4718 part2 = NULL;
4719 }
4720
4721 if(part1 && part2) {
4722 /* maybe the vendor name is already part of the device name... */
4723 if(strstr(part2, part1) || !strcasecmp(part1, part2)) {
4724 part1 = part2;
4725 part2 = NULL;
4726 }
4727 }
4728
4729 if(!part1 && !part2 && hw_class) {
4730 str_printf(&part1, 0, "unknown %s", hw_class);
4731 if(strchr(hw_class, ' ')) {
4732 str_printf(&part1, -1, " hardware");
4733 }
4734 }
4735
4736 str_printf(&hd->model, 0, "%s%s%s", part1, part2 ? " " : "", part2 ? part2 : "");
4737
4738 free_mem(vend);
4739 free_mem(dev);
4740 free_mem(compat);
4741 free_mem(dev_class);
4742 free_mem(hw_class);
4743}
4744
4745
4746#ifndef LIBHD_TINY
4747int hd_change_status(const char *id, hd_status_t status, const char *config_string)
4748{
4749 hd_data_t *hd_data;
4750 hd_manual_t *entry;
4751 int i;
4752
4753 hd_data = new_mem(sizeof *hd_data);
4754
4755 entry = hd_manual_read_entry(hd_data, (char *) id);
4756
4757 if(!entry || status.invalid) return 1;
4758
4759 if(status.configured) entry->status.configured = status.configured;
4760 if(status.available) entry->status.available = status.available;
4761 if(status.needed) entry->status.needed = status.needed;
4762 entry->status.invalid = status.invalid;
4763
4764 if(config_string) {
4765 free_mem(entry->config_string);
4766 entry->config_string = new_str(config_string);
4767 }
4768
4769 i = hd_manual_write_entry(hd_data, entry);
4770
4771 hd_free_manual(entry);
4772
4773 hd_free_hd_data(hd_data);
4774
4775 free_mem(hd_data);
4776
4777 return i;
4778}
4779
4780#endif /* !defined(LIBHD_TINY) */
4781
4782
4783int hd_getdisksize(hd_data_t *hd_data, char *dev, int fd, hd_res_t **geo, hd_res_t **size)
4784{
4785 int status=0;
4786 hd_res_t *res;
4787 struct hd_geometry geo_s;
4788#ifdef HDIO_GETGEO_BIG
4789 struct hd_big_geometry big_geo_s;
4790#endif
4791 unsigned long secs32;
4792 uint64_t secs, secs0;
4793 unsigned sec_size;
4794 int close_fd = 0;
4795 int got_big = 0;
4796
4797 *geo = *size = NULL;
4798
4799 ADD2LOG(" dev = %s, fd = %d\n", dev, fd);
4800
4801 if(fd < 0) {
4802 if(!dev) return 0;
4803 fd = open(dev, O_RDONLY | O_NONBLOCK);
4804 close_fd = 1;
4805 if(fd < 0) return 0;
4806 }
4807
4808 ADD2LOG(" open ok, fd = %d\n", fd);
4809
4810 secs0 = 0;
4811 res = NULL;
4812
4813#ifdef HDIO_GETGEO_BIG
4814 if(!ioctl(fd, HDIO_GETGEO_BIG, &big_geo_s)) {
4815 if(dev) ADD2LOG("%s: ioctl(big geo) ok\n", dev);
4816 res = add_res_entry(geo, new_mem(sizeof *res));
4817 res->disk_geo.type = res_disk_geo;
4818 res->disk_geo.cyls = big_geo_s.cylinders;
4819 res->disk_geo.heads = big_geo_s.heads;
4820 res->disk_geo.sectors = big_geo_s.sectors;
4821 res->disk_geo.geotype = geo_logical;
4822 secs0 = (uint64_t) res->disk_geo.cyls * res->disk_geo.heads * res->disk_geo.sectors;
4823 got_big = 1;
4824 }
4825 else {
4826 ADD2LOG(" big geo failed: %s\n", strerror(errno));
4827#else
4828 {
4829#endif
4830 if(!ioctl(fd, HDIO_GETGEO, &geo_s)) {
4831 if(dev) ADD2LOG("%s: ioctl(geo) ok\n", dev);
4832 res = add_res_entry(geo, new_mem(sizeof *res));
4833 res->disk_geo.type = res_disk_geo;
4834 res->disk_geo.cyls = geo_s.cylinders;
4835 res->disk_geo.heads = geo_s.heads;
4836 res->disk_geo.sectors = geo_s.sectors;
4837 res->disk_geo.geotype = geo_logical;
4838 secs0 = (uint64_t) res->disk_geo.cyls * res->disk_geo.heads * res->disk_geo.sectors;
4839 }
4840 else {
4841 ADD2LOG(" geo failed: %s\n", strerror(errno));
4842 }
4843 }
4844
4845 /* ##### maybe always BLKSZGET or always 0x200? */
4846 if(!ioctl(fd, BLKSSZGET, &sec_size)) {
4847 if(dev) ADD2LOG("%s: ioctl(block size) ok\n", dev);
4848 if(!sec_size) sec_size = 0x200;
4849 }
4850 else {
4851 sec_size = 0x200;
4852 }
4853
4854 secs = 0;
4855
4856#if defined(__s390__) || defined(__s390x__)
4857 if(res && res->disk_geo.sectors == 0)
4858 { /* This seems to be an unformatted DASD -> fake the formatted geometry */
4859 res->disk_geo.sectors=12;
4860 sec_size=4096;
4861 secs = (uint64_t) res->disk_geo.cyls * res->disk_geo.heads * res->disk_geo.sectors;
4862 status=1;
4863 }
4864 else
4865 {
4866#endif
4867 if(!ioctl(fd, BLKGETSIZE64, &secs)) {
4868 if(dev) ADD2LOG("%s: ioctl(disk size) ok\n", dev);
4869 secs /= sec_size;
4870 }
4871 else if(!ioctl(fd, BLKGETSIZE, &secs32)) {
4872 if(dev) ADD2LOG("%s: ioctl(disk size32) ok\n", dev);
4873 secs = secs32;
4874 }
4875 else {
4876 secs = secs0;
4877 }
4878#if defined(__s390__) || defined(__s390x__)
4879 }
4880#endif
4881
4882 if(!got_big && secs0 && res) {
4883 /* fix cylinder value */
4884 res->disk_geo.cyls = secs / (res->disk_geo.heads * res->disk_geo.sectors);
4885 }
4886
4887 if(secs) {
4888 res = add_res_entry(size, new_mem(sizeof *res));
4889 res->size.type = res_size;
4890 res->size.unit = size_unit_sectors;
4891 res->size.val1 = secs;
4892 res->size.val2 = sec_size;
4893 }
4894
4895 // ADD2LOG(" geo = %p, size = %p\n", *geo, *size);
4896
4897 if(close_fd) close(fd);
4898
4899 return status;
4900}
4901
4902
4903str_list_t *hd_split(char del, char *str)
4904{
4905 char *t, *s;
4906 str_list_t *sl = NULL;
4907
4908 if(!str) return NULL;
4909
4910 for(s = str = new_str(str); (t = strchr(s, del)); s = t + 1) {
4911 *t = 0;
4912 add_str_list(&sl, s);
4913 }
4914 add_str_list(&sl, s);
4915
4916 free_mem(str);
4917
4918 return sl;
4919}
4920
4921
4922char *hd_join(char *del, str_list_t *str)
4923{
4924 char *s;
4925 str_list_t *str0;
4926 int len = 0, del_len = 0;
4927
4928 if(del) del_len = strlen(del);
4929
4930 for(str0 = str; str0; str0 = str0->next) {
4931 if(str0->str) len += strlen(str0->str);
4932 if(str0->next) len += del_len;
4933 }
4934
4935 if(!len) return NULL;
4936
4937 len++;
4938
4939 s = new_mem(len);
4940
4941 for(; str; str = str->next) {
4942 if(str->str) strcat(s, str->str);
4943 if(str->next && del) strcat(s, del);
4944 }
4945
4946 return s;
4947}
4948
4949
4950/*
4951 * cf. pcmcia-cs-*:cardmgr/pcic_probe.c
4952 */
4953int is_pcmcia_ctrl(hd_data_t *hd_data, hd_t *hd)
4954{
4955 int i;
4956 static unsigned ids[][2] = {
4957 { 0x1013, 0x1100 },
4958 { 0x1013, 0x1110 },
4959 { 0x10b3, 0xb106 },
4960 { 0x1180, 0x0465 },
4961 { 0x1180, 0x0466 },
4962 { 0x1180, 0x0475 },
4963 { 0x1180, 0x0476 },
4964 { 0x1180, 0x0478 },
4965 { 0x104c, 0xac12 },
4966 { 0x104c, 0xac13 },
4967 { 0x104c, 0xac15 },
4968 { 0x104c, 0xac1a },
4969 { 0x104c, 0xac1e },
4970 { 0x104c, 0xac17 },
4971 { 0x104c, 0xac19 },
4972 { 0x104c, 0xac1c },
4973 { 0x104c, 0xac16 },
4974 { 0x104c, 0xac1d },
4975 { 0x104c, 0xac1f },
4976 { 0x104c, 0xac50 },
4977 { 0x104c, 0xac51 },
4978 { 0x104c, 0xac1b },
4979 { 0x104c, 0xac52 },
4980 { 0x104c, 0xac41 },
4981 { 0x104c, 0xac40 },
4982 { 0x104c, 0xac42 },
4983 { 0x1217, 0x6729 },
4984 { 0x1217, 0x673a },
4985 { 0x1217, 0x6832 },
4986 { 0x1217, 0x6836 },
4987 { 0x1217, 0x6872 },
4988 { 0x1217, 0x6925 },
4989 { 0x1217, 0x6933 },
4990 { 0x1217, 0x6972 },
4991 { 0x1179, 0x0603 },
4992 { 0x1179, 0x060a },
4993 { 0x1179, 0x060f },
4994 { 0x1179, 0x0617 },
4995 { 0x119b, 0x1221 },
4996 { 0x8086, 0x1221 }
4997 };
4998
4999 if(!hd) return 0;
5000
5001 if(
5002 hd->base_class.id == bc_bridge &&
5003 (hd->sub_class.id == sc_bridge_pcmcia || hd->sub_class.id == sc_bridge_cardbus)
5004 ) return 1;
5005
5006 /* just in case... */
5007 if(hd->bus.id == bus_pci) {
5008 for(i = 0; (unsigned) i < sizeof ids / sizeof *ids; i++) {
5009 if(
5010 ID_VALUE(hd->vendor.id) == ids[i][0] &&
5011 ID_VALUE(hd->device.id) == ids[i][1]
5012 ) return 1;
5013 }
5014 }
5015
5016 return 0;
5017}
5018
5019void hd_set_hw_class(hd_t *hd, hd_hw_item_t hw_class)
5020{
5021 unsigned ofs, bit;
5022
5023 ofs = (unsigned) hw_class >> 3;
5024 bit = (unsigned) hw_class & 7;
5025
5026 if(ofs < sizeof hd->hw_class_list / sizeof *hd->hw_class_list) {
5027 hd->hw_class_list[ofs] |= 1 << bit;
5028 }
5029}
5030
5031
5032int hd_is_hw_class(hd_t *hd, hd_hw_item_t hw_class)
5033{
5034 unsigned ofs, bit;
5035
5036 if(hw_class == hw_all) return 1;
5037
5038 ofs = (unsigned) hw_class >> 3;
5039 bit = (unsigned) hw_class & 7;
5040
5041 if(ofs < sizeof hd->hw_class_list / sizeof *hd->hw_class_list) {
5042 return hd->hw_class_list[ofs] & (1 << bit) ? 1 : 0;
5043 }
5044
5045 return 0;
5046}
5047
5048
5049/*
5050 * Start subprocess for dangerous things.
5051 *
5052 * Stop it after total_timeout seconds or if nothing happens for
5053 * timeout seconds.
5054 */
5055void hd_fork(hd_data_t *hd_data, int timeout, int total_timeout)
5056{
5057 void (*old_sigchld_handler)(int);
5058 struct timespec wait_time;
5059 int i, j, sleep_intr = 1;
5060 hd_data_t *hd_data_shm;
5061 time_t stop_time;
5062 int updated, rem_time;
5063 sigset_t new_set, old_set;
5064
5065 if(hd_data->flags.forked) return;
5066
5067 if(hd_data->flags.nofork) {
5068 hd_data->flags.forked = 1;
5069 return;
5070 }
5071
5072 hd_data_shm = hd_data->shm.data;
5073
5074 stop_time = time(NULL) + total_timeout;
5075 rem_time = total_timeout;
5076
5077 child_id = child = 0;
5078
5079 sigemptyset(&new_set);
5080 sigaddset(&new_set, SIGCHLD);
5081 sigprocmask(SIG_BLOCK, &new_set, &old_set);
5082
5083 old_sigchld_handler = signal(SIGCHLD, sigchld_handler);
5084
5085 wait_time.tv_sec = timeout;
5086 wait_time.tv_nsec = 0;
5087
5088 updated = hd_data_shm->shm.updated;
5089
5090 child = fork();
5091
5092 sigprocmask(SIG_SETMASK, &old_set, NULL);
5093
5094 if(child != -1) {
5095 if(child) {
5096 ADD2LOG(
5097 "****** started child process %d (%ds/%ds) ******\n",
5098 (int) child, timeout, total_timeout
5099 );
5100
5101 while(child_id != child && sleep_intr) {
5102 sleep_intr = nanosleep(&wait_time, &wait_time);
5103// fprintf(stderr, "woke up %d\n", sleep_intr);
5104 rem_time = stop_time - time(NULL);
5105 if(updated != hd_data_shm->shm.updated && rem_time >= 0) {
5106 /* reset time if there was some progress and we've got some time left */
5107 rem_time++;
5108 wait_time.tv_sec = rem_time > timeout ? timeout : rem_time;
5109 wait_time.tv_nsec = 0;
5110
5111 sleep_intr = 1;
5112 }
5113 updated = hd_data_shm->shm.updated;
5114 }
5115
5116 if(child_id != child) {
5117 ADD2LOG("****** killed child process %d (%ds) ******\n", (int) child, rem_time);
5118 kill(child, SIGKILL);
5119 for(i = 10; i && !waitpid(child, NULL, WNOHANG); i--) {
5120 wait_time.tv_sec = 0;
5121 wait_time.tv_nsec = 10*1000000;
5122 nanosleep(&wait_time, NULL);
5123 }
5124 }
5125
5126 i = hd_data->log ? strlen(hd_data->log) : 0;
5127
5128 if(hd_data_shm->log) {
5129 j = strlen(hd_data_shm->log);
5130 hd_data->log = resize_mem(hd_data->log, i + j + 1);
5131 memcpy(hd_data->log + i, hd_data_shm->log, j + 1);
5132 }
5133
5134 ADD2LOG("****** stopped child process %d (%ds) ******\n", (int) child, rem_time);
5135 }
5136 else {
5137#ifdef LIBHD_MEMCHECK
5138 /* stop logging in child process */
5139 if(libhd_log) fclose(libhd_log);
5140 libhd_log = NULL;
5141#endif
5142 hd_data->log = free_mem(hd_data->log);
5143
5144 hd_data->flags.forked = 1;
5145 }
5146 }
5147
5148 signal(SIGCHLD, old_sigchld_handler);
5149}
5150
5151
5152/*
5153 * Stop subprocess.
5154 */
5155void hd_fork_done(hd_data_t *hd_data)
5156{
5157 int len;
5158 void *p;
5159 hd_data_t *hd_data_shm;
5160
5161 if(!hd_data->flags.forked || hd_data->flags.nofork) return;
5162
5163 hd_data_shm = hd_data->shm.data;
5164
5165 if(hd_data->log) {
5166 len = strlen(hd_data->log) + 1;
5167 p = hd_shm_add(hd_data, hd_data->log, len);
5168 hd_data_shm->log = p;
5169 }
5170
5171 _exit(0);
5172}
5173
5174
5175/*
5176 * SIGCHLD handler while we're waiting for our child.
5177 */
5178void sigchld_handler(int num)
5179{
5180 pid_t p = waitpid(child, NULL, WNOHANG);
5181
5182 if(p && p == child) child_id = p;
5183}
5184
5185
5186/*
5187 * Get a sufficiently large shm segment.
5188 */
5189void hd_shm_init(hd_data_t *hd_data)
5190{
5191 void *p;
5192
5193 if(hd_data->shm.ok || hd_data->flags.nofork) return;
5194
5195 memset(&hd_data->shm, 0, sizeof hd_data->shm);
5196
5197 hd_data->shm.size = 256*1024;
5198
5199 hd_data->shm.id = shmget(IPC_PRIVATE, hd_data->shm.size, IPC_CREAT | 0600);
5200
5201 if(hd_data->shm.id == -1) {
5202 ADD2LOG("shm: shmget failed (errno %d)\n", errno);
5203 return;
5204 }
5205
5206 p = shmat(hd_data->shm.id, NULL, 0);
5207
5208 if(p == (void *) -1) {
5209 ADD2LOG("shm: shmat for segment %d failed (errno %d)\n", hd_data->shm.id, errno);
5210 }
5211
5212 shmctl(hd_data->shm.id, IPC_RMID, NULL);
5213
5214 if(p == (void *) -1) return;
5215
5216 hd_data->shm.data = p;
5217
5218 ADD2LOG("shm: attached segment %d at %p\n", hd_data->shm.id, hd_data->shm.data);
5219
5220 hd_data->shm.ok = 1;
5221
5222 hd_shm_clean(hd_data);
5223}
5224
5225
5226/*
5227 * Reset shm usage, remove references to shm area.
5228 */
5229void hd_shm_clean(hd_data_t *hd_data)
5230{
5231 hd_data_t *hd_data_shm;
5232
5233 if(!hd_data->shm.ok) return;
5234
5235 if(hd_is_shm_ptr(hd_data, hd_data->ser_mouse)) hd_data->ser_mouse = NULL;
5236 if(hd_is_shm_ptr(hd_data, hd_data->ser_modem)) hd_data->ser_modem = NULL;
5237
5238
5239 hd_data->shm.used = sizeof *hd_data;
5240 hd_data->shm.updated = 0;
5241
5242 memcpy(hd_data_shm = hd_data->shm.data, hd_data, sizeof *hd_data);
5243
5244 hd_data_shm->log = NULL;
5245}
5246
5247
5248/*
5249 * Release shm segment.
5250 */
5251void hd_shm_done(hd_data_t *hd_data)
5252{
5253 if(!hd_data->shm.ok) return;
5254
5255 shmdt(hd_data->shm.data);
5256
5257 hd_data->shm.ok = 0;
5258}
5259
5260
5261/*
5262 * Copy into shm area. If ptr is NULL return a shm area of size len.
5263 */
5264void *hd_shm_add(hd_data_t *hd_data, void *ptr, unsigned len)
5265{
5266 if(!hd_data->shm.ok || !len) return NULL;
5267
5268 hd_data = hd_data->shm.data;
5269
5270 if(hd_data->shm.size - hd_data->shm.used < len) return NULL;
5271
5272 if(ptr) {
5273 ptr = memcpy(hd_data->shm.data + hd_data->shm.used, ptr, len);
5274 }
5275 else {
5276 ptr = memset(hd_data->shm.data + hd_data->shm.used, 0, len);
5277 }
5278
5279 hd_data->shm.used += len;
5280
5281 return ptr;
5282}
5283
5284
5285/*
5286 * Check if ptr points to a valid shm address.
5287 */
5288int hd_is_shm_ptr(hd_data_t *hd_data, void *ptr)
5289{
5290 if(!hd_data->shm.ok || !ptr) return 0;
5291
5292 hd_data = hd_data->shm.data;
5293
5294 if(
5295 ptr < hd_data->shm.data ||
5296 ptr >= hd_data->shm.data + hd_data->shm.used
5297 ) return 0;
5298
5299 return 1;
5300}
5301
5302
5303char *hd_shm_add_str(hd_data_t *hd_data, char *str)
5304{
5305 return hd_shm_add(hd_data, str, str ? strlen(str) + 1 : 0);
5306}
5307
5308
5309str_list_t *hd_shm_add_str_list(hd_data_t *hd_data, str_list_t *sl)
5310{
5311 str_list_t *sl0 = NULL, **sl_shm;
5312
5313 for(sl_shm = &sl0; sl; sl = sl->next, sl_shm = &(*sl_shm)->next) {
5314 *sl_shm = hd_shm_add(hd_data, NULL, sizeof **sl_shm);
5315 (*sl_shm)->str = hd_shm_add_str(hd_data, sl->str);
5316 }
5317
5318 return sl0;
5319}
5320
5321
5322void hd_move_to_shm(hd_data_t *hd_data)
5323{
5324 hd_data_t *hd_data_shm;
5325 ser_device_t *ser, **ser_shm;
5326 struct {
5327 ser_device_t **src, **dst;
5328 } ser_dev[2];
5329 unsigned u;
5330
5331 if(!hd_data->shm.ok) return;
5332
5333 hd_data_shm = hd_data->shm.data;
5334
5335 ser_dev[0].src = &hd_data->ser_mouse;
5336 ser_dev[0].dst = &hd_data_shm->ser_mouse;
5337 ser_dev[1].src = &hd_data->ser_modem;
5338 ser_dev[1].dst = &hd_data_shm->ser_modem;
5339
5340 for(u = 0; u < sizeof ser_dev / sizeof *ser_dev; u++) {
5341 if(*ser_dev[u].src) {
5342 /* copy serial mouse data */
5343 for(
5344 ser = *ser_dev[u].src, ser_shm = ser_dev[u].dst;
5345 ser;
5346 ser = ser->next, ser_shm = &(*ser_shm)->next
5347 ) {
5348 *ser_shm = hd_shm_add(hd_data, ser, sizeof *ser);
5349 }
5350
5351 for(ser = *ser_dev[u].dst; ser; ser = ser->next) {
5352 ser->dev_name = hd_shm_add_str(hd_data, ser->dev_name);
5353 ser->serial = hd_shm_add_str(hd_data, ser->serial);
5354 ser->class_name = hd_shm_add_str(hd_data, ser->class_name);
5355 ser->dev_id = hd_shm_add_str(hd_data, ser->dev_id);
5356 ser->user_name = hd_shm_add_str(hd_data, ser->user_name);
5357 ser->vend = hd_shm_add_str(hd_data, ser->vend);
5358 ser->init_string1 = hd_shm_add_str(hd_data, ser->init_string1);
5359 ser->init_string2 = hd_shm_add_str(hd_data, ser->init_string2);
5360 ser->pppd_option = hd_shm_add_str(hd_data, ser->pppd_option);
5361
5362 ser->at_resp = hd_shm_add_str_list(hd_data, ser->at_resp);
5363 }
5364 }
5365 }
5366
5367}
5368
5369
5370hd_udevinfo_t *hd_free_udevinfo(hd_udevinfo_t *ui)
5371{
5372 hd_udevinfo_t *next;
5373
5374 for(; ui; ui = next) {
5375 next = ui->next;
5376
5377 free_mem(ui->sysfs);
5378 free_mem(ui->name);
5379 free_str_list(ui->links);
5380
5381 free_mem(ui);
5382 }
5383
5384 return NULL;
5385}
5386
5387
5388void read_udevinfo(hd_data_t *hd_data)
5389{
5390 str_list_t *sl, *udevinfo, *sl0, *sl1, *dir_list;
5391 hd_udevinfo_t **uip, *ui;
5392 char *s, buf[256];
5393 int l;
5394
5395 udevinfo = NULL;
5396
5397 if((dir_list = read_dir("/dev/.udevdb", 'r'))) {
5398 s = NULL;
5399
5400 for(sl = dir_list; sl; sl = sl->next) {
5401 str_printf(&s, 0, "/dev/.udevdb/%s", sl->str);
5402 sl0 = read_file(s, 0, 0);
5403 if(sl0) {
5404 sl1 = udevinfo;
5405 udevinfo = sl0;
5406 while(sl0->next) sl0 = sl0->next;
5407 sl0->next = sl1;
5408 }
5409 }
5410
5411 s = free_mem(s);
5412 free_str_list(dir_list);
5413 }
5414 else {
5415 udevinfo = read_file("| " PROG_UDEVINFO " -d 2>/dev/null", 0, 0);
5416 }
5417
5418 ADD2LOG("----- udevinfo -----\n");
5419 for(sl = udevinfo; sl; sl = sl->next) {
5420 ADD2LOG(" %s", sl->str);
5421 }
5422 ADD2LOG("----- udevinfo end -----\n");
5423
5424 hd_data->udevinfo = hd_free_udevinfo(hd_data->udevinfo);
5425
5426 uip = &hd_data->udevinfo;
5427
5428 for(ui = NULL, sl = udevinfo; sl; sl = sl->next) {
5429 if(sscanf(sl->str, "P: %255s", buf) == 1) {
5430 ui = *uip = new_mem(sizeof **uip);
5431 uip = &(*uip)->next;
5432 ui->sysfs = new_str(buf);
5433
5434 continue;
5435 }
5436
5437 if(sscanf(sl->str, "T: %255s", buf) == 1) {
5438 ui->type = *buf;
5439
5440 continue;
5441 }
5442
5443 if(sscanf(sl->str, "N: %255s", buf) == 1) {
5444 free_mem(ui->name);
5445 ui->name = new_str(buf);
5446
5447 continue;
5448 }
5449
5450 if(!strncmp(sl->str, "S:", 2)) {
5451 s = sl->str + 2;
5452 while(*s == ' ') s++;
5453 l = strlen(s);
5454 while(l > 0 && isspace(s[l-1])) s[--l] = 0;
5455 if(*s) {
5456 sl0 = hd_split(' ', s);
5457 for(sl1 = sl0; sl1; sl1 = sl1->next) {
5458 add_str_list(&ui->links, sl1->str);
5459 }
5460 free_str_list(sl0);
5461 }
5462
5463 continue;
5464 }
5465 }
5466
5467 for(ui = hd_data->udevinfo; ui; ui = ui->next) {
5468 ADD2LOG("%s\n", ui->sysfs);
5469 if(ui->name) ADD2LOG(" name: %s\n", ui->name);
5470 if(ui->links) {
5471 s = hd_join(", ", ui->links);
5472 ADD2LOG(" links: %s\n", s);
5473 free_mem(s);
5474 }
5475 }
5476
5477 free_str_list(udevinfo);
5478}
5479
5480
5481/*
5482 * Return libhd version.
5483 */
5484char *hd_version()
5485{
5486 return HD_VERSION_STRING;
5487}
5488
5489
5490hd_t *hd_find_sysfs_id(hd_data_t *hd_data, char *id)
5491{
5492 hd_t *hd;
5493
5494 if(id && *id) {
5495 for(hd = hd_data->hd; hd; hd = hd->next) {
5496 if(hd->sysfs_id && !strcmp(hd->sysfs_id, id)) return hd;
5497 }
5498 }
5499
5500 return NULL;
5501}
5502
5503
5504hd_sysfsdrv_t *hd_free_sysfsdrv(hd_sysfsdrv_t *sf)
5505{
5506 hd_sysfsdrv_t *next;
5507
5508 for(; sf; sf = next) {
5509 next = sf->next;
5510
5511 free_mem(sf->driver);
5512 free_mem(sf->device);
5513
5514 free_mem(sf);
5515 }
5516
5517 return NULL;
5518}
5519
5520
5521void hd_sysfs_driver_list(hd_data_t *hd_data)
5522{
5523 char *bus;
5524 hd_sysfsdrv_t **sfp, *sf;
5525 str_list_t *sl, *sl0;
5526 uint64_t id = 0;
5527
5528 struct sysfs_bus *sf_bus;
5529 struct sysfs_driver *sf_drv;
5530 struct sysfs_device *sf_dev;
5531
5532 struct dlist *sf_subsys;
5533 struct dlist *sf_drv_list;
5534 struct dlist *sf_dev_list;
5535
5536
5537 for(sl = sl0 = read_file(PROC_MODULES, 0, 0); sl; sl = sl->next) {
5538 crc64(&id, sl->str, strlen(sl->str) + 1);
5539 }
5540 free_str_list(sl0);
5541
5542 if(id != hd_data->sysfsdrv_id) {
5543 hd_data->sysfsdrv = hd_free_sysfsdrv(hd_data->sysfsdrv);
5544 }
5545
5546 if(hd_data->sysfsdrv) return;
5547
5548 hd_data->sysfsdrv_id = id;
5549
5550 sfp = &hd_data->sysfsdrv;
5551
5552 ADD2LOG("----- sysfs driver list (id 0x%016"PRIx64") -----\n", id);
5553
5554 sf_subsys = sysfs_open_subsystem_list("bus");
5555
5556 if(sf_subsys) dlist_for_each_data(sf_subsys, bus, char) {
5557 sf_bus = sysfs_open_bus(bus);
5558
5559 if(sf_bus) {
5560 sf_drv_list = sysfs_get_bus_drivers(sf_bus);
5561 if(sf_drv_list) dlist_for_each_data(sf_drv_list, sf_drv, struct sysfs_driver) {
5562 sf_dev_list = sysfs_get_driver_devices(sf_drv);
5563 if(sf_dev_list) dlist_for_each_data(sf_dev_list, sf_dev, struct sysfs_device) {
5564 sf = *sfp = new_mem(sizeof **sfp);
5565 sfp = &(*sfp)->next;
5566 sf->driver = new_str(sf_drv->name);
5567 sf->device = new_str(hd_sysfs_id(sf_dev->path));
5568 ADD2LOG("%16s: %s\n", sf->driver, sf->device);
5569 }
5570 }
5571
5572 sysfs_close_bus(sf_bus);
5573 }
5574 }
5575
5576 sysfs_close_list(sf_subsys);
5577
5578 ADD2LOG("----- sysfs driver list end -----\n");
5579}
5580
5581
5582int hd_report_this(hd_data_t *hd_data, hd_t *hd)
5583{
5584 if(!hd_data->only) return 1;
5585
5586 if(search_str_list(hd_data->only, hd->sysfs_id)) return 1;
5587
5588 return search_str_list(hd_data->only, hd->unix_dev_name) ? 1 : 0;
5589}
5590
5591
5592str_list_t *hd_module_list(hd_data_t *hd_data, unsigned id)
5593{
5594 hd_t *hd;
5595 str_list_t *drivers = NULL, *sl;
5596 driver_info_t *di;
5597
5598 hd = new_mem(sizeof *hd);
5599 hd->tag.freeit = 1;
5600
5601 hd->vendor.id = MAKE_ID(TAG_SPECIAL, 0xf000);
5602 hd->device.id = MAKE_ID(TAG_SPECIAL, id);
5603
5604 hddb_add_info(hd_data, hd);
5605
5606 for(di = hd->driver_info; di; di = di->next) {
5607 if(di->any.type == di_module && di->module.modprobe) {
5608 for(sl = di->module.names; sl; sl = sl->next) {
5609 add_str_list(&drivers, sl->str);
5610 }
5611 }
5612 }
5613
5614 hd_free_hd_list(hd);
5615
5616 return drivers;
5617}
5618
5619
5620/*
5621 * Read using mmap().
5622 */
5623int hd_read_mmap(hd_data_t *hd_data, char *name, unsigned char *buf, off_t start, unsigned size)
5624{
5625 off_t map_start, xofs;
5626 int psize = getpagesize(), fd;
5627 unsigned map_size;
5628 void *p;
5629 struct stat sbuf;
5630
5631 if(!size || !name) return 0;
5632
5633 memset(buf, 0, size);
5634
5635 map_start = start & -psize;
5636 xofs = start - map_start;
5637
5638 map_size = (xofs + size + psize - 1) & -psize;
5639
5640 fd = open(name, O_RDONLY);
5641
5642 if(fd == -1) return 0;
5643
5644 if(!fstat(fd, &sbuf) && S_ISREG(sbuf.st_mode)) {
5645 if(sbuf.st_size < start + size) {
5646 if(sbuf.st_size > start) {
5647 size = sbuf.st_size - start;
5648 }
5649 else {
5650 size = 0;
5651 }
5652 }
5653 }
5654
5655 if(!size) {
5656 close(fd);
5657 return 0;
5658 }
5659
5660 p = mmap(NULL, map_size, PROT_READ, MAP_PRIVATE, fd, map_start);
5661
5662 if(p == MAP_FAILED) {
5663 if(hd_data) ADD2LOG(
5664 "%s[0x%x, %u]: mmap(, %u,,,, 0x%x) failed: %s\n",
5665 name, (unsigned) start, size, map_size, (unsigned) map_start, strerror(errno)
5666 );
5667 close(fd);
5668 return 0;
5669 }
5670 if(hd_data) ADD2LOG(
5671 "%s[0x%x, %u]: mmap(, %u,,,, 0x%x) ok\n",
5672 name, (unsigned) start, size, map_size, (unsigned) map_start
5673 );
5674
5675 memcpy(buf, p + xofs, size);
5676
5677 munmap(p, map_size);
5678
5679 close(fd);
5680
5681 return 1;
5682}
5683
5684