475 lines
20 KiB
C
475 lines
20 KiB
C
|
/***************************************************************************
|
||
|
|
||
|
Copyright (c) 1999 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
WDMUTIL.C
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Stuff that does not fit well with NDIS header files
|
||
|
|
||
|
Environment:
|
||
|
|
||
|
kernel mode only
|
||
|
|
||
|
Notes:
|
||
|
|
||
|
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
|
||
|
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
|
||
|
PURPOSE.
|
||
|
|
||
|
Copyright (c) 1999 Microsoft Corporation. All Rights Reserved.
|
||
|
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
5/17/99 : created
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Tom Green
|
||
|
|
||
|
|
||
|
****************************************************************************/
|
||
|
|
||
|
|
||
|
#include "precomp.h"
|
||
|
|
||
|
|
||
|
/****************************************************************************/
|
||
|
/* DeviceObjectToDriverObject */
|
||
|
/****************************************************************************/
|
||
|
/* */
|
||
|
/* Routine Description: */
|
||
|
/* */
|
||
|
/* Get driver object associated with device object. NDIS has no notion */
|
||
|
/* of the shape of a device object, so we put this here for ease of */
|
||
|
/* building *
|
||
|
/* */
|
||
|
/* Arguments: */
|
||
|
/* */
|
||
|
/* DeviceObject - device object we to get associated driver object for */
|
||
|
/* */
|
||
|
/* Return: */
|
||
|
/* */
|
||
|
/* PDRIVER_OBJECT */
|
||
|
/* */
|
||
|
/****************************************************************************/
|
||
|
PDRIVER_OBJECT
|
||
|
DeviceObjectToDriverObject(IN PDEVICE_OBJECT DeviceObject)
|
||
|
{
|
||
|
return DeviceObject->DriverObject;
|
||
|
} // DeviceObjectToDriverObject
|
||
|
|
||
|
|
||
|
/****************************************************************************/
|
||
|
/* GetDeviceFriendlyName */
|
||
|
/****************************************************************************/
|
||
|
/* */
|
||
|
/* Routine Description: */
|
||
|
/* */
|
||
|
/* Return the friendly name associated with the given device object. */
|
||
|
/* */
|
||
|
/* Arguments: */
|
||
|
/* */
|
||
|
/* pDeviceObject - device object we to get associated driver object for */
|
||
|
/* ppName - Place to return a pointer to an ANSI string containing name */
|
||
|
/* pNameLength - Place to return length of above string */
|
||
|
/* */
|
||
|
/* Return: */
|
||
|
/* */
|
||
|
/* NTSTATUS */
|
||
|
/* */
|
||
|
/****************************************************************************/
|
||
|
NTSTATUS
|
||
|
GetDeviceFriendlyName(IN PDEVICE_OBJECT pDeviceObject,
|
||
|
OUT PANSI_STRING pAnsiName,
|
||
|
OUT PUNICODE_STRING pUnicodeName)
|
||
|
{
|
||
|
NTSTATUS NtStatus;
|
||
|
NDIS_STATUS Status;
|
||
|
ULONG ResultLength;
|
||
|
DEVICE_REGISTRY_PROPERTY Property;
|
||
|
UNICODE_STRING UnicodeString;
|
||
|
ANSI_STRING AnsiString;
|
||
|
USHORT AnsiMaxLength;
|
||
|
PWCHAR pValueInfo;
|
||
|
ULONG i;
|
||
|
|
||
|
pValueInfo = NULL;
|
||
|
AnsiString.Buffer = NULL;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
Property = DevicePropertyFriendlyName;
|
||
|
|
||
|
for (i = 0; i < 2; i++)
|
||
|
{
|
||
|
NtStatus = IoGetDeviceProperty(pDeviceObject,
|
||
|
Property,
|
||
|
0,
|
||
|
NULL,
|
||
|
&ResultLength);
|
||
|
|
||
|
if (NtStatus != STATUS_BUFFER_TOO_SMALL)
|
||
|
{
|
||
|
ASSERT(!NT_SUCCESS(NtStatus));
|
||
|
Property = DevicePropertyDeviceDescription;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Status = MemAlloc(&pValueInfo, ResultLength);
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
NtStatus = IoGetDeviceProperty(pDeviceObject,
|
||
|
Property,
|
||
|
ResultLength,
|
||
|
pValueInfo,
|
||
|
&ResultLength);
|
||
|
|
||
|
if (NtStatus != STATUS_SUCCESS)
|
||
|
{
|
||
|
TRACE1(("IoGetDeviceProperty returned %x\n", NtStatus));
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
RtlInitUnicodeString(&UnicodeString, pValueInfo);
|
||
|
|
||
|
//
|
||
|
// Allocate space for ANSI version.
|
||
|
//
|
||
|
AnsiMaxLength = UnicodeString.MaximumLength / sizeof(WCHAR);
|
||
|
Status = MemAlloc(&AnsiString.Buffer, AnsiMaxLength);
|
||
|
|
||
|
if (Status != NDIS_STATUS_SUCCESS)
|
||
|
{
|
||
|
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
RtlFillMemory(AnsiString.Buffer, AnsiMaxLength, 0);
|
||
|
AnsiString.MaximumLength = AnsiMaxLength;
|
||
|
AnsiString.Length = 0;
|
||
|
|
||
|
NtStatus = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, FALSE);
|
||
|
|
||
|
if (!NT_SUCCESS(NtStatus))
|
||
|
{
|
||
|
ASSERT(FALSE);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
*pAnsiName = AnsiString;
|
||
|
*pUnicodeName = UnicodeString;
|
||
|
break;
|
||
|
}
|
||
|
while (FALSE);
|
||
|
|
||
|
if (!NT_SUCCESS(NtStatus))
|
||
|
{
|
||
|
if (pValueInfo)
|
||
|
{
|
||
|
MemFree(pValueInfo, -1);
|
||
|
}
|
||
|
|
||
|
if (AnsiString.Buffer)
|
||
|
{
|
||
|
MemFree(AnsiString.Buffer, AnsiString.MaximumLength);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return (NtStatus);
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************/
|
||
|
/* HookPnpDispatchRoutine */
|
||
|
/****************************************************************************/
|
||
|
/* */
|
||
|
/* Routine Description: */
|
||
|
/* */
|
||
|
/* Set up the driver object for the specified microport driver to */
|
||
|
/* intercept the IRP_MJ_PNP dispatch routine before it gets to NDIS. */
|
||
|
/* This is in order to support surprise removal on platforms where we */
|
||
|
/* don't have NDIS 5.1 support. If we are running on >= NDIS 5.1, don't */
|
||
|
/* do anything. */
|
||
|
/* */
|
||
|
/* Arguments: */
|
||
|
/* */
|
||
|
/* DriverBlock - pointer to driver block structure for this microport. */
|
||
|
/* */
|
||
|
/* Return: */
|
||
|
/* */
|
||
|
/* VOID */
|
||
|
/* */
|
||
|
/****************************************************************************/
|
||
|
VOID
|
||
|
HookPnpDispatchRoutine(IN PDRIVER_BLOCK DriverBlock)
|
||
|
{
|
||
|
if ((DriverBlock->MajorNdisVersion <= 5) ||
|
||
|
((DriverBlock->MajorNdisVersion == 5) && (DriverBlock->MinorNdisVersion < 1)))
|
||
|
{
|
||
|
DriverBlock->SavedPnPDispatch =
|
||
|
DriverBlock->DriverObject->MajorFunction[IRP_MJ_PNP];
|
||
|
DriverBlock->DriverObject->MajorFunction[IRP_MJ_PNP] = PnPDispatch;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/****************************************************************************/
|
||
|
/* PnPDispatch */
|
||
|
/****************************************************************************/
|
||
|
/* */
|
||
|
/* Routine Description: */
|
||
|
/* */
|
||
|
/* Dispatch routine for IRP_MJ_PNP that is called by the I/O system. */
|
||
|
/* We process surprise removal and query capabilities. */
|
||
|
/* In all cases, we pass on the IRP to NDIS for further processing. */
|
||
|
/* */
|
||
|
/* Arguments: */
|
||
|
/* */
|
||
|
/* pDeviceObject - pointer to Device Object */
|
||
|
/* pIrp - pointer to IRP */
|
||
|
/* */
|
||
|
/* Return: */
|
||
|
/* */
|
||
|
/* VOID */
|
||
|
/* */
|
||
|
/****************************************************************************/
|
||
|
NTSTATUS
|
||
|
PnPDispatch(IN PDEVICE_OBJECT pDeviceObject,
|
||
|
IN PIRP pIrp)
|
||
|
{
|
||
|
PIO_STACK_LOCATION pIrpSp;
|
||
|
NTSTATUS Status;
|
||
|
PDRIVER_BLOCK DriverBlock;
|
||
|
PRNDISMP_ADAPTER pAdapter;
|
||
|
|
||
|
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
||
|
|
||
|
DeviceObjectToAdapterAndDriverBlock(pDeviceObject, &pAdapter, &DriverBlock);
|
||
|
|
||
|
TRACE3(("PnPDispatch: Adapter %x, MinorFunction %x\n",
|
||
|
pAdapter, pIrpSp->MinorFunction));
|
||
|
|
||
|
switch (pIrpSp->MinorFunction)
|
||
|
{
|
||
|
case IRP_MN_QUERY_CAPABILITIES:
|
||
|
pIrpSp->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = 1;
|
||
|
break;
|
||
|
|
||
|
case IRP_MN_SURPRISE_REMOVAL:
|
||
|
TRACE1(("PnPDispatch: PDO %p, Adapter %p, surprise removal!\n",
|
||
|
pDeviceObject, pAdapter));
|
||
|
if (pAdapter)
|
||
|
{
|
||
|
RndismpInternalHalt((NDIS_HANDLE)pAdapter, FALSE);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Status = (DriverBlock->SavedPnPDispatch)(
|
||
|
pDeviceObject,
|
||
|
pIrp);
|
||
|
|
||
|
return (Status);
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifdef BUILD_WIN9X
|
||
|
|
||
|
/****************************************************************************/
|
||
|
/* HookNtKernCMHandler */
|
||
|
/****************************************************************************/
|
||
|
/* */
|
||
|
/* Routine Description: */
|
||
|
/* */
|
||
|
/* Swap the CM handler routine within NDIS' data structures such that */
|
||
|
/* we get called when NDIS forwards a CM message. This can only work on */
|
||
|
/* Win98 and Win98SE. */
|
||
|
/* */
|
||
|
/* Arguments: */
|
||
|
/* */
|
||
|
/* Adapter - pointer to our adapter block */
|
||
|
/* */
|
||
|
/* Return: */
|
||
|
/* */
|
||
|
/* VOID */
|
||
|
/* */
|
||
|
/****************************************************************************/
|
||
|
VOID
|
||
|
HookNtKernCMHandler(IN PRNDISMP_ADAPTER pAdapter)
|
||
|
{
|
||
|
PVOID pNdisWrapperAdapterBlock;
|
||
|
PVOID pDetect;
|
||
|
ULONG WrapContextOffset;
|
||
|
|
||
|
pDetect = (PVOID)((ULONG_PTR)pAdapter->MiniportAdapterHandle + 0x29c);
|
||
|
|
||
|
if (*(PVOID *)pDetect == (PVOID)pAdapter->pPhysDeviceObject)
|
||
|
{
|
||
|
// Win98Gold
|
||
|
WrapContextOffset = 0xf8;
|
||
|
pAdapter->bRunningOnWin98Gold = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Win98SE
|
||
|
WrapContextOffset = 0x60;
|
||
|
pAdapter->bRunningOnWin98Gold = FALSE;
|
||
|
}
|
||
|
pAdapter->WrapContextOffset = WrapContextOffset;
|
||
|
|
||
|
pNdisWrapperAdapterBlock = *(PVOID *)((ULONG_PTR)pAdapter->MiniportAdapterHandle + WrapContextOffset);
|
||
|
|
||
|
// Save away the old handler:
|
||
|
pAdapter->NdisCmConfigHandler = (MY_CMCONFIGHANDLER)
|
||
|
(*(PVOID *)((ULONG_PTR)pNdisWrapperAdapterBlock + 0x78));
|
||
|
|
||
|
// Insert our routine:
|
||
|
(*(PVOID *)((ULONG_PTR)pNdisWrapperAdapterBlock + 0x78)) =
|
||
|
(PVOID)RndisCMHandler;
|
||
|
|
||
|
// Save the devnode to use on lookups based on devnode:
|
||
|
pAdapter->DevNode = (MY_DEVNODE)
|
||
|
(*(PVOID *)((ULONG_PTR)pNdisWrapperAdapterBlock + 0x38));
|
||
|
|
||
|
TRACE1(("HookNtKernCMHandler: Adapter %p, NdisHandler %p, DevNode %x\n",
|
||
|
pAdapter, pAdapter->NdisCmConfigHandler, pAdapter->DevNode));
|
||
|
}
|
||
|
|
||
|
/****************************************************************************/
|
||
|
/* UnHookNtKernCMHandler */
|
||
|
/****************************************************************************/
|
||
|
/* */
|
||
|
/* Routine Description: */
|
||
|
/* */
|
||
|
/* Put back the swapped Config Mgr handler in NDIS' data structures */
|
||
|
/* */
|
||
|
/* Arguments: */
|
||
|
/* */
|
||
|
/* Adapter - pointer to our adapter block */
|
||
|
/* */
|
||
|
/* Return: */
|
||
|
/* */
|
||
|
/* VOID */
|
||
|
/* */
|
||
|
/****************************************************************************/
|
||
|
VOID
|
||
|
UnHookNtKernCMHandler(IN PRNDISMP_ADAPTER pAdapter)
|
||
|
{
|
||
|
PVOID pNdisWrapperAdapterBlock;
|
||
|
|
||
|
if (pAdapter->NdisCmConfigHandler)
|
||
|
{
|
||
|
pNdisWrapperAdapterBlock = *(PVOID *)((ULONG_PTR)pAdapter->MiniportAdapterHandle + pAdapter->WrapContextOffset);
|
||
|
(*(PVOID *)((ULONG_PTR)pNdisWrapperAdapterBlock + 0x78)) =
|
||
|
(PVOID)pAdapter->NdisCmConfigHandler;
|
||
|
}
|
||
|
|
||
|
TRACE1(("UnhookNtKernCMHandler: Adapter %p, NdisHandler %p, DevNode %x\n",
|
||
|
pAdapter, pAdapter->NdisCmConfigHandler, pAdapter->DevNode));
|
||
|
}
|
||
|
|
||
|
/****************************************************************************/
|
||
|
/* RndisCMHandler */
|
||
|
/****************************************************************************/
|
||
|
/* */
|
||
|
/* Routine Description: */
|
||
|
/* */
|
||
|
/* Handler to intercept Config Mgr messages forwarded by NDIS. The only */
|
||
|
/* message of interest is a CONFIG_PREREMOVE, which is our only indication */
|
||
|
/* on Win98 and Win98SE that the device is being removed. */
|
||
|
/* */
|
||
|
/* Arguments: */
|
||
|
/* */
|
||
|
/* Various - documented in Win9x CFmgr header. */
|
||
|
/* */
|
||
|
/* Return: */
|
||
|
/* */
|
||
|
/* MY_CONFIGRET */
|
||
|
/* */
|
||
|
/****************************************************************************/
|
||
|
MY_CONFIGRET __cdecl
|
||
|
RndisCMHandler(IN MY_CONFIGFUNC cfFuncName,
|
||
|
IN MY_SUBCONFIGFUNC cfSubFuncName,
|
||
|
IN MY_DEVNODE cfDevNode,
|
||
|
IN ULONG dwRefData,
|
||
|
IN ULONG ulFlags)
|
||
|
{
|
||
|
PRNDISMP_ADAPTER pAdapter, pTmpAdapter;
|
||
|
PDRIVER_BLOCK pDriverBlock;
|
||
|
MY_CONFIGRET crRetCode;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
//
|
||
|
// Find the adapter to which this is addressed.
|
||
|
//
|
||
|
pAdapter = NULL;
|
||
|
NdisAcquireSpinLock(&RndismpGlobalLock);
|
||
|
|
||
|
for (pDriverBlock = RndismpMiniportBlockListHead.NextDriverBlock;
|
||
|
(pDriverBlock != NULL) && (pAdapter == NULL);
|
||
|
pDriverBlock = pDriverBlock->NextDriverBlock)
|
||
|
{
|
||
|
for (pTmpAdapter = pDriverBlock->AdapterList;
|
||
|
pTmpAdapter != NULL;
|
||
|
pTmpAdapter = pTmpAdapter->NextAdapter)
|
||
|
{
|
||
|
if (pTmpAdapter->DevNode == cfDevNode)
|
||
|
{
|
||
|
pAdapter = pTmpAdapter;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
NdisReleaseSpinLock(&RndismpGlobalLock);
|
||
|
|
||
|
ASSERT(pAdapter != NULL);
|
||
|
|
||
|
TRACE1(("CMHandler: Adapter %p, CfFuncName %x\n",
|
||
|
pAdapter, cfFuncName));
|
||
|
|
||
|
//
|
||
|
// Forward this on before acting on it.
|
||
|
//
|
||
|
if (pAdapter &&
|
||
|
(pAdapter->NdisCmConfigHandler != NULL))
|
||
|
{
|
||
|
crRetCode = pAdapter->NdisCmConfigHandler(
|
||
|
cfFuncName,
|
||
|
cfSubFuncName,
|
||
|
cfDevNode,
|
||
|
dwRefData,
|
||
|
ulFlags);
|
||
|
|
||
|
if ((cfFuncName == MY_CONFIG_PREREMOVE) ||
|
||
|
((cfFuncName == MY_CONFIG_PRESHUTDOWN) &&
|
||
|
(pAdapter->bRunningOnWin98Gold)))
|
||
|
{
|
||
|
RndismpInternalHalt((NDIS_HANDLE)pAdapter, FALSE);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
crRetCode = MY_CR_SUCCESS;
|
||
|
}
|
||
|
}
|
||
|
while (FALSE);
|
||
|
|
||
|
return (crRetCode);
|
||
|
}
|
||
|
|
||
|
#endif // BUILD_WIN9X
|