//************************************************************************** // // MSGAME.C -- Xena Gaming Project // // Version 3.XX // // Copyright (c) 1997 Microsoft Corporation. All rights reserved. // // @doc // @module MSGAME.C | Human Input Device (HID) gameport driver //************************************************************************** #include "msgame.h" //--------------------------------------------------------------------------- // Alloc_text pragma to specify routines that can be paged out. //--------------------------------------------------------------------------- #ifdef ALLOC_PRAGMA #pragma alloc_text (INIT, DriverEntry) #pragma alloc_text (INIT, MSGAME_ReadRegistry) #pragma alloc_text (PAGE, MSGAME_CreateClose) #pragma alloc_text (PAGE, MSGAME_SystemControl) #pragma alloc_text (PAGE, MSGAME_AddDevice) #endif //--------------------------------------------------------------------------- // Private Data //--------------------------------------------------------------------------- static UNICODE_STRING RegistryPath; //--------------------------------------------------------------------------- // @func Main driver entry point // @parm PDRIVER_OBJECT | DriverObject | Pointer to driver object // @parm PUNICODE_STRING | registryPath | Registry path for this device // @rdesc Returns NT status code // @comm Public function //--------------------------------------------------------------------------- NTSTATUS DriverEntry (IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING registryPath) { NTSTATUS ntStatus; RTL_QUERY_REGISTRY_TABLE Parameters[2]; HID_MINIDRIVER_REGISTRATION HidMinidriverRegistration; MsGamePrint ((DBG_CRITICAL, "%s: Built %s at %s\n", MSGAME_NAME, __DATE__, __TIME__)); MsGamePrint ((DBG_INFORM, "%s: DriverEntry Enter\n", MSGAME_NAME)); // // Fill in driver dispatch table // DriverObject->MajorFunction[IRP_MJ_CREATE] = MSGAME_CreateClose; DriverObject->MajorFunction[IRP_MJ_CLOSE] = MSGAME_CreateClose; DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = MSGAME_Internal_Ioctl; DriverObject->MajorFunction[IRP_MJ_PNP] = MSGAME_PnP; DriverObject->MajorFunction[IRP_MJ_POWER] = MSGAME_Power; DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = MSGAME_SystemControl; DriverObject->DriverUnload = MSGAME_Unload; DriverObject->DriverExtension->AddDevice = MSGAME_AddDevice; // // Register driver with Hid.Sys // HidMinidriverRegistration.Revision = HID_REVISION; HidMinidriverRegistration.DriverObject = DriverObject; HidMinidriverRegistration.RegistryPath = registryPath; HidMinidriverRegistration.DeviceExtensionSize = sizeof (DEVICE_EXTENSION); HidMinidriverRegistration.DevicesArePolled = TRUE; MsGamePrint ((DBG_CONTROL, "%s: Registering with HID.SYS\n", MSGAME_NAME)); ntStatus = HidRegisterMinidriver (&HidMinidriverRegistration); // // Need to ensure that the registry path is null-terminated. // Allocate pool to hold a null-terminated copy of the path. // if (NT_SUCCESS(ntStatus)) { RtlInitUnicodeString (&RegistryPath, NULL); RegistryPath.Length = registryPath->Length + sizeof(UNICODE_NULL); RegistryPath.MaximumLength = RegistryPath.Length; RegistryPath.Buffer = ExAllocatePool (PagedPool, RegistryPath.Length); RtlZeroMemory (RegistryPath.Buffer, RegistryPath.Length); RtlMoveMemory (RegistryPath.Buffer, registryPath->Buffer, registryPath->Length); } // // Read any driver specific registry values // if (NT_SUCCESS(ntStatus)) { RtlZeroMemory (Parameters, sizeof(Parameters)); Parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT; Parameters[0].Name = L"PollingInterval"; Parameters[0].EntryContext = &PollingInterval; Parameters[0].DefaultType = REG_DWORD; Parameters[0].DefaultData = &PollingInterval; Parameters[0].DefaultLength = sizeof(ULONG); if (!NT_SUCCESS(RtlQueryRegistryValues (RTL_REGISTRY_ABSOLUTE, RegistryPath.Buffer, Parameters, NULL, NULL))) { MsGamePrint((DBG_INFORM,"%s: %s_DriverEntry RtlQueryRegistryValues failed\n", MSGAME_NAME, MSGAME_NAME)); RtlWriteRegistryValue (RTL_REGISTRY_ABSOLUTE, RegistryPath.Buffer, L"PollingInterval", REG_DWORD, &PollingInterval, sizeof (ULONG)); } MsGamePrint((DBG_CONTROL,"%s: Polling interval will be %lu milliseconds\n", MSGAME_NAME, PollingInterval)); } // // Initialize portio layer on entry // if (NT_SUCCESS(ntStatus)) ntStatus = PORTIO_DriverEntry (); // // Initialize device layer on entry // if (NT_SUCCESS(ntStatus)) ntStatus = DEVICE_DriverEntry (); // // Return driver status // MsGamePrint ((DBG_INFORM, "%s: DriverEntry Exit = %x\n", MSGAME_NAME, ntStatus)); return (ntStatus); } //--------------------------------------------------------------------------- // @func Process the Create and Close IRPs // @parm PDEVICE_OBJECT | DeviceObject | Pointer to device object // @parm PIRP | pIrp | Pointer to IO request packet // @rdesc Returns NT status code // @comm Public function //--------------------------------------------------------------------------- NTSTATUS MSGAME_CreateClose (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PIO_STACK_LOCATION IrpStack; NTSTATUS ntStatus = STATUS_SUCCESS; PAGED_CODE (); MsGamePrint ((DBG_INFORM, "%s: %s_CreateClose Enter\n", MSGAME_NAME, MSGAME_NAME)); // // Get pointer to current location in Irp // IrpStack = IoGetCurrentIrpStackLocation (Irp); // // Process Create or Close function call // switch (IrpStack->MajorFunction) { case IRP_MJ_CREATE: MsGamePrint ((DBG_VERBOSE, "%s: IRP_MJ_CREATE\n", MSGAME_NAME)); Irp->IoStatus.Information = 0; break; case IRP_MJ_CLOSE: MsGamePrint ((DBG_VERBOSE, "%s: IRP_MJ_CLOSE\n", MSGAME_NAME)); Irp->IoStatus.Information = 0; break; default: MsGamePrint ((DBG_SEVERE, "%s: Invalid CreateClose Parameter\n", MSGAME_NAME)); ntStatus = STATUS_INVALID_PARAMETER; break; } // // Save Status for return and complete Irp // Irp->IoStatus.Status = ntStatus; IoCompleteRequest (Irp, IO_NO_INCREMENT); MsGamePrint ((DBG_INFORM, "%s: %s_CreateClose Exit = %x\n", MSGAME_NAME, MSGAME_NAME, ntStatus)); return (ntStatus); } //--------------------------------------------------------------------------- // @func Process the WMI system control IRPs // @parm PDEVICE_OBJECT | DeviceObject | Pointer to device object // @parm PIRP | pIrp | Pointer to IO request packet // @rdesc Returns NT status code // @comm Public function //--------------------------------------------------------------------------- NTSTATUS MSGAME_SystemControl (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { NTSTATUS ntStatus = STATUS_SUCCESS; PAGED_CODE (); MsGamePrint ((DBG_INFORM, "%s: %s_SystemControl Enter\n", MSGAME_NAME, MSGAME_NAME)); IoSkipCurrentIrpStackLocation (Irp); ntStatus = IoCallDriver (GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp); MsGamePrint ((DBG_INFORM, "%s: %s_SystemControl Exit = %x\n", MSGAME_NAME, MSGAME_NAME, ntStatus)); return (ntStatus); } //--------------------------------------------------------------------------- // @func Processes the Pnp Add Device call // @parm PDRIVER_OBJECT | DriverObject | Pointer to driver object // @parm PDEVICE_OBJECT | DeviceObject | Pointer to device object // @rdesc Returns NT status code // @comm Public function //--------------------------------------------------------------------------- NTSTATUS MSGAME_AddDevice (IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT DeviceObject) { NTSTATUS ntStatus = STATUS_SUCCESS; PDEVICE_EXTENSION pDevExt; PAGED_CODE (); MsGamePrint ((DBG_INFORM, "%s: %s_AddDevice Entry\n", MSGAME_NAME, MSGAME_NAME)); // // Initialize the device extension // pDevExt = GET_MINIDRIVER_DEVICE_EXTENSION (DeviceObject); memset(pDevExt, 0, sizeof(DEVICE_EXTENSION)); pDevExt->Driver = DriverObject; pDevExt->Self = DeviceObject; pDevExt->IrpCount = 1; pDevExt->Started = FALSE; pDevExt->Removed = FALSE; pDevExt->Surprised = FALSE; pDevExt->Removing = FALSE; pDevExt->TopOfStack = NULL; KeInitializeEvent (&pDevExt->StartEvent, NotificationEvent, FALSE); KeInitializeEvent (&pDevExt->RemoveEvent, SynchronizationEvent, FALSE); // // Clear device initialization flags // DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; // // Attach our functional driver to the device stack. The return value of // IoAttachDeviceToDeviceStack is the top of the attachment chain. This // is where all the IRPs should be routed. // pDevExt->TopOfStack = GET_NEXT_DEVICE_OBJECT(DeviceObject); // // If this attachment fails then top of stack will be null. Failure // for attachment is an indication of a broken plug play system. // ASSERT (pDevExt->TopOfStack); // // Return status // MsGamePrint ((DBG_INFORM, "%s: %s_AddDevice Exit = %x\n", MSGAME_NAME, MSGAME_NAME, ntStatus)); return (ntStatus); } //--------------------------------------------------------------------------- // @func Processes the driver unload call // @parm PDRIVER_OBJECT | DriverObject | Pointer to driver object // @rdesc Returns NT status code // @comm Public function //--------------------------------------------------------------------------- VOID MSGAME_Unload (IN PDRIVER_OBJECT DriverObject) { PAGED_CODE(); MsGamePrint ((DBG_INFORM, "%s: %s_Unload Enter\n", MSGAME_NAME, MSGAME_NAME)); // // All the device objects should be gone // ASSERT (!DriverObject->DeviceObject); // // Free the unicode strings. // ExFreePool (RegistryPath.Buffer); MsGamePrint ((DBG_CONTROL, "%s: %s_Unload Exit\n", MSGAME_NAME, MSGAME_NAME)); } //--------------------------------------------------------------------------- // @func Reads registry data for a named device // @parm PCHAR | DeviceName | Device name string // @parm PDEVICE_VALUES | DeviceValues | Device values structure to fill // @rdesc Returns nothing // @comm Public function //--------------------------------------------------------------------------- VOID MSGAME_ReadRegistry (PCHAR DeviceName, PDEVICE_VALUES DeviceValues) { #define PARAMS_PLUS_ONE 13 NTSTATUS ntStatus; ANSI_STRING AnsiName; UNICODE_STRING UnicodeName; UNICODE_STRING ParametersPath; PRTL_QUERY_REGISTRY_TABLE Parameters; MsGamePrint((DBG_INFORM,"%s: %s_ReadRegistry Enter\n", MSGAME_NAME, MSGAME_NAME)); // // Initialize local variables // RtlInitAnsiString (&AnsiName, DeviceName); RtlInitUnicodeString (&UnicodeName, NULL); RtlInitUnicodeString (&ParametersPath, NULL); Parameters = ExAllocatePool (PagedPool, sizeof(RTL_QUERY_REGISTRY_TABLE) * PARAMS_PLUS_ONE); if (!Parameters) { MsGamePrint((DBG_CRITICAL, "%s: %s_ReadRegistry couldn't allocate Rtl query table for %ws\n", MSGAME_NAME, MSGAME_NAME, RegistryPath.Buffer)); goto ReadRegistryExit; } RtlZeroMemory (Parameters, sizeof(RTL_QUERY_REGISTRY_TABLE) * PARAMS_PLUS_ONE); // // Form a path to this driver's Parameters subkey. // ParametersPath.MaximumLength = RegistryPath.Length + MAX_DEVICE_NAME; ParametersPath.Buffer = ExAllocatePool (PagedPool, ParametersPath.MaximumLength); if (!ParametersPath.Buffer) { MsGamePrint((DBG_CRITICAL, "%s: %s_ReadRegistry couldn't allocate path string for %ws\n", MSGAME_NAME, MSGAME_NAME, RegistryPath.Buffer)); goto ReadRegistryExit; } // // Form the Parameters path. // RtlZeroMemory (ParametersPath.Buffer, ParametersPath.MaximumLength); RtlAppendUnicodeToString (&ParametersPath, RegistryPath.Buffer); RtlAppendUnicodeToString (&ParametersPath, L"\\"); RtlAnsiStringToUnicodeString (&UnicodeName, &AnsiName, TRUE); RtlAppendUnicodeStringToString (&ParametersPath, &UnicodeName); RtlFreeUnicodeString (&UnicodeName); MsGamePrint((DBG_VERBOSE, "%s: %s_ReadRegistry path is %ws\n", MSGAME_NAME, MSGAME_NAME, ParametersPath.Buffer)); // // Gather all device information from the registry. // Parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT; Parameters[0].Name = L"PacketStartTimeout"; Parameters[0].EntryContext = &DeviceValues->PacketStartTimeout; Parameters[0].DefaultType = REG_DWORD; Parameters[0].DefaultData = &DeviceValues->PacketStartTimeout; Parameters[0].DefaultLength = sizeof(ULONG); Parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT; Parameters[1].Name = L"PacketLowHighTimeout"; Parameters[1].EntryContext = &DeviceValues->PacketLowHighTimeout; Parameters[1].DefaultType = REG_DWORD; Parameters[1].DefaultData = &DeviceValues->PacketLowHighTimeout; Parameters[1].DefaultLength = sizeof(ULONG); Parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT; Parameters[2].Name = L"PacketHighLowTimeout"; Parameters[2].EntryContext = &DeviceValues->PacketHighLowTimeout; Parameters[2].DefaultType = REG_DWORD; Parameters[2].DefaultData = &DeviceValues->PacketHighLowTimeout; Parameters[2].DefaultLength = sizeof(ULONG); Parameters[3].Flags = RTL_QUERY_REGISTRY_DIRECT; Parameters[3].Name = L"IdStartTimeout"; Parameters[3].EntryContext = &DeviceValues->IdStartTimeout; Parameters[3].DefaultType = REG_DWORD; Parameters[3].DefaultData = &DeviceValues->IdStartTimeout; Parameters[3].DefaultLength = sizeof(ULONG); Parameters[4].Flags = RTL_QUERY_REGISTRY_DIRECT; Parameters[4].Name = L"IdLowHighTimeout"; Parameters[4].EntryContext = &DeviceValues->IdLowHighTimeout; Parameters[4].DefaultType = REG_DWORD; Parameters[4].DefaultData = &DeviceValues->IdLowHighTimeout; Parameters[4].DefaultLength = sizeof(ULONG); Parameters[5].Flags = RTL_QUERY_REGISTRY_DIRECT; Parameters[5].Name = L"IdHighLowTimeout"; Parameters[5].EntryContext = &DeviceValues->IdHighLowTimeout; Parameters[5].DefaultType = REG_DWORD; Parameters[5].DefaultData = &DeviceValues->IdHighLowTimeout; Parameters[5].DefaultLength = sizeof(ULONG); Parameters[6].Flags = RTL_QUERY_REGISTRY_DIRECT; Parameters[6].Name = L"InterruptDelay"; Parameters[6].EntryContext = &DeviceValues->InterruptDelay; Parameters[6].DefaultType = REG_DWORD; Parameters[6].DefaultData = &DeviceValues->InterruptDelay; Parameters[6].DefaultLength = sizeof(ULONG); Parameters[7].Flags = RTL_QUERY_REGISTRY_DIRECT; Parameters[7].Name = L"MaxClockDutyCycle"; Parameters[7].EntryContext = &DeviceValues->MaxClockDutyCycle; Parameters[7].DefaultType = REG_DWORD; Parameters[7].DefaultData = &DeviceValues->MaxClockDutyCycle; Parameters[7].DefaultLength = sizeof(ULONG); Parameters[8].Flags = RTL_QUERY_REGISTRY_DIRECT; Parameters[8].Name = L"StatusStartTimeout"; Parameters[8].EntryContext = &DeviceValues->StatusStartTimeout; Parameters[8].DefaultType = REG_DWORD; Parameters[8].DefaultData = &DeviceValues->StatusStartTimeout; Parameters[8].DefaultLength = sizeof(ULONG); Parameters[9].Flags = RTL_QUERY_REGISTRY_DIRECT; Parameters[9].Name = L"StatusLowHighTimeout"; Parameters[9].EntryContext = &DeviceValues->StatusLowHighTimeout; Parameters[9].DefaultType = REG_DWORD; Parameters[9].DefaultData = &DeviceValues->StatusLowHighTimeout; Parameters[9].DefaultLength = sizeof(ULONG); Parameters[10].Flags = RTL_QUERY_REGISTRY_DIRECT; Parameters[10].Name = L"StatusHighLowTimeout"; Parameters[10].EntryContext = &DeviceValues->StatusHighLowTimeout; Parameters[10].DefaultType = REG_DWORD; Parameters[10].DefaultData = &DeviceValues->StatusHighLowTimeout; Parameters[10].DefaultLength = sizeof(ULONG); Parameters[11].Flags = RTL_QUERY_REGISTRY_DIRECT; Parameters[11].Name = L"StatusGateTimeout"; Parameters[11].EntryContext = &DeviceValues->StatusGateTimeout; Parameters[11].DefaultType = REG_DWORD; Parameters[11].DefaultData = &DeviceValues->StatusGateTimeout; Parameters[11].DefaultLength = sizeof(ULONG); ntStatus = RtlQueryRegistryValues (RTL_REGISTRY_ABSOLUTE, ParametersPath.Buffer, Parameters, NULL, NULL); if (!NT_SUCCESS(ntStatus)) { MsGamePrint((DBG_INFORM,"%s: %s_ReadRegistry RtlQueryRegistryValues failed with 0x%x\n", MSGAME_NAME, MSGAME_NAME, ntStatus)); // // Create registry entries as needed // RtlWriteRegistryValue (RTL_REGISTRY_ABSOLUTE, ParametersPath.Buffer, L"PacketStartTimeout", REG_DWORD, &DeviceValues->PacketStartTimeout, sizeof (ULONG)); RtlWriteRegistryValue (RTL_REGISTRY_ABSOLUTE, ParametersPath.Buffer, L"PacketLowHighTimeout", REG_DWORD, &DeviceValues->PacketLowHighTimeout, sizeof (ULONG)); RtlWriteRegistryValue (RTL_REGISTRY_ABSOLUTE, ParametersPath.Buffer, L"PacketHighLowTimeout", REG_DWORD, &DeviceValues->PacketHighLowTimeout, sizeof (ULONG)); RtlWriteRegistryValue (RTL_REGISTRY_ABSOLUTE, ParametersPath.Buffer, L"IdStartTimeout", REG_DWORD, &DeviceValues->IdStartTimeout, sizeof (ULONG)); RtlWriteRegistryValue (RTL_REGISTRY_ABSOLUTE, ParametersPath.Buffer, L"IdLowHighTimeout", REG_DWORD, &DeviceValues->IdLowHighTimeout, sizeof (ULONG)); RtlWriteRegistryValue (RTL_REGISTRY_ABSOLUTE, ParametersPath.Buffer, L"IdHighLowTimeout", REG_DWORD, &DeviceValues->IdHighLowTimeout, sizeof (ULONG)); RtlWriteRegistryValue (RTL_REGISTRY_ABSOLUTE, ParametersPath.Buffer, L"InterruptDelay", REG_DWORD, &DeviceValues->InterruptDelay, sizeof (ULONG)); RtlWriteRegistryValue (RTL_REGISTRY_ABSOLUTE, ParametersPath.Buffer, L"MaxClockDutyCycle", REG_DWORD, &DeviceValues->MaxClockDutyCycle, sizeof (ULONG)); RtlWriteRegistryValue (RTL_REGISTRY_ABSOLUTE, ParametersPath.Buffer, L"StatusStartTimeout", REG_DWORD, &DeviceValues->StatusStartTimeout, sizeof (ULONG)); RtlWriteRegistryValue (RTL_REGISTRY_ABSOLUTE, ParametersPath.Buffer, L"StatusLowHighTimeout", REG_DWORD, &DeviceValues->StatusLowHighTimeout, sizeof (ULONG)); RtlWriteRegistryValue (RTL_REGISTRY_ABSOLUTE, ParametersPath.Buffer, L"StatusHighLowTimeout", REG_DWORD, &DeviceValues->StatusHighLowTimeout, sizeof (ULONG)); RtlWriteRegistryValue (RTL_REGISTRY_ABSOLUTE, ParametersPath.Buffer, L"StatusGateTimeout", REG_DWORD, &DeviceValues->StatusGateTimeout, sizeof (ULONG)); } // ----------------- ReadRegistryExit: // ----------------- if (ParametersPath.Buffer) ExFreePool(ParametersPath.Buffer); if (Parameters) ExFreePool(Parameters); #undef PARAMS_PLUS_ONE } //--------------------------------------------------------------------------- // @func Posts a transaction to hooking driver // @parm PPACKETINFO | PacketInfo | Device packet info struct // @rdesc None // @comm Public function //--------------------------------------------------------------------------- VOID MSGAME_PostTransaction (PPACKETINFO PacketInfo) { // // Not Implemented // }