|
|
1.1 root 1: /*
2:
1.1.1.3 root 3: Copyright 1990,1991,1992 Eric R. Smith.
4:
1.1.1.5 ! root 5: Copyright 1992,1993,1994 Atari Corporation.
1.1.1.3 root 6:
7: All rights reserved.
1.1 root 8:
9: */
10:
11:
12:
13: /*
14:
15: * BIOS replacement routines
16:
17: */
18:
19:
20:
21: #include "mint.h"
22:
1.1.1.3 root 23: #include "xbra.h"
24:
1.1 root 25:
26:
27: #define UNDEF 0 /* should match definition in tty.c */
28:
29:
30:
31: /* some key definitions */
32:
33: #define CTRLALT 0xc
34:
35: #define DEL 0x53 /* scan code of delete key */
36:
37: #define UNDO 0x61 /* scan code of undo key */
38:
39:
40:
41: /* BIOS device definitions */
42:
43: #define CONSDEV 2
44:
45: #define AUXDEV 1
46:
1.1.1.4 root 47: #define PRNDEV 0
48:
1.1 root 49:
50:
51: /* BIOS devices 0..MAX_BHANDLE-1 can be redirected to GEMDOS files */
52:
53: #define MAX_BHANDLE 4
54:
55:
56:
57: /* BIOS redirection maps */
58:
1.1.1.2 root 59: const short binput[MAX_BHANDLE] = { -3, -2, -1, -4 };
1.1 root 60:
1.1.1.2 root 61: const short boutput[MAX_BHANDLE] = { -3, -2, -1, -5 };
1.1 root 62:
63:
64:
65: /* tty structures for the BIOS devices -- see biosfs.c */
66:
67: extern struct tty con_tty, aux_tty, midi_tty;
68:
69:
70:
71: extern int tosvers; /* from main.c */
72:
1.1.1.4 root 73:
74:
1.1 root 75: char *kbshft; /* set in main.c */
76:
77:
78:
1.1.1.5 ! root 79: short console_in; /* wait condition for console input */
! 80:
! 81:
! 82:
1.1 root 83: /* some BIOS vectors; note that the routines at these vectors may do nasty
84:
85: * things to registers!
86:
87: */
88:
89:
90:
1.1.1.2 root 91: #define RWABS *((long *)0x476L)
1.1 root 92:
1.1.1.2 root 93: #define MEDIACH *((long *)0x47eL)
1.1 root 94:
1.1.1.2 root 95: #define GETBPB *((long *)0x472L)
1.1 root 96:
97:
98:
1.1.1.3 root 99:
100:
101: #if 1
102:
1.1.1.2 root 103: /* these are supposed to be tables holding the addresses of the
1.1 root 104:
1.1.1.2 root 105: * first 8 BconXXX functions, but in fact only the first 5 are
1.1 root 106:
1.1.1.2 root 107: * placed here (and device 5 only has Bconout implemented;
1.1 root 108:
1.1.1.2 root 109: * we don't use that device (raw console) anyway).
1.1 root 110:
1.1.1.2 root 111: */
112:
113:
114:
115: #define xconstat ((long *)0x51eL)
116:
117: #define xconin ((long *)0x53eL)
118:
119: #define xcostat ((long *)0x55eL)
120:
121: #define xconout ((long *)0x57eL)
122:
123:
124:
125: #define BCOSTAT(dev) \
126:
1.1.1.4 root 127: ((tosvers > 0x0102 && (unsigned)dev <= 4) ? \
1.1.1.2 root 128:
129: (int)callout1(xcostat[dev], dev) : Bcostat(dev))
1.1 root 130:
1.1.1.2 root 131: #define BCONOUT(dev, c) \
1.1 root 132:
1.1.1.4 root 133: ((tosvers > 0x0102 && (unsigned)dev <= 4) ? \
1.1 root 134:
1.1.1.2 root 135: callout2(xconout[dev], dev, c) : Bconout(dev, c))
1.1 root 136:
1.1.1.2 root 137: #define BCONSTAT(dev) \
1.1 root 138:
1.1.1.4 root 139: ((tosvers > 0x0102 && (unsigned)dev <= 4) ? \
1.1.1.2 root 140:
141: (int)callout1(xconstat[dev], dev) : Bconstat(dev))
142:
143: #define BCONIN(dev) \
144:
1.1.1.4 root 145: ((tosvers > 0x0102 && (unsigned)dev <= 4) ? \
1.1.1.2 root 146:
147: callout1(xconin[dev], dev) : Bconin(dev))
1.1 root 148:
1.1.1.3 root 149: #else
150:
151: #define BCOSTAT(dev) Bcostat(dev)
152:
153: #define BCONOUT(dev,c) Bconout(dev,c)
154:
155: #define BCONSTAT(dev) Bconstat(dev)
156:
157: #define BCONIN(dev) Bconin(dev)
158:
159: #endif
160:
1.1 root 161:
162:
163: /* variables for monitoring the keyboard */
164:
165: IOREC_T *keyrec; /* keyboard i/o record pointer */
166:
167: short kintr = 0; /* keyboard interrupt pending (see intr.s) */
168:
169:
170:
171: /* Getmpb is not allowed under MiNT */
172:
173:
174:
1.1.1.2 root 175: long ARGS_ON_STACK
1.1 root 176:
177: getmpb(ptr)
178:
179: void *ptr;
180:
181: {
182:
1.1.1.2 root 183: UNUSED(ptr);
184:
185:
186:
187: DEBUG(("failed call to Getmpb"));
1.1 root 188:
189: return -1;
190:
191: }
192:
193:
194:
195:
196:
197: /*
198:
199: * Note that BIOS handles 0 - MAX_BHANDLE now reference file handles;
200:
201: * to get the physical devices, go through u:\dev\
202:
203: *
204:
205: * A note on translation: all of the bco[n]XXX functions have a "u"
206:
207: * variant that is actually what the user calls. For example,
208:
209: * ubconstat is the function that gets control after the user does
210:
211: * a Bconstat. It figures out what device or file handle is
212:
213: * appropriate. Typically, it will be a biosfs file handle; a
214:
215: * request is sent to biosfs, and biosfs in turn figures out
216:
217: * the "real" device and calls bconstat.
218:
219: */
220:
221:
222:
1.1.1.2 root 223: /*
224:
225: * WARNING: syscall.spp assumes that ubconstat never blocks.
226:
227: */
228:
229: long ARGS_ON_STACK
1.1 root 230:
231: ubconstat(dev)
232:
233: int dev;
234:
235: {
236:
1.1.1.2 root 237: if (dev < MAX_BHANDLE) {
238:
239: FILEPTR *f = curproc->handle[binput[dev]];
1.1 root 240:
1.1.1.2 root 241: return file_instat(f) ? -1 : 0;
242:
243: }
1.1 root 244:
245: else
246:
247: return bconstat(dev);
248:
249: }
250:
251:
252:
253: long
254:
255: bconstat(dev)
256:
257: int dev;
258:
259: {
260:
261: if (dev == CONSDEV) {
262:
263: if (checkkeys()) return 0;
264:
265: return (keyrec->head != keyrec->tail) ? -1 : 0;
266:
267: }
268:
269: if (dev == AUXDEV && has_bconmap)
270:
271: dev = curproc->bconmap;
272:
273:
274:
1.1.1.2 root 275: return BCONSTAT(dev);
1.1 root 276:
277: }
278:
279:
280:
281: /* bconin: input a character */
282:
1.1.1.2 root 283: /*
1.1 root 284:
1.1.1.2 root 285: * WARNING: syscall.spp assumes that ubconin never
1.1 root 286:
1.1.1.2 root 287: * blocks if ubconstat returns non-zero.
288:
289: */
290:
291: long ARGS_ON_STACK
1.1 root 292:
293: ubconin(dev)
294:
295: int dev;
296:
297: {
298:
1.1.1.2 root 299: if (dev < MAX_BHANDLE) {
300:
301: FILEPTR *f = curproc->handle[binput[dev]];
1.1 root 302:
1.1.1.2 root 303: return file_getchar(f, RAW);
304:
305: }
1.1 root 306:
307: else
308:
309: return bconin(dev);
310:
311: }
312:
313:
314:
315: long
316:
317: bconin(dev)
318:
319: int dev;
320:
321: {
322:
323: IOREC_T *k;
324:
325: long r;
326:
327: short h;
328:
329:
330:
331: if (dev == CONSDEV) {
332:
333: k = keyrec;
334:
335: again:
336:
337: while (k->tail == k->head) {
338:
1.1.1.5 ! root 339: sleep(IO_Q, (long)&console_in);
1.1 root 340:
341: }
342:
343:
344:
345: if (checkkeys()) goto again;
346:
347:
348:
349: h = k->head + 4;
350:
351: if (h >= k->buflen)
352:
353: h = 0;
354:
355: r = *((long *)(k->bufaddr + h));
356:
357: k->head = h;
358:
359: return r;
360:
361: }
362:
363: else {
364:
365: if (dev == AUXDEV && has_bconmap)
366:
367: dev = curproc->bconmap;
368:
369:
370:
1.1.1.2 root 371: if (dev > 0) {
1.1 root 372:
1.1.1.5 ! root 373: unsigned long tick;
! 374:
! 375:
! 376:
! 377: tick = *((unsigned long *)0x4baL);
! 378:
1.1.1.2 root 379: while (!BCONSTAT(dev)) {
1.1 root 380:
1.1.1.5 ! root 381: /* make blocking (for longer) reads eat less CPU...
! 382:
! 383: * if yield()ed > 2 seconds and still no data continue with nap
! 384:
! 385: */
! 386:
! 387: if ((*((unsigned long *)0x4baL) - tick) > 400)
! 388:
! 389: nap(60);
! 390:
! 391: else
! 392:
1.1 root 393: yield();
394:
395: }
396:
1.1.1.2 root 397: }
398:
1.1 root 399: }
400:
401:
402:
1.1.1.2 root 403: r = BCONIN(dev);
1.1 root 404:
405:
406:
407: return r;
408:
409: }
410:
411:
412:
413: /* bconout: output a character.
414:
415: * returns 0 for failure, nonzero for success
416:
417: */
418:
419:
420:
1.1.1.2 root 421: long ARGS_ON_STACK
1.1 root 422:
423: ubconout(dev, c)
424:
425: int dev, c;
426:
427: {
428:
429: FILEPTR *f;
430:
1.1.1.2 root 431: char outp;
432:
1.1 root 433:
434:
435: if (dev < MAX_BHANDLE) {
436:
437: f = curproc->handle[boutput[dev]];
438:
439: if (!f) return 0;
440:
441: if (is_terminal(f)) {
442:
443: return tty_putchar(f, ((long)c)&0x00ff, RAW);
444:
445: }
446:
1.1.1.2 root 447: outp = c;
1.1 root 448:
1.1.1.2 root 449: return (*f->dev->write)(f, &outp, 1L);
1.1 root 450:
451: }
452:
453: else if (dev == 5) {
454:
455: c &= 0x00ff;
456:
457: f = curproc->handle[-1];
458:
459: if (!f) return 0;
460:
461: if (is_terminal(f)) {
462:
463: if (c < ' ') {
464:
465: /* MW hack for quoted characters */
466:
467: tty_putchar(f, (long)'\033', RAW);
468:
469: tty_putchar(f, (long)'Q', RAW);
470:
471: }
472:
473: return tty_putchar(f, ((long)c)&0x00ff, RAW);
474:
475: }
476:
477: /* note: we're assuming sizeof(int) == 2 here! */
478:
1.1.1.2 root 479: outp = c;
480:
481: return (*f->dev->write)(f, &outp, 1L);
1.1 root 482:
483: } else
484:
485: return bconout(dev, c);
486:
487: }
488:
489:
490:
491: long
492:
493: bconout(dev, c)
494:
495: int dev,c;
496:
497: {
498:
499: int statdev;
500:
501: long endtime;
502:
1.1.1.3 root 503: #define curtime *((unsigned long *)0x4baL)
1.1 root 504:
505:
506:
507: if (dev == AUXDEV && has_bconmap) {
508:
509: dev = curproc->bconmap;
510:
511: }
512:
513:
514:
515: /* compensate for a known BIOS bug; MIDI and IKBD are switched */
516:
517: if (dev == 3) { /* MIDI */
518:
519: statdev = 4;
520:
521: } else if (dev == 4) {
522:
523: statdev = 3;
524:
1.1.1.3 root 525: } else {
1.1 root 526:
527: statdev = dev;
528:
1.1.1.3 root 529: }
530:
1.1 root 531:
532:
1.1.1.4 root 533: /* provide a 10 second time out for the printer */
1.1 root 534:
1.1.1.2 root 535: if (!BCOSTAT(statdev)) {
1.1 root 536:
1.1.1.4 root 537: if (dev != PRNDEV) {
538:
539: do {
540:
541: /* BUG: Speedo GDOS isn't re-entrant; so printer output to the
542:
543: * serial port could cause problems
1.1 root 544:
1.1.1.4 root 545: */
546:
547: yield();
548:
549: } while (!BCOSTAT(statdev));
550:
551: } else {
552:
553: endtime = curtime + 10*200L;
554:
555: do {
1.1 root 556:
1.1.1.3 root 557: #if 0
558:
1.1.1.4 root 559: /* Speedo GDOS isn't re-entrant, so we can't give up CPU
560:
561: * time here :-(
562:
563: */
564:
565: yield();
1.1.1.2 root 566:
1.1.1.3 root 567: #endif
1.1 root 568:
1.1.1.4 root 569: } while (!BCOSTAT(statdev) && curtime < endtime);
570:
571: if ( curtime >= endtime) return 0;
1.1.1.3 root 572:
1.1.1.4 root 573: }
1.1.1.2 root 574:
575: }
1.1 root 576:
577:
578:
579: /* special case: many text accelerators return a bad value from
580:
581: * Bconout, so we ignore the returned value for the console
582:
1.1.1.4 root 583: * Sigh. serptch2 and hsmodem1 also screw this up, so for now let's
584:
585: * only count on it being correct for the printer.
586:
1.1 root 587: */
588:
1.1.1.4 root 589: if (dev == PRNDEV) {
1.1 root 590:
591: /* NOTE: if your compiler complains about the next line, then Bconout is
592:
593: * improperly declared in your osbind.h header file. it should be returning
594:
595: * a long value; some libraries incorrectly have Bconout returning void
596:
597: * (or cast the returned value to void)
598:
599: */
600:
1.1.1.2 root 601: return BCONOUT(dev,c);
1.1 root 602:
603: } else {
604:
1.1.1.2 root 605: (void)BCONOUT(dev, c);
1.1 root 606:
607: return 1;
608:
609: }
610:
611: }
612:
613:
614:
615: /* rwabs: various disk stuff */
616:
617:
618:
1.1.1.2 root 619: long ARGS_ON_STACK
1.1 root 620:
621: rwabs(rwflag, buffer, number, recno, dev, lrecno)
622:
623: int rwflag, number, recno, dev;
624:
625: void *buffer;
626:
627: long lrecno;
628:
629: {
630:
631: long r;
632:
1.1.1.2 root 633: extern PROC *dlockproc[]; /* in dosdir.c */
634:
1.1.1.5 ! root 635: extern int aliasdrv[]; /* in filesys.c */
! 636:
1.1.1.2 root 637:
638:
1.1.1.5 ! root 639: if (dev >= 0 && dev < NUM_DRIVES) {
1.1.1.2 root 640:
1.1.1.5 ! root 641: if (aliasdrv[dev]) {
! 642:
! 643: dev = aliasdrv[dev] - 1;
! 644:
! 645: }
! 646:
! 647: if (dlockproc[dev] && dlockproc[dev] != curproc) {
1.1.1.2 root 648:
649: DEBUG(("Rwabs: device %c is locked", dev+'A'));
650:
651: return ELOCKED;
652:
653: }
654:
655: }
656:
1.1 root 657:
658:
1.1.1.5 ! root 659: #if 1
! 660:
! 661: /* only the superuser can make Rwabs calls directly */
1.1 root 662:
663:
664:
1.1.1.5 ! root 665: if (curproc->in_dos || (curproc->euid == 0))
! 666:
! 667: /* Note that some (most?) Rwabs device drivers don't bother saving
! 668:
! 669: * registers, whereas our compiler expects politeness. So we go
! 670:
! 671: * via callout(), which will save registers for us.
! 672:
! 673: */
! 674:
! 675: r = callout(RWABS, rwflag, buffer, number, recno, dev, lrecno);
! 676:
! 677: else {
! 678:
! 679: DEBUG(("Rwabs by non privileged process!"));
! 680:
! 681: r = EACCDN;
! 682:
! 683: }
! 684:
! 685: #else
1.1 root 686:
687: r = callout(RWABS, rwflag, buffer, number, recno, dev, lrecno);
688:
1.1.1.5 ! root 689: #endif
! 690:
1.1 root 691: return r;
692:
693: }
694:
695:
696:
697: /* setexc: set exception vector */
698:
699:
700:
1.1.1.2 root 701: long ARGS_ON_STACK
1.1 root 702:
703: setexc(number, vector)
704:
705: int number;
706:
707: long vector;
708:
709: {
710:
711: long *place;
712:
713: long old;
714:
715: extern long save_dos, save_bios, save_xbios; /* in main.c */
716:
1.1.1.3 root 717: extern int no_mem_prot; /* in main.c */
1.1 root 718:
719:
720:
721: place = (long *)(((long)number) << 2);
722:
723: if (number == 0x21) /* trap_1 */
724:
725: old = save_dos;
726:
727: else if (number == 0x2d) /* trap_13 */
728:
729: old = save_bios;
730:
731: else if (number == 0x2e) /* trap_14 */
732:
733: old = save_xbios;
734:
735: else if (number == 0x101)
736:
737: old = (long)curproc->criticerr; /* critical error vector */
738:
739: else if (number == 0x102)
740:
741: old = curproc->ctxt[SYSCALL].term_vec; /* GEMDOS term vector */
742:
743: else
744:
745: old = *place;
746:
747:
748:
749: if (vector > 0) {
750:
1.1.1.3 root 751: /* validate vector; this will cause a bus error if mem
752:
753: * protection is on and the current process doesn't have
754:
755: * access to the memory
756:
757: */
758:
759: if (*((long *)vector) == 0xDEADBEEFL)
760:
761: return old;
762:
763:
764:
1.1 root 765: if (number == 0x21)
766:
767: save_dos = vector;
768:
769: else if (number == 0x2d)
770:
771: save_bios = vector;
772:
773: else if (number == 0x2e)
774:
775: save_xbios = vector;
776:
777: else if (number == 0x102)
778:
779: curproc->ctxt[SYSCALL].term_vec = vector;
780:
781: else if (number == 0x101) {
782:
783: long mintcerr;
784:
785:
786:
787: /*
788:
789: * problem: lots of TSR's look for the Setexc(0x101,...)
790:
791: * that the AES does at startup time; so we have
792:
793: * to pass it along.
794:
795: */
796:
797: mintcerr = (long) Setexc(0x101, (void *)vector);
798:
1.1.1.2 root 799: curproc->criticerr = (long ARGS_ON_STACK (*) P_((long))) *place;
1.1 root 800:
801: *place = mintcerr;
802:
803: }
804:
805: else {
806:
1.1.1.3 root 807: if (!no_mem_prot) {
808:
809: /*
810:
811: * if memory protection is on, the vector should be
812:
813: * pointing at supervisor or global memory
814:
815: */
816:
817: MEMREGION *r;
818:
819:
820:
821: r = addr2region(vector);
822:
823: if (r && get_prot_mode(r) == PROT_P) {
824:
825: DEBUG(("Changing protection to Supervisor because of Setexc"));
826:
827: mark_region(r, PROT_S);
828:
829: }
830:
831: }
832:
1.1 root 833: /* We would do just *place = vector except that
834:
835: * someone else might be intercepting Setexc looking
836:
837: * for something in particular...
838:
839: */
840:
841: old = (long) Setexc(number, (void *)vector);
842:
843: }
844:
845: }
846:
1.1.1.3 root 847:
848:
849: TRACE(("Setexc %d, %lx -> %lx", number, vector, old));
850:
1.1 root 851: return old;
852:
853: }
854:
855:
856:
857: /* tickcal: return milliseconds per system clock tick */
858:
859:
860:
1.1.1.2 root 861: long ARGS_ON_STACK
1.1 root 862:
863: tickcal()
864:
865: {
866:
867: return (long) (*( (unsigned *) 0x0442L ));
868:
869: }
870:
871:
872:
873: /* getbpb: get BIOS parameter block */
874:
875:
876:
1.1.1.2 root 877: long ARGS_ON_STACK
1.1 root 878:
879: getbpb(dev)
880:
881: int dev;
882:
883: {
884:
885: long r;
886:
887:
888:
889: /* we can't trust the Getbpb routine to accurately save all registers,
890:
891: * so we do it ourselves
892:
893: */
894:
1.1.1.4 root 895: r = callout1(GETBPB, dev);
1.1 root 896:
897: /*
898:
899: * There is a bug in the TOS disk handling routines (well several actually).
900:
901: * If the directory size of Getbpb() is returned as zero then the drive 'dies'
902:
903: * and wont read any new disks even with the 'ESC' enforced disk change . This
904:
905: * is present even in TOS 1.6 (not sure about 1.62 though). This small routine
906:
907: * changes the dir size to '1' if it is zero . It may make some non-TOS disks
908:
909: * look a bit weird but that's better than killing the drive .
910:
911: */
912:
913: if (r) {
914:
915: if ( ((short *)r)[3] == 0) /* 0 directory size? */
916:
917: ((short *)r)[3] = 1;
918:
919: }
920:
921: return r;
922:
923: }
924:
925:
926:
927: /* bcostat: return output device status */
928:
929:
930:
1.1.1.2 root 931: /* WARNING: syscall.spp assumes that ubcostat never
932:
933: * blocks
934:
935: */
936:
937: long ARGS_ON_STACK
1.1 root 938:
939: ubcostat(dev)
940:
941: int dev;
942:
943: {
944:
1.1.1.2 root 945: FILEPTR *f;
946:
947:
948:
1.1 root 949: /* the BIOS switches MIDI (3) and IKBD (4) (a bug, but it can't be corrected) */
950:
951: if (dev == 4) { /* really the MIDI port */
952:
1.1.1.2 root 953: f = curproc->handle[boutput[3]];
954:
955: return file_outstat(f) ? -1 : 0;
1.1 root 956:
957: }
958:
959: if (dev == 3)
960:
1.1.1.2 root 961: return BCOSTAT(dev);
1.1 root 962:
963:
964:
1.1.1.2 root 965: if (dev < MAX_BHANDLE) {
1.1 root 966:
1.1.1.2 root 967: f = curproc->handle[boutput[dev]];
1.1 root 968:
1.1.1.2 root 969: return file_outstat(f) ? -1 : 0;
970:
971: } else
1.1 root 972:
973: return bcostat(dev);
974:
975: }
976:
977:
978:
979: long
980:
981: bcostat(dev)
982:
983: int dev;
984:
985: {
986:
987:
988:
989: if (dev == CONSDEV) {
990:
991: return -1;
992:
993: }
994:
995: else if (dev == AUXDEV && has_bconmap) {
996:
997: dev = curproc->bconmap;
998:
999: }
1000:
1001: /* compensate here for the BIOS bug, so that the MIDI and IKBD files work
1002:
1003: * correctly
1004:
1005: */
1006:
1007: else if (dev == 3) dev = 4;
1008:
1009: else if (dev == 4) dev = 3;
1010:
1011:
1012:
1.1.1.2 root 1013: return BCOSTAT(dev);
1.1 root 1014:
1015: }
1016:
1017:
1018:
1019: /* mediach: check for media change */
1020:
1021:
1022:
1.1.1.2 root 1023: long ARGS_ON_STACK
1.1 root 1024:
1025: mediach(dev)
1026:
1027: int dev;
1028:
1029: {
1030:
1031: long r;
1032:
1033:
1034:
1.1.1.3 root 1035: r = callout1(MEDIACH, dev);
1.1 root 1036:
1037: return r;
1038:
1039: }
1040:
1041:
1042:
1043: /* drvmap: return drives connected to system */
1044:
1045:
1046:
1.1.1.2 root 1047: long ARGS_ON_STACK
1.1 root 1048:
1049: drvmap()
1050:
1051: {
1052:
1053: return *( (long *)0x4c2L );
1054:
1055: }
1056:
1057:
1058:
1059: /* kbshift: return (and possibly change) keyboard shift key status */
1060:
1.1.1.2 root 1061: /* WARNING: syscall.spp assumes that kbshift never blocks, and never
1.1 root 1062:
1.1.1.2 root 1063: * calls any underlying TOS functions
1.1 root 1064:
1.1.1.2 root 1065: */
1066:
1067: long ARGS_ON_STACK
1.1 root 1068:
1069: kbshift(mode)
1070:
1071: int mode;
1072:
1073: {
1074:
1075: int oldshft;
1076:
1077:
1078:
1079: oldshft = *((unsigned char *)kbshft);
1080:
1081: if (mode >= 0)
1082:
1083: *kbshft = mode;
1084:
1085: return oldshft;
1086:
1087: }
1088:
1089:
1090:
1091:
1092:
1093: /* special Bconout buffering code:
1094:
1095: * Because system call overhead is so high, programs that do output
1096:
1097: * with Bconout suffer in performance. To compensate for this,
1098:
1099: * Bconout is special-cased in syscall.s, and if possible characters
1100:
1101: * are placed in the 256 byte bconbuf buffer. This buffer is flushed
1102:
1103: * when any system call other than Bconout happens, or when a context
1104:
1105: * switch occurs.
1106:
1107: */
1108:
1109:
1110:
1111: short bconbsiz; /* number of characters in buffer */
1112:
1113: unsigned char bconbuf[256]; /* buffer contents */
1114:
1115: short bconbdev; /* BIOS device for which the buffer is valid */
1116:
1117: /* (-1 means no buffering is active) */
1118:
1119:
1120:
1121: /*
1122:
1123: * flush pending BIOS output. Return 0 if some bytes were not successfully
1124:
1125: * written, non-zero otherwise (just like bconout)
1126:
1127: */
1128:
1129:
1130:
1.1.1.2 root 1131: long ARGS_ON_STACK
1.1 root 1132:
1133: bflush() /* flush bios output */
1134:
1135: {
1136:
1137: long ret, bsiz;
1138:
1139: unsigned char *s;
1140:
1141: FILEPTR *f;
1142:
1143: short dev;
1144:
1145: short statdev;
1146:
1.1.1.2 root 1147: long lbconbuf[256];
1148:
1.1 root 1149:
1150:
1151: if ((dev = bconbdev) < 0) return 0;
1152:
1153:
1154:
1155: /*
1156:
1157: * Here we lock the BIOS buffering mechanism by setting bconbdev to -1
1158:
1159: * This is necessary because if two or more programs try to do
1160:
1161: * buffered BIOS output at the same time, they can get seriously
1162:
1163: * mixed up. We unlock by setting bconbdev to 0.
1164:
1165: *
1166:
1167: * NOTE: some code (e.g. in sleep()) checks for bconbsiz != 0 in
1168:
1169: * order to see if we need to do a bflush; if one is already in
1170:
1171: * progress, it's pointless to do this, so we save a bit of
1172:
1173: * time by setting bconbsiz to 0 here.
1174:
1175: */
1176:
1177: bconbdev = -1;
1178:
1179: bsiz = bconbsiz;
1180:
1.1.1.2 root 1181: if (bsiz == 0) return 0;
1182:
1.1 root 1183: bconbsiz = 0;
1184:
1185:
1186:
1187: /* BIOS handles 0..MAX_BHANDLE-1 are aliases for special GEMDOS files */
1188:
1189: if (dev < MAX_BHANDLE || dev == 5) {
1190:
1191: if (dev == 5)
1192:
1193: f = curproc->handle[-1];
1194:
1195: else
1196:
1197: f = curproc->handle[boutput[dev]];
1198:
1199:
1200:
1201: if (!f) {
1202:
1203: bconbdev = 0;
1204:
1205: return 0;
1206:
1207: }
1208:
1209: if (is_terminal(f)) {
1210:
1211: s = bconbuf;
1212:
1213: if (dev == 5) {
1214:
1215: while (bsiz-- > 0) {
1216:
1217: if (*s < ' ') {
1218:
1219: /* use ESC-Q to quote control character */
1220:
1221: (void)tty_putchar(f, (long)'\033',
1222:
1223: RAW);
1224:
1225: (void)tty_putchar(f, (long)'Q',
1226:
1227: RAW);
1228:
1229: }
1230:
1231: (void) tty_putchar(f, (long)*s++, RAW);
1232:
1233: }
1234:
1235: } else {
1236:
1.1.1.2 root 1237: #if 1
1238:
1239: long *where, nbytes;
1240:
1241:
1242:
1243: /* the tty_putchar should set up terminal modes correctly */
1244:
1245: (void) tty_putchar(f, (long)*s++, RAW);
1246:
1247: where = lbconbuf;
1248:
1249: nbytes = 0;
1250:
1251: while (--bsiz > 0) {
1252:
1253: *where++ = *s++; nbytes+=4;
1254:
1255: }
1256:
1257: if (nbytes)
1258:
1259: (*f->dev->write)(f, (char *)lbconbuf, nbytes);
1260:
1261: #else
1262:
1.1 root 1263: while (bsiz-- > 0) {
1264:
1265: (void) tty_putchar(f, (long)*s++, RAW);
1266:
1267: }
1268:
1.1.1.2 root 1269: #endif
1270:
1.1 root 1271: }
1272:
1273: ret = -1;
1274:
1275: } else {
1276:
1277: ret = (*f->dev->write)(f, (char *)bconbuf, bsiz);
1278:
1279: }
1280:
1281: bconbdev = 0;
1282:
1283: return ret;
1284:
1285: }
1286:
1287:
1288:
1289: /* Otherwise, we have a real BIOS device */
1290:
1291:
1292:
1293: if (dev == AUXDEV && has_bconmap) {
1294:
1295: dev = curproc->bconmap;
1296:
1297: statdev = dev;
1298:
1299: }
1300:
1301: /* compensate for a known BIOS bug; MIDI and IKBD are switched */
1302:
1303: else if (dev == 3) { /* MIDI */
1304:
1305: statdev = 4;
1306:
1307: } else if (dev == 4) {
1308:
1309: statdev = 3;
1310:
1311: } else
1312:
1313: statdev = dev;
1314:
1315:
1316:
1317: s = bconbuf;
1318:
1319: while (bsiz-- > 0) {
1320:
1.1.1.2 root 1321: while (!BCOSTAT(statdev)) yield();
1.1 root 1322:
1.1.1.2 root 1323: (void)BCONOUT(dev,*s);
1.1 root 1324:
1325: s++;
1326:
1327: }
1328:
1329: bconbdev = 0;
1330:
1331: return 1L;
1332:
1333: }
1334:
1335:
1336:
1337: /* initialize bios table */
1338:
1339:
1340:
1341: #define BIOS_MAX 0x20
1342:
1343:
1344:
1345: Func bios_tab[BIOS_MAX] = {
1346:
1347: getmpb,
1348:
1349: ubconstat,
1350:
1351: ubconin,
1352:
1353: ubconout,
1354:
1.1.1.2 root 1355:
1356:
1.1 root 1357: rwabs,
1358:
1359: setexc,
1360:
1361: tickcal,
1362:
1363: getbpb,
1364:
1.1.1.2 root 1365:
1366:
1.1 root 1367: ubcostat,
1368:
1369: mediach,
1370:
1371: drvmap,
1372:
1373: kbshift,
1374:
1.1.1.2 root 1375:
1376:
1.1 root 1377: 0, 0, 0, 0,
1378:
1379: 0, 0, 0, 0, 0, 0, 0, 0,
1380:
1381: 0, 0, 0, 0, 0, 0, 0, 0
1382:
1383: };
1384:
1385:
1386:
1387: short bios_max = BIOS_MAX;
1388:
1389:
1390:
1391: /*
1392:
1393: * BIOS initialization routine: gets keyboard buffer pointers, for the
1394:
1395: * interrupt routine below
1396:
1397: */
1398:
1399:
1400:
1401: void
1402:
1403: init_bios()
1404:
1405: {
1406:
1407: keyrec = (IOREC_T *)Iorec(1);
1408:
1409: }
1410:
1411:
1412:
1413: /*
1414:
1.1.1.2 root 1415: * do_bconin: try to do a bconin function quickly, without
1416:
1417: * blocking. If we can't do it without blocking, we return
1418:
1419: * 0x0123dead and the calling trap #13 code falls through
1420:
1421: * to the normal bconin stuff. We can't block here because
1422:
1423: * the trap #13 code hasn't yet saved registers or other
1424:
1425: * context bits, so sleep() wouldn't work properly.
1426:
1427: */
1428:
1429:
1430:
1431: #define WOULDBLOCK 0x0123deadL
1432:
1433:
1434:
1435: /* WARNING: syscall.spp assumes that do_bconin never blocks */
1436:
1437:
1438:
1439: long ARGS_ON_STACK
1440:
1441: do_bconin(dev)
1442:
1443: int dev;
1444:
1445: {
1446:
1447: FILEPTR *f;
1448:
1449: long r;
1450:
1451: unsigned char c;
1452:
1453:
1454:
1455: if (dev < MAX_BHANDLE) {
1456:
1457: f = curproc->handle[binput[dev]];
1458:
1459: if (!f) return 0;
1460:
1461: r = 0;
1462:
1463: (void)(*f->dev->ioctl)(f, FIONREAD, &r);
1464:
1465: if (!r) return WOULDBLOCK; /* data not ready */
1466:
1467: if (is_terminal(f))
1468:
1469: r = tty_getchar(f, RAW);
1470:
1471: else {
1472:
1473: r = (*f->dev->read)(f, (char *)&c, 1L);
1474:
1475: r = (r == 1) ? c : MiNTEOF;
1476:
1477: }
1478:
1479: } else {
1480:
1481: if (!bconstat(dev))
1482:
1483: r = WOULDBLOCK;
1484:
1485: else
1486:
1487: r = bconin(dev);
1488:
1489: }
1490:
1491: return r;
1492:
1493: }
1494:
1495:
1496:
1497: /*
1498:
1.1 root 1499: * routine for checking keyboard (called by sleep() on any context
1500:
1501: * switch where a keyboard event occured). returns 1 if a special
1502:
1503: * control character was eaten, 0 if not
1504:
1505: */
1506:
1507:
1508:
1509: int
1510:
1511: checkkeys()
1512:
1513: {
1514:
1515: char scan, ch;
1516:
1517: short shift;
1518:
1519: int sig, ret;
1520:
1521: struct tty *tty = &con_tty;
1522:
1523: extern char mshift; /* for mouse -- see biosfs.c */
1524:
1525: static short oldktail = 0;
1526:
1527:
1528:
1529: ret = 0;
1530:
1531: mshift = kbshift(-1);
1532:
1533: while (oldktail != keyrec->tail) {
1534:
1535:
1536:
1537: /* BUG: we really should check the shift status _at the time the key was
1538:
1539: * pressed_, not now!
1540:
1541: */
1542:
1543: sig = 0;
1544:
1545: shift = mshift;
1546:
1547: oldktail += 4;
1548:
1549: if (oldktail >= keyrec->buflen)
1550:
1551: oldktail = 0;
1552:
1553:
1554:
1555: scan = (keyrec->bufaddr + oldktail)[1];
1556:
1557: /* function key?? */
1558:
1559: if ( (scan >= 0x3b && scan <= 0x44) ||
1560:
1561: (scan >= 0x54 && scan <= 0x5d) ||
1562:
1563: scan == DEL || scan == UNDO) {
1564:
1565: if ( (shift & CTRLALT) == CTRLALT ) {
1566:
1567: oldktail = keyrec->head = keyrec->tail;
1568:
1569: do_func_key(scan);
1570:
1.1.1.2 root 1571: /* do_func_key may have read some keys */
1572:
1573: oldktail = keyrec->head;
1574:
1575: mshift = kbshift (-1);
1576:
1.1 root 1577: ret = 1;
1578:
1579: continue;
1580:
1581: }
1582:
1583: }
1584:
1585:
1586:
1587: /* check for special control keys, etc. */
1588:
1589: /* BUG: this doesn't exactly match TOS' behavior, particularly for
1590:
1591: * ^S/^Q
1592:
1593: */
1594:
1595: if ((tty->state & TS_COOKED) || (shift & CTRLALT) == CTRLALT) {
1596:
1597: ch = (keyrec->bufaddr + keyrec->tail)[3];
1598:
1599: if (ch == UNDEF)
1600:
1601: ; /* do nothing */
1602:
1603: else if (ch == tty->tc.t_intrc)
1604:
1605: sig = SIGINT;
1606:
1607: else if (ch == tty->tc.t_quitc)
1608:
1609: sig = SIGQUIT;
1610:
1611: else if (ch == tty->ltc.t_suspc)
1612:
1613: sig = SIGTSTP;
1614:
1615: else if (ch == tty->tc.t_stopc) {
1616:
1617: tty->state |= TS_HOLD;
1618:
1619: ret = 1;
1620:
1621: keyrec->head = oldktail;
1622:
1623: continue;
1624:
1625: }
1626:
1627: else if (ch == tty->tc.t_startc) {
1628:
1629: tty->state &= ~TS_HOLD;
1630:
1631: ret = 1;
1632:
1633: keyrec->head = oldktail;
1634:
1635: continue;
1636:
1637: }
1638:
1639: if (sig) {
1640:
1641: tty->state &= ~TS_HOLD;
1642:
1643: if (!(tty->sg.sg_flags & T_NOFLSH))
1644:
1645: oldktail = keyrec->head = keyrec->tail;
1646:
1647: killgroup(tty->pgrp, sig);
1648:
1649: ret = 1;
1650:
1651: }
1652:
1653: else if (tty->state & TS_HOLD) {
1654:
1655: keyrec->head = oldktail;
1656:
1657: ret = 1;
1658:
1659: }
1660:
1661: }
1662:
1663:
1664:
1665: }
1666:
1667:
1668:
1.1.1.5 ! root 1669: if (keyrec->head != keyrec->tail) {
1.1 root 1670:
1.1.1.5 ! root 1671: /* wake up any processes waiting in bconin() */
1.1 root 1672:
1.1.1.5 ! root 1673: wake(IO_Q, (long)&console_in);
! 1674:
! 1675: /* wake anyone that did a select() on the keyboard */
! 1676:
! 1677: if (tty->rsel)
! 1678:
! 1679: wakeselect(tty->rsel);
! 1680:
! 1681: }
1.1 root 1682:
1683:
1684:
1685: return ret;
1686:
1687: }
1688:
1689:
1690:
1.1.1.3 root 1691:
1692:
1693: /*
1694:
1695: * special vector stuff: we try to save as many vectors as possible,
1696:
1697: * just in case we need to restore them later
1698:
1699: *
1700:
1701: * BUG: this really should be integrated with the init_intr routine
1702:
1703: * in main.c
1704:
1705: */
1706:
1707:
1708:
1709: #define A(x) ((long *)(long)(x))
1710:
1711: #define L(x) (long)(x)
1712:
1713:
1714:
1715: struct vectab {
1716:
1717: long *addr;
1718:
1719: long def_value;
1720:
1721: } VEC[] = {
1722:
1723: {A(0x28), 0}, /* Line A */
1724:
1725: {A(0x2c), 0}, /* Line F */
1726:
1727: {A(0x60), 0}, /* spurious interrupt */
1728:
1729: {A(0x64), 0}, /* level 1 interrupt */
1730:
1731: {A(0x68), 0}, /* level 2 interrupt */
1732:
1733: {A(0x6c), 0}, /* level 3 interrupt */
1734:
1735: {A(0x70), 0}, /* level 4 interrupt */
1736:
1737: {A(0x74), 0}, /* level 5 interrupt */
1738:
1739: {A(0x78), 0}, /* level 6 interrupt */
1740:
1741: {A(0x7c), 0}, /* level 7 interrupt */
1742:
1743: {A(0x100), 0}, /* various MFP interrupts */
1744:
1745: {A(0x104), 0},
1746:
1747: {A(0x108), 0},
1748:
1749: {A(0x10c), 0},
1750:
1751: {A(0x110), 0},
1752:
1753: {A(0x114), 0},
1754:
1755: {A(0x118), 0},
1756:
1757: {A(0x11c), 0},
1758:
1759: {A(0x120), 0},
1760:
1761: {A(0x124), 0},
1762:
1763: {A(0x128), 0},
1764:
1765: {A(0x12c), 0},
1766:
1767: {A(0x130), 0},
1768:
1769: {A(0x134), 0},
1770:
1771: {A(0x138), 0},
1772:
1773: {A(0x13c), 0},
1774:
1775: {A(0x400), 0}, /* etv_timer */
1776:
1777: {A(0x4f6), 0}, /* shell_p */
1778:
1779:
1780:
1781: {A(0), 0} /* special tag indicating end of list */
1782:
1783: };
1784:
1785:
1786:
1787: void
1788:
1789: init_vectors()
1790:
1791: {
1792:
1793: struct vectab *v;
1794:
1795:
1796:
1797: for (v = VEC; v->addr; v++) {
1798:
1799: v->def_value = *(v->addr);
1800:
1801: }
1802:
1803: }
1804:
1805:
1806:
1807: #if 0 /* bad code */
1808:
1809:
1810:
1811: /* unhook a vector; if possible, do this with XBRA, but
1812:
1813: * if that isn't possible force the vector to have the
1814:
1815: * same value it had when MiNT started
1816:
1817: */
1818:
1819:
1820:
1821: static void
1822:
1823: unhook(v, where)
1824:
1825: struct vectab *v;
1826:
1827: long where;
1828:
1829: {
1830:
1831: xbra_vec *xbra;
1832:
1833: long newval;
1834:
1835: int cookie;
1836:
1837:
1838:
1839: /* to check for XBRA, we need access to the memory where the
1840:
1841: * vector is
1842:
1843: */
1844:
1845: cookie = prot_temp(where - 12, 16L, -1);
1846:
1847:
1848:
1849: if (cookie == 0)
1850:
1851: newval = v->def_value;
1852:
1853: else {
1854:
1855: xbra = (xbra_vec *)(where - 12);
1856:
1857: if (xbra->xbra_magic == XBRA_MAGIC) {
1858:
1859: newval = (long)xbra->next;
1860:
1861: } else {
1862:
1863: newval = v->def_value;
1864:
1865: }
1866:
1867: }
1868:
1869: *(v->addr) = newval;
1870:
1871:
1872:
1873: (void)prot_temp(where - 12, 16L, cookie);
1874:
1875: }
1876:
1877: #endif
1878:
1879:
1880:
1881: /*
1882:
1883: * unlink_vectors(start, end): any of the "normal" system vectors
1884:
1885: * pointing into a freed memory region must be reset to their
1886:
1887: * default values, or else we'll get a memory protection violation
1888:
1889: * next time the vector gets called
1890:
1891: */
1892:
1893:
1894:
1895: void
1896:
1897: unlink_vectors(start, end)
1898:
1899: long start, end;
1900:
1901: {
1902:
1903: #if 0 /* this code is hosed somewhere */
1904:
1905:
1906:
1907: struct vectab *v;
1908:
1909: long where, *p;
1910:
1911: int i;
1912:
1913:
1914:
1915: /* first, unhook any VBL handlers */
1916:
1917: i = *((short *)0x454L); /* i = nvbls */
1918:
1919: p = *((long **)0x456L); /* p = _vblqueue */
1920:
1921: while (i-- > 0) {
1922:
1923: where = *p;
1924:
1925: if (where >= start && where < end)
1926:
1927: *p = 0;
1928:
1929: p++;
1930:
1931: }
1932:
1933:
1934:
1935: /* next, unhook various random vectors */
1936:
1937: for (v = VEC; v->addr; v++) {
1938:
1939: where = *(v->addr);
1940:
1941: if (where >= start && where < end) {
1942:
1943: unhook(v, where);
1944:
1945: }
1946:
1947: }
1948:
1.1.1.4 root 1949: #else
1950:
1951: UNUSED(start); UNUSED(end);
1952:
1.1.1.3 root 1953: #endif
1954:
1955: }
1956:
1957:
1.1 root 1958:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.