2 * linux/arch/i386/kernel/mca.c
3 * Written by Martin Kolinek, February 1996
7 * Chris Beauregard July 28th, 1996
8 * - Fixed up integrated SCSI detection
10 * Chris Beauregard August 3rd, 1996
11 * - Made mca_info local
12 * - Made integrated registers accessible through standard function calls
14 * - More sanity checking
16 * Chris Beauregard August 9th, 1996
19 * Chris Beauregard January 7th, 1997
20 * - Added basic NMI-processing
21 * - Added more information to mca_info structure
23 * David Weinehall October 12th, 1998
24 * - Made a lot of cleaning up in the source
25 * - Added use of save_flags / restore_flags
26 * - Added the 'driver_loaded' flag in MCA_adapter
27 * - Added an alternative implemention of ZP Gu's mca_find_unused_adapter
29 * David Weinehall March 24th, 1999
30 * - Fixed the output of 'Driver Installed' in /proc/mca/pos
31 * - Made the Integrated Video & SCSI show up even if they have id 0000
34 #include <linux/types.h>
35 #include <linux/errno.h>
36 #include <linux/kernel.h>
37 #include <linux/mca.h>
38 #include <asm/system.h>
40 #include <linux/proc_fs.h>
41 #include <linux/mman.h>
42 #include <linux/config.h>
44 #include <linux/pagemap.h>
45 #include <linux/ioport.h>
46 #include <asm/uaccess.h>
47 #include <linux/init.h>
49 /* This structure holds MCA information. Each (plug-in) adapter has
50 * eight POS registers. Then the machine may have integrated video and
51 * SCSI subsystems, which also have eight POS registers.
52 * Other miscellaneous information follows.
56 MCA_ADAPTER_NORMAL
= 0,
58 MCA_ADAPTER_DISABLED
= 2,
63 MCA_AdapterStatus status
; /* is there a valid adapter? */
64 int id
; /* adapter id value */
65 unsigned char pos
[8]; /* POS registers */
66 int driver_loaded
; /* is there a driver installed? */
68 char name
[48]; /* adapter-name provided by driver */
69 char procname
[8]; /* name of /proc/mca file */
70 MCA_ProcFn procfn
; /* /proc info callback */
71 void* dev
; /* device/context info for callback */
75 /* one for each of the 8 possible slots, plus one for integrated SCSI
76 * and one for integrated video.
79 struct MCA_adapter slot
[MCA_NUMADAPTERS
];
81 /* two potential addresses for integrated SCSI adapter - this will
82 * track which one we think it is.
85 unsigned char which_scsi
;
88 /* The mca_info structure pointer. If MCA bus is present, the function
89 * mca_probe() is invoked. The function puts motherboard, then all
90 * adapters into setup mode, allocates and fills an MCA_info structure,
91 * and points this pointer to the structure. Otherwise the pointer
95 static struct MCA_info
* mca_info
= NULL
;
99 #define MCA_MOTHERBOARD_SETUP_REG 0x94
100 #define MCA_ADAPTER_SETUP_REG 0x96
101 #define MCA_POS_REG(n) (0x100+(n))
103 #define MCA_ENABLED 0x01 /* POS 2, set if adapter enabled */
105 /*--------------------------------------------------------------------*/
107 #ifdef CONFIG_PROC_FS
109 static void mca_do_proc_init(void);
110 static int mca_default_procfn(char* buf
, int slot
);
112 static ssize_t
proc_mca_read(struct file
*, char*, size_t, loff_t
*);
114 static struct file_operations proc_mca_operations
= {
116 proc_mca_read
, /* read */
127 NULL
, /* check_media_change */
128 NULL
, /* revalidate */
132 static struct inode_operations proc_mca_inode_operations
= {
133 &proc_mca_operations
, /* default file-ops */
144 NULL
, /* follow_link */
145 NULL
, /* get_block */
147 NULL
, /* writepage */
148 NULL
, /* flushpage */
150 NULL
, /* permission */
152 NULL
/* revalidate */
156 /*--------------------------------------------------------------------*/
158 /* Build the status info for the adapter */
160 static void mca_configure_adapter_status(int slot
) {
161 mca_info
->slot
[slot
].status
= MCA_ADAPTER_NONE
;
163 mca_info
->slot
[slot
].id
= mca_info
->slot
[slot
].pos
[0]
164 + (mca_info
->slot
[slot
].pos
[1] << 8);
166 if(!mca_info
->slot
[slot
].id
&& slot
< MCA_MAX_SLOT_NR
) {
168 /* id = 0x0000 usually indicates hardware failure,
169 * however, ZP Gu (zpg@castle.net> reports that his 9556
170 * has 0x0000 as id and everything still works. There
171 * also seem to be an adapter with id = 0x0000; the
172 * NCR Parallel Bus Memory Card. Until this is confirmed,
173 * however, this code will stay.
176 mca_info
->slot
[slot
].status
= MCA_ADAPTER_ERROR
;
179 } else if(mca_info
->slot
[slot
].id
!= 0xffff) {
181 /* 0xffff usually indicates that there's no adapter,
182 * however, some integrated adapters may have 0xffff as
183 * their id and still be valid. Examples are on-board
184 * VGA of the 55sx, the integrated SCSI of the 56 & 57,
185 * and possibly also the 95 ULTIMEDIA.
188 mca_info
->slot
[slot
].status
= MCA_ADAPTER_NORMAL
;
191 if((mca_info
->slot
[slot
].id
== 0xffff ||
192 mca_info
->slot
[slot
].id
== 0x0000) && slot
>= MCA_MAX_SLOT_NR
) {
195 for(j
= 2; j
< 8; j
++) {
196 if(mca_info
->slot
[slot
].pos
[j
] != 0xff) {
197 mca_info
->slot
[slot
].status
= MCA_ADAPTER_NORMAL
;
203 if(!(mca_info
->slot
[slot
].pos
[2] & MCA_ENABLED
)) {
205 /* enabled bit is in POS 2 */
207 mca_info
->slot
[slot
].status
= MCA_ADAPTER_DISABLED
;
209 } /* mca_configure_adapter_status */
211 /*--------------------------------------------------------------------*/
213 struct resource mca_standard_resources
[] = {
214 { "system control port B (MCA)", 0x60, 0x60 },
215 { "arbitration (MCA)", 0x90, 0x90 },
216 { "card Select Feedback (MCA)", 0x91, 0x91 },
217 { "system Control port A (MCA)", 0x92, 0x92 },
218 { "system board setup (MCA)", 0x94, 0x94 },
219 { "POS (MCA)", 0x96, 0x97 },
220 { "POS (MCA)", 0x100, 0x107 }
223 #define MCA_STANDARD_RESOURCES (sizeof(mca_standard_resources)/sizeof(struct resource))
225 __initfunc(void mca_init(void))
230 /* WARNING: Be careful when making changes here. Putting an adapter
231 * and the motherboard simultaneously into setup mode may result in
232 * damage to chips (according to The Indispensible PC Hardware Book
233 * by Hans-Peter Messmer). Also, we disable system interrupts (so
234 * that we are not disturbed in the middle of this).
237 /* Make sure the MCA bus is present */
241 printk("Micro Channel bus detected.\n");
243 /* Allocate MCA_info structure (at address divisible by 8) */
245 mca_info
= (struct MCA_info
*)kmalloc(sizeof(struct MCA_info
), GFP_KERNEL
);
247 if(mca_info
== NULL
) {
248 printk("Failed to allocate memory for mca_info!");
251 memset(mca_info
, 0, sizeof(struct MCA_info
));
256 /* Make sure adapter setup is off */
258 outb_p(0, MCA_ADAPTER_SETUP_REG
);
260 /* Put motherboard into video setup mode, read integrated video
261 * POS registers, and turn motherboard setup off.
264 outb_p(0xdf, MCA_MOTHERBOARD_SETUP_REG
);
265 mca_info
->slot
[MCA_INTEGVIDEO
].name
[0] = 0;
267 mca_info
->slot
[MCA_INTEGVIDEO
].pos
[j
] = inb_p(MCA_POS_REG(j
));
269 mca_configure_adapter_status(MCA_INTEGVIDEO
);
271 /* Put motherboard into scsi setup mode, read integrated scsi
272 * POS registers, and turn motherboard setup off.
274 * It seems there are two possible SCSI registers. Martin says that
275 * for the 56,57, 0xf7 is the one, but fails on the 76.
276 * Alfredo (apena@vnet.ibm.com) says
277 * 0xfd works on his machine. We'll try both of them. I figure it's
278 * a good bet that only one could be valid at a time. This could
279 * screw up though if one is used for something else on the other
283 outb_p(0xf7, MCA_MOTHERBOARD_SETUP_REG
);
284 mca_info
->slot
[MCA_INTEGSCSI
].name
[0] = 0;
286 if((mca_info
->slot
[MCA_INTEGSCSI
].pos
[j
] = inb_p(MCA_POS_REG(j
))) != 0xff)
288 /* 0xff all across means no device. 0x00 means
289 * something's broken, but a device is probably there.
290 * However, if you get 0x00 from a motherboard
291 * register it won't matter what we find. For the
292 * record, on the 57SLC, the integrated SCSI
293 * adapter has 0xffff for the adapter ID, but
294 * nonzero for other registers.
297 mca_info
->which_scsi
= 0xf7;
300 if(!mca_info
->which_scsi
) {
302 /* Didn't find it at 0xf7, try somewhere else... */
303 mca_info
->which_scsi
= 0xfd;
305 outb_p(0xfd, MCA_MOTHERBOARD_SETUP_REG
);
307 mca_info
->slot
[MCA_INTEGSCSI
].pos
[j
] = inb_p(MCA_POS_REG(j
));
309 mca_configure_adapter_status(MCA_INTEGSCSI
);
311 /* Turn off motherboard setup */
313 outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG
);
315 /* Now loop over MCA slots: put each adapter into setup mode, and
316 * read its POS registers. Then put adapter setup off.
319 for(i
=0; i
<MCA_MAX_SLOT_NR
; i
++) {
320 outb_p(0x8|(i
&0xf), MCA_ADAPTER_SETUP_REG
);
322 mca_info
->slot
[i
].pos
[j
]=inb_p(MCA_POS_REG(j
));
324 mca_info
->slot
[i
].name
[0] = 0;
325 mca_info
->slot
[i
].driver_loaded
= 0;
326 mca_configure_adapter_status(i
);
328 outb_p(0, MCA_ADAPTER_SETUP_REG
);
330 /* Enable interrupts and return memory start */
332 restore_flags(flags
);
334 for (i
= 0; i
< MCA_STANDARD_RESOURCES
; i
++)
335 request_resource(&ioport_resource
, mca_standard_resources
+ i
);
337 #ifdef CONFIG_PROC_FS
342 /*--------------------------------------------------------------------*/
344 static void mca_handle_nmi_slot(int slot
, int check_flag
)
346 if(slot
< MCA_MAX_SLOT_NR
) {
347 printk("NMI: caused by MCA adapter in slot %d (%s)\n", slot
+1,
348 mca_info
->slot
[slot
].name
);
349 } else if(slot
== MCA_INTEGSCSI
) {
350 printk("NMI: caused by MCA integrated SCSI adapter (%s)\n",
351 mca_info
->slot
[slot
].name
);
352 } else if(slot
== MCA_INTEGVIDEO
) {
353 printk("NMI: caused by MCA integrated video adapter (%s)\n",
354 mca_info
->slot
[slot
].name
);
357 /* More info available in POS 6 and 7? */
360 unsigned char pos6
, pos7
;
362 pos6
= mca_read_pos(slot
, 6);
363 pos7
= mca_read_pos(slot
, 7);
365 printk("NMI: POS 6 = 0x%x, POS 7 = 0x%x\n", pos6
, pos7
);
368 } /* mca_handle_nmi_slot */
370 /*--------------------------------------------------------------------*/
372 void mca_handle_nmi(void)
378 /* First try - scan the various adapters and see if a specific
379 * adapter was responsible for the error.
382 for(i
= 0; i
< MCA_NUMADAPTERS
; i
++) {
384 /* Bit 7 of POS 5 is reset when this adapter has a hardware
385 * error. Bit 7 it reset if there's error information
386 * available in POS 6 and 7.
389 pos5
= mca_read_pos(i
, 5);
392 mca_handle_nmi_slot(i
, !(pos5
& 0x40));
397 /* If I recall correctly, there's a whole bunch of other things that
398 * we can do to check for NMI problems, but that's all I know about
402 printk("NMI generated from unknown source!\n");
403 } /* mca_handle_nmi */
405 /*--------------------------------------------------------------------*/
407 int mca_find_adapter(int id
, int start
)
409 if(mca_info
== NULL
|| id
== 0xffff) {
413 for(; start
>= 0 && start
< MCA_NUMADAPTERS
; start
++) {
415 /* Not sure about this. There's no point in returning
416 * adapters that aren't enabled, since they can't actually
417 * be used. However, they might be needed for statistical
418 * purposes or something... But if that is the case, the
419 * user is free to write a routine that manually iterates
420 * through the adapters.
423 if(mca_info
->slot
[start
].status
== MCA_ADAPTER_DISABLED
) {
427 if(id
== mca_info
->slot
[start
].id
) {
433 } /* mca_find_adapter() */
435 /*--------------------------------------------------------------------*/
437 int mca_find_unused_adapter(int id
, int start
)
439 if(mca_info
== NULL
|| id
== 0xffff) {
443 for(; start
>= 0 && start
< MCA_NUMADAPTERS
; start
++) {
445 /* not sure about this. There's no point in returning
446 * adapters that aren't enabled, since they can't actually
447 * be used. However, they might be needed for statistical
448 * purposes or something... But if that is the case, the
449 * user is free to write a routine that manually iterates
450 * through the adapters.
453 if(mca_info
->slot
[start
].status
== MCA_ADAPTER_DISABLED
||
454 mca_info
->slot
[start
].driver_loaded
) {
458 if(id
== mca_info
->slot
[start
].id
) {
464 } /* mca_find_unused_adapter() */
466 /*--------------------------------------------------------------------*/
468 unsigned char mca_read_stored_pos(int slot
, int reg
)
470 if(slot
< 0 || slot
>= MCA_NUMADAPTERS
|| mca_info
== NULL
) return 0;
471 if(reg
< 0 || reg
>= 8) return 0;
472 return mca_info
->slot
[slot
].pos
[reg
];
473 } /* mca_read_stored_pos() */
475 /*--------------------------------------------------------------------*/
477 unsigned char mca_read_pos(int slot
, int reg
)
479 unsigned int byte
= 0;
482 if(slot
< 0 || slot
>= MCA_NUMADAPTERS
|| mca_info
== NULL
) return 0;
483 if(reg
< 0 || reg
>= 8) return 0;
488 /* Make sure motherboard setup is off */
490 outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG
);
492 /* Read in the appropriate register */
494 if(slot
== MCA_INTEGSCSI
&& mca_info
->which_scsi
) {
496 /* Disable adapter setup, enable motherboard setup */
498 outb_p(0, MCA_ADAPTER_SETUP_REG
);
499 outb_p(mca_info
->which_scsi
, MCA_MOTHERBOARD_SETUP_REG
);
501 byte
= inb_p(MCA_POS_REG(reg
));
502 outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG
);
503 } else if(slot
== MCA_INTEGVIDEO
) {
505 /* Disable adapter setup, enable motherboard setup */
507 outb_p(0, MCA_ADAPTER_SETUP_REG
);
508 outb_p(0xdf, MCA_MOTHERBOARD_SETUP_REG
);
510 byte
= inb_p(MCA_POS_REG(reg
));
511 outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG
);
512 } else if(slot
< MCA_MAX_SLOT_NR
) {
514 /* Make sure motherboard setup is off */
516 outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG
);
518 /* Read the appropriate register */
520 outb_p(0x8|(slot
&0xf), MCA_ADAPTER_SETUP_REG
);
521 byte
= inb_p(MCA_POS_REG(reg
));
522 outb_p(0, MCA_ADAPTER_SETUP_REG
);
525 /* Make sure the stored values are consistent, while we're here */
527 mca_info
->slot
[slot
].pos
[reg
] = byte
;
529 restore_flags(flags
);
532 } /* mca_read_pos() */
534 /*--------------------------------------------------------------------*/
536 /* Note that this a technically a Bad Thing, as IBM tech stuff says
537 * you should only set POS values through their utilities.
538 * However, some devices such as the 3c523 recommend that you write
539 * back some data to make sure the configuration is consistent.
540 * I'd say that IBM is right, but I like my drivers to work.
541 * This function can't do checks to see if multiple devices end up
542 * with the same resources, so you might see magic smoke if someone
546 void mca_write_pos(int slot
, int reg
, unsigned char byte
)
550 if(slot
< 0 || slot
>= MCA_MAX_SLOT_NR
)
552 if(reg
< 0 || reg
>= 8)
560 /* Make sure motherboard setup is off */
562 outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG
);
564 /* Read in the appropriate register */
566 outb_p(0x8|(slot
&0xf), MCA_ADAPTER_SETUP_REG
);
567 outb_p(byte
, MCA_POS_REG(reg
));
568 outb_p(0, MCA_ADAPTER_SETUP_REG
);
570 restore_flags(flags
);
572 /* Update the global register list, while we have the byte */
574 mca_info
->slot
[slot
].pos
[reg
] = byte
;
575 } /* mca_write_pos() */
577 /*--------------------------------------------------------------------*/
579 void mca_set_adapter_name(int slot
, char* name
)
581 if(mca_info
== NULL
) return;
583 if(slot
>= 0 && slot
< MCA_NUMADAPTERS
) {
585 strncpy(mca_info
->slot
[slot
].name
, name
,
586 sizeof(mca_info
->slot
[slot
].name
)-1);
587 mca_info
->slot
[slot
].name
[
588 sizeof(mca_info
->slot
[slot
].name
)-1] = 0;
590 mca_info
->slot
[slot
].name
[0] = 0;
595 void mca_set_adapter_procfn(int slot
, MCA_ProcFn procfn
, void* dev
)
597 if(mca_info
== NULL
) return;
599 if(slot
>= 0 && slot
< MCA_NUMADAPTERS
) {
600 mca_info
->slot
[slot
].procfn
= procfn
;
601 mca_info
->slot
[slot
].dev
= dev
;
605 int mca_is_adapter_used(int slot
)
607 return mca_info
->slot
[slot
].driver_loaded
;
610 int mca_mark_as_used(int slot
)
612 if(mca_info
->slot
[slot
].driver_loaded
) return 1;
613 mca_info
->slot
[slot
].driver_loaded
= 1;
617 void mca_mark_as_unused(int slot
)
619 mca_info
->slot
[slot
].driver_loaded
= 0;
622 char *mca_get_adapter_name(int slot
)
624 if(mca_info
== NULL
) return 0;
626 if(slot
>= 0 && slot
< MCA_NUMADAPTERS
) {
627 return mca_info
->slot
[slot
].name
;
633 int mca_isadapter(int slot
)
635 if(mca_info
== NULL
) return 0;
637 if(slot
>= 0 && slot
< MCA_NUMADAPTERS
) {
638 return ((mca_info
->slot
[slot
].status
== MCA_ADAPTER_NORMAL
)
639 || (mca_info
->slot
[slot
].status
== MCA_ADAPTER_DISABLED
));
645 int mca_isenabled(int slot
)
647 if(mca_info
== NULL
) return 0;
649 if(slot
>= 0 && slot
< MCA_NUMADAPTERS
) {
650 return (mca_info
->slot
[slot
].status
== MCA_ADAPTER_NORMAL
);
656 /*--------------------------------------------------------------------*/
658 #ifdef CONFIG_PROC_FS
660 int get_mca_info(char *buf
)
664 if(MCA_bus
&& mca_info
!= NULL
)
666 /* Format POS registers of eight MCA slots */
668 for(i
=0; i
<MCA_MAX_SLOT_NR
; i
++)
670 len
+= sprintf(buf
+len
, "Slot %d: ", i
+1);
672 len
+= sprintf(buf
+len
, "%02x ", mca_info
->slot
[i
].pos
[j
]);
673 len
+= sprintf(buf
+len
, " %s\n", mca_info
->slot
[i
].name
);
676 /* Format POS registers of integrated video subsystem */
678 len
+= sprintf(buf
+len
, "Video : ");
680 len
+= sprintf(buf
+len
, "%02x ", mca_info
->slot
[MCA_INTEGVIDEO
].pos
[j
]);
681 len
+= sprintf(buf
+len
, " %s\n", mca_info
->slot
[MCA_INTEGVIDEO
].name
);
683 /* Format POS registers of integrated SCSI subsystem */
685 len
+= sprintf(buf
+len
, "SCSI : ");
687 len
+= sprintf(buf
+len
, "%02x ", mca_info
->slot
[MCA_INTEGSCSI
].pos
[j
]);
688 len
+= sprintf(buf
+len
, " %s\n", mca_info
->slot
[MCA_INTEGSCSI
].name
);
690 /* Leave it empty if MCA not detected - this should *never*
699 /*--------------------------------------------------------------------*/
701 __initfunc(void mca_do_proc_init(void))
704 struct proc_dir_entry
* node
= NULL
;
706 if(mca_info
== NULL
) return; /* Should never happen */
708 proc_register(&proc_mca
, &(struct proc_dir_entry
) {
709 PROC_MCA_REGISTERS
, 3, "pos", S_IFREG
|S_IRUGO
,
710 1, 0, 0, 0, &proc_mca_inode_operations
,});
712 proc_register(&proc_mca
, &(struct proc_dir_entry
) {
713 PROC_MCA_MACHINE
, 7, "machine", S_IFREG
|S_IRUGO
,
714 1, 0, 0, 0, &proc_mca_inode_operations
,});
716 /* Initialize /proc/mca entries for existing adapters */
718 for(i
= 0; i
< MCA_NUMADAPTERS
; i
++) {
719 mca_info
->slot
[i
].procfn
= 0;
720 mca_info
->slot
[i
].dev
= 0;
722 if(!mca_isadapter(i
)) continue;
724 node
= (struct proc_dir_entry
*)kmalloc(sizeof(struct proc_dir_entry
), GFP_KERNEL
);
727 printk("Failed to allocate memory for MCA proc-entries!");
730 memset(node
, 0, sizeof(struct proc_dir_entry
));
732 if(i
< MCA_MAX_SLOT_NR
) {
733 node
->low_ino
= PROC_MCA_SLOT
+ i
;
734 node
->namelen
= sprintf(mca_info
->slot
[i
].procname
,
736 } else if(i
== MCA_INTEGVIDEO
) {
737 node
->low_ino
= PROC_MCA_VIDEO
;
738 node
->namelen
= sprintf(mca_info
->slot
[i
].procname
,
740 } else if(i
== MCA_INTEGSCSI
) {
741 node
->low_ino
= PROC_MCA_SCSI
;
742 node
->namelen
= sprintf(mca_info
->slot
[i
].procname
,
745 node
->name
= mca_info
->slot
[i
].procname
;
746 node
->mode
= S_IFREG
| S_IRUGO
;
747 node
->ops
= &proc_mca_inode_operations
;
748 proc_register(&proc_mca
, node
);
751 } /* mca_do_proc_init() */
753 /*--------------------------------------------------------------------*/
755 int mca_default_procfn(char* buf
, int slot
)
759 /* This really shouldn't happen... */
761 if(mca_info
== NULL
) {
766 /* Print out the basic information */
768 if(slot
< MCA_MAX_SLOT_NR
) {
769 len
+= sprintf(buf
+len
, "Slot: %d\n", slot
+1);
770 } else if(slot
== MCA_INTEGSCSI
) {
771 len
+= sprintf(buf
+len
, "Integrated SCSI Adapter\n");
772 } else if(slot
== MCA_INTEGVIDEO
) {
773 len
+= sprintf(buf
+len
, "Integrated Video Adapter\n");
775 if(mca_info
->slot
[slot
].name
[0]) {
777 /* Drivers might register a name without /proc handler... */
779 len
+= sprintf(buf
+len
, "Adapter Name: %s\n",
780 mca_info
->slot
[slot
].name
);
782 len
+= sprintf(buf
+len
, "Adapter Name: Unknown\n");
784 len
+= sprintf(buf
+len
, "Id: %02x%02x\n",
785 mca_info
->slot
[slot
].pos
[1], mca_info
->slot
[slot
].pos
[0]);
786 len
+= sprintf(buf
+len
, "Enabled: %s\nPOS: ",
787 mca_isenabled(slot
) ? "Yes" : "No");
789 len
+= sprintf(buf
+len
, "%02x ", mca_info
->slot
[slot
].pos
[i
]);
791 len
+= sprintf(buf
+len
, "\nDriver Installed: %s",
792 mca_is_adapter_used(slot
) ? "Yes" : "No");
797 } /* mca_default_procfn() */
799 static int get_mca_machine_info(char* buf
)
803 len
+= sprintf(buf
+len
, "Model Id: 0x%x\n", machine_id
);
804 len
+= sprintf(buf
+len
, "Submodel Id: 0x%x\n", machine_submodel_id
);
805 len
+= sprintf(buf
+len
, "BIOS Revision: 0x%x\n", BIOS_revision
);
810 static int mca_fill(char* page
, int pid
, int type
, char** start
,
811 loff_t
*offset
, int length
)
817 case PROC_MCA_REGISTERS
:
818 return get_mca_info(page
);
819 case PROC_MCA_MACHINE
:
820 return get_mca_machine_info(page
);
822 slot
= MCA_INTEGVIDEO
;
825 slot
= MCA_INTEGSCSI
;
828 if(type
< PROC_MCA_SLOT
|| type
>= PROC_MCA_LAST
) {
831 slot
= type
- PROC_MCA_SLOT
;
835 /* If we made it here, we better have a valid slot */
837 /* Get the standard info */
839 len
= mca_default_procfn(page
, slot
);
841 /* Do any device-specific processing, if there is any */
843 if(mca_info
->slot
[slot
].procfn
) {
844 len
+= mca_info
->slot
[slot
].procfn(page
+len
, slot
,
845 mca_info
->slot
[slot
].dev
);
851 /* Blatantly stolen from fs/proc/array.c, and thus is probably overkill */
853 #define PROC_BLOCK_SIZE (3*1024)
855 static ssize_t
proc_mca_read(struct file
* file
,
856 char* buf
, size_t count
, loff_t
*ppos
)
862 unsigned int type
, pid
;
863 struct proc_dir_entry
*dp
;
864 struct inode
*inode
= file
->f_dentry
->d_inode
;
868 if(count
> PROC_BLOCK_SIZE
)
869 count
= PROC_BLOCK_SIZE
;
870 if(!(page
= __get_free_page(GFP_KERNEL
)))
876 dp
= (struct proc_dir_entry
*) inode
->u
.generic_ip
;
877 length
= mca_fill((char *) page
, pid
, type
,
878 &start
, ppos
, count
);
884 /* We have had block-adjusting processing! */
886 copy_to_user(buf
, start
, length
);
890 /* Static 4kB (or whatever) block capacity */
892 if(*ppos
>= length
) {
896 if(count
+ *ppos
> length
)
897 count
= length
- *ppos
;
899 copy_to_user(buf
, (char *) page
+ *ppos
, count
);
904 } /* proc_mca_read() */