home *** CD-ROM | disk | FTP | other *** search
- /*
- Copyright 1990,1991,1992 Eric R. Smith. All rights reserved.
- */
-
- /*
- * BIOS replacement routines
- */
-
- #include "mint.h"
-
- #define UNDEF 0 /* should match definition in tty.c */
-
- /* some key definitions */
- #define CTRLALT 0xc
- #define DEL 0x53 /* scan code of delete key */
- #define UNDO 0x61 /* scan code of undo key */
-
- /* BIOS device definitions */
- #define CONSDEV 2
- #define AUXDEV 1
-
- /* BIOS devices 0..MAX_BHANDLE-1 can be redirected to GEMDOS files */
- #define MAX_BHANDLE 4
-
- /* BIOS redirection maps */
- short binput[MAX_BHANDLE] = { -3, -2, -1, -4 };
- short boutput[MAX_BHANDLE] = { -3, -2, -1, -5 };
-
- /* tty structures for the BIOS devices -- see biosfs.c */
- extern struct tty con_tty, aux_tty, midi_tty;
-
- extern int tosvers; /* from main.c */
- char *kbshft; /* set in main.c */
-
- /* some BIOS vectors; note that the routines at these vectors may do nasty
- * things to registers!
- */
-
- #define RWABS 0x476L
- #define MEDIACH 0x47eL
- #define GETBPB 0x472L
-
- /* these aren't used (yet) */
- #define xconin (((long (**) P_((short)))0x53e))
- #define xconout (((long (**) P_((short, short)))0x57e))
-
- /* structure used to hold i/o buffers */
- typedef struct io_rec {
- char *bufaddr;
- short buflen, head, tail, low_water, hi_water;
- } IOREC_T;
-
- /* variables for monitoring the keyboard */
- IOREC_T *keyrec; /* keyboard i/o record pointer */
- short kintr = 0; /* keyboard interrupt pending (see intr.s) */
-
- /* Getmpb is not allowed under MiNT */
-
- long
- getmpb(ptr)
- void *ptr;
- {
- DEBUG("failed call to Getmpb");
- return -1;
- }
-
-
- /*
- * Note that BIOS handles 0 - MAX_BHANDLE now reference file handles;
- * to get the physical devices, go through u:\dev\
- *
- * A note on translation: all of the bco[n]XXX functions have a "u"
- * variant that is actually what the user calls. For example,
- * ubconstat is the function that gets control after the user does
- * a Bconstat. It figures out what device or file handle is
- * appropriate. Typically, it will be a biosfs file handle; a
- * request is sent to biosfs, and biosfs in turn figures out
- * the "real" device and calls bconstat.
- */
-
- long
- ubconstat(dev)
- int dev;
- {
- if (dev < MAX_BHANDLE)
- return file_instat(binput[dev]) ? -1 : 0;
- else
- return bconstat(dev);
- }
-
- long
- bconstat(dev)
- int dev;
- {
- if (dev == CONSDEV) {
- if (checkkeys()) return 0;
- return (keyrec->head != keyrec->tail) ? -1 : 0;
- }
- if (dev == AUXDEV && has_bconmap)
- dev = curproc->bconmap;
-
- return Bconstat(dev);
- }
-
- /* bconin: input a character */
-
- long
- ubconin(dev)
- int dev;
- {
- if (dev < MAX_BHANDLE)
- return file_getchar(binput[dev], RAW);
- else
- return bconin(dev);
- }
-
- long
- bconin(dev)
- int dev;
- {
- IOREC_T *k;
- long r;
- short h;
-
- if (dev == CONSDEV) {
- k = keyrec;
- again:
- while (k->tail == k->head) {
- yield();
- }
-
- if (checkkeys()) goto again;
-
- h = k->head + 4;
- if (h >= k->buflen)
- h = 0;
- r = *((long *)(k->bufaddr + h));
- k->head = h;
- return r;
- }
- else {
- if (dev == AUXDEV && has_bconmap)
- dev = curproc->bconmap;
-
- if (dev > 0)
- while (!Bconstat(dev)) {
- yield();
- }
- }
-
- r = Bconin(dev);
-
- return r;
- }
-
- /* bconout: output a character.
- * returns 0 for failure, nonzero for success
- */
-
- long
- ubconout(dev, c)
- int dev, c;
- {
- FILEPTR *f;
-
- if (dev < MAX_BHANDLE) {
- f = curproc->handle[boutput[dev]];
- if (!f) return 0;
- if (is_terminal(f)) {
- return tty_putchar(f, ((long)c)&0x00ff, RAW);
- }
- /* note: we're assuming sizeof(int) == 2 here! */
- return (*f->dev->write)(f, ((char *)&c)+1, 1L);
- }
- else if (dev == 5) {
- c &= 0x00ff;
- f = curproc->handle[-1];
- if (!f) return 0;
- if (is_terminal(f)) {
- if (c < ' ') {
- /* MW hack for quoted characters */
- tty_putchar(f, (long)'\033', RAW);
- tty_putchar(f, (long)'Q', RAW);
- }
- return tty_putchar(f, ((long)c)&0x00ff, RAW);
- }
- /* note: we're assuming sizeof(int) == 2 here! */
- return (*f->dev->write)(f, ((char *)&c)+1, 1L);
- } else
- return bconout(dev, c);
- }
-
- long
- bconout(dev, c)
- int dev,c;
- {
- int statdev;
- long endtime;
- extern long searchtime; /* in dosdir.c; updated once per second */
-
- if (dev == AUXDEV && has_bconmap) {
- dev = curproc->bconmap;
- }
-
- /* compensate for a known BIOS bug; MIDI and IKBD are switched */
- if (dev == 3) { /* MIDI */
- statdev = 4;
- } else if (dev == 4) {
- statdev = 3;
- } else
- statdev = dev;
-
- /* provide a 10 second time out */
- endtime = searchtime + 10;
- while (!Bcostat(statdev) && searchtime < endtime) {
- yield();
- }
- if ( searchtime >= endtime && !Bcostat(statdev)) return 0;
-
- /* special case: many text accelerators return a bad value from
- * Bconout, so we ignore the returned value for the console
- */
- if (dev != CONSDEV) {
- /* NOTE: if your compiler complains about the next line, then Bconout is
- * improperly declared in your osbind.h header file. it should be returning
- * a long value; some libraries incorrectly have Bconout returning void
- * (or cast the returned value to void)
- */
- return Bconout(dev,c);
- } else {
- (void)Bconout(dev, c);
- return 1;
- }
- }
-
- /* rwabs: various disk stuff */
-
- long
- rwabs(rwflag, buffer, number, recno, dev, lrecno)
- int rwflag, number, recno, dev;
- void *buffer;
- long lrecno;
- {
- long r;
-
- /* Note that some (most?) Rwabs device drivers don't bother saving
- * registers, whereas our compiler expects politeness. So we go
- * via callout(), which will save registers for us.
- */
- r = callout(RWABS, rwflag, buffer, number, recno, dev, lrecno);
- return r;
- }
-
- /* setexc: set exception vector */
-
- long
- setexc(number, vector)
- int number;
- long vector;
- {
- long *place;
- long old;
- extern long save_dos, save_bios, save_xbios; /* in main.c */
-
- TRACE("Setexc %d, %lx", number, vector);
- place = (long *)(((long)number) << 2);
- if (number == 0x21) /* trap_1 */
- old = save_dos;
- else if (number == 0x2d) /* trap_13 */
- old = save_bios;
- else if (number == 0x2e) /* trap_14 */
- old = save_xbios;
- else if (number == 0x101)
- old = (long)curproc->criticerr; /* critical error vector */
- else if (number == 0x102)
- old = curproc->ctxt[SYSCALL].term_vec; /* GEMDOS term vector */
- else
- old = *place;
-
- if (vector > 0) {
- if (number == 0x21)
- save_dos = vector;
- else if (number == 0x2d)
- save_bios = vector;
- else if (number == 0x2e)
- save_xbios = vector;
- else if (number == 0x102)
- curproc->ctxt[SYSCALL].term_vec = vector;
- else if (number == 0x101) {
- long mintcerr;
-
- /*
- * problem: lots of TSR's look for the Setexc(0x101,...)
- * that the AES does at startup time; so we have
- * to pass it along.
- */
- mintcerr = (long) Setexc(0x101, (void *)vector);
- curproc->criticerr = (long (*) P_((long))) *place;
- *place = mintcerr;
- }
- else {
- /* We would do just *place = vector except that
- * someone else might be intercepting Setexc looking
- * for something in particular...
- */
- old = (long) Setexc(number, (void *)vector);
- }
- }
- return old;
- }
-
- /* tickcal: return milliseconds per system clock tick */
-
- long
- tickcal()
- {
- return (long) (*( (unsigned *) 0x0442L ));
- }
-
- /* getbpb: get BIOS parameter block */
-
- long
- getbpb(dev)
- int dev;
- {
- long r;
-
- /* we can't trust the Getbpb routine to accurately save all registers,
- * so we do it ourselves
- */
- r = callout(GETBPB, dev);
- /*
- * There is a bug in the TOS disk handling routines (well several actually).
- * If the directory size of Getbpb() is returned as zero then the drive 'dies'
- * and wont read any new disks even with the 'ESC' enforced disk change . This
- * is present even in TOS 1.6 (not sure about 1.62 though). This small routine
- * changes the dir size to '1' if it is zero . It may make some non-TOS disks
- * look a bit weird but that's better than killing the drive .
- */
- if (r) {
- if ( ((short *)r)[3] == 0) /* 0 directory size? */
- ((short *)r)[3] = 1;
- }
- return r;
- }
-
- /* bcostat: return output device status */
-
- long
- ubcostat(dev)
- int dev;
- {
- /* the BIOS switches MIDI (3) and IKBD (4) (a bug, but it can't be corrected) */
- if (dev == 4) { /* really the MIDI port */
- return file_outstat(boutput[3]) ? -1 : 0;
- }
- if (dev == 3)
- return Bcostat(dev);
-
- if (dev < MAX_BHANDLE)
- return file_outstat(boutput[dev]) ? -1 : 0;
- else
- return bcostat(dev);
- }
-
- long
- bcostat(dev)
- int dev;
- {
-
- if (dev == CONSDEV) {
- return -1;
- }
- else if (dev == AUXDEV && has_bconmap) {
- dev = curproc->bconmap;
- }
- /* compensate here for the BIOS bug, so that the MIDI and IKBD files work
- * correctly
- */
- else if (dev == 3) dev = 4;
- else if (dev == 4) dev = 3;
-
- return Bcostat(dev);
- }
-
- /* mediach: check for media change */
-
- long
- mediach(dev)
- int dev;
- {
- long r;
-
- r = callout(MEDIACH, dev);
- return r;
- }
-
- /* drvmap: return drives connected to system */
-
- long
- drvmap()
- {
- return *( (long *)0x4c2L );
- }
-
- /* kbshift: return (and possibly change) keyboard shift key status */
-
- long
- kbshift(mode)
- int mode;
- {
- int oldshft;
-
- oldshft = *((unsigned char *)kbshft);
- if (mode >= 0)
- *kbshft = mode;
- return oldshft;
- }
-
-
- /* special Bconout buffering code:
- * Because system call overhead is so high, programs that do output
- * with Bconout suffer in performance. To compensate for this,
- * Bconout is special-cased in syscall.s, and if possible characters
- * are placed in the 256 byte bconbuf buffer. This buffer is flushed
- * when any system call other than Bconout happens, or when a context
- * switch occurs.
- */
-
- short bconbsiz; /* number of characters in buffer */
- unsigned char bconbuf[256]; /* buffer contents */
- short bconbdev; /* BIOS device for which the buffer is valid */
- /* (-1 means no buffering is active) */
-
- /*
- * flush pending BIOS output. Return 0 if some bytes were not successfully
- * written, non-zero otherwise (just like bconout)
- */
-
- long
- bflush() /* flush bios output */
- {
- long ret, bsiz;
- unsigned char *s;
- FILEPTR *f;
- short dev;
- short statdev;
-
- if ((dev = bconbdev) < 0) return 0;
-
- /*
- * Here we lock the BIOS buffering mechanism by setting bconbdev to -1
- * This is necessary because if two or more programs try to do
- * buffered BIOS output at the same time, they can get seriously
- * mixed up. We unlock by setting bconbdev to 0.
- *
- * NOTE: some code (e.g. in sleep()) checks for bconbsiz != 0 in
- * order to see if we need to do a bflush; if one is already in
- * progress, it's pointless to do this, so we save a bit of
- * time by setting bconbsiz to 0 here.
- */
- bconbdev = -1;
- bsiz = bconbsiz;
- bconbsiz = 0;
-
- /* BIOS handles 0..MAX_BHANDLE-1 are aliases for special GEMDOS files */
- if (dev < MAX_BHANDLE || dev == 5) {
- if (dev == 5)
- f = curproc->handle[-1];
- else
- f = curproc->handle[boutput[dev]];
-
- if (!f) {
- bconbdev = 0;
- return 0;
- }
- if (is_terminal(f)) {
- s = bconbuf;
- if (dev == 5) {
- while (bsiz-- > 0) {
- if (*s < ' ') {
- /* use ESC-Q to quote control character */
- (void)tty_putchar(f, (long)'\033',
- RAW);
- (void)tty_putchar(f, (long)'Q',
- RAW);
- }
- (void) tty_putchar(f, (long)*s++, RAW);
- }
- } else {
- while (bsiz-- > 0) {
- (void) tty_putchar(f, (long)*s++, RAW);
- }
- }
- ret = -1;
- } else {
- ret = (*f->dev->write)(f, (char *)bconbuf, bsiz);
- }
- bconbdev = 0;
- return ret;
- }
-
- /* Otherwise, we have a real BIOS device */
-
- if (dev == AUXDEV && has_bconmap) {
- dev = curproc->bconmap;
- statdev = dev;
- }
- /* compensate for a known BIOS bug; MIDI and IKBD are switched */
- else if (dev == 3) { /* MIDI */
- statdev = 4;
- } else if (dev == 4) {
- statdev = 3;
- } else
- statdev = dev;
-
- s = bconbuf;
- while (bsiz-- > 0) {
- while (!Bcostat(statdev)) yield();
- (void)Bconout(dev,*s);
- s++;
- }
- bconbdev = 0;
- return 1L;
- }
-
- /* initialize bios table */
-
- #define BIOS_MAX 0x20
-
- Func bios_tab[BIOS_MAX] = {
- getmpb,
- ubconstat,
- ubconin,
- ubconout,
- rwabs,
- setexc,
- tickcal,
- getbpb,
- ubcostat,
- mediach,
- drvmap,
- kbshift,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0
- };
-
- short bios_max = BIOS_MAX;
-
- /*
- * BIOS initialization routine: gets keyboard buffer pointers, for the
- * interrupt routine below
- */
-
- void
- init_bios()
- {
- keyrec = (IOREC_T *)Iorec(1);
- }
-
- /*
- * routine for checking keyboard (called by sleep() on any context
- * switch where a keyboard event occured). returns 1 if a special
- * control character was eaten, 0 if not
- */
-
- int
- checkkeys()
- {
- char scan, ch;
- short shift;
- int sig, ret;
- struct tty *tty = &con_tty;
- extern char mshift; /* for mouse -- see biosfs.c */
- static short oldktail = 0;
-
- ret = 0;
- mshift = kbshift(-1);
- while (oldktail != keyrec->tail) {
-
- /* BUG: we really should check the shift status _at the time the key was
- * pressed_, not now!
- */
- sig = 0;
- shift = mshift;
- oldktail += 4;
- if (oldktail >= keyrec->buflen)
- oldktail = 0;
-
- scan = (keyrec->bufaddr + oldktail)[1];
- /* function key?? */
- if ( (scan >= 0x3b && scan <= 0x44) ||
- (scan >= 0x54 && scan <= 0x5d) ||
- scan == DEL || scan == UNDO) {
- if ( (shift & CTRLALT) == CTRLALT ) {
- oldktail = keyrec->head = keyrec->tail;
- do_func_key(scan);
- ret = 1;
- continue;
- }
- }
-
- /* check for special control keys, etc. */
- /* BUG: this doesn't exactly match TOS' behavior, particularly for
- * ^S/^Q
- */
- if ((tty->state & TS_COOKED) || (shift & CTRLALT) == CTRLALT) {
- ch = (keyrec->bufaddr + keyrec->tail)[3];
- if (ch == UNDEF)
- ; /* do nothing */
- else if (ch == tty->tc.t_intrc)
- sig = SIGINT;
- else if (ch == tty->tc.t_quitc)
- sig = SIGQUIT;
- else if (ch == tty->ltc.t_suspc)
- sig = SIGTSTP;
- else if (ch == tty->tc.t_stopc) {
- tty->state |= TS_HOLD;
- ret = 1;
- keyrec->head = oldktail;
- continue;
- }
- else if (ch == tty->tc.t_startc) {
- tty->state &= ~TS_HOLD;
- ret = 1;
- keyrec->head = oldktail;
- continue;
- }
- if (sig) {
- tty->state &= ~TS_HOLD;
- if (!(tty->sg.sg_flags & T_NOFLSH))
- oldktail = keyrec->head = keyrec->tail;
- killgroup(tty->pgrp, sig);
- ret = 1;
- }
- else if (tty->state & TS_HOLD) {
- keyrec->head = oldktail;
- ret = 1;
- }
- }
-
- }
-
- /* has someone done select() on the keyboard?? */
- if (tty->rsel && keyrec->head != keyrec->tail)
- wakeselect(tty->rsel);
-
- return ret;
- }
-
- /* do_func_key moved to debug.c */
-