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
33 * Alexander Viro November 9th, 1999
34 * - Switched to regular procfs methods
36 * Alfred Arnold & David Weinehall August 23rd, 2000
37 * - Added support for Planar POS-registers
40 #include <linux/module.h>
41 #include <linux/types.h>
42 #include <linux/errno.h>
43 #include <linux/kernel.h>
44 #include <linux/mca.h>
45 #include <asm/system.h>
47 #include <linux/proc_fs.h>
48 #include <linux/mman.h>
49 #include <linux/config.h>
51 #include <linux/pagemap.h>
52 #include <linux/ioport.h>
53 #include <asm/uaccess.h>
54 #include <linux/init.h>
56 /* This structure holds MCA information. Each (plug-in) adapter has
57 * eight POS registers. Then the machine may have integrated video and
58 * SCSI subsystems, which also have eight POS registers.
59 * Finally, the motherboard (planar) has got POS-registers.
60 * Other miscellaneous information follows.
64 MCA_ADAPTER_NORMAL
= 0,
66 MCA_ADAPTER_DISABLED
= 2,
71 MCA_AdapterStatus status
; /* is there a valid adapter? */
72 int id
; /* adapter id value */
73 unsigned char pos
[8]; /* POS registers */
74 int driver_loaded
; /* is there a driver installed? */
76 char name
[48]; /* adapter-name provided by driver */
77 char procname
[8]; /* name of /proc/mca file */
78 MCA_ProcFn procfn
; /* /proc info callback */
79 void* dev
; /* device/context info for callback */
83 /* one for each of the 8 possible slots, plus one for integrated SCSI
84 * and one for integrated video.
87 struct MCA_adapter slot
[MCA_NUMADAPTERS
];
89 /* two potential addresses for integrated SCSI adapter - this will
90 * track which one we think it is.
93 unsigned char which_scsi
;
96 /* The mca_info structure pointer. If MCA bus is present, the function
97 * mca_probe() is invoked. The function puts motherboard, then all
98 * adapters into setup mode, allocates and fills an MCA_info structure,
99 * and points this pointer to the structure. Otherwise the pointer
103 static struct MCA_info
* mca_info
= NULL
;
107 #define MCA_MOTHERBOARD_SETUP_REG 0x94
108 #define MCA_ADAPTER_SETUP_REG 0x96
109 #define MCA_POS_REG(n) (0x100+(n))
111 #define MCA_ENABLED 0x01 /* POS 2, set if adapter enabled */
113 /*--------------------------------------------------------------------*/
115 #ifdef CONFIG_PROC_FS
116 static void mca_do_proc_init(void);
119 /*--------------------------------------------------------------------*/
121 /* Build the status info for the adapter */
123 static void mca_configure_adapter_status(int slot
) {
124 mca_info
->slot
[slot
].status
= MCA_ADAPTER_NONE
;
126 mca_info
->slot
[slot
].id
= mca_info
->slot
[slot
].pos
[0]
127 + (mca_info
->slot
[slot
].pos
[1] << 8);
129 if(!mca_info
->slot
[slot
].id
&& slot
< MCA_MAX_SLOT_NR
) {
131 /* id = 0x0000 usually indicates hardware failure,
132 * however, ZP Gu (zpg@castle.net> reports that his 9556
133 * has 0x0000 as id and everything still works. There
134 * also seem to be an adapter with id = 0x0000; the
135 * NCR Parallel Bus Memory Card. Until this is confirmed,
136 * however, this code will stay.
139 mca_info
->slot
[slot
].status
= MCA_ADAPTER_ERROR
;
142 } else if(mca_info
->slot
[slot
].id
!= 0xffff) {
144 /* 0xffff usually indicates that there's no adapter,
145 * however, some integrated adapters may have 0xffff as
146 * their id and still be valid. Examples are on-board
147 * VGA of the 55sx, the integrated SCSI of the 56 & 57,
148 * and possibly also the 95 ULTIMEDIA.
151 mca_info
->slot
[slot
].status
= MCA_ADAPTER_NORMAL
;
154 if((mca_info
->slot
[slot
].id
== 0xffff ||
155 mca_info
->slot
[slot
].id
== 0x0000) && slot
>= MCA_MAX_SLOT_NR
) {
158 for(j
= 2; j
< 8; j
++) {
159 if(mca_info
->slot
[slot
].pos
[j
] != 0xff) {
160 mca_info
->slot
[slot
].status
= MCA_ADAPTER_NORMAL
;
166 if(!(mca_info
->slot
[slot
].pos
[2] & MCA_ENABLED
)) {
168 /* enabled bit is in POS 2 */
170 mca_info
->slot
[slot
].status
= MCA_ADAPTER_DISABLED
;
172 } /* mca_configure_adapter_status */
174 /*--------------------------------------------------------------------*/
176 struct resource mca_standard_resources
[] = {
177 { "system control port B (MCA)", 0x60, 0x60 },
178 { "arbitration (MCA)", 0x90, 0x90 },
179 { "card Select Feedback (MCA)", 0x91, 0x91 },
180 { "system Control port A (MCA)", 0x92, 0x92 },
181 { "system board setup (MCA)", 0x94, 0x94 },
182 { "POS (MCA)", 0x96, 0x97 },
183 { "POS (MCA)", 0x100, 0x107 }
186 #define MCA_STANDARD_RESOURCES (sizeof(mca_standard_resources)/sizeof(struct resource))
188 void __init
mca_init(void)
193 /* WARNING: Be careful when making changes here. Putting an adapter
194 * and the motherboard simultaneously into setup mode may result in
195 * damage to chips (according to The Indispensible PC Hardware Book
196 * by Hans-Peter Messmer). Also, we disable system interrupts (so
197 * that we are not disturbed in the middle of this).
200 /* Make sure the MCA bus is present */
204 printk("Micro Channel bus detected.\n");
206 /* Allocate MCA_info structure (at address divisible by 8) */
208 mca_info
= (struct MCA_info
*)kmalloc(sizeof(struct MCA_info
), GFP_KERNEL
);
210 if(mca_info
== NULL
) {
211 printk("Failed to allocate memory for mca_info!");
214 memset(mca_info
, 0, sizeof(struct MCA_info
));
219 /* Make sure adapter setup is off */
221 outb_p(0, MCA_ADAPTER_SETUP_REG
);
223 /* Read motherboard POS registers */
225 outb_p(0x7f, MCA_MOTHERBOARD_SETUP_REG
);
226 mca_info
->slot
[MCA_MOTHERBOARD
].name
[0] = 0;
228 mca_info
->slot
[MCA_MOTHERBOARD
].pos
[j
] = inb_p(MCA_POS_REG(j
));
230 mca_configure_adapter_status(MCA_MOTHERBOARD
);
232 /* Put motherboard into video setup mode, read integrated video
233 * POS registers, and turn motherboard setup off.
236 outb_p(0xdf, MCA_MOTHERBOARD_SETUP_REG
);
237 mca_info
->slot
[MCA_INTEGVIDEO
].name
[0] = 0;
239 mca_info
->slot
[MCA_INTEGVIDEO
].pos
[j
] = inb_p(MCA_POS_REG(j
));
241 mca_configure_adapter_status(MCA_INTEGVIDEO
);
243 /* Put motherboard into scsi setup mode, read integrated scsi
244 * POS registers, and turn motherboard setup off.
246 * It seems there are two possible SCSI registers. Martin says that
247 * for the 56,57, 0xf7 is the one, but fails on the 76.
248 * Alfredo (apena@vnet.ibm.com) says
249 * 0xfd works on his machine. We'll try both of them. I figure it's
250 * a good bet that only one could be valid at a time. This could
251 * screw up though if one is used for something else on the other
255 outb_p(0xf7, MCA_MOTHERBOARD_SETUP_REG
);
256 mca_info
->slot
[MCA_INTEGSCSI
].name
[0] = 0;
258 if((mca_info
->slot
[MCA_INTEGSCSI
].pos
[j
] = inb_p(MCA_POS_REG(j
))) != 0xff)
260 /* 0xff all across means no device. 0x00 means
261 * something's broken, but a device is probably there.
262 * However, if you get 0x00 from a motherboard
263 * register it won't matter what we find. For the
264 * record, on the 57SLC, the integrated SCSI
265 * adapter has 0xffff for the adapter ID, but
266 * nonzero for other registers.
269 mca_info
->which_scsi
= 0xf7;
272 if(!mca_info
->which_scsi
) {
274 /* Didn't find it at 0xf7, try somewhere else... */
275 mca_info
->which_scsi
= 0xfd;
277 outb_p(0xfd, MCA_MOTHERBOARD_SETUP_REG
);
279 mca_info
->slot
[MCA_INTEGSCSI
].pos
[j
] = inb_p(MCA_POS_REG(j
));
281 mca_configure_adapter_status(MCA_INTEGSCSI
);
283 /* Turn off motherboard setup */
285 outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG
);
287 /* Now loop over MCA slots: put each adapter into setup mode, and
288 * read its POS registers. Then put adapter setup off.
291 for(i
=0; i
<MCA_MAX_SLOT_NR
; i
++) {
292 outb_p(0x8|(i
&0xf), MCA_ADAPTER_SETUP_REG
);
294 mca_info
->slot
[i
].pos
[j
]=inb_p(MCA_POS_REG(j
));
296 mca_info
->slot
[i
].name
[0] = 0;
297 mca_info
->slot
[i
].driver_loaded
= 0;
298 mca_configure_adapter_status(i
);
300 outb_p(0, MCA_ADAPTER_SETUP_REG
);
302 /* Enable interrupts and return memory start */
304 restore_flags(flags
);
306 for (i
= 0; i
< MCA_STANDARD_RESOURCES
; i
++)
307 request_resource(&ioport_resource
, mca_standard_resources
+ i
);
309 #ifdef CONFIG_PROC_FS
314 /*--------------------------------------------------------------------*/
316 static void mca_handle_nmi_slot(int slot
, int check_flag
)
318 if(slot
< MCA_MAX_SLOT_NR
) {
319 printk("NMI: caused by MCA adapter in slot %d (%s)\n", slot
+1,
320 mca_info
->slot
[slot
].name
);
321 } else if(slot
== MCA_INTEGSCSI
) {
322 printk("NMI: caused by MCA integrated SCSI adapter (%s)\n",
323 mca_info
->slot
[slot
].name
);
324 } else if(slot
== MCA_INTEGVIDEO
) {
325 printk("NMI: caused by MCA integrated video adapter (%s)\n",
326 mca_info
->slot
[slot
].name
);
327 } else if(slot
== MCA_MOTHERBOARD
) {
328 printk("NMI: caused by motherboard (%s)\n",
329 mca_info
->slot
[slot
].name
);
332 /* More info available in POS 6 and 7? */
335 unsigned char pos6
, pos7
;
337 pos6
= mca_read_pos(slot
, 6);
338 pos7
= mca_read_pos(slot
, 7);
340 printk("NMI: POS 6 = 0x%x, POS 7 = 0x%x\n", pos6
, pos7
);
343 } /* mca_handle_nmi_slot */
345 /*--------------------------------------------------------------------*/
347 void mca_handle_nmi(void)
353 /* First try - scan the various adapters and see if a specific
354 * adapter was responsible for the error.
357 for(i
= 0; i
< MCA_NUMADAPTERS
; i
++) {
359 /* Bit 7 of POS 5 is reset when this adapter has a hardware
360 * error. Bit 7 it reset if there's error information
361 * available in POS 6 and 7.
364 pos5
= mca_read_pos(i
, 5);
367 mca_handle_nmi_slot(i
, !(pos5
& 0x40));
372 /* If I recall correctly, there's a whole bunch of other things that
373 * we can do to check for NMI problems, but that's all I know about
377 printk("NMI generated from unknown source!\n");
378 } /* mca_handle_nmi */
380 /*--------------------------------------------------------------------*/
383 * mca_find_adapter - scan for adapters
384 * @id: MCA identification to search for
385 * @start: starting slot
387 * Search the MCA configuration for adapters matching the 16bit
388 * ID given. The first time it should be called with start as zero
389 * and then further calls made passing the return value of the
390 * previous call until %MCA_NOTFOUND is returned.
392 * Disabled adapters are not reported.
395 int mca_find_adapter(int id
, int start
)
397 if(mca_info
== NULL
|| id
== 0xffff) {
401 for(; start
>= 0 && start
< MCA_NUMADAPTERS
; start
++) {
403 /* Not sure about this. There's no point in returning
404 * adapters that aren't enabled, since they can't actually
405 * be used. However, they might be needed for statistical
406 * purposes or something... But if that is the case, the
407 * user is free to write a routine that manually iterates
408 * through the adapters.
411 if(mca_info
->slot
[start
].status
== MCA_ADAPTER_DISABLED
) {
415 if(id
== mca_info
->slot
[start
].id
) {
421 } /* mca_find_adapter() */
423 EXPORT_SYMBOL(mca_find_adapter
);
425 /*--------------------------------------------------------------------*/
428 * mca_find_unused_adapter - scan for unused adapters
429 * @id: MCA identification to search for
430 * @start: starting slot
432 * Search the MCA configuration for adapters matching the 16bit
433 * ID given. The first time it should be called with start as zero
434 * and then further calls made passing the return value of the
435 * previous call until %MCA_NOTFOUND is returned.
437 * Adapters that have been claimed by drivers and those that
438 * are disabled are not reported. This function thus allows a driver
439 * to scan for further cards when some may already be driven.
442 int mca_find_unused_adapter(int id
, int start
)
444 if(mca_info
== NULL
|| id
== 0xffff) {
448 for(; start
>= 0 && start
< MCA_NUMADAPTERS
; start
++) {
450 /* not sure about this. There's no point in returning
451 * adapters that aren't enabled, since they can't actually
452 * be used. However, they might be needed for statistical
453 * purposes or something... But if that is the case, the
454 * user is free to write a routine that manually iterates
455 * through the adapters.
458 if(mca_info
->slot
[start
].status
== MCA_ADAPTER_DISABLED
||
459 mca_info
->slot
[start
].driver_loaded
) {
463 if(id
== mca_info
->slot
[start
].id
) {
469 } /* mca_find_unused_adapter() */
471 EXPORT_SYMBOL(mca_find_unused_adapter
);
473 /*--------------------------------------------------------------------*/
476 * mca_read_stored_pos - read POS register from boot data
477 * @slot: slot number to read from
478 * @reg: register to read from
480 * Fetch a POS value that was stored at boot time by the kernel
481 * when it scanned the MCA space. The register value is returned.
482 * Missing or invalid registers report 0.
485 unsigned char mca_read_stored_pos(int slot
, int reg
)
487 if(slot
< 0 || slot
>= MCA_NUMADAPTERS
|| mca_info
== NULL
) return 0;
488 if(reg
< 0 || reg
>= 8) return 0;
489 return mca_info
->slot
[slot
].pos
[reg
];
490 } /* mca_read_stored_pos() */
492 EXPORT_SYMBOL(mca_read_stored_pos
);
494 /*--------------------------------------------------------------------*/
497 * mca_read_pos - read POS register from card
498 * @slot: slot number to read from
499 * @reg: register to read from
501 * Fetch a POS value directly from the hardware to obtain the
502 * current value. This is much slower than mca_read_stored_pos and
503 * may not be invoked from interrupt context. It handles the
504 * deep magic required for onboard devices transparently.
507 unsigned char mca_read_pos(int slot
, int reg
)
509 unsigned int byte
= 0;
512 if(slot
< 0 || slot
>= MCA_NUMADAPTERS
|| mca_info
== NULL
) return 0;
513 if(reg
< 0 || reg
>= 8) return 0;
518 /* Make sure motherboard setup is off */
520 outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG
);
522 /* Read in the appropriate register */
524 if(slot
== MCA_INTEGSCSI
&& mca_info
->which_scsi
) {
526 /* Disable adapter setup, enable motherboard setup */
528 outb_p(0, MCA_ADAPTER_SETUP_REG
);
529 outb_p(mca_info
->which_scsi
, MCA_MOTHERBOARD_SETUP_REG
);
531 byte
= inb_p(MCA_POS_REG(reg
));
532 outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG
);
533 } else if(slot
== MCA_INTEGVIDEO
) {
535 /* Disable adapter setup, enable motherboard setup */
537 outb_p(0, MCA_ADAPTER_SETUP_REG
);
538 outb_p(0xdf, MCA_MOTHERBOARD_SETUP_REG
);
540 byte
= inb_p(MCA_POS_REG(reg
));
541 outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG
);
542 } else if(slot
== MCA_MOTHERBOARD
) {
544 /* Disable adapter setup, enable motherboard setup */
545 outb_p(0, MCA_ADAPTER_SETUP_REG
);
546 outb_p(0x7f, MCA_MOTHERBOARD_SETUP_REG
);
548 byte
= inb_p(MCA_POS_REG(reg
));
549 outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG
);
550 } else if(slot
< MCA_MAX_SLOT_NR
) {
552 /* Make sure motherboard setup is off */
554 outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG
);
556 /* Read the appropriate register */
558 outb_p(0x8|(slot
&0xf), MCA_ADAPTER_SETUP_REG
);
559 byte
= inb_p(MCA_POS_REG(reg
));
560 outb_p(0, MCA_ADAPTER_SETUP_REG
);
563 /* Make sure the stored values are consistent, while we're here */
565 mca_info
->slot
[slot
].pos
[reg
] = byte
;
567 restore_flags(flags
);
570 } /* mca_read_pos() */
572 EXPORT_SYMBOL(mca_read_pos
);
574 /*--------------------------------------------------------------------*/
577 * mca_write_pos - read POS register from card
578 * @slot: slot number to read from
579 * @reg: register to read from
580 * @byte: byte to write to the POS registers
582 * Store a POS value directly from the hardware. You should not
583 * normally need to use this function and should have a very good
584 * knowledge of MCA bus before you do so. Doing this wrongly can
585 * damage the hardware.
587 * This function may not be used from interrupt context.
589 * Note that this a technically a Bad Thing, as IBM tech stuff says
590 * you should only set POS values through their utilities.
591 * However, some devices such as the 3c523 recommend that you write
592 * back some data to make sure the configuration is consistent.
593 * I'd say that IBM is right, but I like my drivers to work.
595 * This function can't do checks to see if multiple devices end up
596 * with the same resources, so you might see magic smoke if someone
600 void mca_write_pos(int slot
, int reg
, unsigned char byte
)
604 if(slot
< 0 || slot
>= MCA_MAX_SLOT_NR
)
606 if(reg
< 0 || reg
>= 8)
614 /* Make sure motherboard setup is off */
616 outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG
);
618 /* Read in the appropriate register */
620 outb_p(0x8|(slot
&0xf), MCA_ADAPTER_SETUP_REG
);
621 outb_p(byte
, MCA_POS_REG(reg
));
622 outb_p(0, MCA_ADAPTER_SETUP_REG
);
624 restore_flags(flags
);
626 /* Update the global register list, while we have the byte */
628 mca_info
->slot
[slot
].pos
[reg
] = byte
;
629 } /* mca_write_pos() */
631 EXPORT_SYMBOL(mca_write_pos
);
633 /*--------------------------------------------------------------------*/
636 * mca_set_adapter_name - Set the description of the card
637 * @slot: slot to name
638 * @name: text string for the namen
640 * This function sets the name reported via /proc for this
641 * adapter slot. This is for user information only. Setting a
642 * name deletes any previous name.
645 void mca_set_adapter_name(int slot
, char* name
)
647 if(mca_info
== NULL
) return;
649 if(slot
>= 0 && slot
< MCA_NUMADAPTERS
) {
651 strncpy(mca_info
->slot
[slot
].name
, name
,
652 sizeof(mca_info
->slot
[slot
].name
)-1);
653 mca_info
->slot
[slot
].name
[
654 sizeof(mca_info
->slot
[slot
].name
)-1] = 0;
656 mca_info
->slot
[slot
].name
[0] = 0;
661 EXPORT_SYMBOL(mca_set_adapter_name
);
664 * mca_set_adapter_procfn - Set the /proc callback
665 * @slot: slot to configure
666 * @procfn: callback function to call for /proc
667 * @dev: device information passed to the callback
669 * This sets up an information callback for /proc/mca/slot?. The
670 * function is called with the buffer, slot, and device pointer (or
671 * some equally informative context information, or nothing, if you
672 * prefer), and is expected to put useful information into the
673 * buffer. The adapter name, ID, and POS registers get printed
674 * before this is called though, so don't do it again.
676 * This should be called with a %NULL @procfn when a module
677 * unregisters, thus preventing kernel crashes and other such
681 void mca_set_adapter_procfn(int slot
, MCA_ProcFn procfn
, void* dev
)
683 if(mca_info
== NULL
) return;
685 if(slot
>= 0 && slot
< MCA_NUMADAPTERS
) {
686 mca_info
->slot
[slot
].procfn
= procfn
;
687 mca_info
->slot
[slot
].dev
= dev
;
691 EXPORT_SYMBOL(mca_set_adapter_procfn
);
694 * mca_is_adapter_used - check if claimed by driver
695 * @slot: slot to check
697 * Returns 1 if the slot has been claimed by a driver
700 int mca_is_adapter_used(int slot
)
702 return mca_info
->slot
[slot
].driver_loaded
;
705 EXPORT_SYMBOL(mca_is_adapter_used
);
708 * mca_mark_as_used - claim an MCA device
709 * @slot: slot to claim
710 * FIXME: should we make this threadsafe
712 * Claim an MCA slot for a device driver. If the
713 * slot is already taken the function returns 1,
714 * if it is not taken it is claimed and 0 is
718 int mca_mark_as_used(int slot
)
720 if(mca_info
->slot
[slot
].driver_loaded
) return 1;
721 mca_info
->slot
[slot
].driver_loaded
= 1;
725 EXPORT_SYMBOL(mca_mark_as_used
);
728 * mca_mark_as_unused - release an MCA device
729 * @slot: slot to claim
731 * Release the slot for other drives to use.
734 void mca_mark_as_unused(int slot
)
736 mca_info
->slot
[slot
].driver_loaded
= 0;
739 EXPORT_SYMBOL(mca_mark_as_unused
);
742 * mca_get_adapter_name - get the adapter description
743 * @slot: slot to query
745 * Return the adapter description if set. If it has not been
746 * set or the slot is out range then return NULL.
749 char *mca_get_adapter_name(int slot
)
751 if(mca_info
== NULL
) return 0;
753 if(slot
>= 0 && slot
< MCA_NUMADAPTERS
) {
754 return mca_info
->slot
[slot
].name
;
760 EXPORT_SYMBOL(mca_get_adapter_name
);
763 * mca_isadapter - check if the slot holds an adapter
764 * @slot: slot to query
766 * Returns zero if the slot does not hold an adapter, non zero if
770 int mca_isadapter(int slot
)
772 if(mca_info
== NULL
) return 0;
774 if(slot
>= 0 && slot
< MCA_NUMADAPTERS
) {
775 return ((mca_info
->slot
[slot
].status
== MCA_ADAPTER_NORMAL
)
776 || (mca_info
->slot
[slot
].status
== MCA_ADAPTER_DISABLED
));
782 EXPORT_SYMBOL(mca_isadapter
);
786 * mca_isadapter - check if the slot holds an adapter
787 * @slot: slot to query
789 * Returns a non zero value if the slot holds an enabled adapter
790 * and zero for any other case.
793 int mca_isenabled(int slot
)
795 if(mca_info
== NULL
) return 0;
797 if(slot
>= 0 && slot
< MCA_NUMADAPTERS
) {
798 return (mca_info
->slot
[slot
].status
== MCA_ADAPTER_NORMAL
);
804 EXPORT_SYMBOL(mca_isenabled
);
806 /*--------------------------------------------------------------------*/
808 #ifdef CONFIG_PROC_FS
810 int get_mca_info(char *page
, char **start
, off_t off
,
811 int count
, int *eof
, void *data
)
815 if(MCA_bus
&& mca_info
!= NULL
) {
816 /* Format POS registers of eight MCA slots */
818 for(i
=0; i
<MCA_MAX_SLOT_NR
; i
++) {
819 len
+= sprintf(page
+len
, "Slot %d: ", i
+1);
821 len
+= sprintf(page
+len
, "%02x ", mca_info
->slot
[i
].pos
[j
]);
822 len
+= sprintf(page
+len
, " %s\n", mca_info
->slot
[i
].name
);
825 /* Format POS registers of integrated video subsystem */
827 len
+= sprintf(page
+len
, "Video : ");
829 len
+= sprintf(page
+len
, "%02x ", mca_info
->slot
[MCA_INTEGVIDEO
].pos
[j
]);
830 len
+= sprintf(page
+len
, " %s\n", mca_info
->slot
[MCA_INTEGVIDEO
].name
);
832 /* Format POS registers of integrated SCSI subsystem */
834 len
+= sprintf(page
+len
, "SCSI : ");
836 len
+= sprintf(page
+len
, "%02x ", mca_info
->slot
[MCA_INTEGSCSI
].pos
[j
]);
837 len
+= sprintf(page
+len
, " %s\n", mca_info
->slot
[MCA_INTEGSCSI
].name
);
839 /* Format POS registers of motherboard */
841 len
+= sprintf(page
+len
, "Planar: ");
843 len
+= sprintf(page
+len
, "%02x ", mca_info
->slot
[MCA_MOTHERBOARD
].pos
[j
]);
844 len
+= sprintf(page
+len
, " %s\n", mca_info
->slot
[MCA_MOTHERBOARD
].name
);
846 /* Leave it empty if MCA not detected - this should *never*
851 if (len
<= off
+count
) *eof
= 1;
854 if (len
>count
) len
= count
;
859 /*--------------------------------------------------------------------*/
861 static int mca_default_procfn(char* buf
, struct MCA_adapter
*p
)
864 int slot
= p
- mca_info
->slot
;
866 /* Print out the basic information */
868 if(slot
< MCA_MAX_SLOT_NR
) {
869 len
+= sprintf(buf
+len
, "Slot: %d\n", slot
+1);
870 } else if(slot
== MCA_INTEGSCSI
) {
871 len
+= sprintf(buf
+len
, "Integrated SCSI Adapter\n");
872 } else if(slot
== MCA_INTEGVIDEO
) {
873 len
+= sprintf(buf
+len
, "Integrated Video Adapter\n");
874 } else if(slot
== MCA_MOTHERBOARD
) {
875 len
+= sprintf(buf
+len
, "Motherboard\n");
879 /* Drivers might register a name without /proc handler... */
881 len
+= sprintf(buf
+len
, "Adapter Name: %s\n",
884 len
+= sprintf(buf
+len
, "Adapter Name: Unknown\n");
886 len
+= sprintf(buf
+len
, "Id: %02x%02x\n",
887 p
->pos
[1], p
->pos
[0]);
888 len
+= sprintf(buf
+len
, "Enabled: %s\nPOS: ",
889 mca_isenabled(slot
) ? "Yes" : "No");
891 len
+= sprintf(buf
+len
, "%02x ", p
->pos
[i
]);
893 len
+= sprintf(buf
+len
, "\nDriver Installed: %s",
894 mca_is_adapter_used(slot
) ? "Yes" : "No");
899 } /* mca_default_procfn() */
901 static int get_mca_machine_info(char* page
, char **start
, off_t off
,
902 int count
, int *eof
, void *data
)
906 len
+= sprintf(page
+len
, "Model Id: 0x%x\n", machine_id
);
907 len
+= sprintf(page
+len
, "Submodel Id: 0x%x\n", machine_submodel_id
);
908 len
+= sprintf(page
+len
, "BIOS Revision: 0x%x\n", BIOS_revision
);
910 if (len
<= off
+count
) *eof
= 1;
913 if (len
>count
) len
= count
;
918 static int mca_read_proc(char *page
, char **start
, off_t off
,
919 int count
, int *eof
, void *data
)
921 struct MCA_adapter
*p
= (struct MCA_adapter
*)data
;
924 /* Get the standard info */
926 len
= mca_default_procfn(page
, p
);
928 /* Do any device-specific processing, if there is any */
931 len
+= p
->procfn(page
+len
, p
-mca_info
->slot
, p
->dev
);
933 if (len
<= off
+count
) *eof
= 1;
936 if (len
>count
) len
= count
;
939 } /* mca_read_proc() */
941 /*--------------------------------------------------------------------*/
943 void __init
mca_do_proc_init(void)
946 struct proc_dir_entry
*proc_mca
;
947 struct proc_dir_entry
* node
= NULL
;
948 struct MCA_adapter
*p
;
950 if(mca_info
== NULL
) return; /* Should never happen */
952 proc_mca
= proc_mkdir("mca", &proc_root
);
953 create_proc_read_entry("pos",0,proc_mca
,get_mca_info
,NULL
);
954 create_proc_read_entry("machine",0,proc_mca
,get_mca_machine_info
,NULL
);
956 /* Initialize /proc/mca entries for existing adapters */
958 for(i
= 0; i
< MCA_NUMADAPTERS
; i
++) {
959 p
= &mca_info
->slot
[i
];
962 if(i
< MCA_MAX_SLOT_NR
) sprintf(p
->procname
,"slot%d", i
+1);
963 else if(i
== MCA_INTEGVIDEO
) sprintf(p
->procname
,"video");
964 else if(i
== MCA_INTEGSCSI
) sprintf(p
->procname
,"scsi");
965 else if(i
== MCA_MOTHERBOARD
) sprintf(p
->procname
,"planar");
967 if(!mca_isadapter(i
)) continue;
969 node
= create_proc_read_entry(p
->procname
, 0, proc_mca
,
970 mca_read_proc
, (void *)p
);
973 printk("Failed to allocate memory for MCA proc-entries!");
978 } /* mca_do_proc_init() */