/*++

Copyright (c) 1996    Microsoft Corporation

Module Name:

    locate.c

Abstract:

    This module contains the code
    for finding, adding, removing, and identifying hid devices.

Environment:

    Kernel & user mode

Revision History:

    Nov-96 : Created by Kenneth D. Ray

--*/

#include <basetyps.h>
#include <stdlib.h>
#include <wtypes.h>
#include <cfgmgr32.h>
#include <initguid.h>
#include <stdio.h>
#include <winioctl.h>
#include "dock.h"

#define USAGE "Usage: dock [-e] [-v] [-f]\n" \
              "\t -e eject dock\n"  \
              "\t -v verbose\n" \
              "\t -f force\n"

VOID
DockStartEject (
    BOOLEAN Verbose,
    BOOLEAN Force
    );


__cdecl
main (
  ULONG argc,
  CHAR *argv[]
  )
/*++
++*/
{
    BOOLEAN eject = FALSE;
    BOOLEAN verbose = FALSE;
    BOOLEAN force = FALSE;
    BOOLEAN error = FALSE;
    ULONG i;
    char * parameter = NULL;

    //
    // parameter parsing follows:
    //
    try {
        if (argc < 2) {
            leave;
        }

        for (i = 1; i < argc; i++) {
            parameter = argv[i];

            if ('-' == *(parameter ++)) {
                switch (*parameter) {
                case 'e':
                    eject = TRUE;
                    break;

                case 'v':
                    verbose = TRUE;
                    break;

                case 'f':
                    force = TRUE;
                    break;

                default:
                    error = TRUE;
                    leave;
                }
            } else {
                error = TRUE;
                leave;
            }
        }


    } finally {
        if (error || ((!eject) && (!verbose))) {
            printf (USAGE);
            exit (1);
        }
        if (verbose) {
            printf ("Verbose Mode Requested \n");
        }
        if (eject) {
            printf ("Eject Requested \n");
            DockStartEject (verbose, force);
        }
    }

    printf("Done\n");

    return 0;
}


VOID
DockStartEject (
    BOOLEAN Verbose,
    BOOLEAN Force
    )
/*++

--*/
{
    CONFIGRET   status;
    BOOL        present;

    if (Verbose) {
        printf("Checking if Dock Present\n");
    }

    status = CM_Is_Dock_Station_Present (&present);

    if (Verbose) {
        printf("ret 0x%x, Present %s\n",
               status,
               (present ? "TRUE" : "FALSE"));
    }

    if (Force || present) {
        if (Verbose) {
            printf("Calling eject\n");
        }

        status = CM_Request_Eject_PC ();

        if (Verbose) {
            printf("ret 0x%x\n", status);
        }

    } else {
        printf("Skipping eject call\n");
    }
}


#if 0

BOOLEAN
OpenGamePort (
    IN       HDEVINFO                    HardwareDeviceInfo,
    IN       PSP_INTERFACE_DEVICE_DATA   DeviceInfoData,
    IN OUT   PGAME_PORT                  GamePort
    );

BOOLEAN
FindKnownGamePorts (
   OUT PGAME_PORT *     GamePorts, // A array of struct _GAME_PORT.
   OUT PULONG           NumberDevices // the length in elements of this array.
   )
/*++
Routine Description:
   Do the required PnP things in order to find, the all the HID devices in
   the system at this time.
--*/
{
   HDEVINFO                 hardwareDeviceInfo;
   SP_INTERFACE_DEVICE_DATA deviceInfoData;
   ULONG                    i;
   BOOLEAN                  done;
   PGAME_PORT               gamePortInst;
   LPGUID                   gamePortGuid;

   gamePortGuid = (LPGUID) &GUID_GAMEENUM_BUS_ENUMERATOR;

   *GamePorts = NULL;
   *NumberDevices = 0;

   //
   // Open a handle to the plug and play dev node.
   //
   hardwareDeviceInfo = SetupDiGetClassDevs (
                           gamePortGuid,
                           NULL, // Define no enumerator (global)
                           NULL, // Define no
                           (DIGCF_PRESENT | // Only Devices present
                            DIGCF_INTERFACEDEVICE)); // Function class devices.

   //
   // Take a wild guess to start
   //
   *NumberDevices = 4;
   done = FALSE;
   deviceInfoData.cbSize = sizeof (SP_INTERFACE_DEVICE_DATA);

   i=0;
   while (!done) {
      *NumberDevices *= 2;

      if (*GamePorts) {
         *GamePorts =
               realloc (*GamePorts, (*NumberDevices * sizeof (GAME_PORT)));
      } else {
         *GamePorts = calloc (*NumberDevices, sizeof (GAME_PORT));
      }

      if (NULL == *GamePorts) {
         SetupDiDestroyDeviceInfoList (hardwareDeviceInfo);
         return FALSE;
      }

      gamePortInst = *GamePorts + i;

      for (; i < *NumberDevices; i++, gamePortInst++) {
         if (SetupDiEnumInterfaceDevice (hardwareDeviceInfo,
                                         0, // No care about specific PDOs
                                         gamePortGuid,
                                         i,
                                         &deviceInfoData)) {

            if( !OpenGamePort (hardwareDeviceInfo, &deviceInfoData, gamePortInst) )
                printf("Error: OpenGamePort returned FALSE\n");

         } else {
            if (ERROR_NO_MORE_ITEMS == GetLastError()) {
               done = TRUE;
               break;
            }
         }
      }
   }

   *NumberDevices = i;

   SetupDiDestroyDeviceInfoList (hardwareDeviceInfo);
   return TRUE;
}

BOOLEAN
OpenGamePort (
    IN       HDEVINFO                    HardwareDeviceInfo,
    IN       PSP_INTERFACE_DEVICE_DATA   DeviceInfoData,
    IN OUT   PGAME_PORT                  GamePort
    )
/*++
RoutineDescription:
    Given the HardwareDeviceInfo, representing a handle to the plug and
    play information, and deviceInfoData, representing a specific hid device,
    open that device and fill in all the relivant information in the given
    HID_DEVICE structure.

    return if the open and initialization was successfull or not.

--*/
{
    PSP_INTERFACE_DEVICE_DETAIL_DATA     functionClassDeviceData = NULL;
    ULONG                                predictedLength = 0;
    ULONG                                requiredLength = 0;
    ULONG                                i, bytes;
    GAMEENUM_REMOVE_HARDWARE             remove;

    //
    // allocate a function class device data structure to receive the
    // goods about this particular device.
    //
    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;
    // sizeof (SP_FNCLASS_DEVICE_DATA) + 512;

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

    //
    // Retrieve the information from Plug and Play.
    //
    if (! SetupDiGetInterfaceDeviceDetail (
               HardwareDeviceInfo,
               DeviceInfoData,
               functionClassDeviceData,
               predictedLength,
               &requiredLength,
               NULL)) {
        printf("Error in SetupDiGetInterfaceDeviceDetail\n");
        free (functionClassDeviceData);
        return FALSE;
    }

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

    GamePort->File = CreateFile (
                              functionClassDeviceData->DevicePath,
                              GENERIC_READ | GENERIC_WRITE,
                              0, // FILE_SHARE_READ | FILE_SHARE_WRITE
                              NULL, // no SECURITY_ATTRIBUTES structure
                              OPEN_EXISTING, // No special create flags
                              0, // No special attributes
                              NULL); // No template file

    if (INVALID_HANDLE_VALUE == GamePort->File) {
        printf("Error in CreateFile: %x", GetLastError());
        free (functionClassDeviceData);
        return FALSE;
    }
    printf("File Opened!!!\n");

    GamePort->Desc.Size = sizeof (GamePort->Desc);

    if (!DeviceIoControl (GamePort->File,
                          IOCTL_GAMEENUM_PORT_DESC,
                          &GamePort->Desc, sizeof (GamePort->Desc),
                          &GamePort->Desc, sizeof (GamePort->Desc),
                          &bytes, NULL)) {
        printf("Error in DeviceIoctl IOCTL_GAMEENUM_PORT_DESC: %x", GetLastError());
        free (functionClassDeviceData);
        return FALSE;
    }

    printf("Description: Size (%d), Handle (0x%x), Address (0x%x) \n",
           GamePort->Desc.Size,
           GamePort->Desc.PortHandle,
           GamePort->Desc.PortAddress);


    //
    // Set the port up
    //
    if(bExpose) {
        printf("\nThis handle is not valid for remove!!!\n\nExposing port\n");

        GamePort->Hardware = malloc (bytes = (sizeof (GAMEENUM_EXPOSE_HARDWARE) +
                                              GAME_HARDWARE_IDS_LENGTH));

        GamePort->Hardware->Size = sizeof (GAMEENUM_EXPOSE_HARDWARE);
        GamePort->Hardware->PortHandle = GamePort->Desc.PortHandle;
        printf("Enter Number of Joysticks:");
        scanf("%d",&GamePort->Hardware->NumberJoysticks);
        printf("Enter Number of Buttons:");
        scanf("%d", &GamePort->Hardware->NumberButtons);
        printf("Enter Number of Axes:");
        scanf("%d", &GamePort->Hardware->NumberAxis);
        memcpy (GamePort->Hardware->HardwareIDs,
                GAME_HARDWARE_IDS,
                GAME_HARDWARE_IDS_LENGTH);

        if (!DeviceIoControl (GamePort->File,
                              IOCTL_GAMEENUM_EXPOSE_HARDWARE,
                              GamePort->Hardware, bytes,
                              GamePort->Hardware, bytes,
                              &bytes, NULL)) {
              free (functionClassDeviceData);
              free (GamePort->Hardware);
              GamePort->Hardware = NULL;
              printf("Error in DeviceIoctl IOCTL_GAMEENUM_EXPOSE_HARDWARE:  0x%x\n", GetLastError());
              return FALSE;
        }
        printf("Hardware handle 0x%x   <-----  Save this handle!!!\n",GamePort->Hardware->HardwareHandle);
        printf("\t\tGameEnum -r will not be able retrieve it for you.\n");

        free (GamePort->Hardware);
        GamePort->Hardware = NULL;
    }

    if(bRemove) {
        printf("Removing  port\n");

        remove.Size = bytes = sizeof (remove);
        printf("Enter hardware handle: ");
        scanf("%x",&remove.HardwareHandle);
        printf("Entered Handle: %x", remove.HardwareHandle);

        if (!DeviceIoControl (GamePort->File,
                              IOCTL_GAMEENUM_REMOVE_HARDWARE,
                              &remove, bytes,
                              &remove, bytes,
                              &bytes, NULL)) {
            printf("Error in DeviceIoctl IOCTL_GAMEENUM_REMOVE_HARDWARE:  0x%x\n", GetLastError());
            return FALSE;
        }
    }

    free (functionClassDeviceData);
    return TRUE;
}

#endif