VOID PtUnbindAdapter( OUT PNDIS_STATUS Status, IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE UnbindContext ) /*++ Routine Description: Called by NDIS when we are required to unbind to the adapter below. This functions shares functionality with the miniport's HaltHandler. The code should ensure that NdisCloseAdapter and NdisFreeMemory is called only once between the two functions Arguments: Status Placeholder for return status ProtocolBindingContext Pointer to the adapter structure UnbindContext Context for NdisUnbindComplete() if this pends Return Value: Status for NdisIMDeinitializeDeviceContext --*/ { PADAPT pAdapt =(PADAPT)ProtocolBindingContext; NDIS_HANDLE BindingHandle = pAdapt->BindingHandle; NDIS_STATUS LocalStatus; DBGPRINT(("==> PtUnbindAdapter: Adapt %p\n", pAdapt)); if (pAdapt->QueuedRequest == TRUE) { pAdapt->QueuedRequest = FALSE; PtRequestComplete (pAdapt, &pAdapt->Request, NDIS_STATUS_FAILURE ); } #ifndef WIN9X // // Check if we had called NdisIMInitializeDeviceInstanceEx and // we are awaiting a call to MiniportInitialize. // if (pAdapt->MiniportInitPending == TRUE) { // // Try to cancel the pending IMInit process. // LocalStatus = NdisIMCancelInitializeDeviceInstance( DriverHandle, &pAdapt->DeviceName); if (LocalStatus == NDIS_STATUS_SUCCESS) { // // Successfully cancelled IM Initialization; our // Miniport Initialize routine will not be called // for this device. // pAdapt->MiniportInitPending = FALSE; ASSERT(pAdapt->MiniportHandle == NULL); } else { // // Our Miniport Initialize routine will be called // (may be running on another thread at this time). // Wait for it to finish. // NdisWaitEvent(&pAdapt->MiniportInitEvent, 0); ASSERT(pAdapt->MiniportInitPending == FALSE); } } #endif // !WIN9X // // Call NDIS to remove our device-instance. We do most of the work // inside the HaltHandler. // // The Handle will be NULL if our miniport Halt Handler has been called or // if the IM device was never initialized // if (pAdapt->MiniportHandle != NULL) { *Status = NdisIMDeInitializeDeviceInstance(pAdapt->MiniportHandle); if (*Status != NDIS_STATUS_SUCCESS) { *Status = NDIS_STATUS_FAILURE; } } else { // // We need to do some work here. // Close the binding below us // and release the memory allocated. // if(pAdapt->BindingHandle != NULL) { NdisResetEvent(&pAdapt->Event); NdisCloseAdapter(Status, pAdapt->BindingHandle); // // Wait for it to complete // if(*Status == NDIS_STATUS_PENDING) { NdisWaitEvent(&pAdapt->Event, 0); *Status = pAdapt->Status; } } else { // // Both Our MiniportHandle and Binding Handle should not be NULL. // *Status = NDIS_STATUS_FAILURE; ASSERT(0); } // // Free the memory here, if was not released earlier(by calling the HaltHandler) // NdisFreeMemory(pAdapt, sizeof(ADAPT), 0); } DBGPRINT(("<== PtUnbindAdapter: Adapt %p\n", pAdapt)); }
NDIS_STATUS MPQueryInformation( IN NDIS_HANDLE MiniportAdapterContext, IN NDIS_OID Oid, IN PVOID InformationBuffer, IN ULONG InformationBufferLength, OUT PULONG BytesWritten, OUT PULONG BytesNeeded ) /*++ Routine Description: Entry point called by NDIS to query for the value of the specified OID. Typical processing is to forward the query down to the underlying miniport. The following OIDs are filtered here: OID_PNP_QUERY_POWER - return success right here OID_GEN_SUPPORTED_GUIDS - do not forward, otherwise we will show up multiple instances of private GUIDs supported by the underlying miniport. OID_PNP_CAPABILITIES - we do send this down to the lower miniport, but the values returned are postprocessed before we complete this request; see PtRequestComplete. NOTE on OID_TCP_TASK_OFFLOAD - if this IM driver modifies the contents of data it passes through such that a lower miniport may not be able to perform TCP task offload, then it should not forward this OID down, but fail it here with the status NDIS_STATUS_NOT_SUPPORTED. This is to avoid performing incorrect transformations on data. If our miniport edge (upper edge) is at a low-power state, fail the request. If our protocol edge (lower edge) has been notified of a low-power state, we pend this request until the miniport below has been set to D0. Since requests to miniports are serialized always, at most a single request will be pended. Arguments: MiniportAdapterContext Pointer to the adapter structure Oid Oid for this query InformationBuffer Buffer for information InformationBufferLength Size of this buffer BytesWritten Specifies how much info is written BytesNeeded In case the buffer is smaller than what we need, tell them how much is needed Return Value: Return code from the NdisRequest below. --*/ { PADAPT pAdapt = (PADAPT)MiniportAdapterContext; NDIS_STATUS Status = NDIS_STATUS_FAILURE; do { if (Oid == OID_PNP_QUERY_POWER) { // // Do not forward this. // Status = NDIS_STATUS_SUCCESS; break; } if (Oid == OID_GEN_SUPPORTED_GUIDS) { // // Do not forward this, otherwise we will end up with multiple // instances of private GUIDs that the underlying miniport // supports. // Status = NDIS_STATUS_NOT_SUPPORTED; break; } if (Oid == OID_TCP_TASK_OFFLOAD) { // // Fail this -if- this driver performs data transformations // that can interfere with a lower driver's ability to offload // TCP tasks. // // Status = NDIS_STATUS_NOT_SUPPORTED; // break; // } // // If the miniport below is unbinding, just fail any request // NdisAcquireSpinLock(&pAdapt->Lock); if (pAdapt->UnbindingInProcess == TRUE) { NdisReleaseSpinLock(&pAdapt->Lock); Status = NDIS_STATUS_FAILURE; break; } NdisReleaseSpinLock(&pAdapt->Lock); // // All other queries are failed, if the miniport is not at D0, // if (pAdapt->MPDeviceState > NdisDeviceStateD0) { Status = NDIS_STATUS_FAILURE; break; } pAdapt->Request.RequestType = NdisRequestQueryInformation; pAdapt->Request.DATA.QUERY_INFORMATION.Oid = Oid; pAdapt->Request.DATA.QUERY_INFORMATION.InformationBuffer = InformationBuffer; pAdapt->Request.DATA.QUERY_INFORMATION.InformationBufferLength = InformationBufferLength; pAdapt->BytesNeeded = BytesNeeded; pAdapt->BytesReadOrWritten = BytesWritten; // // If the miniport below is binding, fail the request // NdisAcquireSpinLock(&pAdapt->Lock); if (pAdapt->UnbindingInProcess == TRUE) { NdisReleaseSpinLock(&pAdapt->Lock); Status = NDIS_STATUS_FAILURE; break; } // // If the Protocol device state is OFF, mark this request as being // pended. We queue this until the device state is back to D0. // if ((pAdapt->PTDeviceState > NdisDeviceStateD0) && (pAdapt->StandingBy == FALSE)) { pAdapt->QueuedRequest = TRUE; NdisReleaseSpinLock(&pAdapt->Lock); Status = NDIS_STATUS_PENDING; break; } // // This is in the process of powering down the system, always fail the request // if (pAdapt->StandingBy == TRUE) { NdisReleaseSpinLock(&pAdapt->Lock); Status = NDIS_STATUS_FAILURE; break; } pAdapt->OutstandingRequests = TRUE; NdisReleaseSpinLock(&pAdapt->Lock); // // default case, most requests will be passed to the miniport below // NdisRequest(&Status, pAdapt->BindingHandle, &pAdapt->Request); if (Status != NDIS_STATUS_PENDING) { PtRequestComplete(pAdapt, &pAdapt->Request, Status); Status = NDIS_STATUS_PENDING; } } while (FALSE); return(Status); }
NDIS_STATUS PtPnPNetEventSetPower( IN PADAPT pAdapt, IN PNET_PNP_EVENT pNetPnPEvent ) /*++ Routine Description: This is a notification to our protocol edge of the power state of the lower miniport. If it is going to a low-power state, we must wait here for all outstanding sends and requests to complete. NDIS 5.1: Since we use packet stacking, it is not sufficient to check usage of our local send packet pool to detect whether or not all outstanding sends have completed. For this, use the new API NdisQueryPendingIOCount. NDIS 5.1: Use the 5.1 API NdisIMNotifyPnPEvent to pass on PnP notifications to upper protocol(s). Arguments: pAdapt - Pointer to the adpater structure pNetPnPEvent - The Net Pnp Event. this contains the new device state Return Value: NDIS_STATUS_SUCCESS or the status returned by upper-layer protocols. --*/ { PNDIS_DEVICE_POWER_STATE pDeviceState =(PNDIS_DEVICE_POWER_STATE)(pNetPnPEvent->Buffer); NDIS_DEVICE_POWER_STATE PrevDeviceState = pAdapt->PTDeviceState; NDIS_STATUS Status; NDIS_STATUS ReturnStatus; #ifdef NDIS51 ULONG PendingIoCount = 0; #endif // NDIS51 ReturnStatus = NDIS_STATUS_SUCCESS; // // Set the Internal Device State, this blocks all new sends or receives // pAdapt->PTDeviceState = *pDeviceState; // // Check if the miniport below is going to a low power state. // if (*pDeviceState > NdisDeviceStateD0) { #ifdef NDIS51 // // Notify upper layer protocol(s) first. // if (pAdapt->MiniportHandle != NULL) { ReturnStatus = NdisIMNotifyPnPEvent(pAdapt->MiniportHandle, pNetPnPEvent); } #endif // NDIS51 // // If the miniport below is going to standby, fail all incoming requests // if (PrevDeviceState == NdisDeviceStateD0) { pAdapt->StandingBy = TRUE; } // // Wait for outstanding sends and requests to complete. // #ifdef NDIS51 do { Status = NdisQueryPendingIOCount(pAdapt->BindingHandle, &PendingIoCount); if ((Status != NDIS_STATUS_SUCCESS) || (PendingIoCount == 0)) { break; } NdisMSleep(2); } while (TRUE); #else while (NdisPacketPoolUsage(pAdapt->SendPacketPoolHandle) != 0) { NdisMSleep(2); } while (pAdapt->OutstandingRequests == TRUE) { // // sleep till outstanding requests complete // NdisMSleep(2); } #endif // NDIS51 ASSERT(NdisPacketPoolUsage(pAdapt->SendPacketPoolHandle) == 0); ASSERT(pAdapt->OutstandingRequests == FALSE); } else { // // The device below is being turned on. If we had a request // pending, send it down now. // if (pAdapt->QueuedRequest == TRUE) { pAdapt->QueuedRequest = FALSE; NdisRequest(&Status, pAdapt->BindingHandle, &pAdapt->Request); if (Status != NDIS_STATUS_PENDING) { PtRequestComplete(pAdapt, &pAdapt->Request, Status); } } // // If the physical miniport is powering up (from Low power state to D0), // clear the flag // if (PrevDeviceState > NdisDeviceStateD0) { pAdapt->StandingBy = FALSE; } #ifdef NDIS51 // // Pass on this notification to protocol(s) above // if (pAdapt->MiniportHandle) { ReturnStatus = NdisIMNotifyPnPEvent(pAdapt->MiniportHandle, pNetPnPEvent); } #endif // NDIS51 } return ReturnStatus; }