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