File: /usr/src/linux/arch/i386/kernel/mca.c

1     /*
2      *  linux/arch/i386/kernel/mca.c
3      *  Written by Martin Kolinek, February 1996
4      *
5      * Changes:
6      *
7      *	Chris Beauregard July 28th, 1996
8      *	- Fixed up integrated SCSI detection
9      *
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
15      *
16      *	Chris Beauregard August 9th, 1996
17      *	- Rewrote /proc/mca
18      *
19      *	Chris Beauregard January 7th, 1997
20      *	- Added basic NMI-processing
21      *	- Added more information to mca_info structure
22      *
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
28      *
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
32      *
33      *	Alexander Viro November 9th, 1999
34      *	- Switched to regular procfs methods
35      *
36      *	Alfred Arnold & David Weinehall August 23rd, 2000
37      *	- Added support for Planar POS-registers
38      */
39     
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>
55     
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.
61      */
62     
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;
69     
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 */
80     };
81     
82     struct MCA_info {
83     	/* one for each of the 8 possible slots, plus one for integrated SCSI
84     	 * and one for integrated video.
85     	 */
86     
87     	struct MCA_adapter slot[MCA_NUMADAPTERS];
88     
89     	/* two potential addresses for integrated SCSI adapter - this will
90     	 * track which one we think it is.
91     	 */
92     
93     	unsigned char which_scsi;
94     };
95     
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.
101      */
102     
103     static struct MCA_info* mca_info = NULL;
104     
105     /* MCA registers */
106     
107     #define MCA_MOTHERBOARD_SETUP_REG	0x94
108     #define MCA_ADAPTER_SETUP_REG		0x96
109     #define MCA_POS_REG(n)			(0x100+(n))
110     
111     #define MCA_ENABLED	0x01	/* POS 2, set if adapter enabled */
112     
113     /*--------------------------------------------------------------------*/
114     
115     #ifdef CONFIG_PROC_FS
116     static void mca_do_proc_init(void);
117     #endif
118     
119     /*--------------------------------------------------------------------*/
120     
121     /* Build the status info for the adapter */
122     
123     static void mca_configure_adapter_status(int slot) {
124     	mca_info->slot[slot].status = MCA_ADAPTER_NONE;
125     
126     	mca_info->slot[slot].id = mca_info->slot[slot].pos[0]
127     		+ (mca_info->slot[slot].pos[1] << 8);
128     
129     	if(!mca_info->slot[slot].id && slot < MCA_MAX_SLOT_NR) {
130     
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.
137     		 */
138     
139     		mca_info->slot[slot].status = MCA_ADAPTER_ERROR;
140     
141     		return;
142     	} else if(mca_info->slot[slot].id != 0xffff) {
143     
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.
149     		 */
150     
151     		mca_info->slot[slot].status = MCA_ADAPTER_NORMAL;
152     	}
153     
154     	if((mca_info->slot[slot].id == 0xffff ||
155     	   mca_info->slot[slot].id == 0x0000) && slot >= MCA_MAX_SLOT_NR) {
156     		int j;
157     
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;
162     			}
163     		}
164     	}
165     
166     	if(!(mca_info->slot[slot].pos[2] & MCA_ENABLED)) {
167     
168     		/* enabled bit is in POS 2 */
169     
170     		mca_info->slot[slot].status = MCA_ADAPTER_DISABLED;
171     	}
172     } /* mca_configure_adapter_status */
173     
174     /*--------------------------------------------------------------------*/
175     
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 }
184     };
185     
186     #define MCA_STANDARD_RESOURCES	(sizeof(mca_standard_resources)/sizeof(struct resource))
187     
188     void __init mca_init(void)
189     {
190     	unsigned int i, j;
191     	unsigned long flags;
192     
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).
198     	 */
199     
200     	/* Make sure the MCA bus is present */
201     
202     	if(!MCA_bus)
203     		return;
204     	printk("Micro Channel bus detected.\n");
205     
206     	/* Allocate MCA_info structure (at address divisible by 8) */
207     
208     	mca_info = (struct MCA_info *)kmalloc(sizeof(struct MCA_info), GFP_KERNEL);
209     
210     	if(mca_info == NULL) {
211     		printk("Failed to allocate memory for mca_info!");
212     		return;
213     	}
214     	memset(mca_info, 0, sizeof(struct MCA_info));
215     
216     	save_flags(flags);
217     	cli();
218     
219     	/* Make sure adapter setup is off */
220     
221     	outb_p(0, MCA_ADAPTER_SETUP_REG);
222     
223     	/* Read motherboard POS registers */
224     
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));
229     	}
230     	mca_configure_adapter_status(MCA_MOTHERBOARD);
231     
232     	/* Put motherboard into video setup mode, read integrated video
233     	 * POS registers, and turn motherboard setup off.
234     	 */
235     
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));
240     	}
241     	mca_configure_adapter_status(MCA_INTEGVIDEO);
242     
243     	/* Put motherboard into scsi setup mode, read integrated scsi
244     	 * POS registers, and turn motherboard setup off.
245     	 *
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.
253     	 */
254     
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)
259     		{
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.
267     			 */
268     
269     			mca_info->which_scsi = 0xf7;
270     		}
271     	}
272     	if(!mca_info->which_scsi) {
273     
274     		/* Didn't find it at 0xf7, try somewhere else... */
275     		mca_info->which_scsi = 0xfd;
276     
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));
280     	}
281     	mca_configure_adapter_status(MCA_INTEGSCSI);
282     
283     	/* Turn off motherboard setup */
284     
285     	outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
286     
287     	/* Now loop over MCA slots: put each adapter into setup mode, and
288     	 * read its POS registers. Then put adapter setup off.
289     	 */
290     
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));
295     		}
296     		mca_info->slot[i].name[0] = 0;
297     		mca_info->slot[i].driver_loaded = 0;
298     		mca_configure_adapter_status(i);
299     	}
300     	outb_p(0, MCA_ADAPTER_SETUP_REG);
301     
302     	/* Enable interrupts and return memory start */
303     
304     	restore_flags(flags);
305     
306     	for (i = 0; i < MCA_STANDARD_RESOURCES; i++)
307     		request_resource(&ioport_resource, mca_standard_resources + i);
308     
309     #ifdef CONFIG_PROC_FS
310     	mca_do_proc_init();
311     #endif
312     }
313     
314     /*--------------------------------------------------------------------*/
315     
316     static void mca_handle_nmi_slot(int slot, int check_flag)
317     {
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);
330     	}
331     
332     	/* More info available in POS 6 and 7? */
333     
334     	if(check_flag) {
335     		unsigned char pos6, pos7;
336     
337     		pos6 = mca_read_pos(slot, 6);
338     		pos7 = mca_read_pos(slot, 7);
339     
340     		printk("NMI: POS 6 = 0x%x, POS 7 = 0x%x\n", pos6, pos7);
341     	}
342     
343     } /* mca_handle_nmi_slot */
344     
345     /*--------------------------------------------------------------------*/
346     
347     void mca_handle_nmi(void)
348     {
349     
350     	int i;
351     	unsigned char pos5;
352     
353     	/* First try - scan the various adapters and see if a specific
354     	 * adapter was responsible for the error.
355     	 */
356     
357     	for(i = 0; i < MCA_NUMADAPTERS; i++) {
358     
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.
362     	 */
363     
364     	pos5 = mca_read_pos(i, 5);
365     
366     	if(!(pos5 & 0x80)) {
367     			mca_handle_nmi_slot(i, !(pos5 & 0x40));
368     			return;
369     		}
370     	}
371     
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.
375     	 */
376     
377     	printk("NMI generated from unknown source!\n");
378     } /* mca_handle_nmi */
379     
380     /*--------------------------------------------------------------------*/
381     
382     /**
383      *	mca_find_adapter - scan for adapters
384      *	@id:	MCA identification to search for
385      *	@start:	starting slot
386      *
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.
391      *
392      *	Disabled adapters are not reported.
393      */
394     
395     int mca_find_adapter(int id, int start)
396     {
397     	if(mca_info == NULL || id == 0xffff) {
398     		return MCA_NOTFOUND;
399     	}
400     
401     	for(; start >= 0 && start < MCA_NUMADAPTERS; start++) {
402     
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.
409     		 */
410     
411     		if(mca_info->slot[start].status == MCA_ADAPTER_DISABLED) {
412     			continue;
413     		}
414     
415     		if(id == mca_info->slot[start].id) {
416     			return start;
417     		}
418     	}
419     
420     	return MCA_NOTFOUND;
421     } /* mca_find_adapter() */
422     
423     EXPORT_SYMBOL(mca_find_adapter);
424     
425     /*--------------------------------------------------------------------*/
426     
427     /**
428      *	mca_find_unused_adapter - scan for unused adapters
429      *	@id:	MCA identification to search for
430      *	@start:	starting slot
431      *
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.
436      *
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.
440      */
441     
442     int mca_find_unused_adapter(int id, int start)
443     {
444     	if(mca_info == NULL || id == 0xffff) {
445     		return MCA_NOTFOUND;
446     	}
447     
448     	for(; start >= 0 && start < MCA_NUMADAPTERS; start++) {
449     
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.
456     		 */
457     
458     		if(mca_info->slot[start].status == MCA_ADAPTER_DISABLED ||
459     		   mca_info->slot[start].driver_loaded) {
460     			continue;
461     		}
462     
463     		if(id == mca_info->slot[start].id) {
464     			return start;
465     		}
466     	}
467     
468     	return MCA_NOTFOUND;
469     } /* mca_find_unused_adapter() */
470     
471     EXPORT_SYMBOL(mca_find_unused_adapter);
472     
473     /*--------------------------------------------------------------------*/
474     
475     /**
476      *	mca_read_stored_pos - read POS register from boot data
477      *	@slot: slot number to read from
478      *	@reg:  register to read from
479      *
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.
483      */
484     
485     unsigned char mca_read_stored_pos(int slot, int reg)
486     {
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() */
491     
492     EXPORT_SYMBOL(mca_read_stored_pos);
493     
494     /*--------------------------------------------------------------------*/
495     
496     /**
497      *	mca_read_pos - read POS register from card
498      *	@slot: slot number to read from
499      *	@reg:  register to read from
500      *
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.
505      */
506     
507     unsigned char mca_read_pos(int slot, int reg)
508     {
509     	unsigned int byte = 0;
510     	unsigned long flags;
511     
512     	if(slot < 0 || slot >= MCA_NUMADAPTERS || mca_info == NULL) return 0;
513     	if(reg < 0 || reg >= 8) return 0;
514     
515     	save_flags(flags);
516     	cli();
517     
518     	/* Make sure motherboard setup is off */
519     
520     	outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
521     
522     	/* Read in the appropriate register */
523     
524     	if(slot == MCA_INTEGSCSI && mca_info->which_scsi) {
525     
526     		/* Disable adapter setup, enable motherboard setup */
527     
528     		outb_p(0, MCA_ADAPTER_SETUP_REG);
529     		outb_p(mca_info->which_scsi, MCA_MOTHERBOARD_SETUP_REG);
530     
531     		byte = inb_p(MCA_POS_REG(reg));
532     		outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
533     	} else if(slot == MCA_INTEGVIDEO) {
534     
535     		/* Disable adapter setup, enable motherboard setup */
536     
537     		outb_p(0, MCA_ADAPTER_SETUP_REG);
538     		outb_p(0xdf, MCA_MOTHERBOARD_SETUP_REG);
539     
540     		byte = inb_p(MCA_POS_REG(reg));
541     		outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
542     	} else if(slot == MCA_MOTHERBOARD) {
543     
544     		/* Disable adapter setup, enable motherboard setup */
545     		outb_p(0, MCA_ADAPTER_SETUP_REG);
546     		outb_p(0x7f, MCA_MOTHERBOARD_SETUP_REG);
547     
548     		byte = inb_p(MCA_POS_REG(reg));
549     		outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
550     	} else if(slot < MCA_MAX_SLOT_NR) {
551     
552     		/* Make sure motherboard setup is off */
553     
554     		outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
555     
556     		/* Read the appropriate register */
557     
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);
561     	}
562     
563     	/* Make sure the stored values are consistent, while we're here */
564     
565     	mca_info->slot[slot].pos[reg] = byte;
566     
567     	restore_flags(flags);
568     
569     	return byte;
570     } /* mca_read_pos() */
571     
572     EXPORT_SYMBOL(mca_read_pos);
573     
574     /*--------------------------------------------------------------------*/
575     
576     /**
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
581      *
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.
586      *
587      *	This function may not be used from interrupt context.
588      *
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.
594      *
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.
598      */
599     
600     void mca_write_pos(int slot, int reg, unsigned char byte)
601     {
602     	unsigned long flags;
603     
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;
610     
611     	save_flags(flags);
612     	cli();
613     
614     	/* Make sure motherboard setup is off */
615     
616     	outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
617     
618     	/* Read in the appropriate register */
619     
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);
623     
624     	restore_flags(flags);
625     
626     	/* Update the global register list, while we have the byte */
627     
628     	mca_info->slot[slot].pos[reg] = byte;
629     } /* mca_write_pos() */
630     
631     EXPORT_SYMBOL(mca_write_pos);
632     
633     /*--------------------------------------------------------------------*/
634     
635     /**
636      *	mca_set_adapter_name - Set the description of the card
637      *	@slot: slot to name
638      *	@name: text string for the namen
639      *
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.
643      */
644     
645     void mca_set_adapter_name(int slot, char* name)
646     {
647     	if(mca_info == NULL) return;
648     
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;
657     		}
658     	}
659     }
660     
661     EXPORT_SYMBOL(mca_set_adapter_name);
662     
663     /**
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
668      *
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.
675      *
676      *	This should be called with a %NULL @procfn when a module
677      *	unregisters, thus preventing kernel crashes and other such
678      *	nastiness.
679      */
680     
681     void mca_set_adapter_procfn(int slot, MCA_ProcFn procfn, void* dev)
682     {
683     	if(mca_info == NULL) return;
684     
685     	if(slot >= 0 && slot < MCA_NUMADAPTERS) {
686     		mca_info->slot[slot].procfn = procfn;
687     		mca_info->slot[slot].dev = dev;
688     	}
689     }
690     
691     EXPORT_SYMBOL(mca_set_adapter_procfn);
692     
693     /**
694      *	mca_is_adapter_used - check if claimed by driver
695      *	@slot:	slot to check
696      *
697      *	Returns 1 if the slot has been claimed by a driver
698      */
699     
700     int mca_is_adapter_used(int slot)
701     {
702     	return mca_info->slot[slot].driver_loaded;
703     }
704     
705     EXPORT_SYMBOL(mca_is_adapter_used);
706     
707     /**
708      *	mca_mark_as_used - claim an MCA device
709      *	@slot:	slot to claim
710      *	FIXME:  should we make this threadsafe
711      *
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.
716      */
717     
718     int mca_mark_as_used(int slot)
719     {
720     	if(mca_info->slot[slot].driver_loaded) return 1;
721     	mca_info->slot[slot].driver_loaded = 1;
722     	return 0;
723     }
724     
725     EXPORT_SYMBOL(mca_mark_as_used);
726     
727     /**
728      *	mca_mark_as_unused - release an MCA device
729      *	@slot:	slot to claim
730      *
731      *	Release the slot for other drives to use.
732      */
733     
734     void mca_mark_as_unused(int slot)
735     {
736     	mca_info->slot[slot].driver_loaded = 0;
737     }
738     
739     EXPORT_SYMBOL(mca_mark_as_unused);
740     
741     /**
742      *	mca_get_adapter_name - get the adapter description
743      *	@slot:	slot to query
744      *
745      *	Return the adapter description if set. If it has not been
746      *	set or the slot is out range then return NULL.
747      */
748     
749     char *mca_get_adapter_name(int slot)
750     {
751     	if(mca_info == NULL) return 0;
752     
753     	if(slot >= 0 && slot < MCA_NUMADAPTERS) {
754     		return mca_info->slot[slot].name;
755     	}
756     
757     	return 0;
758     }
759     
760     EXPORT_SYMBOL(mca_get_adapter_name);
761     
762     /**
763      *	mca_isadapter - check if the slot holds an adapter
764      *	@slot:	slot to query
765      *
766      *	Returns zero if the slot does not hold an adapter, non zero if
767      *	it does.
768      */
769     
770     int mca_isadapter(int slot)
771     {
772     	if(mca_info == NULL) return 0;
773     
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));
777     	}
778     
779     	return 0;
780     }
781     
782     EXPORT_SYMBOL(mca_isadapter);
783     
784     
785     /**
786      *	mca_isadapter - check if the slot holds an adapter
787      *	@slot:	slot to query
788      *
789      *	Returns a non zero value if the slot holds an enabled adapter
790      *	and zero for any other case.
791      */
792     
793     int mca_isenabled(int slot)
794     {
795     	if(mca_info == NULL) return 0;
796     
797     	if(slot >= 0 && slot < MCA_NUMADAPTERS) {
798     		return (mca_info->slot[slot].status == MCA_ADAPTER_NORMAL);
799     	}
800     
801     	return 0;
802     }
803     
804     EXPORT_SYMBOL(mca_isenabled);
805     
806     /*--------------------------------------------------------------------*/
807     
808     #ifdef CONFIG_PROC_FS
809     
810     int get_mca_info(char *page, char **start, off_t off,
811     				 int count, int *eof, void *data)
812     {
813     	int i, j, len = 0;
814     
815     	if(MCA_bus && mca_info != NULL) {
816     		/* Format POS registers of eight MCA slots */
817     
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);
823     		}
824     
825     		/* Format POS registers of integrated video subsystem */
826     
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);
831     
832     		/* Format POS registers of integrated SCSI subsystem */
833     
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);
838     
839     		/* Format POS registers of motherboard */
840     
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!
848     		 */
849     	}
850     
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;
857     }
858     
859     /*--------------------------------------------------------------------*/
860     
861     static int mca_default_procfn(char* buf, struct MCA_adapter *p)
862     {
863     	int len = 0, i;
864     	int slot = p - mca_info->slot;
865     
866     	/* Print out the basic information */
867     
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");
876     	}
877     	if(p->name[0]) {
878     
879     		/* Drivers might register a name without /proc handler... */
880     
881     		len += sprintf(buf+len, "Adapter Name: %s\n",
882     			p->name);
883     	} else {
884     		len += sprintf(buf+len, "Adapter Name: Unknown\n");
885     	}
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]);
892     	}
893     	len += sprintf(buf+len, "\nDriver Installed: %s",
894     		mca_is_adapter_used(slot) ? "Yes" : "No");
895     	buf[len++] = '\n';
896     	buf[len] = 0;
897     
898     	return len;
899     } /* mca_default_procfn() */
900     
901     static int get_mca_machine_info(char* page, char **start, off_t off,
902     				 int count, int *eof, void *data)
903     {
904     	int len = 0;
905     
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);
909     
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;
916     }
917     
918     static int mca_read_proc(char *page, char **start, off_t off,
919     				 int count, int *eof, void *data)
920     {
921     	struct MCA_adapter *p = (struct MCA_adapter *)data;
922     	int len = 0;
923     
924     	/* Get the standard info */
925     
926     	len = mca_default_procfn(page, p);
927     
928     	/* Do any device-specific processing, if there is any */
929     
930     	if(p->procfn) {
931     		len += p->procfn(page+len, p-mca_info->slot, p->dev);
932     	}
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() */
940     
941     /*--------------------------------------------------------------------*/
942     
943     void __init mca_do_proc_init(void)
944     {
945     	int i;
946     	struct proc_dir_entry *proc_mca;
947     	struct proc_dir_entry* node = NULL;
948     	struct MCA_adapter *p;
949     
950     	if(mca_info == NULL) return;	/* Should never happen */
951     
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);
955     
956     	/* Initialize /proc/mca entries for existing adapters */
957     
958     	for(i = 0; i < MCA_NUMADAPTERS; i++) {
959     		p = &mca_info->slot[i];
960     		p->procfn = 0;
961     
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");
966     
967     		if(!mca_isadapter(i)) continue;
968     
969     		node = create_proc_read_entry(p->procname, 0, proc_mca,
970     						mca_read_proc, (void *)p);
971     
972     		if(node == NULL) {
973     			printk("Failed to allocate memory for MCA proc-entries!");
974     			return;
975     		}
976     	}
977     
978     } /* mca_do_proc_init() */
979     
980     #endif
981