home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR2 / BIMODAL.ZIP / BIMODAL.C < prev    next >
C/C++ Source or Header  |  1993-08-04  |  7KB  |  252 lines

  1. /*
  2.     bimodal.c:
  3.  
  4.     Example showing how to handle hardware interrupts under DOS/4GW,
  5.     whether the processor happens to be in real mode or protected mode
  6.     at the time of the interrupt.
  7.  
  8.     The program installs both protected-mode and real-mode handlers for
  9.     interrupt 0xC (otherwise known as COM1 or IRQ4) that write either a
  10.     'P' to absolute address 0xB8002 or an 'R' to absolute address 0xB8000.
  11.     Conveniently, these locations are the first two character positions
  12.     in the memory map of a color display, so while the program runs
  13.     (at 9600 baud), you can see who is handling the interrupts as the
  14.     display toggles back and forth between 'P' and 'R'.
  15.  
  16.     Note that an external DPMI host (such as Windows) will reflect real
  17.     mode interrupts to a protected mode handler rather than allowing the
  18.     real mode handler to get them; installing a real mode handler in such
  19.     an environment is not necessary.  However, it doesn't hurt to do so,
  20.     so this program will handle interrupts as quickly as possible
  21.     whether or not a DPMI host exists.
  22.  
  23.     The program is written to the DPMI (INT 31h) standard, so the code
  24.     is the same for both environments.
  25.  
  26.     A mouse attached to COM1 makes a suitable demo (you will have to
  27.     load the mouse driver in order to enable the mouse hardware).
  28.     You can type on the keyboard as you move the mouse around; pressing
  29.     the Esc key ends the program.  You can also transmit data from a
  30.     remote machine at 9600 baud; in this case, you don't need to load
  31.     any drivers before running the program.
  32.  
  33.     Written by Dan Teven, Rational Systems Inc., 3/26/92
  34. */
  35.  
  36. #include <stdio.h>
  37. #include <conio.h>
  38. #include <dos.h>
  39.  
  40. #define    D32RealSeg(P)    ((((DWORD) (P)) >> 4) & 0xFFFF)
  41. #define    D32RealOff(P)    (((DWORD) (P)) & 0xF)
  42.  
  43. typedef unsigned int WORD;
  44. typedef unsigned long DWORD;
  45.  
  46. typedef struct _dpmi_callregs
  47. {
  48.     DWORD edi, esi, ebp, esp;
  49.     DWORD ebx, edx, ecx, eax;
  50.     WORD flags;
  51.     WORD es, ds;
  52.     WORD fs, gs;
  53.     WORD ip, cs;
  54.     WORD sp, ss;
  55. } DPMI_CALLREGS;
  56.  
  57. extern void __interrupt pmhandler (void);
  58. extern void com_init (void);
  59.  
  60. extern void __interrupt __far rmhandler (void);
  61. extern unsigned short __far com_port_low;
  62.  
  63. unsigned char com_id = 1;
  64. unsigned char com_int = 0x0C;
  65. unsigned short com_port = 0x3F8;
  66.  
  67. void *D32DosMemAlloc (DWORD size)
  68.     {
  69.     union REGS r;
  70.  
  71.     r.x.eax = 0x0100;                            /* DPMI allocate DOS memory */
  72.     r.x.ebx = (size + 15) >> 4;            /* Number of paragraphs requested */
  73.     int386 (0x31, &r, &r);
  74.  
  75.     if (r.x.cflag)
  76.         return ((DWORD) 0);                    /* Failed */
  77.     return (void *) ((r.x.eax & 0xFFFF) << 4);
  78.     }
  79.  
  80. void main (int argc, char *argv[])
  81.     {
  82.     union REGS r;
  83.     DPMI_CALLREGS dr;
  84.     struct SREGS sr;
  85.     void *lowp;
  86.     unsigned short __far *alias;
  87.     void far *fh;
  88.     WORD orig_rm_seg;
  89.     WORD orig_rm_off;
  90.     DWORD orig_pm_off;
  91.     WORD orig_pm_sel;
  92.     int c;
  93.     int doprot = 1;
  94.     int doreal = 1;
  95.  
  96.     while (argc-- > 1)
  97.         {
  98.         if (argv[argc][0] != '-')
  99.             {
  100. badarg:
  101.             printf ("Invalid argument '%s'\n", argv[argc]);
  102.             printf ("Valid options are:\n");
  103.             printf ("\t-p    Don't install protected mode handler\n");
  104.             printf ("\t-r    Don't install real mode handler\n");
  105.             printf ("\t-2    Use COM2 instead of COM1 for testing\n");
  106.             exit (1);
  107.             }
  108.  
  109.         switch (argv[argc][1])
  110.             {
  111.             case 'p':
  112.                 {
  113.                 doprot = 0;
  114.                 printf ("Not hooking in protected mode\n");
  115.                 break;
  116.                 }
  117.             case 'r':
  118.                 {
  119.                 doreal = 0;
  120.                 printf ("Not hooking in real mode\n");
  121.                 break;
  122.                 }
  123.             case '2':
  124.                 {
  125.                 com_id = 2;
  126.                 com_int = 0x0B;
  127.                 com_port = 0x2F8;
  128.                 printf ("Using COM2 instead of COM1 for testing\n");
  129.                 break;
  130.                 }
  131.             default:
  132.                 goto badarg;
  133.             }
  134.  
  135.         if (argv[argc][2])
  136.             goto badarg;
  137.         }
  138.  
  139.     /* Save the starting real-mode and protected-mode handler addresses.
  140.     */
  141.     r.x.eax = 0x0204;                            /* DPMI get protected mode vector */
  142.     r.h.bl = com_int;
  143.     int386 (0x31, &r, &r);
  144.     orig_pm_sel = (WORD) r.x.ecx;
  145.     orig_pm_off = r.x.edx;
  146.  
  147.     r.x.eax = 0x0200;                            /* DPMI get real mode vector */
  148.     r.h.bl = com_int;
  149.     int386 (0x31, &r, &r);
  150.     orig_rm_seg = (WORD) r.x.ecx;
  151.     orig_rm_off = (WORD) r.x.edx;
  152.  
  153.     /* Allocate 128 bytes of DOS memory for the real-mode handler,
  154.         which must of course be less than 128 bytes long.  Then copy
  155.         the real-mode handler into that segment.  The com_port value
  156.         is copied at the same time.
  157.     */
  158.     if (! (lowp = D32DosMemAlloc (128)))
  159.         {
  160.         printf ("Couldn't get low memory!\n");
  161.         exit (1);
  162.         }
  163.     alias = &com_port_low;
  164.     fh = (void __far *) &com_port;
  165.     *(alias = MK_FP(FP_SEG(fh), FP_OFF(alias))) = com_port;
  166.     _fmemcpy ((void __far *) lowp, (void __far *) rmhandler, 128);
  167.     fh = (void __far *) pmhandler;
  168.  
  169.     /* Install the new handlers.  The memory touched by the protected mode
  170.         handler needs to be locked, in case we are running under VMM
  171.         or an external DPMI host.
  172.     */
  173.     if (doprot)
  174.         {
  175.         r.x.eax = 0x0205;                            /* DPMI set protected mode vector */
  176.         r.x.ebx = (DWORD) com_int;
  177.         r.x.ecx = (DWORD) FP_SEG(fh);
  178.         r.x.edx = FP_OFF(fh);
  179.         int386 (0x31, &r, &r);
  180.  
  181.         r.x.eax = 0x0600;                            /* DPMI lock linear region */
  182.         r.x.ebx = ((DWORD) pmhandler) >> 16;
  183.         r.x.ecx = ((DWORD) pmhandler) & 0xFFFF;
  184.         r.x.esi = 0;
  185.         r.x.edi = 256;                                /* lock 256 bytes */
  186.         int386 (0x31, &r, &r);
  187.         r.x.eax = 0x0600;
  188.         r.x.ebx = ((DWORD) &com_port) >> 16;
  189.         r.x.ecx = ((DWORD) &com_port) & 0xFFFF;
  190.         r.x.esi = 0;
  191.         r.x.edi = sizeof(WORD);                    /* lock 2 bytes */
  192.         int386 (0x31, &r, &r);
  193.         }
  194.     if (doreal)
  195.         {
  196.         r.x.eax = 0x0201;                            /* DPMI set real mode vector */
  197.         r.x.ebx = (DWORD) com_int;
  198.         r.x.ecx = D32RealSeg(lowp);            /* CX:DX == real mode &handler */
  199.         r.x.edx = D32RealOff(lowp);
  200.         int386 (0x31, &r, &r);
  201.         }
  202.  
  203.     /* Initialize COM port.
  204.     */
  205.     com_init ();
  206.  
  207.     puts ("Move the mouse or transmit data; press ESC to cancel\n");
  208.  
  209.     /* Wait for the ESC key to be pressed.  This loop has a good mix of
  210.         time spent in real mode and protected mode, so the upper left
  211.         hand corner of your color screen will toggle between 'R' and 'P'.
  212.     */
  213.     while (1)
  214.         {
  215.         /* Explicitly go down to real mode to ask if a key is ready.
  216.             (The kbhit() call is simpler to code, but extra transfers to
  217.             real mode may be optimized out by the DOS extender.)
  218.         */
  219.         r.x.eax = 0x300;                        /* DPMI signal real mode interrupt */
  220.         r.x.ebx = 0x16;
  221.         r.x.ecx = 0;
  222.         fh = (void far *) &dr;
  223.         _fmemset (fh, 0, sizeof(DPMI_CALLREGS));
  224.         dr.eax = 0x0100;
  225.         sr.ds = 0;
  226.         sr.es = FP_SEG(fh);
  227.         r.x.edi = FP_OFF(fh);
  228.         int386x (0x31, &r, &r, &sr);
  229.  
  230.         if (! (dr.flags & 0x40))            /* Test zero flag */
  231.             {
  232.             if (((c = getch ()) & 0xff) == 27)
  233.                 break;
  234.             putch (c);
  235.             }
  236.         }
  237.  
  238.     /* Clean up.
  239.     */
  240.     r.x.eax = 0x0201;                            /* DPMI set real mode vector */
  241.     r.x.ebx = (DWORD) com_int;
  242.     r.x.ecx = (DWORD) orig_rm_seg;        /* CX:DX == real mode &handler */
  243.     r.x.edx = (DWORD) orig_rm_off;
  244.     int386 (0x31, &r, &r);
  245.  
  246.     r.x.eax = 0x0205;                            /* DPMI set protected mode vector */
  247.     r.x.ebx = (DWORD) com_int;
  248.     r.x.ecx = (DWORD) orig_pm_sel;
  249.     r.x.edx = orig_pm_off;
  250.     int386 (0x31, &r, &r);
  251.     }
  252.