home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 1 / HamRadio.cdr / misc / src0131 / pc.c < prev    next >
C/C++ Source or Header  |  1991-01-31  |  13KB  |  571 lines

  1. /* OS- and machine-dependent stuff for IBM-PC running MS-DOS and Turbo-C
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. #include <stdio.h>
  5. #include <conio.h>
  6. #include <dir.h>
  7. #include <dos.h>
  8. #include <io.h>
  9. #include <sys/stat.h>
  10. #include <string.h>
  11. #include <process.h>
  12. #include <fcntl.h>
  13. #include <alloc.h>
  14. #include <stdarg.h>
  15. #include "global.h"
  16. #include "mbuf.h"
  17. #include "socket.h"
  18. #include "internet.h"
  19. #include "iface.h"
  20. #include "cmdparse.h"
  21. #include "pc.h"
  22. #include "proc.h"
  23. #include "session.h"
  24.  
  25. #define    CTLC    0x3
  26. #define    DEL    0x7f
  27.  
  28. static int kbchar __ARGS((void));
  29. extern int Curdisp;
  30. extern struct proc *Display;
  31. FILE *Rawterm;
  32. unsigned _stklen = 8192;
  33. int Tick;
  34.  
  35. /* This flag is set by setirq() if IRQ 8-15 is used, indicating
  36.  * that the machine is a PC/AT with a second 8259 interrupt controller.
  37.  * If this flag is set, the interrupt return code in pcgen.asm will
  38.  * send an End of Interrupt command to the second 8259 as well as the
  39.  * first.
  40.  */
  41. int Isat;
  42.  
  43. static char Ttbuf[BUFSIZ];
  44. static char Tsbuf[BUFSIZ];
  45. static int saved_break;
  46.  
  47. /* Keyboard input buffer */
  48. #define    KBSIZE    256
  49. static struct {
  50.     char buf[KBSIZE];
  51.     char *wp;
  52.     char *rp;
  53.     int cnt;
  54. } Keyboard;
  55.  
  56. int
  57. errhandler(errval,ax,bp,si)
  58. int errval,ax,bp,si;
  59. {
  60.     return 3;    /* Fail the system call */
  61. }
  62.  
  63. /* Called at startup time to set up console I/O, memory heap */
  64. void
  65. ioinit()
  66. {
  67.     /* Fail all I/O errors */
  68.     harderr(errhandler);
  69.  
  70.     /* Save these two file table entries for something more useful */
  71.     fclose(stdaux);
  72.     fclose(stdprn);
  73.     setbuf(stdout,Tsbuf);
  74.  
  75.     Rawterm = fopen("con","wb");
  76.     setbuf(Rawterm,Ttbuf);
  77.     /* this breaks tab expansion so you must use ANSI or NANSI */
  78.     ioctl(fileno(Rawterm), 1, ioctl(fileno(Rawterm),0) & 0xff | 0x20);
  79.     saved_break = getcbrk();
  80.     setcbrk(0);
  81.  
  82.     /* Link timer handler into timer interrupt chain */
  83.     chtimer(btick);
  84.  
  85.     /* Find out what multitasker we're running under, if any */
  86.     chktasker();
  87.  
  88.     /* Initialize keyboard queue */
  89.     Keyboard.rp = Keyboard.wp = Keyboard.buf;
  90.  
  91. }
  92. /* Called just before exiting to restore console state */
  93. void
  94. iostop()
  95. {
  96.     struct iface *ifp,*iftmp;
  97.     void (**fp)();
  98.  
  99.     setbuf(Rawterm,NULLCHAR);
  100.     ioctl(fileno(Rawterm), 1, ioctl(fileno(Rawterm), 0) & 0xff & ~0x20);
  101.     setcbrk(saved_break);
  102.  
  103.     for(ifp = Ifaces;ifp != NULLIF;ifp = iftmp){
  104.         iftmp = ifp->next;
  105.         if_detach(ifp);
  106.     }
  107.     /* Call list of shutdown functions */
  108.     for(fp = Shutdown;*fp != NULLVFP;fp++){
  109.         (**fp)();
  110.     }    
  111. }
  112. /* Spawn subshell */
  113. int
  114. doshell(argc,argv,p)
  115. int argc;
  116. char *argv[];
  117. void *p;
  118. {
  119.     char *command;
  120.     int ret;
  121.  
  122.     if((command = getenv("COMSPEC")) == NULLCHAR)
  123.         command = "/COMMAND.COM";
  124.     ret = spawnv(P_WAIT,command,argv);
  125.  
  126.     return ret;
  127. }
  128.  
  129. /* Keyboard interrupt handler */
  130. void
  131. kbint()
  132. {
  133.     int sig = 0;
  134.     int c;
  135.  
  136.     while((c = kbraw()) != -1 && Keyboard.cnt < KBSIZE){
  137.         sig = 1;
  138.         *Keyboard.wp++ = c;
  139.         if(Keyboard.wp == &Keyboard.buf[KBSIZE])
  140.             Keyboard.wp = Keyboard.buf;
  141.         Keyboard.cnt++;
  142.     }
  143.     if(sig){
  144.         psignal(&Keyboard,0);
  145.     }
  146. }
  147. static int
  148. kbchar()
  149. {
  150.     char i_state;
  151.     char c;
  152.  
  153.     i_state = dirps();
  154.     while(Keyboard.cnt == 0)
  155.         pwait(&Keyboard);
  156.     Keyboard.cnt--;
  157.     restore(i_state);
  158.     c = *Keyboard.rp++;
  159.     if(Keyboard.rp == &Keyboard.buf[KBSIZE])
  160.         Keyboard.rp = Keyboard.buf;
  161.     return uchar(c);
  162. }
  163. /* Flush the raw terminal output */
  164. void
  165. rflush()
  166. {
  167.     fflush(Rawterm);
  168. }
  169.  
  170. /* Read characters from the keyboard, translating them to "real" ASCII.
  171.  * If none are ready, block. The F-10 key is special; translate it to -2.
  172.  */
  173. int
  174. kbread()
  175. {
  176.     int c;
  177.  
  178.     if((c = kbchar()) == 0){
  179.         /* Lead-in to a special char */
  180.         c = kbchar();
  181.         switch(c){
  182.         case 3:        /* NULL (bizzare!) */
  183.             c = 0;
  184.             break;
  185.         case 68:    /* F-10 key (used as command-mode escape) */
  186.             c = -2;
  187.             break;
  188.         case 83:    /* DEL key */
  189.             c = 0x7f;
  190.             break;
  191.         default:    /* Dunno what it is */
  192.             c = -1;
  193.         }
  194.     }
  195.     return c;
  196. }
  197.  
  198. /* Install hardware interrupt handler.
  199.  * Takes IRQ numbers from 0-7 (0-15 on AT) and maps to actual 8086/286 vectors
  200.  * Note that bus line IRQ2 maps to IRQ9 on the AT
  201.  */
  202. int
  203. setirq(irq,handler)
  204. unsigned irq;
  205. INTERRUPT (*handler)();
  206. {
  207.     /* Set interrupt vector */
  208.     if(irq < 8){
  209.         setvect(8+irq,handler);
  210.     } else if(irq < 16){
  211.         Isat = 1;
  212.         setvect(0x70 + irq - 8,handler);
  213.     } else {
  214.         return -1;
  215.     }
  216.     return 0;
  217. }
  218. /* Return pointer to hardware interrupt handler.
  219.  * Takes IRQ numbers from 0-7 (0-15 on AT) and maps to actual 8086/286 vectors
  220.  */
  221. INTERRUPT
  222. (*getirq(irq))()
  223. unsigned int irq;
  224. {
  225.     /* Set interrupt vector */
  226.     if(irq < 8){
  227.         return getvect(8+irq);
  228.     } else if(irq < 16){
  229.         return getvect(0x70 + irq - 8);
  230.     } else {
  231.         return NULLVIFP;
  232.     }
  233. }
  234. /* Disable hardware interrupt */
  235. int
  236. maskoff(irq)
  237. unsigned irq;
  238. {
  239.     if(irq < 8){
  240.         setbit(0x21,(char)(1<<irq));
  241.     } else if(irq < 16){
  242.         irq -= 8;
  243.         setbit(0xa1,(char)(1<<irq));
  244.     } else {
  245.         return -1;
  246.     }
  247.     return 0;
  248. }
  249. /* Enable hardware interrupt */
  250. int
  251. maskon(irq)
  252. unsigned irq;
  253.  {
  254.     if(irq < 8){
  255.         clrbit(0x21,(char)(1<<irq));
  256.     } else if(irq < 16){
  257.         irq -= 8;
  258.         clrbit(0xa1,(char)(1<<irq));
  259.     } else {
  260.         return -1;
  261.     }
  262.     return 0;
  263. }
  264. /* Return 1 if specified interrupt is enabled, 0 if not, -1 if invalid */
  265. int
  266. getmask(irq)
  267. unsigned irq;
  268. {
  269.     if(irq < 8)
  270.         return (inportb(0x21) & (1 << irq)) ? 0 : 1;
  271.     else if(irq < 16){
  272.         irq -= 8;
  273.         return (inportb(0xa1) & (1 << irq)) ? 0 : 1;
  274.     } else
  275.         return -1;
  276. }
  277. /* Called from assembler stub linked to BIOS interrupt 1C, called on each
  278.  * hardware clock tick. Signal a clock tick to the timer process.
  279.  */
  280. void
  281. ctick()
  282. {
  283.     Tick++;
  284.     Clock++;    /* Keep system time */
  285.     psignal(&Tick,1);
  286. }
  287. /* Set bit(s) in I/O port */
  288. void
  289. setbit(port,bits)
  290. unsigned port;
  291. char bits;
  292. {
  293.     outportb(port,(char)inportb(port)|bits);
  294. }
  295. /* Clear bit(s) in I/O port */
  296. void
  297. clrbit(port,bits)
  298. unsigned port;
  299. char bits;
  300. {
  301.     outportb(port,(char)(inportb(port) & ~bits));
  302. }
  303. /* Convert a pointer to a long integer */
  304. long
  305. ptol(p)
  306. void *p;
  307. {
  308.     long x;
  309.  
  310.     x = FP_OFF(p);
  311. #ifdef    LARGEDATA
  312.     x |= (long)FP_SEG(p) << 16;
  313. #endif
  314.     return x;
  315. }
  316. void *
  317. ltop(l)
  318. long l;
  319. {
  320.     register unsigned seg,offset;
  321.  
  322.     seg = l >> 16;
  323.     offset = l;
  324.     return MK_FP(seg,offset);
  325. }
  326. #ifdef    notdef    /* Assembler versions in pcgen.asm */
  327. /* Multiply a 16-bit multiplier by an arbitrary length multiplicand.
  328.  * Product is left in place of the multiplicand, and the carry is
  329.  * returned
  330.  */
  331. int16
  332. longmul(multiplier,n,multiplicand)
  333. int16 multiplier;
  334. int n;                /* Number of words in multiplicand[] */
  335. register int16 *multiplicand;    /* High word is in multiplicand[0] */
  336. {
  337.     register int i;
  338.     unsigned long pc;
  339.     int16 carry;
  340.  
  341.     carry = 0;
  342.     multiplicand += n;
  343.     for(i=n;i != 0;i--){
  344.         multiplicand--;
  345.         pc = carry + (unsigned long)multiplier * *multiplicand;
  346.         *multiplicand = pc;
  347.         carry = pc >> 16;
  348.     }
  349.     return carry;
  350. }
  351. /* Divide a 16-bit divisor into an arbitrary length dividend using
  352.  * long division. The quotient is returned in place of the dividend,
  353.  * and the function returns the remainder.
  354.  */
  355. int16
  356. longdiv(divisor,n,dividend)
  357. int16 divisor;
  358. int n;                /* Number of words in dividend[] */
  359. register int16 *dividend;    /* High word is in dividend[0] */
  360. {
  361.     /* Before each division, remquot contains the 32-bit dividend for this
  362.      * step, consisting of the 16-bit remainder from the previous division
  363.      * in the high word plus the current 16-bit dividend word in the low
  364.      * word.
  365.      *
  366.      * Immediately after the division, remquot contains the quotient
  367.      * in the low word and the remainder in the high word (which is
  368.      * exactly where we need it for the next division).
  369.      */
  370.     unsigned long remquot;
  371.     register int i;
  372.  
  373.     if(divisor == 0)
  374.         return 0;    /* Avoid divide-by-zero crash */
  375.     remquot = 0;
  376.     for(i=0;i<n;i++,dividend++){
  377.         remquot |= *dividend;
  378.         if(remquot == 0)
  379.             continue;    /* Avoid unnecessary division */
  380. #ifdef    __TURBOC__
  381.         /* Use assembly lang routine that returns both quotient
  382.          * and remainder, avoiding a second costly division
  383.          */
  384.         remquot = divrem(remquot,divisor);
  385.         *dividend = remquot;    /* Extract quotient in low word */
  386.         remquot &= ~0xffffL;    /* ... and mask it off */
  387. #else
  388.         *dividend = remquot / divisor;
  389.         remquot = (remquot % divisor) << 16;
  390. #endif
  391.     }
  392.     return remquot >> 16;
  393. }
  394. #endif
  395. void
  396. sysreset()
  397. {
  398.     void (*foo) __ARGS((void));
  399.  
  400.     foo = MK_FP(0xffff,0);    /* FFFF:0000 is hardware reset vector */
  401.     (*foo)();
  402. }
  403. void
  404. newscreen(sp)
  405. struct session *sp;
  406. {
  407.     if(sp != NULLSESSION)
  408.         sp->screen = callocw(1,sizeof(struct screen));
  409. }
  410. void
  411. freescreen(sp)
  412. struct session *sp;
  413. {
  414.     if(sp == NULLSESSION || sp->screen == NULLSCREEN)
  415.         return;
  416.     if(sp->screen->save != NULLCHAR)
  417.         free(sp->screen->save);
  418.     free((char *)sp->screen);
  419. }
  420.  
  421. /* Save specified session screen and resume console screen */
  422. void
  423. swapscreen(old,new)
  424. struct session *old,*new;
  425. {
  426.     struct text_info tr;
  427.  
  428.     if(old == new)
  429.         return;    /* Nothing to do */
  430.  
  431.     fflush(Rawterm);
  432.     gettextinfo(&tr);
  433.     if(old != NULLSESSION){
  434.         /* Save old screen */
  435.         if(old->screen->save == NULLCHAR)
  436.             old->screen->save
  437.              = malloc(2*tr.screenheight*tr.screenwidth);
  438.         if(old->screen->save != NULLCHAR)
  439.             gettext(tr.winleft,tr.wintop,tr.winright,
  440.              tr.winbottom,old->screen->save);
  441.         old->screen->row = tr.cury;
  442.         old->screen->col = tr.curx;
  443.     }
  444.     if(new != NULLSESSION){
  445.         /* Load new screen */
  446.         if(new->screen->save != NULLCHAR){
  447.             puttext(tr.winleft,tr.wintop,tr.winright,
  448.              tr.winbottom,new->screen->save);
  449.             gotoxy(new->screen->col,new->screen->row);
  450.             /* Free the memory (saves 4K on a continuous basis) */
  451.             free(new->screen->save);
  452.             new->screen->save = NULLCHAR;
  453.         } else
  454.             clrscr();    /* Start with a fresh slate */
  455.     }
  456.     alert(Display,1);    /* Wake him up */
  457. }
  458. void
  459. display(i,v1,v2)
  460. int i;
  461. void *v1;
  462. void *v2;
  463. {
  464.     int c;
  465.     struct session *sp;
  466.  
  467.     /* This is very tricky code. Because the value of "Current" can
  468.      * change any time we do a pwait, we have to be careful to detect
  469.      * any change and go back and start again.
  470.      */
  471.     for(;;){
  472.         sp = Current;
  473.  
  474.         if(sp->morewait){
  475.             pwait(&sp->row);
  476.             if(sp != Current || sp->row <= 0){
  477.                 /* Current changed value, or the user
  478.                  * hasn't really hit a key
  479.                  */
  480.                 continue;
  481.             }
  482.             /* Erase the prompt */
  483.             fprintf(Rawterm,"\r        \r");
  484.         }
  485.         sp->morewait = 0;
  486.         if((c = rrecvchar(sp->output)) == -1){
  487.             /* the alert() in swapscreen will cause this to
  488.              * return -1 when current changes
  489.              */
  490.             pwait(NULL);    /* Prevent a nasty loop */
  491.             continue;
  492.         }
  493.         putc(c,Rawterm);
  494.         if(sp->record != NULLFILE)
  495.             putc(c,sp->record);
  496.         if(sp->flowmode && c == '\n' && --sp->row <= 0){
  497.             fprintf(Rawterm,"--More--");
  498.             sp->morewait = 1;
  499.         }
  500.     }
  501. }
  502. /* Return time since startup in milliseconds. If the system has an
  503.  * 8254 clock chip (standard on ATs and up) then resolution is improved
  504.  * below 55 ms (the clock tick interval) by reading back the instantaneous
  505.  * value of the counter and combining it with the global clock tick counter.
  506.  * Otherwise 55 ms resolution is provided.
  507.  *
  508.  * Reading the 8254 is a bit tricky since a tick could occur asynchronously
  509.  * between the two reads. The tick counter is examined before and after the
  510.  * hardware counter is read. If the tick counter changes, try again.
  511.  * Note: the hardware counter counts down from 65536.
  512.  */
  513. int16 lo;
  514. int32
  515. msclock()
  516. {
  517.     int32 hi;
  518.     int16 lo;
  519.     int16 count[3];    /* extended (48-bit) counter of timer clocks */
  520.  
  521.     if(!Isat)
  522.         return Clock * MSPTICK;
  523.  
  524.     do {
  525.         hi = Clock;
  526.         lo = clockbits();
  527.     } while(((lo & ~0x80) == 0) || hi != Clock); /* Make sure a tick didn't just occur */
  528.     
  529.     hi++;
  530.     count[0] = hi >> 16;
  531.     count[1] = hi;
  532.     count[2] = -lo;
  533.     longmul(11,3,count);    /* The ratio 11/13125 is exact */
  534.     longdiv(13125,3,count);
  535.     return ((long)count[1] << 16) + count[2];
  536. }
  537. /* Return clock in seconds */
  538. int32
  539. secclock()
  540. {
  541.     int32 hi;
  542.     int16 lo;
  543.     int16 count[3];    /* extended (48-bit) counter of timer clocks */
  544.  
  545.     if(!Isat)
  546.         return Clock * MSPTICK / 1000;
  547.  
  548.     do {
  549.         hi = Clock;
  550.         lo = clockbits();
  551.     } while(((lo & ~0x80) == 0) || hi != Clock); /* Make sure a tick didn't just occur */
  552.  
  553.     hi++;
  554.     count[0] = hi >> 16;
  555.     count[1] = hi;
  556.     count[2] = -lo;
  557.     longmul(11,3,count);    /* The ratio 11/13125 is exact */
  558.     longdiv(13125,3,count);
  559.     longdiv(1000,3,count);    /* Convert to seconds */
  560.     return ((long)count[1] << 16) + count[2];
  561. }
  562.  
  563. int
  564. doisat(argc,argv,p)
  565. int argc;
  566. char *argv[];
  567. void *p;
  568. {
  569.     return setbool(&Isat,"AT/386 mode",argc,argv);
  570. }
  571.