diff options
author | Finn Thain <fthain@telegraphics.com.au> | 2018-01-13 17:37:13 -0500 |
---|---|---|
committer | Geert Uytterhoeven <geert@linux-m68k.org> | 2018-01-16 10:47:29 -0500 |
commit | 2f7dd07ecadac6bdc3d55c217d65efa2834ba1cb (patch) | |
tree | bd55d141cdf80fc39cb3aedb87f0621c9c1a51a1 /drivers/nubus | |
parent | 883b8cb31a8546b9921c98b255d5f7779d1bc9f6 (diff) |
nubus: Rework /proc/bus/nubus/s/ implementation
The /proc/bus/nubus/s/ directory tree for any slot s is missing a lot
of information. The struct file_operations methods have long been left
unimplemented (hence the familiar compile-time warning, "Need to set
some I/O handlers here").
Slot resources have a complex structure which varies depending on board
function. The logic for interpreting these ROM data structures is found
in nubus.c. Let's not duplicate that logic in proc.c.
Create the /proc/bus/nubus/s/ inodes while scanning slot s. During
descent through slot resource subdirectories, call the new
nubus_proc_add_foo() functions to create the procfs inodes.
Also add a new function, nubus_seq_write_rsrc_mem(), to write the
contents of a particular slot resource to a given seq_file. This is
used by the procfs file_operations methods, to finally give userspace
access to slot ROM information, such as the available video modes.
Tested-by: Stan Johnson <userm57@yahoo.com>
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
Diffstat (limited to 'drivers/nubus')
-rw-r--r-- | drivers/nubus/nubus.c | 114 | ||||
-rw-r--r-- | drivers/nubus/proc.c | 222 |
2 files changed, 223 insertions, 113 deletions
diff --git a/drivers/nubus/nubus.c b/drivers/nubus/nubus.c index c56ac36d91f2..f05541914c21 100644 --- a/drivers/nubus/nubus.c +++ b/drivers/nubus/nubus.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/errno.h> | 15 | #include <linux/errno.h> |
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/seq_file.h> | ||
18 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
19 | #include <asm/setup.h> | 20 | #include <asm/setup.h> |
20 | #include <asm/page.h> | 21 | #include <asm/page.h> |
@@ -146,7 +147,7 @@ static inline void *nubus_rom_addr(int slot) | |||
146 | return (void *)(0xF1000000 + (slot << 24)); | 147 | return (void *)(0xF1000000 + (slot << 24)); |
147 | } | 148 | } |
148 | 149 | ||
149 | static unsigned char *nubus_dirptr(const struct nubus_dirent *nd) | 150 | unsigned char *nubus_dirptr(const struct nubus_dirent *nd) |
150 | { | 151 | { |
151 | unsigned char *p = nd->base; | 152 | unsigned char *p = nd->base; |
152 | 153 | ||
@@ -173,8 +174,8 @@ void nubus_get_rsrc_mem(void *dest, const struct nubus_dirent *dirent, | |||
173 | } | 174 | } |
174 | EXPORT_SYMBOL(nubus_get_rsrc_mem); | 175 | EXPORT_SYMBOL(nubus_get_rsrc_mem); |
175 | 176 | ||
176 | void nubus_get_rsrc_str(char *dest, const struct nubus_dirent *dirent, | 177 | unsigned int nubus_get_rsrc_str(char *dest, const struct nubus_dirent *dirent, |
177 | unsigned int len) | 178 | unsigned int len) |
178 | { | 179 | { |
179 | char *t = dest; | 180 | char *t = dest; |
180 | unsigned char *p = nubus_dirptr(dirent); | 181 | unsigned char *p = nubus_dirptr(dirent); |
@@ -189,9 +190,33 @@ void nubus_get_rsrc_str(char *dest, const struct nubus_dirent *dirent, | |||
189 | } | 190 | } |
190 | if (len > 0) | 191 | if (len > 0) |
191 | *t = '\0'; | 192 | *t = '\0'; |
193 | return t - dest; | ||
192 | } | 194 | } |
193 | EXPORT_SYMBOL(nubus_get_rsrc_str); | 195 | EXPORT_SYMBOL(nubus_get_rsrc_str); |
194 | 196 | ||
197 | void nubus_seq_write_rsrc_mem(struct seq_file *m, | ||
198 | const struct nubus_dirent *dirent, | ||
199 | unsigned int len) | ||
200 | { | ||
201 | unsigned long buf[32]; | ||
202 | unsigned int buf_size = sizeof(buf); | ||
203 | unsigned char *p = nubus_dirptr(dirent); | ||
204 | |||
205 | /* If possible, write out full buffers */ | ||
206 | while (len >= buf_size) { | ||
207 | unsigned int i; | ||
208 | |||
209 | for (i = 0; i < ARRAY_SIZE(buf); i++) | ||
210 | buf[i] = nubus_get_rom(&p, sizeof(buf[0]), | ||
211 | dirent->mask); | ||
212 | seq_write(m, buf, buf_size); | ||
213 | len -= buf_size; | ||
214 | } | ||
215 | /* If not, write out individual bytes */ | ||
216 | while (len--) | ||
217 | seq_putc(m, nubus_get_rom(&p, 1, dirent->mask)); | ||
218 | } | ||
219 | |||
195 | int nubus_get_root_dir(const struct nubus_board *board, | 220 | int nubus_get_root_dir(const struct nubus_board *board, |
196 | struct nubus_dir *dir) | 221 | struct nubus_dir *dir) |
197 | { | 222 | { |
@@ -326,35 +351,35 @@ EXPORT_SYMBOL(nubus_find_rsrc); | |||
326 | looking at, and print out lots and lots of information from the | 351 | looking at, and print out lots and lots of information from the |
327 | resource blocks. */ | 352 | resource blocks. */ |
328 | 353 | ||
329 | /* FIXME: A lot of this stuff will eventually be useful after | ||
330 | initialization, for intelligently probing Ethernet and video chips, | ||
331 | among other things. The rest of it should go in the /proc code. | ||
332 | For now, we just use it to give verbose boot logs. */ | ||
333 | |||
334 | static int __init nubus_get_block_rsrc_dir(struct nubus_board *board, | 354 | static int __init nubus_get_block_rsrc_dir(struct nubus_board *board, |
355 | struct proc_dir_entry *procdir, | ||
335 | const struct nubus_dirent *parent) | 356 | const struct nubus_dirent *parent) |
336 | { | 357 | { |
337 | struct nubus_dir dir; | 358 | struct nubus_dir dir; |
338 | struct nubus_dirent ent; | 359 | struct nubus_dirent ent; |
339 | 360 | ||
340 | nubus_get_subdir(parent, &dir); | 361 | nubus_get_subdir(parent, &dir); |
362 | dir.procdir = nubus_proc_add_rsrc_dir(procdir, parent, board); | ||
341 | 363 | ||
342 | while (nubus_readdir(&dir, &ent) != -1) { | 364 | while (nubus_readdir(&dir, &ent) != -1) { |
343 | u32 size; | 365 | u32 size; |
344 | 366 | ||
345 | nubus_get_rsrc_mem(&size, &ent, 4); | 367 | nubus_get_rsrc_mem(&size, &ent, 4); |
346 | pr_debug(" block (0x%x), size %d\n", ent.type, size); | 368 | pr_debug(" block (0x%x), size %d\n", ent.type, size); |
369 | nubus_proc_add_rsrc_mem(dir.procdir, &ent, size); | ||
347 | } | 370 | } |
348 | return 0; | 371 | return 0; |
349 | } | 372 | } |
350 | 373 | ||
351 | static int __init nubus_get_display_vidmode(struct nubus_board *board, | 374 | static int __init nubus_get_display_vidmode(struct nubus_board *board, |
375 | struct proc_dir_entry *procdir, | ||
352 | const struct nubus_dirent *parent) | 376 | const struct nubus_dirent *parent) |
353 | { | 377 | { |
354 | struct nubus_dir dir; | 378 | struct nubus_dir dir; |
355 | struct nubus_dirent ent; | 379 | struct nubus_dirent ent; |
356 | 380 | ||
357 | nubus_get_subdir(parent, &dir); | 381 | nubus_get_subdir(parent, &dir); |
382 | dir.procdir = nubus_proc_add_rsrc_dir(procdir, parent, board); | ||
358 | 383 | ||
359 | while (nubus_readdir(&dir, &ent) != -1) { | 384 | while (nubus_readdir(&dir, &ent) != -1) { |
360 | switch (ent.type) { | 385 | switch (ent.type) { |
@@ -366,37 +391,42 @@ static int __init nubus_get_display_vidmode(struct nubus_board *board, | |||
366 | nubus_get_rsrc_mem(&size, &ent, 4); | 391 | nubus_get_rsrc_mem(&size, &ent, 4); |
367 | pr_debug(" block (0x%x), size %d\n", ent.type, | 392 | pr_debug(" block (0x%x), size %d\n", ent.type, |
368 | size); | 393 | size); |
394 | nubus_proc_add_rsrc_mem(dir.procdir, &ent, size); | ||
369 | break; | 395 | break; |
370 | } | 396 | } |
371 | default: | 397 | default: |
372 | pr_debug(" unknown resource 0x%02x, data 0x%06x\n", | 398 | pr_debug(" unknown resource 0x%02x, data 0x%06x\n", |
373 | ent.type, ent.data); | 399 | ent.type, ent.data); |
400 | nubus_proc_add_rsrc_mem(dir.procdir, &ent, 0); | ||
374 | } | 401 | } |
375 | } | 402 | } |
376 | return 0; | 403 | return 0; |
377 | } | 404 | } |
378 | 405 | ||
379 | static int __init nubus_get_display_resource(struct nubus_dev *dev, | 406 | static int __init nubus_get_display_resource(struct nubus_dev *dev, |
407 | struct proc_dir_entry *procdir, | ||
380 | const struct nubus_dirent *ent) | 408 | const struct nubus_dirent *ent) |
381 | { | 409 | { |
382 | switch (ent->type) { | 410 | switch (ent->type) { |
383 | case NUBUS_RESID_GAMMADIR: | 411 | case NUBUS_RESID_GAMMADIR: |
384 | pr_debug(" gamma directory offset: 0x%06x\n", ent->data); | 412 | pr_debug(" gamma directory offset: 0x%06x\n", ent->data); |
385 | nubus_get_block_rsrc_dir(dev->board, ent); | 413 | nubus_get_block_rsrc_dir(dev->board, procdir, ent); |
386 | break; | 414 | break; |
387 | case 0x0080 ... 0x0085: | 415 | case 0x0080 ... 0x0085: |
388 | pr_debug(" mode 0x%02x info offset: 0x%06x\n", | 416 | pr_debug(" mode 0x%02x info offset: 0x%06x\n", |
389 | ent->type, ent->data); | 417 | ent->type, ent->data); |
390 | nubus_get_display_vidmode(dev->board, ent); | 418 | nubus_get_display_vidmode(dev->board, procdir, ent); |
391 | break; | 419 | break; |
392 | default: | 420 | default: |
393 | pr_debug(" unknown resource 0x%02x, data 0x%06x\n", | 421 | pr_debug(" unknown resource 0x%02x, data 0x%06x\n", |
394 | ent->type, ent->data); | 422 | ent->type, ent->data); |
423 | nubus_proc_add_rsrc_mem(procdir, ent, 0); | ||
395 | } | 424 | } |
396 | return 0; | 425 | return 0; |
397 | } | 426 | } |
398 | 427 | ||
399 | static int __init nubus_get_network_resource(struct nubus_dev *dev, | 428 | static int __init nubus_get_network_resource(struct nubus_dev *dev, |
429 | struct proc_dir_entry *procdir, | ||
400 | const struct nubus_dirent *ent) | 430 | const struct nubus_dirent *ent) |
401 | { | 431 | { |
402 | switch (ent->type) { | 432 | switch (ent->type) { |
@@ -406,16 +436,19 @@ static int __init nubus_get_network_resource(struct nubus_dev *dev, | |||
406 | 436 | ||
407 | nubus_get_rsrc_mem(addr, ent, 6); | 437 | nubus_get_rsrc_mem(addr, ent, 6); |
408 | pr_debug(" MAC address: %pM\n", addr); | 438 | pr_debug(" MAC address: %pM\n", addr); |
439 | nubus_proc_add_rsrc_mem(procdir, ent, 6); | ||
409 | break; | 440 | break; |
410 | } | 441 | } |
411 | default: | 442 | default: |
412 | pr_debug(" unknown resource 0x%02x, data 0x%06x\n", | 443 | pr_debug(" unknown resource 0x%02x, data 0x%06x\n", |
413 | ent->type, ent->data); | 444 | ent->type, ent->data); |
445 | nubus_proc_add_rsrc_mem(procdir, ent, 0); | ||
414 | } | 446 | } |
415 | return 0; | 447 | return 0; |
416 | } | 448 | } |
417 | 449 | ||
418 | static int __init nubus_get_cpu_resource(struct nubus_dev *dev, | 450 | static int __init nubus_get_cpu_resource(struct nubus_dev *dev, |
451 | struct proc_dir_entry *procdir, | ||
419 | const struct nubus_dirent *ent) | 452 | const struct nubus_dirent *ent) |
420 | { | 453 | { |
421 | switch (ent->type) { | 454 | switch (ent->type) { |
@@ -426,6 +459,7 @@ static int __init nubus_get_cpu_resource(struct nubus_dev *dev, | |||
426 | nubus_get_rsrc_mem(&meminfo, ent, 8); | 459 | nubus_get_rsrc_mem(&meminfo, ent, 8); |
427 | pr_debug(" memory: [ 0x%08lx 0x%08lx ]\n", | 460 | pr_debug(" memory: [ 0x%08lx 0x%08lx ]\n", |
428 | meminfo[0], meminfo[1]); | 461 | meminfo[0], meminfo[1]); |
462 | nubus_proc_add_rsrc_mem(procdir, ent, 8); | ||
429 | break; | 463 | break; |
430 | } | 464 | } |
431 | case NUBUS_RESID_ROMINFO: | 465 | case NUBUS_RESID_ROMINFO: |
@@ -435,31 +469,35 @@ static int __init nubus_get_cpu_resource(struct nubus_dev *dev, | |||
435 | nubus_get_rsrc_mem(&rominfo, ent, 8); | 469 | nubus_get_rsrc_mem(&rominfo, ent, 8); |
436 | pr_debug(" ROM: [ 0x%08lx 0x%08lx ]\n", | 470 | pr_debug(" ROM: [ 0x%08lx 0x%08lx ]\n", |
437 | rominfo[0], rominfo[1]); | 471 | rominfo[0], rominfo[1]); |
472 | nubus_proc_add_rsrc_mem(procdir, ent, 8); | ||
438 | break; | 473 | break; |
439 | } | 474 | } |
440 | default: | 475 | default: |
441 | pr_debug(" unknown resource 0x%02x, data 0x%06x\n", | 476 | pr_debug(" unknown resource 0x%02x, data 0x%06x\n", |
442 | ent->type, ent->data); | 477 | ent->type, ent->data); |
478 | nubus_proc_add_rsrc_mem(procdir, ent, 0); | ||
443 | } | 479 | } |
444 | return 0; | 480 | return 0; |
445 | } | 481 | } |
446 | 482 | ||
447 | static int __init nubus_get_private_resource(struct nubus_dev *dev, | 483 | static int __init nubus_get_private_resource(struct nubus_dev *dev, |
484 | struct proc_dir_entry *procdir, | ||
448 | const struct nubus_dirent *ent) | 485 | const struct nubus_dirent *ent) |
449 | { | 486 | { |
450 | switch (dev->category) { | 487 | switch (dev->category) { |
451 | case NUBUS_CAT_DISPLAY: | 488 | case NUBUS_CAT_DISPLAY: |
452 | nubus_get_display_resource(dev, ent); | 489 | nubus_get_display_resource(dev, procdir, ent); |
453 | break; | 490 | break; |
454 | case NUBUS_CAT_NETWORK: | 491 | case NUBUS_CAT_NETWORK: |
455 | nubus_get_network_resource(dev, ent); | 492 | nubus_get_network_resource(dev, procdir, ent); |
456 | break; | 493 | break; |
457 | case NUBUS_CAT_CPU: | 494 | case NUBUS_CAT_CPU: |
458 | nubus_get_cpu_resource(dev, ent); | 495 | nubus_get_cpu_resource(dev, procdir, ent); |
459 | break; | 496 | break; |
460 | default: | 497 | default: |
461 | pr_debug(" unknown resource 0x%02x, data 0x%06x\n", | 498 | pr_debug(" unknown resource 0x%02x, data 0x%06x\n", |
462 | ent->type, ent->data); | 499 | ent->type, ent->data); |
500 | nubus_proc_add_rsrc_mem(procdir, ent, 0); | ||
463 | } | 501 | } |
464 | return 0; | 502 | return 0; |
465 | } | 503 | } |
@@ -474,6 +512,7 @@ nubus_get_functional_resource(struct nubus_board *board, int slot, | |||
474 | 512 | ||
475 | pr_debug(" Functional resource 0x%02x:\n", parent->type); | 513 | pr_debug(" Functional resource 0x%02x:\n", parent->type); |
476 | nubus_get_subdir(parent, &dir); | 514 | nubus_get_subdir(parent, &dir); |
515 | dir.procdir = nubus_proc_add_rsrc_dir(board->procdir, parent, board); | ||
477 | 516 | ||
478 | /* Actually we should probably panic if this fails */ | 517 | /* Actually we should probably panic if this fails */ |
479 | if ((dev = kzalloc(sizeof(*dev), GFP_ATOMIC)) == NULL) | 518 | if ((dev = kzalloc(sizeof(*dev), GFP_ATOMIC)) == NULL) |
@@ -495,14 +534,17 @@ nubus_get_functional_resource(struct nubus_board *board, int slot, | |||
495 | dev->dr_hw = nbtdata[3]; | 534 | dev->dr_hw = nbtdata[3]; |
496 | pr_debug(" type: [cat 0x%x type 0x%x sw 0x%x hw 0x%x]\n", | 535 | pr_debug(" type: [cat 0x%x type 0x%x sw 0x%x hw 0x%x]\n", |
497 | nbtdata[0], nbtdata[1], nbtdata[2], nbtdata[3]); | 536 | nbtdata[0], nbtdata[1], nbtdata[2], nbtdata[3]); |
537 | nubus_proc_add_rsrc_mem(dir.procdir, &ent, 8); | ||
498 | break; | 538 | break; |
499 | } | 539 | } |
500 | case NUBUS_RESID_NAME: | 540 | case NUBUS_RESID_NAME: |
501 | { | 541 | { |
502 | char name[64]; | 542 | char name[64]; |
543 | unsigned int len; | ||
503 | 544 | ||
504 | nubus_get_rsrc_str(name, &ent, sizeof(name)); | 545 | len = nubus_get_rsrc_str(name, &ent, sizeof(name)); |
505 | pr_debug(" name: %s\n", name); | 546 | pr_debug(" name: %s\n", name); |
547 | nubus_proc_add_rsrc_mem(dir.procdir, &ent, len + 1); | ||
506 | break; | 548 | break; |
507 | } | 549 | } |
508 | case NUBUS_RESID_DRVRDIR: | 550 | case NUBUS_RESID_DRVRDIR: |
@@ -511,7 +553,7 @@ nubus_get_functional_resource(struct nubus_board *board, int slot, | |||
511 | use this :-) */ | 553 | use this :-) */ |
512 | pr_debug(" driver directory offset: 0x%06x\n", | 554 | pr_debug(" driver directory offset: 0x%06x\n", |
513 | ent.data); | 555 | ent.data); |
514 | nubus_get_block_rsrc_dir(board, &ent); | 556 | nubus_get_block_rsrc_dir(board, dir.procdir, &ent); |
515 | break; | 557 | break; |
516 | } | 558 | } |
517 | case NUBUS_RESID_MINOR_BASEOS: | 559 | case NUBUS_RESID_MINOR_BASEOS: |
@@ -523,6 +565,7 @@ nubus_get_functional_resource(struct nubus_board *board, int slot, | |||
523 | 565 | ||
524 | nubus_get_rsrc_mem(&base_offset, &ent, 4); | 566 | nubus_get_rsrc_mem(&base_offset, &ent, 4); |
525 | pr_debug(" memory offset: 0x%08x\n", base_offset); | 567 | pr_debug(" memory offset: 0x%08x\n", base_offset); |
568 | nubus_proc_add_rsrc_mem(dir.procdir, &ent, 4); | ||
526 | break; | 569 | break; |
527 | } | 570 | } |
528 | case NUBUS_RESID_MINOR_LENGTH: | 571 | case NUBUS_RESID_MINOR_LENGTH: |
@@ -532,18 +575,21 @@ nubus_get_functional_resource(struct nubus_board *board, int slot, | |||
532 | 575 | ||
533 | nubus_get_rsrc_mem(&length, &ent, 4); | 576 | nubus_get_rsrc_mem(&length, &ent, 4); |
534 | pr_debug(" memory length: 0x%08x\n", length); | 577 | pr_debug(" memory length: 0x%08x\n", length); |
578 | nubus_proc_add_rsrc_mem(dir.procdir, &ent, 4); | ||
535 | break; | 579 | break; |
536 | } | 580 | } |
537 | case NUBUS_RESID_FLAGS: | 581 | case NUBUS_RESID_FLAGS: |
538 | pr_debug(" flags: 0x%06x\n", ent.data); | 582 | pr_debug(" flags: 0x%06x\n", ent.data); |
583 | nubus_proc_add_rsrc(dir.procdir, &ent); | ||
539 | break; | 584 | break; |
540 | case NUBUS_RESID_HWDEVID: | 585 | case NUBUS_RESID_HWDEVID: |
541 | pr_debug(" hwdevid: 0x%06x\n", ent.data); | 586 | pr_debug(" hwdevid: 0x%06x\n", ent.data); |
587 | nubus_proc_add_rsrc(dir.procdir, &ent); | ||
542 | break; | 588 | break; |
543 | default: | 589 | default: |
544 | /* Local/Private resources have their own | 590 | /* Local/Private resources have their own |
545 | function */ | 591 | function */ |
546 | nubus_get_private_resource(dev, &ent); | 592 | nubus_get_private_resource(dev, dir.procdir, &ent); |
547 | } | 593 | } |
548 | } | 594 | } |
549 | 595 | ||
@@ -552,6 +598,7 @@ nubus_get_functional_resource(struct nubus_board *board, int slot, | |||
552 | 598 | ||
553 | /* This is *really* cool. */ | 599 | /* This is *really* cool. */ |
554 | static int __init nubus_get_icon(struct nubus_board *board, | 600 | static int __init nubus_get_icon(struct nubus_board *board, |
601 | struct proc_dir_entry *procdir, | ||
555 | const struct nubus_dirent *ent) | 602 | const struct nubus_dirent *ent) |
556 | { | 603 | { |
557 | /* Should be 32x32 if my memory serves me correctly */ | 604 | /* Should be 32x32 if my memory serves me correctly */ |
@@ -564,11 +611,13 @@ static int __init nubus_get_icon(struct nubus_board *board, | |||
564 | pr_debug(" %08x %08x %08x %08x\n", | 611 | pr_debug(" %08x %08x %08x %08x\n", |
565 | icon[i * 4 + 0], icon[i * 4 + 1], | 612 | icon[i * 4 + 0], icon[i * 4 + 1], |
566 | icon[i * 4 + 2], icon[i * 4 + 3]); | 613 | icon[i * 4 + 2], icon[i * 4 + 3]); |
614 | nubus_proc_add_rsrc_mem(procdir, ent, 128); | ||
567 | 615 | ||
568 | return 0; | 616 | return 0; |
569 | } | 617 | } |
570 | 618 | ||
571 | static int __init nubus_get_vendorinfo(struct nubus_board *board, | 619 | static int __init nubus_get_vendorinfo(struct nubus_board *board, |
620 | struct proc_dir_entry *procdir, | ||
572 | const struct nubus_dirent *parent) | 621 | const struct nubus_dirent *parent) |
573 | { | 622 | { |
574 | struct nubus_dir dir; | 623 | struct nubus_dir dir; |
@@ -578,15 +627,18 @@ static int __init nubus_get_vendorinfo(struct nubus_board *board, | |||
578 | 627 | ||
579 | pr_debug(" vendor info:\n"); | 628 | pr_debug(" vendor info:\n"); |
580 | nubus_get_subdir(parent, &dir); | 629 | nubus_get_subdir(parent, &dir); |
630 | dir.procdir = nubus_proc_add_rsrc_dir(procdir, parent, board); | ||
581 | 631 | ||
582 | while (nubus_readdir(&dir, &ent) != -1) { | 632 | while (nubus_readdir(&dir, &ent) != -1) { |
583 | char name[64]; | 633 | char name[64]; |
634 | unsigned int len; | ||
584 | 635 | ||
585 | /* These are all strings, we think */ | 636 | /* These are all strings, we think */ |
586 | nubus_get_rsrc_str(name, &ent, sizeof(name)); | 637 | len = nubus_get_rsrc_str(name, &ent, sizeof(name)); |
587 | if (ent.type < 1 || ent.type > 5) | 638 | if (ent.type < 1 || ent.type > 5) |
588 | ent.type = 5; | 639 | ent.type = 5; |
589 | pr_debug(" %s: %s\n", vendor_fields[ent.type - 1], name); | 640 | pr_debug(" %s: %s\n", vendor_fields[ent.type - 1], name); |
641 | nubus_proc_add_rsrc_mem(dir.procdir, &ent, len + 1); | ||
590 | } | 642 | } |
591 | return 0; | 643 | return 0; |
592 | } | 644 | } |
@@ -599,6 +651,7 @@ static int __init nubus_get_board_resource(struct nubus_board *board, int slot, | |||
599 | 651 | ||
600 | pr_debug(" Board resource 0x%02x:\n", parent->type); | 652 | pr_debug(" Board resource 0x%02x:\n", parent->type); |
601 | nubus_get_subdir(parent, &dir); | 653 | nubus_get_subdir(parent, &dir); |
654 | dir.procdir = nubus_proc_add_rsrc_dir(board->procdir, parent, board); | ||
602 | 655 | ||
603 | while (nubus_readdir(&dir, &ent) != -1) { | 656 | while (nubus_readdir(&dir, &ent) != -1) { |
604 | switch (ent.type) { | 657 | switch (ent.type) { |
@@ -615,49 +668,62 @@ static int __init nubus_get_board_resource(struct nubus_board *board, int slot, | |||
615 | nbtdata[2] != 0 || nbtdata[3] != 0) | 668 | nbtdata[2] != 0 || nbtdata[3] != 0) |
616 | pr_err("Slot %X: sResource is not a board resource!\n", | 669 | pr_err("Slot %X: sResource is not a board resource!\n", |
617 | slot); | 670 | slot); |
671 | nubus_proc_add_rsrc_mem(dir.procdir, &ent, 8); | ||
618 | break; | 672 | break; |
619 | } | 673 | } |
620 | case NUBUS_RESID_NAME: | 674 | case NUBUS_RESID_NAME: |
621 | nubus_get_rsrc_str(board->name, &ent, | 675 | { |
622 | sizeof(board->name)); | 676 | unsigned int len; |
677 | |||
678 | len = nubus_get_rsrc_str(board->name, &ent, | ||
679 | sizeof(board->name)); | ||
623 | pr_debug(" name: %s\n", board->name); | 680 | pr_debug(" name: %s\n", board->name); |
681 | nubus_proc_add_rsrc_mem(dir.procdir, &ent, len + 1); | ||
624 | break; | 682 | break; |
683 | } | ||
625 | case NUBUS_RESID_ICON: | 684 | case NUBUS_RESID_ICON: |
626 | nubus_get_icon(board, &ent); | 685 | nubus_get_icon(board, dir.procdir, &ent); |
627 | break; | 686 | break; |
628 | case NUBUS_RESID_BOARDID: | 687 | case NUBUS_RESID_BOARDID: |
629 | pr_debug(" board id: 0x%x\n", ent.data); | 688 | pr_debug(" board id: 0x%x\n", ent.data); |
689 | nubus_proc_add_rsrc(dir.procdir, &ent); | ||
630 | break; | 690 | break; |
631 | case NUBUS_RESID_PRIMARYINIT: | 691 | case NUBUS_RESID_PRIMARYINIT: |
632 | pr_debug(" primary init offset: 0x%06x\n", ent.data); | 692 | pr_debug(" primary init offset: 0x%06x\n", ent.data); |
693 | nubus_proc_add_rsrc(dir.procdir, &ent); | ||
633 | break; | 694 | break; |
634 | case NUBUS_RESID_VENDORINFO: | 695 | case NUBUS_RESID_VENDORINFO: |
635 | nubus_get_vendorinfo(board, &ent); | 696 | nubus_get_vendorinfo(board, dir.procdir, &ent); |
636 | break; | 697 | break; |
637 | case NUBUS_RESID_FLAGS: | 698 | case NUBUS_RESID_FLAGS: |
638 | pr_debug(" flags: 0x%06x\n", ent.data); | 699 | pr_debug(" flags: 0x%06x\n", ent.data); |
700 | nubus_proc_add_rsrc(dir.procdir, &ent); | ||
639 | break; | 701 | break; |
640 | case NUBUS_RESID_HWDEVID: | 702 | case NUBUS_RESID_HWDEVID: |
641 | pr_debug(" hwdevid: 0x%06x\n", ent.data); | 703 | pr_debug(" hwdevid: 0x%06x\n", ent.data); |
704 | nubus_proc_add_rsrc(dir.procdir, &ent); | ||
642 | break; | 705 | break; |
643 | case NUBUS_RESID_SECONDINIT: | 706 | case NUBUS_RESID_SECONDINIT: |
644 | pr_debug(" secondary init offset: 0x%06x\n", | 707 | pr_debug(" secondary init offset: 0x%06x\n", |
645 | ent.data); | 708 | ent.data); |
709 | nubus_proc_add_rsrc(dir.procdir, &ent); | ||
646 | break; | 710 | break; |
647 | /* WTF isn't this in the functional resources? */ | 711 | /* WTF isn't this in the functional resources? */ |
648 | case NUBUS_RESID_VIDNAMES: | 712 | case NUBUS_RESID_VIDNAMES: |
649 | pr_debug(" vidnames directory offset: 0x%06x\n", | 713 | pr_debug(" vidnames directory offset: 0x%06x\n", |
650 | ent.data); | 714 | ent.data); |
651 | nubus_get_block_rsrc_dir(board, &ent); | 715 | nubus_get_block_rsrc_dir(board, dir.procdir, &ent); |
652 | break; | 716 | break; |
653 | /* Same goes for this */ | 717 | /* Same goes for this */ |
654 | case NUBUS_RESID_VIDMODES: | 718 | case NUBUS_RESID_VIDMODES: |
655 | pr_debug(" video mode parameter directory offset: 0x%06x\n", | 719 | pr_debug(" video mode parameter directory offset: 0x%06x\n", |
656 | ent.data); | 720 | ent.data); |
721 | nubus_proc_add_rsrc(dir.procdir, &ent); | ||
657 | break; | 722 | break; |
658 | default: | 723 | default: |
659 | pr_debug(" unknown resource 0x%02x, data 0x%06x\n", | 724 | pr_debug(" unknown resource 0x%02x, data 0x%06x\n", |
660 | ent.type, ent.data); | 725 | ent.type, ent.data); |
726 | nubus_proc_add_rsrc_mem(dir.procdir, &ent, 0); | ||
661 | } | 727 | } |
662 | } | 728 | } |
663 | return 0; | 729 | return 0; |
@@ -748,6 +814,8 @@ static struct nubus_board * __init nubus_add_board(int slot, int bytelanes) | |||
748 | if (ent.type < 1 || ent.type > 127) | 814 | if (ent.type < 1 || ent.type > 127) |
749 | pr_warn("Slot %X: Board resource ID is invalid!\n", slot); | 815 | pr_warn("Slot %X: Board resource ID is invalid!\n", slot); |
750 | 816 | ||
817 | board->procdir = nubus_proc_add_board(board); | ||
818 | |||
751 | nubus_get_board_resource(board, slot, &ent); | 819 | nubus_get_board_resource(board, slot, &ent); |
752 | 820 | ||
753 | while (nubus_readdir(&dir, &ent) != -1) { | 821 | while (nubus_readdir(&dir, &ent) != -1) { |
@@ -835,8 +903,8 @@ static int __init nubus_init(void) | |||
835 | if (!MACH_IS_MAC) | 903 | if (!MACH_IS_MAC) |
836 | return 0; | 904 | return 0; |
837 | 905 | ||
838 | nubus_scan_bus(); | ||
839 | nubus_proc_init(); | 906 | nubus_proc_init(); |
907 | nubus_scan_bus(); | ||
840 | return 0; | 908 | return 0; |
841 | } | 909 | } |
842 | 910 | ||
diff --git a/drivers/nubus/proc.c b/drivers/nubus/proc.c index 41ec859bdd8b..f47d90924ab4 100644 --- a/drivers/nubus/proc.c +++ b/drivers/nubus/proc.c | |||
@@ -11,24 +11,28 @@ | |||
11 | structure in /proc analogous to the structure of the NuBus ROM | 11 | structure in /proc analogous to the structure of the NuBus ROM |
12 | resources. | 12 | resources. |
13 | 13 | ||
14 | Therefore each NuBus device is in fact a directory, which may in | 14 | Therefore each board function gets a directory, which may in turn |
15 | turn contain subdirectories. The "files" correspond to NuBus | 15 | contain subdirectories. Each slot resource is a file. Unrecognized |
16 | resource records. For those types of records which we know how to | 16 | resources are empty files, since every resource ID requires a special |
17 | convert to formats that are meaningful to userspace (mostly just | 17 | case (e.g. if the resource ID implies a directory or block, then its |
18 | icons) these files will provide "cooked" data. Otherwise they will | 18 | value has to be interpreted as a slot ROM pointer etc.). |
19 | simply provide raw access (read-only of course) to the ROM. */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/types.h> | 21 | #include <linux/types.h> |
22 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
23 | #include <linux/nubus.h> | 23 | #include <linux/nubus.h> |
24 | #include <linux/proc_fs.h> | 24 | #include <linux/proc_fs.h> |
25 | #include <linux/seq_file.h> | 25 | #include <linux/seq_file.h> |
26 | #include <linux/slab.h> | ||
26 | #include <linux/init.h> | 27 | #include <linux/init.h> |
27 | #include <linux/module.h> | 28 | #include <linux/module.h> |
28 | |||
29 | #include <linux/uaccess.h> | 29 | #include <linux/uaccess.h> |
30 | #include <asm/byteorder.h> | 30 | #include <asm/byteorder.h> |
31 | 31 | ||
32 | /* | ||
33 | * /proc/bus/nubus/devices stuff | ||
34 | */ | ||
35 | |||
32 | static int | 36 | static int |
33 | nubus_devices_proc_show(struct seq_file *m, void *v) | 37 | nubus_devices_proc_show(struct seq_file *m, void *v) |
34 | { | 38 | { |
@@ -61,96 +65,141 @@ static const struct file_operations nubus_devices_proc_fops = { | |||
61 | 65 | ||
62 | static struct proc_dir_entry *proc_bus_nubus_dir; | 66 | static struct proc_dir_entry *proc_bus_nubus_dir; |
63 | 67 | ||
64 | static const struct file_operations nubus_proc_subdir_fops = { | 68 | /* |
65 | #warning Need to set some I/O handlers here | 69 | * /proc/bus/nubus/x/ stuff |
70 | */ | ||
71 | |||
72 | struct proc_dir_entry *nubus_proc_add_board(struct nubus_board *board) | ||
73 | { | ||
74 | char name[2]; | ||
75 | |||
76 | if (!proc_bus_nubus_dir) | ||
77 | return NULL; | ||
78 | snprintf(name, sizeof(name), "%x", board->slot); | ||
79 | return proc_mkdir(name, proc_bus_nubus_dir); | ||
80 | } | ||
81 | |||
82 | /* The PDE private data for any directory under /proc/bus/nubus/x/ | ||
83 | * is the bytelanes value for the board in slot x. | ||
84 | */ | ||
85 | |||
86 | struct proc_dir_entry *nubus_proc_add_rsrc_dir(struct proc_dir_entry *procdir, | ||
87 | const struct nubus_dirent *ent, | ||
88 | struct nubus_board *board) | ||
89 | { | ||
90 | char name[9]; | ||
91 | int lanes = board->lanes; | ||
92 | |||
93 | if (!procdir) | ||
94 | return NULL; | ||
95 | snprintf(name, sizeof(name), "%x", ent->type); | ||
96 | return proc_mkdir_data(name, 0555, procdir, (void *)lanes); | ||
97 | } | ||
98 | |||
99 | /* The PDE private data for a file under /proc/bus/nubus/x/ is a pointer to | ||
100 | * an instance of the following structure, which gives the location and size | ||
101 | * of the resource data in the slot ROM. For slot resources which hold only a | ||
102 | * small integer, this integer value is stored directly and size is set to 0. | ||
103 | * A NULL private data pointer indicates an unrecognized resource. | ||
104 | */ | ||
105 | |||
106 | struct nubus_proc_pde_data { | ||
107 | unsigned char *res_ptr; | ||
108 | unsigned int res_size; | ||
66 | }; | 109 | }; |
67 | 110 | ||
68 | static void nubus_proc_subdir(struct nubus_dev* dev, | 111 | static struct nubus_proc_pde_data * |
69 | struct proc_dir_entry* parent, | 112 | nubus_proc_alloc_pde_data(unsigned char *ptr, unsigned int size) |
70 | struct nubus_dir* dir) | ||
71 | { | 113 | { |
72 | struct nubus_dirent ent; | 114 | struct nubus_proc_pde_data *pde_data; |
73 | 115 | ||
74 | /* Some of these are directories, others aren't */ | 116 | pde_data = kmalloc(sizeof(*pde_data), GFP_KERNEL); |
75 | while (nubus_readdir(dir, &ent) != -1) { | 117 | if (!pde_data) |
76 | char name[9]; | 118 | return NULL; |
77 | struct proc_dir_entry* e; | 119 | |
78 | 120 | pde_data->res_ptr = ptr; | |
79 | snprintf(name, sizeof(name), "%x", ent.type); | 121 | pde_data->res_size = size; |
80 | e = proc_create(name, S_IFREG | S_IRUGO | S_IWUSR, parent, | 122 | return pde_data; |
81 | &nubus_proc_subdir_fops); | ||
82 | if (!e) | ||
83 | return; | ||
84 | } | ||
85 | } | 123 | } |
86 | 124 | ||
87 | /* Can't do this recursively since the root directory is structured | 125 | static int nubus_proc_rsrc_show(struct seq_file *m, void *v) |
88 | somewhat differently from the subdirectories */ | ||
89 | static void nubus_proc_populate(struct nubus_dev* dev, | ||
90 | struct proc_dir_entry* parent, | ||
91 | struct nubus_dir* root) | ||
92 | { | 126 | { |
93 | struct nubus_dirent ent; | 127 | struct inode *inode = m->private; |
94 | 128 | struct nubus_proc_pde_data *pde_data; | |
95 | /* We know these are all directories (board resource + one or | 129 | |
96 | more functional resources) */ | 130 | pde_data = PDE_DATA(inode); |
97 | while (nubus_readdir(root, &ent) != -1) { | 131 | if (!pde_data) |
98 | char name[9]; | 132 | return 0; |
99 | struct proc_dir_entry* e; | 133 | |
100 | struct nubus_dir dir; | 134 | if (pde_data->res_size > m->size) |
101 | 135 | return -EFBIG; | |
102 | snprintf(name, sizeof(name), "%x", ent.type); | 136 | |
103 | e = proc_mkdir(name, parent); | 137 | if (pde_data->res_size) { |
104 | if (!e) return; | 138 | int lanes = (int)proc_get_parent_data(inode); |
105 | 139 | struct nubus_dirent ent; | |
106 | /* And descend */ | 140 | |
107 | if (nubus_get_subdir(&ent, &dir) == -1) { | 141 | if (!lanes) |
108 | /* This shouldn't happen */ | 142 | return 0; |
109 | printk(KERN_ERR "NuBus root directory node %x:%x has no subdir!\n", | 143 | |
110 | dev->board->slot, ent.type); | 144 | ent.mask = lanes; |
111 | continue; | 145 | ent.base = pde_data->res_ptr; |
112 | } else { | 146 | ent.data = 0; |
113 | nubus_proc_subdir(dev, e, &dir); | 147 | nubus_seq_write_rsrc_mem(m, &ent, pde_data->res_size); |
114 | } | 148 | } else { |
149 | unsigned int data = (unsigned int)pde_data->res_ptr; | ||
150 | |||
151 | seq_putc(m, data >> 16); | ||
152 | seq_putc(m, data >> 8); | ||
153 | seq_putc(m, data >> 0); | ||
115 | } | 154 | } |
155 | return 0; | ||
116 | } | 156 | } |
117 | 157 | ||
118 | int nubus_proc_attach_device(struct nubus_dev *dev) | 158 | static int nubus_proc_rsrc_open(struct inode *inode, struct file *file) |
159 | { | ||
160 | return single_open(file, nubus_proc_rsrc_show, inode); | ||
161 | } | ||
162 | |||
163 | static const struct file_operations nubus_proc_rsrc_fops = { | ||
164 | .open = nubus_proc_rsrc_open, | ||
165 | .read = seq_read, | ||
166 | .llseek = seq_lseek, | ||
167 | .release = single_release, | ||
168 | }; | ||
169 | |||
170 | void nubus_proc_add_rsrc_mem(struct proc_dir_entry *procdir, | ||
171 | const struct nubus_dirent *ent, | ||
172 | unsigned int size) | ||
119 | { | 173 | { |
120 | struct proc_dir_entry *e; | ||
121 | struct nubus_dir root; | ||
122 | char name[9]; | 174 | char name[9]; |
175 | struct nubus_proc_pde_data *pde_data; | ||
123 | 176 | ||
124 | if (dev == NULL) { | 177 | if (!procdir) |
125 | printk(KERN_ERR | 178 | return; |
126 | "NULL pointer in nubus_proc_attach_device, shoot the programmer!\n"); | ||
127 | return -1; | ||
128 | } | ||
129 | |||
130 | if (dev->board == NULL) { | ||
131 | printk(KERN_ERR | ||
132 | "NULL pointer in nubus_proc_attach_device, shoot the programmer!\n"); | ||
133 | printk("dev = %p, dev->board = %p\n", dev, dev->board); | ||
134 | return -1; | ||
135 | } | ||
136 | |||
137 | if (dev->board->procdir) | ||
138 | return 0; | ||
139 | 179 | ||
140 | /* Create a directory */ | 180 | snprintf(name, sizeof(name), "%x", ent->type); |
141 | snprintf(name, sizeof(name), "%x", dev->board->slot); | 181 | if (size) |
142 | e = proc_mkdir(name, proc_bus_nubus_dir); | 182 | pde_data = nubus_proc_alloc_pde_data(nubus_dirptr(ent), size); |
143 | dev->board->procdir = e; | 183 | else |
144 | if (!e) | 184 | pde_data = NULL; |
145 | return -ENOMEM; | 185 | proc_create_data(name, S_IFREG | 0444, procdir, |
186 | &nubus_proc_rsrc_fops, pde_data); | ||
187 | } | ||
146 | 188 | ||
147 | /* Now recursively populate it with files */ | 189 | void nubus_proc_add_rsrc(struct proc_dir_entry *procdir, |
148 | nubus_get_root_dir(dev->board, &root); | 190 | const struct nubus_dirent *ent) |
149 | nubus_proc_populate(dev, e, &root); | 191 | { |
192 | char name[9]; | ||
193 | unsigned char *data = (unsigned char *)ent->data; | ||
150 | 194 | ||
151 | return 0; | 195 | if (!procdir) |
196 | return; | ||
197 | |||
198 | snprintf(name, sizeof(name), "%x", ent->type); | ||
199 | proc_create_data(name, S_IFREG | 0444, procdir, | ||
200 | &nubus_proc_rsrc_fops, | ||
201 | nubus_proc_alloc_pde_data(data, 0)); | ||
152 | } | 202 | } |
153 | EXPORT_SYMBOL(nubus_proc_attach_device); | ||
154 | 203 | ||
155 | /* | 204 | /* |
156 | * /proc/nubus stuff | 205 | * /proc/nubus stuff |
@@ -219,18 +268,11 @@ static const struct file_operations nubus_proc_fops = { | |||
219 | .release = seq_release, | 268 | .release = seq_release, |
220 | }; | 269 | }; |
221 | 270 | ||
222 | void __init proc_bus_nubus_add_devices(void) | ||
223 | { | ||
224 | struct nubus_dev *dev; | ||
225 | |||
226 | for(dev = nubus_devices; dev; dev = dev->next) | ||
227 | nubus_proc_attach_device(dev); | ||
228 | } | ||
229 | |||
230 | void __init nubus_proc_init(void) | 271 | void __init nubus_proc_init(void) |
231 | { | 272 | { |
232 | proc_create("nubus", 0, NULL, &nubus_proc_fops); | 273 | proc_create("nubus", 0, NULL, &nubus_proc_fops); |
233 | proc_bus_nubus_dir = proc_mkdir("bus/nubus", NULL); | 274 | proc_bus_nubus_dir = proc_mkdir("bus/nubus", NULL); |
275 | if (!proc_bus_nubus_dir) | ||
276 | return; | ||
234 | proc_create("devices", 0, proc_bus_nubus_dir, &nubus_devices_proc_fops); | 277 | proc_create("devices", 0, proc_bus_nubus_dir, &nubus_devices_proc_fops); |
235 | proc_bus_nubus_add_devices(); | ||
236 | } | 278 | } |