/*static char *SCCSID = "@(#)monio.c    6.6 92/01/31";*/

#define INCL_NOXLATE_DOS16
#define INCL_ERRORS
#define INCL_16
#define INCL_DOSINFOSEG
#define INCL_OS2STD

#include <os2def16.h>
#include <bsedos16.h>
#include <drt.h>
#include <bseerr.h>
#include <moncalls.h>



#ifdef MMIOPH
   #include        <infoseg.h>
   #include        <perfhook.h>

    void Mon_Sys_Trace( USHORT mon_major_code,
                            USHORT mon_minor_code,
                            USHORT mon_data_len,
                            char far *mon_data);

    extern struct  InfoSegGDT far  *globptr;

#endif //MMIOPH

extern pascal ENTER_DLL_CONFORM(void);
extern pascal EXIT_DLL_CONFORM(unsigned int);

extern USHORT ValidAddr( PBYTE pbDataBuf);
extern void force_a_fault(VOID);


extern FAR DOS32IMONWRITE( PBYTE pbOutBuf,      /* IMPORT from DOSCALL1 - MDLL*/
                                   PBYTE pbDataBuf,
                                   ULONG cbData);
extern FAR DOS32IMONREAD( PBYTE pbInBuf,        /* IMPORT from DOSCALL1 - MDLL*/
                                  ULONG fWait,
                                  PBYTE pbDataBuf,
                                  PUSHORT pcbData);


//****************** START OF SPECIFICATIONS *******************
//
// SUBROUTINE NAME:  DosMonRead
//
// DESCRIPTIVE NAME:  Read data to a monitor structure.
//
// FUNCTION: DosMonRead is a stub routine that calls Dos32IMonRead
//           (kernel worker routine) which will read a data packet from
//           the previous monitor in the chain.
//
// NOTES: This is a 16-bit PROTECT MODE ONLY API - part of
//        the MONCALLS dynamic link package, provided as
//        the interface between monitors and device drivers.
//
//        A monitor can read only from an input buffer ALREADY
//        registered to an OPENED device.
//
//        Pre- & Post- Invocation of trace occurs only if
//        trace is 'on' for monitor API.
//
//
// ENTRY POINT:  DosMonRead
//    LINKAGE:  FAR CALL
//
// INPUT:
//
//         pbInBuff = 16:16 selector/offset address of input
//                     buffer in calling process' address space.
//                     This is only used as a handle.
//
//         fWait    = Block/Run indicator (=0 if to block until
//                    input is ready; =1, if to return if no
//                    input is ready).
//
//         pbDataBuf  = 16:16 selector/offset address of
//                       private data area in calling process'
//                       address space.
//
//         pcbdata  = 16:16 address of the word containing size
//                     of the private data area.
//
//
// EXIT-NORMAL:  AX = 0
//
// EXIT-ERROR:   AX <> 0; AX = error code:
//                             ERROR_MON_BUFFER_EMPTY
//                             ERROR_MON_BUFFER_TOO_SMALL
//                             ERROR_MON_INVALID_PARMS
//
// EFFECTS:  Contents of AX register altered.
//           Number of bytes actually written into private
//           data area returned at @Bytecnt.
//
// INTERNAL REFERENCES:
//          Mon_Sys_Trace
//          force_a_fault
//          ValidAddr
//
// EXTERNAL REFERENCES:
//          Dos32IMonRead (Call gate to Ring 0 worker)
//
//****************** END OF SPECIFICATIONS *********************

APIRET  APIENTRY DosMonRead(pbInBuf, fWait, pbDataBuf, pcbData)

PBYTE pbInBuf;
USHORT fWait;
PBYTE pbDataBuf;
PUSHORT pcbData;

   {
   register USHORT rc; // Make rc a register var for trace points.
   ENTER_DLL_CONFORM();    /* save registers */

   rc = 0;

#ifdef MMIOPH
   Mon_Sys_Trace((USHORT) 0x60,
                 (USHORT) 0x07,
                 (USHORT) 2,
                 (char far *) pcbData);
#endif /* MMIOPH */

/***DT  DOSMONREAD - Read moniter
 *
 *   TRACE MINOR = 0x0203,
 *         TP    = @
 *         TYPE  = (PRE,API),
 *         GROUP = TSK,
 *         DESC  = "(OS) DosMonRead Pre_Invocation",
 *         FMT   = " Input buffer address = %pa  Wait flag = %pw",
 *         FMT   = " Data buffer address = %pa   Byte count = %pw",
 *         MEM   = (.pbInBuf,DIRECT,4),
 *         MEM   = (.fWait,DIRECT,2),
 *         MEM   = (.pbDataBuf,DIRECT,4),
 *         MEM   = (.pcbData,INDIRECT,2)
 */

   if (!(ValidAddr(pbDataBuf)) || !(ValidAddr((PBYTE)pcbData)))
       // No need to check pbInBuf, we only use it as a handle, not sel:off
      {
      force_a_fault();
      }
   else
      {
      if (MYERROR_FORCE_A_FAULT == (rc = DOS32IMONREAD(pbInBuf,
                                                       (ULONG)fWait,
                                                       pbDataBuf,
                                                       pcbData)))
         {
         force_a_fault();
         }
      }
#ifdef MMIOPH
   Mon_Sys_Trace((USHORT) 0x60,
                 (USHORT) 0x87,
                 (USHORT) 2,
                 (char far *) pcbData);
#endif /* MMIOPH */

/***DT  DOSMONREAD - Read moniter
 *
 *   TRACE MINOR = 0x8203,
 *         TP    = @
 *         TYPE  = (POST,API),
 *         GROUP = TSK,
 *         DESC  = "(OS) DosMonRead Post_Invocation",
 *         FMT   = " Return code = %w  Byte count = %pw  Data = %r %b",
 *         REGS  = (.rc),
 *         MEM   = (.pcbData,INDIRECT,2),
 *         MEM   = (.pbDataBuf,INDIRECT,10)
 */
   return(EXIT_DLL_CONFORM(rc));
   }


//****************** START OF SPECIFICATIONS *******************
//
// SUBROUTINE NAME:  DosMonWrite
//
// DESCRIPTIVE NAME:  Write data to a monitor structure.
//
// FUNCTION: DosMonWrite is a stub routine that calls Dos32IMonWrite
//           (kernel worker routine) which will pass a data packet to
//           the next monitor in the chain.
//
// NOTES: This is a 16-bit PROTECT MODE ONLY API - part of
//        the MONCALLS dynamic link package, provided as
//        the interface between monitors and device drivers.
//
//           A monitor cannot write a datapacket into its output
//        buffer (i.e., into the monitor chain data stream)
//        that is larger than the min_buffer size for the
//        buffers in the monitor chain (i.e., the size of
//        the device driver buffer).
//
//        A monitor can write only to an output buffer ALREADY
//        registered to an OPENED device.
//
//        Pre- & Post- Invocation of trace occurs only if
//        trace is 'on' for monitor API.
//
// ENTRY POINT:  DosMonWrite
//    LINKAGE:  FAR CALL
//
// INPUT:  (from user's stack)
//
//         pbOutBuf  = 16:16 selector/offset address of output buffer in
//                      calling process' address space. We simply use this
//                      value as a "handle", we never write into this buffer.
//
//         pbDataBuf = 16:16 selector/offset address of private data area
//                       in calling process's address space.
//
//         cbData    = number of bytes to write from databuffer
//
// EXIT-NORMAL:  AX = 0
//
// EXIT-ERROR:   AX <> 0; AX = error code:
//                             ERROR_MON_DATA_TOO_LARGE
//                             ERROR_MON_INVALID_PARMS
//                             ERROR_NOT_ENOUGH_MEMORY
//
// EFFECTS:  Contents of AX register altered.
//
// INTERNAL REFERENCES:
//          Mon_Sys_Trace
//          force_a_fault
//          ValidAddr
//
// EXTERNAL REFERENCES:
//          Dos32IMonWrite (Call gate to Ring 0 worker)
//
//****************** END OF SPECIFICATIONS *********************

APIRET  APIENTRY DosMonWrite(pbOutBuf, pbDataBuf, cbData)

PBYTE pbOutBuf;
PBYTE pbDataBuf;
USHORT cbData;

   {
   register USHORT rc; // Make rc a register var for trace points.
   ENTER_DLL_CONFORM();    /* save registers */

   rc = 0;

#ifdef MMIOPH
   Mon_Sys_Trace((USHORT) 0x60,
                 (USHORT) 0x08,
                 (USHORT) 2,
                 (char far *) &cbData);
#endif /* MMIOPH */

/***DT  DOSMONWRITE - Write moniter
 *
 *   TRACE MINOR = 0x0205,
 *         TP    = @
 *         TYPE  = (PRE,API),
 *         GROUP = TSK,
 *         DESC  = "(OS) DosMonWrite Pre_Invocation",
 *         FMT   = " Output buffer address = %pa  Data buffer address = %pa",
 *         FMT   = " Byte count = %pw  Data = %r %b",
 *         MEM   = (.pbOutBuf,DIRECT,4),
 *         MEM   = (.pbDataBuf,DIRECT,4),
 *         MEM   = (.cbData,DIRECT,2),
 *         MEM   = (.pbDataBuf,INDIRECT,10)
 */

   if ( (!(ValidAddr(pbDataBuf))) || (cbData == 0))
      // No need to check pbOutBuf, we only use it as a handle, not Sel:Off
      {
      rc = ERROR_MON_INVALID_PARMS;
      }
   else
      {
      if (MYERROR_FORCE_A_FAULT == (rc = DOS32IMONWRITE(pbOutBuf,
                                                       pbDataBuf,
                                                       (ULONG)cbData)))
         {
         force_a_fault();
         }
      }
#ifdef MMIOPH
   Mon_Sys_Trace((USHORT) 0x60,
                 (USHORT) 0x88,
                 (USHORT) 0,
                 (char far *) NULL);
#endif /* MMIOPH */

/***DT  DOSMONWRITE - Write moniter
 *
 *   TRACE MINOR = 0x8205,
 *         TP    = @
 *         TYPE  = (POST,API),
 *         GROUP = TSK,
 *         DESC  = "(OS) DosMonWrite Post_Invocation",
 *         FMT   = " Return code = %w",
 *         REGS  = (.rc)
 */
   return(EXIT_DLL_CONFORM(rc));
   }




#if defined(MMIOPH)

/********************** START OF SPECIFICATIONS ********************
*
* SUBROUTINE NAME:    Mon_Sys_Trace
*
* DESCRIPTIVE NAME:   MONCALLS System Trace
*
* FUNCTION:   Writes RAS Trace information to appropriate place
*
* NOTES:  This should be in the same segment as the (performance
*         critical) DosMonRead and DosMonWrite routines.
*
* ENTRY POINT:        Mon_Sys_Trace
*    LINKAGE:         ?
*
* INPUT:
*       mon_major_code = Major Event code for monitors
*       mon_minor_code = minor event code
*       mon_data_len   = length of data to trace
*       mon_data       = far pointer to data
*
*
* EXIT-NORMAL: VOID
*
* EXIT-ERROR:  VOID
*
* EFFECTS:
*
* INTERNAL REFERENCES:
*
* EXTERNAL REFERENCES:
*
*********************** END OF SPECIFICATIONS *********************/

void Mon_Sys_Trace(mon_major_code, mon_minor_code, mon_data_len, mon_data)
USHORT mon_major_code;
USHORT mon_minor_code;
USHORT mon_data_len;
char far *mon_data;

{
  // extern  struct  InfoSegGDT far  *globptr;
  struct Dekko_Addr far *base_addr;
  // Are we suppose to send stuff out the dekko port?
    if (TEST_TRACING((*globptr).mec_table,mon_major_code))
     {
     SELECTOROF(base_addr) = (*globptr).MMIOBase;
     OFFSETOF(base_addr) = 0;
     (*base_addr).majmin_code = ((mon_major_code << 8) + mon_minor_code);
     for (;mon_data_len > 1 ;mon_data_len -= 2)
         {
         (*base_addr).perf_data = *((unsigned far *)mon_data)++;
         }
     if (mon_data_len == 1)
        {
        (*base_addr).perf_data = *mon_data;
        } /* endif */
     }
return;
}

#endif //MMIOPH

