349 lines
8.6 KiB
C
349 lines
8.6 KiB
C
|
/*
|
||
|
************************************************************************
|
||
|
*
|
||
|
* RESOURCE.c
|
||
|
*
|
||
|
*
|
||
|
* Portions Copyright (C) 1996-2001 National Semiconductor Corp.
|
||
|
* All rights reserved.
|
||
|
* Copyright (C) 1996-2001 Microsoft Corporation. All Rights Reserved.
|
||
|
*
|
||
|
*
|
||
|
*
|
||
|
*************************************************************************
|
||
|
*/
|
||
|
|
||
|
|
||
|
#include "nsc.h"
|
||
|
|
||
|
|
||
|
/*
|
||
|
*************************************************************************
|
||
|
* MyMemAlloc
|
||
|
*************************************************************************
|
||
|
*
|
||
|
*/
|
||
|
PVOID MyMemAlloc(UINT size, BOOLEAN isDmaBuf)
|
||
|
{
|
||
|
NDIS_STATUS stat;
|
||
|
PVOID memptr;
|
||
|
|
||
|
if (isDmaBuf){
|
||
|
NDIS_PHYSICAL_ADDRESS maxAddr = NDIS_PHYSICAL_ADDRESS_CONST(0x0fffff, 0);
|
||
|
stat = NdisAllocateMemory( &memptr,
|
||
|
size,
|
||
|
NDIS_MEMORY_CONTIGUOUS|NDIS_MEMORY_NONCACHED,
|
||
|
maxAddr);
|
||
|
}
|
||
|
else {
|
||
|
stat = NdisAllocateMemoryWithTag(
|
||
|
&memptr,
|
||
|
size,
|
||
|
'rIsN'
|
||
|
);
|
||
|
}
|
||
|
|
||
|
if (stat == NDIS_STATUS_SUCCESS){
|
||
|
NdisZeroMemory((PVOID)memptr, size);
|
||
|
}
|
||
|
else {
|
||
|
DBGERR(("Memory allocation failed"));
|
||
|
memptr = NULL;
|
||
|
}
|
||
|
|
||
|
return memptr;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
*************************************************************************
|
||
|
* MyMemFree
|
||
|
*************************************************************************
|
||
|
*
|
||
|
*/
|
||
|
VOID MyMemFree(PVOID memptr, UINT size, BOOLEAN isDmaBuf)
|
||
|
{
|
||
|
UINT flags = (isDmaBuf) ? NDIS_MEMORY_CONTIGUOUS|NDIS_MEMORY_NONCACHED : 0;
|
||
|
NdisFreeMemory(memptr, size, flags);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
*************************************************************************
|
||
|
* NewDevice
|
||
|
*************************************************************************
|
||
|
*
|
||
|
*/
|
||
|
IrDevice *NewDevice()
|
||
|
{
|
||
|
IrDevice *newdev;
|
||
|
|
||
|
newdev = MyMemAlloc(sizeof(IrDevice), FALSE);
|
||
|
if (newdev){
|
||
|
InitDevice(newdev);
|
||
|
}
|
||
|
return newdev;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
*************************************************************************
|
||
|
* FreeDevice
|
||
|
*************************************************************************
|
||
|
*
|
||
|
*/
|
||
|
VOID FreeDevice(IrDevice *dev)
|
||
|
{
|
||
|
CloseDevice(dev);
|
||
|
MyMemFree((PVOID)dev, sizeof(IrDevice), FALSE);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
*************************************************************************
|
||
|
* InitDevice
|
||
|
*************************************************************************
|
||
|
*
|
||
|
* Zero out the device object.
|
||
|
*
|
||
|
* Allocate the device object's spinlock, which will persist while
|
||
|
* the device is opened and closed.
|
||
|
*
|
||
|
*/
|
||
|
VOID InitDevice(IrDevice *thisDev)
|
||
|
{
|
||
|
NdisZeroMemory((PVOID)thisDev, sizeof(IrDevice));
|
||
|
NdisInitializeListHead(&thisDev->SendQueue);
|
||
|
NdisAllocateSpinLock(&thisDev->QueueLock);
|
||
|
NdisInitializeTimer(&thisDev->TurnaroundTimer,
|
||
|
DelayedWrite,
|
||
|
thisDev);
|
||
|
NdisInitializeListHead(&thisDev->rcvBufBuf);
|
||
|
NdisInitializeListHead(&thisDev->rcvBufFree);
|
||
|
NdisInitializeListHead(&thisDev->rcvBufFull);
|
||
|
NdisInitializeListHead(&thisDev->rcvBufPend);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
*************************************************************************
|
||
|
* OpenDevice
|
||
|
*************************************************************************
|
||
|
*
|
||
|
* Allocate resources for a single device object.
|
||
|
*
|
||
|
* This function should be called with device lock already held.
|
||
|
*
|
||
|
*/
|
||
|
BOOLEAN OpenDevice(IrDevice *thisDev)
|
||
|
{
|
||
|
BOOLEAN result = FALSE;
|
||
|
NDIS_STATUS stat;
|
||
|
UINT bufIndex;
|
||
|
|
||
|
DBGOUT(("OpenDevice()"));
|
||
|
|
||
|
if (!thisDev){
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Allocate the NDIS packet and NDIS buffer pools
|
||
|
* for this device's RECEIVE buffer queue.
|
||
|
* Our receive packets must only contain one buffer apiece,
|
||
|
* so #buffers == #packets.
|
||
|
*/
|
||
|
|
||
|
NdisAllocatePacketPool(&stat, &thisDev->packetPoolHandle, NUM_RCV_BUFS, 24);
|
||
|
if (stat != NDIS_STATUS_SUCCESS){
|
||
|
goto _openDone;
|
||
|
}
|
||
|
NdisAllocateBufferPool(&stat, &thisDev->bufferPoolHandle, NUM_RCV_BUFS);
|
||
|
if (stat != NDIS_STATUS_SUCCESS){
|
||
|
goto _openDone;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Initialize each of the RECEIVE packet objects for this device.
|
||
|
*/
|
||
|
for (bufIndex = 0; bufIndex < NUM_RCV_BUFS; bufIndex++){
|
||
|
|
||
|
rcvBuffer *rcvBuf = MyMemAlloc(sizeof(rcvBuffer), FALSE);
|
||
|
PVOID buf;
|
||
|
|
||
|
if (!rcvBuf)
|
||
|
{
|
||
|
goto _openDone;
|
||
|
}
|
||
|
|
||
|
rcvBuf->state = STATE_FREE;
|
||
|
rcvBuf->isDmaBuf = FALSE;
|
||
|
|
||
|
/*
|
||
|
* Allocate a data buffer
|
||
|
*
|
||
|
* This buffer gets swapped with the one on comPortInfo
|
||
|
* and must be the same size.
|
||
|
*/
|
||
|
rcvBuf->dataBuf = NULL;
|
||
|
|
||
|
buf = MyMemAlloc(RCV_BUFFER_SIZE, TRUE);
|
||
|
if (!buf){
|
||
|
goto _openDone;
|
||
|
}
|
||
|
|
||
|
// We treat the beginning of the buffer as a LIST_ENTRY.
|
||
|
|
||
|
// Normally we would use NDISSynchronizeInsertHeadList, but the
|
||
|
// Interrupt hasn't been registered yet.
|
||
|
InsertHeadList(&thisDev->rcvBufBuf, (PLIST_ENTRY)buf);
|
||
|
|
||
|
/*
|
||
|
* Allocate the NDIS_PACKET.
|
||
|
*/
|
||
|
NdisAllocatePacket(&stat, &rcvBuf->packet, thisDev->packetPoolHandle);
|
||
|
if (stat != NDIS_STATUS_SUCCESS){
|
||
|
goto _openDone;
|
||
|
}
|
||
|
#if 1
|
||
|
/*
|
||
|
* For future convenience, set the MiniportReserved portion of the packet
|
||
|
* to the index of the rcv buffer that contains it.
|
||
|
* This will be used in ReturnPacketHandler.
|
||
|
*/
|
||
|
*(ULONG_PTR *)rcvBuf->packet->MiniportReserved = (ULONG_PTR)rcvBuf;
|
||
|
#endif
|
||
|
|
||
|
rcvBuf->dataLen = 0;
|
||
|
|
||
|
InsertHeadList(&thisDev->rcvBufFree, &rcvBuf->listEntry);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Set mediaBusy to TRUE initially. That way, we won't
|
||
|
* IndicateStatus to the protocol in the ISR unless the
|
||
|
* protocol has expressed interest by clearing this flag
|
||
|
* via MiniportSetInformation(OID_IRDA_MEDIA_BUSY).
|
||
|
*/
|
||
|
thisDev->mediaBusy = FALSE;
|
||
|
thisDev->haveIndicatedMediaBusy = TRUE;
|
||
|
|
||
|
/*
|
||
|
* Will set speed to 9600 baud initially.
|
||
|
*/
|
||
|
thisDev->linkSpeedInfo = &supportedBaudRateTable[BAUDRATE_9600];
|
||
|
|
||
|
thisDev->lastPacketAtOldSpeed = NULL;
|
||
|
thisDev->setSpeedAfterCurrentSendPacket = FALSE;
|
||
|
|
||
|
result = TRUE;
|
||
|
|
||
|
_openDone:
|
||
|
if (!result){
|
||
|
/*
|
||
|
* If we're failing, close the device to free up any resources
|
||
|
* that were allocated for it.
|
||
|
*/
|
||
|
CloseDevice(thisDev);
|
||
|
DBGOUT(("OpenDevice() failed"));
|
||
|
}
|
||
|
else {
|
||
|
DBGOUT(("OpenDevice() succeeded"));
|
||
|
}
|
||
|
return result;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
*************************************************************************
|
||
|
* CloseDevice
|
||
|
*************************************************************************
|
||
|
*
|
||
|
* Free the indicated device's resources.
|
||
|
*
|
||
|
*
|
||
|
* Called for shutdown and reset.
|
||
|
* Don't clear ndisAdapterHandle, since we might just be resetting.
|
||
|
* This function should be called with device lock held.
|
||
|
*
|
||
|
*
|
||
|
*/
|
||
|
VOID CloseDevice(IrDevice *thisDev)
|
||
|
{
|
||
|
PLIST_ENTRY ListEntry;
|
||
|
|
||
|
DBGOUT(("CloseDevice()"));
|
||
|
|
||
|
if (!thisDev){
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Free all resources for the RECEIVE buffer queue.
|
||
|
*/
|
||
|
|
||
|
while (!IsListEmpty(&thisDev->rcvBufFree))
|
||
|
{
|
||
|
rcvBuffer *rcvBuf;
|
||
|
|
||
|
ListEntry = RemoveHeadList(&thisDev->rcvBufFree);
|
||
|
rcvBuf = CONTAINING_RECORD(ListEntry,
|
||
|
rcvBuffer,
|
||
|
listEntry);
|
||
|
|
||
|
if (rcvBuf->packet){
|
||
|
NdisFreePacket(rcvBuf->packet);
|
||
|
rcvBuf->packet = NULL;
|
||
|
}
|
||
|
|
||
|
MyMemFree(rcvBuf, sizeof(rcvBuffer), FALSE);
|
||
|
}
|
||
|
|
||
|
|
||
|
while (!IsListEmpty(&thisDev->rcvBufBuf))
|
||
|
{
|
||
|
ListEntry = RemoveHeadList(&thisDev->rcvBufBuf);
|
||
|
MyMemFree(ListEntry, RCV_BUFFER_SIZE, TRUE);
|
||
|
}
|
||
|
/*
|
||
|
* Free the packet and buffer pool handles for this device.
|
||
|
*/
|
||
|
if (thisDev->packetPoolHandle){
|
||
|
NdisFreePacketPool(thisDev->packetPoolHandle);
|
||
|
thisDev->packetPoolHandle = NULL;
|
||
|
}
|
||
|
if (thisDev->bufferPoolHandle){
|
||
|
NdisFreeBufferPool(thisDev->bufferPoolHandle);
|
||
|
thisDev->bufferPoolHandle = NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Free all resources for the SEND buffer queue.
|
||
|
*/
|
||
|
while (ListEntry = NdisInterlockedRemoveHeadList(&thisDev->SendQueue, &thisDev->QueueLock)){
|
||
|
|
||
|
// NDIS says we shouldn't try to complete any pending send packets
|
||
|
// because we shouldn't have any packets around to send. If we do,
|
||
|
// it's an NDIS bug.
|
||
|
|
||
|
ASSERT(0);
|
||
|
}
|
||
|
|
||
|
|
||
|
thisDev->mediaBusy = FALSE;
|
||
|
thisDev->haveIndicatedMediaBusy = FALSE;
|
||
|
|
||
|
thisDev->linkSpeedInfo = NULL;
|
||
|
|
||
|
}
|