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