/*
// ExtCalls.c
//
// This file contains code used for executing different HID.DLL functions.  It
//   is a debug only mechanism which uses the DEBUG memory allocation/verification
//   routines in debug.c.  
//
// These functions begin by allocating debug buffers for any input or output buffers
//    that are passed to the corresponding HID.DLL functions.  It then calls the
//    the HidX_Xxx function.  Upon return, it validates any of the report buffers
//    that were setup by before the call and copies the results back to the 
//    buffers if necessary.  The functions also attempt to detect any other errors
//    that may be specific to the given HID.DLL function.  
//
// When examining this implementation along with the routines that use these calls 
//    in the Hclient, it is obvious that sometimes debug buffers are allocated more
//    than once.  This can lead to some confusion as to why this occurs.  The original
//    goal of these ExtCall_ routines was to be able to extract them for debug versions
//    of other client code.  The redundancy in buffer validation is not necessary but
//    does provide another layer of protection.
*/

#ifndef DEBUG
   #define DEBUG
#endif

/*****************************************************************************
/* ExtCalls include files
/*****************************************************************************/
#include <windows.h>
#include <string.h>
#include <limits.h>
#include <setupapi.h>
#include <assert.h>
#include "hid.h"
#include "hidsdi.h"
#include "extcalls.h"
#include "debug.h"


/*****************************************************************************
/* ExtCalls macro definitions for misc. features
/*****************************************************************************/
#define OUTSTRING(win, str)         SendMessage(win, LB_ADDSTRING, 0, (LPARAM) str)
#define STATUS_STRING(str, status)  wsprintf(str, "Status: %s", ExtCalls_GetHidAppStatusString(status))
#define ROUND_TO_NEAREST_BYTE(val)  (((val) % 8) ? ((val) / 8) + 1 : ((val) / 8))

/*****************************************************************************
/* ExtCalls macro definitions setting up and validating buffers
/*****************************************************************************/
#define SETUP_INPUT_BUFFER(tbuf, rbuf, len, funcname, status) \
       { \
            (PCHAR) (tbuf) = (PCHAR) ALLOC((len)); \
            if (NULL == (tbuf)) { \
                wsprintf(szTempBuffer, \
                         "EXTCALLS.C: Memory alloc error - cannot verify %s call", \
                         (funcname) \
                        ); \
                DEBUG_OUT(szTempBuffer); \
                (PCHAR) (tbuf) = (PCHAR) (rbuf); \
           } \
           status = TRUE; \
       }

#define SETUP_OUTPUT_BUFFER(tbuf, rbuf, len, funcname, status) \
       { \
            (PCHAR) (tbuf) = (PCHAR) ALLOC((len)); \
            if (NULL == (tbuf)) { \
                wsprintf(szTempBuffer, \
                         "EXTCALLS.C: Memory alloc error - cannot verify %s call", \
                         (funcname) \
                        ); \
                DEBUG_OUT(szTempBuffer); \
                (PCHAR) (tbuf) = (PCHAR) (rbuf); \
            } \
            else { \
                memcpy((tbuf), (rbuf), (len)); \
            } \
            status = TRUE; \
       }
         
#define VERIFY_INPUT_BUFFER(tbuf, rbuf, len, status) \
       { \
           if ((PCHAR) (tbuf) != (PCHAR) (rbuf)) { \
               status = (status) && (VALIDATEMEM((tbuf))); \
               memcpy((rbuf), (tbuf), (len));  \
               FREE((tbuf)); \
           } \
       } 

#define VERIFY_OUTPUT_BUFFER(tbuf, rbuf, len, status) \
       { \
           if ((PCHAR) (tbuf) != (PCHAR) (rbuf)) { \
               status = (status) && (VALIDATEMEM((tbuf))); \
               FREE((tbuf)); \
           } \
       } 


/*****************************************************************************
/* ExtCalls macro definitions for setting up the status structures
/*****************************************************************************/
#define SET_HIDD_STATUS(pStatusStruct, IsError, AllocStatus) \
       { \
           pStatusStruct -> IsHidError      = IsError; \
           pStatusStruct -> IsHidDbgWarning = FALSE; \
           pStatusStruct -> IsHidDbgError   = !AllocStatus; \
         \
           if (!AllocStatus) { \
               pStatus -> HidDbgErrorCode = HID_DBG_ERROR_CORRUPTED_BUFFER; \
           } \
      }
       
#define SET_HIDP_STATUS(pStatusStruct, CallStatus, AllocStatus) \
       { \
           pStatusStruct -> IsHidError = (HIDP_STATUS_SUCCESS != CallStatus); \
           pStatusStruct -> HidErrorCode = CallStatus; \
         \
           pStatusStruct -> IsHidDbgError   = !AllocStatus; \
         \
           if (!AllocStatus) { \
               pStatus -> HidDbgErrorCode = HID_DBG_ERROR_CORRUPTED_BUFFER; \
           } \
           pStatusStruct -> IsHidDbgWarning = FALSE; \
      }
            

#define TEMP_BUFFER_SIZE 1024

static CHAR             szTempBuffer[TEMP_BUFFER_SIZE];

VOID 
ExtCalls_HidD_FlushQueue(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    pStatus -> IsHidError      = !HidD_FlushQueue(pParams -> DeviceHandle);
    pStatus -> IsHidDbgError   = FALSE;
    pStatus -> IsHidDbgWarning = FALSE;

    return;
}

VOID
ExtCalls_HidD_GetHidGuid(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    LPGUID  pGuid;
    BOOL    AllocStatus;

    SETUP_INPUT_BUFFER(pGuid,
                       pParams -> List,
                       sizeof(GUID),
                       "HidD_GetHidGuid",
                       AllocStatus
                      );
                       
    HidD_GetHidGuid(pGuid);

    VERIFY_INPUT_BUFFER(pGuid,
                        pParams -> List,
                        sizeof(GUID),
                        AllocStatus
                       );
    
    SET_HIDD_STATUS(pStatus, 
                    FALSE,
                    AllocStatus
                   );

    return;
}
    
VOID
ExtCalls_HidD_GetPreparsedData(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    BOOL                       IsHidError;

    IsHidError = !HidD_GetPreparsedData(pParams -> DeviceHandle,
                                        pParams -> ppPd                  
                                       );

    SET_HIDD_STATUS(pStatus,
                    IsHidError,
                    TRUE
                   );
    return;
}

VOID
ExtCalls_HidD_FreePreparsedData(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    BOOL                       IsHidError;

    ASSERT(NULL != pParams -> Ppd);
    
    IsHidError = !HidD_FreePreparsedData(pParams -> Ppd);

    SET_HIDD_STATUS(pStatus,
                    IsHidError,
                    TRUE
                   );

    return;
}

VOID
ExtCalls_HidD_GetAttributes(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    BOOL             IsHidError;
    BOOL             AllocStatus;
    PCHAR            pHidAttrib;   

    SETUP_INPUT_BUFFER(pHidAttrib, 
                       pParams -> List,
                       sizeof(HIDD_ATTRIBUTES),
                       "HidD_GetAttributes",
                       AllocStatus
                      );

    IsHidError = !HidD_GetAttributes(pParams -> DeviceHandle,
                                     (PHIDD_ATTRIBUTES) pHidAttrib
                                    );

    VERIFY_INPUT_BUFFER(pHidAttrib,
                        pParams -> List,
                        sizeof(HIDD_ATTRIBUTES),
                        AllocStatus
                       );

    SET_HIDD_STATUS(pStatus,
                    IsHidError,
                    AllocStatus
                   );
    return;
}

VOID
ExtCalls_HidD_GetFeature(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    BOOL   IsHidError;
    PCHAR  TestBuffer;
    BOOL   AllocStatus;

    SETUP_OUTPUT_BUFFER(TestBuffer,
                       pParams -> ReportBuffer, 
                       pParams -> ReportLength,
                       "HidD_GetFeature",
                       AllocStatus
                      );

    IsHidError = !HidD_GetFeature(pParams -> DeviceHandle,
                                  TestBuffer,
                                  pParams -> ReportLength
                                 );

    VERIFY_INPUT_BUFFER(TestBuffer,
                        pParams -> ReportBuffer, 
                        pParams -> ReportLength,
                        AllocStatus
                       );

    SET_HIDD_STATUS(pStatus,
                    IsHidError,
                    AllocStatus
                   );
    return;
}

VOID
ExtCalls_HidD_SetFeature(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    BOOL   IsHidError;
    PCHAR  TestBuffer;
    BOOL   AllocStatus;

    SETUP_OUTPUT_BUFFER(TestBuffer,
                        pParams -> ReportBuffer, 
                        pParams -> ReportLength,
                        "HidD_SetFeature",
                        AllocStatus
                       );

    IsHidError = !HidD_SetFeature(pParams -> DeviceHandle,
                                  TestBuffer,
                                  pParams -> ReportLength
                                 );

    VERIFY_OUTPUT_BUFFER(TestBuffer,
                         pParams -> ReportBuffer, 
                         pParams -> ReportLength,
                         AllocStatus
                        );

    SET_HIDD_STATUS(pStatus,
                    IsHidError,
                    AllocStatus
                   );

    return;
}

VOID
ExtCalls_HidD_GetNumInputBuffers(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    BOOL     IsHidError;

    IsHidError = !HidD_GetNumInputBuffers(pParams -> DeviceHandle,
                                          &pParams -> Value
                                         );
    SET_HIDD_STATUS(pStatus,
                    IsHidError,
                    TRUE
                   );
    return;
}

VOID
ExtCalls_HidD_SetNumInputBuffers(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    BOOL     IsHidError;

    IsHidError = !HidD_SetNumInputBuffers(pParams -> DeviceHandle,
                                          pParams -> Value
                                         );
    SET_HIDD_STATUS(pStatus,
                    IsHidError,
                    TRUE
                   );
    return;
}

VOID
ExtCalls_HidD_GetPhysicalDescriptor(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    BOOL    IsHidError;
    BOOL    AllocStatus;
    PCHAR   TestDataBuffer;

    SETUP_INPUT_BUFFER(TestDataBuffer,
                       pParams -> List,
                       pParams -> ListLength,
                       "HidD_GetPhysicalDescriptor",
                       AllocStatus
                      );

    IsHidError = !HidD_GetPhysicalDescriptor(pParams -> DeviceHandle,
                                             TestDataBuffer,
                                             pParams -> ListLength
                                            );

    VERIFY_INPUT_BUFFER(TestDataBuffer,
                        pParams -> List,
                        pParams -> ListLength,
                        AllocStatus
                       );

    SET_HIDD_STATUS(pStatus,
                    IsHidError,
                    AllocStatus
                   );

    return;
}


VOID
ExtCalls_HidD_GetManufacturerString(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    BOOL    IsHidError;
    BOOL    AllocStatus;
    PCHAR   TestDataBuffer;

    SETUP_INPUT_BUFFER(TestDataBuffer,
                       pParams -> List,
                       pParams -> ListLength,
                       "HidD_GetManufacturerString",
                       AllocStatus
                      );

    IsHidError = !HidD_GetManufacturerString(pParams -> DeviceHandle,
                                             TestDataBuffer,
                                             pParams -> ListLength
                                            );

    VERIFY_INPUT_BUFFER(TestDataBuffer,
                        pParams -> List,
                        pParams -> ListLength,
                        AllocStatus
                       );

    SET_HIDD_STATUS(pStatus,
                    IsHidError,
                    AllocStatus
                   );

    return;
}


VOID
ExtCalls_HidD_GetProductString(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    BOOL    IsHidError;
    BOOL    AllocStatus;
    PCHAR   TestDataBuffer;

    SETUP_INPUT_BUFFER(TestDataBuffer,
                       pParams -> List,
                       pParams -> ListLength,
                       "HidD_GetProductString",
                       AllocStatus
                      );

    IsHidError = !HidD_GetProductString(pParams -> DeviceHandle,
                                        TestDataBuffer,
                                        pParams -> ListLength
                                       );

    VERIFY_INPUT_BUFFER(TestDataBuffer,
                        pParams -> List,
                        pParams -> ListLength,
                        AllocStatus
                       );

    SET_HIDD_STATUS(pStatus,
                    IsHidError,
                    AllocStatus
                   );

    return;
}

VOID
ExtCalls_HidD_GetIndexedString(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    BOOL    IsHidError;
    BOOL    AllocStatus;
    PCHAR   TestDataBuffer;

    SETUP_INPUT_BUFFER(TestDataBuffer,
                       pParams -> List,
                       pParams -> ListLength,
                       "HidD_GetIndexString",
                       AllocStatus
                      );

    IsHidError = !HidD_GetIndexedString(pParams -> DeviceHandle,
                                        pParams -> StringIndex,
                                        TestDataBuffer,
                                        pParams -> ListLength
                                       );

    VERIFY_INPUT_BUFFER(TestDataBuffer,
                        pParams -> List,
                        pParams -> ListLength,
                        AllocStatus
                       );

    SET_HIDD_STATUS(pStatus,
                    IsHidError,
                    AllocStatus
                   );

    return;
}


VOID
ExtCalls_HidD_GetSerialNumberString(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    BOOL    IsHidError;
    BOOL    AllocStatus;
    PCHAR   TestDataBuffer;

    SETUP_INPUT_BUFFER(TestDataBuffer,
                       pParams -> List,
                       pParams -> ListLength,
                       "HidD_GetSerialNumberString",
                       AllocStatus
                      );

    IsHidError = !HidD_GetSerialNumberString(pParams -> DeviceHandle,
                                                   TestDataBuffer,
                                                   pParams -> ListLength
                                                  );

    VERIFY_INPUT_BUFFER(TestDataBuffer,
                        pParams -> List,
                        pParams -> ListLength,
                        AllocStatus
                       );

    SET_HIDD_STATUS(pStatus,
                    IsHidError,
                    AllocStatus
                   );

    return;
}


VOID
ExtCalls_HidP_GetButtonCaps(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    PHIDP_BUTTON_CAPS pTestButtonCaps;
    NTSTATUS          Status;
    BOOL              AllocStatus;
    ULONG             Caps;

    Caps = pParams -> ListLength;

    SETUP_INPUT_BUFFER(pTestButtonCaps,
                       pParams -> List,
                       Caps * sizeof(HIDP_BUTTON_CAPS),
                       "HidP_GetButtonCaps",
                       AllocStatus
                      );

    Status = HidP_GetButtonCaps(pParams -> ReportType,
                                pTestButtonCaps,
                                (PUSHORT) &pParams -> ListLength,
                                pParams -> Ppd,
                               );

    VERIFY_INPUT_BUFFER(pTestButtonCaps,
                        pParams -> List,
                        Caps * sizeof(HIDP_BUTTON_CAPS),
                        AllocStatus
                       );

    SET_HIDP_STATUS(pStatus,
                    Status,
                    AllocStatus
                   );
    return;
}

VOID
ExtCalls_HidP_GetButtons(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    NTSTATUS   status;
    PUSAGE     TestBuffer;
    ULONG      UsageLength;
    BOOL       AllocStatus;

    UsageLength = pParams -> ListLength;
    SETUP_INPUT_BUFFER(TestBuffer,
                       pParams -> List,
                       UsageLength * sizeof(USAGE),
                       "HidP_GetButtons",
                       AllocStatus
                      );

    status = HidP_GetButtons(pParams -> ReportType,
                             pParams -> UsagePage,
                             pParams -> LinkCollection,
                             TestBuffer,
                             &pParams -> ListLength,
                             pParams -> Ppd,
                             pParams -> ReportBuffer,
                             pParams -> ReportLength
                            );

    VERIFY_INPUT_BUFFER(TestBuffer,
                        pParams -> List,
                        UsageLength * sizeof(USAGE),
                        AllocStatus
                       );

    SET_HIDP_STATUS(pStatus,
                    status,
                    AllocStatus
                   );

    return;
}

VOID
ExtCalls_HidP_GetButtonsEx(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    PUSAGE_AND_PAGE TestBuffer;
    NTSTATUS        status;
    ULONG           UsageLength;
    BOOL            AllocStatus;

    UsageLength = pParams -> ListLength;
    SETUP_INPUT_BUFFER(TestBuffer,
                       pParams -> List,
                       UsageLength * sizeof(USAGE_AND_PAGE),
                       "HidP_GetButtonsEx",
                       AllocStatus
                      );

    status = HidP_GetButtonsEx(pParams -> ReportType,
                               pParams -> LinkCollection,
                               TestBuffer,
                               &pParams -> ListLength,
                               pParams -> Ppd,
                               pParams -> ReportBuffer,
                               pParams -> ReportLength
                              );

    VERIFY_INPUT_BUFFER(TestBuffer,
                        pParams -> List,
                        UsageLength * sizeof(USAGE_AND_PAGE),
                        AllocStatus
                       );

    SET_HIDP_STATUS(pStatus,
                    status,
                    AllocStatus
                   );

    return;
}

VOID
ExtCalls_HidP_GetData(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    PHIDP_DATA      TestBuffer;
    NTSTATUS        status;
    ULONG           DataLength;
    BOOL       AllocStatus;

    DataLength = pParams -> ListLength;
    SETUP_INPUT_BUFFER(TestBuffer,
                       pParams -> List,
                       DataLength * sizeof(HIDP_DATA),
                      "HidP_GetData",
                       AllocStatus
                      );

    status = HidP_GetData(pParams -> ReportType,
                          TestBuffer,
                          &pParams -> ListLength,
                          pParams -> Ppd,
                          pParams -> ReportBuffer,
                          pParams -> ReportLength
                         );

    VERIFY_INPUT_BUFFER(TestBuffer,
                        pParams -> List,
                        DataLength * sizeof(HIDP_DATA),
                        AllocStatus
                       );

    SET_HIDP_STATUS(pStatus,
                    status,
                    AllocStatus
                   );

    return;
}

VOID
ExtCalls_HidP_GetCaps(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    PHIDP_CAPS TestBuffer;
    NTSTATUS   status;
    BOOL       AllocStatus;
    
    SETUP_INPUT_BUFFER(TestBuffer,
                       pParams -> List,
                       sizeof(HIDP_CAPS),
                       "HidP_GetCaps",
                       AllocStatus
                      );

    status = HidP_GetCaps(pParams -> Ppd, TestBuffer);

    VERIFY_INPUT_BUFFER(TestBuffer,
                        pParams -> List,
                        sizeof(HIDP_CAPS),
                        AllocStatus
                       );

    SET_HIDP_STATUS(pStatus,
                    status,
                    AllocStatus
                   );

    return;
}

VOID
ExtCalls_HidP_MaxDataListLength(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
) 
{
    pParams -> Value  = HidP_MaxDataListLength(pParams -> ReportType,
                                               pParams -> Ppd
                                              );

    pStatus -> IsHidError      = FALSE;
    pStatus -> IsHidDbgError   = FALSE;
    pStatus -> IsHidDbgWarning = FALSE;
    
    pStatus -> HidErrorCode = HIDP_STATUS_SUCCESS;
    return;
}

VOID
ExtCalls_HidP_MaxUsageListLength(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
) 
{
    pParams -> Value  = HidP_MaxUsageListLength(pParams -> ReportType,
                                                pParams -> UsagePage,
                                                pParams -> Ppd
                                               );

    pStatus -> IsHidError      = FALSE;
    pStatus -> IsHidDbgError   = FALSE;
    pStatus -> IsHidDbgWarning = FALSE;
    pStatus -> HidErrorCode    = HIDP_STATUS_SUCCESS;

    return;
}

VOID ExtCalls_HidP_GetSpecificButtonCaps(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    ULONG             Caps;
    PHIDP_BUTTON_CAPS TestBuffer;
    NTSTATUS          status;
    BOOL              AllocStatus;

    Caps = pParams -> ListLength;
    SETUP_INPUT_BUFFER(TestBuffer,
                       pParams -> List,
                       Caps * sizeof(HIDP_BUTTON_CAPS),
                       "HidP_GetSpecificButtonCaps",
                       AllocStatus
                      );

    status = HidP_GetSpecificButtonCaps(pParams -> ReportType,
                                        pParams -> UsagePage,
                                        pParams -> LinkCollection,
                                        pParams -> Usage,
                                        TestBuffer,
                                        (PUSHORT) &pParams -> ListLength,
                                        pParams -> Ppd
                                       );

    VERIFY_INPUT_BUFFER(TestBuffer,
                        pParams -> List,
                        Caps * sizeof(HIDP_BUTTON_CAPS),
                        AllocStatus
                       );

    SET_HIDP_STATUS(pStatus,
                    status,
                    AllocStatus
                   );


    return;
}

VOID
ExtCalls_HidP_GetSpecificValueCaps(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    ULONG            Caps;
    PHIDP_VALUE_CAPS TestBuffer;
    NTSTATUS         status;
    BOOL             AllocStatus;

    Caps = pParams -> ListLength;
    SETUP_INPUT_BUFFER(TestBuffer,
                       pParams -> List,
                       Caps * sizeof(HIDP_VALUE_CAPS),
                       "HidP_GetSpecificValueCaps",
                       AllocStatus
                      );
               
    status = HidP_GetSpecificValueCaps(pParams -> ReportType,
                                       pParams -> UsagePage,
                                       pParams -> LinkCollection,
                                       pParams -> Usage,
                                       TestBuffer,
                                       (PUSHORT) &pParams -> ListLength,
                                       pParams -> Ppd
                                      );

    VERIFY_INPUT_BUFFER(TestBuffer,
                        pParams -> List,
                        Caps * sizeof(HIDP_VALUE_CAPS),
                        AllocStatus
                       );

    SET_HIDP_STATUS(pStatus,
                    status,
                    AllocStatus
                   );
    return;
}    

PCHAR ExtCalls_GetHidAppStatusString(NTSTATUS StatusCode)
{
    switch (StatusCode) {
        case HIDP_STATUS_SUCCESS:
            return ("Success");


        case HIDP_STATUS_NULL:
            return ("Status NULL");

        case HIDP_STATUS_INVALID_PREPARSED_DATA:
            return ("Invalid Preparsed Data");

        case HIDP_STATUS_INVALID_REPORT_TYPE:
            return ("Invalid Report Type");

        case HIDP_STATUS_INVALID_REPORT_LENGTH:
            return ("Invalid Report Length");

        case HIDP_STATUS_USAGE_NOT_FOUND:
            return ("Usage not found");

        case HIDP_STATUS_VALUE_OUT_OF_RANGE:
            return ("Value out of range");

        case HIDP_STATUS_BAD_LOG_PHY_VALUES:
            return ("Bad logical physical values");

        case HIDP_STATUS_BUFFER_TOO_SMALL:
            return ("Buffer too small");

        case HIDP_STATUS_INTERNAL_ERROR:
            return ("Internal error");

        case HIDP_STATUS_I8242_TRANS_UNKNOWN:
            return ("I8242 Translation unknown");

        case HIDP_STATUS_INCOMPATIBLE_REPORT_ID:
            return ("Incompatible report ID");

        case HIDP_STATUS_NOT_VALUE_ARRAY:
            return ("Not value array");

        case HIDP_STATUS_IS_VALUE_ARRAY:
            return ("Is value array");

        case HIDP_STATUS_DATA_INDEX_NOT_FOUND:   
            return ("Data index not found");

        case HIDP_STATUS_DATA_INDEX_OUT_OF_RANGE:
            return ("Data index out of range");

        case HIDP_STATUS_BUTTON_NOT_PRESSED:     
            return ("Button not pressed");

        case HIDP_STATUS_NOT_IMPLEMENTED:        
            return ("Not implemented");

        default:
            return ("Unknown HID Status error");
    }
}             

VOID
ExtCalls_HidP_GetLinkCollectionNodes(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    PHIDP_LINK_COLLECTION_NODE  TestBuffer;
    NTSTATUS                    status;
    ULONG                       LinkNodes;
    BOOL                        AllocStatus;

    LinkNodes = pParams -> ListLength;
    SETUP_INPUT_BUFFER(TestBuffer,
                       pParams -> List,
                       LinkNodes * sizeof(HIDP_LINK_COLLECTION_NODE),
                       "HidP_GetLinkCollectionNodes",
                       AllocStatus
                      );

    status = HidP_GetLinkCollectionNodes(TestBuffer,
                                         &pParams -> ListLength,
                                         pParams -> Ppd
                                        );

    VERIFY_INPUT_BUFFER(TestBuffer,
                        pParams -> List,
                        LinkNodes * sizeof(HIDP_LINK_COLLECTION_NODE),
                        AllocStatus
                       );

    SET_HIDP_STATUS(pStatus,
                    status,
                    AllocStatus
                   );

    return;
}

VOID
ExtCalls_HidP_GetScaledUsageValue(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    NTSTATUS status;

    status = HidP_GetScaledUsageValue(pParams -> ReportType,
                                      pParams -> UsagePage,
                                      pParams -> LinkCollection,
                                      pParams -> Usage,
                                      &pParams -> ScaledValue,
                                      pParams -> Ppd,
                                      pParams -> ReportBuffer,
                                      pParams -> ReportLength
                                     );

    SET_HIDP_STATUS(pStatus,
                    status,
                    TRUE
                   );

    return;
}

VOID
ExtCalls_HidP_GetUsages(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    PUSAGE     TestBuffer;
    ULONG      Usages;
    NTSTATUS   status;
    BOOL       AllocStatus;

    Usages = pParams -> ListLength;
    SETUP_INPUT_BUFFER(TestBuffer,
                       pParams -> List,
                       Usages * sizeof(USAGE),
                       "HidP_GetUsages",
                       AllocStatus
                      );

    status = HidP_GetUsages(pParams -> ReportType,
                            pParams -> UsagePage,
                            pParams -> LinkCollection,
                            TestBuffer,
                            &pParams -> ListLength,
                            pParams -> Ppd,
                            pParams -> ReportBuffer,
                            pParams -> ReportLength
                           );

    VERIFY_INPUT_BUFFER(TestBuffer,
                        pParams -> List,
                        Usages * sizeof(USAGE),
                        AllocStatus
                       );

    SET_HIDP_STATUS(pStatus,
                    status,
                    AllocStatus
                   );

    return;
}

VOID
ExtCalls_HidP_GetUsagesEx(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    PUSAGE_AND_PAGE TestBuffer;
    ULONG           Usages;
    NTSTATUS        status;
    BOOL            AllocStatus;


    Usages = pParams -> ListLength;
    SETUP_INPUT_BUFFER(TestBuffer,
                       pParams -> List,
                       Usages * sizeof(USAGE_AND_PAGE),
                       "HidP_GetUsagesEx",
                       AllocStatus
                      );

    status = HidP_GetUsagesEx(pParams -> ReportType,
                              pParams -> LinkCollection,
                              TestBuffer,
                              &pParams -> ListLength,
                              pParams -> Ppd,
                              pParams -> ReportBuffer,
                              pParams -> ReportLength
                             );

    VERIFY_INPUT_BUFFER(TestBuffer,
                        pParams -> List,
                        Usages * sizeof(USAGE_AND_PAGE),
                        AllocStatus
                       );

    SET_HIDP_STATUS(pStatus,
                    status,
                    AllocStatus
                   );

    return;
}

VOID
ExtCalls_HidP_GetUsageValue(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    NTSTATUS status;
    PCHAR            TestBuffer;
    BOOL             AllocStatus;

    SETUP_INPUT_BUFFER(TestBuffer,
                       pParams -> List,
                       pParams -> ListLength,
                       "HidP_GetUsageValueArray",
                       AllocStatus
                      );

    status = HidP_GetUsageValue(pParams -> ReportType,
                                pParams -> UsagePage,
                                pParams -> LinkCollection,
                                pParams -> Usage,
                                &pParams -> Value,
                                pParams -> Ppd,
                                pParams -> ReportBuffer,
                                pParams -> ReportLength
                               );

    VERIFY_INPUT_BUFFER(TestBuffer,
                        pParams -> List,
                        pParams -> ListLength,
                        AllocStatus
                       );

    SET_HIDP_STATUS(pStatus,
                    status,
                    AllocStatus
                   );

    return;
}

VOID
ExtCalls_HidP_GetUsageValueArray(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    NTSTATUS         status;
    PCHAR            TestBuffer;
    BOOL             AllocStatus;

    SETUP_INPUT_BUFFER(TestBuffer,
                       pParams -> List,
                       pParams -> ListLength,
                       "HidP_GetUsageValueArray",
                       AllocStatus
                      );

    status = HidP_GetUsageValueArray(pParams -> ReportType,
                                     pParams -> UsagePage,
                                     pParams -> LinkCollection,
                                     pParams -> Usage,
                                     TestBuffer,
                                     (USHORT) pParams -> ListLength,
                                     pParams -> Ppd,
                                     pParams -> ReportBuffer,
                                     pParams -> ReportLength
                                    );

    VERIFY_INPUT_BUFFER(TestBuffer,
                        pParams -> List,
                        pParams -> ListLength,
                        AllocStatus
                       );

    SET_HIDP_STATUS(pStatus,
                    status,
                    AllocStatus
                   );

    return;
}

VOID
ExtCalls_HidP_GetValueCaps(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    ULONG               Caps;
    NTSTATUS            status;
    PHIDP_VALUE_CAPS    TestBuffer;
    BOOL                AllocStatus;

    Caps = pParams -> ListLength;
    SETUP_INPUT_BUFFER(TestBuffer,
                       pParams -> List,
                       Caps * sizeof(HIDP_VALUE_CAPS),
                       "HidP_GetValueCaps",
                       AllocStatus
                      );

    status = HidP_GetValueCaps(pParams -> ReportType,
                               TestBuffer,
                               (PUSHORT) &pParams -> ListLength,
                               pParams -> Ppd
                              );

    VERIFY_INPUT_BUFFER(TestBuffer,
                        pParams -> List,
                        Caps * sizeof(HIDP_VALUE_CAPS),
                        AllocStatus
                       );

    SET_HIDP_STATUS(pStatus,
                    status,
                    AllocStatus
                   );

    return;
}    

VOID
ExtCalls_HidP_SetButtons(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    PUSAGE   TestDataBuffer;
    PCHAR    TestReportBuffer;
    ULONG    Buttons;
    NTSTATUS status;
    BOOL     AllocStatus;

    Buttons = pParams -> ListLength;
    SETUP_OUTPUT_BUFFER(TestDataBuffer,
                        pParams -> List,
                        Buttons * sizeof(USAGE),
                        "HidP_SetButtons",
                        AllocStatus
                      );

    SETUP_OUTPUT_BUFFER(TestReportBuffer,
                        pParams -> ReportBuffer,
                        pParams -> ReportLength,
                        "HidP_SetButtons",
                        AllocStatus
                       );

    status = HidP_SetButtons(pParams -> ReportType,
                             pParams -> UsagePage,
                             pParams -> LinkCollection,
                             TestDataBuffer, 
                             &pParams -> ListLength,
                             pParams -> Ppd,
                             TestReportBuffer,
                             pParams -> ReportLength
                            );

    VERIFY_OUTPUT_BUFFER(TestDataBuffer,
                         pParams -> List,
                         Buttons * sizeof(USAGE),
                         AllocStatus
                        );

    /*
    // VERIFY_INPUT_BUFFER is called instead of OUTPUT_BUFFER even though it
    //    was set up as an OUTPUT_BUFFER.  This is because we need to copy
    //    the data that was returned back to the output buffer.  In essence,
    //    out ReportBuffer acted as an IN/OUT Buffer
    */

    VERIFY_INPUT_BUFFER(TestReportBuffer,
                        pParams -> ReportBuffer,
                        pParams -> ReportLength,
                        AllocStatus
                       );

    SET_HIDP_STATUS(pStatus,
                    status,
                    AllocStatus
                   );

    return;
}

VOID
ExtCalls_HidP_SetData(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    PHIDP_DATA TestDataBuffer;
    PCHAR      TestReportBuffer;
    ULONG      DataLength;
    NTSTATUS   status;
    BOOL       AllocStatus;

    DataLength = pParams -> ListLength;
    SETUP_OUTPUT_BUFFER(TestDataBuffer,
                        pParams -> List,
                        DataLength * sizeof(HIDP_DATA),
                        "HidP_SetData",
                        AllocStatus
                      );

    SETUP_OUTPUT_BUFFER(TestReportBuffer,
                        pParams -> ReportBuffer,
                        pParams -> ReportLength,
                        "HidP_SetData",
                        AllocStatus
                      );


    status = HidP_SetData(pParams -> ReportType,
                          TestDataBuffer, 
                          &pParams -> ListLength,
                          pParams -> Ppd,
                          TestReportBuffer,
                          pParams -> ReportLength
                         );

    VERIFY_OUTPUT_BUFFER(TestDataBuffer,
                         pParams -> List,
                         DataLength * sizeof(HIDP_DATA),
                         AllocStatus
                        );

    VERIFY_INPUT_BUFFER(TestReportBuffer,
                        pParams -> ReportBuffer,
                        pParams -> ReportLength,
                        AllocStatus
                       );

    SET_HIDP_STATUS(pStatus,
                    status,
                    AllocStatus
                   );
    return;
}
    
VOID
ExtCalls_HidP_SetScaledUsageValue(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    PCHAR    TestReportBuffer;
    NTSTATUS status;
    BOOL     AllocStatus;

    SETUP_OUTPUT_BUFFER(TestReportBuffer,
                        pParams -> ReportBuffer,
                        pParams -> ReportLength,
                        "HidP_SetScaledUsageValue",
                        AllocStatus
                      );

    status = HidP_SetScaledUsageValue(pParams -> ReportType,
                                      pParams -> UsagePage,
                                      pParams -> LinkCollection,
                                      pParams -> Usage,
                                      pParams -> ScaledValue,
                                      pParams -> Ppd,
                                      TestReportBuffer,
                                      pParams -> ReportLength
                                     );

    VERIFY_INPUT_BUFFER(TestReportBuffer,
                        pParams -> ReportBuffer,
                        pParams -> ReportLength,
                        AllocStatus
                       );

    SET_HIDP_STATUS(pStatus,
                    status,
                    TRUE
                   );
    return;
}

VOID
ExtCalls_HidP_SetUsages(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    PUSAGE   TestDataBuffer;
    PCHAR    TestReportBuffer;
    ULONG    Usages;
    NTSTATUS status;
    BOOL     AllocStatus;

    Usages = pParams -> ListLength;
    SETUP_OUTPUT_BUFFER(TestDataBuffer,
                        pParams -> List,
                        Usages * sizeof(USAGE),
                        "HidP_SetUsages",
                        AllocStatus
                       );

    SETUP_OUTPUT_BUFFER(TestReportBuffer,
                        pParams -> ReportBuffer,
                        pParams -> ReportLength,
                        "HidP_SetUsages",
                        AllocStatus
                       );


    status = HidP_SetUsages(pParams -> ReportType,
                            pParams -> UsagePage,
                            pParams -> LinkCollection,
                            TestDataBuffer,
                            &pParams -> ListLength,
                            pParams -> Ppd,
                            TestReportBuffer,
                            pParams -> ReportLength
                           );

    VERIFY_OUTPUT_BUFFER(TestDataBuffer,
                         pParams -> List,
                         Usages * sizeof(USAGE),
                         AllocStatus
                        );

    VERIFY_INPUT_BUFFER(TestReportBuffer,
                        pParams -> ReportBuffer,
                        pParams -> ReportLength,
                        AllocStatus
                       );

    SET_HIDP_STATUS(pStatus,
                    status,
                    AllocStatus
                   );
    return;
}

VOID
ExtCalls_HidP_SetUsageValue(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    PCHAR    TestReportBuffer;
    NTSTATUS status;
    BOOL     AllocStatus;

    SETUP_OUTPUT_BUFFER(TestReportBuffer,
                        pParams -> ReportBuffer,
                        pParams -> ReportLength,
                        "HidP_SetUsageValue",
                        AllocStatus
                       );

    status = HidP_SetUsageValue(pParams -> ReportType,
                                pParams -> UsagePage,
                                pParams -> LinkCollection,
                                pParams -> Usage,
                                pParams -> Value,
                                pParams -> Ppd,
                                TestReportBuffer,
                                pParams -> ReportLength
                               );

    VERIFY_INPUT_BUFFER(TestReportBuffer,
                        pParams -> ReportBuffer,
                        pParams -> ReportLength,
                        AllocStatus
                       );

    SET_HIDP_STATUS(pStatus,
                    status,
                    TRUE
                   );
    return;
}

VOID
ExtCalls_HidP_SetUsageValueArray(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    PCHAR    TestDataBuffer;
    PCHAR    TestReportBuffer;
    NTSTATUS status;
    BOOL     AllocStatus;

    SETUP_OUTPUT_BUFFER(TestDataBuffer,
                        pParams -> List,
                        pParams -> ListLength,
                        "HidP_SetUsageValueArray",
                        AllocStatus
                       );
   
    SETUP_OUTPUT_BUFFER(TestReportBuffer,
                        pParams -> ReportBuffer,
                        pParams -> ReportLength,
                        "HidP_SetUsageValueArray",
                        AllocStatus
                       );

    status = HidP_SetUsageValueArray(pParams -> ReportType,
                                     pParams -> UsagePage,
                                     pParams -> LinkCollection,
                                     pParams -> Usage,
                                     TestDataBuffer,
                                     (USHORT) pParams -> ListLength,
                                     pParams -> Ppd,
                                     TestReportBuffer,
                                     pParams -> ReportLength
                                    );

    VERIFY_OUTPUT_BUFFER(TestDataBuffer,
                         pParams -> List,
                         pParams -> ListLength,
                         AllocStatus
                        );

    VERIFY_INPUT_BUFFER(TestReportBuffer,
                        pParams -> ReportBuffer,
                        pParams -> ReportLength,
                        AllocStatus
                       );

    SET_HIDP_STATUS(pStatus,
                    status,
                    AllocStatus
                   );

    return;
}

VOID
ExtCalls_HidP_UnsetButtons(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    PUSAGE   TestDataBuffer;
    PCHAR    TestReportBuffer;
    ULONG    Buttons;
    NTSTATUS status;
    BOOL     AllocStatus;

    Buttons = pParams -> ListLength;
    SETUP_OUTPUT_BUFFER(TestDataBuffer,
                        pParams -> List,
                        Buttons * sizeof(USAGE),
                        "HidP_UnsetButtons",
                        AllocStatus
                       );

    SETUP_OUTPUT_BUFFER(TestReportBuffer,
                        pParams -> ReportBuffer,
                        pParams -> ReportLength,
                        "HidP_UnsetButtons",
                        AllocStatus
                       );
    
    status = HidP_UnsetButtons(pParams -> ReportType,
                               pParams -> UsagePage,
                               pParams -> LinkCollection,
                               TestDataBuffer,
                               &pParams -> ListLength,
                               pParams -> Ppd,
                               TestReportBuffer,
                               pParams -> ReportLength
                              );

    VERIFY_OUTPUT_BUFFER(TestDataBuffer,
                         pParams -> List,
                         Buttons * sizeof(USAGE),
                         AllocStatus
                        );

    VERIFY_INPUT_BUFFER(TestReportBuffer,
                        pParams -> ReportBuffer,
                        pParams -> ReportLength,
                        AllocStatus
                       );

    SET_HIDP_STATUS(pStatus,
                    status,
                    AllocStatus
                   );

    return;

}

VOID
ExtCalls_HidP_UnsetUsages(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    PUSAGE   TestDataBuffer;
    PCHAR    TestReportBuffer;
    ULONG    Usages;
    NTSTATUS status;
    BOOL     AllocStatus;

    Usages = pParams -> ListLength;
    SETUP_OUTPUT_BUFFER(TestDataBuffer,
                        pParams -> List,
                        Usages * sizeof(USAGE),
                        "HidP_UnsetUsages",
                        AllocStatus
                      );

    SETUP_OUTPUT_BUFFER(TestReportBuffer,
                        pParams -> ReportBuffer,
                        pParams -> ReportLength,
                        "HidP_UnsetUsages",
                        AllocStatus
                      );

    status = HidP_UnsetUsages(pParams -> ReportType,
                              pParams -> UsagePage,
                              pParams -> LinkCollection,
                              TestDataBuffer,
                              &pParams -> ListLength,
                              pParams -> Ppd,
                              TestReportBuffer,
                              pParams -> ReportLength
                             );

    VERIFY_OUTPUT_BUFFER(TestDataBuffer,
                         pParams -> List,
                         Usages * sizeof(USAGE),
                         AllocStatus
                        );

    VERIFY_INPUT_BUFFER(TestReportBuffer,
                        pParams -> ReportBuffer,
                        pParams -> ReportLength,
                        AllocStatus
                       );

    SET_HIDP_STATUS(pStatus,
                    status,
                    AllocStatus
                   );
    return;
}

VOID
ExtCalls_HidP_UsageListDifference(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    PUSAGE      PreviousList;
    PUSAGE      CurrentList;
    PUSAGE      BreakList;
    PUSAGE      MakeList;
    NTSTATUS    status;
    BOOL        AllocStatus;

    SETUP_OUTPUT_BUFFER(PreviousList,
                       pParams -> List,
                       pParams -> ListLength * sizeof(USAGE),
                       "HidP_UsageListDifference",
                       AllocStatus
                      );

    SETUP_OUTPUT_BUFFER(CurrentList,
                        pParams -> List2,
                        pParams -> ListLength * sizeof(USAGE),
                        "HidP_UsageListDifference",
                        AllocStatus
                       );


    SETUP_INPUT_BUFFER(BreakList,
                       pParams -> BreakList,
                       pParams -> ListLength * sizeof(USAGE),
                       "HidP_UsageListDifference",
                       AllocStatus
                      );

    SETUP_INPUT_BUFFER(MakeList,
                       pParams -> MakeList,
                       pParams -> ListLength * sizeof(USAGE),
                       "HidP_UsageListDifference",
                       AllocStatus
                      );

    status = HidP_UsageListDifference(PreviousList,
                                      CurrentList,
                                      BreakList,
                                      MakeList,
                                      pParams -> ListLength
                                     );
                            
    VERIFY_OUTPUT_BUFFER(PreviousList,
                         pParams -> List,
                         pParams -> ListLength * sizeof(USAGE),
                         AllocStatus
                        );

    VERIFY_OUTPUT_BUFFER(CurrentList,
                         pParams -> List,
                         pParams -> ListLength * sizeof(USAGE),
                         AllocStatus
                        );

    VERIFY_INPUT_BUFFER(BreakList,
                        pParams -> BreakList,
                        pParams -> ListLength * sizeof(USAGE),
                        AllocStatus
                       );

    VERIFY_INPUT_BUFFER(MakeList,
                        pParams -> MakeList,
                        pParams -> ListLength * sizeof(USAGE),
                        AllocStatus
                       );

    SET_HIDP_STATUS(pStatus,
                    status,
                    AllocStatus
                   );
    return;
}


VOID
ExtCalls_ReadInputBuffer(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    DWORD    bytesRead;
    BOOL     fReadStatus;

    fReadStatus = ReadFile (pParams -> DeviceHandle,
                            pParams -> ReportBuffer,
                            pParams -> ReportLength,
                            &bytesRead,
                            NULL
                           );

    pStatus -> IsHidError = !fReadStatus;
    pStatus -> IsHidDbgError = FALSE;
    pStatus -> IsHidDbgWarning = FALSE;

    return;
}

VOID
ExtCalls_WriteOutputBuffer(
    IN OUT PEXTCALL_PARAMS     pParams,
    OUT    PEXTCALL_STATUS     pStatus
)
{
    DWORD    bytesWritten;
    BOOL     WriteStatus;

    WriteStatus = WriteFile(pParams -> DeviceHandle,
                            pParams -> ReportBuffer,
                            pParams -> ReportLength,
                            &bytesWritten,
                            NULL
                           );

    pStatus -> IsHidError = !WriteStatus;
    pStatus -> IsHidDbgError = FALSE;
    pStatus -> IsHidDbgWarning = FALSE;

    return;
}
