home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ddrivers.zip / MMAP / MMAP.C < prev    next >
C/C++ Source or Header  |  1993-04-09  |  18KB  |  500 lines

  1. //   OS/2 Device Driver for memory mapped I/O
  2. //
  3. //                Steve Mastrianni
  4. //                15 Great Oak Lane
  5. //                Unionville, CT 06085
  6. //                (203) 693-0404 voice
  7. //                (203) 693-9042 data
  8. //                CI$ 71501,1652
  9. //                BIX smastrianni
  10. //                Internet 6099225@mcimail.com
  11. //
  12. //   This driver is loaded in the config.sys file with the DEVICE=
  13. //   statement. For ISA configuration, the first parameter to the "DEVICE="
  14. //   is the board base memory address in hex.
  15. //
  16. //   This driver also returns a boolean to the calling application to
  17. //   inform it of the bus type (Micro Channel or ISA).
  18. //
  19. //   All numbers are in hex. For MCA configuration, the board address 
  20. //   is read from the board POS regs. The POS regs data is specific for
  21. //   each adapter, so the address calculations here may not work with 
  22. //   your specific adapter. Refer to the hardware tech reference for the
  23. //   particular adapter to determine where and how the address appears
  24. //   in the POS registers.
  25. //
  26. //
  27. //   This driver allows the application I/O to run in Ring 2 with IOPL.
  28. //   The CONFIG.SYS files *must* contain the IOPL=YES statement.
  29. //
  30. //   This driver supports 4 IOCtls, Category 0x90.
  31. //
  32. //   IOCtl 0x01 test for MCA or ISA bus
  33. //   IOCtl 0x02 gets and returns a selector to fabricated board memory
  34. //   IOCtl 0x03 gets the value of a selected POS register
  35. //   IOCtl 0x04 gets the board address that the driver found
  36. //
  37. //   The driver is made by using the make file mmap.mak.
  38.  
  39. #include "drvlib.h" 
  40. #include "mmap.h"
  41.  
  42. extern void near STRATEGY();        // name of strat rout. in DDSTART      
  43.  
  44. DEVICEHDR devhdr = {
  45.         (void far *) 0xFFFFFFFF,    // link                                 
  46.         (DAW_CHR | DAW_OPN | DAW_LEVEL1),// attribute                      
  47.         (OFF) STRATEGY,             // &strategy                        
  48.         (OFF) 0,                    // &IDCroutine                        
  49.         "MMAP$   "
  50. };
  51.  
  52. FPFUNCTION  DevHlp=0;               // storage area for DevHlp calls       
  53. LHANDLE     lock_seg_han;           // handle for locking appl. segment    
  54. PHYSADDR    appl_buffer=0;          // address of caller's buffer          
  55. PREQPACKET  p=0L;                   // pointer to request packet           
  56. ERRCODE     err=0;                  // error return                        
  57. void        far *ptr;               // temp far pointer                    
  58. USHORT      i,j;                    // general counters                    
  59. PHYSADDR    board_address;          // base board address                  
  60. USHORT      opencount;              // count of DosOpens                   
  61. USHORT      savepid;                // save the caller's PID               
  62. USHORT      cntr = 0;               // misc counter                        
  63. USHORT      bus = 0;                // default ISA bus                     
  64. REQBLK      ABIOS_r_blk;            // ABIOS request block                 
  65. LIDBLK      ABIOS_l_blk;            // ABIOS LID block                     
  66. USHORT      lid_blk_size;           // size of LID block                   
  67. CARD        card[MAX_NUM_SLOTS+1];  // array for IDs and POS reg values    
  68. CARD        *pcard;                 // pointer to card array               
  69. USHORT      matches = 0;            // match flag for card ID              
  70. POS_STRUCT  pos_struct;             // struct to get POS reg               
  71. ADDR_STRUCT addr_struct;            // struct for passing addresses        
  72. USHORT      chunk1,chunk2;          // temp variables for address calc     
  73.  
  74. char     arguments[64]={0};         // save command line args in dgroup    
  75. char     NoMatchMsg[]  = " no match for selected Micro Channel card ID found.\r\n";
  76. char     MainMsgMCA[]  = "\r\nOS/2 Micro Channel memory-mapped driver installed.\r\n";
  77. char     MainMsgISA[]  = "\r\nOS/2 ISA bus memory-mapped driver installed.\r\n";
  78.  
  79. // prototypes 
  80.  
  81. int      hex2bin(char c);
  82. USHORT   get_POS();
  83. UCHAR    get_pos_data();
  84. UCHAR    nget_pos_data();
  85.  
  86. // common entry point for calls to Strategy routines 
  87.  
  88. int main(PREQPACKET rp )
  89. {
  90.     void far *ptr;
  91.     int far *pptr;
  92.     PLINFOSEG liptr;                // pointer to local info seg           
  93.     int i;
  94.     ULONG addr;
  95.     USHORT in_data;
  96.  
  97.     switch(rp->RPcommand)
  98.     {
  99.     case RPINIT:                    // 0x00                                
  100.  
  101.         // init called by kernel in protected mode ring 3 with IOPL 
  102.  
  103.         return Init(rp);
  104.  
  105.     case RPOPEN:                    // 0x0d                                
  106.  
  107.         // get current processes id 
  108.  
  109.         if (GetDOSVar(2,&ptr))
  110.             return (RPDONE | RPERR | ERROR_BAD_COMMAND);
  111.  
  112.         // get process info 
  113.  
  114.         liptr = *((PLINFOSEG far *) ptr);
  115.  
  116.         // if this device never opened, can be opened by any process       
  117.  
  118.         if (opencount == 0)    // first time this device opened       
  119.         {
  120.             opencount=1;                 // set open counter                    
  121.             savepid = liptr->pidCurrent; // save current process id   
  122.         }
  123.         else
  124.             {
  125.             if (savepid != liptr->pidCurrent) // another proc tried to open 
  126.                 return (RPDONE | RPERR | RPBUSY ); // so return error      
  127.             ++opencount;            // bump counter, same pid              
  128.         }
  129.         return (RPDONE);
  130.  
  131.     case RPCLOSE:                   // 0x0e                                
  132.  
  133.         // get process info of caller 
  134.  
  135.         if (GetDOSVar(2,&ptr))
  136.             return (RPDONE | RPERR | ERROR_BAD_COMMAND); // no info        
  137.  
  138.         // get process info from os/2 
  139.  
  140.         liptr= *((PLINFOSEG far *) ptr); // ptr to process info seg        
  141.  
  142.         // 
  143.         // make sure that process attempting to close this device 
  144.         // one that originally opened it and the device was open in
  145.         // first place.
  146.         //
  147.  
  148.         if (savepid != liptr->pidCurrent || opencount == 0)  
  149.             return (RPDONE | RPERR | ERROR_BAD_COMMAND);
  150.  
  151.         // if an LDT selector was allocated, free it 
  152.  
  153.         PhysToUVirt(board_address,0x8000,2,&addr_struct.mapped_addr);
  154.  
  155.         --opencount;                // close counts down open counter      
  156.         return (RPDONE);            // return 'done' status to caller      
  157.  
  158.     case RPREAD:                    // 0x04                                
  159.  
  160.         return(RPDONE);
  161.  
  162.     case RPWRITE:                   // 0x08                                
  163.  
  164.         return (RPDONE);
  165.  
  166.     case RPIOCTL:                   // 0x10                                
  167.  
  168.         if (rp->s.IOCtl.category != OUR_CAT) // only our category          
  169.             return (RPDONE);
  170.  
  171.         switch (rp->s.IOCtl.function)
  172.         {
  173.  
  174.           // this IOCtl returns the bus type. If the type is Micro Channel
  175.           // the return is 0xff01. If ISA, the return is ff00
  176.  
  177.         case 0x01:                  // check if MCA or ISA
  178.             return (RPDONE | RPERR | bus);
  179.  
  180.           // this IOCtl maps an adapter memory to an LDT selector:offset,
  181.           // and sends it to the application for direct application reads
  182.           // and writes
  183.  
  184.         case 0x02:                  // send memory-mapped addr to app   
  185.  
  186.             // verify caller owns this buffer area 
  187.  
  188.             if(VerifyAccess(
  189.             SELECTOROF(rp->s.IOCtl.buffer), // selector                    
  190.             OFFSETOF(rp->s.IOCtl.buffer),   // offset                      
  191.             8,                              // 8 bytes                     
  192.             1) )                            // read write                  
  193.                 return (RPDONE | RPERR | ERROR_GEN_FAILURE);
  194.  
  195.             // lock the segment down temp 
  196.  
  197.             if(LockSeg(
  198.             SELECTOROF(rp->s.IOCtl.buffer), // selector                    
  199.             0,                              // lock < 2 sec                
  200.             0,                              // wait for seg lock           
  201.             (PLHANDLE) &lock_seg_han))      // handle returned             
  202.                 return (RPDONE | RPERR | ERROR_GEN_FAILURE);
  203.  
  204.            // map the board address to an LDT entry
  205.  
  206.            if ( PhysToUVirt(board_address,0x8000,1,&addr_struct.mapped_addr)) 
  207.                return (RPDONE | RPERR | ERROR_GEN_FAILURE);
  208.  
  209.            // move data to users buffer 
  210.  
  211.            if(MoveBytes(
  212.            &addr_struct,                   // source
  213.            rp->s.IOCtl.buffer,             // dest                      
  214.            8))                             // 8 bytes                     
  215.                return (RPDONE | RPERR | ERROR_GEN_FAILURE);
  216.  
  217.            // unlock segment 
  218.  
  219.            if(UnLockSeg(lock_seg_han))
  220.                return(RPDONE | RPERR | ERROR_GEN_FAILURE);
  221.  
  222.            return (RPDONE);
  223.  
  224.           // this IOCtl demonstrates how an application program can get the
  225.           // contents of a Micro Channel Adapter's POS registers
  226.  
  227.         case 0x03:                  // get pos reg data                    
  228.  
  229.             // verify caller owns this buffer area 
  230.  
  231.             if(VerifyAccess(
  232.             SELECTOROF(rp->s.IOCtl.buffer), // selector                    
  233.             OFFSETOF(rp->s.IOCtl.buffer),   // offset                      
  234.             6,                              // 6 bytes                     
  235.             1) )                            // read write                  
  236.                 return (RPDONE | RPERR | ERROR_GEN_FAILURE);
  237.  
  238.             // lock the segment down temp 
  239.  
  240.             if(LockSeg(
  241.             SELECTOROF(rp->s.IOCtl.buffer), // selector                    
  242.             0,                              // lock < 2 sec                
  243.             0,                              // wait for seg lock           
  244.             (PLHANDLE) &lock_seg_han))      // handle returned             
  245.                 return (RPDONE | RPERR | ERROR_GEN_FAILURE);
  246.  
  247.             // move slot data to driver buffer 
  248.  
  249.             if(MoveBytes(
  250.             (FARPOINTER) appl_buffer,       // source                      
  251.             &pos_struct,                    // for pos data                
  252.             6))                             // 6 bytes                     
  253.                 return (RPDONE | RPERR | ERROR_GEN_FAILURE);
  254.  
  255.             pos_struct.data = get_pos_data(pos_struct.slot,pos_struct.reg);
  256.  
  257.             // move POS reg data to users buffer 
  258.  
  259.             if(MoveBytes(
  260.             &pos_struct,                    // for pos data                
  261.             (FARPOINTER) appl_buffer,       // source                      
  262.             6))                             // 6 bytes                     
  263.                 return (RPDONE | RPERR | ERROR_GEN_FAILURE);
  264.  
  265.             // unlock segment 
  266.  
  267.             if(UnLockSeg(lock_seg_han))
  268.  
  269.                 return(RPDONE | RPERR | ERROR_GEN_FAILURE);
  270.  
  271.             return (RPDONE);
  272.  
  273.           // this IOCtl is essentially the same as 0x02, except the
  274.           // user virtual address is mapped to a linear address in the
  275.           // process address range and then sent to the application. This
  276.           // save the SelToFlat and FlatToSel each time the pointer is
  277.           // referenced.
  278.  
  279.         case 0x04:                  // 32-bit memory-mapped addr to app   
  280.  
  281.             // verify caller owns this buffer area 
  282.  
  283.             if(VerifyAccess(
  284.             SELECTOROF(rp->s.IOCtl.buffer), // selector                    
  285.             OFFSETOF(rp->s.IOCtl.buffer),   // offset                      
  286.             8,                              // 8 bytes                     
  287.             1) )                            // read write                  
  288.                 return (RPDONE | RPERR | ERROR_GEN_FAILURE);
  289.  
  290.             // lock the segment down temp 
  291.  
  292.             if(LockSeg(
  293.             SELECTOROF(rp->s.IOCtl.buffer), // selector                    
  294.             0,                              // lock < 2 sec                
  295.             0,                              // wait for seg lock           
  296.             (PLHANDLE) &lock_seg_han))      // handle returned             
  297.                 return (RPDONE | RPERR | ERROR_GEN_FAILURE);
  298.  
  299.            // map the board address to an LDT entry
  300.  
  301.            if ( PhysToUVirt(board_address,0x8000,1,&addr_struct.mapped_addr)) 
  302.                return (RPDONE | RPERR | ERROR_GEN_FAILURE);
  303.  
  304.               // now convert it to a linear address
  305.  
  306.               if (VirtToLin((FARPOINTER)addr_struct.mapped_addr,
  307.                                 (PLINADDR)&addr_struct.mapped_addr))
  308.                return (RPDONE | RPERR | ERROR_GEN_FAILURE);
  309.  
  310.            // move data to users buffer 
  311.  
  312.            if(MoveBytes(
  313.            &addr_struct,                   // source
  314.            rp->s.IOCtl.buffer,             // dest                      
  315.            8))                             // 8 bytes                     
  316.                return (RPDONE | RPERR | ERROR_GEN_FAILURE);
  317.  
  318.            // unlock segment 
  319.  
  320.            if(UnLockSeg(lock_seg_han))
  321.                return(RPDONE | RPERR | ERROR_GEN_FAILURE);
  322.  
  323.            return (RPDONE);
  324.  
  325.         } // switch (rp->s.IOCtl.function 
  326.  
  327.     case RPDEINSTALL:               // 0x14                            
  328.  
  329.         return(RPDONE | RPERR | ERROR_BAD_COMMAND);
  330.  
  331.         // all other commands are ignored 
  332.  
  333.     default:
  334.         return(RPDONE);
  335.  
  336.     }
  337. }
  338.  
  339. int  hex2bin(char c)
  340. {
  341.  if(c < 0x3a)
  342.   return (c - 48);
  343.  else
  344.   return (( c & 0xdf) - 55);
  345. }
  346.  
  347. USHORT get_POS(USHORT slot_num,USHORT far *card_ID,UCHAR far *pos_regs)
  348. {
  349. USHORT rc, i, lid;
  350.     
  351.     if (GetLIDEntry(0x10, 0, 1, &lid)) // get LID for POS   
  352.         return (1);
  353.  
  354.     // Get the size of the LID request block 
  355.  
  356.     ABIOS_l_blk.f_parms.req_blk_len = sizeof(struct lid_block_def);
  357.     ABIOS_l_blk.f_parms.LID = lid;
  358.     ABIOS_l_blk.f_parms.unit = 0;;
  359.     ABIOS_l_blk.f_parms.function = GET_LID_BLOCK_SIZE;
  360.     ABIOS_l_blk.f_parms.ret_code = 0x5a5a;
  361.     ABIOS_l_blk.f_parms.time_out = 0;
  362.  
  363.     if (ABIOSCall(lid,0,(void far *)&ABIOS_l_blk))
  364.         return (1);
  365.  
  366.     lid_blk_size = ABIOS_l_blk.s_parms.blk_size; // Get the block size  
  367.  
  368.     // Fill POS regs and card ID with FF in case this does not work          
  369.  
  370.     *card_ID = 0xFFFF;
  371.     for (i=0; i<NUM_POS_BYTES; i++) { pos_regs[i] = 0x00; }; 
  372.  
  373.     // Get the POS registers and card ID for the commanded slot 
  374.  
  375.     ABIOS_r_blk.f_parms.req_blk_len = lid_blk_size;
  376.     ABIOS_r_blk.f_parms.LID = lid;
  377.     ABIOS_r_blk.f_parms.unit = 0;;
  378.     ABIOS_r_blk.f_parms.function = READ_POS_REGS_CARD;
  379.     ABIOS_r_blk.f_parms.ret_code = 0x5a5a;
  380.     ABIOS_r_blk.f_parms.time_out = 0;
  381.     
  382.     ABIOS_r_blk.s_parms.slot_num = (UCHAR)slot_num & 0x0F;
  383.     ABIOS_r_blk.s_parms.pos_buf = (void far *)pos_regs;
  384.     ABIOS_r_blk.s_parms.card_ID = 0xFFFF;
  385.     
  386.     if (ABIOSCall(lid,0,(void far *)&ABIOS_r_blk))
  387.        rc = 1;
  388.      else {                                       // Else                 
  389.        *card_ID = ABIOS_r_blk.s_parms.card_ID;   //    Set the card ID value     
  390.        rc = 0;
  391.       }
  392.     FreeLIDEntry(lid);
  393.     return(rc);
  394.     
  395. }
  396.  
  397. UCHAR get_pos_data (int slot, int reg)
  398. {
  399.    UCHAR pos;
  400.    CARD *cptr;
  401.  
  402.    cptr = &card[slot-1];            // set pointer to beg of card array    
  403.    if (reg == 0)                    // card ID                             
  404.       pos = LOUSHORT(cptr->card_ID);
  405.    else
  406.      if ( reg == 1)
  407.       pos = HIUSHORT(cptr->card_ID);
  408.    else
  409.       pos = cptr->pos_regs[reg-2];  // POS data register                   
  410.    return (pos);
  411. }
  412.  
  413. // Device Initialization Routine 
  414.  
  415. int Init(PREQPACKET rp)
  416. {
  417.     USHORT lid;
  418.  
  419.     register char far *p;
  420.  
  421.     // store DevHlp entry point 
  422.  
  423.     DevHlp = rp->s.Init.DevHlp;  // save DevHlp entry point             
  424.  
  425.     if (!(GetLIDEntry(0x10, 0, 1, &lid))) { // get LID for POS   
  426.        FreeLIDEntry(lid);
  427.  
  428.   // Micro Channel (tm) setup section 
  429.  
  430.   bus = 1;                      // MCA bus                             
  431.  
  432.       //    Get the POS data and card ID for each of 8 possible slots 
  433.  
  434.       for (i=0;i <= MAX_NUM_SLOTS; i++) 
  435.          get_POS(i+1,(FARPOINTER)&card[i].card_ID,(FARPOINTER)card[i].pos_regs);
  436.  
  437.       matches = 0;
  438.       for (i=0, pcard = card; i <= MAX_NUM_SLOTS; i++, pcard++) {
  439.          if (pcard->card_ID == TARGET_ID) { 
  440.             matches = 1;
  441.             break;
  442.             }
  443.          }
  444.  
  445.       if (matches == 0) {           // at least one board found          
  446.    DosPutMessage(1, 8, devhdr.DHname);
  447.    DosPutMessage(1,strlen(NoMatchMsg),NoMatchMsg);
  448.      rp->s.InitExit.finalCS = (OFF) 0;
  449.    rp->s.InitExit.finalDS = (OFF) 0;
  450.    return (RPDONE | RPERR | ERROR_BAD_COMMAND);
  451.    }
  452.  
  453.       // calculate the board address from the POS regs 
  454.  
  455.     board_address = ((unsigned long) get_pos_data(i+1, 4) << 16) |
  456.     ((unsigned long)(get_pos_data(i+1, 3) & 1) << 15);
  457.   }
  458.  
  459.   else
  460.  
  461.   // ISA bus setup 
  462.  
  463.   {
  464.   bus = 0;                      // ISA bus                             
  465.  
  466.   // get parameters, IRQ (not used yet), port addr and base mem addr 
  467.   
  468.   for (p = rp->s.Init.args; *p && *p != ' ';++p);// skip driver name 
  469.   for (; *p == ' '; ++p);       // skip blanks following driver name   
  470.   if (*p)
  471.    {
  472.          board_address=0;           // i/o port address                    
  473.    for (; *p != '\0'; ++p)    // get board address                   
  474.     board_address = (board_address << 4) + (hex2bin(*p));
  475.    addr_struct.board_addr = board_address;
  476.    }
  477.   }
  478.  
  479.   if (bus)
  480.          DosPutMessage(1,strlen(MainMsgMCA),MainMsgMCA);
  481.       else
  482.          DosPutMessage(1,strlen(MainMsgISA),MainMsgISA);
  483.  
  484.   // send back our cs and ds end values to os/2 
  485.         
  486.   if (SegLimit(HIUSHORT((void far *) Init), &rp->s.InitExit.finalCS) ||
  487.      SegLimit(HIUSHORT((void far *) MainMsgISA), &rp->s.InitExit.finalDS))
  488.        Abort();
  489.   
  490.   Beep(200,500);
  491.   Beep(200,500);
  492.   Beep(250,500);
  493.   Beep(300,500);
  494.   Beep(250,500);
  495.   Beep(300,500);
  496.  
  497.   return (RPDONE);
  498.   
  499. }
  500.