]>
Commit | Line | Data |
---|---|---|
93afd047 MT |
1 | #include <stdio.h> |
2 | #include <stdlib.h> | |
3 | #include <string.h> | |
4 | #include <unistd.h> | |
5 | #include <fcntl.h> | |
6 | #include <sys/types.h> | |
7 | #include <sys/stat.h> | |
8 | #include <sys/ioctl.h> | |
9 | ||
10 | #include <linux/hdreg.h> | |
11 | ||
12 | #include "hd.h" | |
13 | #include "hd_int.h" | |
14 | #include "misc.h" | |
15 | #include "klog.h" | |
16 | ||
17 | static void read_ioports(misc_t *m); | |
18 | static void read_dmas(misc_t *m); | |
19 | static void read_irqs(misc_t *m); | |
20 | static int active_vga_card(hd_t *); | |
21 | ||
22 | static void dump_misc_proc_data(hd_data_t *hd_data); | |
23 | static void dump_misc_data(hd_data_t *hd_data); | |
24 | ||
25 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
26 | * misc info | |
27 | * | |
28 | * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
29 | */ | |
30 | ||
31 | void hd_scan_misc(hd_data_t *hd_data) | |
32 | { | |
33 | hd_t *hd; | |
34 | hd_res_t *res; | |
35 | int fd, i; | |
36 | char *s = NULL; | |
37 | bios_info_t *bt = NULL; | |
38 | char par[] = "parport0"; | |
39 | int fd_ser0, fd_ser1; | |
40 | ||
41 | if(!hd_probe_feature(hd_data, pr_misc)) return; | |
42 | ||
43 | hd_data->module = mod_misc; | |
44 | ||
45 | /* some clean-up */ | |
46 | remove_hd_entries(hd_data); | |
47 | hd_data->misc = free_misc(hd_data->misc); | |
48 | ||
49 | PROGRESS(9, 0, "kernel log"); | |
50 | read_klog(hd_data); | |
51 | if((hd_data->debug & HD_DEB_MISC)) dump_klog(hd_data); | |
52 | ||
53 | PROGRESS(1, 0, "misc data"); | |
54 | hd_data->misc = new_mem(sizeof *hd_data->misc); | |
55 | ||
56 | /* this is enough to load the module */ | |
57 | fd_ser0 = fd_ser1 = -1; | |
58 | ||
59 | #if !defined(__sparc__) | |
60 | /* On sparc, the close needs too long */ | |
61 | if(hd_probe_feature(hd_data, pr_misc_serial)) { | |
62 | PROGRESS(1, 1, "open serial"); | |
63 | fd_ser0 = open("/dev/ttyS0", O_RDONLY | O_NONBLOCK); | |
64 | fd_ser1 = open("/dev/ttyS1", O_RDONLY | O_NONBLOCK); | |
65 | /* keep the devices open until the resources have been read */ | |
66 | } | |
67 | #endif | |
68 | ||
69 | /* this is enough to load the module */ | |
70 | if(!hd_data->flags.no_parport && hd_probe_feature(hd_data, pr_misc_par)) { | |
71 | PROGRESS(1, 2, "open parallel"); | |
72 | /* what can the BIOS tell us? */ | |
73 | for(hd = hd_data->hd; hd; hd = hd->next) { | |
74 | if( | |
75 | hd->base_class.id == bc_internal && | |
76 | hd->sub_class.id == sc_int_bios && | |
77 | hd->detail && | |
78 | hd->detail->type == hd_detail_bios && | |
79 | hd->detail->bios.data | |
80 | ) break; | |
81 | } | |
82 | if(hd) { | |
83 | bt = hd->detail->bios.data; | |
84 | if(bt->par_port0) { | |
85 | str_printf(&s, 0, "io=0x%x", bt->par_port0); | |
86 | if(bt->par_port1) { | |
87 | str_printf(&s, -1, ",0x%x", bt->par_port1); | |
88 | if(bt->par_port2) str_printf(&s, -1, ",0x%x", bt->par_port2); | |
89 | } | |
90 | str_printf(&s, -1, " irq=none,none,none"); | |
91 | } | |
92 | unload_module(hd_data, "parport_probe"); | |
93 | unload_module(hd_data, "lp"); | |
94 | unload_module(hd_data, "parport_pc"); | |
95 | unload_module(hd_data, "parport"); | |
96 | ||
97 | /* now load it with the right io */ | |
98 | load_module(hd_data, "parport"); | |
99 | load_module_with_params(hd_data, "parport_pc", s); | |
100 | free_mem(s); | |
101 | } | |
102 | /* now load the rest of the modules */ | |
103 | fd = open("/dev/lp0", O_RDONLY | O_NONBLOCK); | |
104 | if(fd >= 0) close(fd); | |
105 | } | |
106 | ||
107 | /* | |
108 | * floppy driver resources are allocated only temporarily, | |
109 | * so we access it just before we read the resources | |
110 | */ | |
111 | if(hd_probe_feature(hd_data, pr_misc_floppy)) { | |
112 | /* look for a floppy *device* entry... */ | |
113 | for(hd = hd_data->hd; hd; hd = hd->next) { | |
114 | if( | |
115 | hd->base_class.id == bc_storage_device && | |
116 | hd->sub_class.id == sc_sdev_floppy && | |
117 | hd->unix_dev_name && | |
118 | !strncmp(hd->unix_dev_name, "/dev/fd", sizeof "/dev/fd" - 1) | |
119 | ) { | |
120 | ||
121 | PROGRESS(1, 3, "read floppy"); | |
122 | i = 5; | |
123 | hd->block0 = read_block0(hd_data, hd->unix_dev_name, &i); | |
124 | hd->is.notready = hd->block0 ? 0 : 1; | |
125 | if(i < 0) { | |
126 | hd->tag.remove = 1; | |
127 | ADD2LOG("misc.floppy: removing floppy entry %u (timed out)\n", hd->idx); | |
128 | } | |
129 | ||
130 | if(!hd->is.notready) { | |
131 | struct hd_geometry geo; | |
132 | int fd; | |
133 | unsigned size, blk_size = 0x200; | |
134 | ||
135 | fd = open(hd->unix_dev_name, O_RDONLY | O_NONBLOCK); | |
136 | if(fd >= 0) { | |
137 | if(!ioctl(fd, HDIO_GETGEO, &geo)) { | |
138 | ADD2LOG("floppy ioctl(geo) ok\n"); | |
139 | res = add_res_entry(&hd->res, new_mem(sizeof *res)); | |
140 | res->disk_geo.type = res_disk_geo; | |
141 | res->disk_geo.cyls = geo.cylinders; | |
142 | res->disk_geo.heads = geo.heads; | |
143 | res->disk_geo.sectors = geo.sectors; | |
144 | res->disk_geo.geotype = geo_logical; | |
145 | size = geo.cylinders * geo.heads * geo.sectors; | |
146 | for(res = hd->res; res; res = res->next) { | |
147 | if(res->any.type == res_size && res->size.unit == size_unit_sectors) { | |
148 | res->size.val1 = size; res->size.val2 = blk_size; | |
149 | break; | |
150 | } | |
151 | } | |
152 | if(!res) { | |
153 | res = add_res_entry(&hd->res, new_mem(sizeof *res)); | |
154 | res->size.type = res_size; | |
155 | res->size.unit = size_unit_sectors; | |
156 | res->size.val1 = size; res->size.val2 = blk_size; | |
157 | } | |
158 | } | |
159 | close(fd); | |
160 | } | |
161 | } | |
162 | ||
163 | break; | |
164 | } | |
165 | } | |
166 | remove_tagged_hd_entries(hd_data); | |
167 | } | |
168 | ||
169 | PROGRESS(2, 1, "io"); | |
170 | read_ioports(hd_data->misc); | |
171 | ||
172 | PROGRESS(2, 2, "dma"); | |
173 | read_dmas(hd_data->misc); | |
174 | ||
175 | PROGRESS(2, 3, "irq"); | |
176 | read_irqs(hd_data->misc); | |
177 | ||
178 | if((hd_data->debug & HD_DEB_MISC)) dump_misc_proc_data(hd_data); | |
179 | ||
180 | if(fd_ser0 >= 0) close(fd_ser0); | |
181 | if(fd_ser1 >= 0) close(fd_ser1); | |
182 | ||
183 | /* now create some system generic entries */ | |
184 | ||
185 | /* FPU */ | |
186 | PROGRESS(3, 0, "FPU"); | |
187 | res = NULL; | |
188 | gather_resources(hd_data->misc, &res, "fpu", 0); | |
189 | if(res) { | |
190 | hd = add_hd_entry(hd_data, __LINE__, 0); | |
191 | hd->base_class.id = bc_internal; | |
192 | hd->sub_class.id = sc_int_fpu; | |
193 | hd->res = res; | |
194 | } | |
195 | ||
196 | /* DMA */ | |
197 | PROGRESS(3, 1, "DMA"); | |
198 | res = NULL; | |
199 | gather_resources(hd_data->misc, &res, "dma1", 0); | |
200 | gather_resources(hd_data->misc, &res, "dma2", 0); | |
201 | gather_resources(hd_data->misc, &res, "dma page reg", 0); | |
202 | gather_resources(hd_data->misc, &res, "cascade", W_DMA); | |
203 | if(res) { | |
204 | hd = add_hd_entry(hd_data, __LINE__, 0); | |
205 | hd->base_class.id = bc_system; | |
206 | hd->sub_class.id = sc_sys_dma; | |
207 | hd->res = res; | |
208 | } | |
209 | ||
210 | /* PIC */ | |
211 | PROGRESS(3, 2, "PIC"); | |
212 | res = NULL; | |
213 | gather_resources(hd_data->misc, &res, "pic1", 0); | |
214 | gather_resources(hd_data->misc, &res, "pic2", 0); | |
215 | gather_resources(hd_data->misc, &res, "cascade", W_IRQ); | |
216 | if(res) { | |
217 | hd = add_hd_entry(hd_data, __LINE__, 0); | |
218 | hd->base_class.id = bc_system; | |
219 | hd->sub_class.id = sc_sys_pic; | |
220 | hd->res = res; | |
221 | } | |
222 | ||
223 | /* timer */ | |
224 | PROGRESS(3, 3, "timer"); | |
225 | res = NULL; | |
226 | gather_resources(hd_data->misc, &res, "timer", 0); | |
227 | if(res) { | |
228 | hd = add_hd_entry(hd_data, __LINE__, 0); | |
229 | hd->base_class.id = bc_system; | |
230 | hd->sub_class.id = sc_sys_timer; | |
231 | hd->res = res; | |
232 | } | |
233 | ||
234 | /* real time clock */ | |
235 | PROGRESS(3, 4, "RTC"); | |
236 | res = NULL; | |
237 | gather_resources(hd_data->misc, &res, "rtc", 0); | |
238 | if(res) { | |
239 | hd = add_hd_entry(hd_data, __LINE__, 0); | |
240 | hd->base_class.id = bc_system; | |
241 | hd->sub_class.id = sc_sys_rtc; | |
242 | hd->res = res; | |
243 | } | |
244 | ||
245 | /* keyboard */ | |
246 | res = NULL; | |
247 | gather_resources(hd_data->misc, &res, "keyboard", 0); | |
248 | if(res) { | |
249 | hd = add_hd_entry(hd_data, __LINE__, 0); | |
250 | hd->base_class.id = bc_input; | |
251 | hd->sub_class.id = sc_inp_keyb; | |
252 | hd->res = res; | |
253 | } | |
254 | ||
255 | /* parallel ports */ | |
256 | for(i = 0; i < 1; i++, par[sizeof par - 2]++) { | |
257 | res = NULL; | |
258 | gather_resources(hd_data->misc, &res, par, 0); | |
259 | if(res) { | |
260 | hd = add_hd_entry(hd_data, __LINE__, 0); | |
261 | hd->base_class.id = bc_comm; | |
262 | hd->sub_class.id = sc_com_par; | |
263 | str_printf(&hd->unix_dev_name, 0, "/dev/lp%d", i); | |
264 | hd->res = res; | |
265 | } | |
266 | } | |
267 | ||
268 | /* floppy controller */ | |
269 | res = NULL; | |
270 | gather_resources(hd_data->misc, &res, "floppy", 0); | |
271 | gather_resources(hd_data->misc, &res, "floppy DIR", 0); | |
272 | if(res) { | |
273 | /* look for an existing entry */ | |
274 | for(hd = hd_data->hd; hd; hd = hd->next) { | |
275 | if(hd->base_class.id == bc_storage && hd->sub_class.id == sc_sto_floppy) break; | |
276 | } | |
277 | ||
278 | /* missing, so create one */ | |
279 | if(!hd) { | |
280 | hd = add_hd_entry(hd_data, __LINE__, 0); | |
281 | hd->base_class.id = bc_storage; | |
282 | hd->sub_class.id = sc_sto_floppy; | |
283 | } | |
284 | ||
285 | hd->res = res; | |
286 | } | |
287 | ||
288 | /* | |
289 | * look for PS/2 port | |
290 | * | |
291 | * The catch is, that sometimes /dev/psaux is accessible only for root, | |
292 | * so the open() may fail but there are irq events registered. | |
293 | * | |
294 | */ | |
295 | fd = open(DEV_PSAUX, O_RDONLY | O_NONBLOCK); | |
296 | if(fd >= 0) close(fd); | |
297 | ||
298 | res = NULL; | |
299 | gather_resources(hd_data->misc, &res, "PS/2 Mouse", 0); | |
300 | ||
301 | if(res || fd >= 0) { | |
302 | hd = add_hd_entry(hd_data, __LINE__, 0); | |
303 | hd->base_class.id = bc_ps2; | |
304 | ||
305 | if(res) { | |
306 | hd->res = res; | |
307 | } | |
308 | } | |
309 | } | |
310 | ||
311 | ||
312 | void hd_scan_misc2(hd_data_t *hd_data) | |
313 | { | |
314 | hd_t *hd, *hd1; | |
315 | misc_t *m; | |
316 | hd_res_t *res, *res1, *res2; | |
317 | int i; | |
318 | ||
319 | if(!hd_probe_feature(hd_data, pr_misc)) return; | |
320 | ||
321 | hd_data->module = mod_misc; | |
322 | ||
323 | PROGRESS(5, 0, "misc data"); | |
324 | ||
325 | /* create some more system generic entries */ | |
326 | ||
327 | /* IDE */ | |
328 | ||
329 | // ###### add special ide detail to hd_t!!! | |
330 | res = NULL; | |
331 | gather_resources(hd_data->misc, &res, "ide0", 0); | |
332 | gather_resources(hd_data->misc, &res, "ide1", 0); | |
333 | gather_resources(hd_data->misc, &res, "ide2", 0); | |
334 | gather_resources(hd_data->misc, &res, "ide3", 0); | |
335 | if(res) { | |
336 | for(hd = hd_data->hd; hd; hd = hd->next) { | |
337 | if( | |
338 | hd->base_class.id == bc_storage && | |
339 | hd->sub_class.id == sc_sto_ide && | |
340 | have_common_res(hd->res, res) | |
341 | ) break; | |
342 | } | |
343 | if(!hd) { | |
344 | /* eg. non-PCI IDE controller */ | |
345 | hd = add_hd_entry(hd_data, __LINE__, 0); | |
346 | hd->base_class.id = bc_storage; | |
347 | hd->sub_class.id = sc_sto_ide; | |
348 | /* use join_res to join the i/o ranges of ide0/1 */ | |
349 | join_res_io(&hd->res, res); | |
350 | join_res_irq(&hd->res, res); | |
351 | join_res_dma(&hd->res, res); | |
352 | free_res_list(res); | |
353 | } | |
354 | else { | |
355 | /* eg. PCI IDE controller, add resources */ | |
356 | join_res_io(&hd->res, res); | |
357 | join_res_irq(&hd->res, res); | |
358 | join_res_dma(&hd->res, res); | |
359 | free_res_list(res); | |
360 | } | |
361 | } | |
362 | ||
363 | /* VGA */ | |
364 | res = NULL; | |
365 | gather_resources(hd_data->misc, &res, "vga+", 0); | |
366 | gather_resources(hd_data->misc, &res, "vesafb", 0); | |
367 | if(res) { | |
368 | for(i = 0, hd1 = NULL, hd = hd_data->hd; hd; hd = hd->next) { | |
369 | if(hd->base_class.id == bc_display && hd->sub_class.id == sc_dis_vga) { | |
370 | i++; | |
371 | hd1 = hd; | |
372 | } | |
373 | } | |
374 | if(i == 0) { | |
375 | /* non-PCI VGA card ??? - really, we shouldn't care... */ | |
376 | /* FIX THIS !!! ############### */ | |
377 | #ifdef __alpha__ | |
378 | free_res_list(res); | |
379 | #else | |
380 | hd = add_hd_entry(hd_data, __LINE__, 0); | |
381 | hd->base_class.id = bc_display; | |
382 | hd->sub_class.id = sc_dis_vga; | |
383 | hd->res = res; | |
384 | #endif | |
385 | } | |
386 | else if(i == 1) { | |
387 | /* 1 PCI vga card, add resources */ | |
388 | join_res_io(&hd1->res, res); | |
389 | join_res_irq(&hd1->res, res); | |
390 | join_res_dma(&hd1->res, res); | |
391 | free_res_list(res); | |
392 | hd_data->display = hd1->idx; | |
393 | } | |
394 | else { | |
395 | /* more than 1: look again, now only 'active' cards */ | |
396 | for(i = 0, hd1 = NULL, hd = hd_data->hd; hd; hd = hd->next) { | |
397 | if( | |
398 | hd->base_class.id == bc_display && | |
399 | hd->sub_class.id == sc_dis_vga && | |
400 | active_vga_card(hd) | |
401 | ) { | |
402 | i++; | |
403 | hd1 = hd; | |
404 | } | |
405 | } | |
406 | if(i == 1) { | |
407 | /* 'the' active PCI vga card, add resources */ | |
408 | join_res_io(&hd1->res, res); | |
409 | join_res_irq(&hd1->res, res); | |
410 | join_res_dma(&hd1->res, res); | |
411 | hd_data->display = hd1->idx; | |
412 | } | |
413 | else { | |
414 | /* now, what??? */ | |
415 | ADD2LOG("Oopy, could not figure out *the* active display adapter!\n"); | |
416 | } | |
417 | free_res_list(res); | |
418 | } | |
419 | } | |
420 | ||
421 | /* serial ports */ | |
422 | res = NULL; | |
423 | gather_resources(hd_data->misc, &res, "serial(auto)", 0); | |
424 | gather_resources(hd_data->misc, &res, "serial(set)", 0); | |
425 | gather_resources(hd_data->misc, &res, "serial", 0); | |
426 | for(hd = hd_data->hd; hd; hd = hd->next) { | |
427 | if(hd->base_class.id == bc_comm && hd->sub_class.id == sc_com_ser) { | |
428 | for(res1 = hd->res; res1; res1 = res1->next) { | |
429 | for(res2 = res; res2; res2 = res2->next) { | |
430 | if(res1->any.type == res2->any.type) { | |
431 | switch(res1->any.type) { | |
432 | case res_irq: | |
433 | if(res1->irq.base == res2->irq.base) { | |
434 | res2->any.type = res_any; | |
435 | } | |
436 | break; | |
437 | case res_io: | |
438 | if( | |
439 | res1->io.base == res2->io.base && | |
440 | (!res1->io.range || res1->io.range == res2->io.range) | |
441 | ) { | |
442 | res1->io.range = res2->io.range; | |
443 | res2->any.type = res_any; | |
444 | } | |
445 | break; | |
446 | default: /* gcc -Wall */ | |
447 | break; | |
448 | } | |
449 | } | |
450 | } | |
451 | } | |
452 | } | |
453 | } | |
454 | ||
455 | /* if any of the serial resources are unaccounted for, make an extra entry */ | |
456 | for(res2 = res; res2; res2 = res2->next) { | |
457 | if(res2->any.type != res_any) { | |
458 | hd = add_hd_entry(hd_data, __LINE__, 0); | |
459 | hd->base_class.id = bc_comm; | |
460 | hd->sub_class.id = sc_com_ser; | |
461 | hd->prog_if.id = 0x80; | |
462 | for(; res2; res2 = res2->next) { | |
463 | if(res2->any.type != res_any) { | |
464 | res1 = add_res_entry(&hd->res, new_mem(sizeof *res)); | |
465 | *res1 = *res2; | |
466 | res1->next = NULL; | |
467 | } | |
468 | } | |
469 | break; | |
470 | } | |
471 | } | |
472 | free_res_list(res); | |
473 | ||
474 | /* go through our list and assign event counts to irq entries */ | |
475 | m = hd_data->misc; | |
476 | for(hd = hd_data->hd; hd; hd = hd->next) { | |
477 | for(res = hd->res; res; res = res->next) { | |
478 | if(res->irq.type == res_irq) { | |
479 | for(i = 0; (unsigned) i < m->irq_len; i++) { | |
480 | if(res->irq.base == m->irq[i].irq) { | |
481 | res->irq.triggered = m->irq[i].events; | |
482 | break; | |
483 | } | |
484 | } | |
485 | } | |
486 | } | |
487 | } | |
488 | ||
489 | /* look for entries with matching start address */ | |
490 | m = hd_data->misc; | |
491 | for(hd = hd_data->hd; hd; hd = hd->next) { | |
492 | for(res = hd->res; res; res = res->next) { | |
493 | if(res->io.type == res_io) { | |
494 | for(i = 0; (unsigned) i < m->io_len; i++) { | |
495 | if(res->io.base == m->io[i].addr && res->io.range < m->io[i].size) { | |
496 | res->io.range = m->io[i].size; | |
497 | break; | |
498 | } | |
499 | } | |
500 | } | |
501 | } | |
502 | } | |
503 | ||
504 | if((hd_data->debug & HD_DEB_MISC)) dump_misc_data(hd_data); | |
505 | } | |
506 | ||
507 | ||
508 | /* | |
509 | * read /proc/ioports | |
510 | */ | |
511 | void read_ioports(misc_t *m) | |
512 | { | |
513 | char buf[100]; | |
514 | misc_io_t *r; | |
515 | uint64_t u, v; | |
516 | str_list_t *sl; | |
517 | ||
518 | if(!(m->proc_io = read_file(PROC_IOPORTS, 0, 0))) return; | |
519 | ||
520 | for(sl = m->proc_io; sl; sl = sl->next) { | |
521 | if(sscanf(sl->str, " %"PRIx64" - %"PRIx64" : %99[^\n]", &u, &v, buf) == 3) { | |
522 | m->io = add_mem(m->io, sizeof *m->io, m->io_len); | |
523 | r = m->io + m->io_len++; | |
524 | r->addr = u; | |
525 | r->size = v >= u ? v - u + 1 : 0; | |
526 | r->dev = new_str(buf); | |
527 | } | |
528 | } | |
529 | } | |
530 | ||
531 | /* | |
532 | * read /proc/dma | |
533 | */ | |
534 | void read_dmas(misc_t *m) | |
535 | { | |
536 | char buf[100]; | |
537 | misc_dma_t *d; | |
538 | unsigned u; | |
539 | str_list_t *sl; | |
540 | ||
541 | if(!(m->proc_dma = read_file(PROC_DMA, 0, 0))) return; | |
542 | ||
543 | for(sl = m->proc_dma; sl; sl = sl->next) { | |
544 | if(sscanf(sl->str, " %u : %99[^\n]", &u, buf) == 2) { | |
545 | m->dma = add_mem(m->dma, sizeof *m->dma, m->dma_len); | |
546 | d = m->dma + m->dma_len++; | |
547 | d->channel = u; | |
548 | d->dev = new_str(buf); | |
549 | } | |
550 | } | |
551 | } | |
552 | ||
553 | ||
554 | /* | |
555 | * read /proc/interrupts | |
556 | * | |
557 | * This is somewhat more tricky, as the irq event counts are done separately | |
558 | * per cpu *and* there may be irq sharing. | |
559 | */ | |
560 | void read_irqs(misc_t *m) | |
561 | { | |
562 | char buf[100], buf2[100], *s; | |
563 | misc_irq_t *ir; | |
564 | int i, j; | |
565 | unsigned u, v, k; | |
566 | str_list_t *sl; | |
567 | ||
568 | if(!(m->proc_irq = read_file(PROC_INTERRUPTS, 1, 0))) return; | |
569 | ||
570 | for(sl = m->proc_irq; sl; sl = sl->next) { | |
571 | /* irq */ | |
572 | i = 0; | |
573 | if(sscanf(sl->str, " %u: %n", &u, &i) < 1) continue; | |
574 | v = 0; | |
575 | j = i; | |
576 | /* add up all event counters */ | |
577 | while(j < (int) strlen(sl->str) && sscanf(sl->str + j, " %u %n", &k, &i) >= 1) { | |
578 | if(!i) break; | |
579 | v += k; | |
580 | j += i; | |
581 | } | |
582 | /* device driver name string */ | |
583 | #if defined(__PPC__) | |
584 | if( | |
585 | sscanf(sl->str + j, " %*s Edge %99[^\n]", buf) == 1 || | |
586 | sscanf(sl->str + j, " %*s Level %99[^\n]", buf) == 1 || | |
587 | sscanf(sl->str + j, " %*s %99[^\n]", buf) == 1 | |
588 | ) { | |
589 | #else | |
590 | #if defined(__alpha__) || defined(__sparc__) | |
591 | if(sscanf(sl->str + j, " %99[^\n]", buf) == 1) { | |
592 | #else /* __i386__ || __x86_64__ || __ia64__ */ | |
593 | if(sscanf(sl->str + j, " %*s %99[^\n]", buf) == 1) { | |
594 | #endif | |
595 | #endif | |
596 | m->irq = add_mem(m->irq, sizeof *m->irq, m->irq_len); | |
597 | ir = m->irq + m->irq_len++; | |
598 | ir->irq = u; | |
599 | ir->events = v; | |
600 | ||
601 | /* split device driver names (separated by ',') */ | |
602 | s = buf; | |
603 | while(*s && sscanf(s, " %99[^,] %n", buf2, &j) >= 1) { | |
604 | ir->dev = add_mem(ir->dev, sizeof *ir->dev, ir->devs); | |
605 | ir->dev[ir->devs++] = new_str(buf2); | |
606 | s += j; | |
607 | if(*s) s++; /* skip ',' */ | |
608 | } | |
609 | } | |
610 | } | |
611 | } | |
612 | ||
613 | void gather_resources(misc_t *m, hd_res_t **r, char *name, unsigned which) | |
614 | { | |
615 | int i, j; | |
616 | hd_res_t *res; | |
617 | ||
618 | if(!m) return; | |
619 | ||
620 | if(!which) which = W_IO | W_DMA | W_IRQ; | |
621 | ||
622 | if((which & W_IO)) for(i = 0; (unsigned) i < m->io_len; i++) { | |
623 | if(!strcmp(name, m->io[i].dev)) { | |
624 | res = add_res_entry(r, new_mem(sizeof **r)); | |
625 | res->io.type = res_io; | |
626 | res->io.enabled = 1; | |
627 | res->io.base = m->io[i].addr; | |
628 | res->io.range = m->io[i].size; | |
629 | res->io.access = acc_rw; | |
630 | m->io[i].tag++; | |
631 | } | |
632 | } | |
633 | ||
634 | if((which & W_DMA)) for(i = 0; (unsigned) i < m->dma_len; i++) { | |
635 | if(!strcmp(name, m->dma[i].dev)) { | |
636 | res = add_res_entry(r, new_mem(sizeof **r)); | |
637 | res->dma.type = res_dma; | |
638 | res->dma.enabled = 1; | |
639 | res->dma.base = m->dma[i].channel; | |
640 | m->dma[i].tag++; | |
641 | } | |
642 | } | |
643 | ||
644 | if((which & W_IRQ)) for(i = 0; (unsigned) i < m->irq_len; i++) { | |
645 | for(j = 0; j < m->irq[i].devs; j++) { | |
646 | if(!strcmp(name, m->irq[i].dev[j])) { | |
647 | res = add_res_entry(r, new_mem(sizeof **r)); | |
648 | res->irq.type = res_irq; | |
649 | res->irq.enabled = 1; | |
650 | res->irq.base = m->irq[i].irq; | |
651 | res->irq.triggered = m->irq[i].events; | |
652 | m->irq[i].tag++; | |
653 | } | |
654 | } | |
655 | } | |
656 | } | |
657 | ||
658 | ||
659 | int active_vga_card(hd_t *hd) | |
660 | { | |
661 | hd_res_t *res; | |
662 | ||
663 | if(hd->bus.id != bus_pci) return 1; | |
664 | ||
665 | for(res = hd->res; res; res = res->next) { | |
666 | if( | |
667 | (res->mem.type == res_mem && res->mem.enabled) || | |
668 | (res->io.type == res_io && res->io.enabled) | |
669 | ) return 1; | |
670 | } | |
671 | ||
672 | return 0; | |
673 | } | |
674 | ||
675 | ||
676 | /* | |
677 | * Add some proc info to the global log. | |
678 | */ | |
679 | void dump_misc_proc_data(hd_data_t *hd_data) | |
680 | { | |
681 | str_list_t *sl; | |
682 | ||
683 | ADD2LOG("----- /proc/ioports -----\n"); | |
684 | for(sl = hd_data->misc->proc_io; sl; sl = sl->next) { | |
685 | ADD2LOG(" %s", sl->str); | |
686 | } | |
687 | ADD2LOG("----- /proc/ioports end -----\n"); | |
688 | ||
689 | ADD2LOG("----- /proc/interrupts -----\n"); | |
690 | for(sl = hd_data->misc->proc_irq; sl; sl = sl->next) { | |
691 | ADD2LOG(" %s", sl->str); | |
692 | } | |
693 | ADD2LOG("----- /proc/interrupts end -----\n"); | |
694 | ||
695 | ADD2LOG("----- /proc/dma -----\n"); | |
696 | for(sl = hd_data->misc->proc_dma; sl; sl = sl->next) { | |
697 | ADD2LOG(" %s", sl->str); | |
698 | } | |
699 | ADD2LOG("----- /proc/dma end -----\n"); | |
700 | ||
701 | } | |
702 | ||
703 | ||
704 | /* | |
705 | * Add the resource usage to the global log. | |
706 | */ | |
707 | void dump_misc_data(hd_data_t *hd_data) | |
708 | { | |
709 | misc_t *m = hd_data->misc; | |
710 | int i, j; | |
711 | ||
712 | ADD2LOG("----- misc resources -----\n"); | |
713 | ||
714 | for(i = 0; (unsigned) i < m->io_len; i++) { | |
715 | ADD2LOG( | |
716 | "i/o:%u 0x%04"PRIx64" - 0x%04"PRIx64" (0x%02"PRIx64") \"%s\"\n", | |
717 | m->io[i].tag, | |
718 | m->io[i].addr, m->io[i].addr + m->io[i].size - 1, | |
719 | m->io[i].size, m->io[i].dev | |
720 | ); | |
721 | } | |
722 | ||
723 | for(i = 0; (unsigned) i < m->irq_len; i++) { | |
724 | ADD2LOG( | |
725 | "irq:%u %2u (%9u)", | |
726 | m->irq[i].tag, m->irq[i].irq, m->irq[i].events | |
727 | ); | |
728 | for(j = 0; j < m->irq[i].devs; j++) { | |
729 | ADD2LOG(" \"%s\"", m->irq[i].dev[j]); | |
730 | } | |
731 | ADD2LOG("\n"); | |
732 | } | |
733 | ||
734 | for(i = 0; (unsigned) i < m->dma_len; i++) { | |
735 | ADD2LOG( | |
736 | "dma:%u %u \"%s\"\n", | |
737 | m->dma[i].tag, m->dma[i].channel, m->dma[i].dev | |
738 | ); | |
739 | } | |
740 | ||
741 | ADD2LOG("----- misc resources end -----\n"); | |
742 | } |