- remove adb code (#206648)
[opensuse:hwinfo.git] / src / hd / hdp.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include <stdarg.h>
6
7 #include "hd.h"
8 #include "hd_int.h"
9 #include "hdp.h"
10 #include "hddb.h"
11 #include "smbios.h"
12
13
14 /**
15  * @defgroup HDPRINTint Hardware scan console output
16  * @ingroup libhdInternals
17  * @brief Hardware scan console output functions
18  *
19  * This module provides a function that prints a hardware entry. 
20  * This is useful for debugging or to provide the user with some fancy info.
21  *
22  * @{
23  */
24
25 #ifndef LIBHD_TINY
26
27 #define dump_line(x0, x1...) fprintf(f, "%*s" x0, ind, "", x1)
28 #define dump_line_str(x0...) fprintf(f, "%*s%s", ind, "", x0)
29 #define dump_line0(x0...) fprintf(f, x0)
30
31 static int ind = 0;             /* output indentation */
32
33 static void dump_normal(hd_data_t *, hd_t *, FILE *);
34 static void dump_cpu(hd_data_t *, hd_t *, FILE *);
35 static void dump_bios(hd_data_t *, hd_t *, FILE *);
36 static void dump_prom(hd_data_t *, hd_t *, FILE *);
37 static void dump_sys(hd_data_t *, hd_t *, FILE *);
38
39 static char *dump_hid(hd_data_t *hd_data, hd_id_t *hid, int format, char *buf, int buf_size);
40 static char *dump_hid2(hd_data_t *hd_data, hd_id_t *hid1, hd_id_t *hid2, char *buf, int buf_size);
41 static char *print_dev_num(hd_dev_num_t *d);
42
43 /*
44  * Dump a hardware entry to FILE *f.
45  */
46 void hd_dump_entry(hd_data_t *hd_data, hd_t *h, FILE *f)
47 {
48   char *s, *a0, *a1, *a2, *s1, *s2;
49   char buf1[32], buf2[32];
50   hd_t *hd_tmp;
51   int i, j;
52   str_list_t *sl;
53   hal_prop_t *prop;
54
55 #ifdef LIBHD_MEMCHECK
56   {
57     if(libhd_log)
58       fprintf(libhd_log, "; %s\t%p\t%p\n", __FUNCTION__, CALLED_FROM(hd_dump_entry, hd_data), hd_data);
59   }
60 #endif
61
62   if(!h) return;
63
64   s = "";
65   if(h->is.agp) s = "(AGP)";
66   //  pci_flag_pm: dump_line0(", supports PM");
67   if(h->is.isapnp) s = "(PnP)";
68
69   a0 = h->bus.name;
70   a2 = NULL;
71   a1 = h->sub_class.name ?: h->base_class.name;
72   if(a1 && h->prog_if.name) {
73     str_printf(&a2, 0, "%s (%s)", a1, h->prog_if.name);
74   }
75   else {
76     a2 = new_str(a1 ?: "?");
77   }
78   dump_line(
79     "%02d: %s%s %02x.%x: %02x%02x %s\n",
80     h->idx, a0 ? a0 : "?", s, h->slot, h->func,
81     h->base_class.id, h->sub_class.id, a2
82   );
83
84   ind += 2;
85
86   if((hd_data->debug & HD_DEB_CREATION)) {
87     s = mod_name_by_idx(h->module);
88     if(!s) sprintf(s = buf1, "%u", h->module);
89     if(h->count)
90       sprintf(buf2, ".%u", h->count);
91     else
92       *buf2 = 0;
93     dump_line("[Created at %s.%u%s]\n", s, h->line, buf2);
94   }
95
96   if(hd_data->flags.dformat == 1) {
97     dump_line("ClassName: \"%s\"\n", a2);
98     dump_line("Bus: %d\n", h->slot >> 8);
99     dump_line("Slot: %d\n", h->slot & 0xff);
100     dump_line("Function: %d\n", h->func);
101   }
102
103   a2 = free_mem(a2);
104
105   if(h->udi) {
106     dump_line("UDI: %s\n", h->udi);
107   }
108
109   if(h->parent_udi) {
110     dump_line("Parent UDI: %s\n", h->parent_udi);
111   }
112
113   if((hd_data->debug & HD_DEB_CREATION) && h->unique_id) {
114     dump_line("Unique ID: %s\n", h->unique_id);
115   }
116
117   if(hd_data->debug == -1u && h->old_unique_id) {
118     dump_line("Old Unique ID: %s\n", h->old_unique_id);
119   }
120
121   if((hd_data->debug & HD_DEB_CREATION) && h->parent_id) {
122     dump_line("Parent ID: %s\n", h->parent_id);
123   }
124
125   if(hd_data->debug == -1u && h->child_ids) {
126     s = hd_join(", ", h->child_ids);
127     dump_line("Child IDs: %s\n", s);
128     s = free_mem(s);
129   }
130
131   if(h->sysfs_id) {
132     dump_line("SysFS ID: %s\n", h->sysfs_id);
133   }
134
135   if(h->sysfs_bus_id) {
136     dump_line("SysFS BusID: %s\n", h->sysfs_bus_id);
137   }
138
139   if(h->sysfs_device_link) {
140     dump_line("SysFS Device Link: %s\n", h->sysfs_device_link);
141   }
142
143   if(h->hw_class && (s = hd_hw_item_name(h->hw_class))) {
144     dump_line("Hardware Class: %s\n", s);
145   }
146
147   if(hd_data->debug == -1u) {
148     for(i = j = 0; i < (int) hw_all; i++) {
149       if(i != hw_unknown && hd_is_hw_class(h, i) && (s = hd_hw_item_name(i))) {
150         if(!j) {
151           dump_line("HW Class List: %s", s);
152         }
153         else {
154           dump_line0(", %s", s);
155         }
156         j = 1;
157       }
158     }
159     if(j) dump_line0("\n");
160   }
161
162   if(h->base_class.id == bc_internal && h->sub_class.id == sc_int_cpu) {
163     dump_cpu(hd_data, h, f);
164   }
165   else if(h->base_class.id == bc_internal && h->sub_class.id == sc_int_bios) {
166     dump_bios(hd_data, h, f);
167   }
168   else if(h->base_class.id == bc_internal && h->sub_class.id == sc_int_prom) {
169     dump_prom(hd_data, h, f);
170   }
171   else {
172     dump_normal(hd_data, h, f);
173   }
174
175   s1 = s2 = NULL;
176   if(h->is.notready) {
177     if(h->base_class.id == bc_storage_device) {
178       s1 = "no medium";
179     }
180     else {
181       s1 = "not configured";
182     }
183   }
184   if(h->is.softraiddisk) s2 = "soft raid";
185   if(!s1) { s1 = s2; s2 = NULL; }
186
187   if(s1) {
188     dump_line("Drive status: %s%s%s\n", s1, s2 ? ", " : "", s2 ?: "");
189   }
190
191   if(h->extra_info) {
192     dump_line_str("Extra Info: ");
193     for(i = 0, sl = h->extra_info; sl; sl = sl->next) {
194       dump_line0("%s%s", i ? ", " : "", sl->str);
195       i = 1;
196     }
197     dump_line0("\n");
198   }
199
200   if(hd_data->debug == -1 && (prop = h->hal_prop)) {
201     dump_line_str("HAL Properties:\n");
202     for(; prop; prop = prop->next) {
203       s = hd_hal_print_prop(prop);
204       dump_line("  %s\n", s);
205     }
206   }
207
208   if(hd_data->debug == -1 && (prop = h->persistent_prop)) {
209     dump_line_str("Persistent Properties:\n");
210     for(; prop; prop = prop->next) {
211       s = hd_hal_print_prop(prop);
212       dump_line("  %s\n", s);
213     }
214   }
215
216   if(
217     hd_data->debug && (
218       h->status.configured ||
219       h->status.available ||
220       h->status.needed ||
221       h->status.active ||
222       h->status.invalid ||
223       h->is.manual
224     )
225   ) {
226     dump_line_str("Config Status: ");
227     i = 0;
228
229     if(h->status.invalid) {
230       dump_line0("invalid");
231       i++;
232     }
233
234     if(h->is.manual) {
235       dump_line0("%smanual", i ? ", " : "");
236       i++;
237     }
238
239     if(h->status.configured && (s = hd_status_value_name(h->status.configured))) {
240       dump_line0("%scfg=%s", i ? ", " : "", s);
241       i++;
242     }
243
244     if(h->status.available && (s = hd_status_value_name(h->status.available))) {
245       dump_line0("%savail=%s", i ? ", " : "", s);
246       i++;
247     }
248
249     if(h->status.needed && (s = hd_status_value_name(h->status.needed))) {
250       dump_line0("%sneed=%s", i ? ", " : "", s);
251       i++;
252     }
253
254     if(h->status.active && (s = hd_status_value_name(h->status.active))) {
255       dump_line0("%sactive=%s", i ? ", " : "", s);
256       i++;
257     }
258
259     dump_line0("\n");
260   }
261
262   if(hd_data->debug == -1u && h->config_string) {
263     dump_line("Configured as: \"%s\"\n", h->config_string);
264   }
265
266   if(
267     h->attached_to &&
268     (hd_tmp = hd_get_device_by_idx(hd_data, h->attached_to))
269   ) {
270     s = hd_tmp->sub_class.name ?: hd_tmp->base_class.name;
271     dump_line("Attached to: #%u (%s)\n", h->attached_to, s ?: "?");
272   }
273
274   if(h->detail && h->detail->ccw.type==hd_detail_ccw)
275   {
276     dump_line("LCSS: %x.%x\n",h->detail->ccw.data->lcss >> 8, h->detail->ccw.data->lcss & 0xf);
277     dump_line("CU Model: 0x%x\n",h->detail->ccw.data->cu_model);
278     dump_line("Device Model: 0x%x\n",h->detail->ccw.data->dev_model);
279   }
280
281 #if defined(__s390__) || defined(__s390x__)
282   if(h->detail && h->detail->scsi.type==hd_detail_scsi)
283   {
284     if(h->detail->scsi.data->wwpn != (uint64_t)-1)
285       dump_line("WWPN: 0x%llx\n",(unsigned long long)h->detail->scsi.data->wwpn);
286     if(h->detail->scsi.data->wwpn != (uint64_t)-1)
287       dump_line("FCP LUN: 0x%llx\n",(unsigned long long)h->detail->scsi.data->fcp_lun);
288     dump_line("SCSI Host CCW ID: %s\n",h->detail->scsi.data->controller_id);
289   }
290 #endif
291
292   if(
293     h->base_class.id == bc_storage_device &&
294     h->sub_class.id == sc_sdev_cdrom &&
295     h->detail &&
296     h->detail->type == hd_detail_cdrom &&
297     h->detail->cdrom.data
298   ) {
299     cdrom_info_t *ci = h->detail->cdrom.data;
300
301     if(ci->speed) {
302       dump_line("Drive Speed: %u\n", ci->speed);
303     }
304
305     if(ci->iso9660.ok) {
306       if(ci->iso9660.volume) dump_line("Volume ID: \"%s\"\n", ci->iso9660.volume);
307       if(ci->iso9660.application) dump_line("Application: \"%s\"\n", ci->iso9660.application);
308       if(ci->iso9660.publisher) dump_line("Publisher: \"%s\"\n", ci->iso9660.publisher);
309       if(ci->iso9660.preparer) dump_line("Preparer: \"%s\"\n", ci->iso9660.preparer);
310       if(ci->iso9660.creation_date) dump_line("Creation date: \"%s\"\n", ci->iso9660.creation_date);
311     }
312 #if 0
313     else {
314       if(ci->cdrom) {
315         dump_line_str("Drive status: non-ISO9660 cdrom\n");
316       }
317       else {
318         dump_line_str("Drive status: no cdrom found\n");
319       }
320     }
321 #endif
322     if(ci->el_torito.ok) {
323       dump_line(
324         "El Torito info: platform %u, %sbootable\n",
325         ci->el_torito.platform,
326         ci->el_torito.bootable ? "" : "not "
327       );
328       dump_line("  Boot Catalog: at sector 0x%04x\n", ci->el_torito.catalog);
329       if(ci->el_torito.id_string) dump_line("  Id String: \"%s\"\n",  ci->el_torito.id_string);
330       if(ci->el_torito.label) dump_line("  Volume Label: \"%s\"\n",  ci->el_torito.label);
331       {
332         static char *media[] = {
333           "none", "1.2MB Floppy", "1.44MB Floppy", "2.88MB Floppy", "Hard Disk"
334         };
335         dump_line(
336           "  Media: %s starting at sector 0x%04x\n",
337           media[ci->el_torito.media_type < sizeof media / sizeof *media ? ci->el_torito.media_type : 0],
338           ci->el_torito.start
339         );
340       }
341       if(ci->el_torito.geo.size) dump_line(
342         "  Geometry (CHS): %u/%u/%u (%u blocks)\n",
343         ci->el_torito.geo.c, ci->el_torito.geo.h, ci->el_torito.geo.s, ci->el_torito.geo.size
344       );
345       dump_line("  Load: %u bytes", ci->el_torito.load_count * 0x200);
346       if(ci->el_torito.load_address) {
347         dump_line0(" at 0x%04x\n", ci->el_torito.load_address);
348       }
349       else {
350         dump_line0("\n");
351       }
352     }
353   }
354
355 #if 0
356   if(
357     h->base_class.id == bc_storage_device &&
358     h->sub_class.id == sc_sdev_floppy &&
359     h->detail &&
360     h->detail->type == hd_detail_floppy
361   ) {
362     floppy_info_t *fi = h->detail->floppy.data;
363
364     if(fi) {
365       dump_line_str("Drive status: floppy found\n");
366     }
367     else {
368       dump_line_str("Drive status: no floppy found\n");
369     }
370   }
371 #endif
372
373   ind -= 2;
374
375   if(h->next) dump_line_str("\n");
376 }
377
378
379 /*
380  * print 'normal' hardware entries
381  */
382 void dump_normal(hd_data_t *hd_data, hd_t *h, FILE *f)
383 {
384   int i, j;
385   char *s;
386   uint64_t u64;
387   hd_res_t *res;
388   char buf[256], c0, c1;
389   driver_info_t *di;
390   str_list_t *sl, *sl1, *sl2;
391   isdn_parm_t *ip;
392   static char *geo_type_str[] = { "Physical", "Logical", "BIOS EDD", "BIOS Legacy" };
393
394   if(h->model) dump_line("Model: \"%s\"\n", h->model);
395
396   s = NULL;
397   switch(h->hotplug) {
398     case hp_none:
399       break;
400     case hp_pcmcia:
401       s = "PCMCIA";
402       break;
403     case hp_cardbus:
404       s = "CardBus";
405       break;
406     case hp_pci:
407       s = "PCI";
408       break;
409     case hp_usb:
410       s = "USB";
411       break;
412     case hp_ieee1394:
413       s = "IEEE1394 (FireWire)";
414       break;
415   }
416
417   if(s) {
418     dump_line("Hotplug: %s\n", s);
419   }
420
421   if(
422     (h->hotplug == hp_pcmcia || h->hotplug == hp_cardbus) &&
423     h->hotplug_slot
424   ) {
425     dump_line("Socket: %u\n", h->hotplug_slot - 1);
426   }
427
428   if(h->vendor.id || h->vendor.name || h->device.id || h->device.name) {
429     if(h->vendor.id || h->vendor.name) {
430       dump_line("Vendor: %s\n", dump_hid(hd_data, &h->vendor, 1, buf, sizeof buf));
431     }
432     dump_line("Device: %s\n", dump_hid(hd_data, &h->device, 0, buf, sizeof buf));
433   }
434
435   if(h->sub_vendor.id || h->sub_device.id || h->sub_device.name || h->sub_vendor.name) {
436     if(h->sub_vendor.id || h->sub_vendor.name || h->sub_device.id) {
437       dump_line("SubVendor: %s\n", dump_hid(hd_data, &h->sub_vendor, 1, buf, sizeof buf));
438     }
439     dump_line("SubDevice: %s\n", dump_hid(hd_data, &h->sub_device, 0, buf, sizeof buf));
440   }
441
442   if(h->revision.name) {
443     dump_line("Revision: \"%s\"\n", h->revision.name);
444   }
445   else if(h->revision.id) {
446     dump_line("Revision: 0x%02x\n", h->revision.id);
447   }
448
449   if(h->serial) {
450     dump_line("Serial ID: \"%s\"\n", h->serial);
451   }
452
453   if(h->usb_guid) {
454     dump_line("USB GUID: %s\n", h->usb_guid);
455   }
456
457   if(h->compat_vendor.id || h->compat_device.id) {
458     dump_line(
459       "Compatible to: %s\n",
460       dump_hid2(hd_data, &h->compat_vendor, &h->compat_device, buf, sizeof buf)
461     );
462   }
463
464   if(h->base_class.id == bc_internal && h->sub_class.id == sc_int_sys) {
465     dump_sys(hd_data, h, f);
466   }
467
468   if(h->drivers) {
469     s = hd_join("\", \"", h->drivers);
470     dump_line("Driver: \"%s\"\n", s);
471     s = free_mem(s);
472   }
473
474   if(h->driver_modules) {
475     s = hd_join("\", \"", h->driver_modules);
476     dump_line("Driver Modules: \"%s\"\n", s);
477     s = free_mem(s);
478   }
479
480   if(h->broken) {
481     dump_line_str("Warning: might be broken\n");
482   }
483
484   if(hd_data->flags.dformat == 1) {
485     if(h->unix_dev_name) {
486       dump_line("Device File: %s\n", h->unix_dev_name);
487     }
488     if(h->unix_dev_name2) {
489       dump_line("Alternative Device File: %s\n", h->unix_dev_name2);
490     }
491   }
492   else {
493     s = h->unix_dev_name;
494     if(!s) s = h->unix_dev_name2;
495     if(s) {
496       dump_line("Device File: %s", s);
497       if(h->unix_dev_name2) {
498         dump_line0(" (%s)", h->unix_dev_name2);
499       }
500       dump_line0("\n");
501     }
502
503   }
504
505   /* only if there are more than one */
506   if(h->unix_dev_names && h->unix_dev_names->next) {
507     s = hd_join(", ", h->unix_dev_names);
508     dump_line("Device Files: %s\n", s);
509     s = free_mem(s);
510   }
511
512   if(h->unix_dev_num.type) {
513     dump_line("Device Number: %s", print_dev_num(&h->unix_dev_num));
514     if(h->unix_dev_num2.type) {
515       dump_line0(" (%s)", print_dev_num(&h->unix_dev_num2));
516     }
517     dump_line0("\n");
518   }
519
520   if(h->rom_id) {
521 #if defined(__i386__) || defined (__x86_64__)
522     dump_line("BIOS id: %s\n", h->rom_id);
523 #endif
524 #if defined(__PPC__) || defined(__sparc__)
525     dump_line("PROM id: %s\n", h->rom_id);
526 #endif
527 #if defined(__s390__) || defined(__s390x__)
528     dump_line("IUCV user: %s\n", h->rom_id);
529 #endif
530   }
531
532   if(h->tag.ser_skip) {
533     dump_line_str("Tags: ser_skip\n");
534   }
535
536   if(
537     h->is.zip ||
538     h->is.cdr || h->is.cdrw || h->is.dvd || h->is.dvdr || h->is.dvdrw ||
539     h->is.dvdpr || h->is.dvdprw || h->is.dvdprdl || h->is.dvdram ||
540     h->is.pppoe || h->is.wlan || h->is.hotpluggable
541   ) {
542     dump_line_str("Features:");
543     i = 0;
544     if(h->is.zip) dump_line0("%s ZIP", i++ ? "," : "");
545     if(h->is.cdr) dump_line0("%s CD-R", i++ ? "," : "");
546     if(h->is.cdrw) dump_line0("%s CD-RW", i++ ? "," : "");
547     if(h->is.dvd) dump_line0("%s DVD", i++ ? "," : "");
548     if(h->is.dvdr) dump_line0("%s DVD-R", i++ ? "," : "");
549     if(h->is.dvdrw) dump_line0("%s DVD-RW", i++ ? "," : "");
550     if(h->is.dvdpr) dump_line0("%s DVD+R", i++ ? "," : "");
551     if(h->is.dvdprw) dump_line0("%s DVD+RW", i++ ? "," : "");
552     if(h->is.dvdprdl) dump_line0("%s DVD+DL", i++ ? "," : "");
553     if(h->is.dvdram) dump_line0("%s DVDRAM", i++ ? "," : "");
554     if(h->is.pppoe) dump_line0("%s PPPOE", i++ ? "," : "");
555     if(h->is.wlan) dump_line0("%s WLAN", i++ ? "," : "");
556     if(h->is.hotpluggable) dump_line0("%s Hotpluggable", i++ ? "," : "");
557     dump_line0("\n");
558   }
559
560   for(res = h->res; res; res = res->next) {
561     switch(res->any.type) {
562       case res_phys_mem:
563         u64 = res->phys_mem.range >> 10;
564         c0 = 'M'; c1 = 'k';
565         if(u64 >> 20) {
566           u64 >>= 10;
567           c0 = 'G'; c1 = 'M';
568         }
569         if((u64 & 0x3ff)) {
570           dump_line("Memory Size: %"PRId64" %cB + %"PRId64" %cB\n", u64 >> 10, c0, u64 & 0x3ff, c1);
571         }
572         else {
573           dump_line("Memory Size: %"PRId64" %cB\n", u64 >> 10, c0);
574         }
575         break;
576
577       case res_mem:
578         *(s = buf) = 0;
579         strcat(buf, res->mem.access == acc_rw ? "rw" : res->mem.access == acc_ro ? "ro" : "wo");
580         strcat(buf, res->mem.prefetch == flag_yes ? ",prefetchable" : res->mem.prefetch == flag_no ? ",non-prefetchable" : "");
581         if(!res->mem.enabled) strcat(buf, ",disabled");
582         if(*s == ',') s++;
583         if(res->mem.range) {
584           dump_line(
585             "Memory Range: 0x%08"PRIx64"-0x%08"PRIx64" (%s)\n",
586             res->mem.base, res->mem.base + res->mem.range - 1, s
587           );
588         }
589         else {
590           dump_line("Memory Range: 0x%08"PRIx64"-??? (%s)\n", res->mem.base, s);
591         }
592         break;
593
594       case res_io:
595         *(s = buf) = 0;
596         strcat(buf, res->io.access == acc_rw ? "rw" : res->io.access == acc_ro ? "ro" : "wo");
597         if(!res->io.enabled) strcat(buf, ",disabled");
598         if(*s == ',') s++;
599         if(res->io.range == 0) {
600           dump_line("I/O Ports: 0x%02"PRIx64"-??? (%s)\n", res->io.base, s);
601         }
602         else if(res->io.range == 1) {
603           dump_line("I/O Port: 0x%02"PRIx64" (%s)\n", res->io.base, s);
604         }
605         else {
606           dump_line("I/O Ports: 0x%02"PRIx64"-0x%02"PRIx64" (%s)\n", res->io.base, res->io.base + res->io.range -1, s);
607         }
608         break;
609
610       case res_irq:
611         *(s = buf) = 0;
612         switch(res->irq.triggered) {
613           case 0:
614             strcpy(s, "no events");
615             break;
616
617           case 1:
618             strcpy(s, "1 event");
619             break;
620
621           default:
622             sprintf(s, "%u events", res->irq.triggered);
623         }
624         if(!res->irq.enabled) {
625           if(res->irq.triggered)
626             strcat(s, ",");
627           else
628             *s = 0;
629           strcat(s, "disabled");
630         }
631         dump_line("IRQ: %u (%s)\n", res->irq.base, s);
632         break;
633
634       case res_dma:
635         *(s = buf) = 0;
636         if(!res->dma.enabled) strcpy(buf, " (disabled)");
637         dump_line("DMA: %u%s\n", res->dma.base, s);
638         break;
639
640       case res_monitor:
641         dump_line(
642           "Resolution: %ux%u@%uHz%s\n",
643           res->monitor.width, res->monitor.height, res->monitor.vfreq,
644           res->monitor.interlaced ? " (interlaced)" : ""
645         );
646         break;
647
648       case res_size:
649         {
650           char *s, b0[64], b1[64];
651
652           switch(res->size.unit) {
653             case size_unit_cinch:
654               s = "''";
655               snprintf(b0, sizeof b0 - 1, "%s", float2str(res->size.val1, 2));
656               snprintf(b1, sizeof b1 - 1, "%s", float2str(res->size.val2, 2));
657               break;
658
659             default:
660               switch(res->size.unit) {
661                 case size_unit_cm:
662                   s = "cm";
663                   break;
664                 case size_unit_mm:
665                   s = "mm";
666                   break;
667                 case size_unit_sectors:
668                   s = "sectors";
669                   break;
670                 case size_unit_kbyte:
671                   s = "kByte";
672                   break;
673                 default:
674                   s = "some unit";
675               }
676               snprintf(b0, sizeof b0 - 1, "%"PRIu64, res->size.val1);
677               snprintf(b1, sizeof b1 - 1, "%"PRIu64, res->size.val2);
678           }
679           if(!res->size.val2)
680             dump_line("Size: %s %s\n", b0, s);
681           else if(res->size.unit == size_unit_sectors)
682             dump_line("Size: %s %s a %s bytes\n", b0, s, b1);
683           else
684             dump_line("Size: %sx%s %s\n", b0, b1, s);
685         }
686         break;
687
688       case res_disk_geo:
689         s = res->disk_geo.geotype < sizeof geo_type_str / sizeof *geo_type_str ?
690           geo_type_str[res->disk_geo.geotype] : "";
691         dump_line(
692           "Geometry (%s): CHS %u/%u/%u\n", s,
693           res->disk_geo.cyls, res->disk_geo.heads, res->disk_geo.sectors
694         );
695         if(res->disk_geo.size) {
696           dump_line("Size (%s): %"PRIu64" sectors\n", s, res->disk_geo.size);
697         }
698         break;
699
700       case res_cache:
701         dump_line("Cache: %u kb\n", res->cache.size);
702         break;
703
704       case res_baud:
705         if(res->baud.speed == 0 || res->baud.speed % 100) {
706           dump_line("Speed: %u bps\n", res->baud.speed);
707         }
708         else if(res->baud.speed % 100000) {
709           dump_line("Speed: %s kbps\n", float2str(res->baud.speed, 3));
710         }
711         else {
712           dump_line("Speed: %s Mbps\n", float2str(res->baud.speed, 6));
713         }
714         if(res->baud.bits || res->baud.stopbits || res->baud.parity || res->baud.handshake) {
715           int i = 0;
716
717           dump_line_str("Config: ");
718           if(res->baud.bits) {
719             dump_line0("%u bits", res->baud.bits);
720             i++;
721           }
722           if(res->baud.parity) {
723             dump_line0("%sparity %c", i++ ? ", " : "", res->baud.parity);
724           }
725           if(res->baud.stopbits) {
726             dump_line0("%s%u stopbits", i++ ? ", " : "", res->baud.stopbits);
727           }
728           if(res->baud.handshake) {
729             dump_line0("%shandshake %c", i++ ? ", " : "", res->baud.handshake);
730           }
731           dump_line0("\n");
732         }
733         break;
734
735       case res_init_strings:
736         if(res->init_strings.init1) dump_line("Init1: %s\n", res->init_strings.init1);
737         if(res->init_strings.init2) dump_line("Init2: %s\n", res->init_strings.init2);
738         break;
739
740       case res_pppd_option:
741         dump_line("PPPD Option: %s\n", res->pppd_option.option);
742         break;
743
744       case res_framebuffer:
745         dump_line("Mode 0x%04x: %ux%u (+%u), %u bits\n",
746           res->framebuffer.mode,
747           res->framebuffer.width,
748           res->framebuffer.height,
749           res->framebuffer.bytes_p_line,
750           res->framebuffer.colorbits
751         );
752         break;
753
754       case res_hwaddr:
755         dump_line("HW Address: %s\n", res->hwaddr.addr);
756         break;
757
758       case res_link:
759         dump_line("Link detected: %s\n", res->link.state ? "yes" : "no");
760         break;
761
762       case res_wlan:
763         if(res->wlan.channels) {
764                 str_list_t *ptr = res->wlan.channels;
765                 dump_line("WLAN channels: %s", ptr->str);
766                 while((ptr=ptr->next)) dump_line0(" %s", ptr->str);
767                 dump_line0("\n");
768         }
769         if(res->wlan.frequencies) {
770                 str_list_t *ptr = res->wlan.frequencies;
771                 dump_line("WLAN frequencies: %s", ptr->str);
772                 while((ptr=ptr->next)) dump_line0(" %s", ptr->str);
773                 dump_line0("\n");
774         }
775         if(res->wlan.bitrates) {
776                 str_list_t *ptr = res->wlan.bitrates;
777                 dump_line("WLAN bitrates: %s", ptr->str);
778                 while((ptr=ptr->next)) dump_line0(" %s", ptr->str);
779                 dump_line0("\n");
780         }
781         if(res->wlan.enc_modes) {
782                 str_list_t *ptr = res->wlan.enc_modes;
783                 dump_line("WLAN encryption modes: %s", ptr->str);
784                 while((ptr=ptr->next)) dump_line0(" %s", ptr->str);
785                 dump_line0("\n");
786         }
787         if(res->wlan.auth_modes) {
788                 str_list_t *ptr = res->wlan.auth_modes;
789                 dump_line("WLAN authentication modes: %s", ptr->str);
790                 while((ptr=ptr->next)) dump_line0(" %s", ptr->str);
791                 dump_line0("\n");
792         }
793         break;
794
795
796       default:
797         dump_line("Unknown resource type %d\n", res->any.type);
798     }
799   }
800
801   if((sl = h->requires)) {
802     dump_line("Requires: %s", sl->str);
803     for(sl = sl->next; sl; sl = sl->next) {
804       dump_line0(", %s", sl->str);
805     }
806     dump_line0("\n");
807   }
808
809   if(h->modalias) {
810     dump_line("Module Alias: \"%s\"\n", h->modalias);
811   }
812
813   for(di = h->driver_info, i = 0; di; di = di->next, i++) {
814     dump_line("Driver Info #%d:\n", i);
815     ind += 2;
816     switch(di->any.type) {
817       case di_any:
818         dump_line_str("Driver Info:");
819         for(sl = di->any.hddb0, j = 0; sl; sl = sl->next, j++) {
820           dump_line0("%c%s", j ? ',' : ' ', sl->str);
821         }
822         dump_line0("\n");
823         break;
824
825       case di_display:
826         if(di->display.width)
827           dump_line("Max. Resolution: %ux%u\n", di->display.width, di->display.height);
828         if(di->display.min_vsync)
829            dump_line("Vert. Sync Range: %u-%u Hz\n", di->display.min_vsync, di->display.max_vsync);
830         if(di->display.min_hsync)
831            dump_line("Hor. Sync Range: %u-%u kHz\n", di->display.min_hsync, di->display.max_hsync);
832         if(di->display.bandwidth)
833            dump_line("Bandwidth: %u MHz\n", di->display.bandwidth);
834         break;
835
836       case di_module:
837         dump_line_str("Driver Status: ");
838         for(sl1 = di->module.names; sl1; sl1 = sl1->next) {
839           dump_line0("%s%c", sl1->str, sl1->next ? ',' : ' ');
840         }
841         dump_line0("%s %sactive\n",
842           di->module.names->next ? "are" : "is",
843           di->module.active ? "" : "not "
844         );
845
846         dump_line_str("Driver Activation Cmd: \"");
847         for(sl1 = di->module.names, sl2 = di->module.mod_args; sl1 && sl2; sl1 = sl1->next, sl2 = sl2->next) {
848           dump_line0("%s %s%s%s%s",
849             di->module.modprobe ? "modprobe" : "insmod",
850             sl1->str,
851             sl2->str ? " " : "",
852             sl2->str ? sl2->str : "",
853             (sl1->next && sl2->next) ? "; " : ""
854           );
855         }
856
857         dump_line0("\"\n");
858
859         if(di->module.conf) {
860           char *s = di->module.conf;
861
862           dump_line_str("Driver \"modules.conf\" Entry: \"");
863           for(; *s; s++) {
864             if(isprint(*s)) {
865               dump_line0("%c", *s);
866             }
867             else {
868               switch(*s) {
869                 case '\n': dump_line0("\\n"); break;
870                 case '\r': dump_line0("\\r"); break;
871                 case '\t': dump_line0("\t"); break;     /* *no* typo! */
872                 default: dump_line0("\\%03o", *s); 
873               }
874             }
875           }
876           dump_line0("\"\n");
877         }
878       break;
879
880       case di_mouse:
881         if(di->mouse.buttons >= 0) dump_line("Buttons: %d\n", di->mouse.buttons);
882         if(di->mouse.wheels >= 0) dump_line("Wheels: %d\n", di->mouse.wheels);
883         if(di->mouse.xf86) dump_line("XFree86 Protocol: %s\n", di->mouse.xf86);
884         if(di->mouse.gpm) dump_line("GPM Protocol: %s\n", di->mouse.gpm);
885         break;
886
887       case di_x11:
888         if(di->x11.server) {
889           dump_line(
890             "XFree86 v%s Server%s: %s\n",
891             di->x11.xf86_ver, strcmp(di->x11.xf86_ver, "4") ? "" : " Module", di->x11.server
892           );
893         }
894         if(di->x11.x3d) dump_line_str("3D Support: yes\n");
895         if(di->x11.script) dump_line("3D Script: %s\n", di->x11.script);
896         if(di->x11.colors.all) {
897           dump_line_str("Color Depths: ");
898           j = 0;
899           if(di->x11.colors.c8) { dump_line0("8"); j++; }
900           if(di->x11.colors.c15) { if(j) dump_line0(", "); dump_line0("15"); j++; }
901           if(di->x11.colors.c16) { if(j) dump_line0(", "); dump_line0("16"); j++; }
902           if(di->x11.colors.c24) { if(j) dump_line0(", "); dump_line0("24"); j++; }
903           if(di->x11.colors.c32) { if(j) dump_line0(", "); dump_line0("32"); j++; }
904           dump_line0("\n");
905         }
906         if(di->x11.dacspeed) dump_line("Max. DAC Clock: %u MHz\n", di->x11.dacspeed);
907         if(di->x11.extensions) {
908           dump_line("Extensions: %s", di->x11.extensions->str);
909           for(sl = di->x11.extensions->next; sl; sl = sl->next) {
910             dump_line0(", %s", sl->str);
911           }
912           dump_line0("\n");
913         }
914         if(di->x11.options) {
915           dump_line("Options: %s", di->x11.options->str);
916           for(sl = di->x11.options->next; sl; sl = sl->next) {
917             dump_line0(", %s", sl->str);
918           }
919           dump_line0("\n");
920         }
921         if(di->x11.raw) {
922           dump_line("XF86Config Entry: %s", di->x11.raw->str);
923           for(sl = di->x11.raw->next; sl; sl = sl->next) {
924             dump_line0("\\n%s", sl->str);
925           }
926           dump_line0("\n");
927         }
928         break;
929
930       case di_isdn:
931         dump_line(
932           "I4L Type: %d/%d [%s]\n",
933           di->isdn.i4l_type, di->isdn.i4l_subtype, di->isdn.i4l_name
934         );
935         if((ip = di->isdn.params)) {
936           int k, l;
937
938           dump_line_str("Parameter:\n");
939           for(k = 0; ip; ip = ip->next, k++) {
940             dump_line(
941               "  %d%s: (0x%x/%02x): %s = 0x%"PRIx64,
942               k, ip->conflict ? "(conflict)" : ip->valid ? "" : "(invalid)",
943               ip->type, ip->flags >> 8, ip->name, ip->value
944             );
945             if(ip->alt_values) {
946               for(l = 0; l < ip->alt_values; l++) {
947                 dump_line0(
948                   "%s%s0x%x", l ? "," : " [",
949                   ip->alt_value[l] == ip->def_value ? "*" : "",
950                   ip->alt_value[l]
951                 );
952               }
953               dump_line0("]");
954             }
955             dump_line0("\n");
956           }
957         }
958         break;
959
960       case di_dsl:
961         dump_line(
962           "DSL Mode: %s\n",
963           di->dsl.mode
964         );
965         dump_line(
966           "Driver: %s\n",
967           di->dsl.name
968         );
969         break;
970
971       case di_kbd:
972         if(di->kbd.XkbRules) dump_line("XkbRules: %s\n", di->kbd.XkbRules);
973         if(di->kbd.XkbModel) dump_line("XkbModel: %s\n", di->kbd.XkbModel);
974         if(di->kbd.XkbLayout) dump_line("XkbLayout: %s\n", di->kbd.XkbLayout);
975         if(di->kbd.keymap) dump_line("keymap: %s\n", di->kbd.keymap);
976         break;
977
978       default:
979         dump_line_str("Driver Status: unknown driver info format\n");
980     }
981
982     if((hd_data->debug & HD_DEB_DRIVER_INFO)) {
983       for(sl = di->any.hddb0, j = 0; sl; sl = sl->next, j++) {
984         if(j) {
985           dump_line0("|%s", sl->str);
986         }
987         else {
988           dump_line("Driver DB0: %d, %s", di->any.type, sl->str);
989         }
990       }
991       if(di->any.hddb0) dump_line0("\n");
992
993       for(sl = di->any.hddb1, j = 0; sl; sl = sl->next, j++) {
994         if(!j) dump_line_str("Driver DB1: \"");
995         dump_line0("%s\\n", sl->str);
996       }
997       if(di->any.hddb1) dump_line0("\"\n");
998     }
999
1000     ind -= 2;
1001   }
1002 }
1003
1004 /*
1005  * print CPU entries
1006  */
1007 void dump_cpu(hd_data_t *hd_data, hd_t *hd, FILE *f)
1008 {
1009   cpu_info_t *ct;
1010   str_list_t *sl;
1011
1012   if(!hd->detail || hd->detail->type != hd_detail_cpu) return;
1013   if(!(ct = hd->detail->cpu.data)) return;
1014
1015   dump_line0 ("  Arch: ");
1016   switch (ct->architecture) {
1017       case arch_intel:
1018         dump_line0 ("Intel\n");
1019         break;
1020       case arch_alpha:
1021         dump_line0 ("Alpha\n");
1022         break;
1023       case arch_sparc:
1024         dump_line0 ("Sparc (32)\n");
1025         break;
1026       case arch_sparc64:
1027         dump_line0 ("UltraSparc (64)\n");
1028         break;
1029       case arch_ppc:
1030         dump_line0 ("PowerPC\n");
1031         break;
1032       case arch_ppc64:
1033         dump_line0 ("PowerPC (64)\n");
1034         break;
1035       case arch_68k:
1036         dump_line0 ("68k\n");
1037         break;
1038       case arch_ia64:
1039         dump_line0 ("IA-64\n");
1040         break;
1041       case arch_s390:
1042         dump_line0 ("S390\n");
1043         break;
1044       case arch_s390x:
1045         dump_line0 ("S390x\n");
1046         break;
1047       case arch_arm:
1048         dump_line0 ("ARM\n");
1049         break;
1050       case arch_mips:
1051         dump_line0 ("MIPS\n");
1052         break;
1053       case arch_x86_64:
1054         dump_line0 ("X86-64\n");
1055         break;
1056       default:
1057         dump_line0 ("**UNKNWON**\n");
1058         break;
1059   }
1060
1061   if(ct->vend_name) dump_line("Vendor: \"%s\"\n", ct->vend_name);
1062  
1063   if(ct->model_name)
1064     dump_line(
1065       "Model: %u.%u.%u \"%s\"\n",
1066       ct->family, ct->model, ct->stepping, ct->model_name
1067     );
1068
1069   if(ct->platform) dump_line("Platform: \"%s\"\n", ct->platform);
1070
1071   if(ct->features) {
1072     dump_line("Features: %s", ct->features->str);
1073     for(sl = ct->features->next; sl; sl = sl->next) {
1074       dump_line0(",%s", sl->str);
1075     }
1076     dump_line0("\n");
1077   }
1078
1079   if(ct->clock) dump_line("Clock: %u MHz\n", ct->clock);
1080   if(ct->bogo) dump_line("BogoMips: %.2f\n", ct->bogo);
1081   if(ct->cache) dump_line("Cache: %u kb\n", ct->cache);
1082   if(ct->units) dump_line("Units/Processor: %u\n", ct->units);
1083 }
1084
1085
1086 /*
1087  * print BIOS entries
1088  */
1089 void dump_bios(hd_data_t *hd_data, hd_t *hd, FILE *f)
1090 {
1091   bios_info_t *bt;
1092
1093   if(!hd->detail || hd->detail->type != hd_detail_bios) return;
1094   if(!(bt = hd->detail->bios.data)) return;
1095
1096   if(bt->vbe_ver) {
1097     dump_line("VESA BIOS Version: %u.%u\n", bt->vbe_ver >> 8, bt->vbe_ver & 0xff);
1098   }
1099
1100   if(bt->vbe_video_mem) {
1101     dump_line("Video Memory: %u kb\n", bt->vbe_video_mem >> 10);
1102   }
1103
1104   if(bt->vbe.ok && bt->vbe.current_mode) {
1105     dump_line("Current VESA Mode: 0x%04x\n", bt->vbe.current_mode);
1106   }
1107
1108   if(bt->apm_supported) {
1109     dump_line("APM Version: %u.%u\n", bt->apm_ver, bt->apm_subver);
1110     dump_line("APM Status: %s\n", bt->apm_enabled ? "on" : "off");
1111     dump_line("APM BIOS Flags: 0x%x\n", bt->apm_bios_flags);
1112   }
1113
1114   if(bt->led.ok) {
1115     dump_line_str("BIOS Keyboard LED Status:\n");
1116     dump_line("  Scroll Lock: %s\n", bt->led.scroll_lock ? "on" : "off");
1117     dump_line("  Num Lock: %s\n", bt->led.num_lock ? "on" : "off");
1118     dump_line("  Caps Lock: %s\n", bt->led.caps_lock ? "on" : "off");
1119   }
1120
1121   if(bt->ser_port0) dump_line("Serial Port 0: 0x%x\n", bt->ser_port0);
1122   if(bt->ser_port1) dump_line("Serial Port 1: 0x%x\n", bt->ser_port1);
1123   if(bt->ser_port2) dump_line("Serial Port 2: 0x%x\n", bt->ser_port2);
1124   if(bt->ser_port3) dump_line("Serial Port 3: 0x%x\n", bt->ser_port3);
1125
1126   if(bt->par_port0) dump_line("Parallel Port 0: 0x%x\n", bt->par_port0);
1127   if(bt->par_port1) dump_line("Parallel Port 1: 0x%x\n", bt->par_port1);
1128   if(bt->par_port2) dump_line("Parallel Port 2: 0x%x\n", bt->par_port2);
1129
1130   if(bt->low_mem_size) dump_line("Base Memory: %u kB\n", bt->low_mem_size >> 10);
1131
1132   if(bt->is_pnp_bios) {
1133     char *s = isa_id2str(bt->pnp_id);
1134     dump_line("PnP BIOS: %s\n", s);
1135     free_mem(s);
1136   }
1137
1138   if(bt->lba_support) {
1139     dump_line_str("BIOS: extended read supported\n");
1140   }
1141
1142   if(bt->smp.ok) {
1143     dump_line("MP spec rev 1.%u info:\n", bt->smp.rev);
1144     dump_line("  OEM id: \"%s\"\n",  bt->smp.oem_id);
1145     dump_line("  Product id: \"%s\"\n",  bt->smp.prod_id);
1146     dump_line("  %u CPUs (%u disabled)\n",  bt->smp.cpus, bt->smp.cpus - bt->smp.cpus_en);
1147   }
1148
1149   if(bt->bios32.ok) {
1150     dump_line("BIOS32 Service Directory Entry: 0x%05x\n", bt->bios32.entry);
1151   }
1152
1153   if(bt->smbios_ver) {
1154     dump_line("SMBIOS Version: %u.%u\n", bt->smbios_ver >> 8, bt->smbios_ver & 0xff);
1155   }
1156
1157   smbios_dump(hd_data, f);
1158 }
1159
1160
1161 /*
1162  * print PROM entries
1163  */
1164 void dump_prom(hd_data_t *hd_data, hd_t *hd, FILE *f)
1165 {
1166   prom_info_t *pt;
1167   char *s;
1168
1169   if(!hd->detail || hd->detail->type != hd_detail_prom) return;
1170   if(!(pt = hd->detail->prom.data)) return;
1171
1172   if(pt->has_color) {
1173     // ###########################
1174     // s = hd_device_name(hd_data, MAKE_ID(TAG_SPECIAL, 0x0300), MAKE_ID(TAG_SPECIAL, pt->color));
1175     s = NULL;
1176     if(s)
1177       dump_line("Color: %s (0x%02x)\n", s, pt->color);
1178     else
1179       dump_line("Color: 0x%02x\n", pt->color);
1180   }
1181 }
1182
1183
1184 /*
1185  * print System entries
1186  */
1187 void dump_sys(hd_data_t *hd_data, hd_t *hd, FILE *f)
1188 {
1189   sys_info_t *st;
1190
1191   if(!hd->detail || hd->detail->type != hd_detail_sys) return;
1192   if(!(st = hd->detail->sys.data)) return;
1193
1194   if(st->system_type) {
1195     dump_line("SystemType: \"%s\"\n", st->system_type);
1196   }
1197
1198   if(st->generation) {
1199     dump_line("Generation: \"%s\"\n", st->generation);
1200   }
1201
1202   if(st->formfactor) {
1203     dump_line("Formfactor: \"%s\"\n", st->formfactor);
1204   }
1205
1206   if(st->lang) {
1207     dump_line("Language: \"%s\"\n", st->lang);
1208   }
1209 }
1210
1211
1212 char *dump_hid(hd_data_t *hd_data, hd_id_t *hid, int format, char *buf, int buf_size)
1213 {
1214   char *s;
1215   int i;
1216   unsigned t, id;
1217
1218   *buf = 0;
1219
1220   if(hid->id) {
1221     t = ID_TAG(hid->id);
1222     id = ID_VALUE(hid->id);
1223
1224     if(format && t == TAG_EISA) {
1225       snprintf(buf, buf_size - 1, "%s", eisa_vendor_str(id));
1226     }
1227     else {
1228       snprintf(buf, buf_size - 1, "%s0x%04x", hid_tag_name2(t), id);
1229     }
1230   }
1231
1232   i = strlen(buf);
1233   if(i) {
1234     buf[i++] = ' ';
1235     buf[i] = 0;
1236   }
1237   s = buf + i;
1238   buf_size -= i;
1239
1240   if(!buf_size) return buf;
1241
1242   if(hid->name) {
1243     snprintf(s, buf_size - 1, "\"%s\"", hid->name);
1244   }
1245
1246   return buf;
1247 }
1248
1249 char *dump_hid2(hd_data_t *hd_data, hd_id_t *hid1, hd_id_t *hid2, char *buf, int buf_size)
1250 {
1251   char *s;
1252   int i;
1253   unsigned t, id1, id2;
1254
1255   *buf = 0;
1256
1257   t = 0;
1258   if(hid1->id) t = ID_TAG(hid1->id);
1259   if(hid2->id) t = ID_TAG(hid2->id);
1260
1261   id1 = ID_VALUE(hid1->id);
1262   id2 = ID_VALUE(hid2->id);
1263
1264   if(hid1->id || hid2->id) {
1265     if(t == TAG_EISA) {
1266       snprintf(buf, buf_size - 1, "%s 0x%04x", eisa_vendor_str(id1), id2);
1267     }
1268     else {
1269       snprintf(buf, buf_size - 1, "%s0x%04x 0x%04x", hid_tag_name2(t), id1, id2);
1270     }
1271   }
1272
1273   i = strlen(buf);
1274   s = buf + i;
1275   buf_size -= i;
1276
1277   if(!buf_size) return buf;
1278
1279   if(hid2->name) {
1280     snprintf(s, buf_size - 1, " \"%s\"", hid2->name);
1281   }
1282
1283   return buf;
1284 }
1285
1286
1287 char *print_dev_num(hd_dev_num_t *d)
1288 {
1289   static char *buf = NULL;
1290
1291   if(d->type) {
1292     str_printf(&buf, 0, "%s %u:%u",
1293       d->type == 'b' ? "block" : "char",
1294       d->major, d->minor
1295     );
1296     if(d->range > 1) {
1297       str_printf(&buf, -1, "-%u:%u",
1298         d->major, d->minor + d->range - 1
1299       );
1300     }
1301   }
1302   else {
1303     str_printf(&buf, 0, "%s", "");
1304   }
1305
1306   return buf;
1307 }
1308
1309
1310 #else   /* ifndef LIBHD_TINY */
1311
1312 void hd_dump_entry(hd_data_t *hd_data, hd_t *h, FILE *f) { }
1313
1314 #endif  /* ifndef LIBHD_TINY */
1315
1316 /** @} */
1317