/*************************************************************************** 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