/* §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ (C) Copyright 1999 All rights reserved. §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ Portions of this software are: (C) Copyright 1995 TriplePoint, Inc. -- http://www.TriplePoint.com License to use this software is granted under the same terms outlined in the Microsoft Windows Device Driver Development Kit. (C) Copyright 1992 Microsoft Corp. -- http://www.Microsoft.com License to use this software is granted under the terms outlined in the Microsoft Windows Device Driver Development Kit. §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @doc INTERNAL DChannel DChannel_c @module DChannel.c | This module implements the interface to the . Supports the high-level channel control functions used by the CONDIS WAN Minport driver. @comm This module isolates most the vendor specific Call Control interfaces. It will require some changes to accomodate your hardware device's call control mechanism. @head3 Contents | @index class,mfunc,func,msg,mdata,struct,enum | DChannel_c @end §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ */ #define __FILEID__ DCHANNEL_OBJECT_TYPE // Unique file ID for error logging #include "Miniport.h" // Defines all the miniport objects #if defined(NDIS_LCODE) # pragma NDIS_LCODE // Windows 9x wants this code locked down! # pragma NDIS_LDATA #endif DBG_STATIC ULONG g_DChannelInstanceCounter // @globalv // Keeps track of how many s are created. = 0; /* @doc EXTERNAL INTERNAL DChannel DChannel_c g_DChannelParameters §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @topic 5.4 DChannel Parameters | This section describes the registry parameters read into the . @globalv PARAM_TABLE | g_DChannelParameters | This table defines the registry based parameters to be assigned to data members of the . : If you add any registry based data members to you will need to modify and add the parameter definitions to the table. */ DBG_STATIC PARAM_TABLE g_DChannelParameters[] = { PARAM_ENTRY(DCHANNEL_OBJECT, TODO, PARAM_TODO, FALSE, NdisParameterInteger, 0, 0, 0, 0), /* The last entry must be an empty string! */ { { 0 } } }; /* @doc INTERNAL DChannel DChannel_c DChannelReadParameters §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func reads the DChannel parameters from the registry and initializes the associated data members. This should only be called by . : If you add any registry based data members to you will need to modify and add the parameter definitions to the table. @rdesc returns zero if it is successful. Otherwise, a non-zero return value indicates an error condition. */ DBG_STATIC NDIS_STATUS DChannelReadParameters( IN PDCHANNEL_OBJECT pDChannel // @parm // A pointer to the returned by . ) { DBG_FUNC("DChannelReadParameters") NDIS_STATUS Status; // Status result returned from an NDIS function call. PMINIPORT_ADAPTER_OBJECT pAdapter; // A pointer to the . ASSERT(pDChannel && pDChannel->ObjectType == DCHANNEL_OBJECT_TYPE); pAdapter = GET_ADAPTER_FROM_DCHANNEL(pDChannel); DBG_ENTER(pAdapter); /* // Parse the registry parameters. */ Status = ParamParseRegistry( pAdapter->MiniportAdapterHandle, pAdapter->WrapperConfigurationContext, (PUCHAR)pDChannel, g_DChannelParameters ); if (Status == NDIS_STATUS_SUCCESS) { /* // Make sure the parameters are valid. */ if (pDChannel->TODO) { DBG_ERROR(pAdapter,("Invalid parameter\n" )); NdisWriteErrorLogEntry( pAdapter->MiniportAdapterHandle, NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION, 3, pDChannel->TODO, __FILEID__, __LINE__ ); Status = NDIS_STATUS_FAILURE; } else { /* // Finish setting up data members based on registry settings. */ } } DBG_RETURN(pAdapter, Status); return (Status); } /* @doc INTERNAL DChannel DChannel_c DChannelCreateObjects §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func calls the create routines for all the objects contained in . This should only be called by . : If you add any new objects to you will need to modify and so they will get created and destroyed properly. @rdesc returns zero if it is successful. Otherwise, a non-zero return value indicates an error condition. */ DBG_STATIC NDIS_STATUS DChannelCreateObjects( IN PDCHANNEL_OBJECT pDChannel // @parm // A pointer to the returned by . ) { DBG_FUNC("DChannelCreateObjects") NDIS_STATUS Result = NDIS_STATUS_SUCCESS; // Holds the result code returned by this function. PMINIPORT_ADAPTER_OBJECT pAdapter; // A pointer to the . ASSERT(pDChannel && pDChannel->ObjectType == DCHANNEL_OBJECT_TYPE); pAdapter = GET_ADAPTER_FROM_DCHANNEL(pDChannel); DBG_ENTER(pAdapter); // TODO - Add code here to allocate any sub-objects needed to support // your physical DChannels. DBG_RETURN(pAdapter, Result); return (Result); } /* @doc INTERNAL DChannel DChannel_c DChannelCreate §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func allocates memory for a and then initializes the data members to their starting state. If successful,

will be set to point to the newly created . Otherwise,

will be set to NULL. @comm This function should be called only once when the Miniport is loaded. Before the Miniport is unloaded, must be called to release the created by this function. @rdesc returns zero if it is successful. Otherwise, a non-zero return value indicates an error condition. */ NDIS_STATUS DChannelCreate( OUT PDCHANNEL_OBJECT * ppDChannel, // @parm // Points to a caller-defined memory location to which this function // writes the virtual address of the allocated . IN PMINIPORT_ADAPTER_OBJECT pAdapter // @parm // A pointer to the instance. ) { DBG_FUNC("DChannelCreate") PDCHANNEL_OBJECT pDChannel; // Pointer to our newly allocated object. NDIS_STATUS Result = NDIS_STATUS_SUCCESS; // Holds the result code returned by this function. ASSERT(pAdapter && pAdapter->ObjectType == MINIPORT_ADAPTER_OBJECT_TYPE); DBG_ENTER(pAdapter); /* // Make sure the caller's object pointer is NULL to begin with. // It will be set later only if everything is successful. */ *ppDChannel = NULL; /* // Allocate memory for the object. */ Result = ALLOCATE_OBJECT(pDChannel, pAdapter->MiniportAdapterHandle); if (Result == NDIS_STATUS_SUCCESS) { /* // Zero everything to begin with. // Then set the object type and assign a unique ID . */ pDChannel->ObjectType = DCHANNEL_OBJECT_TYPE; pDChannel->ObjectID = ++g_DChannelInstanceCounter; /* // Initialize the member variables to their default settings. */ pDChannel->pAdapter = pAdapter; // TODO - Add code here to allocate any resources needed to support // your physical DChannels. /* // Parse the registry parameters. */ Result = DChannelReadParameters(pDChannel); /* // If all goes well, we are ready to create the sub-components. */ if (Result == NDIS_STATUS_SUCCESS) { Result = DChannelCreateObjects(pDChannel); } if (Result == NDIS_STATUS_SUCCESS) { /* // All is well, so return the object pointer to the caller. */ *ppDChannel = pDChannel; } else { /* // Something went wrong, so let's make sure everything is // cleaned up. */ DChannelDestroy(pDChannel); } } DBG_RETURN(pAdapter, Result); return (Result); } /* @doc INTERNAL DChannel DChannel_c DChannelDestroyObjects §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func calls the destroy routines for all the objects contained in . This should only be called by . : If you add any new objects to you will need to modify and so they will get created and destroyed properly. */ DBG_STATIC void DChannelDestroyObjects( IN PDCHANNEL_OBJECT pDChannel // @parm // A pointer to the returned by . ) { DBG_FUNC("DChannelDestroyObjects") PMINIPORT_ADAPTER_OBJECT pAdapter; // A pointer to the . ASSERT(pDChannel && pDChannel->ObjectType == DCHANNEL_OBJECT_TYPE); pAdapter = GET_ADAPTER_FROM_DCHANNEL(pDChannel); DBG_ENTER(pAdapter); // TODO - Add code here to release any sub-objects allocated by // DChannelCreateObjects. DBG_LEAVE(pAdapter); } /* @doc INTERNAL DChannel DChannel_c DChannelDestroy §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func frees the memory for this . All memory allocated by will be released back to the OS. */ void DChannelDestroy( IN PDCHANNEL_OBJECT pDChannel // @parm // A pointer to the returned by . ) { DBG_FUNC("DChannelDestroy") PMINIPORT_ADAPTER_OBJECT pAdapter; // A pointer to the . if (pDChannel) { ASSERT(pDChannel->ObjectType == DCHANNEL_OBJECT_TYPE); pAdapter = GET_ADAPTER_FROM_DCHANNEL(pDChannel); DBG_ENTER(pAdapter); // TODO - Add code here to release any resources allocated by // DChannelCreate. /* // Release all objects allocated within this object. */ DChannelDestroyObjects(pDChannel); /* // Make sure we fail the ASSERT if we see this object again. */ pDChannel->ObjectType = 0; FREE_OBJECT(pDChannel); DBG_LEAVE(pAdapter); } } /* @doc INTERNAL DChannel DChannel_c DChannelInitialize §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func resets all the internal data members contained in back to their initial state. : If you add any new members to you will need to modify to initialize your new data mamebers. */ void DChannelInitialize( IN PDCHANNEL_OBJECT pDChannel // @parm // A pointer to the returned by . ) { DBG_FUNC("DChannelInitialize") PMINIPORT_ADAPTER_OBJECT pAdapter; // A pointer to the . ASSERT(pDChannel && pDChannel->ObjectType == DCHANNEL_OBJECT_TYPE); pAdapter = GET_ADAPTER_FROM_DCHANNEL(pDChannel); DBG_ENTER(pAdapter); // TODO - Add code here to initialize all the physical D-Channels on // your adapter. DBG_LEAVE(pAdapter); } /* @doc INTERNAL DChannel DChannel_c DChannelOpen §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func establishes a communications path between the miniport and the DChannel. @rdesc returns zero if it is successful. Otherwise, a non-zero return value indicates an error condition. */ NDIS_STATUS DChannelOpen( IN PDCHANNEL_OBJECT pDChannel // @parm // A pointer to the returned by . ) { DBG_FUNC("DChannelOpen") NDIS_STATUS Result = NDIS_STATUS_SUCCESS; // Holds the result code returned by this function. PMINIPORT_ADAPTER_OBJECT pAdapter; // A pointer to the . ASSERT(pDChannel && pDChannel->ObjectType == DCHANNEL_OBJECT_TYPE); pAdapter = GET_ADAPTER_FROM_DCHANNEL(pDChannel); DBG_ENTER(pAdapter); if (++pDChannel->IsOpen == 1) { DBG_NOTICE(pAdapter,("Opening DChannel #%d\n", pDChannel->ObjectID)); // TODO - Add code here to open all the physical D-Channels on // your adapter. } else { DBG_NOTICE(pAdapter,("DChannel #%d already opened\n", pDChannel->ObjectID)); } DBG_RETURN(pAdapter, Result); return (Result); } /* @doc INTERNAL DChannel DChannel_c DChannelClose §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func tears down the communications path between the miniport and the DChannel. */ void DChannelClose( IN PDCHANNEL_OBJECT pDChannel // @parm // A pointer to the returned by . ) { DBG_FUNC("DChannelClose") PMINIPORT_ADAPTER_OBJECT pAdapter; // A pointer to the . ASSERT(pDChannel && pDChannel->ObjectType == DCHANNEL_OBJECT_TYPE); pAdapter = GET_ADAPTER_FROM_DCHANNEL(pDChannel); DBG_ENTER(pAdapter); if (pDChannel->IsOpen == 1) { DBG_NOTICE(pAdapter,("Closing DChannel #%d\n", pDChannel->ObjectID)); // TODO - Add code here to close all the physical D-Channels on // your adapter. pDChannel->IsOpen = 0; } else if (pDChannel->IsOpen == 0) { DBG_WARNING(pAdapter,("DChannel #%d already closed\n", pDChannel->ObjectID)); } else { pDChannel->IsOpen--; } DBG_LEAVE(pAdapter); } /* @doc INTERNAL DChannel DChannel_c DChannelMakeCall §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func places a call over the selected line device. @rdesc returns zero if it is successful. Otherwise, a non-zero return value indicates an error condition. */ NDIS_STATUS DChannelMakeCall( IN PDCHANNEL_OBJECT pDChannel, // @parm // A pointer to the returned by . IN PBCHANNEL_OBJECT pBChannel, // @parm // A pointer to the returned by . IN PUCHAR DialString, // @parm // A pointer to an ASCII null-terminated string of digits. IN USHORT DialStringLength, // @parm // Number of bytes in dial string. IN PLINE_CALL_PARAMS pLineCallParams // @parm // A pointer to the TAPI to be used for this call. ) { DBG_FUNC("DChannelMakeCall") NDIS_STATUS Result = NDIS_STATUS_RESOURCES; // Holds the result code returned by this function. PMINIPORT_ADAPTER_OBJECT pAdapter; // A pointer to the . ASSERT(pDChannel && pDChannel->ObjectType == DCHANNEL_OBJECT_TYPE); pAdapter = GET_ADAPTER_FROM_DCHANNEL(pDChannel); DBG_ENTER(pAdapter); ASSERT(pDChannel->IsOpen); pDChannel->TotalMakeCalls++; pBChannel->Flags |= VCF_OUTGOING_CALL; pBChannel->CallState = LINECALLSTATE_DIALING; #if defined(SAMPLE_DRIVER) // This sample code uses the phone number to select one of the other // BChannels on which to complete the connection. { PBCHANNEL_OBJECT pPeerBChannel; PCARD_EVENT_OBJECT pEvent; pPeerBChannel = GET_BCHANNEL_FROM_PHONE_NUMBER(DialString); if (pPeerBChannel) { pEvent = CardEventAllocate(pPeerBChannel->pAdapter->pCard); if (pEvent) { pEvent->ulEventCode = CARD_EVENT_RING; pEvent->pSendingObject = pBChannel; pEvent->pReceivingObject = pPeerBChannel; pBChannel->pPeerBChannel = pPeerBChannel; CardNotifyEvent(pPeerBChannel->pAdapter->pCard, pEvent); Result = NDIS_STATUS_PENDING; } } else { DBG_ERROR(pAdapter,("Cannot map phone number '%s' to BChannel\n", DialString)); } } #else // SAMPLE_DRIVER // TODO - Add code here to place a call. #endif // SAMPLE_DRIVER DBG_RETURN(pAdapter, Result); return (Result); } /* @doc INTERNAL DChannel DChannel_c DChannelAnswerCall §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func answers the incoming call so it can be connected. @rdesc returns zero if it is successful. Otherwise, a non-zero return value indicates an error condition. */ NDIS_STATUS DChannelAnswerCall( IN PDCHANNEL_OBJECT pDChannel, // @parm // A pointer to the returned by . IN PBCHANNEL_OBJECT pBChannel // @parm // A pointer to the returned by . ) { DBG_FUNC("DChannelAnswerCall") NDIS_STATUS Result = NDIS_STATUS_SUCCESS; // Holds the result code returned by this function. PMINIPORT_ADAPTER_OBJECT pAdapter; // A pointer to the . ASSERT(pDChannel && pDChannel->ObjectType == DCHANNEL_OBJECT_TYPE); pAdapter = GET_ADAPTER_FROM_DCHANNEL(pDChannel); DBG_ENTER(pAdapter); ASSERT(pDChannel->IsOpen); pDChannel->TotalAnswers++; #if defined(SAMPLE_DRIVER) // This sample code sends a connect over to the calling BChannel. { PCARD_EVENT_OBJECT pEvent; PBCHANNEL_OBJECT pPeerBChannel = pBChannel->pPeerBChannel; if (pPeerBChannel) { pEvent = CardEventAllocate(pPeerBChannel->pAdapter->pCard); if (pEvent) { pEvent->ulEventCode = CARD_EVENT_CONNECT; pEvent->pSendingObject = pBChannel; pEvent->pReceivingObject = pPeerBChannel; CardNotifyEvent(pPeerBChannel->pAdapter->pCard, pEvent); } else { Result = NDIS_STATUS_RESOURCES; } } else { DBG_ERROR(pAdapter,("pPeerBChannel == NULL\n")); Result = NDIS_STATUS_RESOURCES; } } #else // SAMPLE_DRIVER // TODO - Add code here to answer a call. // If you return NDIS_STATUS_PENDING from here, you must perform the // following actions when the call is finally answered. // pBChannel->CallState = LINECALLSTATE_CONNECTED; // NdisMCmDispatchCallConnected(pBChannel->NdisVcHandle); // If you fail to answer for some reason you must call: // InitiateCallTeardown(pAdapter, pBChannel); #endif // SAMPLE_DRIVER DBG_RETURN(pAdapter, Result); return (Result); } /* @doc INTERNAL DChannel DChannel_c DChannelCloseCall §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func closes a previously opened call instance as initiated from or . After the call is closed, no one else should reference it. @rdesc returns zero if it is successful. Otherwise, a non-zero return value indicates an error condition. */ NDIS_STATUS DChannelCloseCall( IN PDCHANNEL_OBJECT pDChannel, // @parm // A pointer to the returned by . IN PBCHANNEL_OBJECT pBChannel // @parm // A pointer to the returned by . ) { DBG_FUNC("DChannelCloseCall") NDIS_STATUS Result = NDIS_STATUS_SUCCESS; // Holds the result code returned by this function. PMINIPORT_ADAPTER_OBJECT pAdapter; // A pointer to the . ASSERT(pDChannel && pDChannel->ObjectType == DCHANNEL_OBJECT_TYPE); pAdapter = GET_ADAPTER_FROM_DCHANNEL(pDChannel); DBG_ENTER(pAdapter); ASSERT(pDChannel->IsOpen); // This routine may be called several times during line/call cleanup. // If the call is already closed, just return success. if (pBChannel->CallState != 0 && pBChannel->CallState != LINECALLSTATE_IDLE) { #if defined(SAMPLE_DRIVER) // This sample code sends a disconnect over to the connected BChannel. PCARD_EVENT_OBJECT pEvent; PBCHANNEL_OBJECT pPeerBChannel = pBChannel->pPeerBChannel; if (pPeerBChannel) { pEvent = CardEventAllocate(pPeerBChannel->pAdapter->pCard); if (pEvent) { // Indicate call disconnect to the other channel. pEvent->ulEventCode = CARD_EVENT_DISCONNECT; pEvent->pSendingObject = pBChannel; pEvent->pReceivingObject = pPeerBChannel; CardNotifyEvent(pPeerBChannel->pAdapter->pCard, pEvent); } pBChannel->pPeerBChannel = NULL; } else { DBG_WARNING(pAdapter,("#%d NO PEER CHANNEL - CALLSTATE=%X\n", pBChannel->ObjectID, pBChannel->CallState)); } // Return any pending packets to the protocol stack. pBChannel->CallState = LINECALLSTATE_IDLE; #else // SAMPLE_DRIVER // TODO - Add code here to drop a call. #endif // SAMPLE_DRIVER // Make sure there are no packets left on this channel before it closes. FlushSendPackets(pAdapter, pBChannel); } else { DBG_NOTICE(pAdapter,("#%d ALREADY IDLE - CALLSTATE=%X\n", pBChannel->ObjectID, pBChannel->CallState)); } DBG_RETURN(pAdapter, Result); return (Result); } /* @doc INTERNAL DChannel DChannel_c DChannelRejectCall §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func rejects an incoming call on the specified channel. */ VOID DChannelRejectCall( IN PDCHANNEL_OBJECT pDChannel, // @parm // A pointer to the returned by . IN PBCHANNEL_OBJECT pBChannel // @parm // A pointer to the returned by . ) { DBG_FUNC("DChannelRejectCall") PMINIPORT_ADAPTER_OBJECT pAdapter; // A pointer to the . ASSERT(pDChannel && pDChannel->ObjectType == DCHANNEL_OBJECT_TYPE); pAdapter = GET_ADAPTER_FROM_DCHANNEL(pDChannel); DBG_ENTER(pAdapter); if (pBChannel->CallState != 0 && pBChannel->CallState != LINECALLSTATE_IDLE) { #if defined(SAMPLE_DRIVER) // This sample code sends a disconnect over to the connected BChannel. PCARD_EVENT_OBJECT pEvent; PBCHANNEL_OBJECT pPeerBChannel = pBChannel->pPeerBChannel; if (pPeerBChannel) { pEvent = CardEventAllocate(pPeerBChannel->pAdapter->pCard); if (pEvent) { // Indicate call disconnect to the other channel. pEvent->ulEventCode = CARD_EVENT_DISCONNECT; pEvent->pSendingObject = pBChannel; pEvent->pReceivingObject = pPeerBChannel; CardNotifyEvent(pPeerBChannel->pAdapter->pCard, pEvent); } pBChannel->pPeerBChannel = NULL; } else { DBG_WARNING(pAdapter,("#%d NO PEER CHANNEL - CALLSTATE=%X\n", pBChannel->ObjectID, pBChannel->CallState)); } // Return any pending packets to the protocol stack. pBChannel->CallState = LINECALLSTATE_IDLE; #else // SAMPLE_DRIVER // TODO - Add code here to reject an incoming call. #endif // SAMPLE_DRIVER } DBG_LEAVE(pAdapter); }