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