452 lines
12 KiB
C
452 lines
12 KiB
C
/*++
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
util.c
|
|
|
|
|
|
Author:
|
|
|
|
ervinp
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include <WDM.H>
|
|
|
|
#include <usbdi.h>
|
|
#include <usbdlib.h>
|
|
#include <usbioctl.h>
|
|
|
|
#include "usb8023.h"
|
|
#include "debug.h"
|
|
|
|
|
|
#if DBG_WRAP_MEMORY
|
|
/*
|
|
* Memory Allocation:
|
|
* To catch memory leaks, we will keep a count and list of all allocated memory
|
|
* and then assert that the memory is all freed when we exit.
|
|
*/
|
|
ULONG dbgTotalMemCount = 0;
|
|
LIST_ENTRY dbgAllMemoryList;
|
|
#define ALIGNBYTES 32
|
|
|
|
struct memHeader {
|
|
PUCHAR actualPtr;
|
|
ULONG actualSize;
|
|
LIST_ENTRY listEntry;
|
|
};
|
|
#endif
|
|
|
|
|
|
PVOID AllocPool(ULONG size)
|
|
/*
|
|
*
|
|
* Return a 32-byte aligned pointer.
|
|
* Place a guard word at the end of the buffer.
|
|
* Cache the actual allocated pointer and size before the returned pointer.
|
|
*
|
|
*/
|
|
{
|
|
PUCHAR resultPtr;
|
|
|
|
#if DBG_WRAP_MEMORY
|
|
{
|
|
PUCHAR actualPtr = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
size+ALIGNBYTES+sizeof(struct memHeader)+sizeof(ULONG),
|
|
DRIVER_SIG);
|
|
if (actualPtr){
|
|
struct memHeader *memHdr;
|
|
KIRQL oldIrql;
|
|
|
|
RtlZeroMemory(actualPtr, size+32+sizeof(struct memHeader));
|
|
*(PULONG)(actualPtr+size+ALIGNBYTES+sizeof(struct memHeader)) = GUARD_WORD;
|
|
|
|
/*
|
|
* ExAllocatePoolWithTag returns the 32-byte aligned pointer
|
|
* from ExAllocatePool plus 8 bytes for the tag and kernel tracking info
|
|
* (but don't depend on this).
|
|
* Align the pointer we return, and cache away the actual pointer to free and
|
|
* the buffer size.
|
|
*/
|
|
// ASSERT(((ULONG_PTR)actualPtr & 0x1F) == 0x08); NT only
|
|
resultPtr = (PUCHAR)((ULONG_PTR)(actualPtr+ALIGNBYTES+sizeof(struct memHeader)) & ~(ALIGNBYTES-1));
|
|
|
|
memHdr = (struct memHeader *)(resultPtr-sizeof(struct memHeader));
|
|
memHdr->actualPtr = actualPtr;
|
|
memHdr->actualSize = size+ALIGNBYTES+sizeof(struct memHeader)+sizeof(ULONG);
|
|
|
|
dbgTotalMemCount += memHdr->actualSize;
|
|
|
|
KeAcquireSpinLock(&globalSpinLock, &oldIrql);
|
|
InsertTailList(&dbgAllMemoryList, &memHdr->listEntry);
|
|
KeReleaseSpinLock(&globalSpinLock, oldIrql);
|
|
}
|
|
else {
|
|
resultPtr = NULL;
|
|
}
|
|
}
|
|
#else
|
|
resultPtr = ExAllocatePoolWithTag(NonPagedPool, size, DRIVER_SIG);
|
|
if (resultPtr){
|
|
RtlZeroMemory(resultPtr, size);
|
|
}
|
|
#endif
|
|
|
|
return resultPtr;
|
|
}
|
|
|
|
VOID FreePool(PVOID ptr)
|
|
{
|
|
#if DBG_WRAP_MEMORY
|
|
{
|
|
KIRQL oldIrql;
|
|
struct memHeader *memHdr;
|
|
|
|
ASSERT(ptr);
|
|
|
|
memHdr = (struct memHeader *)((PUCHAR)ptr - sizeof(struct memHeader));
|
|
ASSERT(*(PULONG)(memHdr->actualPtr+memHdr->actualSize-sizeof(ULONG)) == GUARD_WORD);
|
|
ASSERT(dbgTotalMemCount >= memHdr->actualSize);
|
|
|
|
KeAcquireSpinLock(&globalSpinLock, &oldIrql);
|
|
ASSERT(!IsListEmpty(&dbgAllMemoryList));
|
|
RemoveEntryList(&memHdr->listEntry);
|
|
KeReleaseSpinLock(&globalSpinLock, oldIrql);
|
|
|
|
dbgTotalMemCount -= memHdr->actualSize;
|
|
ExFreePool(memHdr->actualPtr);
|
|
}
|
|
#else
|
|
ExFreePool(ptr);
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
********************************************************************************
|
|
* MemDup
|
|
********************************************************************************
|
|
*
|
|
* Return a fresh copy of the argument.
|
|
*
|
|
*/
|
|
PVOID MemDup(PVOID dataPtr, ULONG length)
|
|
{
|
|
PVOID newPtr;
|
|
|
|
newPtr = (PVOID)AllocPool(length);
|
|
if (newPtr){
|
|
RtlCopyMemory(newPtr, dataPtr, length);
|
|
}
|
|
|
|
ASSERT(newPtr);
|
|
return newPtr;
|
|
}
|
|
|
|
|
|
VOID DelayMs(ULONG numMillisec)
|
|
{
|
|
LARGE_INTEGER deltaTime;
|
|
|
|
/*
|
|
* Get delay time into relative units of 100 nsec.
|
|
*/
|
|
deltaTime.QuadPart = -10000 * numMillisec;
|
|
KeDelayExecutionThread(KernelMode, FALSE, &deltaTime);
|
|
}
|
|
|
|
|
|
/*
|
|
* AllocateCommonResources
|
|
*
|
|
* Allocate adapter resources that are common to RNDIS and NDIS interfaces
|
|
* but which for some reason can't be allocated by NewAdapter().
|
|
* These resources will be freed by FreeAdapter().
|
|
*/
|
|
BOOLEAN AllocateCommonResources(ADAPTEREXT *adapter)
|
|
{
|
|
BOOLEAN result = TRUE;
|
|
ULONG i;
|
|
|
|
/*
|
|
* Build the packet pool for this adapter.
|
|
*/
|
|
for (i = 0; i < USB_PACKET_POOL_SIZE; i++){
|
|
USBPACKET *packet = NewPacket(adapter);
|
|
if (packet){
|
|
EnqueueFreePacket(packet);
|
|
}
|
|
else {
|
|
ASSERT(packet);
|
|
result = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ASSERT(result);
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN GetRegValue(ADAPTEREXT *adapter, PWCHAR wValueName, OUT PULONG valuePtr, BOOLEAN hwKey)
|
|
{
|
|
BOOLEAN success = FALSE;
|
|
NTSTATUS status;
|
|
HANDLE hRegDevice;
|
|
KIRQL oldIrql;
|
|
|
|
*valuePtr = 0;
|
|
|
|
status = IoOpenDeviceRegistryKey( adapter->physDevObj,
|
|
hwKey ? PLUGPLAY_REGKEY_DEVICE : PLUGPLAY_REGKEY_DRIVER,
|
|
KEY_READ,
|
|
&hRegDevice);
|
|
if (NT_SUCCESS(status)){
|
|
UNICODE_STRING uValueName;
|
|
PKEY_VALUE_FULL_INFORMATION keyValueInfo;
|
|
ULONG keyValueTotalSize, actualLength;
|
|
|
|
RtlInitUnicodeString(&uValueName, wValueName);
|
|
keyValueTotalSize = sizeof(KEY_VALUE_FULL_INFORMATION) +
|
|
uValueName.Length*sizeof(WCHAR) +
|
|
sizeof(ULONG);
|
|
keyValueInfo = AllocPool(keyValueTotalSize);
|
|
if (keyValueInfo){
|
|
status = ZwQueryValueKey( hRegDevice,
|
|
&uValueName,
|
|
KeyValueFullInformation,
|
|
keyValueInfo,
|
|
keyValueTotalSize,
|
|
&actualLength);
|
|
if (NT_SUCCESS(status)){
|
|
ASSERT(keyValueInfo->Type == REG_DWORD);
|
|
ASSERT(keyValueInfo->DataLength == sizeof(ULONG));
|
|
*valuePtr = *((PULONG)(((PCHAR)keyValueInfo)+keyValueInfo->DataOffset));
|
|
success = TRUE;
|
|
}
|
|
|
|
FreePool(keyValueInfo);
|
|
}
|
|
else {
|
|
ASSERT(keyValueInfo);
|
|
}
|
|
|
|
ZwClose(hRegDevice);
|
|
}
|
|
else {
|
|
DBGWARN(("IoOpenDeviceRegistryKey failed with %xh.", status));
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
|
|
BOOLEAN SetRegValue(ADAPTEREXT *adapter, PWCHAR wValueName, ULONG newValue, BOOLEAN hwKey)
|
|
{
|
|
BOOLEAN success = FALSE;
|
|
NTSTATUS status;
|
|
HANDLE hRegDevice;
|
|
KIRQL oldIrql;
|
|
|
|
status = IoOpenDeviceRegistryKey( adapter->physDevObj,
|
|
hwKey ? PLUGPLAY_REGKEY_DEVICE : PLUGPLAY_REGKEY_DRIVER,
|
|
KEY_READ,
|
|
&hRegDevice);
|
|
if (NT_SUCCESS(status)){
|
|
UNICODE_STRING uValueName;
|
|
PKEY_VALUE_FULL_INFORMATION keyValueInfo;
|
|
ULONG keyValueTotalSize, actualLength;
|
|
|
|
RtlInitUnicodeString(&uValueName, wValueName);
|
|
keyValueTotalSize = sizeof(KEY_VALUE_FULL_INFORMATION) +
|
|
uValueName.Length*sizeof(WCHAR) +
|
|
sizeof(ULONG);
|
|
keyValueInfo = AllocPool(keyValueTotalSize);
|
|
if (keyValueInfo){
|
|
status = ZwSetValueKey( hRegDevice,
|
|
&uValueName,
|
|
0,
|
|
REG_DWORD,
|
|
&newValue,
|
|
sizeof(ULONG));
|
|
if (NT_SUCCESS(status)){
|
|
success = TRUE;
|
|
}
|
|
else {
|
|
DBGERR(("SetRegValue: ZwSetValueKey failed with %xh.", status));
|
|
}
|
|
|
|
FreePool(keyValueInfo);
|
|
}
|
|
else {
|
|
ASSERT(keyValueInfo);
|
|
}
|
|
|
|
ZwClose(hRegDevice);
|
|
}
|
|
else {
|
|
DBGOUT(("IoOpenDeviceRegistryKey failed with %xh.", status));
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
|
|
/*
|
|
* MyInitializeMdl
|
|
*
|
|
* Wrapper for MmInitializeMdl, which doesn't compile under NDIS headers.
|
|
*/
|
|
VOID MyInitializeMdl(PMDL mdl, PVOID buf, ULONG bufLen)
|
|
{
|
|
MmInitializeMdl(mdl, buf, bufLen);
|
|
MmBuildMdlForNonPagedPool(mdl);
|
|
}
|
|
|
|
|
|
PVOID GetSystemAddressForMdlSafe(PMDL MdlAddress)
|
|
{
|
|
PVOID buf;
|
|
|
|
/*
|
|
* Note: we could use MmGetSystemAddressSafe here
|
|
* but not for Win98SE
|
|
*/
|
|
|
|
if (MdlAddress){
|
|
CSHORT oldFlags = MdlAddress->MdlFlags;
|
|
MdlAddress->MdlFlags |= MDL_MAPPING_CAN_FAIL;
|
|
buf = MmGetSystemAddressForMdl(MdlAddress);
|
|
MdlAddress->MdlFlags &= (oldFlags | ~MDL_MAPPING_CAN_FAIL);
|
|
}
|
|
else {
|
|
ASSERT(MdlAddress);
|
|
buf = NULL;
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
|
|
ULONG CopyMdlToBuffer(PUCHAR buf, PMDL mdl, ULONG bufLen)
|
|
{
|
|
ULONG totalLen = 0;
|
|
|
|
while (mdl){
|
|
ULONG thisBufLen = MmGetMdlByteCount(mdl);
|
|
if (totalLen+thisBufLen <= bufLen){
|
|
PVOID thisBuf = GetSystemAddressForMdlSafe(mdl);
|
|
if (thisBuf){
|
|
RtlCopyMemory(buf+totalLen, thisBuf, thisBufLen);
|
|
totalLen += thisBufLen;
|
|
mdl = mdl->Next;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
DBGERR(("CopyMdlToBuffer: mdl @ %ph is too large for buffer size %xh.", mdl, bufLen));
|
|
break;
|
|
}
|
|
}
|
|
|
|
return totalLen;
|
|
}
|
|
|
|
ULONG GetMdlListTotalByteCount(PMDL mdl)
|
|
{
|
|
ULONG totalBytes = 0;
|
|
|
|
do {
|
|
totalBytes += MmGetMdlByteCount(mdl);
|
|
mdl = mdl->Next;
|
|
} while (mdl);
|
|
|
|
return totalBytes;
|
|
}
|
|
|
|
VOID ByteSwap(PUCHAR buf, ULONG len)
|
|
{
|
|
while (len >= 2){
|
|
UCHAR tmp = buf[0];
|
|
buf[0] = buf[1];
|
|
buf[1] = tmp;
|
|
buf += 2;
|
|
len -= 2;
|
|
}
|
|
}
|
|
|
|
|
|
#if SPECIAL_WIN98SE_BUILD
|
|
|
|
PIO_WORKITEM MyIoAllocateWorkItem(PDEVICE_OBJECT DeviceObject)
|
|
{
|
|
PIO_WORKITEM ioWorkItem;
|
|
PWORK_QUEUE_ITEM exWorkItem;
|
|
|
|
ioWorkItem = ExAllocatePool(NonPagedPool, sizeof(IO_WORKITEM));
|
|
if (ioWorkItem) {
|
|
ioWorkItem->DeviceObject = DeviceObject;
|
|
exWorkItem = &ioWorkItem->WorkItem;
|
|
#if DBG
|
|
ioWorkItem->Size = sizeof(IO_WORKITEM);
|
|
#endif
|
|
ExInitializeWorkItem(exWorkItem, MyIopProcessWorkItem, ioWorkItem);
|
|
}
|
|
|
|
return ioWorkItem;
|
|
}
|
|
|
|
VOID MyIoFreeWorkItem(PIO_WORKITEM IoWorkItem)
|
|
{
|
|
ASSERT(IoWorkItem->Size == sizeof(IO_WORKITEM));
|
|
ExFreePool( IoWorkItem );
|
|
}
|
|
|
|
VOID MyIoQueueWorkItem(IN PIO_WORKITEM IoWorkItem, IN PIO_WORKITEM_ROUTINE WorkerRoutine, IN WORK_QUEUE_TYPE QueueType, IN PVOID Context)
|
|
{
|
|
PWORK_QUEUE_ITEM exWorkItem;
|
|
|
|
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
|
|
ASSERT(IoWorkItem->Size == sizeof(IO_WORKITEM));
|
|
|
|
ObReferenceObject( IoWorkItem->DeviceObject );
|
|
|
|
IoWorkItem->Routine = WorkerRoutine;
|
|
IoWorkItem->Context = Context;
|
|
|
|
exWorkItem = &IoWorkItem->WorkItem;
|
|
ExQueueWorkItem( exWorkItem, QueueType );
|
|
}
|
|
|
|
|
|
VOID MyIopProcessWorkItem(IN PVOID Parameter)
|
|
{
|
|
PIO_WORKITEM ioWorkItem;
|
|
PDEVICE_OBJECT deviceObject;
|
|
|
|
PAGED_CODE();
|
|
|
|
ioWorkItem = (PIO_WORKITEM)Parameter;
|
|
deviceObject = ioWorkItem->DeviceObject;
|
|
ioWorkItem->Routine(deviceObject, ioWorkItem->Context);
|
|
ObDereferenceObject(deviceObject);
|
|
}
|
|
|
|
#endif
|
|
|
|
|