Initial revision
[opensuse:hwinfo.git] / src / hd / hdx.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 #include "hd.h"
6 #include "hd_int.h"
7 #include "hdx.h"
8
9 #ifdef SHORT_LIST
10 #define ID_LIST id_list_r
11 #else
12 #define ID_LIST id_list
13 #endif
14 extern char *ID_LIST[];
15
16 // we are somewhat slower if we define this
17 #undef NO_DUP_ENTRIES
18
19 typedef struct {
20   unsigned val0;
21   char *name;
22 } val1_name_t;
23
24 typedef struct {
25   unsigned val0, val1;
26   char *name;
27 } val2_name_t;
28
29 typedef struct {
30   unsigned val0, val1, val2;
31   char *drv;
32   char *name;
33 } val3_name_t;
34
35 typedef struct {
36   unsigned val0, val1, val2, val3, val4;
37   char *drv;
38   char *name;
39 } val5_name_t;
40
41
42 static int no_init = 1;
43
44 static val1_name_t* bus_name_lst = NULL;
45 static unsigned bus_names = 0;
46
47 static val1_name_t* class_name_lst = NULL;
48 static unsigned class_names = 0;
49
50 static val2_name_t* sub_class_name_lst = NULL;
51 static unsigned sub_class_names = 0;
52
53 static val1_name_t* vendor_name_lst = NULL;
54 static unsigned vendor_names = 0;
55
56 static val3_name_t* device_name_lst = NULL;
57 static unsigned device_names = 0;
58
59 static val5_name_t* sub_device_name_lst = NULL;
60 static unsigned sub_device_names = 0;
61
62 static void init_hdx(void);
63
64 static char *next_line(char *buf, int buf_size, FILE *f, int line);
65
66 char *bus_name(unsigned bus)
67 {
68   int i;
69
70   if(no_init) init_hdx();
71
72   for(i = 0; i < bus_names; i++) {
73     if(bus_name_lst[i].val0 == bus) return bus_name_lst[i].name;
74   }
75
76   return NULL;
77 }
78
79 int bus_number(char *bus_name)
80 {
81   int i;
82
83   if(no_init) init_hdx();
84
85   for(i = 0; i < bus_names; i++) {
86     if(!strcmp(bus_name, bus_name_lst[i].name)) return bus_name_lst[i].val0;
87   }
88
89   return -1;
90 }
91
92 char *base_class_name(unsigned bc)
93 {
94   int i;
95
96   if(no_init) init_hdx();
97
98   for(i = 0; i < class_names; i++) {
99     if(class_name_lst[i].val0 == bc) return class_name_lst[i].name;
100   }
101
102   return NULL;
103 }
104
105 int base_class_number(char *bc_name)
106 {
107   int i;
108
109   if(no_init) init_hdx();
110
111   for(i = 0; i < class_names; i++) {
112     if(!strcmp(bc_name, class_name_lst[i].name)) return class_name_lst[i].val0;
113   }
114
115   return -1;
116 }
117
118 char *sub_class_name(unsigned bc, unsigned sc)
119 {
120   int i;
121
122   if(no_init) init_hdx();
123
124   for(i = 0; i < sub_class_names; i++) {
125     if(
126       sub_class_name_lst[i].val0 == sc &&
127       sub_class_name_lst[i].val1 == bc
128     ) return sub_class_name_lst[i].name;
129   }
130
131   return base_class_name(bc);
132 }
133
134 char *vendor_name(unsigned v)
135 {
136   int i;
137
138   if(no_init) init_hdx();
139
140   for(i = 0; i < vendor_names; i++) {
141     if(vendor_name_lst[i].val0 == v) return vendor_name_lst[i].name;
142   }
143
144   return NULL;
145 }
146
147 char *device_name(unsigned v, unsigned d)
148 {
149   int i;
150
151   if(no_init) init_hdx();
152
153   for(i = 0; i < device_names; i++) {
154     if(
155       device_name_lst[i].val0 == d &&
156       device_name_lst[i].val1 == v
157     ) return device_name_lst[i].name;
158   }
159
160   return NULL;
161 }
162
163 unsigned device_class(unsigned v, unsigned d)
164 {
165   int i;
166
167   if(no_init) init_hdx();
168
169   for(i = 0; i < device_names; i++) {
170     if(
171       device_name_lst[i].val0 == d &&
172       device_name_lst[i].val1 == v
173     ) return device_name_lst[i].val2;
174   }
175
176   return 0;
177 }
178
179 char *device_drv_name(unsigned v, unsigned d)
180 {
181   int i;
182
183   if(no_init) init_hdx();
184
185   for(i = 0; i < device_names; i++) {
186     if(
187       device_name_lst[i].val0 == d &&
188       device_name_lst[i].val1 == v
189     ) return device_name_lst[i].drv;
190   }
191
192   return NULL;
193 }
194
195 char *sub_device_name(unsigned v, unsigned d, unsigned sv, unsigned sd)
196 {
197   int i;
198
199   if(no_init) init_hdx();
200
201   for(i = 0; i < sub_device_names; i++) {
202     if(
203       sub_device_name_lst[i].val0 == sd &&
204       sub_device_name_lst[i].val1 == sv &&
205       sub_device_name_lst[i].val2 == d &&
206       sub_device_name_lst[i].val3 == v
207     ) return sub_device_name_lst[i].name;
208   }
209
210   /*
211    * If nothing was found, try dedicated subdevice entries.
212    */
213   for(i = 0; i < sub_device_names; i++) {
214     if(
215       sub_device_name_lst[i].val0 == sd &&
216       sub_device_name_lst[i].val1 == sv &&
217       sub_device_name_lst[i].val2 == 0 &&
218       sub_device_name_lst[i].val3 == 0
219     ) return sub_device_name_lst[i].name;
220   }
221
222   return NULL;          // or try device_name(sv, sd) ???
223 }
224
225 unsigned sub_device_class(unsigned v, unsigned d, unsigned sv, unsigned sd)
226 {
227   int i;
228
229   if(no_init) init_hdx();
230
231   for(i = 0; i < sub_device_names; i++) {
232     if(
233       sub_device_name_lst[i].val0 == sd &&
234       sub_device_name_lst[i].val1 == sv &&
235       sub_device_name_lst[i].val2 == d &&
236       sub_device_name_lst[i].val3 == v
237     ) return sub_device_name_lst[i].val4;
238   }
239
240   /*
241    * If nothing was found, try dedicated subdevice entries.
242    */
243   for(i = 0; i < sub_device_names; i++) {
244     if(
245       sub_device_name_lst[i].val0 == sd &&
246       sub_device_name_lst[i].val1 == sv &&
247       sub_device_name_lst[i].val2 == 0 &&
248       sub_device_name_lst[i].val3 == 0
249     ) return sub_device_name_lst[i].val4;
250   }
251
252   return 0;
253 }
254
255 char *sub_device_drv_name(unsigned v, unsigned d, unsigned sv, unsigned sd)
256 {
257   int i;
258
259   if(no_init) init_hdx();
260
261   for(i = 0; i < sub_device_names; i++) {
262     if(
263       sub_device_name_lst[i].val0 == sd &&
264       sub_device_name_lst[i].val1 == sv &&
265       sub_device_name_lst[i].val2 == d &&
266       sub_device_name_lst[i].val3 == v
267     ) return sub_device_name_lst[i].drv;
268   }
269
270   /*
271    * If nothing was found, try dedicated subdevice entries.
272    */
273   for(i = 0; i < sub_device_names; i++) {
274     if(
275       sub_device_name_lst[i].val0 == sd &&
276       sub_device_name_lst[i].val1 == sv &&
277       sub_device_name_lst[i].val2 == 0 &&
278       sub_device_name_lst[i].val3 == 0
279     ) return sub_device_name_lst[i].drv;
280   }
281
282   return NULL;          // or try device_drv_name(sv, sd) ???
283 }
284
285 char *next_line(char *buf, int buf_size, FILE *f, int line)
286 {
287   if(f) return fgets(buf, buf_size, f);
288   if(ID_LIST[line]) {
289     strncpy(buf, ID_LIST[line], buf_size);
290     buf[buf_size - 1] = 0;
291     return buf;
292   }
293
294   return NULL;
295 }
296
297 void init_hdx()
298 {
299   FILE *f;
300   char buf[256], buf2[256], buf3[10], cur_ent_type = 0;
301   unsigned u, u2, u3;
302   unsigned cur_ent_val = 0, cur_ent_val1 = 0;
303   int line = 0;
304
305   if(no_init < 0) return;
306   no_init = -1;
307
308   f = NULL;
309   if(
310     !(f = fopen(ID_LIST_NAME, "r")) &&
311     !(f = fopen(ID_LIST_NAME_FALLBACK, "r"))
312   );
313
314   while(next_line(buf, sizeof buf, f, line)) {
315     line++;
316
317     if(*buf == '\n' || *buf == '#' || *buf == ';') continue;
318
319     // device or subdevice entries
320     if(*buf == '\t') {
321       // subdevice entries
322       if(buf[1] == '\t') {
323         // EISA subdevice entries with class & subclass value
324         if(
325           cur_ent_type == 'v' &&
326           sscanf(buf, " %3s%x.%x %200[^\n]", buf3, &u, &u2, buf2) == 4
327         ) {
328           u3 = name2eisa_id(buf3);
329           add_sub_device_name(cur_ent_val, cur_ent_val1, u3, MAKE_EISA_ID(u), u2, buf2);
330           continue;
331         }
332
333         // EISA subdevice entries
334         if(
335           cur_ent_type == 'v' &&
336           sscanf(buf, " %3s%x %200[^\n]", buf3, &u, buf2) == 3
337         ) {
338           u3 = name2eisa_id(buf3);
339           add_sub_device_name(cur_ent_val, cur_ent_val1, u3, MAKE_EISA_ID(u), 0, buf2);
340           continue;
341         }
342
343         // subdevice entries
344         if(
345           cur_ent_type == 'V' &&
346           sscanf(buf, " %4x%4x %200[^\n]", &u, &u2, buf2) == 3
347         ) {
348           add_sub_device_name(cur_ent_val, cur_ent_val1, u2, u, 0, buf2);
349           continue;
350         }
351
352         fprintf(stderr, "oops3 at line %d\n", line);
353       }
354
355       // EISA device entries with class & subclass value
356       if(cur_ent_type == 'v' && sscanf(buf, " %x.%x %200[^\n]", &u, &u2, buf2) == 3) {
357         cur_ent_val1 = MAKE_EISA_ID(u);
358         add_device_name(cur_ent_val, cur_ent_val1, u2, buf2);
359         continue;
360       }
361
362       // EISA dedicated subdevice entries with class & subclass value
363       if(cur_ent_type == 's' && sscanf(buf, " %x.%x %200[^\n]", &u, &u2, buf2) == 3) {
364         add_sub_device_name(0, 0, cur_ent_val, MAKE_EISA_ID(u), u2, buf2);
365         continue;
366       }
367
368       // subclass, device or subdevice entries
369       if(sscanf(buf, " %x %200[^\n]", &u, buf2) == 2) {
370         switch(cur_ent_type) {
371           case 'C':
372             add_sub_class_name(cur_ent_val, u, buf2);
373             break;
374
375           case 'V':
376             cur_ent_val1 = u;
377             add_device_name(cur_ent_val, cur_ent_val1, 0, buf2);
378             break;
379
380           case 'S':
381             add_sub_device_name(0, 0, cur_ent_val, u, 0, buf2);
382             break;
383
384           case 'v':
385             cur_ent_val1 = MAKE_EISA_ID(u);
386             add_device_name(cur_ent_val, cur_ent_val1, 0, buf2);
387             break;
388
389           case 's':
390             add_sub_device_name(0, 0, cur_ent_val, MAKE_EISA_ID(u), 0, buf2);
391             break;
392
393           default:
394             fprintf(stderr, "oops2 at line %d\n", line);
395         }
396         continue;
397       }
398     }
399
400     // bus entries
401     if(sscanf(buf, "B %x %200[^\n]", &u, buf2) == 2) {
402       cur_ent_val = cur_ent_val1 = 0;
403       cur_ent_type = 'B';
404       add_bus_name(u, buf2);
405       continue;
406     }
407
408     // class entries
409     if(sscanf(buf, "C %x %200[^\n]", &u, buf2) == 2) {
410       cur_ent_val = cur_ent_val1 = 0;
411       cur_ent_type = 'C';
412       add_class_name(u, buf2);
413       cur_ent_val = u;
414       continue;
415     }
416
417     // EISA vendor entries
418     if((buf[3] == ' ' || buf[3] == '\t') && sscanf(buf, "%3s %200[^\n]", buf3, buf2) == 2) {
419       cur_ent_val = cur_ent_val1 = 0;
420       cur_ent_type = 'v';
421       u = name2eisa_id(buf3);
422       add_vendor_name(u, buf2);
423       cur_ent_val = u;
424       continue;
425     }
426
427     // PCI vendor entries
428     if(sscanf(buf, "%x %200[^\n]", &u, buf2) == 2) {
429       cur_ent_val = cur_ent_val1 = 0;
430       cur_ent_type = 'V';
431       add_vendor_name(u, buf2);
432       cur_ent_val = u;
433       continue;
434     }
435
436     // EISA dedicated subdevice entries
437     if((buf[5] == ' ' || buf[5] == '\t') && sscanf(buf, "S %3s %200[^\n]", buf3, buf2) == 2) {
438       cur_ent_val = cur_ent_val1 = 0;
439       cur_ent_type = 's';
440       u = name2eisa_id(buf3);
441       add_vendor_name(u, buf2);
442       cur_ent_val = u;
443       continue;
444     }
445
446     // PCI dedicated subdevice entries
447     if(sscanf(buf, "S %x %200[^\n]", &u, buf2) == 2) {
448       cur_ent_val = cur_ent_val1 = 0;
449       cur_ent_type = 'S';
450       add_vendor_name(u, buf2);
451       cur_ent_val = u;
452       continue;
453     }
454
455     fprintf(stderr, "oops at line %d\n", line);
456   }
457
458   if(f) fclose(f);  
459
460   no_init = 0;
461 }
462
463
464 /*
465  * b = bus
466  * c = class
467  * d = device
468  * v = vendor
469  * sc, sd, sv = sub...
470  */
471
472 void add_bus_name(unsigned b, char *s)
473 {
474 #ifdef NO_DUP_ENTRIES
475   if(bus_name(b)) return;
476 #endif
477
478   bus_name_lst = add_mem(bus_name_lst, sizeof *bus_name_lst, bus_names);
479   bus_name_lst[bus_names].val0 = b;
480   bus_name_lst[bus_names].name = new_str(s);
481   bus_names++;
482 }
483
484 void add_class_name(unsigned c, char *s)
485 {
486 #ifdef NO_DUP_ENTRIES
487   if(base_class_name(c)) return;
488 #endif
489
490   class_name_lst = add_mem(class_name_lst, sizeof *class_name_lst, class_names);
491   class_name_lst[class_names].val0 = c;
492   class_name_lst[class_names].name = new_str(s);
493   class_names++;
494 }
495
496 void add_sub_class_name(unsigned c, unsigned sc, char *s)
497 {
498 #ifdef NO_DUP_ENTRIES
499   if(sub_class_name(c, sc)) return;
500 #endif
501
502   sub_class_name_lst = add_mem(sub_class_name_lst, sizeof *sub_class_name_lst, sub_class_names);
503   sub_class_name_lst[sub_class_names].val0 = sc;
504   sub_class_name_lst[sub_class_names].val1 = c;
505   sub_class_name_lst[sub_class_names].name = new_str(s);
506   sub_class_names++;
507 }
508
509 void add_vendor_name(unsigned v, char *s)
510 {
511   // always block duplicate entries
512   if(vendor_name(v)) return;
513
514   vendor_name_lst = add_mem(vendor_name_lst, sizeof *vendor_name_lst, vendor_names);
515   vendor_name_lst[vendor_names].val0 = v;
516   vendor_name_lst[vendor_names].name = new_str(s);
517   vendor_names++;
518 }
519
520 void add_device_name(unsigned v, unsigned d, unsigned c, char *s)
521 {
522   char *t, *t1;
523
524 #ifdef NO_DUP_ENTRIES
525   if(device_name(v, d)) return;
526 #endif
527
528   device_name_lst = add_mem(device_name_lst, sizeof *device_name_lst, device_names);
529   device_name_lst[device_names].val0 = d;
530   device_name_lst[device_names].val1 = v;
531   device_name_lst[device_names].val2 = c;
532
533   if(*s == '[' && (t = index(s + 1, ']'))) {
534     if(t > s + 1) {
535       t1 =  new_mem(t - s);
536       memcpy(t1, s + 1, t - s - 1);
537       device_name_lst[device_names].drv = t1;
538     }
539     while(t[1] == ' ' || t[1] == '\t') t++;
540     s = t + 1;
541   }
542
543   device_name_lst[device_names].name = new_str(s);
544   device_names++;
545 }
546
547 void add_sub_device_name(unsigned v, unsigned d, unsigned sv, unsigned sd, unsigned c, char *s)
548 {
549   char *t, *t1;
550
551 #ifdef NO_DUP_ENTRIES
552   if(sub_device_name(v, d, sv, sd)) return;
553 #endif
554
555   sub_device_name_lst = add_mem(sub_device_name_lst, sizeof *sub_device_name_lst, sub_device_names);
556   sub_device_name_lst[sub_device_names].val0 = sd;
557   sub_device_name_lst[sub_device_names].val1 = sv;
558   sub_device_name_lst[sub_device_names].val2 = d;
559   sub_device_name_lst[sub_device_names].val3 = v;
560   sub_device_name_lst[sub_device_names].val4 = c;
561
562   if(*s == '[' && (t = index(s + 1, ']'))) {
563     if(t > s + 1) {
564       t1 =  new_mem(t - s);
565       memcpy(t1, s + 1, t - s - 1);
566       sub_device_name_lst[sub_device_names].drv = t1;
567     }
568     while(t[1] == ' ' || t[1] == '\t') t++;
569     s = t + 1;
570   }
571
572   sub_device_name_lst[sub_device_names].name = new_str(s);
573   sub_device_names++;
574 }
575