VOID NICFillPoMgmtCaps ( __in PFDO_DATA FdoData, __out PNDIS_PNP_CAPABILITIES pPower_Management_Capabilities, __inout PNDIS_STATUS pStatus, __inout PULONG pulInfoLen ) /*++ Routine Description: Fills in the Power Managment structure depending the capabilities of the software driver and the card. Currently this is only supported on 82559 Version of the driver Arguments: FdoData Pointer to the FdoData structure pPower_Management_Capabilities - Power management struct as defined in the DDK, pStatus Status to be returned by the request, pulInfoLen Length of the pPowerManagmentCapabilites Return Value: Success or failure depending on the type of card --*/ { BOOLEAN bIsPoMgmtSupported; bIsPoMgmtSupported = IsPoMgmtSupported(FdoData); if (bIsPoMgmtSupported == TRUE) { pPower_Management_Capabilities->Flags = NDIS_DEVICE_WAKE_UP_ENABLE; pPower_Management_Capabilities->WakeUpCapabilities.MinMagicPacketWakeUp = NdisDeviceStateUnspecified; pPower_Management_Capabilities->WakeUpCapabilities.MinPatternWakeUp = NdisDeviceStateD3; pPower_Management_Capabilities->WakeUpCapabilities.MinLinkChangeWakeUp = NdisDeviceStateUnspecified; *pulInfoLen = sizeof (*pPower_Management_Capabilities); *pStatus = STATUS_SUCCESS; } else { RtlZeroMemory (pPower_Management_Capabilities, sizeof(*pPower_Management_Capabilities)); *pStatus = STATUS_NOT_SUPPORTED; *pulInfoLen = 0; } }
VOID HwSetWakeUpConfigure( __in PFDO_DATA FdoData, PUCHAR pPoMgmtConfigType, UINT WakeUpParameter ) { if (IsPoMgmtSupported( FdoData) == TRUE) { (*pPoMgmtConfigType)= ((*pPoMgmtConfigType)| CB_WAKE_ON_LINK_BYTE9 |CB_WAKE_ON_ARP_PKT_BYTE9 ); } }
VOID HwSetWakeUpConfigure( IN PFDO_DATA FdoData, PUCHAR pPoMgmtConfigType, UINT WakeUpParameter ) { UNREFERENCED_PARAMETER( WakeUpParameter ); if (IsPoMgmtSupported( FdoData) == TRUE) { (*pPoMgmtConfigType)= ((*pPoMgmtConfigType) | CB_WAKE_ON_LINK_BYTE9 | CB_WAKE_ON_ARP_PKT_BYTE9 ); } }
NTSTATUS NICSetPower( PFDO_DATA FdoData , WDF_POWER_DEVICE_STATE PowerState ) /*++ Routine Description: This routine is called when the FdoData receives a SetPower request. It redirects the call to an appropriate routine to Set the New PowerState Arguments: FdoData Pointer to the FdoData structure PowerState NewPowerState Return Value: NTSTATUS Code --*/ { NTSTATUS status = STATUS_SUCCESS; if(IsPoMgmtSupported(FdoData)){ if (PowerState == PowerDeviceD0) { TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "Entering fully on state\n"); MPSetPowerD0 (FdoData); } else { TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "Entering a deeper sleep state\n"); status = MPSetPowerLow (FdoData, PowerState); } } return status; }
NTSTATUS NICHandleSetOidRequest( __in PFDO_DATA FdoData, __in PIRP Irp ) /*++ Routine Description: This routine handles ioctl request for Set OIDs. Most of the IOCTL requests are only if the upper edge is NDIS. Arguments: Return Value: --*/ { NTSTATUS status = STATUS_SUCCESS; PNDISPROT_SET_OID pSet; NDIS_OID Oid; ULONG PacketFilter; PVOID InformationBuffer = NULL; ULONG InformationBufferLength = 0; KIRQL oldIrql; PVOID DataBuffer; ULONG BufferLength, unUsed; PIO_STACK_LOCATION pIrpSp; DEVICE_POWER_STATE newDeviceState, oldDeviceState; pIrpSp = IoGetCurrentIrpStackLocation(Irp); DataBuffer = Irp->AssociatedIrp.SystemBuffer; BufferLength = pIrpSp->Parameters.DeviceIoControl.InputBufferLength; DebugPrint(LOUD, DBG_IOCTLS, "--> HandleSetOIDRequest\n"); Oid = 0; do { if (BufferLength < sizeof(NDISPROT_SET_OID)) { status = STATUS_BUFFER_OVERFLOW; break; } pSet = (PNDISPROT_SET_OID)DataBuffer; Oid = pSet->Oid; InformationBuffer = &pSet->Data[0]; InformationBufferLength = BufferLength - FIELD_OFFSET(NDISPROT_SET_OID, Data); switch(Oid) { case OID_802_3_MULTICAST_LIST: // // Verify the length // if (InformationBufferLength % ETH_LENGTH_OF_ADDRESS != 0) { return(STATUS_INVALID_BUFFER_SIZE); } // // Save the number of MC list size // FdoData->MCAddressCount = InformationBufferLength / ETH_LENGTH_OF_ADDRESS; ASSERT(FdoData->MCAddressCount <= NIC_MAX_MCAST_LIST); InformationBufferLength = InformationBufferLength > sizeof(FdoData->MCList) ? sizeof(FdoData->MCList):InformationBufferLength; // // Save the MC list // RtlMoveMemory( FdoData->MCList, InformationBuffer, InformationBufferLength); KeAcquireSpinLock(&FdoData->Lock, &oldIrql); KeAcquireSpinLockAtDpcLevel(&FdoData->RcvLock); status = NICSetMulticastList(FdoData); KeReleaseSpinLockFromDpcLevel(&FdoData->RcvLock); KeReleaseSpinLock(&FdoData->Lock, oldIrql); break; case OID_GEN_CURRENT_PACKET_FILTER: // // Verify the Length // if (InformationBufferLength != sizeof(ULONG)) { return(STATUS_INVALID_BUFFER_SIZE); } RtlMoveMemory(&PacketFilter, InformationBuffer, sizeof(ULONG)); // // any bits not supported? // if (PacketFilter & ~NIC_SUPPORTED_FILTERS) { return(STATUS_NOT_SUPPORTED); } // // any filtering changes? // if (PacketFilter == FdoData->PacketFilter) { break; } KeAcquireSpinLock(&FdoData->Lock, &oldIrql); KeAcquireSpinLockAtDpcLevel(&FdoData->RcvLock); if (MP_TEST_FLAG(FdoData, fMP_ADAPTER_LINK_DETECTION)) { // // The device is busy doing link detection. Let us queue // the IRP. When the link detection is over, the watchdog // timer DPC will complete this IRP. // ASSERT(!FdoData->SetRequest); status = PciDrvQueueIoctlIrp(FdoData, Irp); KeReleaseSpinLockFromDpcLevel(&FdoData->RcvLock); KeReleaseSpinLock(&FdoData->Lock, oldIrql); break; } status = NICSetPacketFilter( FdoData, PacketFilter); KeReleaseSpinLockFromDpcLevel(&FdoData->RcvLock); KeReleaseSpinLock(&FdoData->Lock, oldIrql); if (status == STATUS_SUCCESS) { FdoData->PacketFilter = PacketFilter; } break; case OID_PNP_SET_POWER: if (InformationBufferLength != sizeof(NDIS_DEVICE_POWER_STATE )) { return(STATUS_BUFFER_TOO_SMALL); } newDeviceState = *(PDEVICE_POWER_STATE UNALIGNED)InformationBuffer; oldDeviceState = FdoData->DevicePowerState; FdoData->DevicePowerState = newDeviceState; if (oldDeviceState == PowerDeviceD0) { status = PciDrvPowerBeginQueuingIrps( FdoData->Self, 1, // One for current OID request. FALSE // Do not query for state change. ); ASSERT(NT_SUCCESS(status)); } // // Set the power state - Cannot fail this request // status = NICSetPower(FdoData, newDeviceState ); if (status != STATUS_SUCCESS) { DebugPrint(ERROR, DBG_IOCTLS, "SET Power: Hardware error !!!\n"); break; } if (newDeviceState == PowerDeviceD0) { // // Our hardware is now on again. Here we empty our existing queue of // requests and let in new ones. // FdoData->QueueState = AllowRequests; PciDrvProcessQueuedRequests(FdoData); } status = STATUS_SUCCESS; break; case OID_PNP_ADD_WAKE_UP_PATTERN: // // call a function that would program the adapter's wake // up pattern, return success // DebugPrint(TRACE, DBG_IOCTLS, "--> OID_PNP_ADD_WAKE_UP_PATTERN\n"); if (IsPoMgmtSupported(FdoData) ) { status = NICAddWakeUpPattern(FdoData, InformationBuffer, InformationBufferLength, &unUsed, &unUsed); } else { status = STATUS_NOT_SUPPORTED; } break; case OID_PNP_REMOVE_WAKE_UP_PATTERN: // // call a function that would remove the adapter's wake // up pattern, return success // DebugPrint(TRACE, DBG_IOCTLS, "--> OID_PNP_ADD_WAKE_UP_PATTERN\n"); if (IsPoMgmtSupported(FdoData) ) { status = NICRemoveWakeUpPattern(FdoData, InformationBuffer, InformationBufferLength, &unUsed, &unUsed); } else { status = STATUS_NOT_SUPPORTED; } break; case OID_PNP_ENABLE_WAKE_UP: // // call a function that would enable wake up on the adapter // return success // DebugPrint(TRACE, DBG_IOCTLS, "--> OID_PNP_ENABLE_WAKE_UP\n"); if (IsPoMgmtSupported(FdoData)) { ULONG WakeUpEnable; RtlMoveMemory(&WakeUpEnable, InformationBuffer,sizeof(ULONG)); // // The WakeUpEable can only be 0, or NDIS_PNP_WAKE_UP_PATTERN_MATCH since the driver only // supports wake up pattern match // if ((WakeUpEnable != 0) && ((WakeUpEnable & NDIS_PNP_WAKE_UP_PATTERN_MATCH) != NDIS_PNP_WAKE_UP_PATTERN_MATCH )) { status = STATUS_NOT_SUPPORTED; FdoData->AllowWakeArming = FALSE; break; } // // When the driver goes to low power state, it would check WakeUpEnable to decide // which wake up methed it should use to wake up the machine. If WakeUpEnable is 0, // no wake up method is enabled. // FdoData->AllowWakeArming = TRUE; status = STATUS_SUCCESS; } else { status = STATUS_NOT_SUPPORTED; } break; default: status = STATUS_NOT_SUPPORTED; break; } }while (FALSE); DebugPrint(LOUD, DBG_IOCTLS, "<-- HandleSetOIDRequest\n"); return (status); }
NTSTATUS PciDrvQueryWmiDataBlock( PDEVICE_OBJECT DeviceObject, PIRP Irp, ULONG GuidIndex, ULONG InstanceIndex, ULONG InstanceCount, PULONG InstanceLengthArray, ULONG OutBufferSize, PUCHAR Buffer ) /*++ Routine Description: This routine is a callback into the driver to query for the contents of a data block. When the driver has finished filling the data block it must call WmiCompleteRequest to complete the irp. The driver can return STATUS_PENDING if the irp cannot be completed immediately. Arguments: DeviceObject is the device whose data block is being queried Irp is the Irp that makes this request GuidIndex is the index into the list of guids provided when the device registered InstanceIndex is the index that denotes which instance of the data block is being queried. InstanceCount is the number of instances expected to be returned for the data block. InstanceLengthArray is a pointer to an array of ULONG that returns the lengths of each instance of the data block. If this is NULL then there was not enough space in the output buffer to fulfill the request so the irp should be completed with the buffer needed. BufferAvail on has the maximum size available to write the data block. Buffer on return is filled with the returned data block Return Value: status --*/ { PFDO_DATA fdoData; NTSTATUS status = STATUS_WMI_GUID_NOT_FOUND; ULONG size = 0; PAGED_CODE(); DebugPrint(TRACE, DBG_WMI, "Entered PciDrvQueryWmiDataBlock\n"); // // Only ever registers 1 instance per guid ASSERT((InstanceIndex == 0) && (InstanceCount == 1)); fdoData = (PFDO_DATA) DeviceObject->DeviceExtension; switch (GuidIndex) { case WMI_PCIDRV_DRIVER_INFORMATION: size = sizeof (PCIDRV_WMI_STD_DATA); if (OutBufferSize < size ) { status = STATUS_BUFFER_TOO_SMALL; break; } // // Copy the structure information // * (PPCIDRV_WMI_STD_DATA) Buffer = fdoData->StdDeviceData; *InstanceLengthArray = size ; status = STATUS_SUCCESS; break; case WMI_POWER_DEVICE_WAKE_ENABLE: // // Here we return the current preference of the user for wait-waking // the system. We read(IoOpenDeviceRegistryKey/ZwQueryValueKey) // the default value written by the INF file in the HW registery. // If the user changes his preference, then we must record // the changes in the registry to have that in affect across // boots. // size = sizeof(BOOLEAN); if (OutBufferSize < size) { status = STATUS_BUFFER_TOO_SMALL; break; } if(IsPoMgmtSupported(fdoData)){ *(PBOOLEAN) Buffer = PciDrvGetWaitWakeEnableState(fdoData) ; *InstanceLengthArray = size; status = STATUS_SUCCESS; } break; case WMI_POWER_DEVICE_ENABLE: // // The same rule discussed above applies here // for responding to the query. // size = sizeof(BOOLEAN); if (OutBufferSize < size) { status = STATUS_BUFFER_TOO_SMALL; break; } if(IsPoMgmtSupported(fdoData)){ *(PBOOLEAN) Buffer = PciDrvGetPowerSaveEnableState(fdoData); *InstanceLengthArray = size; status = STATUS_SUCCESS; } break; case WMI_POWER_CONSERVATION_IDLE_TIME: size = sizeof(ULONG); if (OutBufferSize < size) { status = STATUS_BUFFER_TOO_SMALL; break; } // // Convert the value back to secs. // *(PULONG) Buffer = (ULONG)(fdoData->ConservationIdleTime/-SECOND_TO_100NS); *InstanceLengthArray = size; status = STATUS_SUCCESS; break; case WMI_POWER_PERFORMANCE_IDLE_TIME: size = sizeof(ULONG); if (OutBufferSize < size) { status = STATUS_BUFFER_TOO_SMALL; break; } // // Convert the value back to secs. // *(PULONG) Buffer = (ULONG)(fdoData->PerformanceIdleTime/-SECOND_TO_100NS); *InstanceLengthArray = size; status = STATUS_SUCCESS; break; default: status = STATUS_WMI_GUID_NOT_FOUND; } status = WmiCompleteRequest( DeviceObject, Irp, status, size, IO_NO_INCREMENT); return status; }
NTSTATUS PciDrvSetWmiDataBlock( PDEVICE_OBJECT DeviceObject, PIRP Irp, ULONG GuidIndex, ULONG InstanceIndex, ULONG BufferSize, PUCHAR Buffer ) /*++ Routine Description: This routine is a callback into the driver to set the contents of a data block. When the driver has finished filling the data block it must call WmiCompleteRequest to complete the irp. The driver can return STATUS_PENDING if the irp cannot be completed immediately. Arguments: DeviceObject is the device whose data block is being queried Irp is the Irp that makes this request GuidIndex is the index into the list of guids provided when the device registered InstanceIndex is the index that denotes which instance of the data block is being queried. BufferSize has the size of the data block passed Buffer has the new values for the data block Return Value: status --*/ { PFDO_DATA fdoData; NTSTATUS status = STATUS_WMI_GUID_NOT_FOUND; BOOLEAN waitWakeEnabled; BOOLEAN powerSaveEnabled; LONGLONG newIdleTime, prevIdleTime; ULONG requiredSize = 0; PAGED_CODE(); fdoData = (PFDO_DATA) DeviceObject->DeviceExtension; DebugPrint(TRACE, DBG_WMI, "Entered PciDrvSetWmiDataBlock\n"); switch(GuidIndex) { case WMI_PCIDRV_DRIVER_INFORMATION: // // We will update only writable elements. // requiredSize = sizeof(PCIDRV_WMI_STD_DATA); if (BufferSize < requiredSize) { status = STATUS_BUFFER_TOO_SMALL; break; } DebugLevel = fdoData->StdDeviceData.DebugPrintLevel = ((PPCIDRV_WMI_STD_DATA)Buffer)->DebugPrintLevel; status = STATUS_SUCCESS; break; case WMI_POWER_DEVICE_WAKE_ENABLE: // // If the wait-wake state is true (box is checked), we send a IRP_MN_WAIT_WAKE // irp to the bus driver. If it's FALSE, we cancel it. // Every time the user changes his preference, // we write that to the registry to carry over his preference across boot. // If the user tries to enable wait-wake, and if the driver stack is not // able to do, it will reset the value in the registry to indicate that // the device is incapable of wait-waking the system. // requiredSize = sizeof(BOOLEAN); if (BufferSize < requiredSize) { status = STATUS_BUFFER_TOO_SMALL; break; } if(IsPoMgmtSupported(fdoData)){ waitWakeEnabled = *(PBOOLEAN) Buffer; PciDrvSetWaitWakeEnableState(fdoData, waitWakeEnabled); if (waitWakeEnabled) { PciDrvArmForWake(fdoData, FALSE); } else { PciDrvDisarmWake(fdoData, FALSE); } status = STATUS_SUCCESS; } break; case WMI_POWER_DEVICE_ENABLE: requiredSize = sizeof(BOOLEAN); if (BufferSize < requiredSize) { status = STATUS_BUFFER_TOO_SMALL; break; } if(IsPoMgmtSupported(fdoData)){ powerSaveEnabled = *(PBOOLEAN) Buffer; PciDrvSetPowerSaveEnableState(fdoData, powerSaveEnabled); if(powerSaveEnabled) { PciDrvRegisterForIdleDetection(fdoData, FALSE); } else { PciDrvDeregisterIdleDetection(fdoData, FALSE); } status = STATUS_SUCCESS; } break; case WMI_POWER_CONSERVATION_IDLE_TIME: requiredSize = sizeof(ULONG); if (BufferSize < requiredSize) { status = STATUS_BUFFER_TOO_SMALL; break; } newIdleTime = *(PULONG) Buffer; newIdleTime = max(newIdleTime, PCIDRV_MIN_IDLE_TIME); // // Convert that to ms time units // newIdleTime = (LONGLONG) -SECOND_TO_100NS * newIdleTime; prevIdleTime = fdoData->ConservationIdleTime; fdoData->ConservationIdleTime = newIdleTime; if(IsPoMgmtSupported(fdoData) && newIdleTime != prevIdleTime){ // if not setting the same value // // Reset the timer by deregistering and registering the Idle // detection. // PciDrvDeregisterIdleDetection(fdoData, FALSE); PciDrvRegisterForIdleDetection(fdoData, FALSE); } status = STATUS_SUCCESS; break; case WMI_POWER_PERFORMANCE_IDLE_TIME: requiredSize = sizeof(ULONG); if (BufferSize < requiredSize) { status = STATUS_BUFFER_TOO_SMALL; break; } newIdleTime = *(PULONG) Buffer; newIdleTime = max(newIdleTime, PCIDRV_MIN_IDLE_TIME); // // Convert that to ms time units // newIdleTime = (LONGLONG) -SECOND_TO_100NS * newIdleTime; prevIdleTime = fdoData->PerformanceIdleTime; fdoData->PerformanceIdleTime = newIdleTime; if(IsPoMgmtSupported(fdoData) && newIdleTime != prevIdleTime){ // if not setting the same value // // Reset the timer by deregistering and registering the Idle // detection. // PciDrvDeregisterIdleDetection(fdoData, FALSE); PciDrvRegisterForIdleDetection(fdoData, FALSE); } status = STATUS_SUCCESS; break; default: status = STATUS_WMI_GUID_NOT_FOUND; } status = WmiCompleteRequest( DeviceObject, Irp, status, requiredSize, IO_NO_INCREMENT); return(status); }