- Peter Anvin: more P4 configuration parsing
[davej-history.git] / arch / i386 / kernel / mca.c
blob104ae9e9e1d3c9413ac553918b14ab3ca087991c
1 /*
2 * linux/arch/i386/kernel/mca.c
3 * Written by Martin Kolinek, February 1996
5 * Changes:
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
13 * - Added name field
14 * - More sanity checking
16 * Chris Beauregard August 9th, 1996
17 * - Rewrote /proc/mca
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>
46 #include <asm/io.h>
47 #include <linux/proc_fs.h>
48 #include <linux/mman.h>
49 #include <linux/config.h>
50 #include <linux/mm.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.
63 typedef enum {
64 MCA_ADAPTER_NORMAL = 0,
65 MCA_ADAPTER_NONE = 1,
66 MCA_ADAPTER_DISABLED = 2,
67 MCA_ADAPTER_ERROR = 3
68 } MCA_AdapterStatus;
70 struct MCA_adapter {
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? */
75 /* 0 - No, 1 - Yes */
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 */
82 struct MCA_info {
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
100 * is set to zero.
103 static struct MCA_info* mca_info = NULL;
105 /* MCA registers */
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);
117 #endif
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;
141 return;
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) {
156 int j;
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;
161 break;
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)
190 unsigned int i, j;
191 unsigned long flags;
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 */
202 if(!MCA_bus)
203 return;
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!");
212 return;
214 memset(mca_info, 0, sizeof(struct MCA_info));
216 save_flags(flags);
217 cli();
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;
227 for(j=0; j<8; j++) {
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;
238 for(j=0; j<8; j++) {
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
252 * machine.
255 outb_p(0xf7, MCA_MOTHERBOARD_SETUP_REG);
256 mca_info->slot[MCA_INTEGSCSI].name[0] = 0;
257 for(j=0; j<8; j++) {
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);
278 for(j=0; j<8; j++)
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);
293 for(j=0; j<8; j++) {
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
310 mca_do_proc_init();
311 #endif
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? */
334 if(check_flag) {
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)
350 int i;
351 unsigned char pos5;
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);
366 if(!(pos5 & 0x80)) {
367 mca_handle_nmi_slot(i, !(pos5 & 0x40));
368 return;
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
374 * at the moment.
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) {
398 return MCA_NOTFOUND;
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) {
412 continue;
415 if(id == mca_info->slot[start].id) {
416 return start;
420 return MCA_NOTFOUND;
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) {
445 return MCA_NOTFOUND;
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) {
460 continue;
463 if(id == mca_info->slot[start].id) {
464 return start;
468 return MCA_NOTFOUND;
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;
510 unsigned long flags;
512 if(slot < 0 || slot >= MCA_NUMADAPTERS || mca_info == NULL) return 0;
513 if(reg < 0 || reg >= 8) return 0;
515 save_flags(flags);
516 cli();
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);
569 return byte;
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
597 * screws up.
600 void mca_write_pos(int slot, int reg, unsigned char byte)
602 unsigned long flags;
604 if(slot < 0 || slot >= MCA_MAX_SLOT_NR)
605 return;
606 if(reg < 0 || reg >= 8)
607 return;
608 if(mca_info == NULL)
609 return;
611 save_flags(flags);
612 cli();
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) {
650 if(name != NULL) {
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;
655 } else {
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
678 * nastiness.
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
715 * returned.
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;
722 return 0;
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;
757 return 0;
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
767 * it does.
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));
779 return 0;
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);
801 return 0;
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)
813 int i, j, len = 0;
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);
820 for(j=0; j<8; j++)
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 : ");
828 for(j=0; j<8; j++)
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 : ");
835 for(j=0; j<8; j++)
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: ");
842 for(j=0; j<8; j++)
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);
845 } else {
846 /* Leave it empty if MCA not detected - this should *never*
847 * happen!
851 if (len <= off+count) *eof = 1;
852 *start = page + off;
853 len -= off;
854 if (len>count) len = count;
855 if (len<0) len = 0;
856 return len;
859 /*--------------------------------------------------------------------*/
861 static int mca_default_procfn(char* buf, struct MCA_adapter *p)
863 int len = 0, i;
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");
877 if(p->name[0]) {
879 /* Drivers might register a name without /proc handler... */
881 len += sprintf(buf+len, "Adapter Name: %s\n",
882 p->name);
883 } else {
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");
890 for(i=0; i<8; i++) {
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");
895 buf[len++] = '\n';
896 buf[len] = 0;
898 return len;
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)
904 int len = 0;
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;
911 *start = page + off;
912 len -= off;
913 if (len>count) len = count;
914 if (len<0) len = 0;
915 return len;
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;
922 int len = 0;
924 /* Get the standard info */
926 len = mca_default_procfn(page, p);
928 /* Do any device-specific processing, if there is any */
930 if(p->procfn) {
931 len += p->procfn(page+len, p-mca_info->slot, p->dev);
933 if (len <= off+count) *eof = 1;
934 *start = page + off;
935 len -= off;
936 if (len>count) len = count;
937 if (len<0) len = 0;
938 return len;
939 } /* mca_read_proc() */
941 /*--------------------------------------------------------------------*/
943 void __init mca_do_proc_init(void)
945 int i;
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];
960 p->procfn = 0;
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);
972 if(node == NULL) {
973 printk("Failed to allocate memory for MCA proc-entries!");
974 return;
978 } /* mca_do_proc_init() */
980 #endif