1 /* 2 * PROJECT: ReactOS DC21x4 Driver 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Miniport information callbacks 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 /* GLOBALS ********************************************************************/ 15 16 static const NDIS_OID DcpSupportedOidList[] = 17 { 18 OID_GEN_SUPPORTED_LIST, 19 OID_GEN_CURRENT_PACKET_FILTER, 20 OID_GEN_HARDWARE_STATUS, 21 OID_GEN_MEDIA_SUPPORTED, 22 OID_GEN_MEDIA_IN_USE, 23 OID_GEN_MAXIMUM_LOOKAHEAD, 24 OID_GEN_MAXIMUM_FRAME_SIZE, 25 OID_GEN_MAXIMUM_SEND_PACKETS, 26 OID_GEN_LINK_SPEED, 27 OID_GEN_TRANSMIT_BUFFER_SPACE, 28 OID_GEN_RECEIVE_BUFFER_SPACE, 29 OID_GEN_RECEIVE_BLOCK_SIZE, 30 OID_GEN_TRANSMIT_BLOCK_SIZE, 31 OID_GEN_VENDOR_ID, 32 OID_GEN_VENDOR_DESCRIPTION, 33 OID_GEN_VENDOR_DRIVER_VERSION, 34 OID_GEN_CURRENT_LOOKAHEAD, 35 OID_GEN_DRIVER_VERSION, 36 OID_GEN_MAXIMUM_TOTAL_SIZE, 37 OID_GEN_MAC_OPTIONS, 38 OID_GEN_MEDIA_CONNECT_STATUS, 39 OID_802_3_PERMANENT_ADDRESS, 40 OID_802_3_CURRENT_ADDRESS, 41 OID_802_3_MULTICAST_LIST, 42 OID_802_3_MAXIMUM_LIST_SIZE, 43 44 /* Statistics */ 45 OID_GEN_XMIT_OK, 46 OID_GEN_RCV_OK, 47 OID_GEN_XMIT_ERROR, 48 OID_GEN_RCV_ERROR, 49 OID_GEN_RCV_NO_BUFFER, 50 OID_GEN_DIRECTED_FRAMES_RCV, 51 OID_GEN_MULTICAST_FRAMES_RCV, 52 OID_GEN_BROADCAST_FRAMES_RCV, 53 OID_GEN_RCV_CRC_ERROR, 54 OID_GEN_TRANSMIT_QUEUE_LENGTH, 55 OID_802_3_RCV_ERROR_ALIGNMENT, 56 OID_802_3_XMIT_ONE_COLLISION, 57 OID_802_3_XMIT_MORE_COLLISIONS, 58 OID_802_3_XMIT_DEFERRED, 59 OID_802_3_XMIT_MAX_COLLISIONS, 60 OID_802_3_RCV_OVERRUN, 61 OID_802_3_XMIT_UNDERRUN, 62 OID_802_3_XMIT_HEARTBEAT_FAILURE, 63 OID_802_3_XMIT_TIMES_CRS_LOST, 64 OID_802_3_XMIT_LATE_COLLISIONS, 65 66 /* Power management */ 67 OID_PNP_CAPABILITIES, 68 OID_PNP_SET_POWER, 69 OID_PNP_QUERY_POWER, 70 OID_PNP_ADD_WAKE_UP_PATTERN, 71 OID_PNP_REMOVE_WAKE_UP_PATTERN, 72 OID_PNP_ENABLE_WAKE_UP 73 }; 74 75 /* FUNCTIONS ******************************************************************/ 76 77 static 78 VOID 79 DcQueryStatisticCounter( 80 _In_ PDC21X4_ADAPTER Adapter, 81 _In_ NDIS_OID Oid, 82 _Out_ PULONG64 Counter) 83 { 84 /* When there is no workaround, this function is used to read the hardware RX counters */ 85 if (!(Adapter->Features & DC_NEED_RX_OVERFLOW_WORKAROUND)) 86 { 87 ULONG RxCounters; 88 89 /* 90 * Read the RX missed frame counter. Note that the RX overflow counter is not supported 91 * on older chips without the workaround enabled and reads will return 0xFFFE****. 92 */ 93 RxCounters = DC_READ(Adapter, DcCsr8_RxCounters); 94 95 Adapter->Statistics.ReceiveNoBuffers += RxCounters & DC_COUNTER_RX_NO_BUFFER_MASK; 96 } 97 98 switch (Oid) 99 { 100 case OID_GEN_XMIT_OK: 101 *Counter = Adapter->Statistics.TransmitOk; 102 break; 103 case OID_GEN_RCV_OK: 104 *Counter = Adapter->Statistics.ReceiveOk; 105 break; 106 case OID_GEN_XMIT_ERROR: 107 *Counter = Adapter->Statistics.TransmitErrors; 108 break; 109 case OID_GEN_RCV_ERROR: 110 *Counter = Adapter->Statistics.ReceiveErrors; 111 break; 112 case OID_GEN_RCV_NO_BUFFER: 113 *Counter = Adapter->Statistics.ReceiveNoBuffers; 114 break; 115 case OID_GEN_DIRECTED_FRAMES_RCV: 116 *Counter = Adapter->Statistics.ReceiveUnicast; 117 break; 118 case OID_GEN_MULTICAST_FRAMES_RCV: 119 *Counter = Adapter->Statistics.ReceiveMulticast; 120 break; 121 case OID_GEN_BROADCAST_FRAMES_RCV: 122 *Counter = Adapter->Statistics.ReceiveBroadcast; 123 break; 124 case OID_GEN_RCV_CRC_ERROR: 125 *Counter = Adapter->Statistics.ReceiveCrcErrors; 126 break; 127 case OID_802_3_RCV_ERROR_ALIGNMENT: 128 *Counter = Adapter->Statistics.ReceiveAlignmentErrors; 129 break; 130 case OID_802_3_XMIT_ONE_COLLISION: 131 *Counter = Adapter->Statistics.TransmitOneRetry; 132 break; 133 case OID_802_3_XMIT_MORE_COLLISIONS: 134 *Counter = Adapter->Statistics.TransmitMoreCollisions; 135 break; 136 case OID_802_3_XMIT_DEFERRED: 137 *Counter = Adapter->Statistics.TransmitDeferred; 138 break; 139 case OID_802_3_XMIT_MAX_COLLISIONS: 140 *Counter = Adapter->Statistics.TransmitExcessiveCollisions; 141 break; 142 case OID_802_3_RCV_OVERRUN: 143 *Counter = Adapter->Statistics.ReceiveOverrunErrors; 144 break; 145 case OID_802_3_XMIT_UNDERRUN: 146 *Counter = Adapter->Statistics.TransmitUnderrunErrors; 147 break; 148 case OID_802_3_XMIT_HEARTBEAT_FAILURE: 149 *Counter = Adapter->Statistics.TransmitHeartbeatErrors; 150 break; 151 case OID_802_3_XMIT_TIMES_CRS_LOST: 152 *Counter = Adapter->Statistics.TransmitLostCarrierSense; 153 break; 154 case OID_802_3_XMIT_LATE_COLLISIONS: 155 *Counter = Adapter->Statistics.TransmitLateCollisions; 156 break; 157 158 default: 159 ASSERT(FALSE); 160 UNREACHABLE; 161 break; 162 } 163 } 164 165 static 166 ULONG 167 DcGetLinkSpeed( 168 _In_ PDC21X4_ADAPTER Adapter) 169 { 170 ULONG LinkSpeedMbps; 171 172 switch (Adapter->MediaNumber) 173 { 174 case MEDIA_HMR: 175 LinkSpeedMbps = 1; 176 break; 177 178 case MEDIA_10T: 179 case MEDIA_BNC: 180 case MEDIA_AUI: 181 case MEDIA_10T_FD: 182 LinkSpeedMbps = 10; 183 break; 184 185 case MEDIA_100TX_HD: 186 case MEDIA_100TX_FD: 187 case MEDIA_100T4: 188 case MEDIA_100FX_HD: 189 case MEDIA_100FX_FD: 190 LinkSpeedMbps = 100; 191 break; 192 193 case MEDIA_MII: 194 LinkSpeedMbps = Adapter->LinkSpeedMbps; 195 break; 196 197 default: 198 ASSERT(FALSE); 199 UNREACHABLE; 200 break; 201 } 202 203 return LinkSpeedMbps; 204 } 205 206 NDIS_STATUS 207 NTAPI 208 DcQueryInformation( 209 _In_ NDIS_HANDLE MiniportAdapterContext, 210 _In_ NDIS_OID Oid, 211 _In_ PVOID InformationBuffer, 212 _In_ ULONG InformationBufferLength, 213 _Out_ PULONG BytesWritten, 214 _Out_ PULONG BytesNeeded) 215 { 216 PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext; 217 NDIS_STATUS Status = NDIS_STATUS_SUCCESS; 218 ULONG InfoLength; 219 PVOID InfoPtr; 220 union _GENERIC_INFORMATION 221 { 222 USHORT Ushort; 223 ULONG Ulong; 224 ULONG64 Ulong64; 225 NDIS_MEDIUM Medium; 226 NDIS_HARDWARE_STATUS Status; 227 NDIS_DEVICE_POWER_STATE PowerState; 228 } GenericInfo; 229 230 InfoLength = sizeof(ULONG); 231 InfoPtr = &GenericInfo; 232 233 switch (Oid) 234 { 235 case OID_GEN_SUPPORTED_LIST: 236 InfoPtr = (PVOID)&DcpSupportedOidList; 237 InfoLength = sizeof(DcpSupportedOidList); 238 break; 239 240 case OID_GEN_CURRENT_PACKET_FILTER: 241 GenericInfo.Ulong = Adapter->PacketFilter; 242 break; 243 244 case OID_802_3_MULTICAST_LIST: 245 InfoPtr = Adapter->MulticastList; 246 InfoLength = Adapter->MulticastCount * ETH_LENGTH_OF_ADDRESS; 247 break; 248 249 case OID_802_3_MAXIMUM_LIST_SIZE: 250 GenericInfo.Ulong = Adapter->MulticastMaxEntries; 251 break; 252 253 case OID_GEN_MEDIA_SUPPORTED: 254 case OID_GEN_MEDIA_IN_USE: 255 { 256 GenericInfo.Medium = NdisMedium802_3; 257 InfoLength = sizeof(NDIS_MEDIUM); 258 break; 259 } 260 261 case OID_GEN_HARDWARE_STATUS: 262 { 263 ULONG InterruptStatus; 264 265 /* NOTE: Reading the status register has no effect on the events */ 266 InterruptStatus = DC_READ(Adapter, DcCsr5_Status); 267 268 /* Inserted into the motherboard */ 269 if (InterruptStatus != 0xFFFFFFFF) 270 GenericInfo.Status = NdisHardwareStatusReady; 271 else 272 GenericInfo.Status = NdisHardwareStatusNotReady; 273 274 InfoLength = sizeof(NDIS_HARDWARE_STATUS); 275 break; 276 } 277 278 case OID_GEN_MAXIMUM_FRAME_SIZE: 279 case OID_GEN_MAXIMUM_LOOKAHEAD: 280 case OID_GEN_CURRENT_LOOKAHEAD: 281 GenericInfo.Ulong = DC_MAXIMUM_FRAME_SIZE - DC_ETHERNET_HEADER_SIZE; 282 break; 283 284 case OID_GEN_MAXIMUM_TOTAL_SIZE: 285 GenericInfo.Ulong = DC_MAXIMUM_FRAME_SIZE; 286 break; 287 288 case OID_GEN_TRANSMIT_BLOCK_SIZE: 289 GenericInfo.Ulong = DC_TRANSMIT_BLOCK_SIZE; 290 break; 291 292 case OID_GEN_TRANSMIT_BUFFER_SPACE: 293 GenericInfo.Ulong = DC_TRANSMIT_BLOCK_SIZE * DC_TRANSMIT_BLOCKS; 294 break; 295 296 case OID_GEN_RECEIVE_BLOCK_SIZE: 297 GenericInfo.Ulong = DC_RECEIVE_BLOCK_SIZE; 298 break; 299 300 case OID_GEN_RECEIVE_BUFFER_SPACE: 301 GenericInfo.Ulong = DC_RECEIVE_BLOCK_SIZE * Adapter->RcbCount; 302 break; 303 304 case OID_GEN_LINK_SPEED: 305 GenericInfo.Ulong = DcGetLinkSpeed(Adapter) * 10000; 306 break; 307 308 case OID_GEN_VENDOR_ID: 309 GenericInfo.Ulong = 0; 310 GenericInfo.Ulong |= (Adapter->PermanentMacAddress[0] << 16); 311 GenericInfo.Ulong |= (Adapter->PermanentMacAddress[1] << 8); 312 GenericInfo.Ulong |= (Adapter->PermanentMacAddress[2] & 0xFF); 313 break; 314 315 case OID_GEN_VENDOR_DESCRIPTION: 316 { 317 static const CHAR VendorDesc[] = "DC21x4 compatible Ethernet Adapter"; 318 InfoPtr = (PVOID)&VendorDesc; 319 InfoLength = sizeof(VendorDesc); 320 break; 321 } 322 323 case OID_GEN_VENDOR_DRIVER_VERSION: 324 /* 1.0.0 */ 325 GenericInfo.Ulong = 0x100; 326 break; 327 328 case OID_GEN_DRIVER_VERSION: 329 { 330 InfoLength = sizeof(USHORT); 331 GenericInfo.Ushort = (NDIS_MINIPORT_MAJOR_VERSION << 8) | NDIS_MINIPORT_MINOR_VERSION; 332 break; 333 } 334 335 case OID_GEN_MAXIMUM_SEND_PACKETS: 336 GenericInfo.Ulong = DC_TRANSMIT_BLOCKS - DC_TCB_RESERVE; 337 break; 338 339 case OID_GEN_MAC_OPTIONS: 340 GenericInfo.Ulong = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | 341 NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | 342 NDIS_MAC_OPTION_NO_LOOPBACK; 343 break; 344 345 case OID_GEN_MEDIA_CONNECT_STATUS: 346 GenericInfo.Ulong = Adapter->LinkUp ? NdisMediaStateConnected 347 : NdisMediaStateDisconnected; 348 break; 349 350 case OID_802_3_PERMANENT_ADDRESS: 351 InfoPtr = Adapter->PermanentMacAddress; 352 InfoLength = ETH_LENGTH_OF_ADDRESS; 353 break; 354 355 case OID_802_3_CURRENT_ADDRESS: 356 InfoPtr = Adapter->CurrentMacAddress; 357 InfoLength = ETH_LENGTH_OF_ADDRESS; 358 break; 359 360 case OID_GEN_XMIT_OK: 361 case OID_GEN_RCV_OK: 362 case OID_GEN_XMIT_ERROR: 363 case OID_GEN_RCV_ERROR: 364 case OID_GEN_RCV_NO_BUFFER: 365 case OID_GEN_DIRECTED_FRAMES_RCV: 366 case OID_GEN_MULTICAST_FRAMES_RCV: 367 case OID_GEN_BROADCAST_FRAMES_RCV: 368 case OID_GEN_RCV_CRC_ERROR: 369 case OID_802_3_RCV_ERROR_ALIGNMENT: 370 case OID_802_3_XMIT_ONE_COLLISION: 371 case OID_802_3_XMIT_MORE_COLLISIONS: 372 case OID_802_3_XMIT_DEFERRED: 373 case OID_802_3_XMIT_MAX_COLLISIONS: 374 case OID_802_3_RCV_OVERRUN: 375 case OID_802_3_XMIT_UNDERRUN: 376 case OID_802_3_XMIT_HEARTBEAT_FAILURE: 377 case OID_802_3_XMIT_TIMES_CRS_LOST: 378 case OID_802_3_XMIT_LATE_COLLISIONS: 379 { 380 DcQueryStatisticCounter(Adapter, Oid, &GenericInfo.Ulong64); 381 382 *BytesNeeded = sizeof(ULONG64); 383 if (InformationBufferLength < sizeof(ULONG)) 384 { 385 *BytesWritten = 0; 386 return NDIS_STATUS_BUFFER_TOO_SHORT; 387 } 388 if (InformationBufferLength >= sizeof(ULONG64)) 389 { 390 *BytesWritten = sizeof(ULONG64); 391 NdisMoveMemory(InformationBuffer, InfoPtr, sizeof(ULONG64)); 392 } 393 else 394 { 395 *BytesWritten = sizeof(ULONG); 396 NdisMoveMemory(InformationBuffer, InfoPtr, sizeof(ULONG)); 397 } 398 399 return NDIS_STATUS_SUCCESS; 400 } 401 402 case OID_GEN_TRANSMIT_QUEUE_LENGTH: 403 GenericInfo.Ulong = (DC_TRANSMIT_BLOCKS - DC_TCB_RESERVE) - Adapter->TcbSlots; 404 break; 405 406 case OID_PNP_CAPABILITIES: 407 { 408 PNDIS_PNP_CAPABILITIES Capabilities; 409 410 InfoLength = sizeof(NDIS_PNP_CAPABILITIES); 411 412 if (InformationBufferLength < InfoLength) 413 { 414 *BytesWritten = 0; 415 *BytesNeeded = InfoLength; 416 return NDIS_STATUS_BUFFER_TOO_SHORT; 417 } 418 419 if (!(Adapter->Features & DC_HAS_POWER_MANAGEMENT)) 420 return NDIS_STATUS_NOT_SUPPORTED; 421 422 *BytesWritten = InfoLength; 423 *BytesNeeded = 0; 424 425 Capabilities = InformationBuffer; 426 Capabilities->WakeUpCapabilities.MinMagicPacketWakeUp = NdisDeviceStateD3; 427 Capabilities->WakeUpCapabilities.MinPatternWakeUp = NdisDeviceStateD3; 428 Capabilities->WakeUpCapabilities.MinLinkChangeWakeUp = NdisDeviceStateD3; 429 430 return NDIS_STATUS_SUCCESS; 431 } 432 433 case OID_PNP_QUERY_POWER: 434 { 435 if (!(Adapter->Features & DC_HAS_POWER_MANAGEMENT)) 436 return NDIS_STATUS_NOT_SUPPORTED; 437 438 return NDIS_STATUS_SUCCESS; 439 } 440 441 case OID_PNP_ENABLE_WAKE_UP: 442 { 443 if (!(Adapter->Features & DC_HAS_POWER_MANAGEMENT)) 444 return NDIS_STATUS_NOT_SUPPORTED; 445 446 GenericInfo.Ulong = Adapter->WakeUpFlags & (NDIS_PNP_WAKE_UP_MAGIC_PACKET | 447 NDIS_PNP_WAKE_UP_PATTERN_MATCH | 448 NDIS_PNP_WAKE_UP_LINK_CHANGE); 449 break; 450 } 451 452 default: 453 Status = NDIS_STATUS_INVALID_OID; 454 break; 455 } 456 457 if (Status == NDIS_STATUS_SUCCESS) 458 { 459 if (InfoLength > InformationBufferLength) 460 { 461 *BytesWritten = 0; 462 *BytesNeeded = InfoLength; 463 Status = NDIS_STATUS_BUFFER_TOO_SHORT; 464 } 465 else 466 { 467 NdisMoveMemory(InformationBuffer, InfoPtr, InfoLength); 468 *BytesWritten = InfoLength; 469 *BytesNeeded = 0; 470 } 471 } 472 else 473 { 474 *BytesWritten = 0; 475 *BytesNeeded = 0; 476 } 477 478 return Status; 479 } 480 481 NDIS_STATUS 482 NTAPI 483 DcSetInformation( 484 _In_ NDIS_HANDLE MiniportAdapterContext, 485 _In_ NDIS_OID Oid, 486 _In_ PVOID InformationBuffer, 487 _In_ ULONG InformationBufferLength, 488 _Out_ PULONG BytesRead, 489 _Out_ PULONG BytesNeeded) 490 { 491 PDC21X4_ADAPTER Adapter = (PDC21X4_ADAPTER)MiniportAdapterContext; 492 NDIS_STATUS Status = NDIS_STATUS_SUCCESS; 493 ULONG GenericUlong; 494 495 *BytesRead = 0; 496 *BytesNeeded = 0; 497 498 switch (Oid) 499 { 500 case OID_GEN_CURRENT_PACKET_FILTER: 501 { 502 if (InformationBufferLength < sizeof(ULONG)) 503 { 504 *BytesNeeded = sizeof(ULONG); 505 Status = NDIS_STATUS_INVALID_LENGTH; 506 break; 507 } 508 509 *BytesRead = sizeof(ULONG); 510 NdisMoveMemory(&GenericUlong, InformationBuffer, sizeof(ULONG)); 511 512 if (GenericUlong & ~DC_PACKET_FILTERS) 513 { 514 Status = NDIS_STATUS_NOT_SUPPORTED; 515 break; 516 } 517 518 Status = DcApplyPacketFilter(Adapter, GenericUlong); 519 break; 520 } 521 522 case OID_802_3_MULTICAST_LIST: 523 { 524 ULONG Size; 525 526 if (InformationBufferLength % ETH_LENGTH_OF_ADDRESS) 527 { 528 *BytesNeeded = (InformationBufferLength / ETH_LENGTH_OF_ADDRESS) * 529 ETH_LENGTH_OF_ADDRESS; 530 Status = NDIS_STATUS_INVALID_LENGTH; 531 break; 532 } 533 534 Size = Adapter->MulticastMaxEntries * ETH_LENGTH_OF_ADDRESS; 535 if (InformationBufferLength > Size) 536 { 537 *BytesNeeded = Size; 538 Status = NDIS_STATUS_MULTICAST_FULL; 539 break; 540 } 541 542 *BytesRead = InformationBufferLength; 543 NdisMoveMemory(Adapter->MulticastList, InformationBuffer, InformationBufferLength); 544 545 Adapter->MulticastCount = InformationBufferLength / ETH_LENGTH_OF_ADDRESS; 546 547 Status = DcUpdateMulticastList(Adapter); 548 break; 549 } 550 551 case OID_GEN_CURRENT_LOOKAHEAD: 552 { 553 if (InformationBufferLength < sizeof(ULONG)) 554 { 555 *BytesNeeded = sizeof(ULONG); 556 Status = NDIS_STATUS_INVALID_LENGTH; 557 break; 558 } 559 560 /* Nothing to do */ 561 *BytesRead = sizeof(ULONG); 562 break; 563 } 564 565 case OID_PNP_ENABLE_WAKE_UP: 566 { 567 if (InformationBufferLength < sizeof(ULONG)) 568 { 569 *BytesNeeded = sizeof(ULONG); 570 Status = NDIS_STATUS_INVALID_LENGTH; 571 break; 572 } 573 574 if (!(Adapter->Features & DC_HAS_POWER_MANAGEMENT)) 575 { 576 return NDIS_STATUS_NOT_SUPPORTED; 577 } 578 579 *BytesRead = sizeof(ULONG); 580 NdisMoveMemory(&GenericUlong, InformationBuffer, sizeof(ULONG)); 581 582 Adapter->WakeUpFlags = GenericUlong; 583 break; 584 } 585 586 case OID_PNP_ADD_WAKE_UP_PATTERN: 587 { 588 if (InformationBufferLength < sizeof(NDIS_PM_PACKET_PATTERN)) 589 { 590 *BytesNeeded = sizeof(NDIS_PM_PACKET_PATTERN); 591 Status = NDIS_STATUS_INVALID_LENGTH; 592 break; 593 } 594 595 if (!(Adapter->Features & DC_HAS_POWER_MANAGEMENT)) 596 { 597 return NDIS_STATUS_NOT_SUPPORTED; 598 } 599 600 *BytesRead = sizeof(NDIS_PM_PACKET_PATTERN); 601 602 Status = DcAddWakeUpPattern(Adapter, InformationBuffer); 603 break; 604 } 605 606 case OID_PNP_REMOVE_WAKE_UP_PATTERN: 607 { 608 if (InformationBufferLength < sizeof(NDIS_PM_PACKET_PATTERN)) 609 { 610 *BytesNeeded = sizeof(NDIS_PM_PACKET_PATTERN); 611 Status = NDIS_STATUS_INVALID_LENGTH; 612 break; 613 } 614 615 if (!(Adapter->Features & DC_HAS_POWER_MANAGEMENT)) 616 { 617 return NDIS_STATUS_NOT_SUPPORTED; 618 } 619 620 *BytesRead = sizeof(NDIS_PM_PACKET_PATTERN); 621 622 Status = DcRemoveWakeUpPattern(Adapter, InformationBuffer); 623 break; 624 } 625 626 case OID_PNP_SET_POWER: 627 { 628 if (InformationBufferLength < sizeof(NDIS_DEVICE_POWER_STATE)) 629 { 630 *BytesNeeded = sizeof(NDIS_DEVICE_POWER_STATE); 631 Status = NDIS_STATUS_INVALID_LENGTH; 632 break; 633 } 634 635 if (!(Adapter->Features & DC_HAS_POWER_MANAGEMENT)) 636 { 637 return NDIS_STATUS_NOT_SUPPORTED; 638 } 639 640 *BytesRead = sizeof(ULONG); 641 NdisMoveMemory(&GenericUlong, InformationBuffer, sizeof(ULONG)); 642 643 if (GenericUlong < NdisDeviceStateD0 || GenericUlong > NdisDeviceStateD3) 644 { 645 ASSERT(FALSE); 646 Status = NDIS_STATUS_INVALID_DATA; 647 break; 648 } 649 650 DcSetPower(Adapter, GenericUlong); 651 break; 652 } 653 654 default: 655 Status = NDIS_STATUS_NOT_SUPPORTED; 656 break; 657 } 658 659 return Status; 660 } 661