479 lines
11 KiB
C
479 lines
11 KiB
C
/*****************************************************************************
|
|
*
|
|
* Copyright (c) 1996-1999 Microsoft Corporation
|
|
*
|
|
* @doc
|
|
* @module resource.c | IrSIR NDIS Miniport Driver
|
|
* @comm
|
|
*
|
|
*-----------------------------------------------------------------------------
|
|
*
|
|
* Author: Scott Holden (sholden)
|
|
*
|
|
* Date: 10/3/1996 (created)
|
|
*
|
|
* Contents: initialize and allocate resources
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#include "irsir.h"
|
|
|
|
|
|
#if MEM_CHECKING
|
|
typedef struct MEM_HDR {
|
|
LIST_ENTRY ListEntry;
|
|
ULONG Size;
|
|
CHAR File[12];
|
|
ULONG Line;
|
|
} MEM_HDR;
|
|
|
|
LIST_ENTRY leAlloc;
|
|
NDIS_SPIN_LOCK slAlloc;
|
|
|
|
VOID InitMemory()
|
|
{
|
|
NdisAllocateSpinLock(&slAlloc);
|
|
NdisInitializeListHead(&leAlloc);
|
|
}
|
|
|
|
VOID DeinitMemory()
|
|
{
|
|
PLIST_ENTRY ListEntry;
|
|
|
|
NdisAcquireSpinLock(&slAlloc);
|
|
for (ListEntry=leAlloc.Flink;
|
|
ListEntry!=&leAlloc;
|
|
ListEntry = ListEntry->Flink)
|
|
{
|
|
MEM_HDR *Hdr = (MEM_HDR*)ListEntry;
|
|
DbgPrint("IRSIR: Unfreed Memory:%08x size:%4x <%s:%d>\n",
|
|
&Hdr[1], Hdr->Size, Hdr->File, Hdr->Line);
|
|
|
|
}
|
|
NdisReleaseSpinLock(&slAlloc);
|
|
}
|
|
#endif
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: MyMemAlloc
|
|
*
|
|
* Synopsis: allocates a block of memory using NdisAllocateMemory
|
|
*
|
|
* Arguments: size - size of the block to allocate
|
|
*
|
|
* Returns: a pointer to the allocated block of memory
|
|
*
|
|
* Algorithm:
|
|
*
|
|
* History: dd-mm-yyyy Author Comment
|
|
* 10/3/1996 sholden author
|
|
*
|
|
* Notes:
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#if MEM_CHECKING
|
|
PVOID
|
|
_MyMemAlloc(UINT size, PUCHAR file, UINT line)
|
|
#else
|
|
PVOID
|
|
MyMemAlloc(UINT size)
|
|
#endif
|
|
{
|
|
PVOID memptr;
|
|
NDIS_PHYSICAL_ADDRESS noMaxAddr = NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
|
|
NDIS_STATUS status;
|
|
|
|
#if MEM_CHECKING
|
|
status = NdisAllocateMemoryWithTag(&memptr, size+sizeof(MEM_HDR), IRSIR_TAG);
|
|
#else
|
|
status = NdisAllocateMemoryWithTag(&memptr, size, IRSIR_TAG);
|
|
#endif
|
|
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DEBUGMSG(DBG_ERR, ("Memory allocation failed\n"));
|
|
memptr = NULL;
|
|
}
|
|
#if MEM_CHECKING
|
|
else
|
|
{
|
|
MEM_HDR *Hdr = memptr;
|
|
UINT FileNameLen = strlen(file);
|
|
|
|
Hdr->Line = line;
|
|
if (FileNameLen>sizeof(Hdr->File)-1)
|
|
strcpy(Hdr->File, &file[FileNameLen-sizeof(Hdr->File)+1]);
|
|
else
|
|
strcpy(Hdr->File, file);
|
|
MyInterlockedInsertHeadList(&leAlloc, &Hdr->ListEntry, &slAlloc);
|
|
memptr = &Hdr[1];
|
|
}
|
|
#endif
|
|
|
|
return memptr;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: MyMemFree
|
|
*
|
|
* Synopsis: frees a block of memory allocated by MyMemAlloc
|
|
*
|
|
* Arguments: memptr - memory to free
|
|
* size - size of the block to free
|
|
*
|
|
* Returns: none
|
|
*
|
|
* Algorithm:
|
|
*
|
|
* History: dd-mm-yyyy Author Comment
|
|
* 10/3/1996 sholden author
|
|
*
|
|
* Notes:
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
|
|
|
|
VOID
|
|
MyMemFree(
|
|
PVOID memptr,
|
|
UINT size
|
|
)
|
|
{
|
|
#if MEM_CHECKING
|
|
PLIST_ENTRY ListEntry;
|
|
MEM_HDR *Hdr = (MEM_HDR*)((PUCHAR)memptr-sizeof(MEM_HDR));
|
|
|
|
NdisAcquireSpinLock(&slAlloc);
|
|
for (ListEntry = leAlloc.Flink;
|
|
ListEntry != &leAlloc;
|
|
ListEntry = ListEntry->Flink)
|
|
{
|
|
if (ListEntry==&Hdr->ListEntry)
|
|
{
|
|
RemoveEntryList(&Hdr->ListEntry);
|
|
break;
|
|
}
|
|
}
|
|
if (ListEntry==&leAlloc)
|
|
{
|
|
DEBUGMSG(DBG_ERR, ("IRSIR: Freeing memory not owned %x\n", memptr));
|
|
}
|
|
NdisReleaseSpinLock(&slAlloc);
|
|
|
|
NdisFreeMemory(Hdr, size+sizeof(MEM_HDR), 0);
|
|
#else
|
|
NdisFreeMemory(memptr, size, 0);
|
|
#endif
|
|
}
|
|
|
|
#if LIST_CHECKING
|
|
VOID FASTCALL CheckList(PLIST_ENTRY ListHead)
|
|
{
|
|
PLIST_ENTRY ListEntry, PrevListEntry;
|
|
|
|
if (ListHead->Flink==ListHead)
|
|
{
|
|
if (ListHead->Flink!=ListHead ||
|
|
ListHead->Blink!=ListHead)
|
|
{
|
|
DbgPrint("IRSIR: Corrupt list head:%x Flink:%x Blink:%x\n", ListHead, ListHead->Flink, ListHead->Blink);
|
|
DbgBreakPoint();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ListEntry = ListHead;
|
|
|
|
do
|
|
{
|
|
PrevListEntry = ListEntry;
|
|
ListEntry = ListEntry->Flink;
|
|
|
|
if (ListEntry->Blink!=PrevListEntry)
|
|
{
|
|
DbgPrint("IRSIR: Corrupt LIST_ENTRY Head:%08x %08x->Flink==%08x %08x->Blink==%08x\n",
|
|
ListHead, PrevListEntry, PrevListEntry->Flink, ListEntry, ListEntry->Blink);
|
|
DbgBreakPoint();
|
|
}
|
|
} while (ListEntry!=ListHead);
|
|
}
|
|
}
|
|
|
|
|
|
PLIST_ENTRY FASTCALL MyInterlockedInsertHeadList(PLIST_ENTRY Head, PLIST_ENTRY Entry, PNDIS_SPIN_LOCK SpinLock)
|
|
{
|
|
PLIST_ENTRY RetVal;
|
|
|
|
NdisAcquireSpinLock(SpinLock);
|
|
if (IsListEmpty(Head))
|
|
RetVal = NULL;
|
|
else
|
|
RetVal = Head->Flink;
|
|
CheckedInsertHeadList(Head, Entry);
|
|
NdisReleaseSpinLock(SpinLock);
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
PLIST_ENTRY FASTCALL MyInterlockedInsertTailList(PLIST_ENTRY Head, PLIST_ENTRY Entry, PNDIS_SPIN_LOCK SpinLock)
|
|
{
|
|
PLIST_ENTRY RetVal;
|
|
|
|
NdisAcquireSpinLock(SpinLock);
|
|
if (IsListEmpty(Head))
|
|
RetVal = NULL;
|
|
else
|
|
RetVal = Head->Blink;
|
|
CheckedInsertTailList(Head, Entry);
|
|
NdisReleaseSpinLock(SpinLock);
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
PLIST_ENTRY FASTCALL MyInterlockedRemoveHeadList(PLIST_ENTRY Head, PNDIS_SPIN_LOCK SpinLock)
|
|
{
|
|
PLIST_ENTRY RetVal;
|
|
NdisAcquireSpinLock(SpinLock);
|
|
//RemoveHeadList uses RemoveEntryList, which is redefined to call CheckList in DEBUG.H
|
|
RetVal = RemoveHeadList(Head);
|
|
if (RetVal==Head)
|
|
RetVal = NULL;
|
|
else
|
|
RetVal->Flink = RetVal->Blink = NULL;
|
|
NdisReleaseSpinLock(SpinLock);
|
|
|
|
return RetVal;
|
|
}
|
|
#endif
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: NewDevice
|
|
*
|
|
* Synopsis: allocates an IR_DEVICE and inits the device
|
|
*
|
|
* Arguments: none
|
|
*
|
|
* Returns: initialized IR_DEVICE or NULL (if alloc failed)
|
|
*
|
|
* Algorithm:
|
|
*
|
|
* History: dd-mm-yyyy Author Comment
|
|
* 10/3/1996 sholden author
|
|
*
|
|
* Notes:
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
|
|
PIR_DEVICE
|
|
NewDevice()
|
|
{
|
|
PIR_DEVICE pNewDev;
|
|
|
|
pNewDev = MyMemAlloc(sizeof(IR_DEVICE));
|
|
|
|
if (pNewDev != NULL)
|
|
{
|
|
NdisZeroMemory((PVOID)pNewDev, sizeof(IR_DEVICE));
|
|
}
|
|
|
|
return pNewDev;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: FreeDevice
|
|
*
|
|
* Synopsis: frees an IR_DEVICE allocated by NewDevice
|
|
*
|
|
* Arguments: dev - pointer to device to free
|
|
*
|
|
* Returns: none
|
|
*
|
|
* Algorithm:
|
|
*
|
|
* History: dd-mm-yyyy Author Comment
|
|
* 10/3/1996 sholden author
|
|
*
|
|
* Notes:
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
|
|
VOID
|
|
FreeDevice(
|
|
PIR_DEVICE pDev
|
|
)
|
|
{
|
|
MyMemFree((PVOID)pDev, sizeof(IR_DEVICE));
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Function: IrBuildIrp
|
|
*
|
|
* Synopsis: Builds an I/O request packet for either a read or a write
|
|
* request to the serial device object.
|
|
* Supports the following request codes:
|
|
* IOCTL_MJ_READ
|
|
* IOCTL_MJ_WRITE
|
|
*
|
|
* Arguments:
|
|
*
|
|
* Returns:
|
|
*
|
|
* Algorithm:
|
|
*
|
|
* History: dd-mm-yyyy Author Comment
|
|
* 10/14/1996 sholden author
|
|
*
|
|
* Notes:
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
|
|
PIRP
|
|
SerialBuildReadWriteIrp(
|
|
IN PDEVICE_OBJECT pSerialDevObj,
|
|
IN ULONG MajorFunction,
|
|
IN OUT PVOID pBuffer,
|
|
IN ULONG BufferLength,
|
|
IN PIO_STATUS_BLOCK pIosb
|
|
)
|
|
{
|
|
PIRP pIrp;
|
|
PIO_STACK_LOCATION irpSp;
|
|
|
|
// DEBUGMSG(DBG_FUNC, ("+SerialBuildReadWriteIrp\n"));
|
|
|
|
if (pSerialDevObj == NULL)
|
|
{
|
|
DEBUGMSG(DBG_ERR, (" SerialBuildReadWriteIrp:pSerialDevObj==NULL\n"));
|
|
|
|
return NULL;
|
|
}
|
|
//
|
|
// Allocate the irp.
|
|
//
|
|
|
|
pIrp = IoAllocateIrp(
|
|
pSerialDevObj->StackSize,
|
|
FALSE
|
|
);
|
|
|
|
if (pIrp == NULL)
|
|
{
|
|
DEBUGMSG(DBG_ERR, (" IoAllocateIrp failed.\n"));
|
|
|
|
return pIrp;
|
|
}
|
|
|
|
//
|
|
// Set current thread for IoSetHardErrorOrVerifyDevice.
|
|
//
|
|
|
|
pIrp->Tail.Overlay.Thread = PsGetCurrentThread();
|
|
|
|
//
|
|
// Get a pointer to the stack location of the first driver which will be
|
|
// invoked. This is where the function codes and the parameters are set.
|
|
//
|
|
|
|
irpSp = IoGetNextIrpStackLocation(pIrp);
|
|
|
|
//
|
|
// Set the major function code.
|
|
//
|
|
|
|
irpSp->MajorFunction = (UCHAR)MajorFunction;
|
|
|
|
pIrp->AssociatedIrp.SystemBuffer = pBuffer;
|
|
|
|
if (MajorFunction == IRP_MJ_READ)
|
|
{
|
|
pIrp->Flags = IRP_BUFFERED_IO | IRP_INPUT_OPERATION;
|
|
irpSp->Parameters.Read.Length = BufferLength;
|
|
}
|
|
else // MajorFunction == IRP_MJ_WRITE
|
|
{
|
|
pIrp->Flags = IRP_BUFFERED_IO;
|
|
irpSp->Parameters.Write.Length = BufferLength;
|
|
}
|
|
|
|
pIrp->UserIosb = pIosb;
|
|
|
|
// DEBUGMSG(DBG_FUNC, ("-SerialBuildReadWriteIrp\n"));
|
|
|
|
return pIrp;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ScheduleWorkItem(PASSIVE_PRIMITIVE Prim,
|
|
PIR_DEVICE pDevice,
|
|
WORK_PROC Callback,
|
|
PVOID InfoBuf,
|
|
ULONG InfoBufLen)
|
|
{
|
|
PIR_WORK_ITEM pWorkItem;
|
|
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
|
|
|
|
DEBUGMSG(DBG_FUNC, ("+ScheduleWorkItem\n"));
|
|
|
|
pWorkItem = MyMemAlloc(sizeof(IR_WORK_ITEM));
|
|
|
|
if (pWorkItem != NULL)
|
|
{
|
|
pWorkItem->Prim = Prim;
|
|
pWorkItem->pIrDevice = pDevice;
|
|
pWorkItem->InfoBuf = InfoBuf;
|
|
pWorkItem->InfoBufLen = InfoBufLen;
|
|
|
|
/*
|
|
** This interface was designed to use NdisScheduleWorkItem(), which
|
|
** would be good except that we're really only supposed to use that
|
|
** interface during startup and shutdown, due to the limited pool of
|
|
** threads available to service NdisScheduleWorkItem(). Therefore,
|
|
** instead of scheduling real work items, we simulate them, and use
|
|
** our own thread to process the calls. This also makes it easy to
|
|
** expand the size of our own thread pool, if we wish.
|
|
**
|
|
** Our version is slightly different from actual NDIS_WORK_ITEMs,
|
|
** because that is an NDIS 5.0 structure, and we want people to
|
|
** (at least temporarily) build this with NDIS 4.0 headers.
|
|
*/
|
|
|
|
pWorkItem->Callback = Callback;
|
|
|
|
/*
|
|
** Our worker thread checks this list for new jobs, whenever its event
|
|
** is signalled.
|
|
*/
|
|
|
|
MyInterlockedInsertTailList(&pDevice->leWorkItems,
|
|
&pWorkItem->ListEntry,
|
|
&pDevice->slWorkItem);
|
|
|
|
// Wake up our thread.
|
|
|
|
KeSetEvent(&pDevice->eventPassiveThread, 0, FALSE);
|
|
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
FreeWorkItem(
|
|
PIR_WORK_ITEM pItem
|
|
)
|
|
{
|
|
MyMemFree((PVOID)pItem, sizeof(IR_WORK_ITEM));
|
|
}
|