home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
No Fragments Archive 10: Diskmags
/
nf_archive_10.iso
/
MAGS
/
PURE_B
/
PBMAG22A.MSA
/
MINT095S.ZIP
/
SRC
/
BIOS.C
< prev
next >
Wrap
C/C++ Source or Header
|
1987-04-22
|
15KB
|
653 lines
/*
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 */