- adjust mouse detection to work with mice that do not use
[opensuse:hwinfo.git] / src / hd / int.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <sys/pci.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8
9 #include "hd.h"
10 #include "hd_int.h"
11 #include "int.h"
12 #include "edd.h"
13
14 /**
15  * @defgroup LIBHDint Internal utilities
16  * @ingroup libhdInternals
17  * @brief Internal utility functions
18  *
19  * @{
20  */
21
22 static void int_hotplug(hd_data_t *hd_data);
23 static void int_cdrom(hd_data_t *hd_data);
24 #if defined(__i386__) || defined (__x86_64__)
25 static int set_bios_id(hd_data_t *hd_data, hd_t *hd_ref, int bios_id);
26 static int bios_ctrl_order(hd_data_t *hd_data, unsigned *sctrl, int sctrl_len);
27 static void int_bios(hd_data_t *hd_data);
28 #endif
29 static void int_media_check(hd_data_t *hd_data);
30 static int contains_word(char *str, char *str2);
31 static int is_zip(hd_t *hd);
32 static void int_floppy(hd_data_t *hd_data);
33 static void int_fix_usb_scsi(hd_data_t *hd_data);
34 static void int_mouse(hd_data_t *hd_data);
35 static void new_id(hd_data_t *hd_data, hd_t *hd);
36 static void int_modem(hd_data_t *hd_data);
37 static void int_wlan(hd_data_t *hd_data);
38 static void int_udev(hd_data_t *hd_data);
39 static void int_devicenames(hd_data_t *hd_data);
40 #if defined(__i386__) || defined (__x86_64__)
41 static void int_softraid(hd_data_t *hd_data);
42 #endif
43 #if defined(__i386__) || defined (__x86_64__)
44 static void int_system(hd_data_t *hd_data);
45 static void int_legacy_geo(hd_data_t *hd_data);
46 #endif
47 static void int_find_parent(hd_data_t *hd_data);
48 static void int_add_driver_modules(hd_data_t *hd_data);
49 static void int_update_driver_data(hd_data_t *hd_data, hd_t *hd);
50
51
52 void hd_scan_int(hd_data_t *hd_data)
53 {
54   hd_t *hd;
55
56   if(!hd_probe_feature(hd_data, pr_int)) return;
57
58   hd_data->module = mod_int;
59
60   /* some clean-up */
61   remove_hd_entries(hd_data);
62
63   PROGRESS(2, 0, "cdrom");
64   int_cdrom(hd_data);
65
66   PROGRESS(3, 0, "media");
67   int_media_check(hd_data);
68
69   PROGRESS(4, 0, "floppy");
70   int_floppy(hd_data);
71
72 #if defined(__i386__) || defined (__x86_64__)
73   PROGRESS(5, 0, "edd");
74   assign_edd_info(hd_data);
75
76   PROGRESS(5, 1, "bios");
77   int_bios(hd_data);
78 #endif
79
80   PROGRESS(6, 0, "mouse");
81   int_mouse(hd_data);
82
83 #if defined(__i386__) || defined (__x86_64__)
84   PROGRESS(15, 0, "system info");
85   int_system(hd_data);
86 #endif
87
88   PROGRESS(7, 0, "hdb");
89   hd_data->flags.keep_kmods = 1;
90   for(hd = hd_data->hd; hd; hd = hd->next) {
91     hddb_add_info(hd_data, hd);
92   }
93   hd_data->flags.keep_kmods = 0;
94
95   PROGRESS(7, 1, "modules");
96   int_add_driver_modules(hd_data);
97
98   PROGRESS(8, 0, "usbscsi");
99   int_fix_usb_scsi(hd_data);
100
101   PROGRESS(9, 0, "hotplug");
102   int_hotplug(hd_data);
103
104   PROGRESS(10, 0, "modem");
105   int_modem(hd_data);
106
107   PROGRESS(11, 0, "wlan");
108   int_wlan(hd_data);
109
110   PROGRESS(12, 0, "udev");
111   int_udev(hd_data);
112
113   PROGRESS(13, 0, "device names");
114   int_devicenames(hd_data);
115
116 #if defined(__i386__) || defined (__x86_64__)
117   PROGRESS(14, 0, "soft raid");
118   int_softraid(hd_data);
119
120   PROGRESS(15, 0, "geo");
121   int_legacy_geo(hd_data);
122 #endif
123
124   PROGRESS(16, 0, "parent");
125   int_find_parent(hd_data);
126 }
127
128 /*
129  * Identify hotpluggable devices.
130  */
131 void int_hotplug(hd_data_t *hd_data)
132 {
133   hd_t *hd;
134   hal_prop_t *prop;
135
136   for(hd = hd_data->hd; hd; hd = hd->next) {
137     if(hd->bus.id == bus_usb || hd->usb_guid) {
138       hd->hotplug = hp_usb;
139     }
140     if((prop = hal_get_bool(hd->hal_prop, "storage.hotpluggable")) && prop->val.b) {
141       hd->is.hotpluggable = 1;
142     }
143   }
144 }
145
146 /*
147  * Add more info to CDROM entries.
148  */
149 void int_cdrom(hd_data_t *hd_data)
150 {
151   hd_t *hd;
152   hal_prop_t *prop;
153
154   for(hd = hd_data->hd; hd; hd = hd->next) {
155     if(
156       hd->base_class.id == bc_storage_device &&
157       hd->sub_class.id == sc_sdev_cdrom
158     ) {
159       if(!hd->prog_if.id && hd->device.name && strstr(hd->device.name, "DVD")) hd->is.dvd = 1;
160
161       if((prop = hal_get_bool(hd->hal_prop, "storage.cdrom.cdr")) && prop->val.b) {
162         hd->is.cdr = 1;
163       }
164       if((prop = hal_get_bool(hd->hal_prop, "storage.cdrom.cdrw")) && prop->val.b) {
165         hd->is.cdrw = 1;
166       }
167       if((prop = hal_get_bool(hd->hal_prop, "storage.cdrom.dvdr")) && prop->val.b) {
168         hd->is.dvdr = 1;
169       }
170       if((prop = hal_get_bool(hd->hal_prop, "storage.cdrom.dvdrw")) && prop->val.b) {
171         hd->is.dvdrw = 1;
172       }
173       if((prop = hal_get_bool(hd->hal_prop, "storage.cdrom.dvdram")) && prop->val.b) {
174         hd->is.dvdram = 1;
175       }
176       if((prop = hal_get_bool(hd->hal_prop, "storage.cdrom.dvdplusr")) && prop->val.b) {
177         hd->is.dvdpr = 1;
178       }
179       if((prop = hal_get_bool(hd->hal_prop, "storage.cdrom.dvdplusrw")) && prop->val.b) {
180         hd->is.dvdprw = 1;
181       }
182       if((prop = hal_get_bool(hd->hal_prop, "storage.cdrom.dvdplusrdl")) && prop->val.b) {
183         hd->is.dvdprdl = 1;
184       }
185
186       if(hd->is.dvd) hd->prog_if.id = 3;
187     }
188   }
189 }
190
191 #if defined(__i386__) || defined (__x86_64__)
192
193 int set_bios_id(hd_data_t *hd_data, hd_t *hd_ref, int bios_id)
194 {
195   int found = 0;
196   hd_t *hd;
197
198   if(!hd_ref || !hd_ref->unix_dev_name) return 0;
199
200   for(hd = hd_data->hd; hd; hd = hd->next) {
201     if(
202       hd->base_class.id == bc_storage_device &&
203       hd->sub_class.id == sc_sdev_disk &&
204       hd->unix_dev_name &&
205       !strcmp(hd->unix_dev_name, hd_ref->unix_dev_name)
206     ) {
207       str_printf(&hd->rom_id, 0, "0x%02x", bios_id);
208       found = 1;
209     }
210   }
211
212   return found;
213 }
214
215
216 int bios_ctrl_order(hd_data_t *hd_data, unsigned *sctrl, int sctrl_len)
217 {
218   hd_t *hd;
219   bios_info_t *bt;
220   int i, j, k, sctrl2_len = 0;
221   unsigned pci_slot, pci_func;
222   unsigned *sctrl2 = NULL, *sctrl3 = NULL;
223   int order_info = 0;
224
225   for(bt = NULL, hd = hd_data->hd; hd; hd = hd->next) {
226     if(
227       hd->base_class.id == bc_internal &&
228       hd->sub_class.id == sc_int_bios &&
229       hd->detail &&
230       hd->detail->type == hd_detail_bios &&
231       (bt = hd->detail->bios.data)
232     ) {
233       break;
234     }
235   }
236
237   if(!bt || !bt->bios32.ok || !bt->bios32.compaq) return 0;
238
239   sctrl2 = new_mem((sizeof bt->bios32.cpq_ctrl / sizeof *bt->bios32.cpq_ctrl) * sizeof *sctrl2);
240
241   for(i = 0; (unsigned) i < sizeof bt->bios32.cpq_ctrl / sizeof *bt->bios32.cpq_ctrl; i++) {
242     if(
243       bt->bios32.cpq_ctrl[i].id &&
244       !(bt->bios32.cpq_ctrl[i].misc & 0x40)     /* bios support ??????? */
245     ) {
246       pci_slot = PCI_SLOT(bt->bios32.cpq_ctrl[i].devfn) + (bt->bios32.cpq_ctrl[i].bus << 8);
247       pci_func = PCI_FUNC(bt->bios32.cpq_ctrl[i].devfn);
248       for(hd = hd_data->hd; hd; hd = hd->next) {
249         if(hd->bus.id == bus_pci && hd->slot == pci_slot && hd->func == pci_func) {
250           sctrl2[sctrl2_len++] = hd->idx;
251           break;
252         }
253       }
254     }
255   }
256
257   if(sctrl2_len) order_info = 1;
258
259   for(i = 0; i < sctrl2_len; i++) {
260     ADD2LOG("  bios ord %d: %d\n", i, sctrl2[i]);
261   }
262
263   /* sort list */
264
265   sctrl3 = new_mem(sctrl_len * sizeof *sctrl3);
266
267   k = 0 ;
268   for(i = 0; i < sctrl2_len; i++) {
269     for(j = 0; j < sctrl_len; j++) {
270       if(sctrl[j] == sctrl2[i]) {
271         sctrl3[k++] = sctrl[j];
272         sctrl[j] = 0;
273         break;
274       }
275     }
276   }
277
278   for(i = 0; i < sctrl_len; i++) {
279     if(sctrl[i] && k < sctrl_len) sctrl3[k++] = sctrl[i];
280   }
281
282   memcpy(sctrl, sctrl3, sctrl_len * sizeof *sctrl);
283
284   free_mem(sctrl2);
285   free_mem(sctrl3);
286
287   return order_info;
288 }
289
290
291 void int_bios(hd_data_t *hd_data)
292 {
293   hd_t *hd, *hd_boot;
294   unsigned *sctrl, *sctrl2;
295   int sctrl_len, i, j;
296   int bios_id, list_sorted;
297
298   /* don't do anything if there is useful edd info */
299   if(hd_data->flags.edd_used) return;
300
301   for(i = 0, hd = hd_data->hd; hd; hd = hd->next) {
302     if(
303       hd->base_class.id == bc_storage_device &&
304       hd->sub_class.id == sc_sdev_disk
305     ) {
306       i++;
307     }
308   }
309
310   if(!i) return;
311
312   sctrl = new_mem(i * sizeof *sctrl);
313
314   /* sctrl: list of storage controllers with disks */
315
316   for(sctrl_len = 0, hd = hd_data->hd; hd; hd = hd->next) {
317     if(
318       hd->base_class.id == bc_storage_device &&
319       hd->sub_class.id == sc_sdev_disk
320     ) {
321       for(i = 0; i < sctrl_len; i++) {
322         if(sctrl[i] == hd->attached_to) break;
323       }
324       if(i == sctrl_len) sctrl[sctrl_len++] = hd->attached_to;
325     }
326   }
327
328   /* sort list, if possible */
329
330   list_sorted = bios_ctrl_order(hd_data, sctrl, sctrl_len);
331
332   hd_boot = hd_get_device_by_idx(hd_data, hd_boot_disk(hd_data, &i));
333
334   /* if we know the boot device, make this controller the first */
335
336   if(hd_boot && hd_boot->attached_to && i == 1) {
337     for(i = 0; i < sctrl_len; i++) {
338       if(sctrl[i] == hd_boot->attached_to) break;
339     }
340     if(i < sctrl_len) {
341       sctrl2 = new_mem(sctrl_len * sizeof *sctrl2);
342       *sctrl2 = hd_boot->attached_to;
343       for(i = 0, j = 1; i < sctrl_len; i++) {
344         if(sctrl[i] != hd_boot->attached_to) sctrl2[j++] = sctrl[i];
345       }
346       free_mem(sctrl);
347       sctrl = sctrl2;
348     }
349   }
350   else {
351     hd_boot = NULL;
352   }
353
354   if(hd_boot) ADD2LOG("  bios boot dev: %d\n", hd_boot->idx);
355   for(i = 0; i < sctrl_len; i++) {
356     ADD2LOG("  bios ctrl %d: %d\n", i, sctrl[i]);
357   }
358
359   /* remove existing entries */
360
361   for(hd = hd_data->hd; hd; hd = hd->next) {
362     if(
363       hd->base_class.id == bc_storage_device &&
364       hd->sub_class.id == sc_sdev_disk
365     ) {
366       hd->rom_id = free_mem(hd->rom_id);
367     }
368   }
369
370   if(!list_sorted && !hd_boot && sctrl_len > 1) {
371     /* we have no info at all */
372     sctrl_len = 0;
373   }
374   else if(!list_sorted && hd_boot && sctrl_len > 2) {
375     /* we know which controller has the boot device */
376     sctrl_len = 1;
377   }
378
379   bios_id = 0x80;
380
381   /* rely on it */
382
383   if(hd_boot) {
384     bios_id += set_bios_id(hd_data, hd_boot, bios_id);
385   }
386
387   /* assign all the others */
388
389   for(i = 0; i < sctrl_len; i++) {
390     for(hd = hd_data->hd; hd; hd = hd->next) {
391       if(
392         hd->base_class.id == bc_storage_device &&
393         hd->sub_class.id == sc_sdev_disk &&
394         hd->attached_to == sctrl[i] &&
395         !hd->rom_id
396       ) {
397         bios_id += set_bios_id(hd_data, hd, bios_id);
398       }
399     }
400   }
401
402   free_mem(sctrl);
403 }
404
405
406 #if 0
407 void int_bios(hd_data_t *hd_data)
408 {
409   hd_t *hd, *hd_boot;
410   int i, start, bios = 0x80;
411   int ide_1st;
412   char ide_name[] = "/dev/hda";
413   char scsi_name[] = "/dev/sda";
414   char *s;
415
416   hd_boot = hd_get_device_by_idx(hd_data, hd_boot_disk(hd_data, &i));
417
418   if(hd_boot) {
419     free_mem(hd_boot->rom_id);
420     hd_boot->rom_id = new_str("0x80");
421   }
422
423   if(!hd_boot || i != 1) return;
424
425   if(strstr(hd_boot->unix_dev_name, "/dev/sd") == hd_boot->unix_dev_name) {
426     ide_1st = 0;
427     start = hd_boot->unix_dev_name[sizeof "/dev/sd" - 1] - 'a';
428   }
429   else if(strstr(hd_boot->unix_dev_name, "/dev/hd") == hd_boot->unix_dev_name) {
430     ide_1st = 1;
431     start = hd_boot->unix_dev_name[sizeof "/dev/hd" - 1] - 'a';
432   }
433   else {
434     return;
435   }
436
437   if(start < 0) return;
438
439   for(hd = hd_data->hd; hd; hd = hd->next) {
440     if(
441       hd->base_class.id == bc_storage_device &&
442       hd->sub_class.id == sc_sdev_disk
443     ) {
444       hd->rom_id = free_mem(hd->rom_id);
445     }
446   }
447
448   s = ide_1st ? ide_name : scsi_name;
449
450   for(i = start; i < 26; i++) {
451     s[strlen(s) - 1] = 'a' + i;
452     bios += set_bios_id(hd_data, s, bios);
453   }
454
455   for(i = 0; i < start; i++) {
456     s[strlen(s) - 1] = 'a' + i;
457     bios += set_bios_id(hd_data, s, bios);
458   }
459
460   s = ide_1st ? scsi_name : ide_name;
461
462   for(i = 0; i < 26; i++) {
463     s[strlen(s) - 1] = 'a' + i;
464     bios += set_bios_id(hd_data, s, bios);
465   }
466 }
467 #endif  /* 0 */
468 #endif  /* defined(__i386__) || defined (__x86_64__) */
469
470 /*
471  * Try to read block 0 for block devices.
472  */
473 void int_media_check(hd_data_t *hd_data)
474 {
475   hd_t *hd;
476   int i, j = 0;
477
478   for(hd = hd_data->hd; hd; hd = hd->next) {
479     if(!hd_report_this(hd_data, hd)) continue;
480     if(
481       hd->base_class.id == bc_storage_device &&
482       (
483         /* hd->sub_class.id == sc_sdev_cdrom || */ /* cf. cdrom.c */
484         hd->sub_class.id == sc_sdev_disk ||
485         hd->sub_class.id == sc_sdev_floppy
486       ) &&
487       hd->unix_dev_name &&
488       !hd->block0 &&
489       !hd->is.notready &&
490       hd->status.available != status_no
491     ) {
492       i = 5;
493       PROGRESS(4, ++j, hd->unix_dev_name);
494       hd->block0 = read_block0(hd_data, hd->unix_dev_name, &i);
495       hd->is.notready = hd->block0 ? 0 : 1;
496 #if defined(__i386__) || defined(__x86_64__)
497       if(hd->block0) {
498         ADD2LOG("  mbr sig: 0x%08x\n", edd_disk_signature(hd));
499       }
500 #endif
501     }
502   }
503 }
504
505
506 /*
507  * Check if str has str2 in it.
508  */
509 int contains_word(char *str, char *str2)
510 {
511   int i, len, len2, found = 0;
512   char *s;
513
514   if(!str2 || !*str2 || !str || !*str) return 0;
515
516   str = new_str(str);
517
518   len = strlen(str);
519   len2 = strlen(str2);
520
521   for(i = 0; i < len; i++) {
522     if(str[i] >= 'a' && str[i] <= 'z') str[i] -= 'a' - 'A';
523   }
524
525   for(s = str; (s = strstr(s, str2)); s++) {
526     if(
527       (s == str || s[-1] < 'A' || s[-1] > 'Z') &&
528       (s[len2] < 'A' || s[len2] > 'Z')
529     ) {
530       found = 1;
531       break;
532     }
533   }
534
535   free_mem(str);
536
537   return found;
538 }
539
540
541 /*
542  * Check for zip drive.
543  */
544 int is_zip(hd_t *hd)
545 {
546   if(
547     hd->base_class.id == bc_storage_device &&
548     (
549       hd->sub_class.id == sc_sdev_disk ||
550       hd->sub_class.id == sc_sdev_floppy
551     )
552   ) {
553     if(
554       (
555         contains_word(hd->vendor.name, "IOMEGA") ||
556         contains_word(hd->sub_vendor.name, "IOMEGA") ||
557         contains_word(hd->device.name, "IOMEGA") ||
558         contains_word(hd->sub_device.name, "IOMEGA")
559       ) && (
560         contains_word(hd->device.name, "ZIP") ||
561         contains_word(hd->sub_device.name, "ZIP")
562       )
563     ) {
564       return 1;
565     }
566   }
567
568   return 0;
569 }
570
571
572 /*
573  * Turn some drives into floppies.
574  */
575 void int_floppy(hd_data_t *hd_data)
576 {
577   hd_t *hd;
578   hd_res_t *res;
579
580   for(hd = hd_data->hd; hd; hd = hd->next) {
581     if(is_zip(hd)) hd->is.zip = 1;
582     if(
583       hd->base_class.id == bc_storage_device &&
584       hd->sub_class.id == sc_sdev_disk
585     ) {
586       if(hd->is.zip) {
587         hd->sub_class.id = sc_sdev_floppy;
588         new_id(hd_data, hd);
589       }
590       else {
591         /* make everything a floppy that is 1440k */
592         for(res = hd->res; res; res = res->next) {
593           if(
594             res->any.type == res_size &&
595             res->size.unit == size_unit_sectors &&
596             res->size.val1 == 2880 &&
597             res->size.val2 == 512
598           ) {
599             hd->sub_class.id = sc_sdev_floppy;
600             new_id(hd_data, hd);
601             break;
602           }
603         }
604       }
605     }
606   }
607 }
608
609
610 /*
611  * Remove usb entries that are handled by usb-storage.
612  */
613 void int_fix_usb_scsi(hd_data_t *hd_data)
614 {
615   hd_t *hd_scsi, *hd_usb;
616
617   for(hd_usb = hd_data->hd; hd_usb; hd_usb= hd_usb->next) {
618     if(
619       hd_usb->bus.id == bus_usb &&
620       hd_usb->sysfs_id &&
621       search_str_list(hd_usb->drivers, "usb-storage")
622     ) {
623       for(hd_scsi = hd_data->hd; hd_scsi; hd_scsi = hd_scsi->next) {
624         if(
625           hd_scsi->bus.id == bus_scsi &&
626           hd_scsi->sysfs_device_link &&
627           search_str_list(hd_scsi->drivers, "usb-storage")
628         ) {
629           if(!strncmp(hd_scsi->sysfs_device_link, hd_usb->sysfs_id, strlen(hd_usb->sysfs_id))) {
630             hd_set_hw_class(hd_scsi, hw_usb);
631
632             free_mem(hd_scsi->unique_id);
633             hd_scsi->unique_id = hd_usb->unique_id;
634             hd_usb->unique_id = NULL;
635
636             add_res_entry(&hd_scsi->res, hd_usb->res);
637             hd_usb->res = NULL;
638
639             if(!hd_scsi->modalias) {
640               hd_scsi->modalias = hd_usb->modalias;
641               hd_usb->modalias = NULL;
642             }
643
644             if(!hd_scsi->vendor.id) hd_scsi->vendor.id = hd_usb->vendor.id;
645             if(!hd_scsi->device.id) hd_scsi->device.id = hd_usb->device.id;
646
647             if(!hd_scsi->serial) {
648               hd_scsi->serial = hd_usb->serial;
649               hd_usb->serial = NULL;
650             }
651
652             if(!hd_scsi->driver_info) {
653               hd_scsi->driver_info = hd_usb->driver_info;
654               hd_usb->driver_info = NULL;
655             }
656
657             new_id(hd_data, hd_scsi);
658
659             hd_usb->tag.remove = 1;
660           }
661         }
662       }
663     }
664   }
665
666   remove_tagged_hd_entries(hd_data);
667 }
668
669
670 /*
671  * Improve mouse info.
672  */
673 void int_mouse(hd_data_t *hd_data)
674 {
675   hd_t *hd;
676   bios_info_t *bt = NULL;
677
678 #if 0
679   str_list_t *sl;
680   int is_mouse;
681
682   for(hd = hd_data->hd; hd; hd = hd->next) {
683     if(
684       hd->bus.id != bus_usb ||
685       hd->base_class.id != bc_mouse ||
686       hd->sub_class.id != sc_mou_usb ||
687       !search_str_list(hd->drivers, "usbhid")
688     ) continue;
689
690     is_mouse = 0;
691
692     for(sl = hd->unix_dev_names; sl; sl = sl->next) {
693       if(strstr(sl->str, "/mice") || strstr(sl->str, "/mouse")) {
694         is_mouse = 1;
695         break;
696       }
697     }
698
699     if(!is_mouse) {
700       if(
701         (hd->unix_dev_name && strstr(hd->unix_dev_name, "/mice")) ||
702         (hd->unix_dev_name2 && strstr(hd->unix_dev_name2, "/mouse"))
703       ) {
704         is_mouse = 1;
705       }
706     }
707
708     /* not really a mouse */
709     if(!is_mouse) {
710       hd->base_class.id = 0;
711       hd->sub_class.id = 0;
712       hd->compat_vendor.id = 0;
713       hd->compat_device.id = 0;
714     }
715   }
716 #endif
717
718   for(hd = hd_data->hd; hd; hd = hd->next) {
719     if(
720       hd->detail &&
721       hd->detail->type == hd_detail_bios &&
722       (bt = hd->detail->bios.data) &&
723       bt->mouse.type
724     ) break;
725   }
726
727   if(!bt) return;
728
729   for(hd = hd_data->hd; hd; hd = hd->next) {
730     if(
731       hd->base_class.id == bc_mouse &&
732       hd->sub_class.id == sc_mou_ps2 &&
733       hd->bus.id == bt->mouse.bus &&
734       hd->vendor.id == MAKE_ID(TAG_SPECIAL, 0x0200) &&
735       hd->device.id == MAKE_ID(TAG_SPECIAL, 0x0002)
736     ) {
737       hd->vendor.name = free_mem(hd->vendor.name);
738       hd->device.name = free_mem(hd->device.name);
739       hd->vendor.id = hd->device.id = 0;
740 #if 0
741       hd->vendor.id = bt->mouse.compat_vend;
742       hd->device.id = bt->mouse.compat_dev;
743 #else
744       hd->vendor.name = new_str(bt->mouse.vendor);
745       hd->device.name = new_str(bt->mouse.type);
746       hd->compat_vendor.id = bt->mouse.compat_vend;
747       hd->compat_device.id = bt->mouse.compat_dev;
748 #endif
749       new_id(hd_data, hd);
750     }
751   }
752 }
753
754
755 void new_id(hd_data_t *hd_data, hd_t *hd)
756 {
757 #if 0
758   hd->unique_id = free_mem(hd->unique_id);
759   hd->unique_id1 = free_mem(hd->unique_id1);
760   hd->old_unique_id = free_mem(hd->old_unique_id);
761   hd_add_id(hd_data, hd);
762 #endif
763 }
764  
765
766 /*
767  * Assign device names to (win-)modems.
768  */
769 void int_modem(hd_data_t *hd_data)
770 {
771   hd_t *hd;
772   char *s;
773   hd_dev_num_t dev_num = { type: 'c', range: 1 };
774   unsigned cnt4 = 0;
775
776   for(hd = hd_data->hd; hd; hd = hd->next) {
777     if(
778       hd->base_class.id == bc_modem
779     ) {
780       s = NULL;
781       switch(hd->sub_class.id) {
782         case sc_mod_win1:
783           s = new_str("/dev/ham");
784           dev_num.major = 240;
785           dev_num.minor = 1;
786           break;
787         case sc_mod_win2:
788           s = new_str("/dev/536ep0");
789           dev_num.major = 240;
790           dev_num.minor = 1;
791           break;
792         case sc_mod_win3:
793           s = new_str("/dev/ttyLT0");
794           dev_num.major = 62;
795           dev_num.minor = 64;
796           break;
797         case sc_mod_win4:
798           if(cnt4 < 4) {
799             str_printf(&s, 0, "/dev/ttySL%u", cnt4);
800             dev_num.major = 212;
801             dev_num.minor = cnt4++;
802           }
803           break;
804       }
805       if(s) {
806         free_mem(hd->unix_dev_name);
807         hd->unix_dev_name = s;
808         s = NULL;
809         hd->unix_dev_num = dev_num;
810       }
811     }
812   }
813 }
814
815
816 /*
817  * Look for WLAN cards by checking module info.
818  */
819 void int_wlan(hd_data_t *hd_data)
820 {
821   hd_t *hd;
822   driver_info_t *di;
823   str_list_t *sl;
824   unsigned u, found;
825   static char *wlan_mods[] = {
826     "acx",
827     "acx_pci",
828     "airo",
829     "airo_cs",
830     "aironet4500_card",
831     "aironet4500_cs",
832     "airport",
833     "adm8211",
834     "arlan",
835     "at76c503",
836     "at76c503-i3861",
837     "at76c503-i3863",
838     "at76c503-rfmd",
839     "at76c503-rfmd-acc",
840     "at76c505-rfmd",
841     "at76c505-rfmd2958",
842     "ath_hal",
843     "ath_pci",
844     "atmel",
845     "atmel_cs",
846     "atmel_pci",
847     "hermes",
848     "hostap",
849     "hostap_pci",
850     "hostap_plx",
851     "ipw2100",
852     "ipw2200",
853     "ipw3945",
854     "iwl3945",
855     "iwl4965",
856     "netwave_cs",
857     "orinoco_cs",
858     "orinoco_pci",
859     "orinoco_plx",
860     "p80211",
861     "prism2_cs",
862     "prism2_pci",
863     "prism2_plx",
864     "prism2_usb",
865     "prism54",
866     "r8180",
867     "ray_cs",
868     "rt2400",
869     "rt2500",
870     "rt2570",
871     "rt2400pci",
872     "rt2500pci",
873     "rt2500usb",
874     "usbdfu",
875     "wavelan",
876     "wavelan_cs",
877     "wl3501_cs",
878     "zd1201"
879   };
880
881   for(hd = hd_data->hd; hd; hd = hd->next) {
882     for(found = 0, di = hd->driver_info; di && !found; di = di->next) {
883       if(di->any.type == di_module) {
884         for(sl = di->module.names; sl && !found; sl = sl->next) {
885           for(u = 0; u < sizeof wlan_mods / sizeof *wlan_mods; u++) {
886             if(!strcmp(sl->str, wlan_mods[u])) {
887               found = 1;
888               break;
889             }
890           }
891         }
892       }
893     }
894     if(found) {
895       hd->is.wlan = 1;
896       hd->base_class.id = bc_network;
897       hd->sub_class.id = 0x82;                  /* wlan */
898       hddb_add_info(hd_data, hd);
899     }
900   }
901 }
902
903
904 /*
905  * Add udev info.
906  */
907 void int_udev(hd_data_t *hd_data)
908 {
909   hd_udevinfo_t *ui;
910   hd_t *hd;
911   str_list_t *sl;
912
913   if(!hd_data->udevinfo) read_udevinfo(hd_data);
914
915   if(!hd_data->udevinfo) return;
916
917   for(hd = hd_data->hd; hd; hd = hd->next) {
918     if(!hd->unix_dev_names && hd->unix_dev_name) {
919       add_str_list(&hd->unix_dev_names, hd->unix_dev_name);
920     }
921
922     if(!hd->sysfs_id) continue;
923
924     for(ui = hd_data->udevinfo; ui; ui = ui->next) {
925       if(ui->name && !strcmp(ui->sysfs, hd->sysfs_id)) {
926         if(!search_str_list(hd->unix_dev_names, ui->name)) {
927           add_str_list(&hd->unix_dev_names, ui->name);
928         }
929         for(sl = ui->links; sl; sl = sl->next) {
930           if(!search_str_list(hd->unix_dev_names, sl->str)) {
931             add_str_list(&hd->unix_dev_names, sl->str);
932           }
933         }
934
935         if(!hd->unix_dev_name) {
936           sl = hd->unix_dev_names;
937
938           if(hd_data->flags.udev) {
939             /* use first link as canonical device name */
940             if(ui->links) sl = sl->next;
941           }
942
943           hd->unix_dev_name = new_str(sl->str);
944         }
945
946         break;
947       }
948     }
949   }
950
951   for(hd = hd_data->hd; hd; hd = hd->next) {
952     if(!hd->unix_dev_names) continue;
953
954     for(ui = hd_data->udevinfo; ui; ui = ui->next) {
955       if(search_str_list(hd->unix_dev_names, ui->name)) {
956         for(sl = ui->links; sl; sl = sl->next) {
957           if(!search_str_list(hd->unix_dev_names, sl->str)) {
958             add_str_list(&hd->unix_dev_names, sl->str);
959           }
960         }
961       }
962     }
963   }
964 }
965
966
967 /*
968  * If hd->unix_dev_name is not in hd->unix_dev_names, add it.
969  */
970 void int_devicenames(hd_data_t *hd_data)
971 {
972   hd_t *hd;
973
974   for(hd = hd_data->hd; hd; hd = hd->next) {
975     if(
976       hd->unix_dev_name &&
977       !search_str_list(hd->unix_dev_names, hd->unix_dev_name)
978     ) {
979       add_str_list(&hd->unix_dev_names, hd->unix_dev_name);
980     }
981   }
982 }
983
984
985 #if defined(__i386__) || defined (__x86_64__)
986 /*
987  * Tag ide soft raid disks.
988  */
989 void int_softraid(hd_data_t *hd_data)
990 {
991   hd_t *hd;
992   str_list_t *raid, *sl, *raid_sysfs = NULL, *sl1;
993   size_t len;
994   char *s;
995
996   if(hd_data->flags.fast) return;
997
998   for(hd = hd_data->hd; hd; hd = hd->next) {
999     if(
1000       hd->base_class.id == bc_storage_device &&
1001       hd->status.available != status_no
1002     ) break;
1003   }
1004
1005   /* no disks -> no check necessary */
1006   if(!hd) return;
1007   
1008   raid = read_file("| /sbin/dmraid -rc 2>/dev/null", 0, 0);
1009
1010   for(sl = raid; sl; sl = sl->next) {
1011     s = *sl->str ? strchr(sl->str + 1, '/') : NULL;
1012     if(s) {
1013       sl1 = add_str_list(&raid_sysfs, NULL);
1014       str_printf(&sl1->str, 0, "/block%s", s);
1015       len = strlen(sl1->str);
1016       if(len) sl1->str[len - 1] = 0;
1017     }
1018   }
1019
1020   free_str_list(raid);
1021
1022   ADD2LOG("----- soft raid devices -----\n");
1023   for(sl = raid_sysfs; sl; sl = sl->next) {
1024     ADD2LOG("  %s\n", sl->str);
1025   }
1026   ADD2LOG("----- soft raid devices end -----\n");
1027
1028   for(hd = hd_data->hd; hd; hd = hd->next) {
1029     if(search_str_list(raid_sysfs, hd->sysfs_id)) {
1030       hd->is.softraiddisk = 1;
1031     }
1032   }
1033
1034   free_str_list(raid_sysfs);
1035
1036 }
1037
1038
1039 /*
1040  *
1041  */
1042 void int_system(hd_data_t *hd_data)
1043 {
1044   hd_t *hd_sys;
1045   hd_smbios_t *sm;
1046   struct {
1047     unsigned notebook:1;
1048     enum { v_none = 0, v_ibm = 1, v_toshiba, v_sony } vendor;
1049   } is = { };
1050   char *s;
1051   struct stat sbuf;
1052
1053   for(hd_sys = hd_data->hd; hd_sys; hd_sys = hd_sys->next) {
1054     if(
1055       hd_sys->base_class.id == bc_internal &&
1056       hd_sys->sub_class.id == sc_int_sys
1057     ) break;
1058   }
1059
1060   if(!hd_sys) return;
1061
1062   if(
1063     hd_sys->vendor.name &&
1064     !strncasecmp(hd_sys->vendor.name, "sony", sizeof "sony" - 1)
1065   ) {
1066     is.vendor = v_sony;
1067   }
1068
1069   if(
1070     hd_sys->device.name &&
1071     !strncmp(hd_sys->device.name, "PCG-", sizeof "PCG-" - 1)
1072   ) {
1073     is.notebook = 1;
1074   }
1075
1076   for(sm = hd_data->smbios; sm; sm = sm->next) {
1077     if(
1078       sm->any.type == sm_sysinfo &&
1079       sm->sysinfo.manuf &&
1080       !strcasecmp(sm->sysinfo.manuf, "ibm")
1081     ) {
1082       is.vendor = v_ibm;
1083     }
1084
1085     if(
1086       sm->any.type == sm_sysinfo &&
1087       sm->sysinfo.manuf &&
1088       !strcasecmp(sm->sysinfo.manuf, "toshiba")
1089     ) {
1090       is.vendor = v_toshiba;
1091
1092       if(!hd_sys->device.name && !hd_sys->device.id && sm->sysinfo.product) {
1093         hd_sys->device.name = new_str(sm->sysinfo.product);
1094       }
1095       if(!hd_sys->vendor.name && !hd_sys->vendor.id) {
1096         hd_sys->vendor.name = new_str("Toshiba");
1097       }
1098     }
1099
1100     if(
1101       sm->any.type == sm_sysinfo &&
1102       sm->sysinfo.manuf &&
1103       !strncasecmp(sm->sysinfo.manuf, "sony", sizeof "sony" - 1)
1104     ) {
1105       is.vendor = v_sony;
1106
1107       if(!hd_sys->device.name && !hd_sys->device.id && sm->sysinfo.product) {
1108         hd_sys->device.name = new_str(sm->sysinfo.product);
1109         if(
1110           (s = strchr(hd_sys->device.name, '(')) &&
1111           hd_sys->device.name[strlen(hd_sys->device.name) - 1] == ')'
1112         ) {
1113           *s = 0;
1114         }
1115       }
1116       if(!hd_sys->vendor.name && !hd_sys->vendor.id) {
1117         hd_sys->vendor.name = new_str("Sony");
1118       }
1119     }
1120
1121     if(
1122       sm->any.type == sm_chassis &&
1123       (
1124         (sm->chassis.ch_type.id >= 8 && sm->chassis.ch_type.id <= 11) ||
1125         sm->chassis.ch_type.id == 14
1126       )
1127     ) {
1128       is.notebook = 1;
1129     }
1130   }
1131
1132   ADD2LOG(
1133     "  system type:%s%s\n",
1134     is.vendor == v_ibm ? " ibm" :
1135       is.vendor == v_toshiba ? " toshiba" :
1136       is.vendor == v_sony ? " sony" :
1137       "",
1138     is.notebook ? " notebook" : ""
1139   );
1140
1141   if(is.notebook && is.vendor) {
1142     hd_sys->compat_vendor.id = MAKE_ID(TAG_SPECIAL, 0xf001);
1143     hd_sys->compat_device.id = MAKE_ID(TAG_SPECIAL, is.vendor);
1144   }
1145
1146   hd_sys->is.with_acpi = stat("/proc/acpi", &sbuf) ? 0 : 1;
1147   ADD2LOG("  acpi: %d\n", hd_sys->is.with_acpi);
1148 }
1149
1150
1151 void int_legacy_geo(hd_data_t *hd_data)
1152 {
1153   hd_t *hd;
1154   hd_res_t *res;
1155   int id;
1156   char *s;
1157   edd_info_t *ei;
1158
1159   if(!hd_data->edd) return;
1160
1161   for(hd = hd_data->hd; hd; hd = hd->next) {
1162     if(
1163       hd->base_class.id == bc_storage_device &&
1164       hd->sub_class.id == sc_sdev_disk &&
1165       hd->rom_id
1166     ) {
1167       id = strtol(hd->rom_id, &s, 0) - 0x80;
1168       if(*s || id < 0 || id >= sizeof hd_data->edd / sizeof *hd_data->edd) continue;
1169
1170       ei = hd_data->edd + id;
1171
1172       if(ei->edd.cyls) {
1173         res = add_res_entry(&hd->res, new_mem(sizeof *res));
1174         res->disk_geo.type = res_disk_geo;
1175         res->disk_geo.cyls = ei->edd.cyls;
1176         res->disk_geo.heads = ei->edd.heads;
1177         res->disk_geo.sectors = ei->edd.sectors;
1178         res->disk_geo.size = ei->sectors;
1179         res->disk_geo.geotype = geo_bios_edd;
1180       }
1181
1182       if(ei->legacy.cyls) {
1183         res = add_res_entry(&hd->res, new_mem(sizeof *res));
1184         res->disk_geo.type = res_disk_geo;
1185         res->disk_geo.cyls = ei->legacy.cyls;
1186         res->disk_geo.heads = ei->legacy.heads;
1187         res->disk_geo.sectors = ei->legacy.sectors;
1188         res->disk_geo.geotype = geo_bios_legacy;
1189       }
1190
1191     }
1192   }
1193 }
1194 #endif
1195
1196
1197 void int_find_parent(hd_data_t *hd_data)
1198 {
1199   hd_t *hd, *hd2;
1200
1201   for(hd = hd_data->hd; hd; hd = hd->next) {
1202     if(hd->attached_to || !hd->parent_udi) continue;
1203
1204     for(hd2 = hd_data->hd; hd2; hd2 = hd2->next) {
1205       if(!hd2->udi) continue;
1206       if(!strcmp(hd->parent_udi, hd2->udi)) {
1207         hd->attached_to = hd2->idx;
1208         break;
1209       }
1210     }
1211   }
1212 }
1213
1214
1215 void int_add_driver_modules(hd_data_t *hd_data)
1216 {
1217   hd_t *hd;
1218
1219   hd_sysfs_driver_list(hd_data);
1220
1221   for(hd = hd_data->hd; hd; hd = hd->next) {
1222     int_update_driver_data(hd_data, hd);
1223   }
1224 }
1225
1226
1227 void int_update_driver_data(hd_data_t *hd_data, hd_t *hd)
1228 {
1229   hd_sysfsdrv_t *sf;
1230   str_list_t *sl;
1231
1232   hd->driver_modules = free_str_list(hd->driver_modules);
1233
1234   for(sl = hd->drivers; sl; sl = sl->next) {
1235     for(sf = hd_data->sysfsdrv; sf; sf = sf->next) {
1236       if(sf->module && !strcmp(sf->driver, sl->str)) {
1237         add_str_list(&hd->driver_modules, sf->module);
1238       }
1239     }
1240   }
1241
1242   hd->driver = free_mem(hd->driver);
1243   hd->driver_module = free_mem(hd->driver_module);
1244
1245   if(hd->drivers && hd->drivers->str) {
1246     hd->driver = new_str(hd->drivers->str);
1247
1248     for(sf = hd_data->sysfsdrv; sf; sf = sf->next) {
1249       if(sf->module && !strcmp(sf->driver, hd->driver)) {
1250         hd->driver_module = new_str(sf->module);
1251       }
1252     }
1253   }
1254 }
1255
1256
1257 /*
1258  * Add driver data, if it is missing.
1259  *
1260  * Interface function, don't use internally.
1261  */
1262 void hd_add_driver_data(hd_data_t *hd_data, hd_t *hd)
1263 {
1264   char *s;
1265
1266   if(hd->drivers) return;
1267
1268   hd_sysfs_driver_list(hd_data);
1269
1270   s = hd_sysfs_find_driver(hd_data, hd->sysfs_id, 1);
1271   if(s) add_str_list(&hd->drivers, s);
1272
1273   int_update_driver_data(hd_data, hd);
1274 }
1275
1276 /** @} */
1277