Initial revision
[opensuse:hwinfo.git] / src / hd / util.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <linux/pci.h>
5
6 #include "hd.h"
7 #include "hd_int.h"
8 #include "hdx.h"
9 #include "util.h"
10
11 #define MOD_INFO_SEP            '|'
12 #define MOD_INFO_SEP_STR        "|"
13
14
15 static hd_res_t *get_res(hd_t *h, enum resource_types t, unsigned index);
16 static char *module_cmd(hd_t *, char *);
17
18 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
19  * various functions not *directly* related to hardware probing
20  *
21  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
22  */
23
24
25 /*
26  * Scan the hardware list for CD-ROMs with a given volume_id. Start
27  * searching at the start'th entry.
28  *
29  * Returns a pointer to a hardware entry (hw_t *) or NULL on failure.
30  */
31
32 // ####### replace or fix this!!!
33
34 hw_t *find_cdrom_volume(const char *volume_id, int *start)
35 {
36   int i;
37   cdrom_info_t *ci;
38   hw_t *h;
39
40   for(i = *start; i < hw_len; i++) {
41     h = hw + i;
42     if(
43       h->base_class == bc_storage_device &&
44       h->sub_class == sc_sdev_cdrom /* &&
45       (h->ext_flags & (1 << cdrom_flag_media_probed)) */
46     ) {
47       /* ok, found a CDROM device... */
48       ci = h->ext;
49       /* ... now compare the volume id */
50       if(
51         ci &&
52         (!volume_id || !strncmp(ci->volume, volume_id, strlen(volume_id)))
53       ) {
54         *start = i + 1;
55         return h;
56       }
57     }
58   }
59
60   return NULL;  /* CD not found :-( */
61 }
62
63
64 /*
65  * Reads the driver info.
66  *
67  * If the driver is a module, checks if the module is already loaded.
68  *
69  * If the command line returned is the empty string (""), we could not
70  * figure out what to do.
71  */
72 driver_info_t *get_driver_info(hd_t *h)
73 {
74   char *s = NULL, *s1, *t, *s0 = NULL;
75   char cmd[256], *cmd_ptr;
76   driver_info_t *mi = new_mem(sizeof *mi);
77   char *fields[32];
78   int i;
79   unsigned u1, u2;
80
81   if(h->sub_vend || h->sub_dev) {
82     s = sub_device_drv_name(h->vend, h->dev, h->sub_vend, h->sub_dev);
83   }
84
85   if(!s && (h->vend || h->dev)) {
86     s = device_drv_name(h->vend, h->dev);
87   }
88
89   if(!s) return free_mem(mi);
90
91   s0 = new_str(s);
92   s = s0;
93
94   /* ok, there is a module entry */
95   *(cmd_ptr = cmd) = 0;
96
97   t = "";
98   if(*s && s[1] == MOD_INFO_SEP) {
99     switch(*s) {
100       case 'i':
101         t = "insmod";
102         mi->type = di_module;
103         break;          /* insmod */
104
105       case 'M':         /* conf.modules entry */
106         mi->module.autoload = 1;
107       case 'm':
108         s1 = s + 2;
109         if(strsep(&s1, MOD_INFO_SEP_STR) && s1 && *s1) {
110           i = 0; t = s1;
111           while(t[i]) {
112             if(t[i] == '\\') {
113               switch(t[i + 1]) {
114                 case 'n':
115                   *t = '\n'; i++;
116                   break;
117
118                 case 't':
119                   *t = '\t'; i++;
120                   break;
121
122                 case '\\':
123                   *t = '\\'; i++;
124                   break;
125
126                 default:
127                   *t = t[i];
128               }
129             }
130             else {
131               *t = t[i];
132             }
133             t++;
134           }
135           *t = 0;
136           mi->module.conf = new_str(s1);
137         }
138         t = "modprobe";
139         mi->type = di_module;
140         break;
141
142       case 'p':         /* for mouse driver info */
143         mi->type = di_mouse;
144         break;
145
146       case 'x':         /* for X servers */
147         mi->type = di_x11;
148         break;
149
150       case 'd':         /* for displays */
151         mi->type = di_display;
152         break;
153
154       default:
155         s0 = free_mem(s0);
156         return free_mem(mi);
157     }
158     s += s[1] == MOD_INFO_SEP ? 2 : 1;
159   }
160   else {
161     s0 = free_mem(s0);
162     return free_mem(mi);
163   }
164
165   memset(fields, 0, sizeof fields);
166   // split the fields
167   for(i = 1, *fields = s1 = s; i < sizeof fields / sizeof *fields - 1; i++) {
168     if(strsep(&s1, MOD_INFO_SEP_STR) && s1 && *s1) {
169       fields[i] = s1;
170     }
171     else {
172       break;
173     }
174   }
175
176   if(mi->type == di_module) {
177     // ##### s1 may be NULL !!!!   #####
178     snprintf(cmd, sizeof cmd, "%s %s", t, s1 = module_cmd(h, s));
179     if(s1) mi->module.load_cmd = new_str(cmd);
180     s1 = s; strsep(&s1, " \t");
181     mi->module.name = new_str(s);
182     mi->module.is_active = module_is_active(mi->module.name);
183   }
184
185   if(mi->type == di_mouse) {
186     if(fields[0] && *fields[0]) mi->mouse.xf86 = new_str(fields[0]);
187     if(fields[1] && *fields[1]) mi->mouse.gpm = new_str(fields[1]);
188   }
189
190   if(mi->type == di_x11) {
191     if(fields[0] && *fields[0]) mi->x11.server = new_str(fields[0]);
192     if(fields[1] && *fields[1]) mi->x11.x3d = new_str(fields[1]);
193
194     if(fields[2] && *fields[2]) {
195       mi->x11.colors.all = strtol(fields[2], NULL, 16);
196       if(mi->x11.colors.all & (1 << 0)) mi->x11.colors.c8 = 1;
197       if(mi->x11.colors.all & (1 << 1)) mi->x11.colors.c15 = 1;
198       if(mi->x11.colors.all & (1 << 2)) mi->x11.colors.c16 = 1;
199       if(mi->x11.colors.all & (1 << 3)) mi->x11.colors.c24 = 1;
200       if(mi->x11.colors.all & (1 << 4)) mi->x11.colors.c32 = 1;
201     }
202     if(fields[3] && *fields[3]) mi->x11.dacspeed = strtol(fields[3], NULL, 10);
203   }
204
205   if(mi->type == di_display) {
206     if(fields[0] && *fields[0] && sscanf(fields[0], "%ux%u", &u1, &u2) == 2) {
207       mi->display.width = u1;
208       mi->display.height = u2;
209     }
210
211     if(fields[1] && *fields[1]  && sscanf(fields[1], "%u-%u", &u1, &u2) == 2) {
212       mi->display.min_vsync = u1;
213       mi->display.max_vsync = u2;
214     }
215
216     if(fields[2] && *fields[2]  && sscanf(fields[2], "%u-%u", &u1, &u2) == 2) {
217       mi->display.min_hsync = u1;
218       mi->display.max_hsync = u2;
219     }
220
221     if(fields[3] && *fields[3]  && sscanf(fields[3], "%u", &u1) == 1) {
222       mi->display.bandwidth = u1;
223     }
224   }
225
226   s0 = free_mem(s0);
227   return mi;
228 }
229
230
231 int module_is_active(char *mod)
232 {
233   FILE *f;
234   char buf[256], *s;
235
236   if(!(f = fopen(PROC_MODULES, "r"))) return 0;
237
238   while(fgets(buf, sizeof buf, f)) {
239     s = buf;
240     strsep(&s, " \t");
241     if(!strcmp(mod, buf)) {
242       fclose(f);
243       return 1;
244     }
245   }
246
247   fclose(f);
248
249   return 0;
250 }
251
252 hd_res_t *get_res(hd_t *hd, enum resource_types t, unsigned index)
253 {
254   hd_res_t *res;
255
256   for(res = hd->res; res; res = res->next) {
257     if(res->any.type == t) {
258       if(!index) return res;
259       index--;
260     }
261   }
262
263   return NULL;
264 }
265
266
267 char *module_cmd(hd_t *h, char *cmd)
268 {
269   static char buf[256];
270   char *s = buf;
271   int idx, ofs;
272   hd_res_t *res;
273
274   // skip inactive PnP cards
275   // ##### Really necessary here?
276   if(
277     h->detail &&
278     h->detail->type == hd_detail_isapnp &&
279     !(h->detail->isapnp.data->flags & (1 << isapnp_flag_act))
280   ) return NULL;
281
282   *buf = 0;
283   while(*cmd) {
284     if(sscanf(cmd, "<io%u>%n", &idx, &ofs) >= 1) {
285       if((res = get_res(h, res_io, idx))) {
286         s += sprintf(s, "0x%02"HD_LL"x", res->io.base);
287         cmd += ofs;
288       }
289       else {
290         return NULL;
291       }
292     }
293     else if(sscanf(cmd, "<irq%u>%n", &idx, &ofs) >= 1) {
294       if((res = get_res(h, res_irq, idx))) {
295         s += sprintf(s, "%u", res->irq.base);
296         cmd += ofs;
297       }
298       else {
299         return NULL;
300       }
301     }
302     else {
303       *s++ = *cmd++;
304     }
305
306     if(s - buf > sizeof buf - 20) return NULL;
307   }
308
309   *s = 0;
310   return buf;
311 }
312
313
314 /*
315  * cf. /usr/src/linux/drivers/block/ide-pci.c
316  */
317 int needs_eide_kernel()
318 {
319   int i, j;
320   hw_t *h;
321   static unsigned ids[][2] = {
322     { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561 },
323     { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1 },
324     { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246 },
325     { PCI_VENDOR_ID_PROMISE, 0x4d38 },          // PCI_DEVICE_ID_PROMISE_20262
326     { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513 },
327     { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621 },
328     { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558 },
329     { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C825 },
330     { PCI_VENDOR_ID_TEKRAM, PCI_DEVICE_ID_TEKRAM_DC290 },
331     { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410 },
332     { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415 }
333   };
334
335   for(i = 0; i < hw_len; i++) {
336     h = hw + i;
337     if(h->bus == bus_pci) {
338       for(j = 0; j < sizeof ids / sizeof *ids; j++) {
339         if(h->vend == ids[j][0] && h->dev == ids[j][1]) return 1;
340       }
341     }
342   }
343
344   return 0;
345 }
346
347 /*
348  * cf. pcmcia-cs-3.1.1:cardmgr/probe.c
349  */
350 int has_pcmcia_support()
351 {
352   int i, j;
353   hw_t *h;
354   static unsigned ids[][2] = {
355     { 0x1013, 0x1100 },
356     { 0x1013, 0x1110 },
357     { 0x10b3, 0xb106 },
358     { 0x1180, 0x0465 },
359     { 0x1180, 0x0466 },
360     { 0x1180, 0x0475 },
361     { 0x1180, 0x0476 },
362     { 0x1180, 0x0478 },
363     { 0x104c, 0xac12 },
364     { 0x104c, 0xac13 },
365     { 0x104c, 0xac15 },
366     { 0x104c, 0xac16 },
367     { 0x104c, 0xac17 },
368     { 0x104c, 0xac19 },
369     { 0x104c, 0xac1a },
370     { 0x104c, 0xac1d },
371     { 0x104c, 0xac1f },
372     { 0x104c, 0xac1b },
373     { 0x104c, 0xac1c },
374     { 0x104c, 0xac1e },
375     { 0x104c, 0xac51 },
376     { 0x1217, 0x6729 },
377     { 0x1217, 0x673a },
378     { 0x1217, 0x6832 },
379     { 0x1217, 0x6836 },
380     { 0x1179, 0x0603 },
381     { 0x1179, 0x060a },
382     { 0x1179, 0x060f },
383     { 0x119b, 0x1221 },
384     { 0x8086, 0x1221 }
385   };
386
387   for(i = 0; i < hw_len; i++) {
388     h = hw + i;
389     if(h->bus == bus_pci) {
390       for(j = 0; j < sizeof ids / sizeof *ids; j++) {
391         if(h->vend == ids[j][0] && h->dev == ids[j][1]) return 1;
392       }
393     }
394   }
395
396   return 0;
397 }
398
399
400