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