/*++

Copyright (c) 1998  Microsoft Corporation All Rights Reserved
 
Module Name:

    dmademo.c

Abstract:   

Author:

    Abdul Ismail (Compaq Computer Corp.)

Environment:

    Win32 console application

Revision History:

    3-26-99  Peter Lee (Compaq Computer Corp.) Update to use device management apis.

--*/

#include <windows.h>
#include <basetyps.h>
#include <stdlib.h>
#include <wtypes.h>
#include <setupapi.h>
#include <initguid.h>
#include <stdio.h>
#include <string.h>
#include <winioctl.h>
#include <conio.h>
#include <malloc.h>

#include "dmademo.h"

int __cdecl main(int argc, char **argv)
{
    HANDLE  hTest;
    BOOL    StatusSuccess = TRUE;
    HDEVINFO                            hardwareDeviceInfo;
    SP_INTERFACE_DEVICE_DATA            deviceInfoData;
    PSP_INTERFACE_DEVICE_DETAIL_DATA    functionClassDeviceData = NULL;
    ULONG                               predictedLength = 0;
    ULONG                               requiredLength = 0;
    ULONG                               bytes;
    ULONG                               i;

    LPVOID  lpOutBuffer;
    DWORD   nOutBufferSize;

    DWORD   BytesReturned;

    if (argc < 2)
    {
        puts("Usage:dmademo <StartingBufferSize>\n");
        return 1;
    }

    if (argc >= 2  && (argv[1][0] == '-' || isalpha(argv[1][0])))
    {
        puts("Usage:dmademo <StartingBufferSize>\n");
        return 1;
    }

    //
    // Open a handle to the plug and play dev node.
    //
    hardwareDeviceInfo = SetupDiGetClassDevs (
                       (LPGUID)&GUID_DUMMYDMA_INTERFACE,
                       NULL, // Define no enumerator (global)
                       NULL, // Define no
                       (DIGCF_PRESENT | // Only Devices present
                       DIGCF_INTERFACEDEVICE)); // Function class devices.
    if(0 == hardwareDeviceInfo)
    {
        printf("SetupDiGetClassDevs failed: %x\n", GetLastError());
        return 1;
    }
    
    deviceInfoData.cbSize = sizeof (SP_INTERFACE_DEVICE_DATA);

    if (SetupDiEnumDeviceInterfaces (hardwareDeviceInfo,
                                     0, // No care about specific PDOs
                                     (LPGUID)&GUID_DUMMYDMA_INTERFACE,
                                     0, //
                                     &deviceInfoData)) {
       //
       // Allocate a function class device data structure to 
       // receive the information about this particular device.
       //

       //
       // First find out required length of the buffer
       //
            
       SetupDiGetInterfaceDeviceDetail (
                hardwareDeviceInfo,
                &deviceInfoData,
                NULL, // probing so no output buffer yet
                0, // probing so output buffer length of zero
                &requiredLength,
                NULL); // not interested in the specific dev-node


       predictedLength = requiredLength;

       functionClassDeviceData = malloc (predictedLength);
       functionClassDeviceData->cbSize = 
                       sizeof (SP_INTERFACE_DEVICE_DETAIL_DATA);


       if (! SetupDiGetInterfaceDeviceDetail (
                  hardwareDeviceInfo,
                  &deviceInfoData,
                  functionClassDeviceData,
                  predictedLength,
                  &requiredLength,
                  NULL)) {
           printf("Error in SetupDiGetInterfaceDeviceDetail\n");
           free (functionClassDeviceData);
           return 1;
       }
       
    }
    else if (ERROR_NO_MORE_ITEMS != GetLastError()) {
       printf("Error: No GUID_BUSENUM_BUS_ENUMERATOR interfac\n");
       free (functionClassDeviceData);
       SetupDiDestroyDeviceInfoList (hardwareDeviceInfo);
       return 1;
    }

    SetupDiDestroyDeviceInfoList (hardwareDeviceInfo);

    if (functionClassDeviceData == NULL) {
        //
        // Device not found
        //
        printf("Device path not found\n");
        return 1;
    }

    nOutBufferSize = atoi(argv[1]);
    if (nOutBufferSize == 0)
        nOutBufferSize = 1;

    printf("Starting buffer size = %d\n", nOutBufferSize);

    //
    // Open the device interface
    //

    printf("\nPress any key to quit.\n");

    printf("Opening %s\n", functionClassDeviceData->DevicePath);

    if ((hTest = CreateFile(
                     functionClassDeviceData->DevicePath,
                     GENERIC_READ | GENERIC_WRITE,
                     0,
                     NULL,
                     OPEN_EXISTING,
                     0,
                     NULL
                     )) != ((HANDLE)-1))
    {

        // verify zero length transfers
        StatusSuccess = DeviceIoControl(
            hTest,                  // handle to device of interest
            IOCTL_DUMMY_DMA,        // control code of operation to perform
            NULL,                   // pointer to buffer to supply input data
            0,                      // size of input buffer
            NULL,                   // pointer to buffer to receive output data
            0,                      // size of output buffer
            &BytesReturned,         // pointer to variable to receive output byte count
            NULL );                 // pointer to overlapped structure for asynchronous operation

        if (StatusSuccess) {
           printf("Failed to handle zero length transfers\n");
        }
        else {
           printf("Zero length transfers handled!\n");
           StatusSuccess = TRUE;
        } 

        // Continuously call to the driver to perform dummy DMA...
        while (StatusSuccess && (_kbhit() == 0))
        {
            lpOutBuffer = malloc(nOutBufferSize);
            if (lpOutBuffer == NULL)
            {
                printf("Out of memory... stopping the test. BufferSize =%d\n", nOutBufferSize);
                break;
            }

            printf("Processing buffer size = 0x%x ...........\n", nOutBufferSize);

            StatusSuccess = DeviceIoControl(
                hTest,                  // handle to device of interest
                IOCTL_DUMMY_DMA,        // control code of operation to perform
                NULL,                   // pointer to buffer to supply input data
                0,                      // size of input buffer
                lpOutBuffer,            // pointer to buffer to receive output data
                nOutBufferSize,         // size of output buffer
                &BytesReturned,         // pointer to variable to receive output byte count
                NULL );                 // pointer to overlapped structure for asynchronous operation

            free(lpOutBuffer);

            if (!StatusSuccess) {
               printf("Request failed for buffer size = 0x%x\n", nOutBufferSize);
               printf("Error = 0x%x\n", GetLastError());
               break;
            }

            nOutBufferSize += 0x1000;
        }

        // Point proven.  Be a nice program and close up shop.
        CloseHandle(hTest);

    }
    else {
        printf("Can't get a handle to the DUMMYDMA driver. (0x%x)\n", GetLastError());
    }        
    
    free (functionClassDeviceData);

    return 0;
}



