|
|
//**************************************************************************
//
// HOTPLUG.C -- Xena Gaming Project
//
// Version 3.XX
//
// Copyright (c) 1997 Microsoft Corporation. All rights reserved.
//
// @doc
// @module HOTPLUG.C | Routines to support GameEnum hot-plugging
//**************************************************************************
#include "msgame.h"
//---------------------------------------------------------------------------
// Private Procedures
//---------------------------------------------------------------------------
static VOID MSGAME_CreateDeviceItem (PGAME_WORK_ITEM WorkItem); static VOID MSGAME_RemoveDeviceItem (PGAME_WORK_ITEM WorkItem);
//---------------------------------------------------------------------------
// @func Calls GameEnum to add a new device to the chain
// @parm PGAME_WORK_ITEM | WorkItem | Pointer to add work item
// @rdesc None
// @comm Private function
//---------------------------------------------------------------------------
VOID MSGAME_CreateDeviceItem (PGAME_WORK_ITEM WorkItem) { PIRP pIrp; KEVENT Event; NTSTATUS ntStatus; PDEVICEINFO DevInfo; PDEVICE_EXTENSION DevExt; IO_STATUS_BLOCK IoStatus; GAMEENUM_EXPOSE_SIBLING ExposeSibling;
MsGamePrint ((DBG_INFORM, "%s: %s_ExposeSiblingItem Enter\n", MSGAME_NAME, MSGAME_NAME)); //
// Get a pointer to the device extension.
//
DevExt = GET_MINIDRIVER_DEVICE_EXTENSION (WorkItem->DeviceObject);
//
// Initialize expose sibling structure
//
memset (&ExposeSibling, 0, sizeof (ExposeSibling)); ExposeSibling.Size = sizeof (GAMEENUM_EXPOSE_SIBLING);
//
// Are we changing device or adding a sibling?
//
DevInfo = GET_DEVICE_DETECTED(&WorkItem->PortInfo); if (!DevInfo) DevInfo = GET_DEVICE_INFO(&WorkItem->PortInfo); else ExposeSibling.HardwareIDs = DevInfo->HardwareId;
//
// Initialize the completion event
//
KeInitializeEvent (&Event, SynchronizationEvent, FALSE);
//
// Allocate Internal I/O IRP
//
pIrp = IoBuildDeviceIoControlRequest ( IOCTL_GAMEENUM_EXPOSE_SIBLING, DevExt->TopOfStack, &ExposeSibling, sizeof (GAMEENUM_EXPOSE_SIBLING), &ExposeSibling, sizeof (GAMEENUM_EXPOSE_SIBLING), TRUE, &Event, &IoStatus); //
// Call GameEnum synchronously
//
MsGamePrint ((DBG_CONTROL, "%s: Calling GameEnum to Expose Device at IRQL=%lu\n", MSGAME_NAME, KeGetCurrentIrql())); ntStatus = IoCallDriver (DevExt->TopOfStack, pIrp); if (ntStatus == STATUS_PENDING) ntStatus = KeWaitForSingleObject (&Event, Suspended, KernelMode, FALSE, NULL);
if (!NT_SUCCESS (ntStatus)) MsGamePrint ((DBG_SEVERE, "%s: GameEnum Failed to Expose Device, Status = %X\n", MSGAME_NAME, ntStatus));
//
// Free work item memory
//
ExFreePool (WorkItem);
//
// Decrement IRP count holding driver in memory
//
if (!InterlockedDecrement (&DevExt->IrpCount)) KeSetEvent (&DevExt->RemoveEvent, 0, FALSE); }
//---------------------------------------------------------------------------
// @func Calls GameEnum to remove a device from the chain
// @parm PGAME_WORK_ITEM | WorkItem | Pointer to add work item
// @rdesc None
// @comm Public function
//---------------------------------------------------------------------------
VOID MSGAME_RemoveDeviceItem (PGAME_WORK_ITEM WorkItem) { PIRP pIrp; KEVENT Event; NTSTATUS ntStatus; PDEVICE_EXTENSION DevExt; IO_STATUS_BLOCK IoStatus;
MsGamePrint ((DBG_INFORM, "%s: %s_RemoveDeviceItem Enter\n", MSGAME_NAME, MSGAME_NAME)); //
// Get a pointer to the device extension.
//
DevExt = GET_MINIDRIVER_DEVICE_EXTENSION (WorkItem->DeviceObject);
//
// Initialize the completion event
//
KeInitializeEvent (&Event, SynchronizationEvent, FALSE);
//
// Allocate Internal I/O IRP
//
pIrp = IoBuildDeviceIoControlRequest ( IOCTL_GAMEENUM_REMOVE_SELF, DevExt->TopOfStack, NULL, 0, NULL, 0, TRUE, &Event, &IoStatus);
//
// Call GameEnum synchronously
//
MsGamePrint ((DBG_CONTROL, "%s: Calling GameEnum to Remove Self at IRQL=%lu\n", MSGAME_NAME, KeGetCurrentIrql())); ntStatus = IoCallDriver (DevExt->TopOfStack, pIrp); if (ntStatus == STATUS_PENDING) ntStatus = KeWaitForSingleObject (&Event, Suspended, KernelMode, FALSE, NULL);
if (!NT_SUCCESS (ntStatus)) MsGamePrint ((DBG_SEVERE, "%s: GameEnum Failed to Remove Self, Status = %X\n", MSGAME_NAME, ntStatus));
//
// Free work item memory
//
ExFreePool (WorkItem);
//
// Decrement IRP count holding driver in memory
//
if (!InterlockedDecrement (&DevExt->IrpCount)) KeSetEvent (&DevExt->RemoveEvent, 0, FALSE); }
//---------------------------------------------------------------------------
// @func Calls GameEnum to add a new device to the chain
// @parm PDEVICE_OBJECT | DeviceObject | Pointer to device object
// @rdesc Returns NT status code
// @comm Public function
//---------------------------------------------------------------------------
NTSTATUS MSGAME_CreateDevice (PDEVICE_OBJECT DeviceObject) { PGAME_WORK_ITEM WorkItem; PDEVICE_EXTENSION DevExt;
MsGamePrint ((DBG_INFORM, "%s: %s_ExposeSibling Enter\n", MSGAME_NAME, MSGAME_NAME));
//
// Get pointer to device extension.
//
DevExt = GET_MINIDRIVER_DEVICE_EXTENSION (DeviceObject);
//
// Allocate work item memory
//
WorkItem = ExAllocatePool (NonPagedPool, sizeof (GAME_WORK_ITEM)); if (!WorkItem) { MsGamePrint ((DBG_SEVERE, "%s: %s_ExposeSibling Failed to Allocate Work Item\n", MSGAME_NAME, MSGAME_NAME)); return (STATUS_INSUFFICIENT_RESOURCES); }
//
// Increment IRP count to hold driver in memory
//
InterlockedIncrement (&DevExt->IrpCount);
//
// Initialize work item memory
//
ExInitializeWorkItem (&WorkItem->QueueItem, (PWORKER_THREAD_ROUTINE)MSGAME_CreateDeviceItem, WorkItem); WorkItem->DeviceObject = DeviceObject; WorkItem->PortInfo = DevExt->PortInfo;
//
// Queue the work item
//
MsGamePrint ((DBG_CONTROL, "%s: %s_ExposeSibling Queueing %s_ExposeSiblingItem\n", MSGAME_NAME, MSGAME_NAME, MSGAME_NAME)); ExQueueWorkItem (&WorkItem->QueueItem, DelayedWorkQueue);
//
// Return status
//
return (STATUS_SUCCESS); }
//---------------------------------------------------------------------------
// @func Calls GameEnum to remove a device from the chain
// @parm PDEVICE_OBJECT | DeviceObject | Pointer to device object
// @parm PIRP | pIrp | Pointer to IO request packet
// @comm Public function
//---------------------------------------------------------------------------
NTSTATUS MSGAME_RemoveDevice (PDEVICE_OBJECT DeviceObject) { PDEVICEINFO DevInfo; PGAME_WORK_ITEM WorkItem; PDEVICE_EXTENSION DevExt;
MsGamePrint ((DBG_INFORM, "%s: %s_RemoveDevice Enter\n", MSGAME_NAME, MSGAME_NAME));
//
// Get pointer to device extension.
//
DevExt = GET_MINIDRIVER_DEVICE_EXTENSION (DeviceObject);
//
// Get device information
//
DevInfo = GET_DEVICE_INFO(&DevExt->PortInfo);
//
// Skip if device already removed
//
if (DevExt->Removing || DevExt->Surprised || DevExt->Removed) { MsGamePrint ((DBG_SEVERE, "%s: %s_RemoveDevice attempted to destroy removed device\n", MSGAME_NAME, MSGAME_NAME)); InterlockedIncrement (&DevInfo->DevicePending); return (STATUS_DELETE_PENDING); }
//
// Allocate work item memory
//
WorkItem = ExAllocatePool (NonPagedPool, sizeof (GAME_WORK_ITEM)); if (!WorkItem) { MsGamePrint ((DBG_SEVERE, "%s: %s_RemoveDevice Failed to Allocate Work Item\n", MSGAME_NAME, MSGAME_NAME)); return (STATUS_INSUFFICIENT_RESOURCES); }
//
// Increment IRP count to hold driver in memory
//
InterlockedIncrement (&DevExt->IrpCount);
//
// Mark device as being removed
//
DevExt->Removing = TRUE;
//
// Initialize work item memory
//
ExInitializeWorkItem (&WorkItem->QueueItem, (PWORKER_THREAD_ROUTINE)MSGAME_RemoveDeviceItem, WorkItem); WorkItem->DeviceObject = DevExt->Self; WorkItem->PortInfo = DevExt->PortInfo;
//
// Queue the work item
//
MsGamePrint ((DBG_CONTROL, "%s: %s_RemoveDevice Queueing %s_RemoveDeviceItem\n", MSGAME_NAME, MSGAME_NAME, MSGAME_NAME)); ExQueueWorkItem (&WorkItem->QueueItem, DelayedWorkQueue);
//
// Return status
//
return (STATUS_DEVICE_NOT_READY); }
//---------------------------------------------------------------------------
// @func Calls GameEnum to add a new device to the chain
// @parm PDEVICE_OBJECT | DeviceObject | Pointer to device object
// @rdesc Returns NT status code
// @comm Public function
//---------------------------------------------------------------------------
NTSTATUS MSGAME_ChangeDevice (PDEVICE_OBJECT DeviceObject) { PDEVICE_EXTENSION DevExt;
MsGamePrint ((DBG_CONTROL, "%s: Calling GameEnum to Change Device\n", MSGAME_NAME));
//
// Get pointer to device extension.
//
DevExt = GET_MINIDRIVER_DEVICE_EXTENSION (DeviceObject);
//
// Increment IRP count to hold driver in memory
//
// InterlockedIncrement (&DevExt->IrpCount);
//
// Remove old device first
//
MSGAME_RemoveDevice (DeviceObject);
//
// Create new device second
//
MSGAME_CreateDevice (DeviceObject);
//
// Return status
//
return (STATUS_DEVICE_NOT_READY); }
|