- parse id files in /var/lib/hardware/ids
[opensuse:hwinfo.git] / src / hd / hddb.c
1 #define _GNU_SOURCE     /* asprintf */
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <ctype.h>
7 #include <fnmatch.h>
8 #include <sys/utsname.h>
9
10 #include "hd.h"
11 #include "hd_int.h"
12 #include "hddb.h"
13 #include "isdn.h"
14 #include "hddb_int.h"
15
16 /**
17  * @defgroup HDDBint Hardware DB (HDDB)
18  * @ingroup libhdInternals
19  * @brief Hardware DB functions
20  *
21  * @{
22  */
23
24 extern hddb2_data_t hddb_internal;
25
26 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
27 // #define HDDB_TRACE
28 // #define HDDB_TEST
29 // #define HDDB_EXTERNAL_ONLY
30
31 static char *hid_tag_names[] = { "", "pci ", "eisa ", "usb ", "special ", "pcmcia " };
32 // just experimenting...
33 static char *hid_tag_names2[] = { "", "pci ", "eisa ", "usb ", "int ", "pcmcia " };
34
35 typedef enum {
36   pref_empty, pref_new, pref_and, pref_or, pref_add
37 } prefix_t;
38
39 typedef struct line_s {
40   prefix_t prefix;
41   hddb_entry_t key;
42   char *value;
43   char *raw;
44 } line_t;
45
46 typedef struct {
47   int len;
48   unsigned val[32];     /**< arbitrary (approx. max. number of modules/xf86 config lines) */
49 } tmp_entry_t;
50
51 /**
52  * Hardware DB search struct.
53  * @note except for driver, all strings are static and _must not_ be freed
54  */
55 typedef struct {
56   hddb_entry_mask_t key;
57   hddb_entry_mask_t value;
58   hddb_entry_mask_t value_mask[he_nomask];
59   hd_id_t bus;
60   hd_id_t base_class;
61   hd_id_t sub_class;
62   hd_id_t prog_if;
63   hd_id_t vendor;
64   hd_id_t device;
65   hd_id_t sub_vendor;
66   hd_id_t sub_device;
67   hd_id_t revision;
68   hd_id_t cu_model;
69   char *serial;
70   str_list_t *driver;
71   char *requires;
72   unsigned hwclass;
73 } hddb_search_t;
74
75 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
76 static void hddb_init_pci(hd_data_t *hd_data);
77 static char *get_mi_field(char *str, char *tag, int field_len, unsigned *value, unsigned *has_value);
78 static modinfo_t *parse_modinfo(str_list_t *file);
79 static driver_info_t *hd_modinfo_db(hd_data_t *hd_data, modinfo_t *modinfo_db, hd_t *hd, driver_info_t *drv_info);
80 static int cmp_dir_entry_s(const void *p0, const void *p1);
81 static void hddb_init_external(hd_data_t *hd_data);
82
83 static line_t *parse_line(char *str);
84 static unsigned store_string(hddb2_data_t *x, char *str);
85 static unsigned store_list(hddb2_data_t *x, hddb_list_t *list);
86 static unsigned store_value(hddb2_data_t *x, unsigned val);
87 static unsigned store_entry(hddb2_data_t *x, tmp_entry_t *te);
88 static void clear_entry(tmp_entry_t *te);
89 static void add_value(tmp_entry_t *te, hddb_entry_t idx, unsigned val);
90 static hddb_entry_mask_t add_entry(hddb2_data_t *hddb2, tmp_entry_t *te, hddb_entry_t idx, char *str);
91 static int compare_ids(hddb2_data_t *hddb, hddb_search_t *hs, hddb_entry_mask_t mask, unsigned key);
92 static void complete_ids(hddb2_data_t *hddb, hddb_search_t *hs, hddb_entry_mask_t key_mask, hddb_entry_mask_t mask, unsigned val_idx);
93 static int hddb_search(hd_data_t *hd_data, hddb_search_t *hs, int max_recursions);
94 #ifdef HDDB_TEST
95 static void test_db(hd_data_t *hd_data);
96 #endif
97 static driver_info_t *hddb_to_device_driver(hd_data_t *hd_data, hddb_search_t *hs);
98 static driver_info_t *kbd_driver(hd_data_t *hd_data, hd_t *hd);
99 static driver_info_t *monitor_driver(hd_data_t *hd_data, hd_t *hd);
100
101 #if WITH_ISDN
102 /* static int chk_free_biosmem(hd_data_t *hd_data, unsigned addr, unsigned len); */
103 /* static isdn_parm_t *new_isdn_parm(isdn_parm_t **ip); */
104 static driver_info_t *isdn_driver(hd_data_t *hd_data, hd_t *hd, cdb_isdn_card *cic);
105 static driver_info_t *dsl_driver(hd_data_t *hd_data, hd_t *hd, cdb_isdn_card *cic);
106 #endif
107
108 static hd_res_t *get_res(hd_t *h, enum resource_types t, unsigned index);
109 static driver_info_t *reorder_x11(driver_info_t *di0, char *info);
110 static void expand_driver_info(hd_data_t *hd_data, hd_t *hd);
111 static char *module_cmd(hd_t *hd, char *cmd);
112
113
114 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
115 void hddb_init_pci(hd_data_t *hd_data)
116 {
117   str_list_t *sl = NULL;
118   char *s = NULL, *r;
119   struct utsname ubuf;
120
121   if(!hd_data->modinfo) {
122     if(!uname(&ubuf)) {
123       r = getenv("LIBHD_KERNELVERSION");
124       if(!r || !*r) r = ubuf.release;
125       str_printf(&s, 0, "/lib/modules/%s/modules.alias", r);
126       sl = read_file(s, 0, 0);
127       s = free_mem(s);
128     }
129
130     hd_data->modinfo = parse_modinfo(sl);
131
132     sl = free_str_list(sl);
133   }
134
135 #if 0
136   // currently nothing
137   if(!hd_data->modinfo_ext) {
138     sl = read_file("/WHATEVER", 0, 0);
139     hd_data->modinfo_ext = parse_modinfo(sl);
140     sl = free_str_list(sl);
141   }
142 #endif
143 }
144
145
146 char *get_mi_field(char *str, char *tag, int field_len, unsigned *value, unsigned *has_value)
147 {
148   int i, j;
149
150   i = strlen(tag);
151
152   if(strncmp(str, tag, i)) return NULL;
153   str += i;
154
155   if(*str == '*') {
156     str++;
157     *value = 0;
158     *has_value = 0;
159   }
160   else {
161     i = sscanf(str, "%8x%n", value, &j);
162     if(i < 1) return NULL;
163     *has_value = 1;
164     str += j;
165   }
166
167   return str;
168 }
169
170
171 modinfo_t *parse_modinfo(str_list_t *file)
172 {
173   str_list_t *sl;
174   unsigned len;
175   modinfo_t *modinfo, *m;
176   char *s;
177   unsigned u;
178   char alias[256], module[256];
179
180   /* length + 1! */
181   for(len = 1, sl = file; sl; sl = sl->next) len++;
182
183   modinfo = new_mem(len * sizeof *modinfo);
184
185   for(m = modinfo, sl = file; sl; sl = sl->next) {
186     if(sscanf(sl->str, "alias %255s %255s", alias, module) != 2) continue;
187
188     m->module = new_str(module);
189     m->alias = new_str(alias);
190     m->type = mi_other;
191
192     if(!strncmp(alias, "pci:", sizeof "pci:" - 1)) {
193       s = alias + sizeof "pci:" - 1;
194
195       m->type = mi_pci;
196
197       if(!(s = get_mi_field(s, "v", 8, &m->pci.vendor, &u))) continue;
198       m->pci.has.vendor = u;
199
200       if(!(s = get_mi_field(s, "d", 8, &m->pci.device, &u))) continue;
201       m->pci.has.device = u;
202
203       if(!(s = get_mi_field(s, "sv", 8, &m->pci.sub_vendor, &u))) continue;
204       m->pci.has.sub_vendor = u;
205
206       if(!(s = get_mi_field(s, "sd", 8, &m->pci.sub_device, &u))) continue;
207       m->pci.has.sub_device = u;
208
209       if(!(s = get_mi_field(s, "bc", 2, &m->pci.base_class, &u))) continue;
210       m->pci.has.base_class = u;
211
212       if(!(s = get_mi_field(s, "sc", 2, &m->pci.sub_class, &u))) continue;
213       m->pci.has.sub_class = u;
214
215       if(!(s = get_mi_field(s, "i", 2, &m->pci.prog_if, &u))) continue;
216       m->pci.has.prog_if = u;
217     }
218
219     m++;
220   }
221
222   /* note: list stops at first entry with m->type == mi_none */
223
224 #if 0
225   fprintf(stderr, "---  modinfo  ---\n");
226   for(m = modinfo; m->type; m++) {
227     switch(m->type) {
228       case mi_pci:
229         fprintf(stderr, "%s: %s\n  v 0x%x:%u, d 0x%x:%u, sv 0x%x:%u, sd 0x%x:%u, bc 0x%x:%u, sc 0x%x:%u, i 0x%x:%u\n",
230           m->module, m->alias,
231           m->pci.vendor, m->pci.has.vendor,
232           m->pci.device, m->pci.has.device,
233           m->pci.sub_vendor, m->pci.has.sub_vendor,
234           m->pci.sub_device, m->pci.has.sub_device,
235           m->pci.base_class, m->pci.has.base_class,
236           m->pci.sub_class, m->pci.has.sub_class,
237           m->pci.prog_if, m->pci.has.prog_if
238         );
239         break;
240
241       case mi_other:
242         fprintf(stderr, "%s: %s\n",
243           m->module, m->alias
244         );
245         break;
246
247       case mi_none:
248         break;
249     }
250   }
251 #endif
252
253   return modinfo;
254 }
255
256
257 /**
258  *  return prio, 0: no match 
259  */
260 int match_modinfo(hd_data_t *hd_data, modinfo_t *db, modinfo_t *match)
261 {
262   int prio = 0;
263   char *s;
264
265   if(db->type != match->type) return prio;
266
267   switch(db->type) {
268     case mi_pci:
269       if(db->pci.has.base_class) {
270         if(match->pci.has.base_class && db->pci.base_class == match->pci.base_class) {
271           prio = 10;
272         }
273         else {
274           prio = 0;
275           break;
276         }
277       }
278       if(db->pci.has.sub_class) {
279         if(match->pci.has.sub_class && db->pci.sub_class == match->pci.sub_class) {
280           prio = 10;
281         }
282         else {
283           prio = 0;
284           break;
285         }
286       }
287       if(db->pci.has.prog_if) {
288         if(match->pci.has.prog_if && db->pci.prog_if == match->pci.prog_if) {
289           prio = 10;
290         }
291         else {
292           prio = 0;
293           break;
294         }
295       }
296       if(db->pci.has.vendor) {
297         if(match->pci.has.vendor && db->pci.vendor == match->pci.vendor) {
298           prio = 20;
299         }
300         else {
301           prio = 0;
302           break;
303         }
304       }
305       if(db->pci.has.device) {
306         if(match->pci.has.device && db->pci.device == match->pci.device) {
307           prio = 30;
308         }
309         else {
310           prio = 0;
311           break;
312         }
313       }
314       if(db->pci.has.sub_vendor) {
315         if(match->pci.has.sub_vendor && db->pci.sub_vendor == match->pci.sub_vendor) {
316           prio = 40;
317         }
318         else {
319           prio = 0;
320           break;
321         }
322       }
323       if(db->pci.has.sub_device) {
324         if(match->pci.has.sub_device && db->pci.sub_device == match->pci.sub_device) {
325           prio = 50;
326         }
327         else {
328           prio = 0;
329           break;
330         }
331       }
332       if(prio && db->module) {
333         if(!strncmp(db->module, "pata_", sizeof "pata_" - 1)) {
334           prio += hd_data->flags.pata ? 1 : -1;
335         }
336         if(!strcmp(db->module, "piix")) {               /* ata_piix vs. piix */
337           prio += hd_data->flags.pata ? -1 : 1;
338         }
339         if(!strcmp(db->module, "generic")) prio -= 2;
340         if(!strcmp(db->module, "sk98lin")) prio -= 1;   /* deprecate sk98lin (#298724) */
341       }
342       break;
343
344     case mi_other:
345       if(match->alias && db->alias) {
346         if(!fnmatch(db->alias, match->alias, 0)) {
347           s = strchr(db->alias, '*');
348           prio = s ? s - db->alias + 1 : strlen(db->alias) + 1;
349         }
350       }
351       break;
352
353     case mi_none:
354       return 0;
355   }
356
357   return prio;
358 }
359
360
361 driver_info_t *hd_modinfo_db(hd_data_t *hd_data, modinfo_t *modinfo_db, hd_t *hd, driver_info_t *drv_info)
362 {
363   driver_info_t **di = NULL, *di2;
364   pci_t *pci;
365   char *mod_list[16 /* arbitrary, > 0 */];
366   int mod_prio[sizeof mod_list / sizeof *mod_list];
367   int i, prio, mod_list_len;
368   modinfo_t match = { };
369
370   if(!modinfo_db) return drv_info;
371
372   match.alias = hd->modalias;
373
374   match.type = match.alias && !strncmp(match.alias, "pci:", 4) ? mi_pci : mi_other;
375   
376   if(!match.type) return drv_info;
377
378   /* don't add module info if driver info of some other type exists */
379   for(di = &drv_info; *di; di = &(*di)->next) {
380     if((*di)->any.type != di_module) return drv_info;
381   }
382
383   if(match.type == mi_pci) {
384     if(hd->vendor.id) {
385       match.pci.vendor = ID_VALUE(hd->vendor.id);
386       match.pci.has.vendor = 1;
387     }
388     if(hd->device.id) {
389       match.pci.device = ID_VALUE(hd->device.id);
390       match.pci.has.device = 1;
391     }
392     if(hd->sub_vendor.id) {
393       match.pci.sub_vendor = ID_VALUE(hd->sub_vendor.id);
394       match.pci.has.sub_vendor = 1;
395     }
396     if(hd->sub_device.id) {
397       match.pci.sub_device = ID_VALUE(hd->sub_device.id);
398       match.pci.has.sub_device = 1;
399     }
400     match.pci.base_class = hd->base_class.id;
401     match.pci.has.base_class = 1;
402     match.pci.sub_class = hd->sub_class.id;
403     match.pci.has.sub_class = 1;
404     match.pci.prog_if = hd->prog_if.id;
405     match.pci.has.prog_if = 1;
406
407     if(
408       hd->detail &&
409       hd->detail->type == hd_detail_pci &&
410       (pci = hd->detail->pci.data)
411     ) {
412       match.pci.base_class = pci->base_class;
413       match.pci.sub_class = pci->sub_class;
414       match.pci.prog_if = pci->prog_if;
415     }
416   }
417
418   for(mod_list_len = 0; modinfo_db->type; modinfo_db++) {
419     if((prio = match_modinfo(hd_data, modinfo_db, &match))) {
420       for(di2 = drv_info; di2; di2 = di2->next) {
421         if(
422           di2->any.type == di_module &&
423           di2->any.hddb0 &&
424           (
425             (
426               di2->any.hddb0->str &&
427               !hd_mod_cmp(di2->any.hddb0->str, modinfo_db->module)
428             ) ||
429             (
430               di2->any.hddb0->next &&
431               di2->any.hddb0->next->str &&
432               !hd_mod_cmp(di2->any.hddb0->next->str, modinfo_db->module)
433             )
434           )
435         ) break;
436       }
437
438       if(di2) continue;
439
440       for(i = 0; i < mod_list_len; i++) {
441         if(!strcmp(mod_list[i], modinfo_db->module)) {
442           if(prio > mod_prio[i]) mod_prio[i] = prio;
443           break;
444         }
445       }
446
447       if(i < mod_list_len) continue;
448
449       mod_prio[mod_list_len] = prio;
450       mod_list[mod_list_len++] = modinfo_db->module;
451
452       if(mod_list_len >= sizeof mod_list / sizeof *mod_list) break;
453     }
454   }
455
456   if(!mod_list_len && hd->modalias && !strchr(hd->modalias, ':')) {
457     mod_prio[mod_list_len] = 0;
458     mod_list[mod_list_len++] = hd->modalias;
459   }
460
461   for(prio = 256; prio >= 0; prio--) {
462     for(i = 0; i < mod_list_len; i++) {
463       if(mod_prio[i] == prio) {
464         *di = new_mem(sizeof **di);
465         (*di)->any.type = di_module;
466         (*di)->module.modprobe = 1;
467         add_str_list(&(*di)->any.hddb0, mod_list[i]);
468         di = &(*di)->next;
469       }
470     }
471   }
472
473   return drv_info;
474 }
475
476
477 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
478 /* wrapper for qsort */
479 int cmp_dir_entry_s(const void *p0, const void *p1)
480 {
481   str_list_t **sl0, **sl1;
482
483   sl0 = (str_list_t **) p0;
484   sl1 = (str_list_t **) p1;
485
486   return -strcmp((*sl0)->str, (*sl1)->str);     /* first files win */
487 }
488
489
490 void hddb_init(hd_data_t *hd_data)
491 {
492   hddb_init_pci(hd_data);
493   hddb_init_external(hd_data);
494
495 #ifndef HDDB_EXTERNAL_ONLY
496   hd_data->hddb2[1] = &hddb_internal;
497 #endif
498
499 #ifdef HDDB_TEST
500   test_db(hd_data);
501 #endif
502 }
503
504
505 void hddb_init_external(hd_data_t *hd_data)
506 {
507   str_list_t *sl, *sl0, *sl1, *sl2, *id_dir;
508   line_t *l;
509   unsigned l_start, l_end /* end points _past_ last element */;
510   unsigned u, ent, l_nr = 1;
511   tmp_entry_t tmp_entry[he_nomask /* _must_ be he_nomask! */];
512   hddb_entry_mask_t entry_mask = 0;
513   int state;
514   hddb_list_t dbl = {};
515   hddb2_data_t *hddb2;
516   char *s;
517
518   if(hd_data->hddb2[0]) return;
519
520   hddb2 = hd_data->hddb2[0] = new_mem(sizeof *hd_data->hddb2[0]);
521
522   sl0 = read_file(hd_get_hddb_path("hd.ids"), 0, 0);
523
524   if(sl0) ADD2LOG("id file: hd.ids\n");
525
526   id_dir = read_dir(hd_get_hddb_path("ids"), 0);
527
528   if(id_dir) {
529     id_dir = sort_str_list(id_dir, cmp_dir_entry_s);
530
531     for(sl = id_dir; sl; sl = sl->next) {
532       asprintf(&s, "ids/%s", sl->str);
533       ADD2LOG("id file: %s\n", s);
534       sl1 = sl2 = read_file(hd_get_hddb_path(s), 0, 0);
535       free(s);
536       if(sl1) {
537         while(sl1->next) sl1 = sl1->next;
538         sl1->next = sl0;
539         sl0 = sl2;
540       }
541     }
542   }
543
544   l_start = l_end = 0;
545   state = 0;
546
547   for(sl = sl0; sl; sl = sl->next, l_nr++) {
548     l = parse_line(sl->str);
549     if(!l) {
550       ADD2LOG("id line %d: invalid line\n", l_nr);
551       state = 4;
552       goto error;
553     };
554     if(l->prefix == pref_empty) continue;
555     switch(l->prefix) {
556       case pref_new:
557         if((state == 2 && !entry_mask) || state == 1) {
558           ADD2LOG("id line %d: new item not allowed\n", l_nr);
559           state = 4;
560           break;
561         }
562         if(state == 2 && entry_mask) {
563           ent = store_entry(hddb2, tmp_entry);
564           if(ent == -1u) {
565             ADD2LOG("id line %d: internal hddb oops 1\n", l_nr);
566             state = 4;
567             break;
568           }
569           if(l_end && l_end > l_start) {
570             for(u = l_start; u < l_end; u++) {
571               hddb2->list[u].value_mask = entry_mask;
572               hddb2->list[u].value = ent;
573             }
574           }
575         }
576         entry_mask = 0;
577         clear_entry(tmp_entry);
578         state = 1;
579         l_start = store_list(hddb2, &dbl);
580         l_end = l_start + 1;
581         break;
582
583       case pref_and:
584         if(state != 1) {
585           ADD2LOG("id line %d: must start item first\n", l_nr);
586           state = 4;
587           break;
588         }
589         break;
590
591       case pref_or:
592         if(state != 1 || !entry_mask || l_end <= l_start || l_end < 1) {
593           ADD2LOG("id line %d: must start item first\n", l_nr);
594           state = 4;
595           break;
596         }
597         ent = store_entry(hddb2, tmp_entry);
598         if(ent == -1u) {
599           ADD2LOG("id line %d: internal hddb oops 2\n", l_nr);
600           state = 4;
601           break;
602         }
603         hddb2->list[l_end - 1].key_mask = entry_mask;
604         hddb2->list[l_end - 1].key = ent;
605         entry_mask = 0;
606         clear_entry(tmp_entry);
607         u = store_list(hddb2, &dbl);
608         if(u != l_end) {
609           ADD2LOG("id line %d: internal hddb oops 2\n", l_nr);
610           state = 4;
611           break;
612         }
613         l_end++;
614         break;
615
616       case pref_add:
617         if(state == 1 && !entry_mask) {
618           ADD2LOG("id line %d: driver info not allowed\n", l_nr);
619           state = 4;
620           break;
621         }
622         if(state == 1 && l_end > l_start) {
623           ent = store_entry(hddb2, tmp_entry);
624           if(ent == -1u) {
625             ADD2LOG("id line %d: internal hddb oops 3\n", l_nr);
626             state = 4;
627             break;
628           }
629           hddb2->list[l_end - 1].key_mask = entry_mask;
630           hddb2->list[l_end - 1].key = ent;
631           entry_mask = 0;
632           clear_entry(tmp_entry);
633           state = 2;
634         }
635         if(state != 2 || l_end == 0) {
636           ADD2LOG("id line %d: driver info not allowed\n", l_nr);
637           state = 4;
638           break;
639         }
640         break;
641
642       default:
643         state = 4;
644     }
645
646     if(state != 4) {
647       u = add_entry(hddb2, tmp_entry, l->key, l->value);
648       if(u) {
649         entry_mask |= u;
650       }
651       else {
652         ADD2LOG("id line %d: invalid info\n", l_nr);
653         state = 4;
654       }
655     }
656
657     error:
658
659     if(state == 4) {    /* error */
660       state = 0;
661       u = 10;   /* log max 10 lines context */
662       while(sl->next && *sl->str != '\n') {
663         if(u) {
664           ADD2LOG("  %s", sl->str);
665           u--;
666         }
667         sl = sl->next;
668       }
669     }
670   }
671
672   /* finalize last item */
673   if(state == 2 && entry_mask) {
674     ent = store_entry(hddb2, tmp_entry);
675     if(ent == -1u) {
676       ADD2LOG("id line %d: internal hddb oops 4\n", l_nr);
677       state = 4;
678     }
679     else if(l_end && l_end > l_start) {
680       for(u = l_start; u < l_end; u++) {
681         hddb2->list[u].value_mask = entry_mask;
682         hddb2->list[u].value = ent;
683       }
684     }
685   }
686
687   sl0 = free_str_list(sl0);
688
689   if(state == 4) {
690     /* there was an error */
691
692     free_mem(hddb2->list);
693     free_mem(hddb2->ids);
694     free_mem(hddb2->strings);
695     hd_data->hddb2[0] = free_mem(hd_data->hddb2[0]);
696   }
697 }
698
699
700 line_t *parse_line(char *str)
701 {
702   static line_t l;
703   char *s;
704   int i;
705
706   free_mem(l.raw);
707   str = l.raw = new_str(str);
708
709   /* drop leading spaces */
710   while(isspace(*str)) str++;
711
712   /* skip emtpy lines and comments */
713   if(!*str || *str == ';' || *str == '#') {
714     l.prefix = pref_empty;
715     return &l;
716   }
717
718   l.prefix = pref_new;
719
720   switch(*str) {
721     case '&':
722       l.prefix = pref_and;
723       str++;
724       break;
725
726     case '|':
727       l.prefix = pref_or;
728       str++;
729       break;
730
731     case '+':
732       l.prefix = pref_add;
733       str++;
734       break;
735   }
736
737   /* skip spaces */
738   while(isspace(*str)) str++;
739
740   s = str;
741   while(*str && !isspace(*str)) str++;
742   if(*str) *str++ = 0;
743   while(isspace(*str)) str++;
744
745   for(i = 0; (unsigned) i < sizeof hddb_entry_strings / sizeof *hddb_entry_strings; i++) {
746     if(!strcmp(s, hddb_entry_strings[i])) {
747       l.key = i;
748       break;
749     }
750   }
751
752   if((unsigned) i >= sizeof hddb_entry_strings / sizeof *hddb_entry_strings) return NULL;
753
754   l.value = str;
755
756   /* drop trailing white space */
757   i = strlen(str);
758   while(i > 0) {
759     if(isspace(str[i - 1]))
760       str[--i] = 0;
761     else
762       break;
763   }
764
765   /* special case: drop leading and final double quotes, if any */
766   i = strlen(l.value);
767   if(i >= 2 && l.value[0] == '"' && l.value[i - 1] == '"') {
768     l.value[i - 1] = 0;
769     l.value++;
770   }
771
772   // fprintf(stderr, "pre = %d, key = %d, val = \"%s\"\n", l.prefix, l.key, l.value);
773
774   return &l;
775 }
776
777
778 unsigned store_string(hddb2_data_t *x, char *str)
779 {
780   unsigned l = strlen(str), u;
781
782   if(x->strings_len + l >= x->strings_max) {
783     x->strings_max += l + 0x1000;         /* >4k steps */
784     x->strings = resize_mem(x->strings, x->strings_max * sizeof *x->strings);
785   }
786
787   /* make sure the 1st byte is 0 */
788   if(x->strings_len == 0) {
789     *x->strings = 0;    /* resize_mem does _not_ clear memory */
790     x->strings_len = 1;
791   }
792
793   if(l == 0) return 0;          /* 1st byte is always 0 */
794
795   strcpy(x->strings + (u = x->strings_len), str);
796   x->strings_len += l + 1;
797
798   return u;
799 }
800
801
802 unsigned store_list(hddb2_data_t *x, hddb_list_t *list)
803 {
804   if(x->list_len == x->list_max) {
805     x->list_max += 0x100;       /* 4k steps */
806     x->list = resize_mem(x->list, x->list_max * sizeof *x->list);
807   }
808
809   x->list[x->list_len++] = *list;
810
811   return x->list_len - 1;
812 }
813
814
815 unsigned store_value(hddb2_data_t *x, unsigned val)
816 {
817   if(x->ids_len == x->ids_max) {
818     x->ids_max += 0x400;        /* 4k steps */
819     x->ids = resize_mem(x->ids, x->ids_max * sizeof *x->ids);
820   }
821
822   x->ids[x->ids_len++] = val;
823
824   return x->ids_len - 1;
825 }
826
827
828 /* returns index in hddb2->ids */
829 unsigned store_entry(hddb2_data_t *x, tmp_entry_t *te)
830 {
831   int i, j;
832   unsigned ent = -1, u, v;
833
834   for(i = 0; i < he_nomask; i++) {
835     if(te[i].len) {
836       for(j = 0; j < te[i].len; j++) {
837         v = te[i].val[j] | (1 << 31);
838         if(j == te[i].len - 1) v &= ~(1 << 31);
839         u = store_value(x, v);
840         if(ent == -1u) ent = u;
841       }
842     }
843   }
844
845   return ent;
846 }
847
848 void clear_entry(tmp_entry_t *te)
849 {
850   memset(te, 0, he_nomask * sizeof *te);
851 }
852
853 void add_value(tmp_entry_t *te, hddb_entry_t idx, unsigned val)
854 {
855   if(idx >= he_nomask) return;
856   te += idx;
857
858   if((unsigned) te->len >= sizeof te->val / sizeof *te->val) return;
859
860   te->val[te->len++] = val;
861 }
862
863 int parse_id(char *str, unsigned *id, unsigned *range, unsigned *mask)
864 {
865   static unsigned id0, val;
866   unsigned tag = 0;
867   char c = 0, *s, *t = NULL;
868
869   *id = *range = *mask = 0;
870
871   if(!str || !*str) return 0;
872   
873   for(s = str; *str && !isspace(*str); str++);
874   if(*str) {
875     c = *(t = str);     /* remember for later */
876     *str++ = 0;
877   }
878   while(isspace(*str)) str++;
879
880   if(*s) {
881     if(!strcmp(s, "pci")) tag = TAG_PCI;
882     else if(!strcmp(s, "usb")) tag = TAG_USB;
883     else if(!strcmp(s, "special")) tag = TAG_SPECIAL;
884     else if(!strcmp(s, "eisa")) tag = TAG_EISA;
885     else if(!strcmp(s, "isapnp")) tag = TAG_EISA;
886     else if(!strcmp(s, "pcmcia")) tag = TAG_PCMCIA;
887     else {
888       str = s;
889       if(t) *t = c;     /* restore */
890     }
891   }
892
893   id0 = strtoul(str, &s, 0);
894
895   if(s == str) {
896     id0 = name2eisa_id(str);
897     if(!id0) return 0;
898     s = str + 3;
899     id0 = ID_VALUE(id0);
900     if(!tag) tag = TAG_EISA;
901   }
902
903   while(isspace(*s)) s++;
904   if(*s && *s != '&' && *s != '+') return 0;
905
906   *id = MAKE_ID(tag, id0);
907
908   if(!*s) return 1;
909
910   c = *s++;
911
912   while(isspace(*s)) s++;
913
914   val = strtoul(s, &str, 0);
915
916   if(s == str) return 0;
917
918   while(isspace(*str)) str++;
919
920   if(*str) return 0;
921
922   if(c == '+') *range = val; else *mask = val;
923
924   return c == '+' ? 2 : 3;
925 }
926
927
928 hddb_entry_mask_t add_entry(hddb2_data_t *hddb2, tmp_entry_t *te, hddb_entry_t idx, char *str)
929 {
930   hddb_entry_mask_t mask = 0;
931   int i;
932   unsigned u, u0, u1, u2;
933   char *s, c;
934   str_list_t *sl, *sl0;
935
936   for(i = 0; (unsigned) i < sizeof hddb_is_numeric / sizeof *hddb_is_numeric; i++) {
937     if(idx == hddb_is_numeric[i]) break;
938   }
939
940   if((unsigned) i < sizeof hddb_is_numeric / sizeof *hddb_is_numeric) {
941     /* numeric id */
942     mask |= 1 << idx;
943
944     /* special */
945     if(idx == he_hwclass) {
946       sl0 = hd_split('|', str);
947       for(u0 = u1 = 0, sl = sl0; sl && u1 <= 16; sl = sl->next) {
948         u = hd_hw_item_type(sl->str);
949         if(u) {
950           u0 += u << u1;
951           u1 += 8;
952         }
953       }
954       free_str_list(sl0);
955
956       i = 1;
957     }
958     else {
959       i = parse_id(str, &u0, &u1, &u2);
960     }
961
962     switch(i) {
963       case 1:
964         add_value(te, idx, MAKE_DATA(FLAG_ID, u0));
965         break;
966
967       case 2:
968         add_value(te, idx, MAKE_DATA(FLAG_RANGE, u1));
969         add_value(te, idx, MAKE_DATA(FLAG_ID, u0));
970         break;
971
972       case 3:
973         add_value(te, idx, MAKE_DATA(FLAG_MASK, u2));
974         add_value(te, idx, MAKE_DATA(FLAG_ID, u0));
975         break;
976
977       default:
978         return 0;
979     }
980   }
981   else {
982     if(idx < he_nomask) {
983       /* strings */
984
985       mask |= 1 << idx;
986       u = store_string(hddb2, str);
987       // fprintf(stderr, ">>> %s\n", str);
988       add_value(te, idx, MAKE_DATA(FLAG_STRING, u));
989     }
990     else {
991       /* special */
992
993       if(idx == he_class_id) {
994         i = parse_id(str, &u0, &u1, &u2);
995         if(i != 1) return 0;
996         u = ID_VALUE(u0) >> 8;
997         add_value(te, he_baseclass_id, MAKE_DATA(FLAG_ID, u));
998         u = u0 & 0xff;
999         add_value(te, he_subclass_id, MAKE_DATA(FLAG_ID, u));
1000         /* add_value(te, he_progif_id, MAKE_DATA(FLAG_ID, 0)); */
1001         mask |= (1 << he_baseclass_id) + (1 << he_subclass_id) /* + (1 << he_progif_id) */;
1002       }
1003       else {
1004         switch(idx) {
1005           case he_driver_module_insmod:
1006             c = 'i';
1007             break;
1008
1009           case he_driver_module_modprobe:
1010             c = 'm';
1011             break;
1012
1013           case he_driver_module_config:
1014             c = 'M';
1015             break;
1016
1017           case he_driver_xfree:
1018             c = 'x';
1019             break;
1020
1021           case he_driver_xfree_config:
1022             c = 'X';
1023             break;
1024
1025           case he_driver_mouse:
1026             c = 'p';
1027             break;
1028
1029           case he_driver_display:
1030             c = 'd';
1031             break;
1032
1033           case he_driver_any:
1034             c = 'a';
1035             break;
1036
1037           default:
1038             c = 0;
1039             break;
1040         }
1041         if(c) {
1042           s = new_mem(strlen(str) + 3);
1043           s[0] = c;
1044           s[1] = '\t';
1045           strcpy(s + 2, str);
1046           mask |= add_entry(hddb2, te, he_driver, s);
1047           s = free_mem(s);
1048         }
1049       }
1050     }
1051   }
1052
1053   return mask;
1054 }
1055
1056
1057 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1058 void hddb_dump_raw(hddb2_data_t *hddb, FILE *f)
1059 {
1060   int i;
1061   unsigned u, fl, v, t, id;
1062   char *s;
1063
1064   if(!hddb) return;
1065
1066   fprintf(f, "=== strings 0x%05x/0x%05x ===\n", hddb->strings_len, hddb->strings_max);
1067
1068   for(s = hddb->strings, i = 0, u = 0; u < hddb->strings_len; u++) {
1069     if(!hddb->strings[u]) {
1070       fprintf(f, "%4d (0x%05x): \"%s\"\n", i, (unsigned) (s - hddb->strings), s);
1071       i++;
1072       s = hddb->strings + u + 1;
1073     }
1074   }
1075
1076   fprintf(f, "\n=== ids 0x%05x/0x%05x ===\n", hddb->ids_len, hddb->ids_max);
1077
1078   for(u = 0; u < hddb->ids_len; u++) {
1079     fprintf(f, "0x%05x: 0x%08x  ", u, hddb->ids[u]);
1080     if(hddb->ids[u] & (1 << 31)) fprintf(f, "    ");
1081     fl = DATA_FLAG(hddb->ids[u]) & 0x7;
1082     v = DATA_VALUE(hddb->ids[u]);
1083     if(fl == FLAG_STRING && v < hddb->strings_len) {
1084       fprintf(f, "\"%s\"", hddb->strings + v);
1085     }
1086     else if(fl == FLAG_MASK) {
1087       fprintf(f, "&0x%04x", v);
1088     }
1089     else if(fl == FLAG_RANGE) {
1090       fprintf(f, "+0x%04x", v);
1091     }
1092     else if(fl == FLAG_ID) {
1093       t = ID_TAG(v);
1094       id = ID_VALUE(v);
1095       fprintf(f, "%s0x%04x", hid_tag_name(t), id);
1096       if(t == TAG_EISA) {
1097         fprintf(f, " (%s)", eisa_vendor_str(id));
1098       }
1099     }
1100     fprintf(f, "\n");
1101   }
1102
1103   fprintf(f, "\n===  search list 0x%05x/0x%05x ===\n", hddb->list_len, hddb->list_max);
1104
1105   for(u = 0; u < hddb->list_len; u++) {
1106     fprintf(f,
1107       "%4d: 0x%08x 0x%08x 0x%05x 0x%05x\n",
1108       u, hddb->list[u].key_mask, hddb->list[u].value_mask,
1109       hddb->list[u].key, hddb->list[u].value
1110     );
1111   }
1112 }
1113
1114
1115 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1116 void hddb_dump_ent_name(hddb2_data_t *hddb, FILE *f, char pre, hddb_entry_t ent)
1117 {
1118   int len, tab_ind = 24;
1119
1120   if(ent >= sizeof hddb_entry_strings / sizeof *hddb_entry_strings) return;
1121
1122   fprintf(f, "%c%s\t", pre, hddb_entry_strings[ent]);
1123
1124   len = strlen(hddb_entry_strings[ent]) + 1;
1125
1126   for(len = (len & ~7) + 8; len < tab_ind; len += 8) {
1127     fputc('\t', f);
1128   }
1129 }
1130
1131
1132 void hddb_dump_skey(hddb2_data_t *hddb, FILE *f, prefix_t pre, hddb_entry_mask_t key_mask, unsigned key)
1133 {
1134   static char pref_char[5] = { ' ', ' ', '&', '|', '+' };
1135   hddb_entry_t ent;
1136   unsigned rm_val = 0, r_or_m = 0;
1137   unsigned fl, val, *ids, id, tag, u;
1138   char *str_val, *s;
1139   int i;
1140
1141   if(pre >= sizeof pref_char) return;
1142
1143   if(key >= hddb->ids_len) return;
1144
1145   ids = hddb->ids + key;
1146
1147   for(ent = 0; ent < he_nomask && key_mask; ent++, key_mask >>= 1) {
1148     if(!(key_mask & 1)) continue;
1149
1150     fl = DATA_FLAG(*ids);
1151     val = DATA_VALUE(*ids);
1152
1153     r_or_m = 0;
1154
1155     while((fl & FLAG_CONT)) {
1156       if(fl == (FLAG_CONT | FLAG_RANGE)) {
1157         rm_val = val;
1158         r_or_m = 1;
1159       }
1160       else if(fl == (FLAG_CONT | FLAG_MASK)) {
1161         rm_val = val;
1162         r_or_m = 2;
1163       }
1164       else {
1165         break;
1166       }
1167
1168       ids++;
1169
1170       fl = DATA_FLAG(*ids);
1171       val = DATA_VALUE(*ids);
1172     }
1173
1174     fl &= ~FLAG_CONT;
1175
1176     if(ent != he_driver) {
1177       hddb_dump_ent_name(hddb, f, pref_char[pre], ent);
1178
1179       if(fl == FLAG_ID) {
1180         tag = ID_TAG(val);
1181         id = ID_VALUE(val);
1182         if(ent == he_hwclass) {
1183           /* is special */
1184           for(u = (val & 0xffffff); u; u >>= 8) {
1185             s = hd_hw_item_name(u & 0xff);
1186             if(s) fprintf(f, "%s", s);
1187             if(u > 0x100) fprintf(f, "|");
1188           }
1189         }
1190         else if(tag == TAG_EISA && (ent == he_vendor_id || ent == he_subvendor_id)) {
1191           fprintf(f, "%s", eisa_vendor_str(id));
1192         }
1193         else {
1194           u = 4;
1195           if(ent == he_bus_id || ent == he_subclass_id || ent == he_progif_id) {
1196             u = 2;
1197           }
1198           else if(ent == he_baseclass_id) {
1199             u = 3;
1200           }
1201           fprintf(f, "%s0x%0*x", hid_tag_name(tag), u, id);
1202         }
1203         if(r_or_m) {
1204           fprintf(f, "%c0x%04x", r_or_m == 1 ? '+' : '&', rm_val);
1205         }
1206       }
1207       else if(fl == FLAG_STRING) {
1208         if(val < hddb->strings_len) {
1209           str_val = hddb->strings + val;
1210           fprintf(f, "%s", str_val);
1211         }
1212       }
1213       fputc('\n', f);
1214     }
1215     else {
1216       ids--;
1217       do {
1218         ids++;
1219         fl = DATA_FLAG(*ids) & ~FLAG_CONT;
1220         val = DATA_VALUE(*ids);
1221         if(fl != FLAG_STRING) break;
1222         str_val = NULL;
1223         if(val < hddb->strings_len) str_val = hddb->strings + val;
1224         if(!str_val) break;
1225         if(!*str_val && !str_val[1] == '\t') break;
1226
1227         switch(*str_val) {
1228           case 'x':
1229              i = he_driver_xfree;
1230              break;
1231
1232            case 'X':
1233              i = he_driver_xfree_config;
1234              break;
1235
1236            case 'i':
1237              i = he_driver_module_insmod;
1238              break;
1239
1240            case 'm':
1241              i = he_driver_module_modprobe;
1242              break;
1243
1244            case 'M':
1245              i = he_driver_module_config;
1246              break;
1247
1248            case 'p':
1249              i = he_driver_mouse;
1250              break;
1251
1252            case 'd':
1253              i = he_driver_display;
1254              break;
1255
1256            case 'a':
1257              i = he_driver_any;
1258              break;
1259
1260            default:
1261              i = -1;
1262              break;
1263         }
1264         if(i == -1) break;
1265
1266         hddb_dump_ent_name(hddb, f, pref_char[pre], i);
1267         fprintf(f, "%s\n", str_val + 2);
1268       }
1269       while((*ids & (1 << 31)));
1270     }
1271
1272     /* at this point 'ids' must be the _current_ entry (_not_ the next) */
1273
1274     /* skip potential garbage/unhandled entries */
1275     while((*ids & (1 << 31))) ids++;
1276
1277     ids++;
1278
1279     if(pre != pref_add) pre = pref_and;
1280   }
1281 }
1282
1283
1284 void hddb_dump(hddb2_data_t *hddb, FILE *f)
1285 {
1286   unsigned u;
1287
1288   if(!hddb) return;
1289
1290   for(u = 0; u < hddb->list_len; u++) {
1291     hddb_dump_skey(hddb, f, pref_new, hddb->list[u].key_mask, hddb->list[u].key);
1292     hddb_dump_skey(hddb, f, pref_add, hddb->list[u].value_mask, hddb->list[u].value);
1293     fputc('\n', f);
1294   }
1295 }
1296
1297
1298 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1299 int compare_ids(hddb2_data_t *hddb, hddb_search_t *hs, hddb_entry_mask_t mask, unsigned key)
1300 {
1301   hddb_entry_t ent;
1302   unsigned rm_val = 0, r_or_m = 0, res = 0;
1303   unsigned fl, val, ok, *ids, id;
1304   char *str, *str_val;
1305
1306   if(key >= hddb->ids_len) return 1;
1307
1308   ids = hddb->ids + key;
1309
1310   for(ent = 0; ent < he_nomask && mask && !res; ent++, mask >>= 1) {
1311     if(!(mask & 1)) continue;
1312
1313     fl = DATA_FLAG(*ids);
1314     val = DATA_VALUE(*ids);
1315
1316     r_or_m = 0;
1317
1318     while((fl & FLAG_CONT)) {
1319       if(fl == (FLAG_CONT | FLAG_RANGE)) {
1320         rm_val = val;
1321         r_or_m = 1;
1322       }
1323       else if(fl == (FLAG_CONT | FLAG_MASK)) {
1324         rm_val = val;
1325         r_or_m = 2;
1326       }
1327       else {
1328         break;
1329       }
1330
1331       ids++;
1332
1333       fl = DATA_FLAG(*ids);
1334       val = DATA_VALUE(*ids);
1335     }
1336
1337     fl &= ~FLAG_CONT;
1338
1339     id = 0;
1340     str = str_val = NULL;
1341     ok = 0;
1342     if(fl == FLAG_ID) {
1343       ok = 1;
1344       switch(ent) {
1345         case he_bus_id:
1346           id = hs->bus.id;
1347           break;
1348
1349         case he_baseclass_id:
1350           id = hs->base_class.id;
1351           break;
1352
1353         case he_subclass_id:
1354           id = hs->sub_class.id;
1355           break;
1356
1357         case he_progif_id:
1358           id = hs->prog_if.id;
1359           break;
1360
1361         case he_vendor_id:
1362           id = hs->vendor.id;
1363           break;
1364
1365         case he_device_id:
1366           id = hs->device.id;
1367           break;
1368
1369         case he_subvendor_id:
1370           id = hs->sub_vendor.id;
1371           break;
1372
1373         case he_subdevice_id:
1374           id = hs->sub_device.id;
1375           break;
1376
1377         case he_rev_id:
1378           id = hs->revision.id;
1379           break;
1380
1381         case he_detail_ccw_data_cu_model:
1382           id = hs->cu_model.id;
1383           break;
1384
1385 #if 0
1386         /* not allowed as search key */
1387         case he_hwclass:
1388 #endif
1389
1390         default:
1391           ok = 0;
1392           break;
1393       }
1394     }
1395     else if(fl == FLAG_STRING) {
1396       if(val < hddb->strings_len) str_val = hddb->strings + val;
1397       ok = 2;
1398       switch(ent) {
1399         case he_bus_name:
1400           str = hs->bus.name;
1401           break;
1402
1403         case he_baseclass_name:
1404           str = hs->base_class.name;
1405           break;
1406
1407         case he_subclass_name:
1408           str = hs->sub_class.name;
1409           break;
1410
1411         case he_progif_name:
1412           str = hs->prog_if.name;
1413           break;
1414
1415         case he_vendor_name:
1416           str = hs->vendor.name;
1417           break;
1418
1419         case he_device_name:
1420           str = hs->device.name;
1421           break;
1422
1423         case he_subvendor_name:
1424           str = hs->sub_vendor.name;
1425           break;
1426
1427         case he_subdevice_name:
1428           str = hs->sub_device.name;
1429           break;
1430
1431         case he_rev_name:
1432           str = hs->revision.name;
1433           break;
1434
1435         case he_serial:
1436           str = hs->serial;
1437           break;
1438
1439         case he_requires:
1440           str = hs->requires;
1441           break;
1442
1443         default:
1444           ok = 0;
1445       }
1446     }
1447
1448     switch(ok) {
1449       case 1:
1450         switch(r_or_m) {
1451           case 1:
1452             if(id < val || id >= val + rm_val) res = 1;
1453             break;
1454
1455           case 2:
1456             if((id & ~rm_val) != val) res = 1;
1457             break;
1458
1459           default:
1460             if(id != val) res = 1;
1461         }
1462         break;
1463
1464       case 2:
1465         if(str && str_val) {
1466           if(strcmp(str, str_val)) res = 1;
1467         }
1468         else {
1469           res = 1;
1470         }
1471         break;
1472
1473       default:
1474         res = 1;
1475     }
1476
1477 #ifdef HDDB_TRACE
1478     switch(ok) {
1479       case 1:
1480         if(r_or_m) {
1481           printf(
1482             "cmp: 0x%05x: (ent = %2d, id = 0x%x, val = 0x%x%c0x%x) = %d\n",
1483             key, ent, id, val, r_or_m == 1 ? '+' : '&', rm_val, res
1484           );
1485         }
1486         else {
1487           printf(
1488             "cmp: 0x%05x: (ent = %2d, id = 0x%x, val = 0x%x) = %d\n",
1489             key, ent, id, val, res
1490           );
1491         }
1492         break;
1493
1494       case 2:
1495         printf(
1496           "cmp: 0x%05x: (ent = %2d, id = \"%s\", val = \"%s\") = %d\n",
1497           key, ent, str, str_val, res
1498         );
1499         
1500         break;
1501
1502       default:
1503         printf("cmp: 0x%05x: (ent = %2d, *** unhandled key ***) = %d\n", key, ent, res);
1504     }
1505 #endif
1506
1507     /* at this point 'ids' must be the _current_ entry (_not_ the next) */
1508
1509     /* skip potential garbage/unhandled entries */
1510     while((*ids & (1 << 31))) ids++;
1511
1512     ids++;
1513   }
1514
1515   return res;
1516 }
1517
1518
1519 void complete_ids(
1520   hddb2_data_t *hddb, hddb_search_t *hs,
1521   hddb_entry_mask_t key_mask, hddb_entry_mask_t mask, unsigned val_idx
1522 )
1523 {
1524   hddb_entry_t ent;
1525   unsigned *ids, *id;
1526   unsigned fl, val, ok;
1527   char **str, *str_val;
1528
1529   if(val_idx >= hddb->ids_len) return;
1530
1531   ids = hddb->ids + val_idx;
1532
1533   for(ent = 0; ent < he_nomask && mask; ent++, mask >>= 1) {
1534     if(!(mask & 1)) continue;
1535
1536     fl = DATA_FLAG(*ids);
1537     val = DATA_VALUE(*ids);
1538
1539     fl &= ~FLAG_CONT;
1540
1541     id = NULL;
1542     str = NULL;
1543     str_val = NULL;
1544     ok = 0;
1545     if(fl == FLAG_ID) {
1546       ok = 1;
1547       switch(ent) {
1548         case he_bus_id:
1549           id = &hs->bus.id;
1550           break;
1551
1552         case he_baseclass_id:
1553           id = &hs->base_class.id;
1554           break;
1555
1556         case he_subclass_id:
1557           id = &hs->sub_class.id;
1558           break;
1559
1560         case he_progif_id:
1561           id = &hs->prog_if.id;
1562           break;
1563
1564         case he_vendor_id:
1565           id = &hs->vendor.id;
1566           break;
1567
1568         case he_device_id:
1569           id = &hs->device.id;
1570           break;
1571
1572         case he_subvendor_id:
1573           id = &hs->sub_vendor.id;
1574           break;
1575
1576         case he_subdevice_id:
1577           id = &hs->sub_device.id;
1578           break;
1579
1580         case he_rev_id:
1581           id = &hs->revision.id;
1582           break;
1583
1584         case he_detail_ccw_data_cu_model:
1585           id = &hs->cu_model.id;
1586           break;
1587
1588         case he_hwclass:
1589           id = &hs->hwclass;
1590           break;
1591
1592         default:
1593           ok = 0;
1594           break;
1595       }
1596     }
1597     else if(fl == FLAG_STRING) {
1598       if(val < hddb->strings_len) str_val = hddb->strings + val;
1599       ok = 2;
1600       switch(ent) {
1601         case he_bus_name:
1602           str = &hs->bus.name;
1603           break;
1604
1605         case he_baseclass_name:
1606           str = &hs->base_class.name;
1607           break;
1608
1609         case he_subclass_name:
1610           str = &hs->sub_class.name;
1611           break;
1612
1613         case he_progif_name:
1614           str = &hs->prog_if.name;
1615           break;
1616
1617         case he_vendor_name:
1618           str = &hs->vendor.name;
1619           break;
1620
1621         case he_device_name:
1622           str = &hs->device.name;
1623           break;
1624
1625         case he_subvendor_name:
1626           str = &hs->sub_vendor.name;
1627           break;
1628
1629         case he_subdevice_name:
1630           str = &hs->sub_device.name;
1631           break;
1632
1633         case he_rev_name:
1634           str = &hs->revision.name;
1635           break;
1636
1637         case he_serial:
1638           str = &hs->serial;
1639           break;
1640
1641         case he_driver:
1642           ok = 3;
1643           break;
1644
1645         case he_requires:
1646           str = &hs->requires;
1647           break;
1648
1649         default:
1650           ok = 0;
1651       }
1652     }
1653
1654     if(ok) {
1655       if(
1656         (hs->value_mask[ent] & key_mask) == hs->value_mask[ent] &&
1657         key_mask != hs->value_mask[ent]
1658       ) {
1659         hs->value_mask[ent] = key_mask;
1660         hs->value |= 1 << ent;
1661       }
1662       else {
1663         /* don't change if already set */
1664         ok = 4;
1665       }
1666
1667 #if 0
1668       if((hs->value & (1 << ent))) {
1669         /* don't change if already set */
1670         ok = 4;
1671       }
1672       else if(ent != he_driver) {
1673         hs->value |= 1 << ent;
1674       }
1675 #endif
1676     }
1677
1678     switch(ok) {
1679       case 1:
1680         *id = val;
1681 #ifdef HDDB_TRACE
1682         printf("add: 0x%05x: (ent = %2d, val = 0x%08x)\n", val_idx, ent, val);
1683 #endif
1684         break;
1685
1686       case 2:
1687         *str = str_val;
1688 #ifdef HDDB_TRACE
1689         printf("add: 0x%05x: (ent = %2d, val = \"%s\")\n", val_idx, ent, str_val);
1690 #endif
1691         break;
1692
1693       case 3:
1694         ids--;
1695         hs->driver = free_str_list(hs->driver);
1696         do {
1697           ids++;
1698           fl = DATA_FLAG(*ids) & ~FLAG_CONT;
1699           val = DATA_VALUE(*ids);
1700           if(fl != FLAG_STRING) break;
1701           str_val = NULL;
1702           if(val < hddb->strings_len) str_val = hddb->strings + val;
1703           if(!str_val) break;
1704 #ifdef HDDB_TRACE
1705           printf("add: 0x%05x: (ent = %2d, val = \"%s\")\n", val_idx, ent, str_val);
1706 #endif
1707           add_str_list(&hs->driver, str_val);
1708         }
1709         while((*ids & (1 << 31)));
1710         break;
1711
1712       case 4:
1713         break;
1714
1715 #ifdef HDDB_TRACE
1716       default:
1717         printf("add: 0x%05x: (ent = %2d, *** unhandled value ***)\n", val_idx, ent);
1718 #endif
1719     }
1720
1721     /* at this point 'ids' must be the _current_ entry (_not_ the next) */
1722
1723     /* skip potential garbage/unhandled entries */
1724     while((*ids & (1 << 31))) ids++;
1725
1726     ids++;
1727   }
1728 }
1729
1730 int hddb_search(hd_data_t *hd_data, hddb_search_t *hs, int max_recursions)
1731 {
1732   unsigned u;
1733   int i;
1734   hddb2_data_t *hddb;
1735   int db_idx;
1736   hddb_entry_mask_t all_values = 0;
1737
1738   if(!hs) return 0;
1739
1740   if(!max_recursions) max_recursions = 2;
1741
1742   while(max_recursions--) {
1743     for(db_idx = 0; (unsigned) db_idx < sizeof hd_data->hddb2 / sizeof *hd_data->hddb2; db_idx++) {
1744       if(!(hddb = hd_data->hddb2[db_idx])) continue;
1745
1746       for(u = 0; u < hddb->list_len; u++) {
1747         if(
1748           (hs->key & hddb->list[u].key_mask) == hddb->list[u].key_mask
1749           /* && (hs->value & hddb->list[u].value_mask) != hddb->list[u].value_mask */
1750         ) {
1751           i = compare_ids(hddb, hs, hddb->list[u].key_mask, hddb->list[u].key);
1752           if(!i) {
1753             complete_ids(hddb, hs,
1754               hddb->list[u].key_mask,
1755               hddb->list[u].value_mask, hddb->list[u].value
1756             );
1757           }
1758         }
1759       }
1760     }
1761
1762     all_values |= hs->value;
1763
1764     if(!max_recursions) break;
1765
1766     hs->key |= hs->value;
1767     hs->value = 0;
1768     memset(hs->value_mask, 0, sizeof hs->value_mask);
1769   }
1770
1771   hs->value = all_values;
1772
1773   return 1;
1774 }
1775
1776 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1777 #ifdef HDDB_TEST
1778 void test_db(hd_data_t *hd_data)
1779 {
1780   hddb_search_t hs = {};
1781   int i;
1782
1783   hs.bus.id = 4;
1784   hs.key |= (1 << he_bus_id) + (1 << he_serial);
1785
1786   hs.serial = "ser 0123";
1787
1788   i = hddb_search(hd_data, &hs, 0);
1789
1790   printf("%d, >%s<\n", i, hs.bus.name);
1791 }
1792 #endif
1793
1794
1795 str_list_t *hddb_get_packages(hd_data_t *hd_data)
1796 {
1797   return NULL;
1798 }
1799
1800
1801 unsigned device_class(hd_data_t *hd_data, unsigned vendor, unsigned device)
1802 {
1803   hddb_search_t hs = {};
1804
1805   hs.vendor.id = vendor;
1806   hs.device.id = device;
1807   hs.key |= (1 << he_vendor_id) + (1 << he_device_id);
1808
1809   hddb_search(hd_data, &hs, 1);
1810
1811   if(
1812     (hs.value & ((1 << he_baseclass_id) + (1 << he_subclass_id))) ==
1813     ((1 << he_baseclass_id) + (1 << he_subclass_id))
1814   ) {
1815     return (hs.base_class.id << 8) + (hs.sub_class.id & 0xff);
1816   }
1817
1818   return 0;
1819 }
1820
1821
1822 unsigned sub_device_class(hd_data_t *hd_data, unsigned vendor, unsigned device, unsigned sub_vendor, unsigned sub_device)
1823 {
1824   hddb_search_t hs = {};
1825
1826   hs.vendor.id = vendor;
1827   hs.device.id = device;
1828   hs.sub_vendor.id = sub_vendor;
1829   hs.sub_device.id = sub_device;
1830   hs.key |= (1 << he_vendor_id) + (1 << he_device_id) + (1 << he_subvendor_id) + (1 << he_subdevice_id);
1831
1832   hddb_search(hd_data, &hs, 1);
1833
1834   if(
1835     (hs.value & ((1 << he_baseclass_id) + (1 << he_subclass_id))) ==
1836     ((1 << he_baseclass_id) + (1 << he_subclass_id))
1837   ) {
1838     return (hs.base_class.id << 8) + (hs.sub_class.id & 0xff);
1839   }
1840
1841   return 0;
1842 }
1843
1844
1845 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1846 void hddb_add_info(hd_data_t *hd_data, hd_t *hd)
1847 {
1848   hddb_search_t hs = {};
1849   driver_info_t *new_driver_info = NULL;
1850   unsigned u;
1851 #if WITH_ISDN
1852   cdb_isdn_card *cic;
1853 #endif
1854
1855   if(hd->tag.fixed) return;
1856
1857   hs.bus.id = hd->bus.id;
1858   hs.key |= 1 << he_bus_id;
1859
1860   hs.base_class.id = hd->base_class.id;
1861   hs.key |= 1 << he_baseclass_id;
1862
1863   hs.sub_class.id = hd->sub_class.id;
1864   hs.key |= 1 << he_subclass_id;
1865
1866   hs.prog_if.id = hd->prog_if.id;
1867   hs.key |= 1 << he_progif_id;
1868
1869   if(hd->vendor.id) {
1870     hs.vendor.id = hd->vendor.id;
1871     hs.key |= 1 << he_vendor_id;
1872   }
1873
1874   if(hd->vendor.name) {
1875     hs.vendor.name = hd->vendor.name;
1876     hs.key |= 1 << he_vendor_name;
1877   }
1878
1879   if(hd->device.id) {
1880     hs.device.id = hd->device.id;
1881     hs.key |= 1 << he_device_id;
1882   }
1883
1884   if(hd->device.name) {
1885     hs.device.name = hd->device.name;
1886     hs.key |= 1 << he_device_name;
1887   }
1888
1889   if(hd->sub_vendor.id) {
1890     hs.sub_vendor.id = hd->sub_vendor.id;
1891     hs.key |= 1 << he_subvendor_id;
1892   }
1893
1894   if(hd->sub_device.id) {
1895     hs.sub_device.id = hd->sub_device.id;
1896     hs.key |= 1 << he_subdevice_id;
1897   }
1898
1899   hs.revision.id = hd->revision.id;
1900   hs.key |= 1 << he_rev_id;
1901
1902   if(hd->revision.name) {
1903     hs.revision.name = hd->revision.name;
1904     hs.key |= 1 << he_rev_name;
1905   }
1906
1907   if(hd->serial) {
1908     hs.serial = hd->serial;
1909     hs.key |= 1 << he_serial;
1910   }
1911
1912   if(hd->detail && hd->detail->ccw.data) {
1913     hs.cu_model.id=hd->detail->ccw.data->cu_model;
1914     hs.key |= 1 << he_detail_ccw_data_cu_model;
1915   }
1916
1917   hddb_search(hd_data, &hs, 0);
1918
1919   if((hs.value & (1 << he_bus_id))) {
1920     hd->bus.id = hs.bus.id;
1921   }
1922
1923   if((hs.value & (1 << he_bus_name))) {
1924     if(!hd->ref) free_mem(hd->bus.name);
1925     hd->bus.name = new_str(hs.bus.name);
1926   }
1927
1928   if((hs.value & (1 << he_baseclass_id))) {
1929     hd->base_class.id = hs.base_class.id;
1930   }
1931
1932   if((hs.value & (1 << he_baseclass_name))) {
1933     if(!hd->ref) free_mem(hd->base_class.name);
1934     hd->base_class.name = new_str(hs.base_class.name);
1935   }
1936
1937   if((hs.value & (1 << he_subclass_id))) {
1938     hd->sub_class.id = hs.sub_class.id;
1939   }
1940
1941   if((hs.value & (1 << he_subclass_name))) {
1942     if(!hd->ref) free_mem(hd->sub_class.name);
1943     hd->sub_class.name = new_str(hs.sub_class.name);
1944   }
1945
1946   if((hs.value & (1 << he_progif_id))) {
1947     hd->prog_if.id = hs.prog_if.id;
1948   }
1949
1950   if((hs.value & (1 << he_progif_name))) {
1951     if(!hd->ref) free_mem(hd->prog_if.name);
1952     hd->prog_if.name = new_str(hs.prog_if.name);
1953   }
1954
1955   if((hs.value & (1 << he_requires))) {
1956     if(!hd->ref) hd->requires = free_str_list(hd->requires);
1957     hd->requires = hd_split('|', hs.requires);
1958   }
1959
1960   if((hs.value & (1 << he_vendor_id))) {
1961     hd->vendor.id = hs.vendor.id;
1962   }
1963
1964   if((hs.value & (1 << he_vendor_name))) {
1965     if(!hd->ref) free_mem(hd->vendor.name);
1966     hd->vendor.name = new_str(hs.vendor.name);
1967   }
1968
1969   if((hs.value & (1 << he_device_id))) {
1970     hd->device.id = hs.device.id;
1971   }
1972
1973   if((hs.value & (1 << he_device_name))) {
1974     if(!hd->ref) free_mem(hd->device.name);
1975     hd->device.name = new_str(hs.device.name);
1976   }
1977
1978   if((hs.value & (1 << he_subvendor_id))) {
1979     hd->sub_vendor.id = hs.sub_vendor.id;
1980   }
1981
1982   if((hs.value & (1 << he_subvendor_name))) {
1983     if(!hd->ref) free_mem(hd->sub_vendor.name);
1984     hd->sub_vendor.name = new_str(hs.sub_vendor.name);
1985   }
1986
1987   if((hs.value & (1 << he_subdevice_id))) {
1988     hd->sub_device.id = hs.sub_device.id;
1989   }
1990
1991   if((hs.value & (1 << he_subdevice_name))) {
1992     if(!hd->ref) free_mem(hd->sub_device.name);
1993     hd->sub_device.name = new_str(hs.sub_device.name);
1994   }
1995
1996   if((hs.value & (1 << he_detail_ccw_data_cu_model))) {
1997     if(hd->detail && hd->detail->ccw.data)
1998       hd->detail->ccw.data->cu_model=hs.cu_model.id;
1999   }
2000
2001   if((hs.value & (1 << he_hwclass))) {
2002     for(u = hs.hwclass; u; u >>= 8) {
2003       hd_set_hw_class(hd, u & 0xff);
2004     }
2005   }
2006
2007   /* look for sub vendor again */
2008
2009   if(!hd->sub_vendor.name && hd->sub_vendor.id) {
2010     hddb_search_t hs2 = {};
2011
2012     hs2.vendor.id = hd->sub_vendor.id;
2013     hs2.key |= 1 << he_vendor_id;
2014
2015     hddb_search(hd_data, &hs2, 1);
2016
2017     if((hs2.value & (1 << he_vendor_name))) {
2018       hd->sub_vendor.name = new_str(hs2.vendor.name);
2019     }
2020   }
2021
2022   /* look for compat device name */
2023   if(
2024     hd->compat_vendor.id &&
2025     hd->compat_device.id &&
2026     !hd->compat_vendor.name &&
2027     !hd->compat_device.name
2028   ) {
2029     hddb_search_t hs2 = {};
2030
2031     hs2.vendor.id = hd->compat_vendor.id;
2032     hs2.key |= 1 << he_vendor_id;
2033
2034     hs2.device.id = hd->compat_device.id;
2035     hs2.key |= 1 << he_device_id;
2036
2037     hddb_search(hd_data, &hs2, 1);
2038
2039     if((hs2.value & (1 << he_vendor_name))) {
2040       hd->compat_vendor.name = new_str(hs2.vendor.name);
2041     }
2042
2043     if((hs2.value & (1 << he_device_name))) {
2044       hd->compat_device.name = new_str(hs2.device.name);
2045     }
2046   }
2047
2048   /* get package info for compat device id */
2049
2050   if(!hd->requires) {
2051     hddb_search_t hs2 = {};
2052
2053     hs2.vendor.id = hd->compat_vendor.id;
2054     hs2.key |= 1 << he_vendor_id;
2055
2056     hs2.device.id = hd->compat_device.id;
2057     hs2.key |= 1 << he_device_id;
2058
2059     hddb_search(hd_data, &hs2, 1);
2060
2061     if((hs2.value & (1 << he_requires))) {
2062       hd->requires = hd_split('|', hs2.requires);
2063     }
2064   }
2065
2066   /* get driver info */
2067
2068 #if WITH_ISDN
2069   if((cic = get_isdn_info(hd))) {
2070     new_driver_info = isdn_driver(hd_data, hd, cic);
2071     if(!hd->model && cic->lname && *cic->lname) {
2072       hd->model = new_str(cic->lname);
2073     }
2074     free_mem(cic);
2075   }
2076   if (!new_driver_info && ((cic = get_dsl_info(hd)))) {
2077     new_driver_info = dsl_driver(hd_data, hd, cic);
2078     if(!hd->model && cic->lname && *cic->lname) {
2079       hd->model = new_str(cic->lname);
2080     }
2081     free_mem(cic);
2082   }
2083 #endif
2084
2085   if(!new_driver_info) {
2086     new_driver_info = hd_modinfo_db(hd_data, hd_data->modinfo_ext, hd, new_driver_info);
2087   }
2088
2089 #if 1
2090   if(!new_driver_info && (hs.value & (1 << he_driver))) {
2091     new_driver_info = hddb_to_device_driver(hd_data, &hs);
2092   }
2093
2094   if(!new_driver_info && (hd->compat_vendor.id || hd->compat_device.id)) {
2095     memset(&hs, 0, sizeof hs);
2096
2097     if(hd->compat_vendor.id) {
2098       hs.vendor.id = hd->compat_vendor.id;
2099       hs.key |= 1 << he_vendor_id;
2100     }
2101     if(hd->compat_device.id) {
2102       hs.device.id = hd->compat_device.id;
2103       hs.key |= 1 << he_device_id;
2104     }
2105
2106     hddb_search(hd_data, &hs, 1);
2107
2108     if((hs.value & (1 << he_driver))) {
2109       new_driver_info =  hddb_to_device_driver(hd_data, &hs);
2110     }
2111   }
2112 #endif
2113
2114   /* acpi: load temperature control modules */
2115   if(!new_driver_info && hd->is.with_acpi) {
2116     memset(&hs, 0, sizeof hs);
2117
2118     hs.vendor.id = MAKE_ID(TAG_SPECIAL, 0xf001);
2119     hs.key |= 1 << he_vendor_id;
2120
2121     hs.device.id = MAKE_ID(TAG_SPECIAL, 4);
2122     hs.key |= 1 << he_device_id;
2123
2124     hddb_search(hd_data, &hs, 1);
2125
2126     if((hs.value & (1 << he_driver))) {
2127       new_driver_info =  hddb_to_device_driver(hd_data, &hs);
2128     }
2129   }
2130
2131   if(!new_driver_info && hd->base_class.id == bc_keyboard) {
2132     new_driver_info = kbd_driver(hd_data, hd);
2133   }
2134
2135   if(!new_driver_info && hd->base_class.id == bc_monitor) {
2136     new_driver_info = monitor_driver(hd_data, hd);
2137   }
2138
2139   new_driver_info = hd_modinfo_db(hd_data, hd_data->modinfo, hd, new_driver_info);
2140
2141   if(new_driver_info) {
2142     if(!hd->ref) {
2143       hd->driver_info = free_driver_info(hd->driver_info);
2144     }
2145     hd->driver_info = new_driver_info;
2146     expand_driver_info(hd_data, hd);
2147   }
2148
2149   free_str_list(hs.driver);
2150 }
2151
2152
2153 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2154 driver_info_t *hddb_to_device_driver(hd_data_t *hd_data, hddb_search_t *hs)
2155 {
2156   char *s, *t, *t0;
2157   driver_info_t *di = NULL, *di0 = NULL;
2158   str_list_t *sl;
2159
2160   for(sl = hs->driver; sl; sl = sl->next) {
2161     if(!sl->str || !*sl->str || sl->str[1] != '\t') return NULL;
2162
2163     if(di && (*sl->str == 'M' || *sl->str == 'X')) {
2164       add_str_list(&di->any.hddb1, sl->str + 2);
2165       continue;
2166     }
2167
2168     if(di)
2169       di = di->next = new_mem(sizeof *di);
2170     else
2171       di = di0 = new_mem(sizeof *di);
2172
2173     switch(*sl->str) {
2174       case 'd':
2175         di->any.type = di_display;
2176         break;
2177
2178       case 'm':
2179         di->module.modprobe = 1;
2180       case 'i':
2181         di->any.type = di_module;
2182         break;
2183
2184       case 'p':
2185         di->any.type = di_mouse;
2186         break;
2187
2188       case 'x':
2189         di->any.type = di_x11;
2190         break;
2191
2192       default:
2193         di->any.type = di_any;
2194     }
2195
2196     s = new_str(sl->str + 2);
2197     for(t0 = s; (t = strsep(&t0, "|")); ) {
2198       add_str_list(&di->any.hddb0, t);
2199     }
2200     free_mem(s);
2201   }
2202
2203   return di0;
2204 }
2205
2206
2207 driver_info_t *kbd_driver(hd_data_t *hd_data, hd_t *hd)
2208 {
2209   driver_info_t *di;
2210   driver_info_kbd_t *ki;
2211   int arch = hd_cpu_arch(hd_data);
2212   unsigned u;
2213   char *s1, *s2;
2214   hd_t *hd_tmp;
2215   usb_t *usb;
2216
2217   /* country codes
2218      1 Arabic
2219      2 Belgian
2220      3 Canadian-Bilingual
2221      4 Canadian-French
2222      5 Czech Republic
2223      6 Danish
2224      7 Finnish
2225      8 French
2226      9 German
2227     10 Greek
2228     11 Hebrew
2229     12 Hungary
2230     13 International (ISO)
2231     14 Italian
2232     15 Japan (Katakana)
2233     16 Korean
2234     17 Latin American
2235     18 Netherlands/Dutch
2236     19 Norwegian
2237     20 Persian (Farsi)
2238     21 Poland
2239     22 Portuguese
2240     23 Russia
2241     24 Slovakia
2242     25 Spanish
2243     26 Swedish 
2244     27 Swiss/French
2245     28 Swiss/German
2246     29 Switzerland
2247     30 Taiwan
2248     31 Turkish
2249     32 UK
2250     33 US
2251     34 Yugoslavia
2252   */
2253   static struct {
2254     unsigned country;
2255     char *layout;
2256     char *keymap;
2257   } country_code[] = {
2258     {  5, "cs", "cz-us-qwertz" },
2259     {  8, "fr", "fr-latin1" },
2260     {  9, "de", "de-latin1-nodeadkeys" },
2261     { 10, "gr", "gr" },
2262     { 14, "it", "it" },
2263     { 18, "nl", "us" },
2264     { 23, "ru", "ru1" },
2265     { 25, "es", "es" },
2266     { 32, "uk", "uk" },
2267     { 33, "us", "us" }
2268   };
2269
2270   if(hd->sub_class.id == sc_keyboard_console) return NULL;
2271
2272   di = new_mem(sizeof *di);
2273   di->kbd.type = di_kbd;
2274   ki = &(di->kbd);
2275
2276   switch(arch) {
2277     case arch_intel:
2278     case arch_x86_64:
2279     case arch_alpha:
2280       ki->XkbRules = new_str("xfree86");
2281       ki->XkbModel = new_str(hd->vendor.id == MAKE_ID(TAG_USB, 0x05ac) ? "macintosh" : "pc104");
2282       break;
2283
2284     case arch_ppc:
2285     case arch_ppc64:
2286       ki->XkbRules = new_str("xfree86");
2287       ki->XkbModel = new_str("macintosh");
2288       for(hd_tmp = hd_data->hd; hd_tmp; hd_tmp = hd_tmp->next) {
2289         if(
2290           hd_tmp->base_class.id == bc_internal &&
2291           hd_tmp->sub_class.id == sc_int_cpu &&
2292           hd_tmp->detail &&
2293           hd_tmp->detail->type == hd_detail_cpu &&
2294           hd_tmp->detail->cpu.data
2295         ) {
2296           s1 = hd_tmp->detail->cpu.data->vend_name;
2297           if(s1 && (strstr(s1, "CHRP ") == s1 || strstr(s1, "PReP ") == s1)) {
2298             free_mem(ki->XkbModel);
2299             ki->XkbModel = new_str("pc104");
2300           }
2301         }
2302       }
2303       if(ID_TAG(hd->vendor.id) == TAG_USB) {
2304         free_mem(ki->XkbModel);
2305         ki->XkbModel = new_str(hd->vendor.id == MAKE_ID(TAG_USB, 0x05ac) ? "macintosh" : "pc104");
2306       }
2307       break;
2308
2309     case arch_sparc:
2310     case arch_sparc64:
2311       if(hd->vendor.id == MAKE_ID(TAG_SPECIAL, 0x0202)) {
2312         ki->XkbRules = new_str("sun");
2313         u = ID_VALUE(hd->device.id);
2314         if(u == 4) ki->XkbModel = new_str("type4");
2315         if(u == 5) {
2316           ki->XkbModel = new_str(ID_VALUE(hd->sub_device.id) == 2 ? "type5_euro" : "type5");
2317         }
2318         s1 = s2 = NULL;
2319
2320         switch(hd->prog_if.id) {
2321           case  0: case  1: case 33: case 34: case 80: case 81:
2322           default:
2323             s1 = "us"; s2 = "sunkeymap";
2324             break;
2325
2326           case  2:
2327             s1 = "fr"; s2 = "sunt5-fr-latin1"; // fr_BE?
2328             break;
2329
2330           case  3:
2331             s1 = "ca";
2332             break;
2333
2334           case  4: case 36: case 83:
2335             s1 = "dk";
2336             break;
2337
2338           case  5: case 37: case 84:
2339             s1 = "de"; s2 = "sunt5-de-latin1";
2340             break;
2341
2342           case  6: case 38: case 85:
2343             s1 = "it";
2344             break;
2345
2346           case  7: case 39: case 86:
2347             s1 = "nl";
2348             break;
2349
2350           case  8: case 40: case 87:
2351             s1 = "no";
2352             if(u == 4) s2 = "sunt4-no-latin1";
2353             break;
2354
2355           case  9: case 41: case 88:
2356             s1 = "pt";
2357             break;
2358
2359           case 10: case 42: case 89:
2360             s1 = "es";
2361             s2 = u == 4 ? "sunt4-es" : "sunt5-es";
2362             break;
2363
2364           case 11: case 43: case 90:
2365             s1 = "se"; s2 = "sunt5-fi-latin1";  // se is swedish, not fi
2366             break;
2367
2368           case 12: case 44: case 91:
2369             s1 = "fr"; s2 = "sunt5-fr-latin1"; // fr_CH
2370             break;
2371
2372           case 13: case 45: case 92:
2373             s1 = "de"; s2 = "sunt5-de-latin1";  // de_CH
2374             break;
2375
2376           case 14: case 46: case 93:
2377             s1 = "gb"; s2 = "sunt5-uk";
2378             break;
2379
2380           case 16: case 47: case 94:
2381             s1 = "ko";
2382             break;
2383
2384           case 17: case 48: case 95:
2385             s1 = "tw";
2386             break;
2387
2388           case 32: case 49: case 96:
2389             s1 = "jp";
2390             break;
2391
2392           case 50: case 97:
2393             s1 = "fr"; s2 = "sunt5-fr-latin1"; // fr_CA
2394             break;
2395
2396           case 51:
2397             s1 = "hu";
2398             break;
2399
2400           case 52:
2401             s1 = "pl"; s2 = "sun-pl";
2402             break;
2403
2404           case 53:
2405             s1 = "cs";
2406             break;
2407
2408           case 54:
2409             s1 = "ru"; s2 = "sunt5-ru";
2410             break;
2411         }
2412         ki->XkbLayout = new_str(s1);
2413         ki->keymap = new_str(s2);
2414       }
2415       else {
2416         ki->XkbRules = new_str("xfree86");
2417         ki->XkbModel = new_str("pc104");
2418       }
2419       break;
2420
2421     default:
2422       ki->XkbRules = new_str("xfree86");
2423   }
2424
2425   if(
2426     hd->bus.id == bus_usb &&
2427     hd->detail &&
2428     hd->detail->type == hd_detail_usb &&
2429     (usb = hd->detail->usb.data) &&
2430     usb->country
2431   ) {
2432     for(u = 0; u < sizeof country_code / sizeof *country_code; u++) {
2433       if(country_code[u].country == usb->country) {
2434         if(!ki->XkbLayout) ki->XkbLayout = new_str(country_code[u].layout);
2435         if(!ki->keymap) ki->keymap = new_str(country_code[u].keymap);
2436         break;
2437       }
2438     }
2439   }
2440
2441   return di;
2442 }
2443
2444
2445 driver_info_t *monitor_driver(hd_data_t *hd_data, hd_t *hd)
2446 {
2447   driver_info_t *di = NULL;
2448   driver_info_display_t *ddi;
2449   monitor_info_t *mi;
2450   hd_res_t *res;
2451   unsigned width = 640, height = 480;
2452
2453   if(
2454     hd->detail &&
2455     hd->detail->type == hd_detail_monitor &&
2456     (mi = hd->detail->monitor.data) &&
2457     mi->min_hsync
2458   ) {
2459     di = new_mem(sizeof *di);
2460     di->display.type = di_display;
2461     ddi = &(di->display);
2462
2463     ddi->min_vsync = mi->min_vsync;
2464     ddi->max_vsync = mi->max_vsync;
2465     ddi->min_hsync = mi->min_hsync;
2466     ddi->max_hsync = mi->max_hsync;
2467     ddi->bandwidth = mi->clock / 1000;
2468     ddi->hdisp     = mi->hdisp; 
2469     ddi->hsyncstart= mi->hsyncstart;
2470     ddi->hsyncend  = mi->hsyncend;
2471     ddi->htotal    = mi->htotal;
2472     ddi->hflag     = mi->hflag;
2473     ddi->vdisp     = mi->vdisp;
2474     ddi->vsyncstart= mi->vsyncstart;
2475     ddi->vsyncend  = mi->vsyncend;
2476     ddi->vtotal    = mi->vtotal;
2477     ddi->vflag     = mi->vflag;
2478
2479     for(res = hd->res; res; res = res->next) {
2480       if(res->any.type == res_monitor) {
2481         if(res->monitor.width * res->monitor.height > width * height ) {
2482           width = res->monitor.width;
2483           height = res->monitor.height;
2484         }
2485       }
2486     }
2487
2488     ddi->width = width;
2489     ddi->height = height;
2490   }
2491
2492   return di;
2493 }
2494
2495
2496 #if WITH_ISDN
2497
2498 #if 0
2499 int chk_free_biosmem(hd_data_t *hd_data, unsigned addr, unsigned len)
2500 {
2501   unsigned u;
2502   unsigned char c;
2503
2504   addr -= hd_data->bios_rom.start;
2505   if(
2506     !hd_data->bios_rom.data ||
2507     addr >= hd_data->bios_rom.size ||
2508     addr + len > hd_data->bios_rom.size
2509   ) return 0;
2510
2511   for(c = 0xff, u = addr; u < addr + len; u++) {
2512     c &= hd_data->bios_rom.data[u];
2513   }
2514
2515   return c == 0xff ? 1 : 0;
2516 }
2517
2518 isdn_parm_t *new_isdn_parm(isdn_parm_t **ip)
2519 {
2520   while(*ip) ip = &(*ip)->next;
2521
2522   return *ip = new_mem(sizeof **ip);
2523 }
2524 #endif
2525
2526 driver_info_t *isdn_driver(hd_data_t *hd_data, hd_t *hd, cdb_isdn_card *cic)
2527 {
2528   driver_info_t *di0, *di;
2529   cdb_isdn_vario *civ;
2530 /*  hd_res_t *res;
2531   uint64_t i, irqs, irqs2;
2532   int irq_val, pnr;
2533 */
2534   int drv;
2535   str_list_t *sl, *sl0;
2536
2537   if(!cic) return NULL;
2538
2539   di0 = new_mem(sizeof *di0);
2540
2541   drv = cic->vario;
2542   di = NULL;
2543
2544   while((civ = hd_cdbisdn_get_vario(drv))) {
2545     drv = civ->next_vario;
2546     if (di) {
2547       di->next = new_mem(sizeof *di);
2548       di = di->next;
2549     } else {
2550       di = di0;
2551     }
2552     di->isdn.type = di_isdn;
2553     di->isdn.i4l_type = civ->typ;
2554     di->isdn.i4l_subtype = civ->subtyp;
2555     di->isdn.i4l_name = new_str(cic->lname);
2556
2557     if(civ->need_pkg && *civ->need_pkg) {
2558       sl0 = hd_split(',', (char *) civ->need_pkg);
2559       for(sl = sl0; sl; sl = sl->next) {
2560         if(!search_str_list(hd->requires, sl->str)) {
2561           add_str_list(&hd->requires, sl->str);
2562         }
2563       }
2564       free_str_list(sl0);
2565     }
2566
2567     if(hd->bus.id == bus_pci) continue;
2568 #if 0
2569     pnr = 1;
2570     civ = hd_cdbisdn_get_vario(cic->vario);
2571     if (!civ) continue;
2572     if (civ->irq && civ->irq[0]) {
2573         ip = new_isdn_parm(&di->isdn.params);
2574         ip->name = new_str("IRQ");
2575         ip->type = CDBISDN_P_IRQ;
2576     }
2577     if (civ->io && civ->io[0]) {
2578         ip = new_isdn_parm(&di->isdn.params);
2579         ip->name = new_str("IO");
2580         ip->type = CDBISDN_P_IO;
2581     }
2582     if (civ->membase && civ->membase[0]) {
2583         ip = new_isdn_parm(&di->isdn.params);
2584         ip->name = new_str("MEMBASE");
2585         ip->type = CDBISDN_P_MEM;
2586     }
2587     while((ipi = hd_ihw_get_parameter(ici->handle, pnr++))) {
2588       ip = new_isdn_parm(&di->isdn.params);
2589       ip->name = new_str(ipi->name);
2590       ip->type = ipi->type & P_TYPE_MASK;
2591       ip->flags = ipi->flags & P_PROPERTY_MASK;
2592       ip->def_value = ipi->def_value;
2593       if(ipi->list) ip->alt_values = *ipi->list;
2594       ip->alt_value = new_mem(ip->alt_values * sizeof *ip->alt_value);
2595       for(i = 0; i < ip->alt_values; i++) {
2596         ip->alt_value[i] = ipi->list[i + 1];
2597       }
2598       ip->valid = 1;
2599
2600       if((ip->flags & P_SOFTSET)) {
2601         switch(ip->type) {
2602           case P_IRQ:
2603             update_irq_usage(hd_data);
2604             irqs = 0;
2605             for(i = 0; i < ip->alt_values; i++) {
2606               irqs |= 1ull << ip->alt_value[i];
2607             }
2608             irqs &= ~(hd_data->used_irqs | hd_data->assigned_irqs);
2609 #ifdef __i386__
2610             irqs &= 0xffffull;  /* max. 16 on intel */
2611             /*
2612              * The point is, that this is relevant for isa boards only
2613              * and those have irq values < 16 anyway. So it really
2614              * doesn't matter if we mask with 0xffff or not.
2615              */
2616 #endif
2617             if(!irqs) {
2618               ip->conflict = 1;
2619               ip->valid = 0;
2620             }
2621             else {
2622               irqs2 = irqs & ~0xc018ull;
2623               /* see if we can avoid irqs 3,4,14,15 */
2624               if(irqs2) irqs = irqs2;
2625               irq_val = -1;
2626               /* try default value first */
2627               if(ip->def_value && (irqs & (1ull << ip->def_value))) {
2628                 irq_val = ip->def_value;
2629               }
2630               else {
2631                 for(i = 0; i < 64 && irqs; i++, irqs >>= 1) {
2632                   if((irqs & 1)) irq_val = i;
2633                 }
2634               }
2635               if(irq_val >= 0) {
2636                 ip->value = irq_val;
2637                 hd_data->assigned_irqs |= 1ull << irq_val;
2638               }
2639               else {
2640                 ip->valid = 0;
2641               }
2642             }
2643             break;
2644           case P_MEM:
2645             if(!hd_data->bios_rom.data) {
2646               if(ip->def_value) {
2647                 ip->value = ip->def_value;
2648               }
2649             }
2650             else {
2651               /* ###### 0x2000 is just guessing -> should be provided by libihw */
2652               if(ip->def_value && chk_free_biosmem(hd_data, ip->def_value, 0x2000)) {
2653                 ip->value = ip->def_value;
2654               }
2655               else {
2656                 for(i = ip->alt_values - 1; i >= 0; i--) {
2657                   if(chk_free_biosmem(hd_data, ip->alt_value[i], 0x2000)) {
2658                     ip->value = ip->alt_value[i];
2659                     break;
2660                   }
2661                 }
2662               }
2663             }
2664             if(!ip->value) ip->conflict = 1;
2665             break;
2666           default:
2667             ip->valid = 0;
2668         }
2669       }
2670       else if((ip->flags & P_DEFINE)) {
2671         res = NULL;
2672         switch(ip->type) {
2673           case P_IRQ:
2674             res = get_res(hd, res_irq, 0);
2675             if(res) ip->value = res->irq.base;
2676             break;
2677           case P_MEM:
2678             res = get_res(hd, res_mem, 0);
2679             if(res) ip->value = res->mem.base;
2680             break;
2681           case P_IO:
2682             res = get_res(hd, res_io, 0);
2683             if(res) ip->value = res->io.base;
2684             break;
2685           case P_IO0:
2686           case P_IO1:
2687           case P_IO2:
2688             res = get_res(hd, res_io, ip->type - P_IO0);
2689             if(res) ip->value = res->io.base;
2690             break;
2691           // ##### might break for 64bit pci entries?
2692           case P_BASE0:
2693           case P_BASE1:
2694           case P_BASE2:
2695           case P_BASE3:
2696           case P_BASE4:
2697           case P_BASE5:
2698             res = get_res(hd, res_mem, ip->type - P_BASE0);
2699             if(res) ip->value = res->mem.base;
2700             break;
2701           default:
2702             ip->valid = 0;
2703         }
2704         if(!res) ip->valid = 0;
2705       }
2706     }
2707 #endif
2708   }
2709   if(!di) di0 = free_mem(di0);
2710
2711   return di0;
2712 }
2713
2714 driver_info_t *dsl_driver(hd_data_t *hd_data, hd_t *hd, cdb_isdn_card *cic)
2715 {
2716   driver_info_t *di0, *di;
2717   cdb_isdn_vario *civ;
2718   int drv;
2719   str_list_t *sl, *sl0;
2720
2721   if(!cic) return NULL;
2722
2723   di0 = new_mem(sizeof *di0);
2724
2725   drv = cic->vario;
2726   di = NULL;
2727
2728   while((civ = hd_cdbisdn_get_vario(drv))) {
2729     drv = civ->next_vario;
2730     if (di) {
2731       di->next = new_mem(sizeof *di);
2732       di = di->next;
2733     } else {
2734       di = di0;
2735     }
2736     di->dsl.type = di_dsl;
2737     if(civ->interface && *civ->interface) {
2738       if (!strcmp(civ->interface, "CAPI20")) {
2739         di->dsl.mode = new_str("capiadsl");
2740         if(civ->mod_name && *civ->mod_name)
2741           di->dsl.name = new_str(civ->mod_name);
2742         else
2743           di->dsl.name = new_str("unknown");
2744       } else if (!strcmp(civ->interface, "pppoe")) {
2745         di->dsl.mode = new_str("pppoe");
2746         if(civ->mod_name && *civ->mod_name)
2747           di->dsl.name = new_str(civ->mod_name);
2748         else
2749           di->dsl.name = new_str("none");
2750       } else {
2751         di->dsl.mode = new_str("unknown");
2752         di->dsl.name = new_str("unknown");
2753       }
2754     } else {
2755       di->dsl.mode = new_str("unknown");
2756       di->dsl.name = new_str("unknown");
2757     }
2758
2759     if(civ->need_pkg && *civ->need_pkg) {
2760       sl0 = hd_split(',', (char *) civ->need_pkg);
2761       for(sl = sl0; sl; sl = sl->next) {
2762         if(!search_str_list(hd->requires, sl->str)) {
2763           add_str_list(&hd->requires, sl->str);
2764         }
2765       }
2766       free_str_list(sl0);
2767     }
2768
2769     if(hd->bus.id == bus_pci) continue;
2770   }
2771   if(!di) di0 = free_mem(di0);
2772
2773   return di0;
2774 }
2775
2776 #endif          /* WITH_ISDN */
2777
2778
2779 hd_res_t *get_res(hd_t *hd, enum resource_types t, unsigned index)
2780 {
2781   hd_res_t *res;
2782
2783   for(res = hd->res; res; res = res->next) {
2784     if(res->any.type == t) {
2785       if(!index) return res;
2786       index--;
2787     }
2788   }
2789
2790   return NULL;
2791 }
2792
2793
2794 driver_info_t *reorder_x11(driver_info_t *di0, char *info)
2795 {
2796   driver_info_t *di, *di_new, **di_list;
2797   int i, dis, found;
2798
2799   for(dis = 0, di = di0; di; di = di->next) dis++;
2800
2801   di_list = new_mem(dis * sizeof *di_list);
2802
2803   for(i = 0, di = di0; di; di = di->next) {
2804     di_list[i++] = di;
2805   }
2806
2807   di = di_new = NULL;
2808   for(i = found = 0; i < dis; i++) {
2809     if(
2810       !strcmp(di_list[i]->x11.xf86_ver, info) ||
2811       !strcmp(di_list[i]->x11.server, info)
2812     ) {
2813       found = 1;
2814       if(di) {
2815         di = di->next = di_list[i];
2816       }
2817       else {
2818         di = di_new = di_list[i];
2819       }
2820       di->next = NULL;
2821       di_list[i] = NULL;
2822     }
2823   }
2824
2825   for(i = 0; i < dis; i++) {
2826     if(di_list[i]) {
2827       if(di) {
2828         di = di->next = di_list[i];
2829       }
2830       else {
2831         di = di_new = di_list[i];
2832       }
2833       di->next = NULL;
2834       di_list[i] = NULL;
2835     }
2836   }
2837
2838   free_mem(di_list);
2839
2840   if(!found && strlen(info) > 1) {
2841     free_driver_info(di_new);
2842     di_new = new_mem(sizeof *di_new);
2843     di_new->any.type = di_x11;
2844     di_new->x11.server = new_str(info);
2845     di_new->x11.xf86_ver = new_str(*info >= 'A' && *info <= 'Z' ? "3" : "4");
2846   }
2847
2848   return di_new;
2849 }
2850
2851
2852 void expand_driver_info(hd_data_t *hd_data, hd_t *hd)
2853 {
2854   int i;
2855   unsigned u1, u2;
2856   char *s, *t, *t0;
2857   driver_info_t *di;
2858   str_list_t *sl, *sl1, *sl2, *cmd;
2859
2860   if(!hd || !hd->driver_info) return;
2861
2862   for(di = hd->driver_info; di; di = di->next) {
2863     switch(di->any.type) {
2864       case di_display:
2865         for(i = 0, sl = di->display.hddb0; sl; sl = sl->next, i++) {
2866           if(i == 0 && sscanf(sl->str, "%ux%u", &u1, &u2) == 2) {
2867             di->display.width = u1;
2868             di->display.height = u2;
2869           }
2870           else if(i == 1 && sscanf(sl->str, "%u-%u", &u1, &u2) == 2) {
2871             di->display.min_vsync = u1;
2872             di->display.max_vsync = u2;
2873           }
2874           else if(i == 2 && sscanf(sl->str, "%u-%u", &u1, &u2) == 2) {
2875             di->display.min_hsync = u1;
2876             di->display.max_hsync = u2;
2877           }
2878           else if(i == 3 && sscanf(sl->str, "%u", &u1) == 1) {
2879             di->display.bandwidth = u1;
2880           }
2881         }
2882         break;
2883
2884       case di_module:
2885         for(di->module.active = 1, sl = di->module.hddb0; sl; sl = sl->next) {
2886           t0 = s = new_str(sl->str);
2887
2888           t = strsep(&t0, " ");
2889
2890           add_str_list(&di->module.names, t);
2891           di->module.active &= (
2892             hd_module_is_active(hd_data, t) |
2893             (search_str_list(hd->drivers, t) ? 1 : 0)
2894           );
2895
2896           if(t0) {
2897             add_str_list(&di->module.mod_args, module_cmd(hd, t0));
2898           }
2899           else {
2900             add_str_list(&di->module.mod_args, NULL);
2901           }
2902
2903           free_mem(s);
2904         }
2905         for(sl = di->module.hddb1; sl; sl = sl->next) {
2906           s = module_cmd(hd, sl->str);
2907           if(s) str_printf(&di->module.conf, -1, "%s\n", s);
2908         }
2909         break;
2910
2911       case di_mouse:
2912         di->mouse.buttons = di->mouse.wheels = -1;
2913         u1 = 0;
2914         if(
2915           hd->compat_vendor.id == MAKE_ID(TAG_SPECIAL, 0x0210) &&
2916           ID_TAG(hd->compat_device.id) == TAG_SPECIAL
2917         ) {
2918           u1 = hd->compat_device.id;
2919         }
2920         if(
2921           hd->vendor.id == MAKE_ID(TAG_SPECIAL, 0x0210) &&
2922           ID_TAG(hd->device.id) == TAG_SPECIAL
2923         ) {
2924           u1 = hd->device.id;
2925         }
2926         if(u1) {
2927           di->mouse.wheels = ID_VALUE(u1) >> 4;
2928           di->mouse.buttons = ID_VALUE(u1) & 15;
2929         }
2930         for(i = 0, sl = di->mouse.hddb0; sl; sl = sl->next, i++) {
2931           if(i == 0) {
2932             di->mouse.xf86 = new_str(sl->str);
2933           }
2934           else if(i == 1) {
2935             di->mouse.gpm = new_str(sl->str);
2936           }
2937           else if(i == 2 && *sl->str) {
2938             di->mouse.buttons = strtol(sl->str, NULL, 10);
2939           }
2940           else if(i == 3 && *sl->str) {
2941             di->mouse.wheels = strtol(sl->str, NULL, 10);
2942           }
2943         }
2944         break;
2945
2946       case di_x11:
2947         for(i = 0, sl = di->x11.hddb0; sl; sl = sl->next, i++) {
2948           if(i == 0) {
2949             di->x11.xf86_ver = new_str(sl->str);
2950           }
2951           else if(i == 1) {
2952             di->x11.server = new_str(sl->str);
2953           }
2954           else if(i == 2) {
2955             if(!strcmp(sl->str, "3d")) di->x11.x3d = 1;
2956           }
2957 #if 0
2958           else if(i == 3) {
2959             s = new_str(sl->str);
2960             for(t0 = s; (t = strsep(&t0, ",")); ) {
2961               add_str_list(&di->x11.packages, t);
2962             }
2963             free_mem(s);
2964           }
2965 #endif
2966           else if(i == 4) {
2967             s = new_str(sl->str);
2968             for(t0 = s; (t = strsep(&t0, ",")); ) {
2969               add_str_list(&di->x11.extensions, t);
2970             }
2971             free_mem(s);
2972           }
2973           else if(i == 5) {
2974             s = new_str(sl->str);
2975             for(t0 = s; (t = strsep(&t0, ",")); ) {
2976               add_str_list(&di->x11.options, t);
2977             }
2978             free_mem(s);
2979           }
2980           else if(i == 6) {
2981             for(sl2 = sl1 = hd_split(',', sl->str); sl2; sl2 = sl2->next) {
2982               u1 = strtoul(sl2->str, NULL, 0);
2983               switch(u1) {
2984                 case 8:
2985                   di->x11.colors.c8 = 1;
2986                   di->x11.colors.all |= (1 << 0);
2987                   break;
2988
2989                 case 15:
2990                   di->x11.colors.c15 = 1;
2991                   di->x11.colors.all |= (1 << 1);
2992                   break;
2993
2994                 case 16:
2995                   di->x11.colors.c16 = 1;
2996                   di->x11.colors.all |= (1 << 2);
2997                   break;
2998
2999                 case 24:
3000                   di->x11.colors.c24 = 1;
3001                   di->x11.colors.all |= (1 << 3);
3002                   break;
3003
3004                 case 32:
3005                   di->x11.colors.c32 = 1;
3006                   di->x11.colors.all |= (1 << 4);
3007                   break;
3008               }
3009             }
3010             free_str_list(sl1);
3011           }
3012           else if(i == 7) {
3013             di->x11.dacspeed = strtol(sl->str, NULL, 10);
3014           }
3015           else if(i == 8) {
3016             di->x11.script = new_str(sl->str);
3017           }
3018         }
3019         for(i = 0, sl = di->x11.hddb1; sl; sl = sl->next, i++) {
3020           add_str_list(&di->x11.raw, sl->str);
3021         }
3022 #if 0
3023         // ######## for compatibility
3024         for(sl = hd->requires; sl; sl = sl->next) {
3025           add_str_list(&di->x11.packages, sl->str);
3026         }
3027 #endif
3028         break;
3029
3030       default:
3031         break;
3032     }
3033   }
3034
3035   di = hd->driver_info;
3036   if(di && di->any.type == di_x11 && !hd_probe_feature(hd_data, pr_ignx11)) {
3037     cmd = get_cmdline(hd_data, "x11");
3038     if(cmd && *cmd->str) {
3039       hd->driver_info = reorder_x11(di, cmd->str);
3040     }
3041     free_str_list(cmd);
3042   }
3043 }
3044
3045
3046 char *module_cmd(hd_t *hd, char *cmd)
3047 {
3048   static char buf[256];
3049   char *s = buf;
3050   int idx, ofs;
3051   hd_res_t *res;
3052
3053   // skip inactive PnP cards
3054   // ##### Really necessary here?
3055   if(
3056     hd->is.isapnp &&
3057     hd->detail &&
3058     hd->detail->isapnp.data &&
3059     !(hd->detail->isapnp.data->flags & (1 << isapnp_flag_act))
3060   ) return NULL;
3061
3062   *buf = 0;
3063   while(*cmd) {
3064     if(sscanf(cmd, "<io%u>%n", &idx, &ofs) >= 1) {
3065       if((res = get_res(hd, res_io, idx))) {
3066         s += sprintf(s, "0x%02"PRIx64, res->io.base);
3067         cmd += ofs;
3068       }
3069       else {
3070         return NULL;
3071       }
3072     }
3073     else if(sscanf(cmd, "<irq%u>%n", &idx, &ofs) >= 1) {
3074       if((res = get_res(hd, res_irq, idx))) {
3075         s += sprintf(s, "%u", res->irq.base);
3076         cmd += ofs;
3077       }
3078       else {
3079         return NULL;
3080       }
3081     }
3082     else {
3083       *s++ = *cmd++;
3084     }
3085
3086     if(s - buf > (int) sizeof buf - 20) return NULL;
3087   }
3088
3089   *s = 0;
3090   return buf;
3091 }
3092
3093
3094 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
3095 char *hid_tag_name(int tag)
3096 {
3097   return (unsigned) tag < sizeof hid_tag_names / sizeof *hid_tag_names ? hid_tag_names[tag] : "";
3098 }
3099
3100 char *hid_tag_name2(int tag)
3101 {
3102   return (unsigned) tag < sizeof hid_tag_names2 / sizeof *hid_tag_names2 ? hid_tag_names2[tag] : "";
3103 }
3104
3105 /** @} */
3106