xref: /reactos/drivers/network/dd/dc21x4/requests.c (revision 3fb5957d)
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