home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 4 Drivers / 04-Drivers.zip / CDRIVER.ZIP / BIKONC.C < prev    next >
C/C++ Source or Header  |  1991-01-12  |  47KB  |  1,548 lines

  1. /****************************************************************************
  2.  
  3.     OS/2 Device Driver module for IKON 10092 Plotter Adaptors.
  4.  
  5.     The entry point DriverStrategy() is called from the BIKONA.ASM 
  6.     module with the address of the Driver Request Packet for further 
  7.     processing.
  8.  
  9.     void _near _fastcall DriverStrategy( DRV_REQ     *pDrvReq    );
  10.  
  11.     Note:
  12.  
  13.     ******************************************************************
  14.     All statics should be initialized so as to force them into the
  15.     _DATA segment, rather than the CONST or _BSS segments.  Data
  16.     values that end up in the CONST or _BSS segments will be discarded
  17.     after 'init' time.
  18.  
  19.     Any data defined after the L_LastData variable will be discarded
  20.     at Init time.  If referenced during later Strategy or Interrupt
  21.     calls, the system will crash with a protection violation.
  22.     ******************************************************************
  23.  
  24.     History:
  25.     01-08-91 ras - SCR P0487, initial entry
  26.     01-09-91 ras - SCR P0487, continue
  27.     01-10-91 ras - SCR P0487, continue
  28.     01-11-91 ras - SCR P0487, add text mode processing
  29.     01-12-91 ras - SCR P0487, add move mode processing
  30.  
  31.         Copyright 1991, Byers Engineering Company
  32. ****************************************************************************/
  33. #define INCL_DOS
  34. #include <os2.h>                // OS/2   defines
  35. #include <conio.h>                // I/O    defines
  36. #include <memory.h>                // Memory defines
  37. #include <stdlib.h>                // Standard Lib defines
  38. #include <dos.h>                // DOS    defines
  39. #include "cdriver.h"                // OS/2 C defines
  40. #include "bikon.h"                // IKON   defines
  41.  
  42. // verify compiled using LARGE model
  43. #ifndef    M_I86LM
  44. #error *** MUST COMPILE IN LARGE MODEL ONLY
  45. #endif
  46.  
  47. // specify compilation options
  48. #pragma    intrinsic(     inp, outp, memcpy     )
  49. #pragma intrinsic(    _enable, _disable    )
  50. #pragma intrinsic(    abs            )
  51. #pragma    check_stack(    off            )
  52.  
  53. // declare functions for 'alloc_text'
  54.        void  _near _fastcall DriverStrategy(     DRV_REQ    *pDrvReq    );
  55. static void  _near          L_ReqInit(         DRV_REQ    *pDrvReq    );
  56. static void  _near          L_ReqClose(     DRV_REQ    *pDrvReq    );
  57. static void  _near          L_InitAdaptor(     IK_REQ     *pIkReq    );
  58. static void  _near          L_WriteRaster(     IK_REQ     *pIkReq    );
  59. static void  _near          L_WriteText(     IK_REQ     *pIkReq    );
  60. static void  _near          L_WriteMove(     IK_REQ     *pIkReq    );
  61. static void  _near          L_WriteControl(     IK_REQ     *pIkReq    );
  62. static int   _near         L_WaitReady(     uint32         qTimeout    );
  63. static void  _far         L_InterruptService( void            );
  64. static void  _near         L_StartControl(     void            );
  65. static void  _near         L_StartDma(     int         nRasterFlag);
  66. static void  _near          L_LastCode(     void             );
  67.  
  68. // force allocation of functions to _TEXT
  69. #pragma    alloc_text( _TEXT, DriverStrategy    )
  70. #pragma alloc_text( _TEXT, L_ReqInit        )
  71. #pragma alloc_text( _TEXT, L_ReqClose        )
  72. #pragma alloc_text( _TEXT, L_InitAdaptor    )
  73. #pragma alloc_text( _TEXT, L_WriteRaster    )
  74. #pragma alloc_text( _TEXT, L_WriteText        )
  75. #pragma alloc_text( _TEXT, L_WriteMove        )
  76. #pragma alloc_text( _TEXT, L_WriteControl    )
  77. #pragma alloc_text( _TEXT, L_WaitReady        )
  78. #pragma alloc_text( _TEXT, L_InterruptService    )
  79. #pragma alloc_text( _TEXT, L_StartControl    )
  80. #pragma alloc_text( _TEXT, L_StartDma        )
  81. #pragma alloc_text( _TEXT, L_LastCode        )
  82.  
  83. // define Interrupt service modes, used by L_InterruptService()
  84. // to determine next action to perform.  these values are
  85. // used as a mask to determine which threads the interrupt
  86. // routine should resume
  87. #define    I_IDLE        0
  88. #define    I_READY        0x0001
  89. #define    I_RASTER    0x0002
  90. #define    I_TEXT        0x0004
  91. #define    I_MOVE        0x0008
  92. #define    I_CONTROL    0x0010
  93.  
  94. //********************************************
  95. // define local statics kept as part of driver
  96. //********************************************
  97. static    char        L_Id1[] = "BYERS IKON";    // id to find with Ramscope
  98. static    uint32        L_qBufPhyAddr       = 0; // Physical buffer address
  99. static    uint16        L_nBufPhyOff       = 0; //           offset
  100. static    uint16        L_nBufLineCnt       = 0; // Raster lines left to write
  101. static    uint16        L_nBufBytesPerLine = 0; //      bytes per line
  102. static    uint16        L_nControlFlags       = 0; // Control flag values
  103. static    int        L_nIntMode    = I_IDLE;    // Interrupts idle
  104. static    int        L_nIntSimulate        = 0;    // non-zero for internal int
  105. static    REG_STACK_USAGE(L_RegStack,   0,    // def interrupt stack usage
  106.                     256,
  107.                       0,
  108.                       0,
  109.                       0,
  110.                       0 );
  111. static    uint32        L_qIntServAddr = (uint32) &L_InterruptService;
  112.  
  113.  
  114. //*****************************
  115. // Define IKON Adaptor literals
  116. //*****************************
  117.  
  118. //;define IKON I/O Port addresses
  119. #define IO_BASE_ADDR        0x0300        //;base port address
  120. //; output port offsets
  121. #define IO_OUT_SETUP_OFF    0        //;write setup control
  122. #define IO_OUT_REMOTE_OFF    1        //;write remote functions
  123. #define IO_OUT_DATA_OFF        2        //;write programmed data
  124. //; input port offsets
  125. #define IO_IN_SETUP_OFF        0        //;read setup status
  126. #define IO_IN_ISTAT_OFF        1        //;read interface status
  127. #define IO_IN_DIAG_OFF        2        //;read diagnostic data
  128. #define IO_IN_DSTAT_OFF        3        //;read device status
  129. #define IO_IN_STRAP_OFF        4        //;read interface strap options
  130.  
  131. //;define Setup Register IN/OUT mask bits
  132. #define IO_SETUP_HI_TEST_ENABLE    0x80        //;hi to enable internal test
  133. #define IO_SETUP_HI_TEST_STROBE    0x40        //;hi to strobe test ready
  134. #define IO_SETUP_HI_LATCH_RESET    0x20        //;hi to force device reset
  135. #define IO_SETUP_HI_DMA_ENABLE    0x10        //;hi to start DMA requests
  136. #define IO_SETUP_LO_DMA_DISABLE    0x00        //;lo to disable DMA
  137. #define IO_SETUP_HI_STREAM_MODE    0x08        //;hi to enable stream mode
  138. #define IO_SETUP_HI_INT_ENABLE    0x04        //;hi to enable interrupts
  139. #define IO_SETUP_HI_SPP_MODE    0x02        //;hi for Versatec SPP mode
  140. #define IO_SETUP_HI_PLOT_MODE    0x01        //;hi for Versatec Plot mode
  141. #define IO_SETUP_LO_PRINT_MODE    0x00        //;lo for Versatec Print mode
  142.  
  143. //;define Remote Register mask bits
  144. #define IO_REMOTE_HI_SOFT_ACK    0x80        //;hi to simulate device ack
  145. #define IO_REMOTE_HI_RESET_ADP    0x40        //;hi to reset adaptor
  146. #define IO_REMOTE_HI_RESET_INT    0x20        //;hi to reset interrupt flag
  147. #define IO_REMOTE_HI_RESET_DEV    0x10        //;hi to reset device
  148. #define IO_REMOTE_HI_CLEAR    0x08        //;hi to set Versa CLEAR-
  149. #define IO_REMOTE_HI_FF        0x04        //;hi to set Versa FORM FEED-
  150. #define IO_REMOTE_HI_EOT    0x02        //;hi to set Versa EOT-
  151. #define IO_REMOTE_HI_TERM    0x01        //;hi to set Versa LINE TERM-
  152.  
  153. //;define Interface Status Register mask bits
  154. #define IO_ISTAT_HI_READY    0x80        //;hi when adaptor,device ready
  155. #define IO_ISTAT_HI_READY_DEV    0x40        //;hi when device ready
  156. #define IO_ISTAT_HI_INTERRUPT    0x20        //;hi when interrupting
  157. #define IO_ISTAT_LO_WORD    0x10        //;lo when 16 bit mode
  158. #define IO_ISTAT_LO_SWAP    0x08        //;lo when byte swap
  159. #define IO_ISTAT_BIT_TSEL    0x04        //;test pattern switch 1 status
  160. #define IO_ISTAT_BIT_FPLT    0x02        //;test pattern switch 2 status
  161. #define IO_ISTAT_LO_TEST    0x01        //;lo when adaptor testing
  162.  
  163. //;define Input Device Status Register mask bits
  164. #define IO_DSTAT_LO_TTL        0x80        //;lo when TTL mode
  165. #define IO_DSTAT_LO_DIF        0x40        //;lo when Differential mode
  166. #define IO_DSTAT_LO_CENT    0x20        //;lo when Centronics mode
  167. #define IO_DSTAT_HI_VRDY    0x10        //;hi when Versatec ready
  168. #define IO_DSTAT_HI_CBSY    0x08        //;hi when Centronics busy
  169. #define IO_DSTAT_HI_NOPAP    0x04        //;hi when no paper
  170. #define IO_DSTAT_HI_ONLIN    0x02        //;hi when device on-line
  171. #define IO_DSTAT_HI_FAULT    0x01        //;hi when Centronics fault
  172.  
  173. //;define Strap Status Register mask bits
  174. #define IO_STRAP_LO_PULLDOWN    0x80        //;lo-pulldown,hi-pullup
  175. #define IO_STRAP_DMA_MASK    0x70        //;DMA bits mask
  176. #define IO_STRAP_DMA_SHIFT    4        //;DMA bits shift to 0
  177. #define IO_STRAP_INT_MASK    0x0f        //;INT bits mask
  178. #define IO_STRAP_INT_SHIFT    0        //;INT bits shift to 0
  179.  
  180. //**************************************************************
  181. // define IKON I/O Port addresses (updated during IK_INIT_SETUP)
  182. //**************************************************************
  183.  
  184. //;IKON Register addresses
  185. static    uint16    L_nIoBase        =    IO_BASE_ADDR;
  186. static    uint16    L_nIoOutSetupAddr   =    IO_BASE_ADDR+IO_OUT_SETUP_OFF;
  187. static    uint16    L_nIoOutRemoteAddr  =    IO_BASE_ADDR+IO_OUT_REMOTE_OFF;
  188. static    uint16    L_nIoOutDataAddr    =    IO_BASE_ADDR+IO_OUT_DATA_OFF;
  189. static    uint16    L_nIoInSetupAddr    =    IO_BASE_ADDR+IO_IN_SETUP_OFF;
  190. static    uint16    L_nIoInIstatAddr    =    IO_BASE_ADDR+IO_IN_ISTAT_OFF;
  191. static    uint16    L_nIoInDiagAddr     =    IO_BASE_ADDR+IO_IN_DIAG_OFF;
  192. static    uint16    L_nIoInDstatAddr    =    IO_BASE_ADDR+IO_IN_DSTAT_OFF;
  193. static    uint16    L_nIoInStrapAddr    =    IO_BASE_ADDR+IO_IN_STRAP_OFF;
  194.  
  195.  
  196. //**************************************************************
  197. // define IKON Interrupt controls (updated during IK_INIT_SETUP)
  198. //**************************************************************
  199. static    int        L_nIntNum    = 15;    // adaptor interrupt number
  200. static    int        L_nIntInUse    =  0;    // non-zero when int in use
  201.  
  202. //***************************************************************
  203. // define IKON DMA access controls (updated during IK_INIT_SETUP)
  204. //***************************************************************
  205.  
  206. typedef    struct                // DMA control structure
  207.   {    uint16        nAdrStatus;        //status      reg address
  208.     uint16        nAdrMask;        //mask           reg address
  209.     uint16        nAdrMode;        //mode        reg address
  210.     uint16        nAdrReset;        //reset count reg address
  211.     uint16        nAdrPage;        //page        reg address
  212.     uint16        nAdrOff;        //offset      reg address
  213.     uint16        nAdrCnt;        //count       reg address
  214.     uint16        nValStatus;        //status done value
  215.     uint16        nValMode;        //mode        value (read mem)
  216.     uint16        nValSet;        //set   mask  value (disable)
  217.     uint16        nValReset;        //reset mask  value (enable)
  218.   } DMA_DEF;  
  219.  
  220. // define entry for current DMA channel values (updated during IK_INIT_SETUP)
  221. static    uint16        L_nDmaNum    = 7;    // current DMA channel number
  222. static    DMA_DEF        L_Dma            // current DMA controls
  223.             = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  224.  
  225. // define table of all DMA channel values
  226. static    DMA_DEF        L_DmaVals[]        // table of all DMA controls
  227.             = { { 0x08,0x0a,0x0b,0x0c,0x87,0x00,    // channel 0
  228.                   0x01,0x01,0x08,0x04,0x00 },
  229.                 { 0x08,0x0a,0x0b,0x0c,0x83,0x02,    //       1
  230.                   0x03,0x02,0x09,0x05,0x01 },
  231.                 { 0x08,0x0a,0x0b,0x0c,0x81,0x04,    //       2
  232.                   0x05,0x04,0x0a,0x06,0x02 },
  233.                 { 0x08,0x0a,0x0b,0x0c,0x82,0x06,    //       3
  234.                   0x07,0x08,0x0b,0x07,0x03 },
  235.                 { 0xd0,0xd4,0xd6,0xd8,0x8f,0xc0,    //       4
  236.                   0xc2,0x01,0x08,0x04,0x00 },
  237.                 { 0xd0,0xd4,0xd6,0xd8,0x8b,0xc4,    //       5
  238.                   0xc6,0x02,0x09,0x05,0x01 },
  239.                 { 0xd0,0xd4,0xd6,0xd8,0x89,0xc8,    //       6
  240.                   0xca,0x04,0x0a,0x06,0x02 },
  241.                 { 0xd0,0xd4,0xd6,0xd8,0x8a,0xcc,    //       7
  242.                   0xce,0x08,0x0b,0x07,0x03 },
  243.               };
  244.  
  245. //***************************************************
  246. // define local statics discarded after initilization
  247. //***************************************************
  248. static    char    L_LastData      = 0;        // last dataseg loc to save
  249. static    char    L_acMsg[]     = "\r\nByers OS/2 IKON 10092(7) Driver"
  250.                   "\r\nVersion 0.0.1";
  251.  
  252. /****************************************************************************
  253.  
  254.     void _near _fastcall DriverStrategy( DRV_REQ     *pDrvReq    )
  255.  
  256.     This function is the primary entry point for device driver services.
  257.     It is called from the .ASM entry point module with the address of
  258.     the Driver Request packet.  It should perform whatever services
  259.     are required by the packet, set the packet status and return.
  260.  
  261.     Called with:
  262.         pDrvReq        ptr to Driver Request packet
  263.  
  264.     Returns:
  265.         none
  266.  
  267.     Note:
  268.  
  269.     This module should reside in the primary code segment _TEXT
  270.     declared by the .ASM stub.  All driver functions can be
  271.     accomplished within this function, or by calling other
  272.     functions also declared to exist within the _TEXT segment
  273.     by the above 'alloc_text' pragma.
  274.  
  275.     If some driver functions are to be accomplished by calling other
  276.     functions, they can be allocated into 'high' memory segments by
  277.     not including them in the 'alloc_text' pragma.  The .DEF file
  278.     should declare IOPL for any such segments that are to be
  279.     preserved after 'init' time.  Note that 'high' memory functions
  280.     can not be called in 'real' mode, only in 'protected' mode.
  281.  
  282.     Segments loaded into 'high' memory are swappable unless locked
  283.     by the 'init' processing.
  284.     
  285.         Copyright 1991, Byers Engineering Company
  286. ****************************************************************************/
  287.  
  288. // define function
  289. void _near _fastcall    DriverStrategy(    DRV_REQ     *pDrvReq    )
  290.  
  291.   {    // define automatics
  292.     IK_REQ           *pIkReq;            // IKON Request ptr
  293.  
  294.     // clear status word for default 'no error' indication
  295.     pDrvReq->nStatus = 0;
  296.  
  297.     // process by type of request packet
  298.     switch ( pDrvReq->bCmd )
  299.     {
  300.                       //********************************
  301.       case DREQ_INIT:    // CONFIG.SYS Initialize Driver
  302.                       //********************************
  303.         // call Init routine
  304.         L_ReqInit( pDrvReq );
  305.  
  306.         // stop case
  307.         break;
  308.  
  309.                       //********************************
  310.       case DREQ_OPEN:    // OPEN command
  311.                       //********************************
  312.         // nothing to do, driver declared as 'one at a time'
  313.         // so don't need to worry about exclusivity
  314.         break;
  315.  
  316.  
  317.                       //********************************
  318.       case DREQ_CLOSE:    // CLOSE command
  319.                       //********************************
  320.         // terminate any plotter activities
  321.         L_ReqClose( pDrvReq );
  322.  
  323.         // stop case
  324.         break;
  325.  
  326.  
  327.                       //********************************
  328.       case DREQ_IOCTL:    // IOCTL command
  329.                       //********************************
  330.         // verify Category 128, Function 0 in Request Packet
  331.         if (    pDrvReq->IoCtl.bCategory != 128
  332.              || pDrvReq->IoCtl.bFunction != 0 )
  333.         {   // nope, don't know this one, indicate it
  334.             pDrvReq->nStatus = 0x8103;
  335.  
  336.         // stop case
  337.         break;
  338.         }
  339.  
  340.         // extract ptr to IKON Request data
  341.         // should point to a IK_REQ structure
  342.         pIkReq = pDrvReq->IoCtl.fpParm;
  343.  
  344.         // verify r/w accessibility of IK_REQ structure
  345.         HlpVerifyAccess( pIkReq, sizeof(IK_REQ), 1 );
  346.  
  347.         // default status to bad parameters
  348.         pIkReq->qBufUsed = 0;
  349.         pIkReq->nStatus  = ERR_IK_BAD_PARM;
  350.  
  351.         // process by type of Client Request
  352.         switch ( pIkReq->nOpCode )
  353.         {
  354.                           //********************************
  355.           case IK_INIT_QUERY:    // Query value of IK_CFG_PARM
  356.                           //********************************
  357.         // IK_REQ should point to a IK_CFG_PARM
  358.         // check buffer claims big enough
  359.         if ( pIkReq->qBufSize < sizeof(IK_CFG_PARM) )
  360.         {   // nope, stop case
  361.             break;
  362.         }
  363.  
  364.         // verify accessibility of it
  365.         HlpVerifyAccess( pIkReq->fpcBuf,
  366.                  sizeof(IK_CFG_PARM),
  367.                  1 );
  368.  
  369.         // copy data from local values to their buffer
  370.         ((IK_CFG_PARM *) (pIkReq->fpcBuf))->nIoPort    = L_nIoBase;
  371.         ((IK_CFG_PARM *) (pIkReq->fpcBuf))->nInterrupt = L_nIntNum;
  372.         ((IK_CFG_PARM *) (pIkReq->fpcBuf))->nDma       = L_nDmaNum;
  373.  
  374.         // set params to show successful transfer
  375.         pIkReq->qBufUsed = sizeof( IK_CFG_PARM );
  376.         pIkReq->nStatus  = 0;
  377.  
  378.               // stop case
  379.         break;
  380.  
  381.                           //********************************
  382.           case IK_INIT_SET:        // Setup value of IK_CFG_PARM
  383.                           //********************************
  384.         // IK_REQ should point to a IK_CFG_PARM
  385.         // check buffer claims big enough
  386.         if ( pIkReq->qBufSize < sizeof(IK_CFG_PARM) )
  387.         {   // nope, stop case
  388.             break;
  389.         }
  390.  
  391.         // verify accessibility of it
  392.         HlpVerifyAccess( pIkReq->fpcBuf,
  393.                  sizeof(IK_CFG_PARM),
  394.                  1 );
  395.  
  396.         // set params to show amt transferred
  397.         pIkReq->qBufUsed = sizeof( IK_CFG_PARM );
  398.  
  399.         // perform remainder of adaptor initialization
  400.         // set 'nStatus' value appropriately
  401.         L_InitAdaptor( pIkReq );
  402.  
  403.               // stop case
  404.         break;
  405.  
  406.                           //*************************
  407.         case IK_WRITE_RASTER:    // Write raster from IK_REQ
  408.                           //*************************
  409.         // IK_REQ.fpcBuf       points to raster data
  410.         //     .qBufSize     is raster byte count
  411.         //     .nBytesPerLine    is used to determine line count
  412.  
  413.         // write raster data, will set status, etc. appropriately
  414.         L_WriteRaster( pIkReq );
  415.  
  416.         // stop case
  417.         break;
  418.  
  419.                           //***********************
  420.         case IK_WRITE_TEXT:        // Write text from IK_REQ
  421.                           //***********************
  422.         // IK_REQ.fpcBuf   points to text data
  423.         //     .qBufSize is text byte count
  424.  
  425.         // verify accessibility of text data
  426.         HlpVerifyAccess( pIkReq->fpcBuf,
  427.                  (uint16) pIkReq->qBufSize,
  428.                  1 );
  429.  
  430.         // write text data, will set status, etc. appropriately
  431.         L_WriteText( pIkReq );
  432.  
  433.         // stop case
  434.         break;
  435.  
  436.                           //*****************************
  437.         case IK_WRITE_MOVE:        // Write paper move from IK_REQ
  438.                           //*****************************
  439.         // IK_REQ.nBytesPerLine contains paper move count
  440.  
  441.         // write paper move data, will set status, etc.
  442.         L_WriteMove( pIkReq );
  443.  
  444.         // stop case
  445.         break;
  446.  
  447.                           //***********************************
  448.         case IK_WRITE_CONTROLS:    // Write plotter controls from IK_REQ
  449.                           //***********************************
  450.         // IK_REQ.nFlags contains plotter control mask to write
  451.  
  452.         // write plotter control data, will set status, etc.
  453.         L_WriteControl( pIkReq );
  454.  
  455.         // stop case
  456.         break;
  457.  
  458.         } // end IoCtl case
  459.  
  460.         // stop IoCtl case
  461.         break;
  462.         
  463.  
  464.             //****************
  465.       default:    // unknown command
  466.             //****************
  467.         // set error
  468.         pDrvReq->nStatus = 0x8103;
  469.  
  470.         // stop default case
  471.         break;
  472.     }
  473.  
  474.     // set 'done' bit in status
  475.     pDrvReq->nStatus |= 0x0100;
  476.  
  477.  
  478.     // return to caller
  479.     return;
  480.   }
  481.  
  482. /****************************************************************************
  483.  
  484.     static void _near L_WriteRaster(    IK_REQ     *pIkReq    )
  485.  
  486.     This function starts output of raster data from the pIkReq data.
  487.  
  488.     Called with:
  489.         pIkReq            ptr to IK_REQ structure
  490.  
  491.     Returns:
  492.         none, returns status in pIkReq
  493.  
  494.         Copyright 1991, Byers Engineering Company
  495. ****************************************************************************/
  496.  
  497. // define function
  498. static void _near L_WriteRaster(    IK_REQ     *pIkReq    )
  499.  
  500.   {    // define automatics
  501.     int        nStatus;        // Hlp function status
  502.     uint32        qLockHandle;        // client buffer lock
  503.     uint32        qTimeout;        // timeout value
  504.  
  505.     // verify not already doing this
  506.     if ( L_nBufLineCnt != 0 )
  507.     {   // whoops, can't start another one yet
  508.         pIkReq->nStatus  = ERR_IK_ALREADY_BUSY;
  509.         pIkReq->qBufUsed = 0;
  510.  
  511.         // return to caller
  512.         return;
  513.     }
  514.  
  515.     // verify params (does not check for short last line)
  516.     if (    pIkReq->nBytesPerLine == 0
  517.          || pIkReq->nBytesPerLine  > (uint16) pIkReq->qBufSize )
  518.     {   // can't have empty lines of data
  519.         pIkReq->nStatus  = ERR_IK_BAD_PARM;
  520.         pIkReq->qBufUsed = 0;
  521.  
  522.         // return to caller
  523.         return;
  524.     }
  525.  
  526.     // lock the client data buffer (assumes zero offset)
  527.     qLockHandle = HlpLock( FP_SEG(pIkReq->fpcBuf), 0, 0 );
  528.  
  529.     // verify accessibility of raster data
  530.     HlpVerifyAccess( pIkReq->fpcBuf,
  531.              (uint16) pIkReq->qBufSize,
  532.              1 );
  533.  
  534.     // get physical address of buffer, set offset to zero
  535.     L_qBufPhyAddr = HlpVirtToPhys( (uint32) pIkReq->fpcBuf );
  536.     L_nBufPhyOff  = 0;
  537.  
  538.     // setup the bytes per line value
  539.     L_nBufBytesPerLine = pIkReq->nBytesPerLine;
  540.  
  541.     // compute how many lines of data we will output
  542.     // note that we are restricting to a 64k buffer
  543.     // so the math will be done without library call
  544.     L_nBufLineCnt  = (uint16) pIkReq->qBufSize / L_nBufBytesPerLine;
  545.  
  546.     // compute timeout value
  547.     qTimeout = (pIkReq->qTimeout == 0)
  548.             ? IK_TIMEOUT_DEFAULT
  549.             : pIkReq->qTimeout;
  550.  
  551.     // block on adaptor being ready to run
  552.     if ( L_WaitReady(qTimeout) != 0 )
  553.     {   // never came ready, set timeout error
  554.         pIkReq->nStatus  = ERR_IK_TIMEOUT;
  555.         pIkReq->qBufUsed = 0;
  556.  
  557.         // unlock the callers data
  558.         HlpUnLock( qLockHandle );
  559.  
  560.         // clear the count in process value
  561.         L_nBufLineCnt = 0;
  562.  
  563.         // return to caller
  564.         return;
  565.     }
  566.  
  567.     // set interrupt mode to raster, perform simulated 
  568.     // interrupt to start raster data running
  569.     _disable();
  570.     L_nIntMode     |= I_RASTER;
  571.     L_nIntSimulate  = 1;
  572.     L_InterruptService();
  573.     _enable();
  574.  
  575.     // block on raster data transfer until interrupt time
  576.     while ( 1 )
  577.     {
  578.         // disable interrupts for check that we are done
  579.         _disable();
  580.  
  581.         // check if all raster lines written
  582.         if ( L_nBufLineCnt == 0 )
  583.         {   // yep, re-enable interrupts
  584.             _enable();
  585.  
  586.         // stop wait loop
  587.         break;
  588.         }
  589.  
  590.         // still have lines of data to write, block thread
  591.         // waiting on a long composed of the virtual address
  592.         // of a piece of our data plus the type of call
  593.         nStatus = HlpBlock( (uint32) &L_qIntServAddr+I_RASTER,
  594.                 qTimeout,
  595.                 0 );
  596.  
  597.         // check unusual (0x0100) or timeout (0x4000) return
  598.         if (    (nStatus & 0x0100) != 0
  599.              || (nStatus & 0x4000) == 0 )
  600.         {   // timeout return, indicate no data written and timeout
  601.         pIkReq->nStatus  = ERR_IK_TIMEOUT;
  602.         pIkReq->qBufUsed = 0;
  603.  
  604.         // clear Interrupt control bit, raster line count
  605.         L_nIntMode    &= ~I_RASTER;
  606.         L_nBufLineCnt  = 0;
  607.  
  608.         // release lock
  609.         HlpUnLock( qLockHandle );
  610.  
  611.         // return to caller
  612.         return;
  613.         }
  614.  
  615.     }
  616.  
  617.     // all raster lines written, clear Interrupt control bit
  618.     L_nIntMode &= ~I_RASTER;
  619.  
  620.     // release client data buffer lock
  621.     HlpUnLock( qLockHandle );
  622.  
  623.     // set status, count for successful completion
  624.     pIkReq->nStatus  = 0;
  625.     pIkReq->qBufUsed = pIkReq->qBufSize;
  626.  
  627.     // return to caller without error
  628.     return;
  629.   }
  630.  
  631. /****************************************************************************
  632.  
  633.     static void _near L_WriteText(    IK_REQ     *pIkReq    )
  634.  
  635.     This function starts output of text data from the pIkReq data.
  636.     The buffer is not considered to be composed of 'lines' of data,
  637.     but is output to the device as one string of data.  Multiple
  638.     lines of data must be indicated by a 'LF' character with the
  639.     data stream.  The IkReq->nBytesPerLine is consequently not used.
  640.  
  641.     A single 'Line Terminate' control will be written at the end
  642.     of the data stream.
  643.  
  644.     Called with:
  645.         pIkReq            ptr to IK_REQ structure
  646.  
  647.     Returns:
  648.         none, returns status in pIkReq
  649.  
  650.         Copyright 1991, Byers Engineering Company
  651. ****************************************************************************/
  652.  
  653. // define function
  654. static void _near L_WriteText(    IK_REQ     *pIkReq    )
  655.  
  656.   {    // define automatics
  657.     int        nStatus;        // Hlp function status
  658.     uint32        qLockHandle;        // client buffer lock
  659.     uint32        qTimeout;        // timeout value
  660.  
  661.     // verify not already busy
  662.     if ( L_nBufLineCnt != 0 )
  663.     {   // whoops, can't start another one yet
  664.         pIkReq->nStatus  = ERR_IK_ALREADY_BUSY;
  665.         pIkReq->qBufUsed = 0;
  666.  
  667.         // return to caller
  668.         return;
  669.     }
  670.  
  671.     // verify params
  672.     if ( pIkReq->qBufSize == 0 )
  673.     {   // can't have empty buffer
  674.         pIkReq->nStatus  = ERR_IK_BAD_PARM;
  675.         pIkReq->qBufUsed = 0;
  676.  
  677.         // return to caller
  678.         return;
  679.     }
  680.  
  681.     // lock the client data buffer (assumes zero offset)
  682.     qLockHandle = HlpLock( FP_SEG(pIkReq->fpcBuf), 0, 0 );
  683.  
  684.     // verify accessibility of text data
  685.     HlpVerifyAccess( pIkReq->fpcBuf,
  686.              (uint16) pIkReq->qBufSize,
  687.              1 );
  688.  
  689.     // get physical address of buffer, set offset to zero
  690.     L_qBufPhyAddr = HlpVirtToPhys( (uint32) pIkReq->fpcBuf );
  691.     L_nBufPhyOff  = 0;
  692.  
  693.     // setup the bytes per line value, indicating only one line
  694.     L_nBufBytesPerLine = (uint16) pIkReq->qBufSize;
  695.  
  696.     // set lines of data count to 1
  697.     L_nBufLineCnt = 1;
  698.  
  699.     // compute timeout value
  700.     qTimeout = (pIkReq->qTimeout == 0)
  701.             ? IK_TIMEOUT_DEFAULT
  702.             : pIkReq->qTimeout;
  703.  
  704.     // block on adaptor being ready to run
  705.     if ( L_WaitReady(qTimeout) != 0 )
  706.     {   // never came ready, set timeout error
  707.         pIkReq->nStatus  = ERR_IK_TIMEOUT;
  708.         pIkReq->qBufUsed = 0;
  709.  
  710.         // unlock the callers data
  711.         HlpUnLock( qLockHandle );
  712.  
  713.         // clear the count in process value
  714.         L_nBufLineCnt = 0;
  715.  
  716.         // return to caller
  717.         return;
  718.     }
  719.  
  720.     // set interrupt mode to text, perform simulated 
  721.     // interrupt to start text data running
  722.     _disable();
  723.     L_nIntMode     |= I_TEXT;
  724.     L_nIntSimulate  = 1;
  725.     L_InterruptService();
  726.     _enable();
  727.  
  728.     // block on text data transfer until interrupt time
  729.     while ( 1 )
  730.     {
  731.         // disable interrupts for check that we are done
  732.         _disable();
  733.  
  734.         // check if the text line written
  735.         if ( L_nBufLineCnt == 0 )
  736.         {   // yep, re-enable interrupts
  737.             _enable();
  738.  
  739.         // stop wait loop
  740.         break;
  741.         }
  742.  
  743.         // still have lines of data to write, block thread
  744.         // waiting on a long composed of the virtual address
  745.         // of a piece of our data plus the type of call
  746.         nStatus = HlpBlock( (uint32) &L_qIntServAddr+I_TEXT,
  747.                 qTimeout,
  748.                 0 );
  749.  
  750.         // check unusual (0x0100) or timeout (0x4000) return
  751.         if (    (nStatus & 0x0100) != 0
  752.              || (nStatus & 0x4000) == 0 )
  753.         {   // timeout return, indicate no data written and timeout
  754.         pIkReq->nStatus  = ERR_IK_TIMEOUT;
  755.         pIkReq->qBufUsed = 0;
  756.  
  757.         // clear Interrupt control bit, raster line count
  758.         L_nIntMode    &= ~I_TEXT;
  759.         L_nBufLineCnt  = 0;
  760.  
  761.         // release lock
  762.         HlpUnLock( qLockHandle );
  763.  
  764.         // return to caller
  765.         return;
  766.         }
  767.  
  768.     }
  769.  
  770.     // all text data written, clear Interrupt control bit
  771.     L_nIntMode &= ~I_TEXT;
  772.  
  773.     // release client data buffer lock
  774.     HlpUnLock( qLockHandle );
  775.  
  776.     // set status, count for successful completion
  777.     pIkReq->nStatus  = 0;
  778.     pIkReq->qBufUsed = pIkReq->qBufSize;
  779.  
  780.     // return to caller without error
  781.     return;
  782.   }
  783.  
  784. /****************************************************************************
  785.  
  786.     static void _near L_WriteMove(    IK_REQ     *pIkReq    )
  787.  
  788.     This function starts output of paper moves from the pIkReq data.
  789.     The paper moves are accomplished by outputting a string of
  790.     Line Terminate control functions.  No data is expected to be
  791.     supplied from the incoming module, except that the number of
  792.     raster lines to move paper is supplied in the nBytesPerLine.
  793.  
  794.     Called with:
  795.         pIkReq            ptr to IK_REQ structure
  796.  
  797.     Returns:
  798.         none, returns status in pIkReq
  799.  
  800.         Copyright 1991, Byers Engineering Company
  801. ****************************************************************************/
  802.  
  803. // define function
  804. static void _near L_WriteMove(    IK_REQ     *pIkReq    )
  805.  
  806.   {    // define automatics
  807.     int        nStatus;        // Hlp function status
  808.     uint32        qLockHandle;        // client buffer lock
  809.     uint32        qTimeout;        // timeout value
  810.  
  811.     // verify not already busy
  812.     if ( L_nBufLineCnt != 0 )
  813.     {   // whoops, can't start another one yet
  814.         pIkReq->nStatus  = ERR_IK_ALREADY_BUSY;
  815.         pIkReq->qBufUsed = 0;
  816.  
  817.         // return to caller
  818.         return;
  819.     }
  820.  
  821.     // verify params
  822.     if ( pIkReq->nBytesPerLine == 0 )
  823.     {   // can't have empty lines to move request
  824.         pIkReq->nStatus  = ERR_IK_BAD_PARM;
  825.         pIkReq->qBufUsed = 0;
  826.  
  827.         // return to caller
  828.         return;
  829.     }
  830.  
  831.     // setup the bytes per line value to zero
  832.     L_nBufBytesPerLine = 0;
  833.  
  834.  
  835.     // set lines of data count from the IkReq->nBytesPerLine field
  836.     L_nBufLineCnt = pIkReq->nBytesPerLine;
  837.  
  838.     // compute timeout value
  839.     qTimeout = (pIkReq->qTimeout == 0)
  840.             ? IK_TIMEOUT_DEFAULT
  841.             : pIkReq->qTimeout;
  842.  
  843.     // block on adaptor being ready to run
  844.     if ( L_WaitReady(qTimeout) != 0 )
  845.     {   // never came ready, set timeout error
  846.         pIkReq->nStatus  = ERR_IK_TIMEOUT;
  847.         pIkReq->qBufUsed = 0;
  848.  
  849.         // unlock the callers data
  850.         HlpUnLock( qLockHandle );
  851.  
  852.         // clear the count in process value
  853.         L_nBufLineCnt = 0;
  854.  
  855.         // return to caller
  856.         return;
  857.     }
  858.  
  859.     // set interrupt mode to Move, perform simulated 
  860.     // interrupt to start move operations running
  861.     _disable();
  862.     L_nIntMode     |= I_MOVE;
  863.     L_nIntSimulate  = 1;
  864.     L_InterruptService();
  865.     _enable();
  866.  
  867.     // block on Move operations until interrupt time
  868.     while ( 1 )
  869.     {
  870.         // disable interrupts for check that we are done
  871.         _disable();
  872.  
  873.         // check if the text line written
  874.         if ( L_nBufLineCnt == 0 )
  875.         {   // yep, re-enable interrupts
  876.             _enable();
  877.  
  878.         // stop wait loop
  879.         break;
  880.         }
  881.  
  882.         // still have lines of data to write, block thread
  883.         // waiting on a long composed of the virtual address
  884.         // of a piece of our data plus the type of call
  885.         nStatus = HlpBlock( (uint32) &L_qIntServAddr+I_MOVE,
  886.                 qTimeout,
  887.                 0 );
  888.  
  889.         // check unusual (0x0100) or timeout (0x4000) return
  890.         if (    (nStatus & 0x0100) != 0
  891.              || (nStatus & 0x4000) == 0 )
  892.         {   // timeout return, indicate no data written and timeout
  893.         pIkReq->nStatus  = ERR_IK_TIMEOUT;
  894.         pIkReq->qBufUsed = 0;
  895.  
  896.         // clear Interrupt control bit, raster line count
  897.         L_nIntMode    &= ~I_MOVE;
  898.         L_nBufLineCnt  = 0;
  899.  
  900.         // release lock
  901.         HlpUnLock( qLockHandle );
  902.  
  903.         // return to caller
  904.         return;
  905.         }
  906.  
  907.     }
  908.  
  909.     // all text data written, clear Interrupt control bit
  910.     L_nIntMode &= ~I_MOVE;
  911.  
  912.     // release client data buffer lock
  913.     HlpUnLock( qLockHandle );
  914.  
  915.     // set status, count for successful completion
  916.     pIkReq->nStatus  = 0;
  917.     pIkReq->qBufUsed = pIkReq->qBufSize;
  918.  
  919.     // return to caller without error
  920.     return;
  921.   }
  922.  
  923. /****************************************************************************
  924.  
  925.     static void _near L_WriteControl(    IK_REQ     *pIkReq    )
  926.  
  927.     This function outputs plotter controls from the pIkReq data.
  928.  
  929.     Called with:
  930.         pIkReq            ptr to IK_REQ structure
  931.  
  932.     Returns:
  933.         none, returns status in pIkReq
  934.  
  935.         Copyright 1991, Byers Engineering Company
  936. ****************************************************************************/
  937.  
  938. // define function
  939. static void _near L_WriteControl(    IK_REQ     *pIkReq    )
  940.  
  941.   {    // define automatics
  942.     uint32        qTimeout;        // timeout value
  943.  
  944.     // verify not already doing this
  945.     if ( L_nBufLineCnt != 0 )
  946.     {   // whoops, can't start another one yet
  947.         pIkReq->nStatus  = ERR_IK_ALREADY_BUSY;
  948.         pIkReq->qBufUsed = 0;
  949.  
  950.         // return to caller
  951.         return;
  952.     }
  953.  
  954.     // verify params
  955.     if ( (pIkReq->nFlags & (  IK_FLAG_C_LT
  956.                     | IK_FLAG_C_EOT
  957.                     | IK_FLAG_C_FF
  958.                     | IK_FLAG_C_CLR)) == 0 )
  959.     {   // can't have empty control flags
  960.         pIkReq->nStatus  = ERR_IK_BAD_PARM;
  961.         pIkReq->qBufUsed = 0;
  962.  
  963.         // return to caller
  964.         return;
  965.     }
  966.  
  967.     // setup the control value
  968.     L_nControlFlags = pIkReq->nFlags;
  969.  
  970.     // compute timeout value
  971.     qTimeout = (pIkReq->qTimeout == 0)
  972.             ? IK_TIMEOUT_DEFAULT
  973.             : pIkReq->qTimeout;
  974.  
  975.     // block on adaptor being ready to run
  976.     if ( L_WaitReady(qTimeout) != 0 )
  977.     {   // never came ready, set timeout error
  978.         pIkReq->nStatus  = ERR_IK_TIMEOUT;
  979.         pIkReq->qBufUsed = 0;
  980.  
  981.         // clear the control values
  982.         L_nControlFlags = 0;
  983.  
  984.         // return to caller
  985.         return;
  986.     }
  987.  
  988.     // note: we do not block from here on, assumption is that
  989.     // if the adaptor is ready, we can start a control operation
  990.     // and then return back to the caller
  991.  
  992.     // set interrupt mode to control, perform simulated 
  993.     // interrupt to start control value running
  994.     _disable();
  995.     L_nIntMode     |= I_CONTROL;
  996.     L_nIntSimulate  = 1;
  997.     L_InterruptService();
  998.     _enable();
  999.  
  1000.     // set status, count for successful completion
  1001.     pIkReq->nStatus  = 0;
  1002.     pIkReq->qBufUsed = pIkReq->qBufSize;
  1003.  
  1004.     // return to caller without error
  1005.     return;
  1006.   }
  1007.  
  1008. /****************************************************************************
  1009.  
  1010.     static int _near L_WaitReady(    uint32    qTimeout    )
  1011.  
  1012.     This function is used to test the adaptor for Ready status, and
  1013.     if not already ready, to enable interrupts and block on the
  1014.     adaptor becoming ready.
  1015.  
  1016.     Called with:
  1017.         qTimeout        max time (msecs) to wait on device
  1018.  
  1019.     Returns:
  1020.         0        adaptor is  ready
  1021.         1            not ready
  1022.  
  1023.         Copyright 1991, Byers Engineering Company
  1024. ****************************************************************************/
  1025.  
  1026. // start function
  1027. static int  _near L_WaitReady(    uint32    qTimeout    )
  1028.  
  1029.   {    // define automatics
  1030.     int        nStatus;        // Block status
  1031.  
  1032.     // check if adaptor (and device) are ready
  1033.     if ( (inp(L_nIoInIstatAddr) & IO_ISTAT_HI_READY) != 0 )
  1034.     {   // is already ready, return to caller, ready status
  1035.         return( 0 );
  1036.     }
  1037.  
  1038.     // not ready, disable interrupts while we
  1039.     // setup the adaptor interrupt control
  1040.     _disable();
  1041.  
  1042.     // enable the adaptor interrupt control
  1043.     outp( L_nIoOutSetupAddr,
  1044.           inp(L_nIoInSetupAddr) | IO_SETUP_HI_INT_ENABLE );
  1045.  
  1046.     // set the simulated interrupt mode to wake us on ready
  1047.     L_nIntMode |= I_READY;
  1048.  
  1049.     // block on ISR addr + Ready status, qTimeout wait
  1050.     // thread will resume with interrupts enabled, either
  1051.     // on timeout, or by HlpRun from Interrupt Service
  1052.     nStatus = HlpBlock( (uint32) &L_qIntServAddr+I_READY,
  1053.                 qTimeout,
  1054.                 0 );
  1055.  
  1056.     // clear wait ready flag
  1057.     L_nIntMode &= ~I_READY;
  1058.  
  1059.     // check status once more (probably potential for race
  1060.     // condition here if more than one thread is allowed
  1061.     // into the driver at a time)
  1062.     if ( (inp(L_nIoInIstatAddr) & IO_ISTAT_HI_READY) != 0 )
  1063.     {   // is ready, return to caller, ready status
  1064.         return( 0 );
  1065.     }
  1066.  
  1067.     // not ready, timed out, return to caller with error
  1068.     return( 1 );
  1069.   }
  1070.  
  1071. /****************************************************************************
  1072.  
  1073.     static void _far L_InterruptService(    void    )
  1074.  
  1075.     This function handles hardware interrupts from the Scanner.
  1076.  
  1077.     Called with:
  1078.         none
  1079.  
  1080.     Returns:
  1081.         none
  1082.  
  1083.         Copyright 1991, Byers Engineering Company
  1084. ****************************************************************************/
  1085.  
  1086. // define function
  1087. static void _far L_InterruptService(    void    )
  1088.  
  1089.   {    // define automatics
  1090.     int        nAdpStat;        // adaptor status value
  1091.  
  1092.     // get adaptor status value
  1093.     nAdpStat = inp( L_nIoInIstatAddr );
  1094.  
  1095.     // if adaptor interrupting, clear it
  1096.     if ( (nAdpStat & IO_ISTAT_HI_INTERRUPT) != 0 )
  1097.     {   // adaptor generated interrupt, clear it
  1098.         outp( L_nIoOutRemoteAddr, IO_REMOTE_HI_RESET_INT );
  1099.     }
  1100.  
  1101.     // if device ready, check active operations
  1102.     // (use 'while' so can use break to stop)
  1103.     while ( (nAdpStat & IO_ISTAT_HI_READY) != 0 )
  1104.     {   // device is ready, do first requested operation
  1105.  
  1106.         // check for Adaptor Ready wait
  1107.         if ( (L_nIntMode & I_READY) != 0 )
  1108.         {   // wanted notification when adaptor ready
  1109.         // release waiting thread (from L_WaitReady())
  1110.         HlpRun( (uint32) &L_qIntServAddr+I_READY );
  1111.  
  1112.         // stop loop, any others must wait
  1113.         break;
  1114.         }
  1115.  
  1116.         // check for Raster Control Lines
  1117.         if (    (L_nIntMode & I_CONTROL) != 0
  1118.              && L_nControlFlags         != 0 )
  1119.         {   // want to output control data
  1120.             L_StartControl();
  1121.  
  1122.         // clear output control data flag
  1123.         L_nIntMode &= ~I_CONTROL;
  1124.  
  1125.         // continue with next entry, device will
  1126.         // still be 'ready' enough to setup for 
  1127.         // Raster, Text, or Move output preparation
  1128.         }
  1129.  
  1130.         // check for Raster Line Output
  1131.         if (    (L_nIntMode & I_RASTER) != 0
  1132.              && L_nBufLineCnt        != 0 )
  1133.         {   // want to output raster data
  1134.         L_StartDma( I_RASTER );
  1135.  
  1136.         // set flag for need Line Terminate control data
  1137.         // at the next interrupt process
  1138.         L_nIntMode     |= I_CONTROL;
  1139.         L_nControlFlags |= IK_FLAG_C_LT;
  1140.  
  1141.         // stop while
  1142.         break;
  1143.         }
  1144.  
  1145.         // check for Text Data Output
  1146.         if (    (L_nIntMode & I_TEXT) != 0
  1147.              && L_nBufLineCnt      != 0 )
  1148.         {   // want to output text data
  1149.         L_StartDma( I_TEXT );
  1150.  
  1151.         // set flag for need Line Terminate control data
  1152.         // at the next interrupt process
  1153.         L_nIntMode     |= I_CONTROL;
  1154.         L_nControlFlags |= IK_FLAG_C_LT;
  1155.  
  1156.         // stop while
  1157.         break;
  1158.         }
  1159.  
  1160.         // check for Move Mode Output
  1161.         if (    (L_nIntMode & I_MOVE) != 0
  1162.              && L_nBufLineCnt      != 0 )
  1163.         {   // want to output move mode data, do so by
  1164.             // setting the Line Terminate Control flag
  1165.         // and performing a L_StartControl()
  1166.         L_nControlFlags |= IK_FLAG_C_LT;
  1167.         L_StartControl();
  1168.  
  1169.         // stop while
  1170.         break;
  1171.         }
  1172.  
  1173.         // all options tested, stop loop
  1174.         break;
  1175.     }
  1176.  
  1177.     // if a Hardware interrupt, acknowledge it in the PIC
  1178.     if ( L_nIntSimulate == 0 )
  1179.     {   // acknowledge interrupt in PIC
  1180.         HlpEOI( L_nIntNum );
  1181.     }
  1182.     else
  1183.     {   // simulated interrupt, clear flag
  1184.         L_nIntSimulate = 0;
  1185.     }
  1186.  
  1187.     // return to caller
  1188.     return;
  1189.   }
  1190.  
  1191. /****************************************************************************
  1192.  
  1193.     static void _near L_StartDma(    int    nRasterFlag    )
  1194.  
  1195.     This function is used to startup a raster mode data transfer from
  1196.     the memory buffer to the adaptor using DMA.
  1197.  
  1198.     Note:
  1199.     This module assumes that interrupts have been disabled before
  1200.     calling.  This assumption is necessary during manipulation of
  1201.     the DMA channel registers.
  1202.  
  1203.     This module also assumes that the adaptor is in a ready state.
  1204.  
  1205.     Called with:
  1206.         nRasterFlag        I_RASTER for raster mode data
  1207.                     I_TEXT   for text   mode data
  1208.  
  1209.     Returns:
  1210.         none
  1211.  
  1212.         Copyright 1991, Byers Engineering Company
  1213. ****************************************************************************/
  1214.  
  1215. // start function
  1216. static void _near L_StartDma(    int    nRasterFlag    )
  1217.  
  1218.   {    // define automatics
  1219.     uint16        nDmaCnt;        // dma output count
  1220.     uint32        qPhyAddr;        // dma physical buffer loc
  1221.  
  1222. //DEBUG, need to handle various byte orders in buffered data
  1223. //     and the swap mode and dma channel (word or byte) 
  1224. //     that the adaptor is using
  1225.  
  1226.     // Note: It is assumed that the Adaptor and Device are 'ready'
  1227.     // at this point.
  1228.  
  1229.     // set plotter into proper mode (PLOT or TEXT)
  1230.     if ( nRasterFlag == I_RASTER )
  1231.     {   // raster mode, set PLOT bit
  1232.         outp( L_nIoOutSetupAddr,
  1233.               inp(L_nIoInSetupAddr) | IO_SETUP_HI_PLOT_MODE );
  1234.     }
  1235.     else
  1236.     {   // text mode, reset PLOT bit
  1237.         outp( L_nIoOutSetupAddr,
  1238.               inp(L_nIoInSetupAddr) & ~IO_SETUP_HI_PLOT_MODE );
  1239.     }
  1240.  
  1241.     //******************
  1242.     // setup DMA channel
  1243.     //******************
  1244.  
  1245.     // disable DMA channel operation
  1246.     outp( L_Dma.nAdrMask,    L_Dma.nValSet    );
  1247.  
  1248.     // set DMA mode to READ MEMORY
  1249.     outp( L_Dma.nAdrMode,    L_Dma.nValMode    );
  1250.  
  1251.     // calc physical address of buffer, update offset for next buffer
  1252.     qPhyAddr       = L_qBufPhyAddr + L_nBufPhyOff;
  1253.     L_nBufPhyOff += L_nBufBytesPerLine;
  1254.  
  1255.     // setup DMA buffer address in WORD mode
  1256.     // it looks screwy:
  1257.     //    1. reset logic
  1258.     //    2. output lo byte of hi 16 bits
  1259.     //    3. output lo byte of (phy addr divided by 2) (words)
  1260.     //    4. output hi byte of lo 16 bit (phy addr divided by 2)
  1261.     outp( L_Dma.nAdrReset,    0 );
  1262.     outp( L_Dma.nAdrPage,    (uint8) ((qPhyAddr >> 16) & 0xff) );
  1263.     outp( L_Dma.nAdrOff,    (uint8) ((qPhyAddr >>  1) & 0xff) );
  1264.     outp( L_Dma.nAdrOff,    (uint8) ((qPhyAddr >>  9) & 0xff) );
  1265.  
  1266.     // set DMA transfer count (cnt is 1 less than desired moves in words)
  1267.     nDmaCnt = (L_nBufBytesPerLine >> 1) - 1;
  1268.     outp( L_Dma.nAdrCnt, (uint8) ( nDmaCnt       & 0xff) );
  1269.     outp( L_Dma.nAdrCnt, (uint8) ((nDmaCnt >> 8) & 0xff) );
  1270.  
  1271.     // start DMA operation
  1272.     outp( L_Dma.nAdrMask,     L_Dma.nValReset );
  1273.  
  1274.     // start IKON dma mode with adaptor interrupts enabled
  1275.     // in the current PLOT or TEXT mode
  1276.     outp( L_nIoOutSetupAddr,
  1277.           inp(L_nIoInSetupAddr) 
  1278.           | IO_SETUP_HI_DMA_ENABLE
  1279.           | IO_SETUP_HI_INT_ENABLE );
  1280.  
  1281.     // return to caller
  1282.     return;
  1283.   }
  1284.  
  1285. /****************************************************************************
  1286.  
  1287.     static void _near L_StartControl(    void    )
  1288.  
  1289.     This function is used to startup a Control Mode output to the
  1290.     plotter, primarily Line Terminate, Form Feed, etc.
  1291.  
  1292.     Called with:
  1293.         none
  1294.  
  1295.     Returns:
  1296.         none
  1297.  
  1298.         Copyright 1991, Byers Engineering Company
  1299. ****************************************************************************/
  1300.  
  1301. // start function
  1302. static void _near L_StartControl(    void    )
  1303.  
  1304.   {
  1305.     // Note: It is assumed that the Adaptor and Device are 'ready'
  1306.     // at this point.
  1307.  
  1308.     // output control flag word to port
  1309.     outp( L_nIoOutRemoteAddr, 
  1310.           L_nControlFlags & (  IK_FLAG_C_LT
  1311.                        | IK_FLAG_C_EOT
  1312.                  | IK_FLAG_C_FF
  1313.                  | IK_FLAG_C_CLR ) );
  1314.  
  1315.     // test if LT set and Line Count not zero
  1316.     if (    (L_nControlFlags & IK_FLAG_C_LT) != 0
  1317.          && L_nBufLineCnt              > 0 )
  1318.     {   // yep, must be completing an output line, adjust count
  1319.         L_nBufLineCnt--;
  1320.  
  1321.         // if raster line count now zero, need to unblock thread
  1322.         if ( L_nBufLineCnt == 0 )
  1323.         {   // yep, it is waiting, release the proper thread
  1324.         // note that only one of the following three should 
  1325.         // actually be set at a time
  1326.  
  1327.         // test for Raster mode output
  1328.             if ( (L_nIntMode & I_RASTER) != 0 )
  1329.         {   // raster mode threads
  1330.             HlpRun( (uint32) &L_qIntServAddr+I_RASTER );
  1331.         }
  1332.  
  1333.         // test for Text mode output
  1334.             if ( (L_nIntMode & I_TEXT) != 0 )
  1335.         {   // text mode threads
  1336.             HlpRun( (uint32) &L_qIntServAddr+I_TEXT );
  1337.         }
  1338.  
  1339.         // test for Move mode output
  1340.             if ( (L_nIntMode & I_MOVE) != 0 )
  1341.         {   // move mode threads
  1342.             HlpRun( (uint32) &L_qIntServAddr+I_MOVE );
  1343.         }
  1344.         }
  1345.     }
  1346.  
  1347.     // clear the control flag word bits
  1348.     L_nControlFlags &= ~(  IK_FLAG_C_LT
  1349.                        | IK_FLAG_C_EOT
  1350.                  | IK_FLAG_C_FF
  1351.                  | IK_FLAG_C_CLR );
  1352.  
  1353.     // return to caller
  1354.     return;
  1355.   }
  1356.  
  1357. /****************************************************************************
  1358.  
  1359.     static void _near L_InitAdaptor( IK_REQ *pIkReq    )
  1360.  
  1361.     This function performs initialization of the Vidar Adaptor.  It
  1362.     expects the I/O Port to be defined in the IK_CFG_PARM structure 
  1363.     pointed to by the IK_REQ.  If an Ikon adaptor appears to be at
  1364.     the appropriate address, it will fill in the Interrupt and DMA
  1365.     members of the caller's IK_CFG_PARM structure.
  1366.  
  1367.     Called with:
  1368.         pIkReq        ptr to IK_REQ structure
  1369.         none
  1370.  
  1371.     Returns:
  1372.         none, errors returned to pIkReq->nStatus
  1373.  
  1374.         Copyright 1991, Byers Engineering Company
  1375. ****************************************************************************/
  1376.  
  1377. // define function
  1378. static void _near L_InitAdaptor( IK_REQ *pIkReq    )
  1379.  
  1380.   {    // define automatics
  1381.     int        nStrap;            // adaptor strapping values
  1382.  
  1383.     // extract I/O, precompute adaptor port addresses
  1384.     L_nIoBase       = ((IK_CFG_PARM *) (pIkReq->fpcBuf))->nIoPort;
  1385.     L_nIoOutSetupAddr  = L_nIoBase + IO_OUT_SETUP_OFF;
  1386.     L_nIoOutRemoteAddr = L_nIoBase + IO_OUT_REMOTE_OFF;
  1387.     L_nIoOutDataAddr   = L_nIoBase + IO_OUT_DATA_OFF;
  1388.     L_nIoInSetupAddr   = L_nIoBase + IO_IN_SETUP_OFF;
  1389.     L_nIoInIstatAddr   = L_nIoBase + IO_IN_ISTAT_OFF;
  1390.     L_nIoInDiagAddr       = L_nIoBase + IO_IN_DIAG_OFF;
  1391.     L_nIoInSetupAddr   = L_nIoBase + IO_IN_SETUP_OFF;
  1392.     L_nIoInStrapAddr   = L_nIoBase + IO_IN_STRAP_OFF;
  1393.  
  1394.     // reset adaptor interface logic
  1395.     outp( L_nIoOutRemoteAddr, IO_REMOTE_HI_RESET_ADP );
  1396.  
  1397.     // verify latched function register is all zero
  1398.     // the previous reset adaptor should have cleared it
  1399.     if ( inp(L_nIoInSetupAddr) != 0 )
  1400.     {   // nope, must not be an IKON card!
  1401.         // so set status error indicator
  1402.         pIkReq->nStatus = ERR_IK_NO_ADAPTOR;
  1403.  
  1404.         // and return to caller
  1405.         return;
  1406.     }
  1407.  
  1408.     // get Interrupt, DMA channels from ports on card
  1409.     nStrap    = inp( L_nIoInStrapAddr );
  1410.     L_nIntNum = (nStrap & IO_STRAP_INT_MASK) >> IO_STRAP_INT_SHIFT;
  1411.     L_nDmaNum = (nStrap & IO_STRAP_DMA_MASK) >> IO_STRAP_DMA_SHIFT;
  1412.  
  1413.     // tell caller what we found
  1414.     ((IK_CFG_PARM *) (pIkReq->fpcBuf))->nInterrupt = L_nIntNum;
  1415.     ((IK_CFG_PARM *) (pIkReq->fpcBuf))->nDma       = L_nDmaNum;
  1416.  
  1417.     // setup the DMA access control structure
  1418.     memcpy( &L_Dma, &L_DmaVals[L_nDmaNum], sizeof(L_Dma) );
  1419.  
  1420.     // allocate an interrupt vector
  1421.     if ( HlpSetIRQ( (uint16) L_qIntServAddr,
  1422.             L_nIntNum,
  1423.             0 ) != 0 )
  1424.     {   // unable to allocate interrupt vector, return error
  1425.         pIkReq->nStatus = ERR_IK_BAD_INTERRUPT;
  1426.         return;
  1427.     }
  1428.  
  1429.     // interrupt allocated, set flag
  1430.     L_nIntInUse = 1;
  1431.  
  1432.     // no errors, clear status
  1433.     pIkReq->nStatus = 0;
  1434.  
  1435.     // return to caller
  1436.     return;
  1437.   }
  1438.  
  1439. /****************************************************************************
  1440.  
  1441.     static void _near L_ReqClose(    DRV_REQ *pDrvReq    )
  1442.  
  1443.     This function performs termination of the Vidar Adaptor.
  1444.  
  1445.     Called with:
  1446.         pDrvReq        ptr to Driver Request Pkt
  1447.  
  1448.     Returns:
  1449.         none
  1450.  
  1451.         Copyright 1991, Byers Engineering Company
  1452. ****************************************************************************/
  1453.  
  1454. // define function
  1455. static void _near L_ReqClose(    DRV_REQ *pDrvReq    )
  1456.  
  1457.   {
  1458.     // disable interrupts at the adaptor
  1459.     outp( L_nIoOutSetupAddr,
  1460.           inp(L_nIoInSetupAddr) & ~IO_SETUP_HI_INT_ENABLE );
  1461.  
  1462.     // if in use, terminate interrupt vector
  1463.     if ( L_nIntInUse == 1 )
  1464.     {   // yep, release it
  1465.         HlpUnSetIRQ( L_nIntNum );
  1466.  
  1467.         // clear the flag
  1468.         L_nIntInUse = 0;
  1469.     }
  1470.  
  1471.     // return to caller
  1472.     return;
  1473.   }
  1474.  
  1475. /***************************************************************************/
  1476. /***************************************************************************/
  1477. /***************************************************************************/
  1478. /****************************************************************************
  1479.  
  1480.     static void _near     L_LastCode(    void    )
  1481.  
  1482.     This function serves the purpose of marking the end of the
  1483.     code which should be included in the _TEXT segment.  Functions
  1484.     placed in the _TEXT segment after this point (and also defined
  1485.     in the 'alloc_text' pragma) will be discarded after 'init' time.
  1486.  
  1487.     Called with:
  1488.         none
  1489.  
  1490.     Returns:
  1491.         none
  1492.  
  1493.         Copyright 1991, Byers Engineering Company
  1494. ****************************************************************************/
  1495.  
  1496. // define function
  1497. static void _near     L_LastCode(    void    )
  1498.  
  1499.   {
  1500.     // return to caller
  1501.     return;
  1502.   }
  1503.  
  1504. /****************************************************************************
  1505.  
  1506.     static void _near L_ReqInit( DRV_REQ *pDrvReq    )
  1507.  
  1508.     This function performs config.sys load time driver initialization.
  1509.     It is code that can be discarded after initialization.
  1510.  
  1511.     Called with:
  1512.         pDrvReq        ptr to Driver Request Pkt
  1513.  
  1514.     Returns:
  1515.         none
  1516.  
  1517.         Copyright 1991, Byers Engineering Company
  1518. ****************************************************************************/
  1519.  
  1520. // define function
  1521. static void _near L_ReqInit( DRV_REQ *pDrvReq    )
  1522.  
  1523.   {    // define automatics
  1524.     uint16        nWrLen;            // DosWrite length
  1525.  
  1526.     // save DevHlp address
  1527.     Drv_qDevHlpAddr = pDrvReq->Init.In.qDevHlpAddr;
  1528.  
  1529.     // save code and data offset values in request header
  1530.     pDrvReq->Init.Out.nCodeEnd = (uint16) &L_LastCode;
  1531.     pDrvReq->Init.Out.nDataEnd = (uint16) &L_LastData;
  1532.  
  1533.     // init the Bpb address field
  1534.     pDrvReq->Init.Out.qBpbAddr = 0;
  1535.  
  1536.     // display driver signon
  1537.     DosWrite( 1,
  1538.               &L_acMsg[0],
  1539.           sizeof(L_acMsg),
  1540.           &nWrLen );
  1541.  
  1542.     // register our interrupt stack usage
  1543.     HlpRegisterStack( (uint16) &L_RegStack );
  1544.  
  1545.     // return to caller
  1546.     return;
  1547.   }
  1548.