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