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 >
C/C++ Source or Header  |  1987-04-22  |  15KB  |  653 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith. All rights reserved.
  3. */
  4.  
  5. /*
  6.  * BIOS replacement routines
  7.  */
  8.  
  9. #include "mint.h"
  10.  
  11. #define UNDEF 0        /* should match definition in tty.c */
  12.  
  13. /* some key definitions */
  14. #define CTRLALT 0xc
  15. #define DEL 0x53    /* scan code of delete key */
  16. #define UNDO 0x61    /* scan code of undo key */
  17.  
  18. /* BIOS device definitions */
  19. #define CONSDEV 2
  20. #define AUXDEV 1
  21.  
  22. /* BIOS devices 0..MAX_BHANDLE-1 can be redirected to GEMDOS files */
  23. #define MAX_BHANDLE    4
  24.  
  25. /* BIOS redirection maps */
  26. short binput[MAX_BHANDLE] = { -3, -2, -1, -4 };
  27. short boutput[MAX_BHANDLE] = { -3, -2, -1, -5 };
  28.  
  29. /* tty structures for the BIOS devices -- see biosfs.c */
  30. extern struct tty con_tty, aux_tty, midi_tty;
  31.  
  32. extern int tosvers;    /* from main.c */
  33. char *kbshft;        /* set in main.c */
  34.  
  35. /* some BIOS vectors; note that the routines at these vectors may do nasty
  36.  * things to registers!
  37.  */
  38.  
  39. #define RWABS 0x476L
  40. #define MEDIACH 0x47eL
  41. #define GETBPB 0x472L
  42.  
  43. /* these aren't used (yet) */
  44. #define xconin (((long (**) P_((short)))0x53e))
  45. #define xconout (((long (**) P_((short, short)))0x57e))
  46.  
  47. /* structure used to hold i/o buffers */
  48. typedef struct io_rec {
  49.     char *bufaddr;
  50.     short buflen, head, tail, low_water, hi_water;
  51. } IOREC_T;
  52.  
  53. /* variables for monitoring the keyboard */
  54. IOREC_T    *keyrec;        /* keyboard i/o record pointer */
  55. short    kintr = 0;        /* keyboard interrupt pending (see intr.s) */
  56.  
  57. /* Getmpb is not allowed under MiNT */
  58.  
  59. long
  60. getmpb(ptr)
  61.     void *ptr;
  62. {
  63.     DEBUG("failed call to Getmpb");
  64.     return -1;
  65. }
  66.  
  67.  
  68. /*
  69.  * Note that BIOS handles 0 - MAX_BHANDLE now reference file handles;
  70.  * to get the physical devices, go through u:\dev\
  71.  *
  72.  * A note on translation: all of the bco[n]XXX functions have a "u"
  73.  * variant that is actually what the user calls. For example,
  74.  * ubconstat is the function that gets control after the user does
  75.  * a Bconstat. It figures out what device or file handle is
  76.  * appropriate. Typically, it will be a biosfs file handle; a
  77.  * request is sent to biosfs, and biosfs in turn figures out
  78.  * the "real" device and calls bconstat.
  79.  */
  80.  
  81. long
  82. ubconstat(dev)
  83. int dev;
  84. {
  85.     if (dev < MAX_BHANDLE)
  86.         return file_instat(binput[dev]) ? -1 : 0;
  87.     else
  88.         return bconstat(dev);
  89. }
  90.  
  91. long
  92. bconstat(dev)
  93. int dev;
  94. {
  95.     if (dev == CONSDEV) {
  96.         if (checkkeys()) return 0;
  97.         return (keyrec->head != keyrec->tail) ? -1 : 0;
  98.     }
  99.     if (dev == AUXDEV && has_bconmap)
  100.         dev = curproc->bconmap;
  101.  
  102.     return Bconstat(dev);
  103. }
  104.  
  105. /* bconin: input a character */
  106.  
  107. long
  108. ubconin(dev)
  109. int dev;
  110. {
  111.     if (dev < MAX_BHANDLE)
  112.         return file_getchar(binput[dev], RAW);
  113.     else
  114.         return bconin(dev);
  115. }
  116.  
  117. long
  118. bconin(dev)
  119. int dev;
  120. {
  121.     IOREC_T *k;
  122.     long r;
  123.     short h;
  124.  
  125.     if (dev == CONSDEV) {
  126.         k = keyrec;
  127. again:
  128.         while (k->tail == k->head) {
  129.             yield();
  130.         }
  131.  
  132.         if (checkkeys()) goto again;
  133.  
  134.         h = k->head + 4;
  135.         if (h >= k->buflen)
  136.             h = 0;
  137.         r = *((long *)(k->bufaddr + h));
  138.         k->head = h;
  139.         return r;
  140.     }
  141.     else {
  142.         if (dev == AUXDEV && has_bconmap)
  143.             dev = curproc->bconmap;
  144.  
  145.         if (dev > 0)
  146.             while (!Bconstat(dev)) {
  147.                 yield();
  148.             }
  149.     }
  150.  
  151.     r = Bconin(dev);
  152.  
  153.     return r;
  154. }
  155.  
  156. /* bconout: output a character.
  157.  * returns 0 for failure, nonzero for success
  158.  */
  159.  
  160. long
  161. ubconout(dev, c)
  162. int dev, c;
  163. {
  164.     FILEPTR *f;
  165.  
  166.     if (dev < MAX_BHANDLE) {
  167.         f = curproc->handle[boutput[dev]];
  168.         if (!f) return 0;
  169.         if (is_terminal(f)) {
  170.             return tty_putchar(f, ((long)c)&0x00ff, RAW);
  171.         }
  172.     /* note: we're assuming sizeof(int) == 2 here! */
  173.         return (*f->dev->write)(f, ((char *)&c)+1, 1L);
  174.     }
  175.     else if (dev == 5) {
  176.         c &= 0x00ff;
  177.         f = curproc->handle[-1];
  178.         if (!f) return 0;
  179.         if (is_terminal(f)) {
  180.             if (c < ' ') {
  181.             /* MW hack for quoted characters */
  182.                 tty_putchar(f, (long)'\033', RAW);
  183.                 tty_putchar(f, (long)'Q', RAW);
  184.             }
  185.             return tty_putchar(f, ((long)c)&0x00ff, RAW);
  186.         }
  187.     /* note: we're assuming sizeof(int) == 2 here! */
  188.         return (*f->dev->write)(f, ((char *)&c)+1, 1L);
  189.     } else
  190.         return bconout(dev, c);
  191. }
  192.  
  193. long
  194. bconout(dev, c)
  195. int dev,c;
  196. {
  197.     int statdev;
  198.     long endtime;
  199.     extern long searchtime;    /* in dosdir.c; updated once per second */
  200.  
  201.     if (dev == AUXDEV && has_bconmap) {
  202.         dev = curproc->bconmap;
  203.     }
  204.  
  205. /* compensate for a known BIOS bug; MIDI and IKBD are switched */
  206.     if (dev == 3) {        /* MIDI */
  207.         statdev = 4;
  208.     } else if (dev == 4) {
  209.         statdev = 3;
  210.     } else
  211.         statdev = dev;
  212.  
  213. /* provide a 10 second time out */
  214.     endtime = searchtime + 10;
  215.     while (!Bcostat(statdev) && searchtime < endtime) {
  216.         yield();
  217.     }
  218.     if ( searchtime >= endtime && !Bcostat(statdev)) return 0;
  219.  
  220. /* special case: many text accelerators return a bad value from
  221.  * Bconout, so we ignore the returned value for the console
  222.  */
  223.     if (dev != CONSDEV) {
  224. /* NOTE: if your compiler complains about the next line, then Bconout is
  225.  * improperly declared in your osbind.h header file. it should be returning
  226.  * a long value; some libraries incorrectly have Bconout returning void
  227.  * (or cast the returned value to void)
  228.  */
  229.         return Bconout(dev,c);
  230.     } else {
  231.         (void)Bconout(dev, c);
  232.         return 1;
  233.     }
  234. }
  235.  
  236. /* rwabs: various disk stuff */
  237.  
  238. long
  239. rwabs(rwflag, buffer, number, recno, dev, lrecno)
  240. int rwflag, number, recno, dev;
  241. void *buffer;
  242. long lrecno;
  243. {
  244.     long r;
  245.  
  246. /* Note that some (most?) Rwabs device drivers don't bother saving
  247.  * registers, whereas our compiler expects politeness. So we go
  248.  * via callout(), which will save registers for us.
  249.  */
  250.     r = callout(RWABS, rwflag, buffer, number, recno, dev, lrecno);
  251.     return r;
  252. }
  253.  
  254. /* setexc: set exception vector */
  255.  
  256. long
  257. setexc(number, vector)
  258. int number;
  259. long vector;
  260. {
  261.     long *place;
  262.     long old;
  263.     extern long save_dos, save_bios, save_xbios;    /* in main.c */
  264.  
  265.     TRACE("Setexc %d, %lx", number, vector);
  266.     place = (long *)(((long)number) << 2);
  267.     if (number == 0x21)                /* trap_1 */
  268.         old = save_dos;
  269.     else if (number == 0x2d)            /* trap_13 */
  270.         old = save_bios;
  271.     else if (number == 0x2e)            /* trap_14 */
  272.         old = save_xbios;
  273.     else if (number == 0x101)
  274.         old = (long)curproc->criticerr;        /* critical error vector */
  275.     else if (number == 0x102)
  276.         old = curproc->ctxt[SYSCALL].term_vec;    /* GEMDOS term vector */
  277.     else
  278.         old = *place;
  279.  
  280.     if (vector > 0) {
  281.         if (number == 0x21)
  282.             save_dos = vector;
  283.         else if (number == 0x2d)
  284.             save_bios = vector;
  285.         else if (number == 0x2e)
  286.             save_xbios = vector;
  287.         else if (number == 0x102)
  288.             curproc->ctxt[SYSCALL].term_vec = vector;
  289.         else if (number == 0x101) {
  290.             long mintcerr;
  291.  
  292.         /*
  293.          * problem: lots of TSR's look for the Setexc(0x101,...)
  294.           * that the AES does at startup time; so we have
  295.          * to pass it along.
  296.          */
  297.             mintcerr = (long) Setexc(0x101, (void *)vector);
  298.             curproc->criticerr = (long (*) P_((long))) *place;
  299.             *place = mintcerr;
  300.         }
  301.         else {
  302.         /* We would do just *place = vector except that
  303.          * someone else might be intercepting Setexc looking
  304.          * for something in particular...
  305.          */
  306.             old = (long) Setexc(number, (void *)vector);
  307.         }
  308.     }
  309.     return old;
  310. }
  311.  
  312. /* tickcal: return milliseconds per system clock tick */
  313.  
  314. long
  315. tickcal()
  316. {
  317.     return (long) (*( (unsigned *) 0x0442L ));
  318. }
  319.  
  320. /* getbpb: get BIOS parameter block */
  321.  
  322. long
  323. getbpb(dev)
  324. int dev;
  325. {
  326.     long r;
  327.  
  328. /* we can't trust the Getbpb routine to accurately save all registers,
  329.  * so we do it ourselves
  330.  */
  331.     r = callout(GETBPB, dev);
  332. /* 
  333.  * There is a bug in the  TOS  disk handling routines (well several actually).
  334.  * If the directory size of Getbpb() is returned as zero then the drive 'dies'
  335.  * and wont read any new disks even with the 'ESC' enforced disk change . This
  336.  * is present even in TOS 1.6 (not sure about 1.62 though). This small routine
  337.  * changes the dir size to '1' if it is zero . It may make some non-TOS disks
  338.  * look a bit weird but that's better than killing the drive .
  339.  */
  340.     if (r) {
  341.         if ( ((short *)r)[3] == 0)    /* 0 directory size? */
  342.             ((short *)r)[3] = 1;
  343.     }
  344.     return r;
  345. }
  346.  
  347. /* bcostat: return output device status */
  348.  
  349. long
  350. ubcostat(dev)
  351. int dev;
  352. {
  353. /* the BIOS switches MIDI (3) and IKBD (4) (a bug, but it can't be corrected) */
  354.     if (dev == 4) {        /* really the MIDI port */
  355.         return file_outstat(boutput[3]) ? -1 : 0;
  356.     }
  357.     if (dev == 3)
  358.         return Bcostat(dev);
  359.  
  360.     if (dev < MAX_BHANDLE)
  361.         return file_outstat(boutput[dev]) ? -1 : 0;
  362.     else
  363.         return bcostat(dev);
  364. }
  365.  
  366. long
  367. bcostat(dev)
  368. int dev;
  369. {
  370.  
  371.     if (dev == CONSDEV) {
  372.         return -1;
  373.     }
  374.     else if (dev == AUXDEV && has_bconmap) {
  375.         dev = curproc->bconmap;
  376.     }
  377. /* compensate here for the BIOS bug, so that the MIDI and IKBD files work
  378.  * correctly
  379.  */
  380.     else if (dev == 3) dev = 4;
  381.     else if (dev == 4) dev = 3;
  382.  
  383.     return Bcostat(dev);
  384. }
  385.  
  386. /* mediach: check for media change */
  387.  
  388. long
  389. mediach(dev)
  390. int dev;
  391. {
  392.     long r;
  393.  
  394.     r = callout(MEDIACH, dev);
  395.     return r;
  396. }
  397.  
  398. /* drvmap: return drives connected to system */
  399.  
  400. long
  401. drvmap()
  402. {
  403.     return *( (long *)0x4c2L );
  404. }
  405.  
  406. /* kbshift: return (and possibly change) keyboard shift key status */
  407.  
  408. long
  409. kbshift(mode)
  410. int mode;
  411. {
  412.     int oldshft;
  413.  
  414.     oldshft = *((unsigned char *)kbshft);
  415.     if (mode >= 0)
  416.         *kbshft = mode;
  417.     return oldshft;
  418. }
  419.  
  420.  
  421. /* special Bconout buffering code:
  422.  * Because system call overhead is so high, programs that do output
  423.  * with Bconout suffer in performance. To compensate for this,
  424.  * Bconout is special-cased in syscall.s, and if possible characters
  425.  * are placed in the 256 byte bconbuf buffer. This buffer is flushed
  426.  * when any system call other than Bconout happens, or when a context
  427.  * switch occurs.
  428.  */
  429.  
  430. short bconbsiz;            /* number of characters in buffer */
  431. unsigned char bconbuf[256];    /* buffer contents */
  432. short bconbdev;            /* BIOS device for which the buffer is valid */
  433.                 /* (-1 means no buffering is active) */
  434.  
  435. /*
  436.  * flush pending BIOS output. Return 0 if some bytes were not successfully
  437.  * written, non-zero otherwise (just like bconout)
  438.  */
  439.  
  440. long
  441. bflush()        /* flush bios output */
  442. {
  443.     long ret, bsiz;
  444.     unsigned char *s;
  445.     FILEPTR *f;
  446.     short dev;
  447.     short statdev;
  448.  
  449.     if ((dev = bconbdev) < 0) return 0;
  450.  
  451. /*
  452.  * Here we lock the BIOS buffering mechanism by setting bconbdev to -1
  453.  * This is necessary because if two or more programs try to do
  454.  * buffered BIOS output at the same time, they can get seriously
  455.  * mixed up. We unlock by setting bconbdev to 0.
  456.  *
  457.  * NOTE: some code (e.g. in sleep()) checks for bconbsiz != 0 in
  458.  * order to see if we need to do a bflush; if one is already in
  459.  * progress, it's pointless to do this, so we save a bit of
  460.  * time by setting bconbsiz to 0 here.
  461.  */
  462.     bconbdev = -1;
  463.     bsiz = bconbsiz;
  464.     bconbsiz = 0;
  465.  
  466. /* BIOS handles 0..MAX_BHANDLE-1 are aliases for special GEMDOS files */
  467.     if (dev < MAX_BHANDLE || dev == 5) {
  468.         if (dev == 5)
  469.             f = curproc->handle[-1];
  470.         else
  471.             f = curproc->handle[boutput[dev]];
  472.  
  473.         if (!f) {
  474.             bconbdev = 0;
  475.             return 0;
  476.         }
  477.         if (is_terminal(f)) {
  478.             s = bconbuf;
  479.             if (dev == 5) {
  480.                 while (bsiz-- > 0) {
  481.                 if (*s < ' ') {
  482.             /* use ESC-Q to quote control character */
  483.                     (void)tty_putchar(f, (long)'\033',
  484.                                 RAW);
  485.                     (void)tty_putchar(f, (long)'Q',
  486.                                 RAW);
  487.                 }
  488.                 (void) tty_putchar(f, (long)*s++, RAW);
  489.                 }
  490.             } else {
  491.                 while (bsiz-- > 0) {
  492.                 (void) tty_putchar(f, (long)*s++, RAW);
  493.                 }
  494.             }
  495.             ret = -1;
  496.         } else {
  497.             ret = (*f->dev->write)(f, (char *)bconbuf, bsiz);
  498.         }
  499.         bconbdev = 0;
  500.         return ret;
  501.     }
  502.  
  503. /* Otherwise, we have a real BIOS device */
  504.  
  505.     if (dev == AUXDEV && has_bconmap) {
  506.         dev = curproc->bconmap;
  507.         statdev = dev;
  508.     }
  509. /* compensate for a known BIOS bug; MIDI and IKBD are switched */
  510.     else if (dev == 3) {        /* MIDI */
  511.         statdev = 4;
  512.     } else if (dev == 4) {
  513.         statdev = 3;
  514.     } else
  515.         statdev = dev;
  516.         
  517.     s = bconbuf;
  518.     while (bsiz-- > 0) {
  519.         while (!Bcostat(statdev)) yield();
  520.         (void)Bconout(dev,*s);
  521.         s++;
  522.     }
  523.     bconbdev = 0;
  524.     return 1L;
  525. }
  526.  
  527. /* initialize bios table */
  528.  
  529. #define BIOS_MAX 0x20
  530.  
  531. Func bios_tab[BIOS_MAX] = {
  532.     getmpb,
  533.     ubconstat,
  534.     ubconin,
  535.     ubconout,
  536.     rwabs,
  537.     setexc,
  538.     tickcal,
  539.     getbpb,
  540.     ubcostat,
  541.     mediach,
  542.     drvmap,
  543.     kbshift,
  544.     0, 0, 0, 0,
  545.     0, 0, 0, 0, 0, 0, 0, 0,
  546.     0, 0, 0, 0, 0, 0, 0, 0
  547. };
  548.  
  549. short bios_max = BIOS_MAX;
  550.  
  551. /*
  552.  * BIOS initialization routine: gets keyboard buffer pointers, for the
  553.  * interrupt routine below
  554.  */
  555.  
  556. void
  557. init_bios()
  558. {
  559.     keyrec = (IOREC_T *)Iorec(1);
  560. }
  561.  
  562. /*
  563.  * routine for checking keyboard (called by sleep() on any context
  564.  * switch where a keyboard event occured). returns 1 if a special
  565.  * control character was eaten, 0 if not
  566.  */
  567.  
  568. int
  569. checkkeys()
  570. {
  571.     char scan, ch;
  572.     short shift;
  573.     int sig, ret;
  574.     struct tty *tty = &con_tty;
  575.     extern char mshift;        /* for mouse -- see biosfs.c */
  576.     static short oldktail = 0;
  577.  
  578.     ret = 0;
  579.     mshift = kbshift(-1);
  580.     while (oldktail != keyrec->tail) {
  581.  
  582. /* BUG: we really should check the shift status _at the time the key was
  583.  * pressed_, not now!
  584.  */
  585.         sig = 0;
  586.         shift = mshift;
  587.         oldktail += 4;
  588.         if (oldktail >= keyrec->buflen)
  589.             oldktail = 0;
  590.  
  591.         scan = (keyrec->bufaddr + oldktail)[1];
  592. /* function key?? */
  593.         if ( (scan >= 0x3b && scan <= 0x44) ||
  594.              (scan >= 0x54 && scan <= 0x5d) ||
  595.              scan == DEL || scan == UNDO) {
  596.             if ( (shift & CTRLALT) == CTRLALT ) {
  597.                 oldktail = keyrec->head = keyrec->tail;
  598.                 do_func_key(scan);
  599.                 ret = 1;
  600.                 continue;
  601.             }
  602.         }
  603.  
  604. /* check for special control keys, etc. */
  605. /* BUG: this doesn't exactly match TOS' behavior, particularly for
  606.  * ^S/^Q
  607.  */
  608.         if ((tty->state & TS_COOKED) || (shift & CTRLALT) == CTRLALT) {
  609.             ch = (keyrec->bufaddr + keyrec->tail)[3];
  610.             if (ch == UNDEF)
  611.                 ;    /* do nothing */
  612.             else if (ch == tty->tc.t_intrc)
  613.                 sig = SIGINT;
  614.             else if (ch == tty->tc.t_quitc)
  615.                 sig = SIGQUIT;
  616.             else if (ch == tty->ltc.t_suspc)
  617.                 sig = SIGTSTP;
  618.             else if (ch == tty->tc.t_stopc) {
  619.                 tty->state |= TS_HOLD;
  620.                 ret = 1;
  621.                 keyrec->head = oldktail;
  622.                 continue;
  623.             }
  624.             else if (ch == tty->tc.t_startc) {
  625.                 tty->state &= ~TS_HOLD;
  626.                 ret = 1;
  627.                 keyrec->head = oldktail;
  628.                 continue;
  629.             }
  630.             if (sig) {
  631.                 tty->state &= ~TS_HOLD;
  632.                 if (!(tty->sg.sg_flags & T_NOFLSH))
  633.                     oldktail = keyrec->head = keyrec->tail;
  634.                 killgroup(tty->pgrp, sig);
  635.                 ret = 1;
  636.             }
  637.             else if (tty->state & TS_HOLD) {
  638.                 keyrec->head = oldktail;
  639.                 ret = 1;
  640.             }
  641.         }
  642.  
  643.     }
  644.  
  645. /* has someone done select() on the keyboard?? */
  646.     if (tty->rsel && keyrec->head != keyrec->tail)
  647.         wakeselect(tty->rsel);
  648.  
  649.     return ret;
  650. }
  651.  
  652. /* do_func_key moved to debug.c */
  653.