home *** CD-ROM | disk | FTP | other *** search
/ Atari FTP / ATARI_FTP_0693.zip / ATARI_FTP_0693 / Mint / mint104s.zoo / mint.src / bios.c < prev    next >
C/C++ Source or Header  |  1993-03-08  |  22KB  |  951 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992,1993 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. /*
  8.  * BIOS replacement routines
  9.  */
  10.  
  11. #include "mint.h"
  12. #include "xbra.h"
  13.  
  14. #define UNDEF 0        /* should match definition in tty.c */
  15.  
  16. /* some key definitions */
  17. #define CTRLALT 0xc
  18. #define DEL 0x53    /* scan code of delete key */
  19. #define UNDO 0x61    /* scan code of undo key */
  20.  
  21. /* BIOS device definitions */
  22. #define CONSDEV 2
  23. #define AUXDEV 1
  24.  
  25. /* BIOS devices 0..MAX_BHANDLE-1 can be redirected to GEMDOS files */
  26. #define MAX_BHANDLE    4
  27.  
  28. /* BIOS redirection maps */
  29. const short binput[MAX_BHANDLE] = { -3, -2, -1, -4 };
  30. const short boutput[MAX_BHANDLE] = { -3, -2, -1, -5 };
  31.  
  32. /* tty structures for the BIOS devices -- see biosfs.c */
  33. extern struct tty con_tty, aux_tty, midi_tty;
  34.  
  35. extern int tosvers;    /* from main.c */
  36. char *kbshft;        /* set in main.c */
  37.  
  38. /* some BIOS vectors; note that the routines at these vectors may do nasty
  39.  * things to registers!
  40.  */
  41.  
  42. #define RWABS *((long *)0x476L)
  43. #define MEDIACH *((long *)0x47eL)
  44. #define GETBPB *((long *)0x472L)
  45.  
  46. #define is_falcon ((mch & 0xffff0000L) == 0x00030000L)
  47.  
  48. #if 1
  49. /* these are supposed to be tables holding the addresses of the
  50.  * first 8 BconXXX functions, but in fact only the first 5 are
  51.  * placed here (and device 5 only has Bconout implemented; 
  52.  * we don't use that device (raw console) anyway).
  53.  */
  54.  
  55. #define xconstat ((long *)0x51eL)
  56. #define xconin     ((long *)0x53eL)
  57. #define xcostat ((long *)0x55eL)
  58. #define xconout    ((long *)0x57eL)
  59.  
  60. #define BCOSTAT(dev) \
  61.     ((tosvers >= 0x0102 && (unsigned)dev <= 4) ? \
  62.        (int)callout1(xcostat[dev], dev) : Bcostat(dev))
  63. #define BCONOUT(dev, c) \
  64.     ((tosvers >= 0x0102 && (unsigned)dev <= 4) ? \
  65.        callout2(xconout[dev], dev, c) : Bconout(dev, c))
  66. #define BCONSTAT(dev) \
  67.     ((tosvers >= 0x0102 && (unsigned)dev <= 4) ? \
  68.        (int)callout1(xconstat[dev], dev) : Bconstat(dev))
  69. #define BCONIN(dev) \
  70.     ((tosvers >= 0x0102 && (unsigned)dev <= 4) ? \
  71.        callout1(xconin[dev], dev) : Bconin(dev))
  72. #else
  73. #define BCOSTAT(dev) Bcostat(dev)
  74. #define BCONOUT(dev,c) Bconout(dev,c)
  75. #define BCONSTAT(dev) Bconstat(dev)
  76. #define BCONIN(dev) Bconin(dev)
  77. #endif
  78.  
  79. /* variables for monitoring the keyboard */
  80. IOREC_T    *keyrec;        /* keyboard i/o record pointer */
  81. short    kintr = 0;        /* keyboard interrupt pending (see intr.s) */
  82.  
  83. /* Getmpb is not allowed under MiNT */
  84.  
  85. long ARGS_ON_STACK
  86. getmpb(ptr)
  87.     void *ptr;
  88. {
  89.     UNUSED(ptr);
  90.  
  91.     DEBUG(("failed call to Getmpb"));
  92.     return -1;
  93. }
  94.  
  95.  
  96. /*
  97.  * Note that BIOS handles 0 - MAX_BHANDLE now reference file handles;
  98.  * to get the physical devices, go through u:\dev\
  99.  *
  100.  * A note on translation: all of the bco[n]XXX functions have a "u"
  101.  * variant that is actually what the user calls. For example,
  102.  * ubconstat is the function that gets control after the user does
  103.  * a Bconstat. It figures out what device or file handle is
  104.  * appropriate. Typically, it will be a biosfs file handle; a
  105.  * request is sent to biosfs, and biosfs in turn figures out
  106.  * the "real" device and calls bconstat.
  107.  */
  108.  
  109. /*
  110.  * WARNING: syscall.spp assumes that ubconstat never blocks.
  111.  */
  112. long ARGS_ON_STACK
  113. ubconstat(dev)
  114. int dev;
  115. {
  116.     if (dev < MAX_BHANDLE) {
  117.         FILEPTR *f = curproc->handle[binput[dev]];
  118.         return file_instat(f) ? -1 : 0;
  119.     }
  120.     else
  121.         return bconstat(dev);
  122. }
  123.  
  124. long
  125. bconstat(dev)
  126. int dev;
  127. {
  128.     if (dev == CONSDEV) {
  129.         if (checkkeys()) return 0;
  130.         return (keyrec->head != keyrec->tail) ? -1 : 0;
  131.     }
  132.     if (dev == AUXDEV && has_bconmap)
  133.         dev = curproc->bconmap;
  134.  
  135. /* compensate for a bug in the Falcon BIOS */
  136.     if (dev == 7 && is_falcon)
  137.         return Bconstat(1);
  138.  
  139.     return BCONSTAT(dev);
  140. }
  141.  
  142. /* bconin: input a character */
  143. /*
  144.  * WARNING: syscall.spp assumes that ubconin never
  145.  * blocks if ubconstat returns non-zero.
  146.  */
  147. long ARGS_ON_STACK
  148. ubconin(dev)
  149. int dev;
  150. {
  151.     if (dev < MAX_BHANDLE) {
  152.         FILEPTR *f = curproc->handle[binput[dev]];
  153.         return file_getchar(f, RAW);
  154.     }
  155.     else
  156.         return bconin(dev);
  157. }
  158.  
  159. long
  160. bconin(dev)
  161. int dev;
  162. {
  163.     IOREC_T *k;
  164.     long r;
  165.     short h;
  166.  
  167.     if (dev == CONSDEV) {
  168.         k = keyrec;
  169. again:
  170.         while (k->tail == k->head) {
  171.             yield();
  172.         }
  173.  
  174.         if (checkkeys()) goto again;
  175.  
  176.         h = k->head + 4;
  177.         if (h >= k->buflen)
  178.             h = 0;
  179.         r = *((long *)(k->bufaddr + h));
  180.         k->head = h;
  181.         return r;
  182.     }
  183.     else {
  184.         if (dev == AUXDEV && has_bconmap)
  185.             dev = curproc->bconmap;
  186.  
  187.         if (dev == 7 && is_falcon) {
  188.             while (!Bconstat(1))
  189.                 yield();
  190.             return Bconin(1);
  191.         }
  192.         if (dev > 0) {
  193.             while (!BCONSTAT(dev)) {
  194.                 yield();
  195.             }
  196.         }
  197.     }
  198.  
  199.     r = BCONIN(dev);
  200.  
  201.     return r;
  202. }
  203.  
  204. /* bconout: output a character.
  205.  * returns 0 for failure, nonzero for success
  206.  */
  207.  
  208. long ARGS_ON_STACK
  209. ubconout(dev, c)
  210. int dev, c;
  211. {
  212.     FILEPTR *f;
  213.     char outp;
  214.  
  215.     if (dev < MAX_BHANDLE) {
  216.         f = curproc->handle[boutput[dev]];
  217.         if (!f) return 0;
  218.         if (is_terminal(f)) {
  219.             return tty_putchar(f, ((long)c)&0x00ff, RAW);
  220.         }
  221.         outp = c;
  222.         return (*f->dev->write)(f, &outp, 1L);
  223.     }
  224.     else if (dev == 5) {
  225.         c &= 0x00ff;
  226.         f = curproc->handle[-1];
  227.         if (!f) return 0;
  228.         if (is_terminal(f)) {
  229.             if (c < ' ') {
  230.             /* MW hack for quoted characters */
  231.                 tty_putchar(f, (long)'\033', RAW);
  232.                 tty_putchar(f, (long)'Q', RAW);
  233.             }
  234.             return tty_putchar(f, ((long)c)&0x00ff, RAW);
  235.         }
  236.     /* note: we're assuming sizeof(int) == 2 here! */
  237.         outp = c;
  238.         return (*f->dev->write)(f, &outp, 1L);
  239.     } else
  240.         return bconout(dev, c);
  241. }
  242.  
  243. long
  244. bconout(dev, c)
  245. int dev,c;
  246. {
  247.     int statdev;
  248.     long endtime;
  249. #define curtime *((unsigned long *)0x4baL)
  250.  
  251.     if (dev == AUXDEV && has_bconmap) {
  252.         dev = curproc->bconmap;
  253.     }
  254.  
  255. /* compensate for a known BIOS bug; MIDI and IKBD are switched */
  256.     if (dev == 3) {        /* MIDI */
  257.         statdev = 4;
  258.     } else if (dev == 4) {
  259.         statdev = 3;
  260.     } else if (dev == 7 && is_falcon) {
  261. /* Falcon BIOS bug */
  262.         (void)Bconout(1,c);
  263.         return 1;
  264.     } else {
  265.         statdev = dev;
  266.     }
  267.  
  268. /* provide a 10 second time out */
  269.     if (!BCOSTAT(statdev)) {
  270.         endtime = curtime + 10*200L;
  271.         do {
  272. #if 0
  273.             yield();
  274. #endif
  275.         } while (!BCOSTAT(statdev) && curtime < endtime);
  276.         if ( curtime >= endtime) return 0;
  277.     }
  278.  
  279. /* special case: many text accelerators return a bad value from
  280.  * Bconout, so we ignore the returned value for the console
  281.  */
  282.     if (dev != CONSDEV) {
  283. /* NOTE: if your compiler complains about the next line, then Bconout is
  284.  * improperly declared in your osbind.h header file. it should be returning
  285.  * a long value; some libraries incorrectly have Bconout returning void
  286.  * (or cast the returned value to void)
  287.  */
  288.         return BCONOUT(dev,c);
  289.     } else {
  290.         (void)BCONOUT(dev, c);
  291.         return 1;
  292.     }
  293. }
  294.  
  295. /* rwabs: various disk stuff */
  296.  
  297. /* BUG: Rwabs should respect Dlock */
  298.  
  299. long ARGS_ON_STACK
  300. rwabs(rwflag, buffer, number, recno, dev, lrecno)
  301. int rwflag, number, recno, dev;
  302. void *buffer;
  303. long lrecno;
  304. {
  305.     long r;
  306.     extern PROC *dlockproc[];    /* in dosdir.c */
  307.  
  308.     if (dev >= 0 && dev < NUM_DRIVES && dlockproc[dev]) {
  309.         if (dlockproc[dev] != curproc) {
  310.             DEBUG(("Rwabs: device %c is locked", dev+'A'));
  311.             return ELOCKED;
  312.         }
  313.     }
  314.  
  315. /* Note that some (most?) Rwabs device drivers don't bother saving
  316.  * registers, whereas our compiler expects politeness. So we go
  317.  * via callout(), which will save registers for us.
  318.  */
  319.     r = callout(RWABS, rwflag, buffer, number, recno, dev, lrecno);
  320.     return r;
  321. }
  322.  
  323. /* setexc: set exception vector */
  324.  
  325. long ARGS_ON_STACK
  326. setexc(number, vector)
  327. int number;
  328. long vector;
  329. {
  330.     long *place;
  331.     long old;
  332.     extern long save_dos, save_bios, save_xbios;    /* in main.c */
  333.     extern int no_mem_prot;                /* in main.c */
  334.  
  335.     place = (long *)(((long)number) << 2);
  336.     if (number == 0x21)                /* trap_1 */
  337.         old = save_dos;
  338.     else if (number == 0x2d)            /* trap_13 */
  339.         old = save_bios;
  340.     else if (number == 0x2e)            /* trap_14 */
  341.         old = save_xbios;
  342.     else if (number == 0x101)
  343.         old = (long)curproc->criticerr;        /* critical error vector */
  344.     else if (number == 0x102)
  345.         old = curproc->ctxt[SYSCALL].term_vec;    /* GEMDOS term vector */
  346.     else
  347.         old = *place;
  348.  
  349.     if (vector > 0) {
  350.     /* validate vector; this will cause a bus error if mem
  351.      * protection is on and the current process doesn't have
  352.      * access to the memory
  353.      */
  354.         if (*((long *)vector) == 0xDEADBEEFL)
  355.             return old;
  356.  
  357.         if (number == 0x21)
  358.             save_dos = vector;
  359.         else if (number == 0x2d)
  360.             save_bios = vector;
  361.         else if (number == 0x2e)
  362.             save_xbios = vector;
  363.         else if (number == 0x102)
  364.             curproc->ctxt[SYSCALL].term_vec = vector;
  365.         else if (number == 0x101) {
  366.             long mintcerr;
  367.  
  368.         /*
  369.          * problem: lots of TSR's look for the Setexc(0x101,...)
  370.           * that the AES does at startup time; so we have
  371.          * to pass it along.
  372.          */
  373.             mintcerr = (long) Setexc(0x101, (void *)vector);
  374.             curproc->criticerr = (long ARGS_ON_STACK (*) P_((long))) *place;
  375.             *place = mintcerr;
  376.         }
  377.         else {
  378.             if (!no_mem_prot) {
  379.             /*
  380.              * if memory protection is on, the vector should be
  381.              * pointing at supervisor or global memory
  382.              */
  383.                 MEMREGION *r;
  384.  
  385.                 r = addr2region(vector);
  386.                 if (r && get_prot_mode(r) == PROT_P) {
  387.                 DEBUG(("Changing protection to Supervisor because of Setexc"));
  388.                 mark_region(r, PROT_S);
  389.                 }
  390.             }
  391.         /* We would do just *place = vector except that
  392.          * someone else might be intercepting Setexc looking
  393.          * for something in particular...
  394.          */
  395.             old = (long) Setexc(number, (void *)vector);
  396.         }
  397.     }
  398.  
  399.     TRACE(("Setexc %d, %lx -> %lx", number, vector, old));
  400.     return old;
  401. }
  402.  
  403. /* tickcal: return milliseconds per system clock tick */
  404.  
  405. long ARGS_ON_STACK
  406. tickcal()
  407. {
  408.     return (long) (*( (unsigned *) 0x0442L ));
  409. }
  410.  
  411. /* getbpb: get BIOS parameter block */
  412.  
  413. long ARGS_ON_STACK
  414. getbpb(dev)
  415. int dev;
  416. {
  417.     long r;
  418.  
  419. /* we can't trust the Getbpb routine to accurately save all registers,
  420.  * so we do it ourselves
  421.  */
  422.     r = callout(GETBPB, dev);
  423. /* 
  424.  * There is a bug in the  TOS  disk handling routines (well several actually).
  425.  * If the directory size of Getbpb() is returned as zero then the drive 'dies'
  426.  * and wont read any new disks even with the 'ESC' enforced disk change . This
  427.  * is present even in TOS 1.6 (not sure about 1.62 though). This small routine
  428.  * changes the dir size to '1' if it is zero . It may make some non-TOS disks
  429.  * look a bit weird but that's better than killing the drive .
  430.  */
  431.     if (r) {
  432.         if ( ((short *)r)[3] == 0)    /* 0 directory size? */
  433.             ((short *)r)[3] = 1;
  434.     }
  435.     return r;
  436. }
  437.  
  438. /* bcostat: return output device status */
  439.  
  440. /* WARNING: syscall.spp assumes that ubcostat never
  441.  * blocks
  442.  */
  443. long ARGS_ON_STACK
  444. ubcostat(dev)
  445. int dev;
  446. {
  447.     FILEPTR *f;
  448.  
  449. /* the BIOS switches MIDI (3) and IKBD (4) (a bug, but it can't be corrected) */
  450.     if (dev == 4) {        /* really the MIDI port */
  451.         f = curproc->handle[boutput[3]];
  452.         return file_outstat(f) ? -1 : 0;
  453.     }
  454.     if (dev == 3)
  455.         return BCOSTAT(dev);
  456.  
  457.     if (dev < MAX_BHANDLE) {
  458.         f = curproc->handle[boutput[dev]];
  459.         return file_outstat(f) ? -1 : 0;
  460.     } else
  461.         return bcostat(dev);
  462. }
  463.  
  464. long
  465. bcostat(dev)
  466. int dev;
  467. {
  468.  
  469.     if (dev == CONSDEV) {
  470.         return -1;
  471.     }
  472.     else if (dev == AUXDEV && has_bconmap) {
  473.         dev = curproc->bconmap;
  474.     }
  475. /* compensate here for the BIOS bug, so that the MIDI and IKBD files work
  476.  * correctly
  477.  */
  478.     else if (dev == 3) dev = 4;
  479.     else if (dev == 4) dev = 3;
  480.  
  481. /* correct for a bug in the Falcon BIOS */
  482.     if (dev == 7 && is_falcon)
  483.         return Bcostat(1);
  484.     return BCOSTAT(dev);
  485. }
  486.  
  487. /* mediach: check for media change */
  488.  
  489. long ARGS_ON_STACK
  490. mediach(dev)
  491. int dev;
  492. {
  493.     long r;
  494.  
  495.     r = callout1(MEDIACH, dev);
  496.     return r;
  497. }
  498.  
  499. /* drvmap: return drives connected to system */
  500.  
  501. long ARGS_ON_STACK
  502. drvmap()
  503. {
  504.     return *( (long *)0x4c2L );
  505. }
  506.  
  507. /* kbshift: return (and possibly change) keyboard shift key status */
  508. /* WARNING: syscall.spp assumes that kbshift never blocks, and never
  509.  * calls any underlying TOS functions
  510.  */
  511. long ARGS_ON_STACK
  512. kbshift(mode)
  513. int mode;
  514. {
  515.     int oldshft;
  516.  
  517.     oldshft = *((unsigned char *)kbshft);
  518.     if (mode >= 0)
  519.         *kbshft = mode;
  520.     return oldshft;
  521. }
  522.  
  523.  
  524. /* special Bconout buffering code:
  525.  * Because system call overhead is so high, programs that do output
  526.  * with Bconout suffer in performance. To compensate for this,
  527.  * Bconout is special-cased in syscall.s, and if possible characters
  528.  * are placed in the 256 byte bconbuf buffer. This buffer is flushed
  529.  * when any system call other than Bconout happens, or when a context
  530.  * switch occurs.
  531.  */
  532.  
  533. short bconbsiz;            /* number of characters in buffer */
  534. unsigned char bconbuf[256];    /* buffer contents */
  535. short bconbdev;            /* BIOS device for which the buffer is valid */
  536.                 /* (-1 means no buffering is active) */
  537.  
  538. /*
  539.  * flush pending BIOS output. Return 0 if some bytes were not successfully
  540.  * written, non-zero otherwise (just like bconout)
  541.  */
  542.  
  543. long ARGS_ON_STACK
  544. bflush()        /* flush bios output */
  545. {
  546.     long ret, bsiz;
  547.     unsigned char *s;
  548.     FILEPTR *f;
  549.     short dev;
  550.     short statdev;
  551.     long lbconbuf[256];
  552.  
  553.     if ((dev = bconbdev) < 0) return 0;
  554.  
  555. /*
  556.  * Here we lock the BIOS buffering mechanism by setting bconbdev to -1
  557.  * This is necessary because if two or more programs try to do
  558.  * buffered BIOS output at the same time, they can get seriously
  559.  * mixed up. We unlock by setting bconbdev to 0.
  560.  *
  561.  * NOTE: some code (e.g. in sleep()) checks for bconbsiz != 0 in
  562.  * order to see if we need to do a bflush; if one is already in
  563.  * progress, it's pointless to do this, so we save a bit of
  564.  * time by setting bconbsiz to 0 here.
  565.  */
  566.     bconbdev = -1;
  567.     bsiz = bconbsiz;
  568.     if (bsiz == 0) return 0;
  569.     bconbsiz = 0;
  570.  
  571. /* BIOS handles 0..MAX_BHANDLE-1 are aliases for special GEMDOS files */
  572.     if (dev < MAX_BHANDLE || dev == 5) {
  573.         if (dev == 5)
  574.             f = curproc->handle[-1];
  575.         else
  576.             f = curproc->handle[boutput[dev]];
  577.  
  578.         if (!f) {
  579.             bconbdev = 0;
  580.             return 0;
  581.         }
  582.         if (is_terminal(f)) {
  583.             s = bconbuf;
  584.             if (dev == 5) {
  585.                 while (bsiz-- > 0) {
  586.                 if (*s < ' ') {
  587.             /* use ESC-Q to quote control character */
  588.                     (void)tty_putchar(f, (long)'\033',
  589.                                 RAW);
  590.                     (void)tty_putchar(f, (long)'Q',
  591.                                 RAW);
  592.                 }
  593.                 (void) tty_putchar(f, (long)*s++, RAW);
  594.                 }
  595.             } else {
  596. #if 1
  597.                 long *where, nbytes;
  598.  
  599. /* the tty_putchar should set up terminal modes correctly */
  600.                 (void) tty_putchar(f, (long)*s++, RAW);
  601.                 where = lbconbuf;
  602.                 nbytes = 0;
  603.                 while (--bsiz > 0) {
  604.                 *where++ = *s++; nbytes+=4;
  605.                 }
  606.                 if (nbytes)
  607.                 (*f->dev->write)(f, (char *)lbconbuf, nbytes);
  608. #else
  609.                 while (bsiz-- > 0) {
  610.                 (void) tty_putchar(f, (long)*s++, RAW);
  611.                 }
  612. #endif
  613.             }
  614.             ret = -1;
  615.         } else {
  616.             ret = (*f->dev->write)(f, (char *)bconbuf, bsiz);
  617.         }
  618.         bconbdev = 0;
  619.         return ret;
  620.     }
  621.  
  622. /* Otherwise, we have a real BIOS device */
  623.  
  624.     if (dev == AUXDEV && has_bconmap) {
  625.         dev = curproc->bconmap;
  626.         statdev = dev;
  627.     }
  628. /* compensate for a known BIOS bug; MIDI and IKBD are switched */
  629.     else if (dev == 3) {        /* MIDI */
  630.         statdev = 4;
  631.     } else if (dev == 4) {
  632.         statdev = 3;
  633.     } else
  634.         statdev = dev;
  635.         
  636.     s = bconbuf;
  637.     while (bsiz-- > 0) {
  638.         while (!BCOSTAT(statdev)) yield();
  639.         (void)BCONOUT(dev,*s);
  640.         s++;
  641.     }
  642.     bconbdev = 0;
  643.     return 1L;
  644. }
  645.  
  646. /* initialize bios table */
  647.  
  648. #define BIOS_MAX 0x20
  649.  
  650. Func bios_tab[BIOS_MAX] = {
  651.     getmpb,
  652.     ubconstat,
  653.     ubconin,
  654.     ubconout,
  655.  
  656.     rwabs,
  657.     setexc,
  658.     tickcal,
  659.     getbpb,
  660.  
  661.     ubcostat,
  662.     mediach,
  663.     drvmap,
  664.     kbshift,
  665.  
  666.     0, 0, 0, 0,
  667.     0, 0, 0, 0, 0, 0, 0, 0,
  668.     0, 0, 0, 0, 0, 0, 0, 0
  669. };
  670.  
  671. short bios_max = BIOS_MAX;
  672.  
  673. /*
  674.  * BIOS initialization routine: gets keyboard buffer pointers, for the
  675.  * interrupt routine below
  676.  */
  677.  
  678. void
  679. init_bios()
  680. {
  681.     keyrec = (IOREC_T *)Iorec(1);
  682. }
  683.  
  684. /*
  685.  * do_bconin: try to do a bconin function quickly, without
  686.  * blocking. If we can't do it without blocking, we return
  687.  * 0x0123dead and the calling trap #13 code falls through
  688.  * to the normal bconin stuff. We can't block here because
  689.  * the trap #13 code hasn't yet saved registers or other
  690.  * context bits, so sleep() wouldn't work properly.
  691.  */
  692.  
  693. #define WOULDBLOCK 0x0123deadL
  694.  
  695. /* WARNING: syscall.spp assumes that do_bconin never blocks */
  696.  
  697. long ARGS_ON_STACK
  698. do_bconin(dev)
  699.     int dev;
  700. {
  701.     FILEPTR *f;
  702.     long r;
  703.     unsigned char c;
  704.  
  705.     if (dev < MAX_BHANDLE) {
  706.         f = curproc->handle[binput[dev]];
  707.         if (!f) return 0;
  708.         r = 0;
  709.         (void)(*f->dev->ioctl)(f, FIONREAD, &r);
  710.         if (!r) return WOULDBLOCK;    /* data not ready */
  711.         if (is_terminal(f))
  712.             r = tty_getchar(f, RAW);
  713.         else {
  714.             r = (*f->dev->read)(f, (char *)&c, 1L);
  715.             r = (r == 1) ? c : MiNTEOF;
  716.         }
  717.     } else {
  718.         if (!bconstat(dev))
  719.             r = WOULDBLOCK;
  720.         else
  721.             r = bconin(dev);
  722.     }
  723.     return r;
  724. }
  725.  
  726. /*
  727.  * routine for checking keyboard (called by sleep() on any context
  728.  * switch where a keyboard event occured). returns 1 if a special
  729.  * control character was eaten, 0 if not
  730.  */
  731.  
  732. int
  733. checkkeys()
  734. {
  735.     char scan, ch;
  736.     short shift;
  737.     int sig, ret;
  738.     struct tty *tty = &con_tty;
  739.     extern char mshift;        /* for mouse -- see biosfs.c */
  740.     static short oldktail = 0;
  741.  
  742.     ret = 0;
  743.     mshift = kbshift(-1);
  744.     while (oldktail != keyrec->tail) {
  745.  
  746. /* BUG: we really should check the shift status _at the time the key was
  747.  * pressed_, not now!
  748.  */
  749.         sig = 0;
  750.         shift = mshift;
  751.         oldktail += 4;
  752.         if (oldktail >= keyrec->buflen)
  753.             oldktail = 0;
  754.  
  755.         scan = (keyrec->bufaddr + oldktail)[1];
  756. /* function key?? */
  757.         if ( (scan >= 0x3b && scan <= 0x44) ||
  758.              (scan >= 0x54 && scan <= 0x5d) ||
  759.              scan == DEL || scan == UNDO) {
  760.             if ( (shift & CTRLALT) == CTRLALT ) {
  761.                 oldktail = keyrec->head = keyrec->tail;
  762.                 do_func_key(scan);
  763.                 /* do_func_key may have read some keys */
  764.                 oldktail = keyrec->head;
  765.                 mshift = kbshift (-1);
  766.                 ret = 1;
  767.                 continue;
  768.             }
  769.         }
  770.  
  771. /* check for special control keys, etc. */
  772. /* BUG: this doesn't exactly match TOS' behavior, particularly for
  773.  * ^S/^Q
  774.  */
  775.         if ((tty->state & TS_COOKED) || (shift & CTRLALT) == CTRLALT) {
  776.             ch = (keyrec->bufaddr + keyrec->tail)[3];
  777.             if (ch == UNDEF)
  778.                 ;    /* do nothing */
  779.             else if (ch == tty->tc.t_intrc)
  780.                 sig = SIGINT;
  781.             else if (ch == tty->tc.t_quitc)
  782.                 sig = SIGQUIT;
  783.             else if (ch == tty->ltc.t_suspc)
  784.                 sig = SIGTSTP;
  785.             else if (ch == tty->tc.t_stopc) {
  786.                 tty->state |= TS_HOLD;
  787.                 ret = 1;
  788.                 keyrec->head = oldktail;
  789.                 continue;
  790.             }
  791.             else if (ch == tty->tc.t_startc) {
  792.                 tty->state &= ~TS_HOLD;
  793.                 ret = 1;
  794.                 keyrec->head = oldktail;
  795.                 continue;
  796.             }
  797.             if (sig) {
  798.                 tty->state &= ~TS_HOLD;
  799.                 if (!(tty->sg.sg_flags & T_NOFLSH))
  800.                     oldktail = keyrec->head = keyrec->tail;
  801.                 killgroup(tty->pgrp, sig);
  802.                 ret = 1;
  803.             }
  804.             else if (tty->state & TS_HOLD) {
  805.                 keyrec->head = oldktail;
  806.                 ret = 1;
  807.             }
  808.         }
  809.  
  810.     }
  811.  
  812. /* has someone done select() on the keyboard?? */
  813.     if (tty->rsel && keyrec->head != keyrec->tail)
  814.         wakeselect(tty->rsel);
  815.  
  816.     return ret;
  817. }
  818.  
  819.  
  820. /*
  821.  * special vector stuff: we try to save as many vectors as possible,
  822.  * just in case we need to restore them later
  823.  *
  824.  * BUG: this really should be integrated with the init_intr routine
  825.  * in main.c
  826.  */
  827.  
  828. #define A(x) ((long *)(long)(x))
  829. #define L(x) (long)(x)
  830.  
  831. struct vectab {
  832.     long *addr;
  833.     long def_value;
  834. } VEC[] = {
  835. {A(0x28), 0},    /* Line A */
  836. {A(0x2c), 0},    /* Line F */
  837. {A(0x60), 0},    /* spurious interrupt */
  838. {A(0x64), 0},      /* level 1 interrupt */
  839. {A(0x68), 0},    /* level 2 interrupt */
  840. {A(0x6c), 0},    /* level 3 interrupt */
  841. {A(0x70), 0},    /* level 4 interrupt */
  842. {A(0x74), 0},    /* level 5 interrupt */
  843. {A(0x78), 0},    /* level 6 interrupt */
  844. {A(0x7c), 0},    /* level 7 interrupt */
  845. {A(0x100), 0},    /* various MFP interrupts */
  846. {A(0x104), 0},
  847. {A(0x108), 0},
  848. {A(0x10c), 0},
  849. {A(0x110), 0},
  850. {A(0x114), 0},
  851. {A(0x118), 0},
  852. {A(0x11c), 0},
  853. {A(0x120), 0},
  854. {A(0x124), 0},
  855. {A(0x128), 0},
  856. {A(0x12c), 0},
  857. {A(0x130), 0},
  858. {A(0x134), 0},
  859. {A(0x138), 0},
  860. {A(0x13c), 0},
  861. {A(0x400), 0},    /* etv_timer */
  862. {A(0x4f6), 0},  /* shell_p */
  863.  
  864. {A(0), 0}    /* special tag indicating end of list */
  865. };
  866.  
  867. void
  868. init_vectors() 
  869. {
  870.     struct vectab *v;
  871.  
  872.     for (v = VEC; v->addr; v++) {
  873.         v->def_value = *(v->addr);
  874.     } 
  875. }
  876.  
  877. #if 0    /* bad code */
  878.  
  879. /* unhook a vector; if possible, do this with XBRA, but
  880.  * if that isn't possible force the vector to have the
  881.  * same value it had when MiNT started
  882.  */
  883.  
  884. static void
  885. unhook(v, where)
  886.     struct vectab *v;
  887.     long where;
  888. {
  889.     xbra_vec *xbra;
  890.     long newval;
  891.     int cookie;
  892.  
  893. /* to check for XBRA, we need access to the memory where the
  894.  * vector is
  895.  */
  896.     cookie = prot_temp(where - 12, 16L, -1);
  897.  
  898.     if (cookie == 0)
  899.         newval = v->def_value;
  900.     else {
  901.         xbra = (xbra_vec *)(where - 12);
  902.         if (xbra->xbra_magic == XBRA_MAGIC) {
  903.             newval = (long)xbra->next;
  904.         } else {
  905.             newval = v->def_value;
  906.         }
  907.     }
  908.     *(v->addr) = newval;
  909.  
  910.     (void)prot_temp(where - 12, 16L, cookie);
  911. }
  912. #endif
  913.  
  914. /*
  915.  * unlink_vectors(start, end): any of the "normal" system vectors
  916.  * pointing into a freed memory region must be reset to their
  917.  * default values, or else we'll get a memory protection violation
  918.  * next time the vector gets called
  919.  */
  920.  
  921. void
  922. unlink_vectors(start, end)
  923.     long start, end;
  924. {
  925. #if 0    /* this code is hosed somewhere */
  926.  
  927.     struct vectab *v;
  928.     long where, *p;
  929.     int i;
  930.  
  931. /* first, unhook any VBL handlers */
  932.     i = *((short *)0x454L);    /* i = nvbls */
  933.     p = *((long **)0x456L);    /* p = _vblqueue */
  934.     while (i-- > 0) {
  935.         where = *p;
  936.         if (where >= start && where < end)
  937.             *p = 0;
  938.         p++;
  939.     }
  940.  
  941. /* next, unhook various random vectors */
  942.     for (v = VEC; v->addr; v++) {
  943.         where = *(v->addr);
  944.         if (where >= start && where < end) {
  945.             unhook(v, where);
  946.         }
  947.     }
  948. #endif
  949. }
  950.  
  951.