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