|
|
1.1 root 1: /*
2:
3: Copyright 1990,1991,1992 Eric R. Smith. All rights reserved.
4:
5: */
6:
7:
8:
9: /*
10:
11: * BIOS replacement routines
12:
13: */
14:
15:
16:
17: #include "mint.h"
18:
19:
20:
21: #define UNDEF 0 /* should match definition in tty.c */
22:
23:
24:
25: /* some key definitions */
26:
27: #define CTRLALT 0xc
28:
29: #define DEL 0x53 /* scan code of delete key */
30:
31: #define UNDO 0x61 /* scan code of undo key */
32:
33:
34:
35: /* BIOS device definitions */
36:
37: #define CONSDEV 2
38:
39: #define AUXDEV 1
40:
41:
42:
43: /* BIOS devices 0..MAX_BHANDLE-1 can be redirected to GEMDOS files */
44:
45: #define MAX_BHANDLE 4
46:
47:
48:
49: /* BIOS redirection maps */
50:
51: short binput[MAX_BHANDLE] = { -3, -2, -1, -4 };
52:
53: short boutput[MAX_BHANDLE] = { -3, -2, -1, -5 };
54:
55:
56:
57: /* tty structures for the BIOS devices -- see biosfs.c */
58:
59: extern struct tty con_tty, aux_tty, midi_tty;
60:
61:
62:
63: extern int tosvers; /* from main.c */
64:
65: char *kbshft; /* set in main.c */
66:
67:
68:
69: /* some BIOS vectors; note that the routines at these vectors may do nasty
70:
71: * things to registers!
72:
73: */
74:
75:
76:
77: #define RWABS 0x476L
78:
79: #define MEDIACH 0x47eL
80:
81: #define GETBPB 0x472L
82:
83:
84:
85: /* these aren't used (yet) */
86:
87: #define xconin (((long (**) P_((short)))0x53e))
88:
89: #define xconout (((long (**) P_((short, short)))0x57e))
90:
91:
92:
93: /* structure used to hold i/o buffers */
94:
95: typedef struct io_rec {
96:
97: char *bufaddr;
98:
99: short buflen, head, tail, low_water, hi_water;
100:
101: } IOREC_T;
102:
103:
104:
105: /* variables for monitoring the keyboard */
106:
107: IOREC_T *keyrec; /* keyboard i/o record pointer */
108:
109: short kintr = 0; /* keyboard interrupt pending (see intr.s) */
110:
111:
112:
113: /* Getmpb is not allowed under MiNT */
114:
115:
116:
117: long
118:
119: getmpb(ptr)
120:
121: void *ptr;
122:
123: {
124:
125: DEBUG("failed call to Getmpb");
126:
127: return -1;
128:
129: }
130:
131:
132:
133:
134:
135: /*
136:
137: * Note that BIOS handles 0 - MAX_BHANDLE now reference file handles;
138:
139: * to get the physical devices, go through u:\dev\
140:
141: *
142:
143: * A note on translation: all of the bco[n]XXX functions have a "u"
144:
145: * variant that is actually what the user calls. For example,
146:
147: * ubconstat is the function that gets control after the user does
148:
149: * a Bconstat. It figures out what device or file handle is
150:
151: * appropriate. Typically, it will be a biosfs file handle; a
152:
153: * request is sent to biosfs, and biosfs in turn figures out
154:
155: * the "real" device and calls bconstat.
156:
157: */
158:
159:
160:
161: long
162:
163: ubconstat(dev)
164:
165: int dev;
166:
167: {
168:
169: if (dev < MAX_BHANDLE)
170:
171: return file_instat(binput[dev]) ? -1 : 0;
172:
173: else
174:
175: return bconstat(dev);
176:
177: }
178:
179:
180:
181: long
182:
183: bconstat(dev)
184:
185: int dev;
186:
187: {
188:
189: if (dev == CONSDEV) {
190:
191: if (checkkeys()) return 0;
192:
193: return (keyrec->head != keyrec->tail) ? -1 : 0;
194:
195: }
196:
197: if (dev == AUXDEV && has_bconmap)
198:
199: dev = curproc->bconmap;
200:
201:
202:
203: return Bconstat(dev);
204:
205: }
206:
207:
208:
209: /* bconin: input a character */
210:
211:
212:
213: long
214:
215: ubconin(dev)
216:
217: int dev;
218:
219: {
220:
221: if (dev < MAX_BHANDLE)
222:
223: return file_getchar(binput[dev], RAW);
224:
225: else
226:
227: return bconin(dev);
228:
229: }
230:
231:
232:
233: long
234:
235: bconin(dev)
236:
237: int dev;
238:
239: {
240:
241: IOREC_T *k;
242:
243: long r;
244:
245: short h;
246:
247:
248:
249: if (dev == CONSDEV) {
250:
251: k = keyrec;
252:
253: again:
254:
255: while (k->tail == k->head) {
256:
257: yield();
258:
259: }
260:
261:
262:
263: if (checkkeys()) goto again;
264:
265:
266:
267: h = k->head + 4;
268:
269: if (h >= k->buflen)
270:
271: h = 0;
272:
273: r = *((long *)(k->bufaddr + h));
274:
275: k->head = h;
276:
277: return r;
278:
279: }
280:
281: else {
282:
283: if (dev == AUXDEV && has_bconmap)
284:
285: dev = curproc->bconmap;
286:
287:
288:
289: if (dev > 0)
290:
291: while (!Bconstat(dev)) {
292:
293: yield();
294:
295: }
296:
297: }
298:
299:
300:
301: r = Bconin(dev);
302:
303:
304:
305: return r;
306:
307: }
308:
309:
310:
311: /* bconout: output a character.
312:
313: * returns 0 for failure, nonzero for success
314:
315: */
316:
317:
318:
319: long
320:
321: ubconout(dev, c)
322:
323: int dev, c;
324:
325: {
326:
327: FILEPTR *f;
328:
329:
330:
331: if (dev < MAX_BHANDLE) {
332:
333: f = curproc->handle[boutput[dev]];
334:
335: if (!f) return 0;
336:
337: if (is_terminal(f)) {
338:
339: return tty_putchar(f, ((long)c)&0x00ff, RAW);
340:
341: }
342:
343: /* note: we're assuming sizeof(int) == 2 here! */
344:
345: return (*f->dev->write)(f, ((char *)&c)+1, 1L);
346:
347: }
348:
349: else if (dev == 5) {
350:
351: c &= 0x00ff;
352:
353: f = curproc->handle[-1];
354:
355: if (!f) return 0;
356:
357: if (is_terminal(f)) {
358:
359: if (c < ' ') {
360:
361: /* MW hack for quoted characters */
362:
363: tty_putchar(f, (long)'\033', RAW);
364:
365: tty_putchar(f, (long)'Q', RAW);
366:
367: }
368:
369: return tty_putchar(f, ((long)c)&0x00ff, RAW);
370:
371: }
372:
373: /* note: we're assuming sizeof(int) == 2 here! */
374:
375: return (*f->dev->write)(f, ((char *)&c)+1, 1L);
376:
377: } else
378:
379: return bconout(dev, c);
380:
381: }
382:
383:
384:
385: long
386:
387: bconout(dev, c)
388:
389: int dev,c;
390:
391: {
392:
393: int statdev;
394:
395: long endtime;
396:
397: extern long searchtime; /* in dosdir.c; updated once per second */
398:
399:
400:
401: if (dev == AUXDEV && has_bconmap) {
402:
403: dev = curproc->bconmap;
404:
405: }
406:
407:
408:
409: /* compensate for a known BIOS bug; MIDI and IKBD are switched */
410:
411: if (dev == 3) { /* MIDI */
412:
413: statdev = 4;
414:
415: } else if (dev == 4) {
416:
417: statdev = 3;
418:
419: } else
420:
421: statdev = dev;
422:
423:
424:
425: /* provide a 10 second time out */
426:
427: endtime = searchtime + 10;
428:
429: while (!Bcostat(statdev) && searchtime < endtime) {
430:
431: yield();
432:
433: }
434:
435: if ( searchtime >= endtime && !Bcostat(statdev)) return 0;
436:
437:
438:
439: /* special case: many text accelerators return a bad value from
440:
441: * Bconout, so we ignore the returned value for the console
442:
443: */
444:
445: if (dev != CONSDEV) {
446:
447: /* NOTE: if your compiler complains about the next line, then Bconout is
448:
449: * improperly declared in your osbind.h header file. it should be returning
450:
451: * a long value; some libraries incorrectly have Bconout returning void
452:
453: * (or cast the returned value to void)
454:
455: */
456:
457: return Bconout(dev,c);
458:
459: } else {
460:
461: (void)Bconout(dev, c);
462:
463: return 1;
464:
465: }
466:
467: }
468:
469:
470:
471: /* rwabs: various disk stuff */
472:
473:
474:
475: long
476:
477: rwabs(rwflag, buffer, number, recno, dev, lrecno)
478:
479: int rwflag, number, recno, dev;
480:
481: void *buffer;
482:
483: long lrecno;
484:
485: {
486:
487: long r;
488:
489:
490:
491: /* Note that some (most?) Rwabs device drivers don't bother saving
492:
493: * registers, whereas our compiler expects politeness. So we go
494:
495: * via callout(), which will save registers for us.
496:
497: */
498:
499: r = callout(RWABS, rwflag, buffer, number, recno, dev, lrecno);
500:
501: return r;
502:
503: }
504:
505:
506:
507: /* setexc: set exception vector */
508:
509:
510:
511: long
512:
513: setexc(number, vector)
514:
515: int number;
516:
517: long vector;
518:
519: {
520:
521: long *place;
522:
523: long old;
524:
525: extern long save_dos, save_bios, save_xbios; /* in main.c */
526:
527:
528:
529: TRACE("Setexc %d, %lx", number, vector);
530:
531: place = (long *)(((long)number) << 2);
532:
533: if (number == 0x21) /* trap_1 */
534:
535: old = save_dos;
536:
537: else if (number == 0x2d) /* trap_13 */
538:
539: old = save_bios;
540:
541: else if (number == 0x2e) /* trap_14 */
542:
543: old = save_xbios;
544:
545: else if (number == 0x101)
546:
547: old = (long)curproc->criticerr; /* critical error vector */
548:
549: else if (number == 0x102)
550:
551: old = curproc->ctxt[SYSCALL].term_vec; /* GEMDOS term vector */
552:
553: else
554:
555: old = *place;
556:
557:
558:
559: if (vector > 0) {
560:
561: if (number == 0x21)
562:
563: save_dos = vector;
564:
565: else if (number == 0x2d)
566:
567: save_bios = vector;
568:
569: else if (number == 0x2e)
570:
571: save_xbios = vector;
572:
573: else if (number == 0x102)
574:
575: curproc->ctxt[SYSCALL].term_vec = vector;
576:
577: else if (number == 0x101) {
578:
579: long mintcerr;
580:
581:
582:
583: /*
584:
585: * problem: lots of TSR's look for the Setexc(0x101,...)
586:
587: * that the AES does at startup time; so we have
588:
589: * to pass it along.
590:
591: */
592:
593: mintcerr = (long) Setexc(0x101, (void *)vector);
594:
595: curproc->criticerr = (long (*) P_((long))) *place;
596:
597: *place = mintcerr;
598:
599: }
600:
601: else {
602:
603: /* We would do just *place = vector except that
604:
605: * someone else might be intercepting Setexc looking
606:
607: * for something in particular...
608:
609: */
610:
611: old = (long) Setexc(number, (void *)vector);
612:
613: }
614:
615: }
616:
617: return old;
618:
619: }
620:
621:
622:
623: /* tickcal: return milliseconds per system clock tick */
624:
625:
626:
627: long
628:
629: tickcal()
630:
631: {
632:
633: return (long) (*( (unsigned *) 0x0442L ));
634:
635: }
636:
637:
638:
639: /* getbpb: get BIOS parameter block */
640:
641:
642:
643: long
644:
645: getbpb(dev)
646:
647: int dev;
648:
649: {
650:
651: long r;
652:
653:
654:
655: /* we can't trust the Getbpb routine to accurately save all registers,
656:
657: * so we do it ourselves
658:
659: */
660:
661: r = callout(GETBPB, dev);
662:
663: /*
664:
665: * There is a bug in the TOS disk handling routines (well several actually).
666:
667: * If the directory size of Getbpb() is returned as zero then the drive 'dies'
668:
669: * and wont read any new disks even with the 'ESC' enforced disk change . This
670:
671: * is present even in TOS 1.6 (not sure about 1.62 though). This small routine
672:
673: * changes the dir size to '1' if it is zero . It may make some non-TOS disks
674:
675: * look a bit weird but that's better than killing the drive .
676:
677: */
678:
679: if (r) {
680:
681: if ( ((short *)r)[3] == 0) /* 0 directory size? */
682:
683: ((short *)r)[3] = 1;
684:
685: }
686:
687: return r;
688:
689: }
690:
691:
692:
693: /* bcostat: return output device status */
694:
695:
696:
697: long
698:
699: ubcostat(dev)
700:
701: int dev;
702:
703: {
704:
705: /* the BIOS switches MIDI (3) and IKBD (4) (a bug, but it can't be corrected) */
706:
707: if (dev == 4) { /* really the MIDI port */
708:
709: return file_outstat(boutput[3]) ? -1 : 0;
710:
711: }
712:
713: if (dev == 3)
714:
715: return Bcostat(dev);
716:
717:
718:
719: if (dev < MAX_BHANDLE)
720:
721: return file_outstat(boutput[dev]) ? -1 : 0;
722:
723: else
724:
725: return bcostat(dev);
726:
727: }
728:
729:
730:
731: long
732:
733: bcostat(dev)
734:
735: int dev;
736:
737: {
738:
739:
740:
741: if (dev == CONSDEV) {
742:
743: return -1;
744:
745: }
746:
747: else if (dev == AUXDEV && has_bconmap) {
748:
749: dev = curproc->bconmap;
750:
751: }
752:
753: /* compensate here for the BIOS bug, so that the MIDI and IKBD files work
754:
755: * correctly
756:
757: */
758:
759: else if (dev == 3) dev = 4;
760:
761: else if (dev == 4) dev = 3;
762:
763:
764:
765: return Bcostat(dev);
766:
767: }
768:
769:
770:
771: /* mediach: check for media change */
772:
773:
774:
775: long
776:
777: mediach(dev)
778:
779: int dev;
780:
781: {
782:
783: long r;
784:
785:
786:
787: r = callout(MEDIACH, dev);
788:
789: return r;
790:
791: }
792:
793:
794:
795: /* drvmap: return drives connected to system */
796:
797:
798:
799: long
800:
801: drvmap()
802:
803: {
804:
805: return *( (long *)0x4c2L );
806:
807: }
808:
809:
810:
811: /* kbshift: return (and possibly change) keyboard shift key status */
812:
813:
814:
815: long
816:
817: kbshift(mode)
818:
819: int mode;
820:
821: {
822:
823: int oldshft;
824:
825:
826:
827: oldshft = *((unsigned char *)kbshft);
828:
829: if (mode >= 0)
830:
831: *kbshft = mode;
832:
833: return oldshft;
834:
835: }
836:
837:
838:
839:
840:
841: /* special Bconout buffering code:
842:
843: * Because system call overhead is so high, programs that do output
844:
845: * with Bconout suffer in performance. To compensate for this,
846:
847: * Bconout is special-cased in syscall.s, and if possible characters
848:
849: * are placed in the 256 byte bconbuf buffer. This buffer is flushed
850:
851: * when any system call other than Bconout happens, or when a context
852:
853: * switch occurs.
854:
855: */
856:
857:
858:
859: short bconbsiz; /* number of characters in buffer */
860:
861: unsigned char bconbuf[256]; /* buffer contents */
862:
863: short bconbdev; /* BIOS device for which the buffer is valid */
864:
865: /* (-1 means no buffering is active) */
866:
867:
868:
869: /*
870:
871: * flush pending BIOS output. Return 0 if some bytes were not successfully
872:
873: * written, non-zero otherwise (just like bconout)
874:
875: */
876:
877:
878:
879: long
880:
881: bflush() /* flush bios output */
882:
883: {
884:
885: long ret, bsiz;
886:
887: unsigned char *s;
888:
889: FILEPTR *f;
890:
891: short dev;
892:
893: short statdev;
894:
895:
896:
897: if ((dev = bconbdev) < 0) return 0;
898:
899:
900:
901: /*
902:
903: * Here we lock the BIOS buffering mechanism by setting bconbdev to -1
904:
905: * This is necessary because if two or more programs try to do
906:
907: * buffered BIOS output at the same time, they can get seriously
908:
909: * mixed up. We unlock by setting bconbdev to 0.
910:
911: *
912:
913: * NOTE: some code (e.g. in sleep()) checks for bconbsiz != 0 in
914:
915: * order to see if we need to do a bflush; if one is already in
916:
917: * progress, it's pointless to do this, so we save a bit of
918:
919: * time by setting bconbsiz to 0 here.
920:
921: */
922:
923: bconbdev = -1;
924:
925: bsiz = bconbsiz;
926:
927: bconbsiz = 0;
928:
929:
930:
931: /* BIOS handles 0..MAX_BHANDLE-1 are aliases for special GEMDOS files */
932:
933: if (dev < MAX_BHANDLE || dev == 5) {
934:
935: if (dev == 5)
936:
937: f = curproc->handle[-1];
938:
939: else
940:
941: f = curproc->handle[boutput[dev]];
942:
943:
944:
945: if (!f) {
946:
947: bconbdev = 0;
948:
949: return 0;
950:
951: }
952:
953: if (is_terminal(f)) {
954:
955: s = bconbuf;
956:
957: if (dev == 5) {
958:
959: while (bsiz-- > 0) {
960:
961: if (*s < ' ') {
962:
963: /* use ESC-Q to quote control character */
964:
965: (void)tty_putchar(f, (long)'\033',
966:
967: RAW);
968:
969: (void)tty_putchar(f, (long)'Q',
970:
971: RAW);
972:
973: }
974:
975: (void) tty_putchar(f, (long)*s++, RAW);
976:
977: }
978:
979: } else {
980:
981: while (bsiz-- > 0) {
982:
983: (void) tty_putchar(f, (long)*s++, RAW);
984:
985: }
986:
987: }
988:
989: ret = -1;
990:
991: } else {
992:
993: ret = (*f->dev->write)(f, (char *)bconbuf, bsiz);
994:
995: }
996:
997: bconbdev = 0;
998:
999: return ret;
1000:
1001: }
1002:
1003:
1004:
1005: /* Otherwise, we have a real BIOS device */
1006:
1007:
1008:
1009: if (dev == AUXDEV && has_bconmap) {
1010:
1011: dev = curproc->bconmap;
1012:
1013: statdev = dev;
1014:
1015: }
1016:
1017: /* compensate for a known BIOS bug; MIDI and IKBD are switched */
1018:
1019: else if (dev == 3) { /* MIDI */
1020:
1021: statdev = 4;
1022:
1023: } else if (dev == 4) {
1024:
1025: statdev = 3;
1026:
1027: } else
1028:
1029: statdev = dev;
1030:
1031:
1032:
1033: s = bconbuf;
1034:
1035: while (bsiz-- > 0) {
1036:
1037: while (!Bcostat(statdev)) yield();
1038:
1039: (void)Bconout(dev,*s);
1040:
1041: s++;
1042:
1043: }
1044:
1045: bconbdev = 0;
1046:
1047: return 1L;
1048:
1049: }
1050:
1051:
1052:
1053: /* initialize bios table */
1054:
1055:
1056:
1057: #define BIOS_MAX 0x20
1058:
1059:
1060:
1061: Func bios_tab[BIOS_MAX] = {
1062:
1063: getmpb,
1064:
1065: ubconstat,
1066:
1067: ubconin,
1068:
1069: ubconout,
1070:
1071: rwabs,
1072:
1073: setexc,
1074:
1075: tickcal,
1076:
1077: getbpb,
1078:
1079: ubcostat,
1080:
1081: mediach,
1082:
1083: drvmap,
1084:
1085: kbshift,
1086:
1087: 0, 0, 0, 0,
1088:
1089: 0, 0, 0, 0, 0, 0, 0, 0,
1090:
1091: 0, 0, 0, 0, 0, 0, 0, 0
1092:
1093: };
1094:
1095:
1096:
1097: short bios_max = BIOS_MAX;
1098:
1099:
1100:
1101: /*
1102:
1103: * BIOS initialization routine: gets keyboard buffer pointers, for the
1104:
1105: * interrupt routine below
1106:
1107: */
1108:
1109:
1110:
1111: void
1112:
1113: init_bios()
1114:
1115: {
1116:
1117: keyrec = (IOREC_T *)Iorec(1);
1118:
1119: }
1120:
1121:
1122:
1123: /*
1124:
1125: * routine for checking keyboard (called by sleep() on any context
1126:
1127: * switch where a keyboard event occured). returns 1 if a special
1128:
1129: * control character was eaten, 0 if not
1130:
1131: */
1132:
1133:
1134:
1135: int
1136:
1137: checkkeys()
1138:
1139: {
1140:
1141: char scan, ch;
1142:
1143: short shift;
1144:
1145: int sig, ret;
1146:
1147: struct tty *tty = &con_tty;
1148:
1149: extern char mshift; /* for mouse -- see biosfs.c */
1150:
1151: static short oldktail = 0;
1152:
1153:
1154:
1155: ret = 0;
1156:
1157: mshift = kbshift(-1);
1158:
1159: while (oldktail != keyrec->tail) {
1160:
1161:
1162:
1163: /* BUG: we really should check the shift status _at the time the key was
1164:
1165: * pressed_, not now!
1166:
1167: */
1168:
1169: sig = 0;
1170:
1171: shift = mshift;
1172:
1173: oldktail += 4;
1174:
1175: if (oldktail >= keyrec->buflen)
1176:
1177: oldktail = 0;
1178:
1179:
1180:
1181: scan = (keyrec->bufaddr + oldktail)[1];
1182:
1183: /* function key?? */
1184:
1185: if ( (scan >= 0x3b && scan <= 0x44) ||
1186:
1187: (scan >= 0x54 && scan <= 0x5d) ||
1188:
1189: scan == DEL || scan == UNDO) {
1190:
1191: if ( (shift & CTRLALT) == CTRLALT ) {
1192:
1193: oldktail = keyrec->head = keyrec->tail;
1194:
1195: do_func_key(scan);
1196:
1197: ret = 1;
1198:
1199: continue;
1200:
1201: }
1202:
1203: }
1204:
1205:
1206:
1207: /* check for special control keys, etc. */
1208:
1209: /* BUG: this doesn't exactly match TOS' behavior, particularly for
1210:
1211: * ^S/^Q
1212:
1213: */
1214:
1215: if ((tty->state & TS_COOKED) || (shift & CTRLALT) == CTRLALT) {
1216:
1217: ch = (keyrec->bufaddr + keyrec->tail)[3];
1218:
1219: if (ch == UNDEF)
1220:
1221: ; /* do nothing */
1222:
1223: else if (ch == tty->tc.t_intrc)
1224:
1225: sig = SIGINT;
1226:
1227: else if (ch == tty->tc.t_quitc)
1228:
1229: sig = SIGQUIT;
1230:
1231: else if (ch == tty->ltc.t_suspc)
1232:
1233: sig = SIGTSTP;
1234:
1235: else if (ch == tty->tc.t_stopc) {
1236:
1237: tty->state |= TS_HOLD;
1238:
1239: ret = 1;
1240:
1241: keyrec->head = oldktail;
1242:
1243: continue;
1244:
1245: }
1246:
1247: else if (ch == tty->tc.t_startc) {
1248:
1249: tty->state &= ~TS_HOLD;
1250:
1251: ret = 1;
1252:
1253: keyrec->head = oldktail;
1254:
1255: continue;
1256:
1257: }
1258:
1259: if (sig) {
1260:
1261: tty->state &= ~TS_HOLD;
1262:
1263: if (!(tty->sg.sg_flags & T_NOFLSH))
1264:
1265: oldktail = keyrec->head = keyrec->tail;
1266:
1267: killgroup(tty->pgrp, sig);
1268:
1269: ret = 1;
1270:
1271: }
1272:
1273: else if (tty->state & TS_HOLD) {
1274:
1275: keyrec->head = oldktail;
1276:
1277: ret = 1;
1278:
1279: }
1280:
1281: }
1282:
1283:
1284:
1285: }
1286:
1287:
1288:
1289: /* has someone done select() on the keyboard?? */
1290:
1291: if (tty->rsel && keyrec->head != keyrec->tail)
1292:
1293: wakeselect(tty->rsel);
1294:
1295:
1296:
1297: return ret;
1298:
1299: }
1300:
1301:
1302:
1303: /* do_func_key moved to debug.c */
1304:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.