|
|
//
// Copyright (c) 1998-1999, Microsoft Corporation, all rights reserved
//
// cm.c
//
// IEEE1394 mini-port/call-manager driver
//
// Call Manager routines
//
// 12/28/1998 JosephJ Created
// 01/01/1999 ADube modified - Added Remote Node Capability
//
#include "precomp.h"
//-----------------------------------------------------------------------------
// Call-manager handlers and completers
//-----------------------------------------------------------------------------
NDIS_STATUS NicCmOpenAf( IN NDIS_HANDLE CallMgrBindingContext, IN PCO_ADDRESS_FAMILY AddressFamily, IN NDIS_HANDLE NdisAfHandle, OUT PNDIS_HANDLE CallMgrAfContext )
// Standard 'CmCmOpenAfHandler' routine called by NDIS when a client
// requests to open an address family. See DDK doc.
//
{ ADAPTERCB* pAdapter; NDIS_HANDLE hExistingAf; NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
TIMESTAMP_ENTRY ("==>Open Af");
TRACE( TL_T, TM_Cm, ( "==>NicCmOpenAf" ) );
pAdapter = (ADAPTERCB* )CallMgrBindingContext; if (pAdapter->ulTag != MTAG_ADAPTERCB) { ASSERT( !"Atag?" ); return NDIS_STATUS_INVALID_DATA; }
if (AddressFamily->AddressFamily != CO_ADDRESS_FAMILY_1394 || AddressFamily->MajorVersion != NDIS_MajorVersion || AddressFamily->MinorVersion != NDIS_MinorVersion) { return NDIS_STATUS_BAD_VERSION; }
do { AFCB *pAF = NULL;
// Allocate and initialize the adress family structure.
//
pAF = ALLOC_NONPAGED( sizeof(*pAF), MTAG_AFCB ); if (!pAF) { Status = NDIS_STATUS_RESOURCES; break; } NdisZeroMemory( pAF, sizeof(*pAF) );
// Set a marker for easier memory dump browsing and future assertions.
//
pAF->ulTag = MTAG_AFCB; // Save the NDIS handle associated with this AF for use in future
// NdisXxx calls.
//
ADAPTER_ACQUIRE_LOCK( pAdapter );
pAF->NdisAfHandle = NdisAfHandle; // Initialize the VC list for this AF.
//
InitializeListHead( &pAF->AFVCList ); // Set up linkages and references.
//
pAF->pAdapter = pAdapter; nicReferenceAF( pAF ); // OpenAF
nicReferenceAdapter( pAdapter ,"NicCmOpenAf "); // OpenAF
InsertHeadList(&pAdapter->AFList, &pAF->linkAFCB);
// Return pAF as the address family context.
//
*CallMgrAfContext = (PNDIS_HANDLE )pAF;
ADAPTER_RELEASE_LOCK (pAdapter);
} while (FALSE);
TRACE( TL_T, TM_Cm, ( "NicCmOpenAf Status %x", Status ) );
TIMESTAMP_EXIT("<==Open Af ");
return Status; }
NDIS_STATUS NicCmCloseAf( IN NDIS_HANDLE CallMgrAfContext )
// Standard 'CmCloseAfHandler' routine called by NDIS when a client
// requests to close an address family. See DDK doc.
//
{ AFCB* pAF; TIMESTAMP_ENTRY ("==>CloseAf"); TRACE( TL_T, TM_Cm, ( "NicCmCloseAf" ) );
pAF = (AFCB* )CallMgrAfContext; if (pAF->ulTag != MTAG_AFCB) { ASSERT( !"AFCB?" ); return NDIS_STATUS_INVALID_DATA; } nicSetFlags (&pAF->ulFlags, ACBF_ClosePending);
// This dereference will eventually lead to us calling
// NdisMCmCloseAfComplete.
//
//
// The references that were made in OpenAf
//
nicDereferenceAF( pAF );
TRACE( TL_T, TM_Cm, ( "NicCmCloseAf pending" ) ); TIMESTAMP_EXIT ("<==Close Af");
return NDIS_STATUS_PENDING; }
NDIS_STATUS NicCmCreateVc( IN NDIS_HANDLE ProtocolAfContext, IN NDIS_HANDLE NdisVcHandle, OUT PNDIS_HANDLE ProtocolVcContext )
// Standard 'CmCreateVc' routine called by NDIS in response to a
// client's request to create a virtual circuit. This
// call must return synchronously.
//
{ NDIS_STATUS status; AFCB* pAF; VCCB* pVc;
TRACE( TL_T, TM_Cm, ( "==>NicCmCreateVc, Af %x",ProtocolAfContext) ); pAF = (AFCB* )ProtocolAfContext; if (pAF->ulTag != MTAG_AFCB) { ASSERT( !"Atag?" ); return NDIS_STATUS_INVALID_DATA; }
// Allocate and zero a VC control block, then make any non-zero
// initializations.
//
pVc = ALLOC_VCCB( pAdapter ); if (!pVc) { ASSERT( !"Alloc VC?" ); return NDIS_STATUS_RESOURCES; }
NdisZeroMemory( pVc, sizeof(*pVc) );
TRACE( TL_I, TM_Cm, ( "NicCmCreateVc $%p", pVc ) );
// Set a marker for easier memory dump browsing.
//
pVc->Hdr.ulTag = MTAG_VCCB;
// Save the NDIS handle of this VC for use in indications to NDIS later.
//
pVc->Hdr.NdisVcHandle = NdisVcHandle;
// The VC control block's address is the VC context we return to NDIS.
//
*ProtocolVcContext = (NDIS_HANDLE )pVc;
// Add a reference to the control block and the associated address family
// that is removed by LmpCoDeleteVc. Add the linkages.
//
pVc->Hdr.pAF = pAF; // Initialize the VC's copy of the spinlock to point to the Adapter's spinlock.
//
pVc->Hdr.plock = &pAF->pAdapter->lock;
nicReferenceVc( pVc ); // Create VC
nicReferenceAF( pAF ); // Create VC
VC_SET_FLAG (pVc, VCBF_VcCreated); // Add to list of VC's associated with this AF
//
AF_ACQUIRE_LOCK (pAF); InsertHeadList(&pAF->AFVCList, &pVc->Hdr.linkAFVcs);
AF_RELEASE_LOCK (pAF);
TRACE( TL_T, TM_Cm, ( "<==NicCmCreateVc=0" ) ); return NDIS_STATUS_SUCCESS; }
NDIS_STATUS NicCmDeleteVc( IN NDIS_HANDLE ProtocolVcContext )
// Standard 'CmDeleteVc' routine called by NDIS in response to a
// client's request to delete a virtual circuit. This
// call must return synchronously.
//
{ VCCB* pVc = NULL; AFCB *pAF = NULL; PADAPTERCB pAdapter = NULL;
TRACE( TL_T, TM_Cm, ( "==>NicCmDelVc($%p)", ProtocolVcContext ) );
pVc = (VCCB* )ProtocolVcContext; if (pVc->Hdr.ulTag != MTAG_VCCB) { ASSERT( !"Vtag?" ); return NDIS_STATUS_INVALID_DATA; }
VC_ACQUIRE_LOCK (pVc); // Set vc flag to deleted, and remove back pointer to AF
//
{
// This flag catches attempts by the client to delete the VC twice.
//
if (nicReadFlags( &pVc->Hdr.ulFlags ) & VCBF_VcDeleted) { TRACE( TL_A, TM_Cm, ( "VC $%p re-deleted?", pVc ) );
VC_RELEASE_LOCK ( pVc );
ASSERT (0); return NDIS_STATUS_FAILURE; } nicSetFlags( &pVc->Hdr.ulFlags, VCBF_VcDeleted );
pAF = pVc->Hdr.pAF; }
// Unlink from the AF vc list.
//
{
nicRemoveEntryList (&pVc->Hdr.linkAFVcs); InitializeListHead (&pVc->Hdr.linkAFVcs);
pVc->Hdr.pAF = NULL;
}
// Remove the references added by NicCmCreateVc.
//
VC_RELEASE_LOCK (pVc);
nicDereferenceAF( pAF );
//
// This deref could cause the Vc to be deleted. Don't touch the Vc after that
//
nicDereferenceVc( pVc );
TRACE( TL_T, TM_Cm, ( "<==NicCmDelVc 0" ) ); return NDIS_STATUS_SUCCESS; }
NDIS_STATUS NicCmMakeCall( IN NDIS_HANDLE CallMgrVcContext, IN OUT PCO_CALL_PARAMETERS pCallParameters, IN NDIS_HANDLE NdisPartyHandle, OUT PNDIS_HANDLE CallMgrPartyContext )
// Function Description:
//
// Standard 'CmMakeCallHandler' routine called by NDIS when the a client
// has requested to connect to a remote end-point. See DDK doc.
//
// Arguments
// Call Mge context:
// Call Parameters
// Optiuonal NdisPartyHandle
// Return Value:
//
//
{
PVCCB pVc = (VCCB* )CallMgrVcContext; NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; PADAPTERCB pAdapter = NULL; NDIS_WORK_ITEM* pMakeCallCompleteWorkItem = NULL;
PCO_MEDIA_PARAMETERS pMediaParams = pCallParameters->MediaParameters; PNIC1394_MEDIA_PARAMETERS pN1394Params = (PNIC1394_MEDIA_PARAMETERS) pMediaParams->MediaSpecific.Parameters;
TRACE( TL_T, TM_Cm, ( "==>NicCmMakeCall" ) );
nicInterceptMakeCallParameters(pMediaParams);
do {
if (NdisPartyHandle != NULL || pVc == NULL || pCallParameters == NULL || pCallParameters->MediaParameters == NULL || pCallParameters->MediaParameters->MediaSpecific.ParamType != NIC1394_MEDIA_SPECIFIC || pN1394Params->MTU == 0) { //
// We do not support these parameters
//
return NDIS_STATUS_FAILURE; }
pAdapter = pVc->Hdr.pAF->pAdapter; ASSERT (pAdapter != NULL);
//
// Reference the Vc so it does not go during this makeCall
// This is decremented in the failure code path or the workitem or
// when the call is closed
VC_ACQUIRE_LOCK (pVc); nicReferenceVc (pVc);
//
// Erase all references to past calls
//
VC_CLEAR_FLAGS (pVc, VCBM_NoActiveCall); VC_SET_FLAG (pVc, VCBF_MakeCallPending); //
// Initialize the Call's refcount to 1 beacuse we are about to begin to allocate resources to the MakeCall
// This will be decremented in the closecall handler. Or in the failure code path
//
nicInitializeCallRef (pVc);
VC_RELEASE_LOCK (pVc);
pVc->Hdr.pCallParameters = pCallParameters; NdisStatus = nicCmGenericMakeCallInit (pVc);
if (NdisStatus != NDIS_STATUS_SUCCESS) { TRACE( TL_A, TM_Cm, ( "nicCmGenericMakeCallInit did not succeed- Make Call FAILED($%p)", CallMgrVcContext ) ); break; } //
// If status is pending it means that we want to make this an asynchronous call
// The completing th
pMakeCallCompleteWorkItem = ALLOC_NONPAGED (sizeof(NDIS_WORK_ITEM), MTAG_WORKITEM);
if (pMakeCallCompleteWorkItem == NULL) { TRACE( TL_A, TM_Cm, ( "Local Alloc failed for WorkItem - Make Call FAILED($%p)", CallMgrVcContext ) ); NdisStatus = NDIS_STATUS_RESOURCES; break; }
//
// Now schedule the work item so it runs at passive level and pass the Vc as
// an argument
//
NdisInitializeWorkItem ( pMakeCallCompleteWorkItem, (NDIS_PROC)nicCmMakeCallComplete, (PVOID)pVc );
NdisInterlockedIncrement(&pAdapter->OutstandingWorkItems);
NdisScheduleWorkItem (pMakeCallCompleteWorkItem);
NdisStatus = NDIS_STATUS_PENDING;
} while (FALSE);
if (!NT_SUCCESS (NdisStatus)) {
//
// Clean up, close the ref on the Calls, Deref the Call. And Update the Vc
// to show that we have failed the make call
//
nicCmGenrericMakeCallFailure (pVc);
}
TRACE( TL_T, TM_Cm, ( "<==NicCmMakeCall, Vc %x, Status%x", pVc, NdisStatus ) ); return NdisStatus; }
NDIS_STATUS nicCmGenericMakeCallInitChannels ( IN PCHANNEL_VCCB pChannelVc, VC_SEND_RECEIVE VcType ) /*++
Routine Description: Initialze handlers for Send / Recv Channels
Arguments:
Return Value:
--*/ { NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS; // As there are no allocations
PCO_MEDIA_PARAMETERS pMediaParams = pChannelVc->Hdr.pCallParameters->MediaParameters; PNIC1394_MEDIA_PARAMETERS pN1394Params = (PNIC1394_MEDIA_PARAMETERS) pMediaParams->MediaSpecific.Parameters;
if ((pN1394Params->Flags & NIC1394_VCFLAG_ALLOCATE) == NIC1394_VCFLAG_ALLOCATE) { TRACE( TL_V, TM_Cm, ( " MakeCall- Channel Vc %x nneds to allocate channel %x", pChannelVc, pN1394Params->Destination.Channel) );
VC_SET_FLAG (pChannelVc, VCBF_NeedsToAllocateChannel); } switch (VcType) { case TransmitAndReceiveVc: { //
// Channels will be defaulted to have Send And Receive Capabilities
//
TRACE( TL_V, TM_Cm, ( " MakeCall- Channel Transmit and Receive Vc Vc %x", pChannelVc ) );
pChannelVc->Hdr.VcType = NIC1394_SendRecvChannel; pChannelVc->Hdr.VcHandlers.MakeCallHandler = nicCmMakeCallInitSendRecvChannelVc; pChannelVc->Hdr.VcHandlers.CloseCallHandler = nicCmCloseCallSendRecvChannel; pChannelVc->Hdr.VcHandlers.SendPackets = AsyncStreamSendPacketsHandler; break; } case ReceiveVc: { TRACE( TL_V, TM_Cm, ( " MakeCall- Channel Receive Vc %x", pChannelVc ) ); pChannelVc->Hdr.VcType = NIC1394_RecvChannel; pChannelVc->Hdr.VcHandlers.MakeCallHandler = nicCmMakeCallInitSendRecvChannelVc; pChannelVc->Hdr.VcHandlers.CloseCallHandler = nicCmCloseCallSendRecvChannel; pChannelVc->Hdr.VcHandlers.SendPackets = DummySendPacketsHandler;
break; } case TransmitVc: { TRACE( TL_V, TM_Cm, ( " MakeCall- Channel Transmit Vc Vc %x", pChannelVc ) ); pChannelVc->Hdr.VcType = NIC1394_SendChannel; pChannelVc->Hdr.VcHandlers.MakeCallHandler = nicCmMakeCallSendChannel ; pChannelVc->Hdr.VcHandlers.CloseCallHandler = nicCmCloseCallSendChannel; pChannelVc->Hdr.VcHandlers.SendPackets = AsyncStreamSendPacketsHandler; break;
}
default: {
NdisStatus = NDIS_STATUS_FAILURE; }
}
return NdisStatus;
}
NDIS_STATUS nicCmGenericMakeCallInitFifo ( IN PVCCB pVc, VC_SEND_RECEIVE VcType
) /*++
Routine Description: Initializes Fifo Vcs'. This only fails a recv fifo is asked for and the adapter already has one. Arguments: pVc
Return Value:
--*/ { NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS; //As there are no allocations
PCO_MEDIA_PARAMETERS pMediaParams = pVc->Hdr.pCallParameters->MediaParameters; PNIC1394_MEDIA_PARAMETERS pN1394Params = (PNIC1394_MEDIA_PARAMETERS) pMediaParams->MediaSpecific.Parameters;
switch (VcType) { case ReceiveVc: { //
// Recv FifoVcs
//
PADAPTERCB pAdapter = pVc->Hdr.pAF->pAdapter; PRECVFIFO_VCCB pRecvFIFOVc = (PRECVFIFO_VCCB) pVc;
ASSERT(pMediaParams->Flags & RECEIVE_VC); TRACE( TL_V, TM_Cm, ( " MakeCall - AsyncReceiveVc Vc %x", pVc ) ); pVc->Hdr.VcType = NIC1394_RecvFIFO;
pVc->Hdr.VcHandlers.MakeCallHandler = nicCmMakeCallInitRecvFIFOVc; pVc->Hdr.VcHandlers.SendPackets = DummySendPacketsHandler; pVc->Hdr.VcHandlers.CloseCallHandler = nicCmCloseCallRecvFIFO;
//
// There are two reasons to fail a RecvFIFO Make call.
// One, a REcvFIFO already exists and second UniqueId != 0
//
if (pAdapter->pRecvFIFOVc == NULL && pN1394Params->Destination.FifoAddress.UniqueID == 0 ) { ADAPTER_ACQUIRE_LOCK (pAdapter); pAdapter->pRecvFIFOVc = (PRECVFIFO_VCCB)pVc; //
// Since the adapter now has a pointer to the Vc, increment the Refcount.
// This will be decremented in the CloseCall
//
nicReferenceVc (pVc);
ADAPTER_RELEASE_LOCK (pAdapter); } else { TRACE( TL_A, TM_Cm, ( "Adapter at %x, already has a recvFIFO. Field is at %x", pAdapter, &pAdapter->pRecvFIFOVc ) ); ASSERT (pAdapter->pRecvFIFOVc == NULL);
NdisStatus = NDIS_STATUS_FAILURE;
pVc->Hdr.VcHandlers.MakeCallHandler = NULL; pVc->Hdr.VcHandlers.CloseCallHandler = NULL; }
break; } case TransmitVc: { //
// Send Fifo Vcs
//
TRACE( TL_V, TM_Cm, ( " MakeCall - AsyncTransmitVc Vc %x", pVc ) );
pVc->Hdr.VcType = NIC1394_SendFIFO;
pVc->Hdr.VcHandlers.MakeCallHandler = nicCmMakeCallInitSendFIFOVc; pVc->Hdr.VcHandlers.SendPackets = AsyncWriteSendPacketsHandler; pVc->Hdr.VcHandlers.CloseCallHandler = nicCmCloseCallSendFIFO;
break;
}
case TransmitAndReceiveVc: default: {
NdisStatus = NDIS_STATUS_FAILURE; }
}
return NdisStatus;
}
NDIS_STATUS nicCmGenericMakeCallMutilChannel ( IN PVCCB pVc, VC_SEND_RECEIVE VcType ) /*++
Routine Description: Init the handlers
Arguments:
Return Value:
--*/ {
TRACE( TL_A, TM_Cm, ( "Make Call Recvd for MultiChannel %x ", pVc) ); pVc->Hdr.VcType = NIC1394_MultiChannel; pVc->Hdr.VcHandlers.MakeCallHandler = nicCmMakeCallMultiChannel ; pVc->Hdr.VcHandlers.CloseCallHandler = nicCmCloseCallMultiChannel ; pVc->Hdr.VcHandlers.SendPackets = AsyncStreamSendPacketsHandler;
return NDIS_STATUS_SUCCESS;
}
NDIS_STATUS nicCmGenericMakeCallEthernet( IN PVCCB pVc, IN VC_SEND_RECEIVE VcType ) /*++
Routine Description:
Init the handlers Arguments:
Return Value:
--*/
{
TRACE( TL_A, TM_Cm, ( "Make Call Recvd for Ethernet %x ", pVc) );
pVc->Hdr.VcType = NIC1394_Ethernet;
pVc->Hdr.VcHandlers.MakeCallHandler = nicCmMakeCallInitEthernet; pVc->Hdr.VcHandlers.SendPackets = nicEthernetVcSend; pVc->Hdr.VcHandlers.CloseCallHandler = nicCmCloseCallEthernet ;
return NDIS_STATUS_SUCCESS;
}
NDIS_STATUS nicCmGenericMakeCallInit ( IN PVCCB pVc ) // Function Description:
//
// This initializes the VcType and Copied the Media Parameters over
// Initialized VCType to SendChannel, RecvChannel, SendAndRecvChanne,
// SendFifo,
//
// Arguments
// Vc - Vc that needs to be initalized
//
// Return Value:
// Success - as no memory allocation takes place
// This function should not do anything that can fail.
{ NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS; VC_SEND_RECEIVE VcType = InvalidType; PCO_MEDIA_PARAMETERS pMediaParams = pVc->Hdr.pCallParameters->MediaParameters; PNIC1394_MEDIA_PARAMETERS pN1394Params = (PNIC1394_MEDIA_PARAMETERS) pMediaParams->MediaSpecific.Parameters;
TRACE( TL_T, TM_Cm, ( "==>nicCmGenericMakeCallInit pVc %x", pVc ) );
pVc->Hdr.Nic1394MediaParams = *pN1394Params; ASSERT(pVc->Hdr.pAF!=NULL); pVc->Hdr.pGeneration = &pVc->Hdr.pAF->pAdapter->Generation;
//
// Figure out if this is send or receive Vc Or both
//
do { if ((pMediaParams->Flags & (TRANSMIT_VC |RECEIVE_VC)) == TRANSMIT_VC) { VcType = TransmitVc; break; }
if ((pMediaParams->Flags & (TRANSMIT_VC |RECEIVE_VC)) == RECEIVE_VC) { VcType = ReceiveVc; break; } if ((pMediaParams->Flags & (TRANSMIT_VC |RECEIVE_VC)) == (TRANSMIT_VC |RECEIVE_VC) ) { VcType = TransmitAndReceiveVc; break; }
} while (FALSE); ASSERT (VcType <= TransmitAndReceiveVc);
switch (pN1394Params->Destination.AddressType) { case NIC1394AddressType_Channel: { NdisStatus = nicCmGenericMakeCallInitChannels ((PCHANNEL_VCCB)pVc, VcType);
break; } case NIC1394AddressType_FIFO: { //
// Now we are in FIFO land.
//
NdisStatus = nicCmGenericMakeCallInitFifo (pVc, VcType ); break; }
case NIC1394AddressType_MultiChannel: {
NdisStatus = nicCmGenericMakeCallMutilChannel (pVc, VcType ); break; }
case NIC1394AddressType_Ethernet: { NdisStatus = nicCmGenericMakeCallEthernet(pVc, VcType ); break; }
default: {
ASSERT (pN1394Params->Destination.AddressType<=NIC1394AddressType_Ethernet); NdisStatus = NDIS_STATUS_FAILURE; break; }
}
TRACE( TL_T, TM_Cm, ( "<==nicCmGenericMakeCallInit pVc %x, Status %x",pVc , NdisStatus) ); return NdisStatus; }
VOID nicCmGenrericMakeCallFailure ( IN PVCCB pVc ) // Function Description:
// Does the clean up on the VcHDr structure. Will cleanup the Destination, VcType
// and Vc. Initialize Handler. Special case - Recv VC
// Arguments
// PVCCB : Vc on which cleanup need to be done.
// Return Value:
// None
{
TRACE( TL_T, TM_Cm, ( "==>nicGenrericMakeCallFailure pVc %x, ",pVc ) );
//
// First, we need to make sure if adapter's VC is the same as this VC,
// otherwise the adapters'recv VC is Valid Vc currently in Use. Do not touch it.
//
if (pVc->Hdr.VcType == NIC1394_RecvFIFO && pVc->Hdr.pAF->pAdapter->pRecvFIFOVc == (PRECVFIFO_VCCB)pVc) { //
// This is the reference that was added GenericInitVc function
// and only applied to Recv VC's
//
nicDereferenceVc (pVc); }
VC_ACQUIRE_LOCK(pVc)
pVc->Hdr.VcHandlers.MakeCallHandler = NULL; pVc->Hdr.VcHandlers.CloseCallHandler = NULL;
pVc->Hdr.VcType = NIC1394_Invalid_Type;
NdisZeroMemory (&pVc->Hdr.Nic1394MediaParams , sizeof (pVc->Hdr.Nic1394MediaParams) );
nicCloseCallRef (pVc);
//
// Mark the Vc Flags, with a MakeCall Failed
//
VC_CLEAR_FLAGS(pVc ,VCBF_MakeCallPending);
VC_SET_FLAG (pVc, VCBF_MakeCallFailed);
VC_RELEASE_LOCK (pVc); TRACE( TL_T, TM_Cm, ( "<==nicGenrericMakeCallFailure pVc %x, ",pVc ) );
}
VOID nicCmMakeCallComplete ( NDIS_WORK_ITEM* pMakeCallCompleteWorkItem, IN PVOID Context ) // Function:
// This function is used to complete a Make Call. This can be done synchronously
// or asynchronous. If a status pending was passed to this function, it will complete using
// the asynchronous route
//
// If everytrhing succeeds, one Ref to the Vc will be passed through and that will be decremented
// when the call is closed
// This function should never return NDIS_STATUS_PENDING. Will be called as a WorkItem
{
PVCCB pVc = (PVCCB)Context; PADAPTERCB pAdapter = pVc->Hdr.pAF->pAdapter; NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; STORE_CURRENT_IRQL;
TRACE( TL_T, TM_Cm, ( "==>NicCmMakeCallComplete ,pVc %x",pVc ) );
//
// Reference the Vc as we want the Vc structure to stay alive till
// the end of the make call complete
//
nicReferenceVc (pVc); //
// Call the Initialize handler for the VC so that it can be initialized
//
ASSERT (pVc->Hdr.VcHandlers.MakeCallHandler != NULL);
NdisStatus = (*pVc->Hdr.VcHandlers.MakeCallHandler) (pVc); MATCH_IRQL;
if (NdisStatus == NDIS_STATUS_SUCCESS) { VC_ACQUIRE_LOCK(pVc); //
// Now mark the Vc as active
//
VC_SET_FLAG( pVc, VCBF_VcActivated); VC_CLEAR_FLAGS(pVc ,VCBF_MakeCallPending);
VC_RELEASE_LOCK (pVc); } else { //
// call the clean up routine to bring the Vc back to its old state
//
nicCmMakeCallCompleteFailureCleanUp (pVc);
//
// Dereference the call that we are about to fail. This reference was made in
// the beginning of make call routine. when the callref ==0, the Vc will be
// dereferenced as well
//
VC_ACQUIRE_LOCK (pVc);
VC_SET_FLAG (pVc, VCBF_MakeCallFailed); VC_CLEAR_FLAGS(pVc ,VCBF_MakeCallPending); nicDereferenceCall (pVc, "nicCmMakeCallComplete");
VC_RELEASE_LOCK (pVc); }
MATCH_IRQL;
//
// Complete the call with the correct status
//
TRACE( TL_N, TM_Cm, ( "Completing the Make Call , Vc %x, Status %x", pVc, NdisStatus ) );
NdisCmMakeCallComplete(NdisStatus, pVc->Hdr.NdisVcHandle, NULL, NULL, pVc->Hdr.pCallParameters );
TRACE( TL_I, TM_Cm, ( "Called NdisCmMakeCallComplete, Vc %x, Status%x", pVc, NdisStatus ) );
TRACE( TL_T, TM_Cm, ( "<==NicCmMakeCallComplete, Vc %x, Status%x", pVc, NdisStatus ) );
FREE_NONPAGED (pMakeCallCompleteWorkItem);
NdisInterlockedDecrement(&pAdapter->OutstandingWorkItems); //
// This will cause the Vc Refcount to go to zero if the Make Call fails
//
nicDereferenceVc (pVc);
MATCH_IRQL; }
NDIS_STATUS nicCmMakeCallInitRecvFIFOVc( IN OUT PVCCB pVc ) // Function Description:
//
// This function allocates, packet pool, populates the Slist
// allocates the address range and
// inserts the Vc into the Adapter->pRecvFifoVc field
//
// Will succeed the call, if this process was successful on 1 remote node
// Arguments
// PVCCB : pVc that the call is made on
//
//
// Return Value:
// Success: If all allocations succeeded for just 1 remote node
{
PRECVFIFO_VCCB pRecvFIFOVc = (PRECVFIFO_VCCB) pVc; NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS; REMOTE_NODE *pRemoteNode = NULL; PADAPTERCB pAdapter = pRecvFIFOVc->Hdr.pAF->pAdapter;
PNIC1394_MEDIA_PARAMETERS pN1394Params = &pVc->Hdr.Nic1394MediaParams; UINT64 UniqueId = pN1394Params->Destination.FifoAddress.UniqueID; PLIST_ENTRY pPdoListEntry = NULL; BOOLEAN fWaitSuccessful = FALSE; BOOLEAN fInitRecvFifoDataStructures = FALSE; BOOLEAN fNeedToWait = FALSE; PNIC1394_FIFO_ADDRESS pFifoAddress = NULL;
STORE_CURRENT_IRQL;
TRACE( TL_T, TM_Cm, ( "==>nicCmMakeCallInitRecvFIFOVc pRecvFIFOVc %x ", pRecvFIFOVc) );
ASSERT (pAdapter != NULL); ASSERT (KeGetCurrentIrql()==PASSIVE_LEVEL);
pFifoAddress = &pN1394Params->Destination.FifoAddress;
UniqueId = pFifoAddress->UniqueID; do {
NdisStatus = nicInitRecvFifoDataStructures (pRecvFIFOVc);
if (NdisStatus != NDIS_STATUS_SUCCESS) { TRACE( TL_A, TM_Cm, ( " nicInitRecvFifoDataStructures FAILED pRecvFIFOVc is %x, UniqueId %I64x ", pRecvFIFOVc) ); break; }
fInitRecvFifoDataStructures = TRUE;
//
// This field is not used by a RecvFIFO because it has multiple Pdos
//
pRecvFIFOVc->Hdr.pRemoteNode = NULL;
NdisStatus = nicAllocateAddressRange(pAdapter, pRecvFIFOVc);
if(NdisStatus != NDIS_STATUS_SUCCESS) { TRACE( TL_A, TM_Cm, ( "Unable to get Pdo and allocate addresses, call FAILED ,pRecvFIFOVc is %x", pRecvFIFOVc) );
ASSERT(NdisStatus == NDIS_STATUS_SUCCESS);
break; }
ASSERT(pRecvFIFOVc->PacketPool.Handle != NULL); ASSERT(pRecvFIFOVc->Hdr.MTU != 0);
} while (FALSE);
if (NdisStatus != NDIS_STATUS_SUCCESS) { //
// Undo all allocated memory
//
TRACE( TL_A, TM_Cm, ( "Failing the Make Call for Vc %x" , pVc) );
if (fInitRecvFifoDataStructures == TRUE) { nicUnInitRecvFifoDataStructures (pRecvFIFOVc); }
} TRACE( TL_I, TM_Cm, ( "pVc's Offset High %4x",pVc->Hdr.Nic1394MediaParams.Destination.FifoAddress.Off_High ) ); TRACE( TL_I, TM_Cm, ( "pVc's Offset Low %x",pVc->Hdr.Nic1394MediaParams.Destination.FifoAddress.Off_Low ) );
TRACE( TL_T, TM_Cm, ( "<==nicCmMakeCallInitRecvFIFOVc %x",NdisStatus ) );
MATCH_IRQL;
return NdisStatus;
}
NDIS_STATUS nicCmMakeCallInitSendFIFOVc( IN OUT PVCCB pVc )
/*++
Routine Description:
This initializes a Send Fifo Make Call. It i) finds the remote node using the make call parameters ii) inititalizes strcutures
Arguments: pVc - Vc that the make call is done on.
Return Value:
--*/ //
{
PSENDFIFO_VCCB pSendFIFOVc = (PSENDFIFO_VCCB) pVc; NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS; UINT Generation = 0; PREMOTE_NODE pRemoteNode = NULL; PADAPTERCB pAdapter = pSendFIFOVc->Hdr.pAF->pAdapter; PNIC1394_MEDIA_PARAMETERS pN1394Params = NULL; UINT64 UniqueId = 0; PNIC1394_FIFO_ADDRESS pFifoAddress = NULL; ULONG Speed; ULONG MaxBufferSize; ULONG RemoteMaxRec; BOOLEAN fDeRefRemoteNode = FALSE;
STORE_CURRENT_IRQL; TRACE( TL_T, TM_Cm, ( "==>NicCmMakeCallInitSendFIFOVc pSendFIFOVc %x", pSendFIFOVc ) ); pN1394Params = (PNIC1394_MEDIA_PARAMETERS)&pVc->Hdr.pCallParameters->MediaParameters->MediaSpecific.Parameters[0]; ASSERT (pN1394Params->Destination.AddressType == NIC1394AddressType_FIFO);
pFifoAddress = &pN1394Params->Destination.FifoAddress;
UniqueId = pFifoAddress->UniqueID;
TRACE( TL_V, TM_Cm, ( "FifoAddress %x, UniqueId %I64x, Hi %.4x, Lo %x", pFifoAddress, pFifoAddress->UniqueID, pFifoAddress->Off_High, pFifoAddress->Off_Low ) );
do {
//
// Get the Pdo that corresponds with the UniqueId
//
ASSERT(pSendFIFOVc->Hdr.pAF->pAdapter != NULL);
NdisStatus = nicFindRemoteNodeFromAdapter( pSendFIFOVc->Hdr.pAF->pAdapter, NULL, UniqueId, &pRemoteNode); if(NdisStatus != NDIS_STATUS_SUCCESS) { TRACE( TL_A, TM_Cm, ( "Unable to Find Pdo, call FAILED ,pSendFIFOVc is %x, UniqueId %I64x ", pSendFIFOVc, UniqueId ) );
break; } ASSERT (pRemoteNode != NULL); //
// nicFindRemoteNodeFromAdapter ref's pRemoteNode on success.
// We need to deref it if we're not going to be using it.
// Let's start by assuming we aren't.
//
fDeRefRemoteNode = TRUE;
//
// Get the Generation Count of the device
//
NdisStatus = nicGetGenerationCount ( pRemoteNode->pAdapter, &Generation);
if(NdisStatus != NDIS_STATUS_SUCCESS) { TRACE( TL_A, TM_Cm, ( "GET GENERATION FAILED ,pSendFIFOVc is %x", pSendFIFOVc ) );
ASSERT(NdisStatus == NDIS_STATUS_SUCCESS); break; }
TRACE( TL_V, TM_Cm, ( "Found PdoCb %x for pSendFIFOVc %x", pRemoteNode,pSendFIFOVc ) );
//
// We check if the remote node's pdo is active. if so, then insert the Vc into the
// PdoCb's list. Now responsibility for any removals has moved to the remove remote node code path
//
//
// Get the max buffer size that can be transmitted on this link
//
NdisStatus = nicQueryRemoteNodeCaps (pAdapter, pRemoteNode, // FALSE, // FALSE== not from cache.
&Speed, &MaxBufferSize, &RemoteMaxRec); if (NdisStatus != NDIS_STATUS_SUCCESS) { break; }
ADAPTER_ACQUIRE_LOCK (pAdapter);
if (REMOTE_NODE_ACTIVE (pRemoteNode) == FALSE) { NdisStatus = NDIS_STATUS_DEST_OUT_OF_ORDER;
ADAPTER_RELEASE_LOCK (pAdapter);
break; }
//
// Reference the call in the Vc as the RemoteNodePdo is about to have a pointer to it., This is dereferenced
// in the CloseCallComplete Send Fifo Function. we have the lock
//
nicReferenceCall (pVc, "nicCmMakeCallInitSendFIFOVc");
//
// We keep the reference to pRemoteNode that was added by FindRemoteNode.
// Derefed in SendFifoCloseCall when the pointer is nulled
//
fDeRefRemoteNode = FALSE;
//
// Insert the Vc into the Pdo's List
//
InsertTailList (&pRemoteNode->VcList, &pSendFIFOVc->Hdr.SinglePdoVcLink);
TRACE( TL_V, TM_Cm, ( "Inserted Vc %x into Pdo List %x ", pSendFIFOVc, pRemoteNode) );
//
// This is not protected by the lock, but we are gauranteed that the Call will not be closed
// and the Pdo will not be be removed from the system at this point, So we can update
// this field.
//
pSendFIFOVc->Hdr.pRemoteNode = pRemoteNode;
ADAPTER_RELEASE_LOCK (pAdapter);
//
// Acquire the spin lock and initialize the structures
//
VC_ACQUIRE_LOCK (pSendFIFOVc);
pSendFIFOVc->Hdr.MTU = pN1394Params->MTU;
pSendFIFOVc->Hdr.pGeneration = &pAdapter->Generation;
pSendFIFOVc->FifoAddress = pN1394Params->Destination.FifoAddress;
pSendFIFOVc->MaxSendSpeed = pN1394Params->MaxSendSpeed;
pSendFIFOVc->Hdr.MaxPayload = min (pN1394Params->MTU, (ULONG)pN1394Params->MaxSendBlockSize);
VC_RELEASE_LOCK (pSendFIFOVc);
//
// Validate the parameters for the Vc
//
ASSERT(pSendFIFOVc->Hdr.pRemoteNode != NULL); ASSERT(pSendFIFOVc->Hdr.pRemoteNode->pPdo != NULL); ASSERT(pSendFIFOVc->Hdr.pGeneration != NULL); ASSERT(pSendFIFOVc->MaxSendSpeed != 0); ASSERT(pSendFIFOVc->Hdr.MTU != 0);
TRACE( TL_V, TM_Cm, ( " Generation is %x", *pSendFIFOVc->Hdr.pGeneration ) ); TRACE( TL_N, TM_Cm, ( " Pdo in the Send VC is %x", pSendFIFOVc->Hdr.pRemoteNode->pPdo) );
if (NdisStatus != NDIS_STATUS_SUCCESS) { break; }
pSendFIFOVc->MaxSendSpeed = min(pSendFIFOVc->MaxSendSpeed,Speed); pSendFIFOVc->Hdr.MaxPayload = min (pSendFIFOVc->Hdr.MaxPayload, MaxBufferSize);
#ifdef LOWER_SEND_SPEED
pSendFIFOVc->MaxSendSpeed = SCODE_200_RATE;//min(pSendFIFOVc->MaxSendSpeed,Speed);
pSendFIFOVc->Hdr.MaxPayload = ASYNC_PAYLOAD_200_RATE ;// min(pSendFIFOVc->Hdr.MaxPayload, MaxBufferSize);
#endif
TRACE( TL_V, TM_Cm, ( " MaxSendSpeed is %x", pSendFIFOVc->MaxSendSpeed) ); TRACE( TL_V, TM_Cm, ( " MaxPayload is %d", pSendFIFOVc->Hdr.MaxPayload ) );
} while (FALSE);
if ( NdisStatus != NDIS_STATUS_SUCCESS) { //
// The Make is going to be failed asynchrnously
// If we allocated in resources, we must free them
// In this case, there have been no Resources allocated
//
}
TRACE( TL_I, TM_Cm, ( " pVc's Offset High %4x",pVc->Hdr.Nic1394MediaParams.Destination.FifoAddress.Off_High ) ); TRACE( TL_I, TM_Cm, ( " pVc's Offset Low %x",pVc->Hdr.Nic1394MediaParams.Destination.FifoAddress.Off_Low ) );
TRACE( TL_T, TM_Cm, ( "<==NicCmMakeCallInitSendFIFOVc %x",NdisStatus ) );
if (fDeRefRemoteNode) { nicDereferenceRemoteNode (pRemoteNode, FindRemoteNodeFromAdapterFail); }
MATCH_IRQL; return NdisStatus;
}
NDIS_STATUS nicCmMakeCallInitSendRecvChannelVc( IN OUT PVCCB pVc ) // Function Description:
//
// Arguments
// pVc, This is the send fifo that needs to be initilaized
//
//
// Return Value:
//
// Success if the irps sent to the driver succeed
//
//
{
PCHANNEL_VCCB pChannelVc = (PCHANNEL_VCCB)pVc; NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; PNIC1394_MEDIA_PARAMETERS pN1394Params = NULL; PADAPTERCB pAdapter = pVc->Hdr.pAF->pAdapter; ULONG Channel = 64; HANDLE hResource=NULL; ULONG MaxBufferSize = 0; ULONG QuadletsToStrip = 0; PISOCH_DESCRIPTOR pIsochDescriptor = NULL; CYCLE_TIME CycleTime; PDEVICE_OBJECT ArrayRemotePDO[64]; //NDIS_HANDLE hPacketPoolHandle=NULL;
BOOLEAN fAnyChannel = FALSE; NIC_PACKET_POOL PacketPool; STORE_CURRENT_IRQL; TRACE( TL_T, TM_Cm, ( "==>NicCmMakeCallInitSendRecvChannelVc pVc %x", pVc ) );
ASSERT (pAdapter != NULL);
pN1394Params = (PNIC1394_MEDIA_PARAMETERS)&pVc->Hdr.pCallParameters->MediaParameters->MediaSpecific.Parameters[0];
Channel = pN1394Params->Destination.Channel;
TRACE( TL_V, TM_Cm, ( "Channel %x", Channel ) );
do { PacketPool.Handle = NULL; ADAPTER_ACQUIRE_LOCK( pAdapter );
//
// Set up the the VDO, so that all channel operations can use it
//
pVc->Hdr.pLocalHostVDO = pAdapter->pNextDeviceObject;
ADAPTER_RELEASE_LOCK( pAdapter );
NdisAllocatePacketPoolEx ( &NdisStatus, &PacketPool.Handle, MIN_PACKET_POOL_SIZE, MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE, sizeof (RSVD) ); if (PacketPool.Handle == NULL || NdisStatus != NDIS_STATUS_SUCCESS) { BREAK (TM_Cm, ( "NdisAllocatePacketPoolEx FAILED" ) ); }
//
// Reference Call for Packet Pool Handle
//
nicReferenceCall ((PVCCB)pChannelVc, "nicCmMakeCallInitSendRecvChannelVc - packet pool ");
PacketPool.AllocatedPackets = 0; pChannelVc->Hdr.MTU = pN1394Params->MTU; pChannelVc->PacketPool= PacketPool; NdisInitializeEvent(&pChannelVc->LastDescReturned);
//
// This function should do its own cleanup
//
NdisStatus = nicAllocateChannelResourcesAndListen (pAdapter, pChannelVc );
if (NdisStatus != NDIS_STATUS_SUCCESS) { BREAK (TM_Cm, ( "nicAllocateChannelResourcesAndListen FAILED" ) ); } //
// Return the allocated channel number, if this is an any channel
// or broadcast channel call
//
if ((pN1394Params->Destination.Channel == NIC1394_ANY_CHANNEL) && (pN1394Params->Destination.AddressType == NIC1394AddressType_Channel)) { pN1394Params->Destination.Channel = pChannelVc->Channel; }
//
// Make the same change for broadcast channels
//
if ((pN1394Params->Destination.Channel == NIC1394_BROADCAST_CHANNEL) && (pN1394Params->Destination.AddressType == NIC1394AddressType_Channel)) { pN1394Params->Destination.Channel = pChannelVc->Channel; }
} while (FALSE); //
// Time to do clean up based on what resources were allocated
//
if (NdisStatus != NDIS_STATUS_SUCCESS ) { //Undo all resources acquired
if (PacketPool.Handle != NULL) { //
// Free the pool
//
nicFreePacketPool(&PacketPool);
nicDereferenceCall ((PVCCB)pChannelVc, "nicCmMakeCallInitSendRecvChannelVc - packet pool ");
NdisZeroMemory (&pChannelVc->PacketPool, sizeof (pChannelVc->PacketPool)); }
//
// Do not decrement any ref counts because if Status != success
// then we have not incremented refcounts.
//
}
TRACE( TL_T, TM_Cm, ( "<==NicCmMakeCallInitSendRecvChannelVc %x", NdisStatus) );
return NdisStatus; }
NDIS_STATUS nicCmMakeCallInitEthernet ( IN PVCCB pVc ) /*++
Routine Description: Do nothing for now. Just succeed
Arguments:
Return Value:
--*/ {
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; PADAPTERCB pAdapter = pVc->Hdr.pAF->pAdapter; PETHERNET_VCCB pEthernetVc = (PETHERNET_VCCB)pVc; NIC_PACKET_POOL PacketPool; TRACE( TL_T, TM_Cm, ( "==>nicCmMakeCallInitEthernet %x", pVc) );
do { PacketPool.Handle = NULL; //
// Initialize the PacketPool
//
NdisAllocatePacketPoolEx ( &NdisStatus, &PacketPool.Handle, MIN_PACKET_POOL_SIZE, MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE, sizeof (RSVD) ); if (NdisStatus!= NDIS_STATUS_SUCCESS) { ASSERT(NdisStatus != NDIS_STATUS_SUCCESS); pEthernetVc->PacketPool.Handle = NULL; PacketPool.Handle = NULL; break; }
NdisStatus = NDIS_STATUS_SUCCESS; //
// No more failures
//
nicReferenceCall ((PVCCB)pEthernetVc, "Alloc PacketPool - Ethernet VC " ) ; ADAPTER_ACQUIRE_LOCK (pAdapter);
//
// Reference the VC as the adapter has a pointer to it
//
nicReferenceCall (pVc, "nicCmMakeCallEthernet ");
pAdapter->pEthernetVc = (PETHERNET_VCCB)pVc;
pEthernetVc->PacketPool= PacketPool; pEthernetVc->PacketPool.AllocatedPackets = 0;
ADAPTER_RELEASE_LOCK (pAdapter);
} while (FALSE);
if (NdisStatus != NDIS_STATUS_SUCCESS) { if (PacketPool.Handle != NULL) { //
// Free the pool
//
nicFreePacketPool(&PacketPool);
} }
TRACE( TL_T, TM_Cm, ( "<==nicCmMakeCallEthernet %x", NdisStatus) ); return NdisStatus;
}
NDIS_STATUS nicCmMakeCallMultiChannel ( IN PVCCB pVc ) /*++
Routine Description: Do whatever the channel Vc does
Arguments:
Return Value:
--*/ {
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; PADAPTERCB pAdapter = pVc->Hdr.pAF->pAdapter; PCHANNEL_VCCB pMcVc = (PCHANNEL_VCCB)pVc; NIC_PACKET_POOL PacketPool; TRACE( TL_T, TM_Cm, ( "==>nicCmMakeCallMultiChannel %x", pVc) );
do { PacketPool.Handle = NULL;
//
// Initialize the PacketPool
//
NdisAllocatePacketPoolEx ( &NdisStatus, &PacketPool.Handle, MIN_PACKET_POOL_SIZE, MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE, sizeof (RSVD) ); if (NdisStatus!= NDIS_STATUS_SUCCESS) { ASSERT(NdisStatus != NDIS_STATUS_SUCCESS); pMcVc->PacketPool.Handle = NULL; break; }
NdisStatus = NDIS_STATUS_SUCCESS; //
// No more failures
//
nicReferenceCall ((PVCCB)pMcVc, "Alloc PacketPool - MultiChannel VC " ) ; ADAPTER_ACQUIRE_LOCK (pAdapter);
pMcVc->PacketPool= PacketPool; pMcVc->PacketPool.AllocatedPackets = 0;
pMcVc->Hdr.MTU = pMcVc->Hdr.Nic1394MediaParams.MTU;
ADAPTER_RELEASE_LOCK (pAdapter);
if (pMcVc->Hdr.Nic1394MediaParams.Destination.ChannnelMap.QuadPart == 0) {
pMcVc->Channel = 0xff; NdisStatus = NDIS_STATUS_SUCCESS; break; }
//
// This portion Not Implemented yet. ChannelMap != 0
// Should use nicAllocateResourcesAndListen after updating the
// Nic1394MediaParams to make it look like a regular ChannelMake Call
//
NdisStatus = NDIS_STATUS_FAILURE; ASSERT (0); } while (FALSE);
if (NdisStatus != NDIS_STATUS_SUCCESS) { if (PacketPool.Handle != NULL) { //
// Free the pool
//
nicFreePacketPool(&PacketPool);
} }
TRACE( TL_T, TM_Cm, ( "<==nicCmMakeCallMultiChannel %x", NdisStatus) ); return NdisStatus;
}
NDIS_STATUS nicCmMakeCallSendChannel ( IN PVCCB pVc ) /*++
Routine Description: This function allocates the channel but does nothing else. It is only used to send data and therefore needs no other data
It needs to update pChannelVc->Channel; ulSynch; Speed; all of which are needed to do an AsyncStream Irb
Arguments:
Return Value:
--*/ { NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; PCHANNEL_VCCB pChannelVc = (PCHANNEL_VCCB)pVc; BOOLEAN fNeedToAllocate = VC_TEST_FLAG (pChannelVc, VCBF_NeedsToAllocateChannel); PADAPTERCB pAdapter = pVc->Hdr.pAF->pAdapter; ULONG Speed = 0; UINT MaxPacketSize = 0; PNIC1394_MEDIA_PARAMETERS pN1394Params = (PNIC1394_MEDIA_PARAMETERS)&pChannelVc->Hdr.Nic1394MediaParams; ULONG Channel = pN1394Params->Destination.Channel; TRACE( TL_T, TM_Cm, ( "==>nicCmMakeCallSendChannel pVc %x", pVc) );
do {
//
// Allocate the channel
//
if (fNeedToAllocate == TRUE) { NdisStatus = nicAllocateRequestedChannelMakeCallComplete (pAdapter, pChannelVc, &Channel); if (NdisStatus != NDIS_STATUS_SUCCESS) { BREAK (TM_Cm, ("Unable to allocate Channel on Send Only Vc" ) ); }
}
//
// Find out the Speed.
//
if (pAdapter->Speed == 0) { nicUpdateLocalHostSpeed (pAdapter); }
pChannelVc->Speed = pAdapter->Speed;
Speed = pAdapter->Speed; switch (pChannelVc->Speed) { case SPEED_FLAGS_100 : { pChannelVc->Hdr.MaxPayload = ISOCH_PAYLOAD_100_RATE; break; } case SPEED_FLAGS_200 : { pChannelVc->Hdr.MaxPayload = ISOCH_PAYLOAD_200_RATE ; break; } case SPEED_FLAGS_400 : { pChannelVc->Hdr.MaxPayload = ISOCH_PAYLOAD_400_RATE; break; }
case SPEED_FLAGS_800: { pChannelVc->Hdr.MaxPayload = ISOCH_PAYLOAD_400_RATE; break; }
case SPEED_FLAGS_1600: { pChannelVc->Hdr.MaxPayload = ISOCH_PAYLOAD_400_RATE; break; }
case SPEED_FLAGS_3200 : { pChannelVc->Hdr.MaxPayload = ISOCH_PAYLOAD_400_RATE; break; }
default : { pChannelVc->Hdr.MaxPayload = ISOCH_PAYLOAD_400_RATE; break; }
}
pChannelVc->Channel = Channel ;
MaxPacketSize = min(pN1394Params->MTU + sizeof(GASP_HEADER) , pChannelVc->Hdr.MaxPayload);
//
// If broadcast channel, then decrease the speed setting, and fragment
//
pChannelVc->Channel = Channel; pChannelVc->MaxBufferSize = 0; pChannelVc->Speed = Speed;
pChannelVc->Hdr.MaxPayload = MaxPacketSize; pChannelVc->Hdr.MTU = pN1394Params->MTU ;
pChannelVc->NumDescriptors = 0; pChannelVc->pIsochDescriptor = NULL;
NdisStatus = NDIS_STATUS_SUCCESS;
} while (FALSE);
TRACE( TL_T, TM_Cm, ( "<==nicCmMakeCallSendChannel %x", NdisStatus) );
return NdisStatus; }
VOID nicCmMakeCallCompleteFailureCleanUp( IN OUT PVCCB pVc )
// Function Description:
// This function cleans up, if the makecallcomplete fails for whatever reason.
// Maybe this should be split up as well
// In the RecvFIFOVc case: it needs to deallocate the Slist and PacketPool,
// Common:
// Also delete the VcType and nic1394 destination in the Vc Hdr
// Arguments
// PVCCB pVc - Vc that needs to be cleaned up
//
// Return Value:
//
//
{
STORE_CURRENT_IRQL; TRACE( TL_T, TM_Cm, ( "==>nicCmMakeCallCompleteFailureCleanUp pVc %x", pVc ) ); switch (pVc->Hdr.VcType) {
case NIC1394_RecvFIFO: { PRECVFIFO_VCCB pRecvFIFOVc = (PRECVFIFO_VCCB )pVc;
TRACE( TL_V, TM_Cm, ( "Cleaning up a recv FIFo %x", pVc ) );
if (pRecvFIFOVc->PacketPool.Handle != NULL) { nicFreePacketPool (&pRecvFIFOVc->PacketPool); } pRecvFIFOVc->PacketPool.Handle = NULL;
if (pRecvFIFOVc->FifoSListHead.Alignment != 0) { nicFreeAllocateAddressRangeSList (pRecvFIFOVc); }
pRecvFIFOVc->FifoSListHead.Alignment = 0; break; }
case NIC1394_SendFIFO: case NIC1394_SendRecvChannel: case NIC1394_SendChannel: case NIC1394_RecvChannel:
default: break; }
//
// This call does the generic clean up
//
nicCmGenrericMakeCallFailure (pVc);
TRACE( TL_T, TM_Cm, ( "<==nicCmMakeCallCompleteFailureCleanUp ") );
MATCH_IRQL; return ; }
NDIS_STATUS NicCmCloseCall( IN NDIS_HANDLE CallMgrVcContext, IN NDIS_HANDLE CallMgrPartyContext, IN PVOID CloseData, IN UINT Size )
// Standard 'CmCloseCallHandler' routine called by NDIS when the a client
// has requested to tear down a call. See DDK doc.
//
{ NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; ADAPTERCB* pAdapter = NULL; VCCB* pVc = NULL; NDIS_WORK_ITEM* pCloseCallCompleteWorkItem = NULL;
STORE_CURRENT_IRQL; TRACE( TL_T, TM_Cm, ( "==>NicCmCloseCall($%p)", CallMgrVcContext ) );
pVc = (VCCB* )CallMgrVcContext;
if (pVc->Hdr.ulTag != MTAG_VCCB) { ASSERT( !"Vtag?" ); return NDIS_STATUS_INVALID_DATA; }
do { pAdapter = pVc->Hdr.pAF->pAdapter;
if (pAdapter == NULL) { TRACE( TL_A, TM_Cm, ( "pAdpater is NULL - Make Call FAILED($%p)", CallMgrVcContext ) ); NdisStatus = NDIS_STATUS_FAILURE; break; }
VC_ACQUIRE_LOCK (pVc);
//
// If the Make Call is Pending, then fail the CloseCall.
// Or if there call is already closing then fail this close call
//
if ( VC_ACTIVE (pVc) == FALSE ) { TRACE( TL_A, TM_Cm, ( "NicCmCloseCall Invalid flags - Close Call FAILED Vc $%p, flags %x", pVc, pVc->Hdr.ulFlags ) );
ASSERT ( ! "MakeCallPending or Call already closed?");
VC_RELEASE_LOCK (pVc); break; }
//
//
// Reference the Vc so we can gaurantee its presence till the end of the work item
// to CloseCallComplete. we have the lock
//
nicReferenceVc (pVc);
//
// Mark the Call as closing, and close the refcount, so no one can increment it
//
VC_SET_FLAG ( pVc, VCBF_CloseCallPending);
nicCloseCallRef (pVc);
VC_RELEASE_LOCK (pVc);
pCloseCallCompleteWorkItem = ALLOC_NONPAGED (sizeof(NDIS_WORK_ITEM), MTAG_WORKITEM);
if (pCloseCallCompleteWorkItem == NULL) { TRACE( TL_A, TM_Cm, ( "Local Alloc failed for WorkItem - Close Call FAILED($%p)", CallMgrVcContext ) ); NdisStatus = NDIS_STATUS_RESOURCES;
break; } NdisInitializeWorkItem ( pCloseCallCompleteWorkItem, (NDIS_PROC)nicCmCloseCallComplete, (PVOID)pVc );
NdisInterlockedIncrement(&pAdapter->OutstandingWorkItems);
NdisScheduleWorkItem (pCloseCallCompleteWorkItem);
NdisStatus = NDIS_STATUS_PENDING;
} while (FALSE); MATCH_IRQL; TRACE( TL_T, TM_Cm, ( "<==NicCmCloseCall pending" ) );
return NdisStatus; }
VOID nicCmCloseCallComplete( NDIS_WORK_ITEM* pCloseCallCompleteWorkItem, IN PVOID Context ) // Function Description:
// This function completes the close call. The qor Item gaurantees that all work will be
// done at passive level
//
// Arguments
// Context : Which is VCCB for which the close call was requested
//
//
// Return Value:
// None
// However an NdisStatus is passed in the call to Ndis' close call complete function
//
//
{ NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; PVCCB pVc = (PVCCB) Context; PADAPTERCB pAdapter = pVc->Hdr.pAF->pAdapter; BOOLEAN fCallClosable = FALSE; BOOLEAN fWaitSucceeded = FALSE;
STORE_CURRENT_IRQL;
TRACE( TL_T, TM_Cm, ( "==>nicCmCloseCallComplete pVc %x", pVc ) );
//
// Invoke the close call handler of the VC
//
ASSERT (pVc->Hdr.VcHandlers.CloseCallHandler != NULL); NdisStatus = (*pVc->Hdr.VcHandlers.CloseCallHandler) (pVc); //
// right now, we do not fail a close call because the bus driver failed us.
//
NdisStatus = NDIS_STATUS_SUCCESS; //
// Made it so far, we now need to dereference the call. We made the reference in
// MakeCall. This will complete the call if it gets down to zero
//
if (NdisStatus == NDIS_STATUS_SUCCESS) { //
// Derefercence the call ref and Vc Refs that were added at the end of
// a successful make call
//
nicDereferenceCall (pVc, "nicCmCloseCallComplete");
}
//
// Important : THIS WAIT is for the REFCOUNT on the CALL , not the VC
//
TRACE( TL_N, TM_Cm, ( "About to Wait for CallRefs to go to zero pVc %x ", pVc) );
fWaitSucceeded = NdisWaitEvent (&pVc->Hdr.CallRef.RefZeroEvent, WAIT_INFINITE );
if (fWaitSucceeded == FALSE) { TRACE( TL_A, TM_Cm, ( "Wait Timed Out Call, Vc %x, RefCount %x ", pVc , pVc->Hdr.CallRef.ReferenceCount) );
ASSERT (fWaitSucceeded == TRUE); }
ASSERT (KeGetCurrentIrql() <= DISPATCH_LEVEL); //
// Succeed the Close call as all references have gone to zero
// The call has no more outstanding resources
//
TRACE( TL_N, TM_Cm, ( "About to Close Call on pVc %x", pVc ) );
NdisMCmCloseCallComplete( NDIS_STATUS_SUCCESS, pVc->Hdr.NdisVcHandle, NULL );
VC_ACQUIRE_LOCK (pVc);
VC_CLEAR_FLAGS (pVc, VCBF_CloseCallPending); VC_SET_FLAG (pVc, VCBF_CloseCallCompleted);
VC_RELEASE_LOCK (pVc);
FREE_NONPAGED (pCloseCallCompleteWorkItem); NdisInterlockedDecrement(&pAdapter->OutstandingWorkItems);
//
// Release the reference made when entering the Close Call function above. so the Vc can disappear if it wants to
// Remember that delete Vc can already have gone through at this time, and the Vc will be freed after the deref
//
nicDereferenceVc (pVc);
TRACE( TL_T, TM_Cm, ( "<==nicCmCloseCallComplete pVc %x, Status %x", pVc, NdisStatus ) );
MATCH_IRQL; }
NDIS_STATUS nicCmCloseCallEthernet ( IN PVCCB pVc ) /*++
Routine Description: Do nothing for now. Just succeed
Arguments:
Return Value:
--*/ {
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; PADAPTERCB pAdapter = pVc->Hdr.pAF->pAdapter; PETHERNET_VCCB pEthernetVc = (PETHERNET_VCCB)pVc; NIC_PACKET_POOL PacketPool;
TRACE( TL_T, TM_Cm, ( "==>nicCmCloseCallEthernet %x", pVc) );
ADAPTER_ACQUIRE_LOCK (pAdapter); PacketPool = pEthernetVc->PacketPool;
pEthernetVc->PacketPool.Handle = 0; pEthernetVc->PacketPool.AllocatedPackets = 0; ADAPTER_RELEASE_LOCK (pAdapter);
if (PacketPool.Handle != NULL) { nicDereferenceCall ((PVCCB)pEthernetVc, "pEthernetVc - Free PacketPool" ); nicFreePacketPool (&PacketPool);
}
ADAPTER_ACQUIRE_LOCK (pAdapter);
//
// Dereference the VC as the adapter's pointer has been cleared
//
nicDereferenceCall (pVc, "nicCmMakeCallEthernet ");
pAdapter->pEthernetVc = NULL; ADAPTER_RELEASE_LOCK (pAdapter);
NdisStatus = NDIS_STATUS_SUCCESS; TRACE( TL_T, TM_Cm, ( "<==nicCmCloseCallEthernet %x", NdisStatus) ); return NdisStatus;
}
NDIS_STATUS nicCmCloseCallMultiChannel ( IN PVCCB pVc ) /*++
Routine Description: Free the packet pool and Just succeed
Arguments:
Return Value:
--*/ {
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; PADAPTERCB pAdapter = pVc->Hdr.pAF->pAdapter; PCHANNEL_VCCB pMcVc = (PCHANNEL_VCCB)pVc; NIC_PACKET_POOL PacketPool; TRACE( TL_T, TM_Cm, ( "==>nicCmCloseCallMultiChannel %x", pVc) );
ASSERT (VC_TEST_FLAG (pVc, VCBF_BroadcastVc) == FALSE);
//
// Mask the fact that this is a multichannel Call
//
NdisStatus = nicCmCloseCallSendRecvChannel (pVc);
//
// Nothing to fail
//
NdisStatus = NDIS_STATUS_SUCCESS;
TRACE( TL_T, TM_Cm, ( "<==nicCmCloseCallMultiChannel %x", NdisStatus) ); return NdisStatus;
}
NDIS_STATUS nicCmCloseCallSendRecvChannel ( IN PVCCB pVc ) // Function Description:
// This function will do clean up for RecvFifos
// Includes removing the VC pointer from Pdo Adapter structure.
// And needs to go through all active remote nodes and free the address ranges on them
// The BCM Vc has the added overhead of having an address range associated with it.
// which we need to free
//
// Arguments
// PVCCB pVc - The Channel VC that needs to be closed
//
// Return Value:
// Success for now
//
// Called with the lock held
{ PCHANNEL_VCCB pChannelVc = (PCHANNEL_VCCB ) pVc; PCHANNEL_VCCB pTempVc = NULL; BOOLEAN fIsBroadcastVc = FALSE; PLIST_ENTRY pVcListEntry = NULL; PADAPTERCB pAdapter = NULL; ULONG NumDereferenced ; HANDLE hResource ; ULONG NumDescriptors ; PISOCH_DESCRIPTOR pIsochDescriptor; BOOLEAN fAllocatedChannel ; ULONG Channel ; NIC_PACKET_POOL PacketPool;
STORE_CURRENT_IRQL;
TRACE( TL_T, TM_Cm, ( "==> nicCmCloseCallSendRecvChannel pVc %x", pVc) );
ASSERT (pVc!=NULL); pAdapter = pChannelVc->Hdr.pAF->pAdapter; ASSERT (pAdapter != NULL); do {
VC_ACQUIRE_LOCK (pChannelVc);
if (VC_TEST_FLAG (pChannelVc, VCBF_BroadcastVc) == TRUE) { PADDRESS_RANGE_CONTEXT pBCRAddress = &pAdapter->BCRData.AddressRangeContext; //
// Free the allocated address renge for the Broadcast Channel Register
//
if ( BCR_TEST_FLAG (pAdapter, BCR_Initialized) == TRUE) {
//
// Clear out the Broadcast VC in the BCRData structure, Derereference the call. and clear the flag
// The ref was made in the MakeCallAllocateChannel function
//
if (pAdapter->BCRData.pBroadcastChanneVc != NULL) { pAdapter->BCRData.pBroadcastChanneVc = NULL;
nicDereferenceCall((PVCCB) pChannelVc, "nicCmCloseCallSendRecvChannel Broadcast VC"); } VC_CLEAR_FLAGS (pChannelVc, VCBF_BroadcastVc) ; }
} VC_RELEASE_LOCK (pChannelVc); nicIsochStop (pAdapter, pChannelVc->hResource);
VC_ACQUIRE_LOCK (pChannelVc); PacketPool = pChannelVc->PacketPool;
hResource = pChannelVc->hResource;
NumDescriptors = pChannelVc->NumDescriptors;
pIsochDescriptor = pChannelVc->pIsochDescriptor;
fAllocatedChannel = VC_TEST_FLAGS( pChannelVc, VCBF_AllocatedChannel);
Channel = pChannelVc->Channel;
PacketPool = pChannelVc->PacketPool;
//
// Clean out the VC structure and then call NDIS or the bus driver to free all
// the resources
//
nicChannelCallCleanDataStructure (pChannelVc, pChannelVc->hResource, pChannelVc->NumDescriptors, pChannelVc->pIsochDescriptor, fAllocatedChannel, pChannelVc->Channel, pChannelVc->PacketPool.Handle, &NumDereferenced );
VC_RELEASE_LOCK (pChannelVc);
nicChannelCallFreeResources ( pChannelVc, pAdapter, hResource, NumDescriptors, pIsochDescriptor, fAllocatedChannel, Channel, &PacketPool); } while (FALSE);
TRACE( TL_T, TM_Cm, ( "<== nicCmCloseCallSendRecvChannel Status %x(always success)" ) ); MATCH_IRQL; return NDIS_STATUS_SUCCESS;
}
NDIS_STATUS nicCmCloseCallRecvFIFO ( IN PVCCB pVc ) // Function Description:
// This function will do clean up for RecvFifos
// Includes removing the VC pointer from Pdo Adapter structure.
// And needs to go through all active remote nodes and free the address ranges on them
//
//
// Arguments
// PVCCB pVc - The SendFifo that needs to be closed
//
// Return Value:
// Success for now
//
{ NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; PRECVFIFO_VCCB pRecvFIFOVc = (PRECVFIFO_VCCB)pVc; PADDRESS_FIFO pAddressFifo = NULL; PSINGLE_LIST_ENTRY pAddressFifoEntry = NULL; PADAPTERCB pAdapter = pVc->Hdr.pAF->pAdapter;
TRACE( TL_T, TM_Cm, ( "==> nicCmCloseCallRecvFIFO pVc %x", pVc) );
NdisStatus = nicFreeAddressRange( pAdapter, pRecvFIFOVc->AddressesReturned, &pRecvFIFOVc->VcAddressRange, &pRecvFIFOVc->hAddressRange );
if (NdisStatus != NDIS_STATUS_SUCCESS) { TRACE( TL_I, TM_Cm, ( "Call to Free Address Range Failed pVc at %x",pVc ) );
ASSERT (NdisStatus == NDIS_STATUS_SUCCESS);
//
// Do not Break. Continue
//
NdisStatus = NDIS_STATUS_SUCCESS; }
pRecvFIFOVc->hAddressRange = NULL; pRecvFIFOVc->AddressesReturned = 0; pRecvFIFOVc->VcAddressRange.AR_Off_High = 0; pRecvFIFOVc->VcAddressRange.AR_Off_Low = 0;
nicDereferenceCall ((PVCCB)pRecvFIFOVc, "nicCmCloseCallRecvFIFO - Free address range" );
nicFreePacketPool (&pRecvFIFOVc->PacketPool);
//
// Free the Slist Entries (AddressFifo, Mdl's) and their associated memory
// and decrease the refcount for each entry
//
nicFreeAllocateAddressRangeSList (pRecvFIFOVc);
//
// At this point all the resources of the call have been exhuasted and we can del the pointer in the adapter structure
//
VC_ACQUIRE_LOCK (pVc);
pVc->Hdr.pAF->pAdapter->pRecvFIFOVc = NULL;
VC_RELEASE_LOCK (pVc);
//
// Decrement the Vc Refcount as the adapter no longer has a pointer to it
//
nicDereferenceVc (pVc);
TRACE( TL_T, TM_Cm, ( "<== nicCmCloseCallRecvFIFO Status %x", NdisStatus) );
return NdisStatus; }
NDIS_STATUS nicCmCloseCallSendFIFO ( IN PVCCB pVc ) // Function Description:
// This function will do clean up for Send Fifos
// Includes removing the pointer to the Vc that is in Pdo Adapter structure.
// For the Send FIFO, the Pdo block is in the pVc->Hdr.pRemoteNode location, so
// this does not try and find the pRemoteNode
// Arguments
// PVCCB pVc - The SendFifo that needs to be closed
//
// Return Value:
// Success for now
//
{ NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; REMOTE_NODE * pRemoteNode = pVc->Hdr.pRemoteNode; PLIST_ENTRY pVcListEntry = NULL; PSENDFIFO_VCCB pTempVc = NULL; BOOLEAN fVcFound = FALSE; TRACE( TL_T, TM_Cm, ( "==> nicCmCloseCallSendFIFO pVc %x", pVc) );
//
// SendComplete Handler will complete the close call.
// This thread should not do it
// Called in nicFreeSendPacketDataStructures
//
//
// Go through the PdoCb structure and remove the VC from it's VC List
//
ASSERT (pRemoteNode != NULL);
VC_ACQUIRE_LOCK (pVc); for (pVcListEntry = pRemoteNode->VcList.Flink; pVcListEntry != &pRemoteNode->VcList; pVcListEntry = pVcListEntry->Flink) { pTempVc = (PSENDFIFO_VCCB) CONTAINING_RECORD (pVcListEntry, VCHDR, SinglePdoVcLink);
//
// Now remove the Vc from that linked list
//
if (pTempVc == (PSENDFIFO_VCCB) pVc ) {
nicRemoveEntryList (pVcListEntry); TRACE( TL_V, TM_Cm, ( "==> Removed Vc %x From Pdo's Vc List ", pVc) );
//
// Remove the reference from the Vc as the Pdo no longer
// has a pointer to it. This ref was made in MakeCallInitSendFifo
//
nicDereferenceCall (pVc, "nicCmCloseCallSendFIFO "); NdisStatus = NDIS_STATUS_SUCCESS; break; }
} //
// Decerement the Ref on the Pdo as the Vc no longer has a pointer to it.
// This Ref was made in MakeCallSendFifo function
//
nicDereferenceRemoteNode (pRemoteNode, FindRemoteNodeFromAdapter); //
// Null, it so that if we try to access this pointer, we bugcheck
//
pVc->Hdr.pRemoteNode = NULL;
VC_RELEASE_LOCK (pVc);
//
// There is no reason why we should not have found the Vc in the Pdo list
//
ASSERT (NdisStatus == NDIS_STATUS_SUCCESS);
TRACE( TL_T, TM_Cm, ( "<== nicCmCloseCallSendFIFO Status %x", NdisStatus) );
NdisStatus = NDIS_STATUS_SUCCESS; return NdisStatus; }
NDIS_STATUS nicCmCloseCallSendChannel( IN PVCCB pVc ) /*++
Routine Description:
Free the channel, if its been allocated Arguments:
Return Value:
--*/ { PADAPTERCB pAdapter = (PADAPTERCB) pVc->Hdr.pAF->pAdapter; PCHANNEL_VCCB pChannelVc = (PCHANNEL_VCCB)pVc;
TRACE( TL_T, TM_Cm, ( "==>nicCmCloseCallSendChannel " ) );
if (VC_TEST_FLAG (pVc,VCBF_AllocatedChannel) == TRUE) { nicFreeChannel (pAdapter, pChannelVc->Channel); nicDereferenceCall ((PVCCB)pChannelVc, "Close Call - Send Channel - Freeing Channel" ); } TRACE( TL_T, TM_Cm, ( "<==nicCmCloseCallSendChannel " ) ); return NDIS_STATUS_SUCCESS;
}
VOID nicChannelCallFreeResources ( IN PCHANNEL_VCCB pChannelVc, IN PADAPTERCB pAdapter, IN HANDLE hResource, IN ULONG NumDescriptors, IN PISOCH_DESCRIPTOR pIsochDescriptor, IN BOOLEAN fChannelAllocated, IN ULONG Channel, IN PNIC_PACKET_POOL pPacketPool ) // Function Description:
// This function is called from Close call or MakeCall Failure code path.
// It will detach buffers, free resources, free channel and free bandwdith.
// It is the responsibility of the caller to do all the appropriate ref counting
//
// Arguments
//
// pAdapter contains the VDO to which all the IRPs were sent
// hResource resource handle to be used by the bus driver,
// NumDescriptors Number of descriptors attached to the buffer,
// pIsochDesciptor Original pointer to the start of the Buffer Descriptor ,
// Channel, - Channel that was allocated
//
// Return Value:
// Success if all irps completed succeesfully. Wil be ignored by called
//
{ NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; STORE_CURRENT_IRQL; TRACE( TL_T, TM_Cm, ( "==>nicChannelCallFreeResources " ) ); TRACE( TL_V, TM_Cm, ( "hResource %x, NumDescriptors %.2x, pIsochDescriptor %x, Channel Allocated %.2x, Channel %x", hResource, NumDescriptors, pIsochDescriptor, fChannelAllocated, Channel ) )
//
// Reference the pdo structure so it will be around until the end
// of this function
// Reference decremented at the end of this function
//
ADAPTER_ACQUIRE_LOCK (pAdapter); nicReferenceAdapter (pAdapter, "nicChannelCallFreeResources "); ADAPTER_RELEASE_LOCK (pAdapter);
//
// Do not break out of the loop. We need to try and free as much as possible
//
if (pIsochDescriptor != NULL) { // Detach Buffers
//
while (pChannelVc->NumIndicatedIsochDesc != 0 ) { //
// we will wait for ever, checking periodically for all the packets to return
//
TRACE( TL_V, TM_Cm, ( " nicChannelCallFreeResources - Sleeping to wait for packets to be retuerned " ) ); NdisMSleep ( FIFTY_MILLISECONDS );
}
NdisStatus = nicIsochDetachBuffers( pAdapter, hResource, NumDescriptors, pIsochDescriptor ); if (NdisStatus != NDIS_STATUS_SUCCESS) { TRACE( TL_A, TM_Cm, ( "nicIsochDetachBuffers FAILED " ) ); ASSERT (NdisStatus == NDIS_STATUS_SUCCESS); }
// First Free Isoch Descriptors and their associated MDLs
//
nicFreeIsochDescriptors (NumDescriptors, pIsochDescriptor, (PVCCB)pChannelVc); }
if (hResource != NULL) {
// Free resources
//
NdisStatus = nicIsochFreeResources( pAdapter, hResource );
if (NdisStatus != NDIS_STATUS_SUCCESS) { TRACE( TL_A, TM_Cm, ( "nicIsochFreeResources FAILED " ) ); ASSERT (NdisStatus == NDIS_STATUS_SUCCESS); }
}
if (fChannelAllocated == TRUE) { PULONGLONG pLocalHostChannels = &pAdapter->ChannelsAllocatedByLocalHost; ASSERT (Channel < NIC1394_MAX_NUMBER_CHANNELS); // Free the Channel
//
NdisStatus = nicFreeChannel (pAdapter, Channel);
if (NdisStatus != NDIS_STATUS_SUCCESS) { TRACE( TL_A, TM_Cm, ( "nicIsochFreeChannel FAILED " ) ); ASSERT (NdisStatus == NDIS_STATUS_SUCCESS); }
//
// Clear the bit in the adapter;s channel bitmap
//
VC_ACQUIRE_LOCK (pChannelVc);
(*pLocalHostChannels)= ((*pLocalHostChannels) & (~(g_ullOne <<Channel)));
VC_CLEAR_FLAGS( pChannelVc, VCBF_AllocatedChannel);
VC_RELEASE_LOCK (pChannelVc);
}
if (pPacketPool->Handle != NULL) { nicFreePacketPool(pPacketPool); }
//
// Remove The Ref that was added in the beginning of the function
//
nicDereferenceAdapter (pAdapter, "nicChannelCallFreeResources ");
MATCH_IRQL;
TRACE( TL_T, TM_Cm, ( "<==nicChannelCallFreeResources " ) ); }
VOID nicChannelCallCleanDataStructure ( IN PCHANNEL_VCCB pChannelVc, IN HANDLE hResource, IN ULONG NumDescriptors, IN PISOCH_DESCRIPTOR pIsochDescriptor, IN BOOLEAN fChannelAllocated, IN ULONG Channel, IN NDIS_HANDLE hPacketPoolHandle, OUT PULONG pNumRefsDecremented ) // Function Description:
// If any of the data fields in the ChannelVc match the
// corresponding argument in this structure it will be
// NULLed out and the call dereferenced
//
// Called with the lock held.
//
// Arguments
// PCHANNEL_VCCB pChannelVc, - Channel Vc
// HANDLE hResource, - Handle to resource
// ULONG NumDescriptors, - Num descriptors will be set to zero
// PISOCH_DESCRIPTOR pIsochDesciptor, - Pointer to array of isoch descriptors
// BOOLEAN fChannelAllocated, - Was the Channel allocated
// ULONG Channel, - channel number
// NDIS_HANDLE hPacketPoolHandle - Packet pool handle
//
//
//
// Return Value:
//
//
//
//
{ NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; ULONG NumRefsDecremented = 0; TRACE( TL_T, TM_Cm, ( "==>nicChannelCallCleanDataStructure " ) );
TRACE( TL_V, TM_Cm, ( "hResource %x, NumDescriptors %.2x, pIsochDescriptor %x, Channel Allocated %.2x, Channel %x", hResource, NumDescriptors, pIsochDescriptor, fChannelAllocated, Channel ) )
if (pChannelVc == NULL) { return ; }
if ((pChannelVc->NumDescriptors == NumDescriptors )&& (pChannelVc->pIsochDescriptor == pIsochDescriptor ) && pIsochDescriptor != NULL ) { pChannelVc->NumDescriptors = 0; pChannelVc->pIsochDescriptor = NULL; nicDereferenceCall ((PVCCB)pChannelVc, "nicChannelCallCleanDataStructure Detach Buffers "); NumRefsDecremented ++; }
if (hResource != NULL && pChannelVc->hResource == hResource) { pChannelVc->hResource = NULL; nicDereferenceCall ((PVCCB)pChannelVc, "nicChannelCallCleanDataStructure Free Resource "); NumRefsDecremented ++; }
if (fChannelAllocated == TRUE) { ASSERT ( VC_TEST_FLAG (pChannelVc, VCBF_AllocatedChannel) == TRUE); VC_CLEAR_FLAGS (pChannelVc, VCBF_AllocatedChannel);
pChannelVc->Channel = INVALID_CHANNEL; nicDereferenceCall ((PVCCB)pChannelVc, "nicChannelCallCleanDataStructure - Free Channel"); NumRefsDecremented ++;
}
if (hPacketPoolHandle != NULL && pChannelVc->PacketPool.Handle == hPacketPoolHandle) { pChannelVc->PacketPool.Handle = NULL; nicDereferenceCall ((PVCCB)pChannelVc, "nicChannelCallCleanDataStructure - Packet Pool"); NumRefsDecremented ++; }
//REMOTE_NODE_RELEASE_LOCK (pRemoteNodePdoCb);
//
// Remove The Ref that was added in the beginning of the function
//
NdisStatus = NDIS_STATUS_SUCCESS;
if (pNumRefsDecremented != NULL) { *pNumRefsDecremented = NumRefsDecremented ; }
TRACE( TL_T, TM_Cm, ( "<==nicChannelCallCleanDataStructure %x", *pNumRefsDecremented ) ); }
NDIS_STATUS NicCmModifyCallQoS( IN NDIS_HANDLE CallMgrVcContext, IN PCO_CALL_PARAMETERS CallParameters )
// Standard 'CmModifyQoSCallHandler' routine called by NDIS when a client
// requests a modification in the quality of service provided by the
// virtual circuit. See DDK doc.
//
{ TRACE( TL_T, TM_Cm, ( "NicCmModQoS" ) );
// There is no useful concept of quality of service for IP media.
//
return NDIS_STATUS_NOT_SUPPORTED; }
NDIS_STATUS NicCmRequest( IN NDIS_HANDLE CallMgrAfContext, IN NDIS_HANDLE CallMgrVcContext, IN NDIS_HANDLE CallMgrPartyContext, IN OUT PNDIS_REQUEST pNdisRequest )
// Standard 'CmRequestHandler' routine called by NDIS in response to a
// client's request for information from the call manager.
//
{ AFCB* pAF; VCCB* pVc; NDIS_STATUS NdisStatus;
TRACE( TL_T, TM_Cm, ( "==>NicCmReq" ) );
pAF = (AFCB*) CallMgrAfContext;
if (pAF->ulTag != MTAG_AFCB ) { ASSERT( !"Atag?" ); return NDIS_STATUS_INVALID_DATA; }
pVc = (VCCB* )CallMgrVcContext;
if (pVc && pVc->Hdr.ulTag != MTAG_VCCB) { ASSERT( !"Vtag?" ); return NDIS_STATUS_INVALID_DATA; }
#if TODO // Add 1394-specific functionality here.
#endif
ASSERT(pNdisRequest != NULL); switch (pNdisRequest->RequestType) { case NdisRequestQueryStatistics: case NdisRequestQueryInformation:
{ NdisStatus = nicCmQueryInformation( CallMgrAfContext, CallMgrVcContext, CallMgrPartyContext, pNdisRequest->DATA.QUERY_INFORMATION.Oid, pNdisRequest->DATA.QUERY_INFORMATION.InformationBuffer, pNdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength, &pNdisRequest->DATA.QUERY_INFORMATION.BytesWritten, &pNdisRequest->DATA.QUERY_INFORMATION.BytesNeeded ); break; }
case NdisRequestSetInformation: { NdisStatus = nicCmSetInformation( CallMgrAfContext, CallMgrVcContext, CallMgrPartyContext, pNdisRequest->DATA.SET_INFORMATION.Oid, pNdisRequest->DATA.SET_INFORMATION.InformationBuffer, pNdisRequest->DATA.SET_INFORMATION.InformationBufferLength, &pNdisRequest->DATA.SET_INFORMATION.BytesRead, &pNdisRequest->DATA.SET_INFORMATION.BytesNeeded ); break; }
default: { NdisStatus = NDIS_STATUS_NOT_SUPPORTED; TRACE( TL_A, TM_Mp, ( "type=%d?", pNdisRequest->RequestType ) ); break; } }
TRACE( TL_T, TM_Cm, ( "<==NicCmReq" ) ); return NdisStatus; }
VOID nicDereferenceAF( IN AFCB* pAF )
// Removes a reference from the address family of adapter control block
// 'pAdapter', and when frees the block when the last reference is
// removed.
//
{ LONG lRef;
lRef = NdisInterlockedDecrement (&pAF->lRef);
TRACE( TL_T, TM_Ref, ( "DerefAf to %d", lRef ) ); ASSERT( lRef >= 0 );
if (lRef == 0) { ADAPTERCB* pAdapter = pAF->pAdapter;
// Remove linkages.
//
ADAPTER_ACQUIRE_LOCK (pAdapter); pAF->pAdapter = NULL;
nicRemoveEntryList (&pAF->linkAFCB); InitializeListHead (&pAF->linkAFCB);
ADAPTER_RELEASE_LOCK (pAdapter);
// Tell NDIS it's close is complete.
//
ASSERT ( nicReadFlags (&pAF->ulFlags) & ACBF_ClosePending); TRACE( TL_I, TM_Cm, ( "NdisMCmCloseAfComp Af %x",pAF ) ); NdisMCmCloseAddressFamilyComplete( NDIS_STATUS_SUCCESS, pAF->NdisAfHandle );
//
// Update State information to show that we have called CloseComplete
//
nicSetFlags ( &pAF->ulFlags, ACBF_CloseComplete); nicClearFlags ( &pAF->ulFlags, ACBF_ClosePending);
nicDereferenceAdapter (pAdapter, "NdisMCmCloseAfComp "); // nicDereferenceFA (CloseAfComp)
nicFreeAF (pAF);
TRACE( TL_I, TM_Cm, ( "NdisMCmCloseAfComp done Af %x", pAF ) );
} }
BOOLEAN nicDereferenceCall( IN VCCB* pVc, IN PCHAR pDebugPrint )
// Removes a reference from the call active on 'pVc', invoking call clean
// up when the value reaches zero.
//
// CAlled with the lock held
{ BOOLEAN bRefZero = FALSE; LONG RefCount; //
// If the Ref goes to zero, derefref return true
//
bRefZero = nicDereferenceRef (&pVc->Hdr.CallRef, &RefCount);
TRACE( TL_V, TM_Ref, ( "***DerefCall %x to %d , %s" , pVc, RefCount, pDebugPrint ) );
if ( bRefZero == TRUE) { //
// Dereference the Vc as the Call no longer exists. This reference was
// added in the beginning of the make call
nicDereferenceVc (pVc);
} return bRefZero; }
VOID nicDereferenceVc( IN VCCB* pVc )
// Removes a reference to the VC control block 'pVc', and when frees the
// block when the last reference is removed.
//
{ LONG lRef;
lRef = NdisInterlockedDecrement( &pVc->Hdr.lRef );
TRACE( TL_V, TM_Ref, ( "DerefVC to %d", lRef ) ); ASSERT( lRef >= 0 );
if (lRef == 0 ) { // If close call is pending and the refcount has gone to zero, then call
//
ASSERT( pVc->Hdr.ulTag == MTAG_VCCB );
pVc->Hdr.ulTag = MTAG_FREED;
FREE_VCCB( pAdapter, pVc );
TRACE( TL_I, TM_Mp, ( "VCB freed $%p", pVc ) ); } }
VOID nicFreeAF( IN AFCB* pAF )
// Frees all resources allocated for address family 'pAF', including
// 'pAF' itself.
//
{
#if TODO
Assert that the various lists (such as pAF->AFVCList) and resources are empty. #endif // TODO
pAF->ulTag = MTAG_FREED;
FREE_NONPAGED (pAF); }
VOID nicReferenceAF( IN AFCB* pAF )
// Adds areference to the address family of adapter block, 'pAdapter'.
//
{ LONG lRef=0;
lRef = NdisInterlockedIncrement (&pAF->lRef);
TRACE( TL_V, TM_Ref, ( "RefAf to %d", lRef ) ); }
BOOLEAN nicReferenceCall( IN VCCB* pVc, IN PCHAR pDebugPrint )
// Returns true if a reference is added to the active call on VC control
// block, 'pVc', or false if no reference was added because no call is
// active.
//
{ BOOLEAN fActive; LONG RefNumber;
fActive = nicReferenceRef (&pVc->Hdr.CallRef, &RefNumber); TRACE( TL_V, TM_Ref, ( "***RefCall %x to %d , %s" , pVc, pVc->Hdr.CallRef.ReferenceCount, pDebugPrint ) );
if ( fActive==FALSE) { TRACE( TL_N, TM_Ref, ( "RefC Inactive" ) ); }
return fActive; }
VOID nicReferenceVc( IN VCCB* pVc )
// Adds a reference to the VC control block 'pVc'.
//
{ LONG lRef;
lRef = NdisInterlockedIncrement (&pVc->Hdr.lRef);
TRACE( TL_I, TM_Ref, ( "RefVc to %d", lRef ) ); }
NDIS_STATUS nicAllocateRequestedChannelMakeCallComplete ( IN PADAPTERCB pAdapter, IN PCHANNEL_VCCB pChannelVc, IN OUT PULONG pChannel ) // Function Description:
// This function allocates the channel requested in the make
// If any channel is requested it will try all 64.
// If the broadcast channel is requested, it will look for
// for the channel allocated by the BCM
// Other wise it will simply try and allocate the requested channel
//
// This can be called from the AddFirstRemoteNode code path.
//
// Arguments
// Channel Vc - The channel Vc in question
// Channel - the channel requested
//
// Return Value:
// Success : if allocate channel succeeds
// pChannel - contains the allocated channel
//
{ NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; ULONG Channel = *pChannel; BOOLEAN fAnyChannel = FALSE; BOOLEAN fFailCall = FALSE; TRACE( TL_T, TM_Cm, ( " ==>nicAllocateRequestedChannelMakeCallComplete pAdapter, pVc %x, Channel %x ", pAdapter, pChannelVc, *pChannel ) );
do {
//
// First make sure we have a good channel number
//
if ( (signed long)Channel < (signed long)NIC1394_BROADCAST_CHANNEL || (signed long)Channel >(signed long)MAX_CHANNEL_NUMBER) { TRACE( TL_A, TM_Cm, ( "Invalid Channel Number, channel %x", Channel) );
NdisStatus = NDIS_STATUS_INVALID_DATA;
ASSERT (!(signed long)Channel < (signed long)NIC1394_BROADCAST_CHANNEL || (signed long)Channel >(signed long)MAX_CHANNEL_NUMBER); break; }
if ((signed long)Channel == NIC1394_BROADCAST_CHANNEL ) { NETWORK_CHANNELSR* pBCR; ULONG i = 0; pBCR = &pAdapter->BCRData.IRM_BCR;
ADAPTER_ACQUIRE_LOCK (pAdapter);
if (BCR_IS_VALID (pBCR) == FALSE) { BOOLEAN bWaitSuccessful = FALSE; BOOLEAN fIsTheBCRFree = FALSE; //
// BCM algorithm has not completed yet, we need to wait
//
TRACE( TL_I, TM_Cm, ( " nicAllocateRequestedChannelMakeCallComplete : BCR Has not completed. About to wait BCR %x ", *pBCR ) );
BCR_SET_FLAG (pAdapter, BCR_MakeCallPending);
ADAPTER_RELEASE_LOCK (pAdapter);
//
// If we don't have a BCR then we should wait until the BCM algorithm completes
//
//
// Now wait for the BCM algorithm to complete. First we will wait for
// 5 seconds. (5*1)
// If we still don't see it, we will reset the bus and hope that the new
// iteration of BCM will succeed.
//
//
// There can 2 reasons to stop waiting, the BCR is being freed because of a
// standby or BCR is correct. We check both conditions
//
NdisWaitEvent (&pAdapter->BCRData.MakeCallWaitEvent.NdisEvent, (5000));
//
// We reset the bus - if the BCR is not getting freed and we
// still do not have a valid BCR . and than we wait
// for the BCR to complete
//
if (BCR_IS_VALID(pBCR) == FALSE && (BCR_TEST_FLAGS (pAdapter, BCR_BCRNeedsToBeFreed | BCR_Freed)== FALSE)) { TRACE( TL_I, TM_Cm, ( " nicAllocateRequestedChannelMakeCallComplete WaitCompleted - About to RESET THE BUS" ) ); nicIssueBusReset (pAdapter, BUS_RESET_FLAGS_FORCE_ROOT );
//
// Wait for 5 minutes before failing the Make Call
// (5 minutes is an experimental number)
//
{ BOOLEAN bWait;
bWait = NdisWaitEvent ( &pAdapter->BCRData.MakeCallWaitEvent.NdisEvent, ONE_MINUTE * 5 ); } }
ADAPTER_ACQUIRE_LOCK (pAdapter);
NdisResetEvent (&pAdapter->BCRData.MakeCallWaitEvent.NdisEvent);
pAdapter->BCRData.MakeCallWaitEvent.EventCode = Nic1394EventCode_InvalidEventCode; BCR_CLEAR_FLAG (pAdapter, BCR_MakeCallPending);
//
// if we have not got a valid BCR, then fail the call
//
if (BCR_IS_VALID(pBCR) == FALSE || BCR_TEST_FLAGS (pAdapter, BCR_BCRNeedsToBeFreed | BCR_Freed)) { fFailCall = TRUE; ADAPTER_RELEASE_LOCK(pAdapter); NdisStatus = NDIS_STATUS_FAILURE; break;
}
}
Channel = pBCR->NC_Channel;
//
// Update the VC structure and break .
// Do not add a reference. Do not set the flag
//
pChannelVc->Channel = Channel;
pChannelVc->Hdr.Nic1394MediaParams.Destination.Channel = Channel;
//
// Reference that this Vc now has a pointer in the BCRData. This is dereferneced
// in the channel close call complete.
//
nicReferenceCall ((PVCCB)pChannelVc, "nicAllocateRequestedChannelMakeCallComplete Broadcast VC");
pAdapter->BCRData.pBroadcastChanneVc = pChannelVc;
VC_SET_FLAG (pChannelVc, VCBF_BroadcastVc);
pAdapter->ChannelsAllocatedByLocalHost = pAdapter->ChannelsAllocatedByLocalHost | (g_ullOne<<Channel);
ADAPTER_RELEASE_LOCK (pAdapter); NdisStatus = NDIS_STATUS_SUCCESS; break; }
if ((signed long)Channel == NIC1394_ANY_CHANNEL ) { TRACE( TL_V, TM_Cm, ( "Requesting Any Channel %x", Channel) );
fAnyChannel = TRUE; Channel = MAX_CHANNEL_NUMBER; }
//
// Now begin the request to allocate a channel
//
if (fAnyChannel == FALSE) { TRACE( TL_V, TM_Cm, ( "Requesting Channel %x, on remote node ", Channel ) );
NdisStatus = nicAllocateChannel ( pAdapter, Channel, NULL);
}
else { //
// we need to go through all 64 channels.
//
do {
NdisStatus = nicAllocateChannel ( pAdapter, Channel, NULL);
if (NdisStatus != NDIS_STATUS_SUCCESS) { if (Channel == 0 ) { //
// We now need to fail the make call as the user asked for any channel
// and none are available
//
break; } Channel --;
} else { //
// We succeeded in allocating a channel .. break
//
break; }
} while (TRUE);
}
//
// Status of Channel allocation. If AnyChannel == TRUE then we need to make sure that
// a channel was allocated
//
if (NdisStatus == NDIS_STATUS_SUCCESS) {
VC_ACQUIRE_LOCK (pChannelVc);
VC_SET_FLAG( pChannelVc, VCBF_AllocatedChannel);
pChannelVc->Channel = Channel;
pChannelVc->Hdr.Nic1394MediaParams.Destination.Channel = Channel;
//
// Record the channel number in the adpater structure
//
pAdapter->ChannelsAllocatedByLocalHost = pAdapter->ChannelsAllocatedByLocalHost | (g_ullOne<<Channel);
VC_RELEASE_LOCK (pChannelVc); nicReferenceCall ((PVCCB)pChannelVc, "nicAllocateRequestedChannelMakeCallComplete -Allocated Channel");
} else { //
// we failed to allocate any channel and are going to fail
//
if (fAnyChannel == TRUE) { Channel = 0xff; NdisStatus = NDIS_STATUS_RESOURCES; break; } else {
//
// If the Call specifically wants the channel to
// be allocated, we return the correct channel allocate
// status to it,
//
// Otherwise we overwrite and presume that another node may
// already have allocated the channel
//
if (VC_TEST_FLAG (pChannelVc,VCBF_NeedsToAllocateChannel) == FALSE) { NdisStatus = NDIS_STATUS_SUCCESS; } else {
ASSERT (!"Failing make call because channel was allocated, Hit 'g'"); } }
}
} while (FALSE);
*pChannel = Channel;
TRACE( TL_T, TM_Cm, ( "<==nicAllocateRequestedChannelMakeCallComplete Status %x Channel %x", NdisStatus, *pChannel ) );
return NdisStatus;
}
NDIS_STATUS nicFindRemoteNodeFromAdapter( IN PADAPTERCB pAdapter, IN PDEVICE_OBJECT pRemotePdo, IN UINT64 UniqueId, IN OUT REMOTE_NODE ** ppRemoteNode ) /*++
Routine Description:
This routine matches either a Remote Node' pdo OR unique Id to the Remote node's on the adapter It walks the RemoteNode List in the Adapter Structure and tries to find a match for the Unique Id, or match the remote Pdo from the adapter's PdoList
Arguments: pAdapter - pAdapter on which to search pRemoptePdo - Remote Pdo to find UniqueId - Unique Id to find ppRemoteNode - Remote Node structure
Return Value: Success if the node is found
--*/ { NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; PLIST_ENTRY pPdoListEntry = NULL; PREMOTE_NODE pRemoteNode = NULL; BOOLEAN fPdoFound = FALSE; STORE_CURRENT_IRQL; TRACE( TL_T, TM_Cm, ( "==>nicFindRemoteNodeFromAdapter pAdapter is %x, ,Pdo %x, UniqueId %I64x ", pAdapter, pRemotePdo, UniqueId ) );
//
// Validate the parameters
//
ASSERT (pAdapter != NULL); TRACE( TL_I, TM_Cm, ( " Request to Match UniqueID %I64x or pRemotePdo %x", UniqueId, pRemotePdo) );
do { (*ppRemoteNode) = NULL;
ADAPTER_ACQUIRE_LOCK (pAdapter); //
// Check for empty list
//
if (pAdapter->PDOList.Flink == &pAdapter->PDOList) {
ADAPTER_RELEASE_LOCK (pAdapter); MATCH_IRQL; NdisStatus = NDIS_STATUS_FAILURE; (*ppRemoteNode) = NULL; TRACE( TL_A, TM_Cm, ( " NO REMOTE NODES PRESENT FAILING MAKE CALL ") ); break; }
//
// go through all the Pdo's on the adapter
//
for (pPdoListEntry = pAdapter->PDOList.Flink; pPdoListEntry!= &pAdapter->PDOList; pPdoListEntry = pPdoListEntry->Flink) { pRemoteNode = CONTAINING_RECORD( pPdoListEntry, REMOTE_NODE, linkPdo);
//
// Check for the two cases, i.e unique Id's match or Pdo's match
//
if ( pRemoteNode->UniqueId == UniqueId || pRemoteNode->pPdo == pRemotePdo) { TRACE( TL_I, TM_Cm, ( " Matched UniqueID or pRemotePdo for Pdo%x",pRemoteNode->pPdo) );
*ppRemoteNode = pRemoteNode; nicReferenceRemoteNode (pRemoteNode, FindRemoteNodeFromAdapter); //
// We ref pRemoteNode to keep it alive once we release the lock.
// Caller is responsible for derefing pRemoteNode.
//
fPdoFound = TRUE;
NdisStatus = NDIS_STATUS_SUCCESS; break; } else { TRACE( TL_A, TM_Cm, ( "remote node's Unique ID's %I64x, given UniqueID %I64x ", pRemoteNode->UniqueId, UniqueId ) ); }
} ADAPTER_RELEASE_LOCK (pAdapter); MATCH_IRQL;
TRACE( TL_V, TM_Cm, ( "Is PdoFound %.2x, RemoteNode at %x ", fPdoFound, &fPdoFound ) );
if (fPdoFound ==FALSE) { TRACE( TL_A, TM_Cm, ( "Remote Node was NOT Found: Make Call failed " ) ); ASSERT ((*ppRemoteNode) == NULL); }
} while (FALSE);
TRACE( TL_T, TM_Cm, ( "<==nicFindRemoteNodeFromAdapter pPdoBlock %x",(*ppRemoteNode) ) );
MATCH_IRQL; return NdisStatus; }
NDIS_STATUS nicCmQueryInformation( IN NDIS_HANDLE CallMgrAfContext, IN NDIS_HANDLE CallMgrVcContext, IN NDIS_HANDLE CallMgrPartyContext, IN NDIS_OID Oid, IN PVOID InformationBuffer, IN ULONG InformationBufferLength, OUT PULONG BytesWritten, OUT PULONG BytesNeeded )
// Handle QueryInformation requests. Arguments are as for the standard
// NDIS 'CallMgrQueryInformation' handler except this routine does not
// count on being serialized with respect to other requests.
//
{
NDIS_STATUS NdisStatus; ULONG ulInfo; VOID* pInfo; ULONG ulInfoLen; USHORT usInfo;
// The next variables are used to setup the data structures that are
// used to respond to the OIDs they correspond to
//
NDIS_CO_LINK_SPEED CoLinkSpeed; NIC1394_LOCAL_NODE_INFO LocalNodeInfo; NIC1394_VC_INFO VcInfo; PVCCB pVc;
TRACE( TL_T, TM_Cm, ( "==>nicCmQueryInformation %x, Vc %x", Oid, CallMgrVcContext ) );
// The cases in this switch statement find or create a buffer containing
// the requested information and point 'pInfo' at it, noting it's length
// in 'ulInfoLen'. Since many of the OIDs return a ULONG, a 'ulInfo'
// buffer is set up as the default.
//
ulInfo = 0; pInfo = &ulInfo; ulInfoLen = sizeof (ulInfo);
NdisStatus = NDIS_STATUS_SUCCESS;
// Validate the arguments
//
pVc = (VCCB* )CallMgrVcContext;
if (pVc && pVc->Hdr.ulTag != MTAG_VCCB) { ASSERT( !"Vtag?" ); return NDIS_STATUS_INVALID_DATA; }
// Perform the request
//
switch (Oid) { case OID_1394_VC_INFO: {
// Returns information about the VC that is being queried
//
TRACE( TL_N, TM_Mp, ("QInfo(OID_1394_VC_INFO)") );
VcInfo.Destination = pVc->Hdr.Nic1394MediaParams.Destination;
pInfo = &VcInfo;
ulInfoLen = sizeof (VcInfo);
break; }
case OID_1394_ISSUE_BUS_RESET: { PADAPTERCB pAdapter = pVc->Hdr.pAF->pAdapter; TRACE( TL_V, TM_Mp, ( " OID_1394_ISSUE_BUS_RESET" ) );
if (InformationBufferLength == sizeof(ULONG)) { nicIssueBusReset (pAdapter, (*(PULONG)InformationBuffer)); } else { nicIssueBusReset (pAdapter, BUS_RESET_FLAGS_FORCE_ROOT );
} break; } default: { TRACE( TL_A, TM_Cm, ( "Q-OID=$%08x?", Oid ) ); NdisStatus = NDIS_STATUS_NOT_SUPPORTED; ulInfoLen = 0; break; } }
if (ulInfoLen > InformationBufferLength) { // Caller's buffer is too small. Tell him what he needs.
//
*BytesNeeded = ulInfoLen; *BytesWritten = 0; NdisStatus = NDIS_STATUS_INVALID_LENGTH; } else { // Copy the found result to caller's buffer.
//
if (ulInfoLen > 0) { NdisMoveMemory (InformationBuffer, pInfo, ulInfoLen );
DUMPDW( TL_N, TM_Mp, pInfo, ulInfoLen ); }
*BytesNeeded = *BytesWritten = ulInfoLen; }
TRACE( TL_T, TM_Cm, ( "<==nicCmQueryInformation %x",NdisStatus ) );
return NdisStatus;
}
NDIS_STATUS nicCmSetInformation( IN NDIS_HANDLE CallMgrAfContext, IN NDIS_HANDLE CallMgrVcContext, IN NDIS_HANDLE CallMgrPartyContext, IN NDIS_OID Oid, IN PVOID InformationBuffer, IN ULONG InformationBufferLength, OUT PULONG BytesRead, OUT PULONG BytesNeeded ) //
// Not implemented yet. Will be used to set information
//
{ NDIS_STATUS NdisStatus = NDIS_STATUS_NOT_SUPPORTED; PVCCB pVc;
TRACE( TL_T, TM_Cm, ( "==>NicCmMakeCallInitVc Oid %x",Oid ) );
// Validate the arguments
//
UNREFERENCED_PARAMETER(CallMgrAfContext); UNREFERENCED_PARAMETER(CallMgrVcContext); UNREFERENCED_PARAMETER(CallMgrAfContext); UNREFERENCED_PARAMETER(CallMgrPartyContext); UNREFERENCED_PARAMETER(Oid); UNREFERENCED_PARAMETER(InformationBuffer); UNREFERENCED_PARAMETER(InformationBufferLength); UNREFERENCED_PARAMETER(BytesRead); UNREFERENCED_PARAMETER(BytesNeeded); TRACE( TL_T, TM_Cm, ( "<==NicCmMakeCallInitVc %x",NdisStatus ) );
return NDIS_STATUS_FAILURE; }
NDIS_STATUS nicInitRecvFifoDataStructures ( IN PRECVFIFO_VCCB pRecvFIFOVc ) // Function Description:
// This function will initialize the data structures, buffers etc that are needed on
// all the allocate address range Irps that will be called because of the RecvFifo Vc
//
// Arguments
// pRecvFIFOVc - RecvFifo Vc structure
//
// Return Value:
// SUCCESS: If all the values are initiaized successfully
// Appropriate error code otherwise
{
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; NDIS_HANDLE PacketPoolHandle = NULL; PSLIST_HEADER pSlistHead = NULL; extern UINT NumRecvFifos ; UINT AllocateNumBuffers = NumRecvFifos; NIC_PACKET_POOL PacketPool;
TRACE( TL_T, TM_Cm, ( "==> nicInitRecvFifoDataStructures pVc %x",pRecvFIFOVc ) );
do { PacketPool.Handle = NULL; //
// Initialize the PacketPool
//
NdisAllocatePacketPoolEx ( &NdisStatus, &PacketPool.Handle, MIN_PACKET_POOL_SIZE, MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE, sizeof (RSVD) ); if (NdisStatus!= NDIS_STATUS_SUCCESS) { ASSERT(NdisStatus != NDIS_STATUS_SUCCESS); pRecvFIFOVc->PacketPool.Handle = NULL; break; }
//
// Do not acquire the lock as we cannot have two make
// calls for the same Vc at the same time
//
//
// Create an S-list and intialize its structures
//
ExInitializeSListHead (&pRecvFIFOVc->FifoSListHead);
KeInitializeSpinLock (&pRecvFIFOVc->FifoSListSpinLock);
pRecvFIFOVc->Hdr.MTU = pRecvFIFOVc->Hdr.Nic1394MediaParams.MTU ; TRACE( TL_I, TM_Cm, ( " Recv FIFO MTU is %d ", pRecvFIFOVc->Hdr.MTU ) );
ASSERT (pRecvFIFOVc->Hdr.MTU >= 512);
//
// Now, fill the Slist with buffers.
//
NdisStatus = nicFillAllocateAddressRangeSList (pRecvFIFOVc, &AllocateNumBuffers); if (NdisStatus != NDIS_STATUS_SUCCESS) { //
// nicFillAllocateAddressRangeSlist does its own clean up
// but we should free the Packet Pool Allocated above
//
if (PacketPool.Handle != NULL) { nicFreePacketPool (&PacketPool); }
break; }
ASSERT(AllocateNumBuffers == NumRecvFifos );
pRecvFIFOVc->PacketPool= PacketPool; pRecvFIFOVc->PacketPool.AllocatedPackets = 0; pRecvFIFOVc->NumAllocatedFifos = AllocateNumBuffers ;
TRACE( TL_V, TM_Cm, ( "PacketPool allocated at %x", PacketPool.Handle) );
} while (FALSE);
TRACE( TL_T, TM_Cm, ( "<== nicInitRecvFifoDataStructures Status %x", NdisStatus ) ); return NdisStatus; }
VOID nicUnInitRecvFifoDataStructures ( IN PRECVFIFO_VCCB pRecvFIFOVc )
/*++
Routine Description: Frees all the resources that were allocated in nicInitRecvFifoDataStructures
Arguments:
Return Value:
--*/ {
if (pRecvFIFOVc->PacketPool.Handle != NULL) { ASSERT (pRecvFIFOVc->PacketPool.AllocatedPackets == 0); nicFreePacketPool (&pRecvFIFOVc->PacketPool); } pRecvFIFOVc->PacketPool.Handle = NULL;
if (pRecvFIFOVc->FifoSListHead.Alignment != 0) { nicFreeAllocateAddressRangeSList(pRecvFIFOVc);
ASSERT (pRecvFIFOVc->FifoSListHead.Alignment == 0)
}
pRecvFIFOVc->FifoSListHead.Alignment = 0;
}
ULONG nicGetMaxPayLoadForSpeed( IN ULONG Speed, IN ULONG mtu ) // Function Description:
// The purpose is to map a speed to the max payload that
// can be delivered at that speed . this is limited by the Bytes PerFrameAvailable
//
// Arguments
// Speed - the speed supported by the Bus driver or the Max speed between devices
// BytesPerFrameAvailable Bytes per frame available on the bus.
//
//
// Return Value:
// Minimin of the Size determined by the payload and the size determined by the
// byte per frame available.
{
ULONG maxIsochPayload = ISOCH_PAYLOAD_400_RATE;
TRACE( TL_T, TM_Cm, ( "<==nicGetMaxPayLoadForSpeed %x", Speed ) );
switch (Speed) {
case SPEED_FLAGS_100:
maxIsochPayload = ISOCH_PAYLOAD_100_RATE; break;
case SPEED_FLAGS_200:
maxIsochPayload = ISOCH_PAYLOAD_200_RATE; break;
case SPEED_FLAGS_400:
maxIsochPayload = ISOCH_PAYLOAD_400_RATE; break;
case SPEED_FLAGS_800:
maxIsochPayload = ISOCH_PAYLOAD_800_RATE; break;
case SPEED_FLAGS_1600:
maxIsochPayload = ISOCH_PAYLOAD_1600_RATE; break;
default : TRACE( TL_A, TM_Cm, ( "Invalid Speed %x", Speed ) ); ASSERT (Speed < SPEED_FLAGS_1600); maxIsochPayload = ISOCH_PAYLOAD_1600_RATE; break;
}
if (maxIsochPayload > mtu) { maxIsochPayload = mtu; }
TRACE( TL_T, TM_Cm, ( "<==nicGetMaxPayLoadForSpeed, payload %x", maxIsochPayload ) );
return maxIsochPayload;
}
//---------------------------------------------------------------------------------
// SAP function - all of them return failure
//-------------------------------------------------------------------------------
NDIS_STATUS nicRegisterSapHandler( IN NDIS_HANDLE CallMgrAfContext, IN PCO_SAP Sap, IN NDIS_HANDLE NdisSapHandle, OUT PNDIS_HANDLE CallMgrSapContext ) {
*CallMgrSapContext = NULL; return NDIS_STATUS_FAILURE; }
NDIS_STATUS nicDeregisterSapHandler( IN NDIS_HANDLE CallMgrSapContext ) { return NDIS_STATUS_FAILURE; }
NDIS_STATUS nicCmDropPartyHandler( IN NDIS_HANDLE CallMgrPartyContext, IN PVOID CloseData OPTIONAL, IN UINT Size OPTIONAL ) { return NDIS_STATUS_FAILURE;
}
NDIS_STATUS nicCmAddPartyHandler( IN NDIS_HANDLE CallMgrVcContext, IN OUT PCO_CALL_PARAMETERS CallParameters, IN NDIS_HANDLE NdisPartyHandle, OUT PNDIS_HANDLE CallMgrPartyContext ) { *CallMgrPartyContext = NULL; return NDIS_STATUS_FAILURE; }
NDIS_STATUS nicAllocateChannelResourcesAndListen ( IN PADAPTERCB pAdapter, IN PCHANNEL_VCCB pChannelVc ) // Function Description:
// This function isolated the reource and channel allocation portion
// of initializing a MakeCall. This lets us do the same work when the
// AddRemoteNode code path is hit and there is an existing Channel Vc
//
// Arguments
// pChannelVc, This is the send fifo that needs to be initilaized
//
// Return Value:
//
// Success if the irps sent to the driver succeed
//
//
{ NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; PDEVICE_OBJECT ArrayRemotePDO[NIC1394_MAX_NUMBER_NODES]; ULONG Channel = INVALID_CHANNEL; ULONG Speed; PNIC1394_MEDIA_PARAMETERS pN1394Params; ULONG NumDescriptors = MAX_NUM_ISOCH_DESCRIPTOR; PISOCH_DESCRIPTOR pIsochDescriptor = NULL; ULONG MaxBufferSize; ULONG MaxBytesPerFrame; HANDLE hResource; CYCLE_TIME CycleTime; ULARGE_INTEGER uliChannelMap; ULONG ResourceFlags = 0; ULONG State = 0; BOOLEAN fBroadcastVc = FALSE; BOOLEAN fChannelAllocate = FALSE; BOOLEAN fIsMultiChannel = FALSE; enum { StartState, AllocatedResources, AllocatedBuffers, AttachedBuffers, IsochListen };
STORE_CURRENT_IRQL;
TRACE( TL_T, TM_Cm, ( "==> nicAllocateChannelResourcesAndListen pAdapter %x, pChannelVc %x ", pAdapter,pChannelVc ) );
State = StartState; pN1394Params = (PNIC1394_MEDIA_PARAMETERS)&pChannelVc->Hdr.Nic1394MediaParams;
//
// Use the original request to figure out which channel needs to be allocated
//
fIsMultiChannel = (pN1394Params->Destination.AddressType == NIC1394AddressType_MultiChannel);
if (fIsMultiChannel == FALSE) { Channel = pN1394Params->Destination.Channel; }
do { if (pAdapter == NULL) { BREAK (TM_Cm, ("nicAllocateChannelResourcesAndListen : pAdapter == NULL ") ); }
//
// Get the max payload that is possible for isoch receives
//
if (pAdapter->Speed == 0) { nicUpdateLocalHostSpeed (pAdapter); }
Speed = pAdapter->Speed; switch (Speed) { case SPEED_FLAGS_100 : { pChannelVc->Hdr.MaxPayload = ISOCH_PAYLOAD_100_RATE; break; } case SPEED_FLAGS_200 : { pChannelVc->Hdr.MaxPayload = ISOCH_PAYLOAD_200_RATE ; break; } case SPEED_FLAGS_400 : { pChannelVc->Hdr.MaxPayload = ISOCH_PAYLOAD_400_RATE; break; }
case SPEED_FLAGS_800 : { pChannelVc->Hdr.MaxPayload = ISOCH_PAYLOAD_400_RATE; break; }
case SPEED_FLAGS_1600 : { pChannelVc->Hdr.MaxPayload = ISOCH_PAYLOAD_400_RATE; break; } case SPEED_FLAGS_3200 : { pChannelVc->Hdr.MaxPayload = ISOCH_PAYLOAD_400_RATE; break; } default : { ASSERT (Speed <= SPEED_FLAGS_3200 && Speed != 0 ); pChannelVc->Hdr.MaxPayload = ISOCH_PAYLOAD_400_RATE; break; }
}
//
// If the make call wants the channel to allocate we try and allocate the channel,
// In the Multichannel case, we do not allocate the channel (as this is
// for listening purposes only )
//
fBroadcastVc = (Channel == NIC1394_BROADCAST_CHANNEL); fChannelAllocate = VC_TEST_FLAG (pChannelVc,VCBF_NeedsToAllocateChannel); if (fChannelAllocate || fBroadcastVc ) { ASSERT (pChannelVc->Hdr.VcType != NIC1394_MultiChannel);
NdisStatus = nicAllocateRequestedChannelMakeCallComplete( pAdapter, pChannelVc, &Channel );
if (NdisStatus != NDIS_STATUS_SUCCESS) { BREAK( TM_Cm, ( " nicAllocateChannelResourcesAndListen : nicAllocateRequestedChannelMakeCallComplete FAILED") );
}
TRACE( TL_I, TM_Cm, ( "Using Channel %x, on remote node ", Channel ) );
ASSERT (Channel < NIC1394_MAX_NUMBER_NODES);
ResourceFlags = 0;
uliChannelMap.QuadPart = 0;
} else { //
// Multichannels - no allocation just update the ullChannelMap
//
uliChannelMap = pChannelVc->uliChannelMap;
if (fIsMultiChannel == TRUE) { ResourceFlags = RESOURCE_USE_MULTICHANNEL; } else { pChannelVc->Channel = Channel ; } } MaxBufferSize = min(pN1394Params->MTU + sizeof(GASP_HEADER) , pChannelVc->Hdr.MaxPayload);
MaxBytesPerFrame = MaxBufferSize;
TRACE( TL_V, TM_Cm, ( " MAxBufferSize %x, MaxBytesPerFrame %x", MaxBufferSize, MaxBytesPerFrame ) );
//
// Add the flags used for resources allocation
//
ResourceFlags |= (RESOURCE_USED_IN_LISTENING | RESOURCE_USE_PACKET_BASED | RESOURCE_BUFFERS_CIRCULAR); //
// MaxBufferSize should be an integral mutiple of MaxBytesPerFram
//
ASSERT (MaxBufferSize % MaxBytesPerFrame == 0);
//
// Noe allocate the resource
//
NdisStatus = nicIsochAllocateResources( pAdapter, Speed, ResourceFlags, Channel, MaxBytesPerFrame, NumDescriptors, MaxBufferSize, 0, //QuadletsToStrip,
uliChannelMap, &hResource);
if (NdisStatus != NDIS_STATUS_SUCCESS) { hResource = NULL; BREAK(TM_Cm, ( "Allocate Resources Failed. Make Call failed ") ); } State = AllocatedResources; ASSERT (NumDescriptors != 0);
ASSERT (pChannelVc->Hdr.MTU != 0);
//
// Get Isoch Descriptors that will be submitted to the Bus drivers
//
//
// Add room for the Isoch Header and Isoch prefix
//
MaxBufferSize += ISOCH_PREFIX_LENGTH ;
NdisStatus = nicAllocateAndInitializeIsochDescriptors (pChannelVc, NumDescriptors, MaxBufferSize, &pIsochDescriptor ); if(NdisStatus != NDIS_STATUS_SUCCESS) { BREAK (TM_Cm, (" nicAllocateAndInitializeIsochDescriptors failed, Make Call Failed") ); } ASSERT (pIsochDescriptor != NULL);
State = AllocatedBuffers;
NdisStatus = nicIsochAttachBuffers( pAdapter, hResource, NumDescriptors, pIsochDescriptor);
if (NdisStatus != NDIS_STATUS_SUCCESS) { BREAK (TM_Cm, "nicIsochAttachBuffers FAILED"); }
State = AttachedBuffers;
//
// Start the Listen
//
NdisZeroMemory (&CycleTime, sizeof(CycleTime)); NdisStatus = nicIsochListen (pAdapter, hResource, 0, CycleTime ); // Cycle Time is Zero
//
// Update the Vc structure, because we have now succeeded
//
State = IsochListen;
VC_ACQUIRE_LOCK (pChannelVc); //
// If broadcast channel, then decrease the speed setting, and fragment
//
if (Channel == NIC1394_BROADCAST_CHANNEL) { Speed = SPEED_FLAGS_200 ; pChannelVc->Hdr.MaxPayload = ISOCH_PAYLOAD_200_RATE ; }
pChannelVc->Channel = Channel; pChannelVc->MaxBufferSize = MaxBufferSize - ISOCH_PREFIX_LENGTH; pChannelVc->Speed = Speed; pChannelVc->hResource = hResource; //
// Reference Call for allocated resource handle
//
nicReferenceCall ( (PVCCB) pChannelVc, "nicAllocateRequestedChannelMakeCallComplete - allocate resources ");
pChannelVc->NumDescriptors = NumDescriptors; pChannelVc->pIsochDescriptor = pIsochDescriptor; //
// Reference the call because we will now need to detach buffers
//
nicReferenceCall ( (PVCCB) pChannelVc, "nicAllocateRequestedChannelMakeCallComplete - Attach Buffers");
//
// We have succeded in allocating all resources.
// If the Freed Resources flag is set it needs to be cleared
//
VC_CLEAR_FLAGS (pChannelVc, VCBF_FreedResources); VC_RELEASE_LOCK (pChannelVc);
//
// No more failures
//
} while (FALSE);
//
// Time to do clean up based on what resources were allocated.
// There are no failures after the point where the refs for
// Allocate Resources and Attach Buffers are added, so
// No Derefs in the following code except in ( FreeIsochDesc)
//
if (NdisStatus != NDIS_STATUS_SUCCESS ) { BOOLEAN fAllocatedChannel = FALSE;
switch (State) { case IsochListen: { nicIsochStop(pAdapter, hResource); FALL_THROUGH } case AttachedBuffers: { nicIsochDetachBuffers( pAdapter, hResource, NumDescriptors, pIsochDescriptor );
FALL_THROUGH; } case AllocatedBuffers: { //
// Free the isoch Buffers and Descriptors that were
// allocated
//
nicFreeIsochDescriptors(NumDescriptors, pIsochDescriptor, (PVCCB) pChannelVc); FALL_THROUGH }
case AllocatedResources: { //
// Free the Isoch Resources Handle
//
nicIsochFreeResources (pAdapter, hResource); FALL_THROUGH }
case StartState: { FALL_THROUGH } default: { break; } } VC_ACQUIRE_LOCK (pChannelVc);
//
// Update Flags in the VC structure
//
VC_SET_FLAG (pChannelVc, VCBF_FreedResources); fAllocatedChannel = VC_TEST_FLAGS( pChannelVc, VCBF_AllocatedChannel);
//
// Do we need to free a channel as well
//
if (fAllocatedChannel == TRUE) { Channel = pChannelVc->Channel; pChannelVc->Channel = INVALID_CHANNEL;
nicDereferenceCall ((PVCCB) pChannelVc, "Free Allocated Channel"); } VC_RELEASE_LOCK (pChannelVc);
if (fAllocatedChannel) { nicFreeChannel (pAdapter, pChannelVc->Channel); }
} // end of failure code path
TRACE( TL_T, TM_Cm, ( "<== nicAllocateChannelResourcesAndListen NdisStatus %x ",NdisStatus) );
MATCH_IRQL; return NdisStatus;
}
NDIS_STATUS nicQueryRemoteNodeCaps ( IN PADAPTERCB pAdapter, IN PREMOTE_NODE pRemoteNode, OUT PULONG pSpeedTo, OUT PULONG pMaxBufferSize, OUT PULONG pMaxRec ) /*++
Routine Description:
Queries the remote Node for speed and max size
Arguments: pSpeedTo -- max speed to the remote node. From nodes config rom. in units of SCODE_XXX_RATE. pMaxBufferSize -- max buffer size to use ( this is the min of local, remote and max allowed by *pSpeedTo). pMaxRec -- maxrec of the remote node -- from the node's config rom.
Return Value:
--*/ { NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; ULONG Speed = 0; // Speed in units of SPEED_FLAG_XXX
ULONG MaxBufferSize; PVOID pCRom = NULL; PCONFIG_ROM pBusInfo = NULL; ULONG SpeedMaxRec = 0; ULONG MaxRec= 0; ULONG MinMaxRec= 0;
TRACE( TL_T, TM_Cm, ( "==> nicQueryRemoteNodeCaps pRemoteNode%x ",pRemoteNode) );
do { ASSERT (KeGetCurrentIrql()==PASSIVE_LEVEL); ADAPTER_ACQUIRE_LOCK (pAdapter);
if (REMOTE_NODE_ACTIVE (pRemoteNode) == FALSE) { NdisStatus = NDIS_STATUS_DEST_OUT_OF_ORDER;
ADAPTER_RELEASE_LOCK (pAdapter);
break; }
ADAPTER_RELEASE_LOCK (pAdapter);
NdisStatus = nicGetMaxSpeedBetweenDevices (pAdapter, 1 , &pRemoteNode->pPdo, &Speed);
if (NdisStatus != NDIS_STATUS_SUCCESS) { BREAK (TM_Cm, (" nicQueryRemoteNodeCaps : nicGetMaxSpeedBetweenDevices FAILED") ); } TRACE( TL_V, TM_Cm, ( "nicGetMaxSpeedBetweenDevices Speed %x ",Speed) );
//
// This is the MaxRec from the Actual speed of
// the link.
//
SpeedMaxRec = nicGetMaxRecFromSpeed(Speed);
//
// Now get the max rec from the config rom
//
NdisStatus = nicGetConfigRom (pRemoteNode->pPdo, &pCRom);
if (NdisStatus != NDIS_STATUS_SUCCESS) { BREAK (TM_Cm, (" nicQueryRemoteNodeCaps : nicGetMaxSpeedBetweenDevices FAILED") ); }
//
// Now extract the bus info, and get the remoteNode's MaxRec
// The max rec is a 4-bit field at location 0x0000f000.
// See for example Figure 11-3: Format of the Bus_Info_Block in
// the Mind Share Inc's FireWire System Architecture book.
//
//
pBusInfo = (PCONFIG_ROM) pCRom;
MaxRec = SWAPBYTES_ULONG (pBusInfo->CR_BusInfoBlockCaps);
MaxRec &= 0xf000;
MaxRec = MaxRec >> 12;
//
// Take the minimum of the adapter, the remote node
// and the link's maxRec
//
MinMaxRec = min (MaxRec, pAdapter->MaxRec); MinMaxRec = min (MinMaxRec, SpeedMaxRec);
switch (MinMaxRec) { case MAX_REC_100_RATE: { MaxBufferSize = ASYNC_PAYLOAD_100_RATE ; break; } case MAX_REC_200_RATE: { MaxBufferSize = ASYNC_PAYLOAD_200_RATE; break; } case MAX_REC_400_RATE : { MaxBufferSize = ASYNC_PAYLOAD_400_RATE; break; } default: { //
// Use the 400 size for all larger payloads.
//
MaxBufferSize = ASYNC_PAYLOAD_400_RATE; break; }
}
TRACE( TL_N, TM_Cm, (" MaxRec %x\n", MaxRec ) );
} while (FALSE);
if (NdisStatus == NDIS_STATUS_SUCCESS) { Speed = nicSpeedFlagsToSCode(Speed); *pSpeedTo = Speed; *pMaxBufferSize = MaxBufferSize; *pMaxRec = MaxRec;
// Update the remote node's cached caps.
//
REMOTE_NODE_ACQUIRE_LOCK (pRemoteNode); pRemoteNode->CachedCaps.SpeedTo = Speed; pRemoteNode->CachedCaps.EffectiveMaxBufferSize = MaxBufferSize; pRemoteNode->CachedCaps.MaxRec = MaxRec; REMOTE_NODE_RELEASE_LOCK (pRemoteNode); } if (pCRom != NULL) { FREE_NONPAGED (pCRom); }
TRACE( TL_T, TM_Cm, ( "<== nicQueryRemoteNodeCaps pRemoteNode%x , NdisStatus %x",pRemoteNode, NdisStatus) ); return NdisStatus; }
VOID nicInterceptMakeCallParameters ( PCO_MEDIA_PARAMETERS pMedia ) {
PNIC1394_MEDIA_PARAMETERS p1394Params = (PNIC1394_MEDIA_PARAMETERS )(pMedia->MediaSpecific.Parameters);
#if INTERCEPT_MAKE_CALL
if (p1394Params->Destination.AddressType == NIC1394AddressType_MultiChannel) { p1394Params->Destination.AddressType = NIC1394AddressType_Channel; p1394Params->Destination.Channel = 0x3a; p1394Params->Flags |= NIC1394_VCFLAG_ALLOCATE; pMedia->Flags |= TRANSMIT_VC; pMedia->Flags &= (~RECEIVE_VC); return; }
if (p1394Params->Destination.AddressType == NIC1394AddressType_Ethernet) { p1394Params->Destination.AddressType = NIC1394AddressType_Channel; p1394Params->Destination.Channel = 0x3a; pMedia->Flags |= RECEIVE_VC; pMedia->Flags &= (~TRANSMIT_VC); return;
}
#endif
}
UINT nicSpeedFlagsToSCode( IN UINT SpeedFlags ) { UINT SCode = SCODE_400_RATE;
switch (SpeedFlags) { case SPEED_FLAGS_100 : { SCode = SCODE_100_RATE; break; } case SPEED_FLAGS_200 : { SCode = SCODE_200_RATE; break; } case SPEED_FLAGS_400 : { SCode = SCODE_400_RATE; break; }
case SPEED_FLAGS_800 : { SCode = SCODE_800_RATE; break; }
case SPEED_FLAGS_1600 : { SCode = SCODE_1600_RATE; break; }
case SPEED_FLAGS_3200 : { SCode = SCODE_3200_RATE; break; }
default : { ASSERT (!"SpeedFlags out of range"); break; } }
return SCode; }
|