1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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
57
58
59
60
61
62
63typedef 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
70struct MCA_adapter {
71 MCA_AdapterStatus status;
72 int id;
73 unsigned char pos[8];
74 int driver_loaded;
75
76 char name[48];
77 char procname[8];
78 MCA_ProcFn procfn;
79 void* dev;
80};
81
82struct MCA_info {
83
84
85
86
87 struct MCA_adapter slot[MCA_NUMADAPTERS];
88
89
90
91
92
93 unsigned char which_scsi;
94};
95
96
97
98
99
100
101
102
103static struct MCA_info* mca_info = NULL;
104
105
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
112
113
114
115#ifdef CONFIG_PROC_FS
116static void mca_do_proc_init(void);
117#endif
118
119
120
121
122
123static 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
132
133
134
135
136
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
145
146
147
148
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
169
170 mca_info->slot[slot].status = MCA_ADAPTER_DISABLED;
171 }
172}
173
174
175
176struct 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
188void __init mca_init(void)
189{
190 unsigned int i, j;
191 unsigned long flags;
192
193
194
195
196
197
198
199
200
201
202 if(!MCA_bus)
203 return;
204 printk("Micro Channel bus detected.\n");
205
206
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
220
221 outb_p(0, MCA_ADAPTER_SETUP_REG);
222
223
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
233
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
244
245
246
247
248
249
250
251
252
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
261
262
263
264
265
266
267
268
269 mca_info->which_scsi = 0xf7;
270 }
271 }
272 if(!mca_info->which_scsi) {
273
274
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
284
285 outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
286
287
288
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
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
316static 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
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}
344
345
346
347void mca_handle_nmi(void)
348{
349
350 int i;
351 unsigned char pos5;
352
353
354
355
356
357 for(i = 0; i < MCA_NUMADAPTERS; i++) {
358
359
360
361
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
373
374
375
376
377 printk("NMI generated from unknown source!\n");
378}
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395int 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
404
405
406
407
408
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}
422
423EXPORT_SYMBOL(mca_find_adapter);
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442int 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
451
452
453
454
455
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}
470
471EXPORT_SYMBOL(mca_find_unused_adapter);
472
473
474
475
476
477
478
479
480
481
482
483
484
485unsigned 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}
491
492EXPORT_SYMBOL(mca_read_stored_pos);
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507unsigned 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
519
520 outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
521
522
523
524 if(slot == MCA_INTEGSCSI && mca_info->which_scsi) {
525
526
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
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
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
553
554 outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
555
556
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
564
565 mca_info->slot[slot].pos[reg] = byte;
566
567 restore_flags(flags);
568
569 return byte;
570}
571
572EXPORT_SYMBOL(mca_read_pos);
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600void 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
615
616 outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
617
618
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
627
628 mca_info->slot[slot].pos[reg] = byte;
629}
630
631EXPORT_SYMBOL(mca_write_pos);
632
633
634
635
636
637
638
639
640
641
642
643
644
645void 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
661EXPORT_SYMBOL(mca_set_adapter_name);
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681void 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
691EXPORT_SYMBOL(mca_set_adapter_procfn);
692
693
694
695
696
697
698
699
700int mca_is_adapter_used(int slot)
701{
702 return mca_info->slot[slot].driver_loaded;
703}
704
705EXPORT_SYMBOL(mca_is_adapter_used);
706
707
708
709
710
711
712
713
714
715
716
717
718int 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
725EXPORT_SYMBOL(mca_mark_as_used);
726
727
728
729
730
731
732
733
734void mca_mark_as_unused(int slot)
735{
736 mca_info->slot[slot].driver_loaded = 0;
737}
738
739EXPORT_SYMBOL(mca_mark_as_unused);
740
741
742
743
744
745
746
747
748
749char *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
760EXPORT_SYMBOL(mca_get_adapter_name);
761
762
763
764
765
766
767
768
769
770int 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
782EXPORT_SYMBOL(mca_isadapter);
783
784
785
786
787
788
789
790
791
792
793int 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
804EXPORT_SYMBOL(mca_isenabled);
805
806
807
808#ifdef CONFIG_PROC_FS
809
810int 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
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
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
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
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
847
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
861static 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
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
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}
900
901static 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
918static 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
925
926 len = mca_default_procfn(page, p);
927
928
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}
940
941
942
943void __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;
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
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}
979
980#endif
981