/*************************************************************************** * * DISPATCH.C * * FastMAC Plus based NDIS3 miniport driver dispatch routines. This module * contains all of the upper interface functions that are not purely * for initialization and closedown (i.e. DriverEntry, MadgeInitialize * and MadgeHalt) excluding MadgeSetInformation and MadgeQueryInformation. * * Copyright (c) Madge Networks Ltd 1994 * * COMPANY CONFIDENTIAL * * Created: PBA 21/06/1994 * ****************************************************************************/ #include #include "ftk_defs.h" #include "ftk_intr.h" #include "ftk_extr.h" #include "mdgmport.upd" #include "ndismod.h" /**************************************************************************** * * Function - MadgeGetAdapterStatus * * Parameters - systemSpecific1 -> Unused. * context -> Actually a pointer to our NDIS3 level * adapter structure. * systemSpecific2 -> Unused. * systemSpecific3 -> Unused. * * Purpose - This function is called of a timer tick and notifies * open bindings of any interesting events. * * Returns - Nothing. * ****************************************************************************/ VOID MadgeGetAdapterStatus( PVOID systemSpecific1, PVOID context, PVOID systemSpecific2, PVOID systemSpecific3 ) { PMADGE_ADAPTER ndisAdap; NDIS_STATUS notifyStatus; WORD ringStatus; // // Do some pre-calculation. // ndisAdap = (PMADGE_ADAPTER) context; notifyStatus = 0; ringStatus = ndisAdap->CurrentRingStatus; if (ndisAdap->CurrentRingState == NdisRingStateOpened) { // // WARNING: If the adapter has been shutdown, this will return zero // in the two fields. // driver_get_open_and_ring_status( ndisAdap->FtkAdapterHandle, &ndisAdap->CurrentRingStatus, &ndisAdap->LastOpenStatus ); if (ringStatus != ndisAdap->CurrentRingStatus) { if (ndisAdap->CurrentRingStatus & RING_STATUS_RING_RECOVERY) { notifyStatus |= NDIS_RING_RING_RECOVERY; } if (ndisAdap->CurrentRingStatus & RING_STATUS_SINGLE_STATION) { notifyStatus |= NDIS_RING_SINGLE_STATION; } if (ndisAdap->CurrentRingStatus & RING_STATUS_COUNTER_OVERFLOW) { notifyStatus |= NDIS_RING_COUNTER_OVERFLOW; } if (ndisAdap->CurrentRingStatus & RING_STATUS_REMOVE_RECEIVED) { notifyStatus |= NDIS_RING_REMOVE_RECEIVED; } if (ndisAdap->CurrentRingStatus & RING_STATUS_AUTO_REMOVAL) { notifyStatus |= NDIS_RING_AUTO_REMOVAL_ERROR; } if (ndisAdap->CurrentRingStatus & RING_STATUS_LOBE_FAULT) { notifyStatus |= NDIS_RING_LOBE_WIRE_FAULT; } if (ndisAdap->CurrentRingStatus & RING_STATUS_TRANSMIT_BEACON) { notifyStatus |= NDIS_RING_TRANSMIT_BEACON; } if (ndisAdap->CurrentRingStatus & RING_STATUS_SOFT_ERROR) { notifyStatus |= NDIS_RING_SOFT_ERROR; } if (ndisAdap->CurrentRingStatus & RING_STATUS_HARD_ERROR) { notifyStatus |= NDIS_RING_HARD_ERROR; } if (ndisAdap->CurrentRingStatus & RING_STATUS_SIGNAL_LOSS) { notifyStatus |= NDIS_RING_SIGNAL_LOSS; } if (notifyStatus != 0) { NdisMIndicateStatus( ndisAdap->UsedInISR.MiniportHandle, NDIS_STATUS_RING_STATUS, (PVOID) ¬ifyStatus, sizeof(notifyStatus) ); NdisMIndicateStatusComplete( ndisAdap->UsedInISR.MiniportHandle ); MadgePrint2( "Ring Status %04x\n", ndisAdap->CurrentRingStatus); } } } // // Just before we go, clear the JustReadErrorLog flag, so that requests // for statistics will cause an SRB to be issued every now and then. // ndisAdap->JustReadErrorLog = 0; // // And finally re-arm the timer. // NdisMSetTimer(&ndisAdap->WakeUpTimer, EVERY_2_SECONDS); } /**************************************************************************** * * Function - MadgeCheckForHang * * Parameters - adapterContext -> A pointer to our NDIS adapter structure. * * Purpose - Process a call from the NDIS3 wrapper to check if * an adapter has hung. * * Returns - We always return FALSE since the only action the wrapper * can take is to invoke a reset, which we don't support * anyway. * ****************************************************************************/ BOOLEAN MadgeCheckForHang(NDIS_HANDLE adapterContext) { return FALSE; } /**************************************************************************** * * Function - MadgeReset * * Parameters - adapterContext -> A pointer to our NDIS adapter structure. * addressReset -> Ignored. * * Purpose - Process a call from the NDIS3 wrapper to reset an * adapter. * * Returns - NDIS_STATUS_NOT_RESETTABLE as we don't support resets. * ****************************************************************************/ NDIS_STATUS MadgeReset(PBOOLEAN addressReset, NDIS_HANDLE adapterContext) { MadgePrint1("MadgeReset\n"); MadgePrint2( "ndisAdap = %x\n", PMADGE_ADAPTER_FROM_CONTEXT(adapterContext) ); return NDIS_STATUS_NOT_RESETTABLE; } /**************************************************************************** * * Function - MadgeDisableInterrupts * * Parameters - adapterContext -> A pointer to our NDIS adapter structure. * * Purpose - Process a call from the NDIS3 wrapper to turn adapter * interrupts off. * * Returns - Nothing. * ****************************************************************************/ VOID MadgeDisableInterrupts(NDIS_HANDLE adapterContext) { // MadgePrint1("MadgeDisableInterrupts\n"); // // Note: it is very difficult for use to disble interrupts at the // adapter so we don't. We use a spin lock to protect our DPR // routine. // } /**************************************************************************** * * Function - MadgeEnableInterrupts * * Parameters - adapterContext -> A pointer to our NDIS adapter structure. * * Purpose - Process a call from the NDIS3 wrapper to turn adapter * interrupts on. * * Returns - Nothing. * ****************************************************************************/ VOID MadgeEnableInterrupts(NDIS_HANDLE adapterContext) { // MadgePrint1("MadgeEnableInterrupts\n"); // // Note: it is very difficult for use to disble interrupts at the // adapter so we don't. We use a spin lock to protect our DPR // routine. // } /**************************************************************************** * * Function - MadgeSend * * Parameters - adapterContext -> Pointer to our NDIS level adapter * structure. * packet -> Pointer to the NDIS3 packet to send. * flags -> Optional flags. * * Purpose - Called by the NDIS3 wrapper when it wants us to send a * frame. * * Returns - NDIS3 status code. * ****************************************************************************/ NDIS_STATUS MadgeSend(NDIS_HANDLE adapterContext, PNDIS_PACKET packet, UINT flags) { ULONG *pagePtr; UINT pageCount; UINT physFrags; UINT i; UINT size; UINT bytes; UINT count; NDIS_BUFFER *bufPtr; NDIS_STATUS retCode; PMADGE_ADAPTER ndisAdap; UINT totalPacketSize; WORD status; // // Set up a pointer to our adapter handle. // ndisAdap = PMADGE_ADAPTER_FROM_CONTEXT(adapterContext); // // Find out how long the frame is and where it's header is. // NdisQueryPacket(packet, NULL, NULL, NULL, &totalPacketSize); // // Make sure the frame isn't too long or two short. // if (totalPacketSize > ndisAdap->MaxFrameSize || totalPacketSize < FRAME_HEADER_SIZE) { retCode = NDIS_STATUS_INVALID_PACKET; } // // Check that a PCMCIA adapter is still physically present. // else if (ndisAdap->AdapterRemoved) { MadgePrint1("MadgeSend aborting - adapter removed\n"); retCode = NDIS_STATUS_SUCCESS; } // // Otherwise we need to send the frame over the ring. // else { status = rxtx_transmit_frame( ndisAdap->FtkAdapterHandle, (DWORD) packet, (WORD) totalPacketSize, TRUE ); // // Check if the frame has been transmitted completely. // if (status == DRIVER_TRANSMIT_SUCCEED) { ndisAdap->FramesTransmitted++; retCode = NDIS_STATUS_SUCCESS; #ifdef OID_MADGE_MONITOR // // Update the appropriate parts of the monitor structure // (ndisAdap->MonitorInfo).TransmitFrames++; (ndisAdap->MonitorInfo).TransmitFrameSize[totalPacketSize/128]++; // // Find the number of physical fragments sent // NdisQueryPacket(packet, NULL, NULL, &bufPtr, &totalPacketSize); physFrags = 0; count = 0; while (bufPtr != NULL) { MDL *mdl = (MDL *) bufPtr; count++; pageCount = (((MDL *) bufPtr)->Size - sizeof(MDL)) / sizeof(ULONG); pagePtr = (ULONG *) (((MDL *) bufPtr) + 1); physFrags++; // First page. bytes = mdl->ByteCount; if (pageCount <= 1) { size = bytes; } else { size = 4096 - mdl->ByteOffset; bytes -= size; } for (i = 1; i < pageCount; i++) { if (pagePtr[i] != pagePtr[i - 1] + 1) { size = 0; physFrags++; } if (i == pageCount - 1) { size += bytes; } else { bytes -= 4096; size += 4096; } } NdisGetNextBuffer(bufPtr, &bufPtr); } if (count < 65) { (ndisAdap->MonitorInfo).NumberOfVFrags[count]++; } if (physFrags < 65) { (ndisAdap->MonitorInfo).NumberOfPFrags[physFrags]++; } #endif } // // Or not transmitted at all, in which case we must // queue it for later. // else { retCode = NDIS_STATUS_RESOURCES; } } return retCode; } /*************************************************************************** * * Function - MadgeCopyFromPacketToBuffer * * Parameters - packet -> The NDIS3 packet to copy. * offset -> Starting offset into the packet. * bytesToCopy -> Number of bytes to copy. * destPtr -> Pointer to the destination buffer. * bytesCopied -> Pointer to a holder for the number of * bytes actually copied. * * Purpose - Copy data from an NDIS3 packet into a buffer. * * Returns - Nothing. * ****************************************************************************/ VOID MadgeCopyFromPacketToBuffer( PNDIS_PACKET packet, UINT offset, UINT bytesToCopy, PCHAR destPtr, PUINT bytesCopied ) { UINT bufferCount; PNDIS_BUFFER currentBuffer; PVOID currentPtr; UINT currentLength; UINT amountToMove; UINT localBytesCopied; *bytesCopied = 0; localBytesCopied = 0; if (bytesToCopy == 0) { return; } NdisQueryPacket(packet, NULL, &bufferCount, ¤tBuffer, NULL); if (bufferCount == 0) { return; } NdisQueryBuffer(currentBuffer, ¤tPtr, ¤tLength); while (localBytesCopied < bytesToCopy) { if (currentLength == 0) { NdisGetNextBuffer(currentBuffer, ¤tBuffer); if (currentBuffer == 0) { break; } NdisQueryBuffer(currentBuffer, ¤tPtr, ¤tLength); continue; } if (offset > 0) { if (offset > currentLength) { offset -= currentLength; currentLength = 0; continue; } else { currentPtr = (PCHAR) currentPtr + offset; currentLength -= offset; offset = 0; } } amountToMove = (currentLength <= (bytesToCopy - localBytesCopied)) ? currentLength : bytesToCopy - localBytesCopied; MADGE_MOVE_MEMORY(destPtr, currentPtr, amountToMove); destPtr = (PCHAR) destPtr + amountToMove; currentPtr = (PCHAR) currentPtr + amountToMove; localBytesCopied += amountToMove; currentLength -= amountToMove; } *bytesCopied = localBytesCopied; } /**************************************************************************** * * Function - MadgeTransferData * * Parameters - adapterContext -> Pointer to our NDIS level adapter * structure. * receiveContext -> Pointer to the start of the frame data. * byteOffset -> Offset to start copying from. * bytesToTransfer -> Number of bytes to copy. * packet -> NDIS packet for the data. * bytesTransferred -> Pointer to a holder for the number of * bytes actually copied. * * Purpose - Copy data from the received frame just indicated into an * NDIS packet. This function is called by the NDIS3 wrapper * in response to our indication frame rxtx_irq_received_frame. * * Returns - An NDIS3 status code. * ****************************************************************************/ NDIS_STATUS MadgeTransferData( PNDIS_PACKET packet, PUINT bytesTransferred, NDIS_HANDLE adapterContext, NDIS_HANDLE receiveContext, UINT byteOffset, UINT bytesToTransfer ) { PMADGE_ADAPTER ndisAdap; NDIS_STATUS retCode; // // Pre-calculate some values. // ndisAdap = PMADGE_ADAPTER_FROM_CONTEXT(adapterContext); // // Check that the data pointer is valid. // if ((PCHAR) receiveContext == NULL) { retCode = NDIS_STATUS_FAILURE; } // // If it is, copy from the frame from the receive buffer // into the packet. // else { MadgeCopyFromBufferToPacket( (PCHAR) receiveContext + byteOffset, bytesToTransfer, packet, 0, bytesTransferred ); retCode = NDIS_STATUS_SUCCESS; #ifdef OID_MADGE_MONITOR // // Update the appropriate parts of the monitor structure // if ((ndisAdap->MonitorInfo).ReceiveFlag > 0) { (ndisAdap->MonitorInfo).TransferFrames++; (ndisAdap->MonitorInfo).TransferFrameSize[(ndisAdap->MonitorInfo).CurrentFrameSize/128]++; (ndisAdap->MonitorInfo).ReceiveFlag = 0; } #endif } return retCode; } /*************************************************************************** * * Function - MadgeCopyFromBufferToPacket * * Parameters - srcPtr -> Pointer to the source buffer. * bytesToCopy -> Number of bytes to copy. * packet -> The NDIS3 destination packet. * offset -> Starting offset into the buffer. * bytesCopied -> Pointer to a holder for the number of * bytes actually copied. * * Purpose - Copy data from a buffer into an NDIS3 packet. * * Returns - Nothing. * ****************************************************************************/ VOID MadgeCopyFromBufferToPacket( PCHAR srcPtr, UINT bytesToCopy, PNDIS_PACKET packet, UINT offset, PUINT bytesCopied ) { UINT bufferCount; PNDIS_BUFFER currentBuffer; PVOID virtualAddress; UINT currentLength; UINT amountToMove; UINT localBytesCopied; *bytesCopied = 0; localBytesCopied = 0; if (bytesToCopy == 0) { return; } NdisQueryPacket(packet, NULL, &bufferCount, ¤tBuffer, NULL); if (bufferCount == 0) { return; } NdisQueryBuffer(currentBuffer, &virtualAddress, ¤tLength); while (localBytesCopied < bytesToCopy) { if (currentLength == 0) { NdisGetNextBuffer(currentBuffer, ¤tBuffer); if (currentBuffer == NULL) { break; } NdisQueryBuffer(currentBuffer, &virtualAddress, ¤tLength); continue; } if (offset > 0) { if (offset > currentLength) { offset -= currentLength; currentLength = 0; continue; } else { virtualAddress = (PCHAR) virtualAddress + offset; currentLength -= offset; offset = 0; } } amountToMove = (bytesToCopy - localBytesCopied < currentLength) ? bytesToCopy - localBytesCopied : currentLength; MADGE_MOVE_MEMORY( virtualAddress, srcPtr, amountToMove ); srcPtr += amountToMove; localBytesCopied += amountToMove; currentLength -= amountToMove; } *bytesCopied = localBytesCopied; } /*************************************************************************** * * Function - MadgeISR * * Parameters - interruptRecognised -> Pointer to an interrupt recognised * flag we set if we recognise the * interrupt. * queueDPR -> Pointer to DPR required flag we * set if we need a DPR. * adapterContext -> Pointer to our NDIS level adapter * structure. * * Purpose - Process an IRQ from an adapter. All we do is call the * HWI and schedule a DPR if required. * * Returns - Nothing. * ****************************************************************************/ VOID MadgeISR( PBOOLEAN interruptRecognised, PBOOLEAN queueDPR, NDIS_HANDLE adapterContext ) { PMADGE_ADAPTER ndisAdap; ndisAdap = PMADGE_ADAPTER_FROM_CONTEXT(adapterContext); hwi_interrupt_entry( ndisAdap->FtkAdapterHandle, (WORD) ndisAdap->UsedInISR.InterruptNumber ); // // If ndisAdap->DprRequired is TRUE then we recognised the interrupt // and found something that requires further processing (e.g. received // a frame). If ndisAdap->DprRequired is FALSE then we either didn't // recognise the interrupt or we don't need any further processing. // The only operation that doesn't need further processing is ISA // PIO. Since ISA cards cannot share interrupt lines it doesn't // matter if we say we don't recognise the interrupt if we don't // need any further processing. Hence we can use ndisAdap->DprRequired // to set both *interruptRecognised and *queueDpr. // // // However ... // There is a race condition with ATULA based cards in PIO mode. // Normally we do not claim interrupts that are used for PIO transfers // to avoid the overhead of a DPR on PIO transfers. However, in some // instances if we do not claim the PIO interrupts used for the // initial "DMA" tests then WFWG (and possibly NT) permanently disables // our interrupts. To get around this we claim all interrupts until // our rx/tx buffers have been allocated since the optimisation of not // queuing a DPR for PIO interrupts doesn't matter until we have // rx/tx buffers in place. // *interruptRecognised = (ndisAdap->RxTxBufferState != MADGE_RXTX_INITIALIZED) ? TRUE : ndisAdap->DprRequired; *queueDPR = ndisAdap->DprRequired; ndisAdap->DprRequired = FALSE; } /*-------------------------------------------------------------------------- | | Function - MadgeSyncSRBPending | | Parameters - synchonizedContext -> A pointer to an NDIS3 level adapter | structure. | | Purpose - Process a completed SRBs. This routine is always | syncronised with IRQs. | | Returns - TRUE if the SRB has actually completed or FALSE if not. | --------------------------------------------------------------------------*/ STATIC BOOLEAN MadgeSyncSRBPending(PVOID synchronizeContext) { PMADGE_ADAPTER ndisAdap; BOOLEAN retCode; ndisAdap = PMADGE_ADAPTER_FROM_CONTEXT(synchronizeContext); retCode = ndisAdap->UsedInISR.SrbRequestCompleted; if (retCode) { ndisAdap->UsedInISR.SrbRequestCompleted = FALSE; ndisAdap->SrbRequestStatus = ndisAdap->UsedInISR.SrbRequestStatus; } return retCode; } /**************************************************************************** * * Function - MadgeHandleInterrupt * * Parameters - adapterContext -> Pointer to our NDIS level adapter * structure. * * Purpose - Our DPR routine. * * Returns - Nothing. * ****************************************************************************/ VOID MadgeHandleInterrupt(NDIS_HANDLE adapterContext) { PMADGE_ADAPTER ndisAdap; ndisAdap = PMADGE_ADAPTER_FROM_CONTEXT(adapterContext); // // Must do anything if we don't have tx/rx buffers. // if (ndisAdap->RxTxBufferState != MADGE_RXTX_INITIALIZED) { return; } // // I think this check is a bit paranoid. I think DPRs are guaranteed // to be single threaded. I suppose it might be needed on a multi- // processor. Just 'cos your've paraonoid doesn't mean they're not // out to get you! // if (!ndisAdap->DprInProgress) { ndisAdap->DprInProgress = TRUE; // // Handle completed SRBs first. // if (NdisMSynchronizeWithInterrupt( &ndisAdap->Interrupt, MadgeSyncSRBPending, adapterContext)) { MadgeCompletePendingRequest(ndisAdap); } // // If the adapter has been removed then call the housekeeping // function. // if (ndisAdap->AdapterRemoved) { rxtx_adapter_removed(ndisAdap->FtkAdapterHandle); } // // Check for transmit completions. // rxtx_irq_tx_completion_check( ndisAdap->FtkAdapterHandle, adapter_record[ndisAdap->FtkAdapterHandle] ); // // See if there are any received frames. // driver_get_outstanding_receive(ndisAdap->FtkAdapterHandle); ndisAdap->DprInProgress = FALSE; } // // This else should never be executed! // else { MadgePrint1("DPR reentered!!!!\n"); } } /******** End of DISPATCH.C ************************************************/