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
mca_configure_adapter_status(int slot)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
mca_init(void)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
mca_handle_nmi_slot(int slot,int check_flag)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
mca_handle_nmi(void)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
mca_find_adapter(int id,int start)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
mca_find_unused_adapter(int id,int start)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
mca_read_stored_pos(int slot,int reg)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
mca_read_pos(int slot,int reg)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
mca_write_pos(int slot,int reg,unsigned char byte)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
mca_set_adapter_name(int slot,char * name)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
mca_set_adapter_procfn(int slot,MCA_ProcFn procfn,void * dev)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
mca_is_adapter_used(int slot)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
mca_mark_as_used(int slot)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
mca_mark_as_unused(int slot)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
mca_get_adapter_name(int slot)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
mca_isadapter(int slot)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
mca_isenabled(int slot)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
get_mca_info(char * page,char ** start,off_t off,int count,int * eof,void * data)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
mca_default_procfn(char * buf,struct MCA_adapter * p)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
get_mca_machine_info(char * page,char ** start,off_t off,int count,int * eof,void * data)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
mca_read_proc(char * page,char ** start,off_t off,int count,int * eof,void * data)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
mca_do_proc_init(void)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