1 /* 2 * PROJECT: ReactOS DC21x4 Driver 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Power management 5 * COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean@protonmail.com> 6 */ 7 8 /* INCLUDES *******************************************************************/ 9 10 #include "dc21x4.h" 11 12 #include <debug.h> 13 14 /* FUNCTIONS ******************************************************************/ 15 16 static 17 CODE_SEG("PAGE") 18 VOID 19 DcDownloadPatternFilter( 20 _In_ PDC21X4_ADAPTER Adapter, 21 _In_ PDC_PATTERN_FILTER_BLOCK FilterBlock) 22 { 23 ULONG i; 24 25 PAGED_CODE(); 26 27 for (i = 0; i < sizeof(*FilterBlock) / sizeof(ULONG); ++i) 28 { 29 DC_WRITE(Adapter, DcCsr1_WakeUpFilter, FilterBlock->AsULONG[i]); 30 } 31 } 32 33 static 34 CODE_SEG("PAGE") 35 VOID 36 DcSetupWakeUpFilter( 37 _In_ PDC21X4_ADAPTER Adapter) 38 { 39 DC_PATTERN_FILTER_BLOCK FilterBlock; 40 41 PAGED_CODE(); 42 43 /* Save the address filtering */ 44 NdisMoveMemory(Adapter->SetupFrameSaved, Adapter->SetupFrame, DC_SETUP_FRAME_SIZE); 45 46 NdisZeroMemory(&FilterBlock, sizeof(FilterBlock)); 47 48 // TODO: Convert NDIS patterns to HW filter and prepare a setup frame 49 50 DcDownloadPatternFilter(Adapter, &FilterBlock); 51 } 52 53 static 54 CODE_SEG("PAGE") 55 VOID 56 DcProgramWakeUpEvents( 57 _In_ PDC21X4_ADAPTER Adapter) 58 { 59 ULONG WakeUpControl; 60 61 PAGED_CODE(); 62 63 /* Clear the wake-up events */ 64 WakeUpControl = (DC_WAKE_UP_STATUS_LINK_CHANGE | 65 DC_WAKE_UP_STATUS_MAGIC_PACKET | 66 DC_WAKE_UP_CONTROL_PATTERN_MATCH); 67 68 /* Convert NDIS flags to hardware-specific values */ 69 if (Adapter->WakeUpFlags & NDIS_PNP_WAKE_UP_LINK_CHANGE) 70 WakeUpControl |= DC_WAKE_UP_CONTROL_LINK_CHANGE; 71 if (Adapter->WakeUpFlags & NDIS_PNP_WAKE_UP_MAGIC_PACKET) 72 WakeUpControl |= DC_WAKE_UP_CONTROL_MAGIC_PACKET; 73 #if 0 // TODO: Pattern matching is not yet supported 74 if (Adapter->WakeUpFlags & NDIS_PNP_WAKE_UP_PATTERN_MATCH) 75 WakeUpControl |= DC_WAKE_UP_CONTROL_PATTERN_MATCH; 76 #endif 77 78 DC_WRITE(Adapter, DcCsr2_WakeUpControl, WakeUpControl); 79 } 80 81 static 82 CODE_SEG("PAGE") 83 VOID 84 DcPowerDown( 85 _In_ PDC21X4_ADAPTER Adapter) 86 { 87 ULONG SiaState, SerialInterface; 88 89 PAGED_CODE(); 90 91 /* Stop the receive and transmit processes */ 92 DcStopAdapter(Adapter, FALSE); 93 94 Adapter->CurrentInterruptMask = 0; 95 96 /* Enable the link integrity test bit */ 97 switch (Adapter->MediaNumber) 98 { 99 case MEDIA_AUI: 100 case MEDIA_BNC: 101 case MEDIA_HMR: 102 { 103 SiaState = DC_READ(Adapter, DcCsr14_SiaTxRx); 104 if (!(SiaState & DC_SIA_TXRX_LINK_TEST)) 105 { 106 SiaState |= DC_SIA_TXRX_LINK_TEST; 107 DC_WRITE(Adapter, DcCsr14_SiaTxRx, SiaState); 108 } 109 break; 110 } 111 112 default: 113 break; 114 } 115 116 /* Clear the MDC bit */ 117 SerialInterface = DC_READ(Adapter, DcCsr9_SerialInterface); 118 if (SerialInterface & DC_SERIAL_MII_MDC) 119 { 120 SerialInterface &= ~DC_SERIAL_MII_MDC; 121 DC_WRITE(Adapter, DcCsr9_SerialInterface, SerialInterface); 122 } 123 124 /* Unprotect PM access */ 125 DC_WRITE(Adapter, DcCsr0_BusMode, Adapter->BusMode | DC_BUS_MODE_ON_NOW_UNLOCK); 126 127 /* Program the requested WOL events */ 128 DcSetupWakeUpFilter(Adapter); 129 DcProgramWakeUpEvents(Adapter); 130 131 /* Protect PM access */ 132 DC_WRITE(Adapter, DcCsr0_BusMode, Adapter->BusMode); 133 } 134 135 static 136 CODE_SEG("PAGE") 137 VOID 138 DcPowerUp( 139 _In_ PDC21X4_ADAPTER Adapter) 140 { 141 PAGED_CODE(); 142 143 /* Restore the address filtering */ 144 NdisMoveMemory(Adapter->SetupFrame, Adapter->SetupFrameSaved, DC_SETUP_FRAME_SIZE); 145 146 /* Re-initialize the chip to leave D3 state */ 147 if (Adapter->PrevPowerState == NdisDeviceStateD3) 148 { 149 NT_VERIFY(DcSetupAdapter(Adapter) == TRUE); 150 } 151 else 152 { 153 /* Start the transmit process */ 154 Adapter->OpMode |= DC_OPMODE_TX_ENABLE; 155 DC_WRITE(Adapter, DcCsr6_OpMode, Adapter->OpMode); 156 157 /* Load the address recognition RAM */ 158 NT_VERIFY(DcSetupFrameDownload(Adapter, TRUE) == TRUE); 159 } 160 161 DcStartAdapter(Adapter); 162 } 163 164 CODE_SEG("PAGE") 165 VOID 166 NTAPI 167 DcPowerWorker( 168 _In_ PNDIS_WORK_ITEM WorkItem, 169 _In_opt_ PVOID Context) 170 { 171 PDC21X4_ADAPTER Adapter = Context; 172 173 UNREFERENCED_PARAMETER(WorkItem); 174 175 PAGED_CODE(); 176 177 if (Adapter->PowerState == NdisDeviceStateD0) 178 { 179 DcPowerUp(Adapter); 180 } 181 else 182 { 183 DcPowerDown(Adapter); 184 } 185 Adapter->PrevPowerState = Adapter->PowerState; 186 187 NdisMSetInformationComplete(Adapter->AdapterHandle, NDIS_STATUS_SUCCESS); 188 } 189 190 NDIS_STATUS 191 DcSetPower( 192 _In_ PDC21X4_ADAPTER Adapter, 193 _In_ NDIS_DEVICE_POWER_STATE PowerState) 194 { 195 INFO("Power state %u\n", PowerState); 196 197 Adapter->PowerState = PowerState; 198 199 NdisScheduleWorkItem(&Adapter->PowerWorkItem); 200 201 return NDIS_STATUS_PENDING; 202 } 203 204 NDIS_STATUS 205 DcRemoveWakeUpPattern( 206 _In_ PDC21X4_ADAPTER Adapter, 207 _In_ PNDIS_PM_PACKET_PATTERN PmPattern) 208 { 209 // TODO: Not implemented 210 ERR("FIXME: Not implemented\n"); 211 return NDIS_STATUS_NOT_SUPPORTED; 212 } 213 214 NDIS_STATUS 215 DcAddWakeUpPattern( 216 _In_ PDC21X4_ADAPTER Adapter, 217 _In_ PNDIS_PM_PACKET_PATTERN PmPattern) 218 { 219 // TODO: Not implemented 220 ERR("FIXME: Not implemented\n"); 221 return NDIS_STATUS_NOT_SUPPORTED; 222 } 223 224 VOID 225 DcPowerSave( 226 _In_ PDC21X4_ADAPTER Adapter, 227 _In_ BOOLEAN Enable) 228 { 229 ULONG ConfigValue; 230 231 if (!(Adapter->Features & DC_HAS_POWER_SAVING)) 232 return; 233 234 NdisReadPciSlotInformation(Adapter->AdapterHandle, 235 0, 236 DC_PCI_DEVICE_CONFIG, 237 &ConfigValue, 238 sizeof(ConfigValue)); 239 240 ConfigValue &= ~DC_PCI_DEVICE_CONFIG_SLEEP; 241 242 if (Enable) 243 ConfigValue |= DC_PCI_DEVICE_CONFIG_SNOOZE; 244 else 245 ConfigValue &= ~DC_PCI_DEVICE_CONFIG_SNOOZE; 246 247 NdisWritePciSlotInformation(Adapter->AdapterHandle, 248 0, 249 DC_PCI_DEVICE_CONFIG, 250 &ConfigValue, 251 sizeof(ConfigValue)); 252 } 253