xref: /reactos/drivers/network/dd/dc21x4/init.c (revision 59d8a77d)
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 initialization helper routines
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 /*
17  * The driver must align the buffers on a 4 byte boundary to meet the hardware requirement.
18  * We stick with cache alignment to get better performance.
19  */
20 C_ASSERT((SYSTEM_CACHE_ALIGNMENT_SIZE % DC_RECEIVE_BUFFER_ALIGNMENT) == 0);
21 C_ASSERT((SYSTEM_CACHE_ALIGNMENT_SIZE % DC_DESCRIPTOR_ALIGNMENT) == 0);
22 C_ASSERT((SYSTEM_CACHE_ALIGNMENT_SIZE % DC_SETUP_FRAME_ALIGNMENT) == 0);
23 
24 /* Errata: The end of receive buffer must not fall on a cache boundary */
25 #define DC_RECEIVE_BUFFER_SIZE     (DC_RECEIVE_BLOCK_SIZE - 4)
26 C_ASSERT((DC_RECEIVE_BUFFER_SIZE % 32) != 0);
27 
28 #define DC_MEM_BLOCK_SIZE_RCB \
29     (DC_RECEIVE_BLOCK_SIZE + SYSTEM_CACHE_ALIGNMENT_SIZE - 1)
30 
31 #define DC_MEM_BLOCK_SIZE_RBD \
32     (sizeof(DC_RBD) * DC_RECEIVE_BUFFERS_DEFAULT + SYSTEM_CACHE_ALIGNMENT_SIZE - 1)
33 
34 #define DC_MEM_BLOCK_SIZE_TBD_AUX \
35     (sizeof(DC_TBD) * DC_TRANSMIT_DESCRIPTORS + SYSTEM_CACHE_ALIGNMENT_SIZE - 1 + \
36      DC_SETUP_FRAME_SIZE + SYSTEM_CACHE_ALIGNMENT_SIZE - 1 + \
37      DC_LOOPBACK_FRAME_SIZE * DC_LOOPBACK_FRAMES + SYSTEM_CACHE_ALIGNMENT_SIZE - 1)
38 
39 #define DC_MEM_BLOCK_SIZE_TX_BUFFER \
40     (DC_TRANSMIT_BLOCK_SIZE + SYSTEM_CACHE_ALIGNMENT_SIZE - 1)
41 
42 /* FUNCTIONS ******************************************************************/
43 
44 static
45 CODE_SEG("PAGE")
46 VOID
DcConfigQueryInteger(_In_ NDIS_HANDLE ConfigurationHandle,_In_ PCWSTR EntryName,_Out_ PULONG EntryContext,_In_ ULONG DefaultValue,_In_ ULONG Minimum,_In_ ULONG Maximum)47 DcConfigQueryInteger(
48     _In_ NDIS_HANDLE ConfigurationHandle,
49     _In_ PCWSTR EntryName,
50     _Out_ PULONG EntryContext,
51     _In_ ULONG DefaultValue,
52     _In_ ULONG Minimum,
53     _In_ ULONG Maximum)
54 {
55     NDIS_STATUS Status;
56     UNICODE_STRING Keyword;
57     PNDIS_CONFIGURATION_PARAMETER ConfigurationParameter;
58 
59     PAGED_CODE();
60 
61     NdisInitUnicodeString(&Keyword, EntryName);
62     NdisReadConfiguration(&Status,
63                           &ConfigurationParameter,
64                           ConfigurationHandle,
65                           &Keyword,
66                           NdisParameterInteger);
67     if (Status != NDIS_STATUS_SUCCESS)
68     {
69         TRACE("'%S' request failed, default value %u\n", EntryName, DefaultValue);
70 
71         *EntryContext = DefaultValue;
72         return;
73     }
74 
75     if (ConfigurationParameter->ParameterData.IntegerData >= Minimum &&
76         ConfigurationParameter->ParameterData.IntegerData <= Maximum)
77     {
78         *EntryContext = ConfigurationParameter->ParameterData.IntegerData;
79     }
80     else
81     {
82         WARN("'%S' value out of range\n", EntryName);
83 
84         *EntryContext = DefaultValue;
85     }
86 
87     TRACE("Set '%S' to %u\n", EntryName, *EntryContext);
88 }
89 
90 static
91 CODE_SEG("PAGE")
92 NDIS_STATUS
DcReadConfiguration(_In_ PDC21X4_ADAPTER Adapter)93 DcReadConfiguration(
94     _In_ PDC21X4_ADAPTER Adapter)
95 {
96     NDIS_STATUS Status;
97     NDIS_HANDLE ConfigurationHandle;
98     PUCHAR NetworkAddress;
99     UINT Length;
100     ULONG GenericUlong;
101 
102     PAGED_CODE();
103 
104     NdisOpenConfiguration(&Status,
105                           &ConfigurationHandle,
106                           Adapter->WrapperConfigurationHandle);
107     if (Status != NDIS_STATUS_SUCCESS)
108         return Status;
109 
110     DcConfigQueryInteger(ConfigurationHandle,
111                          L"SpeedDuplex",
112                          &GenericUlong,
113                          MEDIA_AUTO,
114                          MEDIA_10T,
115                          MEDIA_HMR);
116     Adapter->DefaultMedia = GenericUlong;
117 
118     NdisReadNetworkAddress(&Status,
119                            (PVOID*)&NetworkAddress,
120                            &Length,
121                            ConfigurationHandle);
122     if ((Status == NDIS_STATUS_SUCCESS) && (Length == ETH_LENGTH_OF_ADDRESS))
123     {
124         if (ETH_IS_MULTICAST(NetworkAddress) ||
125             ETH_IS_EMPTY(NetworkAddress) ||
126             ETH_IS_BROADCAST(NetworkAddress) ||
127             !ETH_IS_LOCALLY_ADMINISTERED(NetworkAddress))
128         {
129             ERR("Invalid software MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
130                 NetworkAddress[0],
131                 NetworkAddress[1],
132                 NetworkAddress[2],
133                 NetworkAddress[3],
134                 NetworkAddress[4],
135                 NetworkAddress[5]);
136         }
137         else
138         {
139             INFO("Using software MAC address\n");
140 
141             /* Override the MAC address */
142             NdisMoveMemory(Adapter->CurrentMacAddress, NetworkAddress, ETH_LENGTH_OF_ADDRESS);
143         }
144     }
145 
146     NdisCloseConfiguration(ConfigurationHandle);
147 
148     return NDIS_STATUS_SUCCESS;
149 }
150 
151 static
152 CODE_SEG("PAGE")
153 VOID
DcFreeRcb(_In_ PDC21X4_ADAPTER Adapter,_In_ __drv_freesMem (Mem)PDC_RCB Rcb)154 DcFreeRcb(
155     _In_ PDC21X4_ADAPTER Adapter,
156     _In_ __drv_freesMem(Mem) PDC_RCB Rcb)
157 {
158     PAGED_CODE();
159 
160     if (Rcb->VirtualAddressOriginal)
161     {
162         NdisMFreeSharedMemory(Adapter->AdapterHandle,
163                               DC_MEM_BLOCK_SIZE_RCB,
164                               TRUE, /* Cached */
165                               Rcb->VirtualAddressOriginal,
166                               Rcb->PhysicalAddressOriginal);
167     }
168 
169     if (Rcb->NdisBuffer)
170         NdisFreeBuffer(Rcb->NdisBuffer);
171     if (Rcb->Packet)
172         NdisFreePacket(Rcb->Packet);
173 
174     NdisFreeMemory(Rcb, sizeof(*Rcb), 0);
175 }
176 
177 static
178 CODE_SEG("PAGE")
179 PDC_RCB
DcAllocateRcb(_In_ PDC21X4_ADAPTER Adapter)180 DcAllocateRcb(
181     _In_ PDC21X4_ADAPTER Adapter)
182 {
183     NDIS_STATUS Status;
184     PDC_RCB Rcb;
185     PVOID VirtualAddress;
186     NDIS_PHYSICAL_ADDRESS PhysicalAddress;
187 
188     PAGED_CODE();
189 
190     Status = NdisAllocateMemoryWithTag((PVOID*)&Rcb, sizeof(*Rcb), DC21X4_TAG);
191     if (Status != NDIS_STATUS_SUCCESS)
192         return NULL;
193     NdisZeroMemory(Rcb, sizeof(*Rcb));
194 
195     NdisMAllocateSharedMemory(Adapter->AdapterHandle,
196                               DC_MEM_BLOCK_SIZE_RCB,
197                               TRUE, /* Cached */
198                               &VirtualAddress,
199                               &PhysicalAddress);
200     if (!VirtualAddress)
201         goto Failure;
202 
203     /* 32-bit DMA */
204     ASSERT(PhysicalAddress.HighPart == 0);
205 
206     Rcb->VirtualAddress = ALIGN_UP_POINTER_BY(VirtualAddress, SYSTEM_CACHE_ALIGNMENT_SIZE);
207     Rcb->PhysicalAddress = ALIGN_UP_BY(PhysicalAddress.LowPart, SYSTEM_CACHE_ALIGNMENT_SIZE);
208 
209     ASSERT((Rcb->PhysicalAddress % DC_RECEIVE_BUFFER_ALIGNMENT) == 0);
210 
211     Rcb->VirtualAddressOriginal = VirtualAddress;
212     Rcb->PhysicalAddressOriginal.QuadPart = PhysicalAddress.QuadPart;
213 
214     NdisAllocatePacket(&Status, &Rcb->Packet, Adapter->PacketPool);
215     if (Status != NDIS_STATUS_SUCCESS)
216         goto Failure;
217 
218     *DC_RCB_FROM_PACKET(Rcb->Packet) = Rcb;
219 
220     NdisAllocateBuffer(&Status,
221                        &Rcb->NdisBuffer,
222                        Adapter->BufferPool,
223                        Rcb->VirtualAddress,
224                        DC_RECEIVE_BLOCK_SIZE);
225     if (Status != NDIS_STATUS_SUCCESS)
226         goto Failure;
227 
228     NDIS_SET_PACKET_HEADER_SIZE(Rcb->Packet, DC_ETHERNET_HEADER_SIZE);
229     NdisChainBufferAtFront(Rcb->Packet, Rcb->NdisBuffer);
230 
231     PushEntryList(&Adapter->AllocRcbList, &Rcb->AllocListEntry);
232 
233     return Rcb;
234 
235 Failure:
236     DcFreeRcb(Adapter, Rcb);
237 
238     return NULL;
239 }
240 
241 static
242 CODE_SEG("PAGE")
243 NDIS_STATUS
DcAllocateReceiveBuffers(_In_ PDC21X4_ADAPTER Adapter)244 DcAllocateReceiveBuffers(
245     _In_ PDC21X4_ADAPTER Adapter)
246 {
247     ULONG i;
248     NDIS_STATUS Status;
249     PDC_RCB Rcb;
250 
251     PAGED_CODE();
252 
253     NdisAllocatePacketPool(&Status,
254                            &Adapter->PacketPool,
255                            DC_RECEIVE_BUFFERS_DEFAULT + DC_RECEIVE_BUFFERS_EXTRA,
256                            PROTOCOL_RESERVED_SIZE_IN_PACKET);
257     if (Status != NDIS_STATUS_SUCCESS)
258         return Status;
259 
260     NdisAllocateBufferPool(&Status,
261                            &Adapter->BufferPool,
262                            DC_RECEIVE_BUFFERS_DEFAULT + DC_RECEIVE_BUFFERS_EXTRA);
263     if (Status != NDIS_STATUS_SUCCESS)
264         return Status;
265 
266     /* Allocate RCBs */
267     for (i = 0; i < DC_RECEIVE_BUFFERS_DEFAULT; ++i)
268     {
269         Rcb = DcAllocateRcb(Adapter);
270         if (!Rcb)
271         {
272             WARN("RCB allocation failed, total buffers %u\n", Adapter->RcbCount);
273             break;
274         }
275 
276         PushEntryList(&Adapter->UsedRcbList, &Rcb->ListEntry);
277 
278         ++Adapter->RcbCount;
279     }
280 
281     if (Adapter->RcbCount < DC_RECEIVE_BUFFERS_MIN)
282         return NDIS_STATUS_RESOURCES;
283 
284     Adapter->RcbFree = Adapter->RcbCount;
285 
286     /* Fix up the ring size */
287     Adapter->TailRbd = Adapter->HeadRbd + Adapter->RcbCount - 1;
288 
289     /* Allocate extra RCBs for receive indication */
290     for (i = 0; i < DC_RECEIVE_BUFFERS_EXTRA; ++i)
291     {
292         Rcb = DcAllocateRcb(Adapter);
293         if (!Rcb)
294         {
295             WARN("Extra RCB allocation failed\n");
296             break;
297         }
298 
299         PushEntryList(&Adapter->FreeRcbList, &Rcb->ListEntry);
300     }
301 
302     Status = NdisAllocateMemoryWithTag((PVOID*)&Adapter->RcbArray,
303                                        sizeof(PVOID) * Adapter->RcbCount,
304                                        DC21X4_TAG);
305     if (Status != NDIS_STATUS_SUCCESS)
306         return Status;
307 
308     return NDIS_STATUS_SUCCESS;
309 }
310 
311 static
312 CODE_SEG("PAGE")
313 NDIS_STATUS
DcAllocateReceiveDescriptors(_In_ PDC21X4_ADAPTER Adapter)314 DcAllocateReceiveDescriptors(
315     _In_ PDC21X4_ADAPTER Adapter)
316 {
317     PDC_RBD Rbd;
318 
319     PAGED_CODE();
320 
321     NdisMAllocateSharedMemory(Adapter->AdapterHandle,
322                               DC_MEM_BLOCK_SIZE_RBD,
323                               FALSE, /* Non-cached */
324                               &Adapter->RbdOriginal,
325                               &Adapter->RbdPhysOriginal);
326     if (!Adapter->RbdOriginal)
327         return NDIS_STATUS_RESOURCES;
328 
329     /* 32-bit DMA */
330     ASSERT(Adapter->RbdPhysOriginal.HighPart == 0);
331 
332     Adapter->RbdPhys = ALIGN_UP_BY(Adapter->RbdPhysOriginal.LowPart, SYSTEM_CACHE_ALIGNMENT_SIZE);
333 
334     ASSERT((Adapter->RbdPhys % DC_DESCRIPTOR_ALIGNMENT) == 0);
335 
336     Rbd = ALIGN_UP_POINTER_BY(Adapter->RbdOriginal, SYSTEM_CACHE_ALIGNMENT_SIZE);
337 
338     Adapter->HeadRbd = Rbd;
339 
340     return NDIS_STATUS_SUCCESS;
341 }
342 
343 static
344 CODE_SEG("PAGE")
345 NDIS_STATUS
DcAllocateTransmitBlocks(_In_ PDC21X4_ADAPTER Adapter)346 DcAllocateTransmitBlocks(
347     _In_ PDC21X4_ADAPTER Adapter)
348 {
349     PDC_TCB Tcb;
350     NDIS_STATUS Status;
351 
352     PAGED_CODE();
353 
354     Status = NdisAllocateMemoryWithTag((PVOID*)&Tcb,
355                                        DC_TRANSMIT_BLOCKS * sizeof(*Tcb),
356                                        DC21X4_TAG);
357     if (Status != NDIS_STATUS_SUCCESS)
358         return Status;
359 
360     NdisZeroMemory(Tcb, DC_TRANSMIT_BLOCKS * sizeof(*Tcb));
361 
362     Adapter->HeadTcb = Tcb;
363     Adapter->TailTcb = Tcb + (DC_TRANSMIT_BLOCKS - 1);
364 
365     return NDIS_STATUS_SUCCESS;
366 }
367 
368 static
369 CODE_SEG("PAGE")
370 NDIS_STATUS
DcAllocateTransmitDescriptorsAndBuffers(_In_ PDC21X4_ADAPTER Adapter)371 DcAllocateTransmitDescriptorsAndBuffers(
372     _In_ PDC21X4_ADAPTER Adapter)
373 {
374     ULONG_PTR BufferVa, BufferPa;
375     NDIS_STATUS Status;
376     ULONG i;
377 
378     PAGED_CODE();
379 
380     NdisMAllocateSharedMemory(Adapter->AdapterHandle,
381                               DC_MEM_BLOCK_SIZE_TBD_AUX,
382                               FALSE, /* Non-cached */
383                               &Adapter->TbdOriginal,
384                               &Adapter->TbdPhysOriginal);
385     if (!Adapter->TbdOriginal)
386         return NDIS_STATUS_RESOURCES;
387 
388     /* 32-bit DMA */
389     ASSERT(Adapter->TbdPhysOriginal.HighPart == 0);
390 
391     BufferVa = (ULONG_PTR)Adapter->TbdOriginal;
392     BufferPa = Adapter->TbdPhysOriginal.LowPart;
393 
394     BufferVa = ALIGN_UP_BY(BufferVa, SYSTEM_CACHE_ALIGNMENT_SIZE);
395     BufferPa = ALIGN_UP_BY(BufferPa, SYSTEM_CACHE_ALIGNMENT_SIZE);
396 
397     ASSERT((BufferPa % DC_DESCRIPTOR_ALIGNMENT) == 0);
398 
399     Adapter->TbdPhys = (ULONG)BufferPa;
400     Adapter->HeadTbd = (PDC_TBD)BufferVa;
401     Adapter->TailTbd = (PDC_TBD)BufferVa + DC_TRANSMIT_DESCRIPTORS - 1;
402 
403     BufferVa += sizeof(DC_TBD) * DC_TRANSMIT_DESCRIPTORS;
404     BufferPa += sizeof(DC_TBD) * DC_TRANSMIT_DESCRIPTORS;
405 
406     BufferVa = ALIGN_UP_BY(BufferVa, SYSTEM_CACHE_ALIGNMENT_SIZE);
407     BufferPa = ALIGN_UP_BY(BufferPa, SYSTEM_CACHE_ALIGNMENT_SIZE);
408 
409     ASSERT((BufferPa % DC_SETUP_FRAME_ALIGNMENT) == 0);
410 
411     Adapter->SetupFrame = (PVOID)BufferVa;
412     Adapter->SetupFramePhys = BufferPa;
413 
414     BufferVa += DC_SETUP_FRAME_SIZE;
415     BufferPa += DC_SETUP_FRAME_SIZE;
416 
417     BufferVa = ALIGN_UP_BY(BufferVa, SYSTEM_CACHE_ALIGNMENT_SIZE);
418     BufferPa = ALIGN_UP_BY(BufferPa, SYSTEM_CACHE_ALIGNMENT_SIZE);
419 
420     for (i = 0; i < DC_LOOPBACK_FRAMES; ++i)
421     {
422         Adapter->LoopbackFrame[i] = (PVOID)BufferVa;
423         Adapter->LoopbackFramePhys[i] = BufferPa;
424 
425         BufferVa += DC_LOOPBACK_FRAME_SIZE;
426         BufferPa += DC_LOOPBACK_FRAME_SIZE;
427     }
428 
429     if (Adapter->Features & DC_HAS_POWER_MANAGEMENT)
430     {
431         Status = NdisAllocateMemoryWithTag((PVOID*)&Adapter->SetupFrameSaved,
432                                            DC_SETUP_FRAME_SIZE,
433                                            DC21X4_TAG);
434         if (Status != NDIS_STATUS_SUCCESS)
435             return Status;
436     }
437 
438     return NDIS_STATUS_SUCCESS;
439 }
440 
441 static
442 CODE_SEG("PAGE")
443 NDIS_STATUS
DcAllocateTransmitBuffers(_In_ PDC21X4_ADAPTER Adapter)444 DcAllocateTransmitBuffers(
445     _In_ PDC21X4_ADAPTER Adapter)
446 {
447     PDC_COALESCE_BUFFER CoalesceBuffer;
448     NDIS_STATUS Status;
449     ULONG i;
450 
451     PAGED_CODE();
452 
453     Status = NdisAllocateMemoryWithTag((PVOID*)&CoalesceBuffer,
454                                        DC_TRANSMIT_BUFFERS * sizeof(*CoalesceBuffer),
455                                        DC21X4_TAG);
456     if (Status != NDIS_STATUS_SUCCESS)
457         return Status;
458 
459     NdisZeroMemory(CoalesceBuffer, DC_TRANSMIT_BUFFERS * sizeof(*CoalesceBuffer));
460 
461     Adapter->CoalesceBuffer = CoalesceBuffer;
462 
463     for (i = 0; i < DC_TRANSMIT_BUFFERS; ++i)
464     {
465         PVOID VirtualAddress;
466         NDIS_PHYSICAL_ADDRESS PhysicalAddress;
467 
468         NdisMAllocateSharedMemory(Adapter->AdapterHandle,
469                                   DC_MEM_BLOCK_SIZE_TX_BUFFER,
470                                   FALSE, /* Non-cached */
471                                   &VirtualAddress,
472                                   &PhysicalAddress);
473         if (!VirtualAddress)
474             continue;
475 
476         ASSERT(PhysicalAddress.HighPart == 0);
477 
478         CoalesceBuffer->VirtualAddress =
479             ALIGN_UP_POINTER_BY(VirtualAddress, SYSTEM_CACHE_ALIGNMENT_SIZE);
480         CoalesceBuffer->PhysicalAddress =
481             ALIGN_UP_BY(PhysicalAddress.LowPart, SYSTEM_CACHE_ALIGNMENT_SIZE);
482 
483         Adapter->SendBufferData[i].PhysicalAddress.QuadPart = PhysicalAddress.QuadPart;
484         Adapter->SendBufferData[i].VirtualAddress = VirtualAddress;
485 
486         PushEntryList(&Adapter->SendBufferList, &CoalesceBuffer->ListEntry);
487 
488         ++CoalesceBuffer;
489     }
490 
491     if (!Adapter->SendBufferList.Next)
492         return NDIS_STATUS_RESOURCES;
493 
494     return NDIS_STATUS_SUCCESS;
495 }
496 
497 CODE_SEG("PAGE")
498 VOID
DcInitTxRing(_In_ PDC21X4_ADAPTER Adapter)499 DcInitTxRing(
500     _In_ PDC21X4_ADAPTER Adapter)
501 {
502     PDC_TCB Tcb;
503     PDC_TBD Tbd;
504 
505     PAGED_CODE();
506 
507     InitializeListHead(&Adapter->SendQueueList);
508 
509     Tcb = Adapter->HeadTcb;
510 
511     Adapter->CurrentTcb = Tcb;
512     Adapter->LastTcb = Tcb;
513 
514     Adapter->TcbSlots = DC_TRANSMIT_BLOCKS - DC_TCB_RESERVE;
515     Adapter->TbdSlots = DC_TRANSMIT_DESCRIPTORS - DC_TBD_RESERVE;
516     Adapter->LoopbackFrameSlots = DC_LOOPBACK_FRAMES;
517     Adapter->TcbCompleted = 0;
518 
519     Tbd = Adapter->HeadTbd;
520     Adapter->CurrentTbd = Tbd;
521 
522     NdisZeroMemory(Tbd, sizeof(*Tbd) * DC_TRANSMIT_DESCRIPTORS);
523 
524     Adapter->TailTbd->Control |= DC_TBD_CONTROL_END_OF_RING;
525 }
526 
527 static
528 CODE_SEG("PAGE")
529 VOID
DcCreateRxRing(_In_ PDC21X4_ADAPTER Adapter)530 DcCreateRxRing(
531     _In_ PDC21X4_ADAPTER Adapter)
532 {
533     PDC_RCB* RcbSlot;
534     PDC_RCB Rcb;
535     PDC_RBD Rbd;
536     PSINGLE_LIST_ENTRY Entry;
537 
538     PAGED_CODE();
539 
540     Rbd = Adapter->HeadRbd;
541     Adapter->CurrentRbd = Rbd;
542 
543     RcbSlot = DC_GET_RCB_SLOT(Adapter, Rbd);
544     Rcb = (PDC_RCB)Adapter->UsedRcbList.Next;
545 
546     for (Entry = Adapter->UsedRcbList.Next;
547          Entry != NULL;
548          Entry = Entry->Next)
549     {
550         Rcb = (PDC_RCB)Entry;
551 
552         C_ASSERT((DC_RECEIVE_BUFFER_SIZE % DC_RECEIVE_BUFFER_SIZE_MULTIPLE) == 0);
553 
554         Rbd->Address1 = Rcb->PhysicalAddress;
555         Rbd->Address2 = 0;
556         Rbd->Control = DC_RECEIVE_BUFFER_SIZE;
557         Rbd->Status = DC_RBD_STATUS_OWNED;
558 
559         *RcbSlot = Rcb;
560 
561         ++RcbSlot;
562         ++Rbd;
563         Rcb = (PDC_RCB)Rcb->ListEntry.Next;
564     }
565     Rbd = Rbd - 1;
566     Rbd->Control |= DC_RBD_CONTROL_CHAINED;
567     Rbd->Address2 = Adapter->RbdPhys;
568 
569     ASSERT(Rbd == Adapter->TailRbd);
570 }
571 
572 CODE_SEG("PAGE")
573 VOID
DcInitRxRing(_In_ PDC21X4_ADAPTER Adapter)574 DcInitRxRing(
575     _In_ PDC21X4_ADAPTER Adapter)
576 {
577     PDC_RBD Rbd;
578     ULONG i;
579 
580     PAGED_CODE();
581 
582     Rbd = Adapter->HeadRbd;
583     Adapter->CurrentRbd = Rbd;
584 
585     for (i = 0; i < Adapter->RcbCount; ++i)
586     {
587         Rbd->Control = DC_RECEIVE_BUFFER_SIZE;
588         Rbd->Status = DC_RBD_STATUS_OWNED;
589 
590         ++Rbd;
591     }
592     Rbd = Rbd - 1;
593     Rbd->Control |= DC_RBD_CONTROL_CHAINED;
594 
595     ASSERT(Rbd == Adapter->TailRbd);
596 }
597 
598 static
599 CODE_SEG("PAGE")
600 NDIS_STATUS
DcAllocateMemory(_In_ PDC21X4_ADAPTER Adapter)601 DcAllocateMemory(
602     _In_ PDC21X4_ADAPTER Adapter)
603 {
604     NDIS_STATUS Status;
605 
606     PAGED_CODE();
607 
608     Status = NdisMInitializeScatterGatherDma(Adapter->AdapterHandle,
609                                              FALSE, /* 32-bit DMA */
610                                              DC_TRANSMIT_BLOCK_SIZE);
611     if (Status != NDIS_STATUS_SUCCESS)
612         return Status;
613 
614     Status = DcAllocateReceiveDescriptors(Adapter);
615     if (Status != NDIS_STATUS_SUCCESS)
616         return Status;
617 
618     Status = DcAllocateTransmitBlocks(Adapter);
619     if (Status != NDIS_STATUS_SUCCESS)
620         return Status;
621 
622     Status = DcAllocateTransmitBuffers(Adapter);
623     if (Status != NDIS_STATUS_SUCCESS)
624         return Status;
625 
626     Status = DcAllocateTransmitDescriptorsAndBuffers(Adapter);
627     if (Status != NDIS_STATUS_SUCCESS)
628         return Status;
629 
630     Status = DcAllocateReceiveBuffers(Adapter);
631     if (Status != NDIS_STATUS_SUCCESS)
632         return Status;
633 
634     NdisAllocateSpinLock(&Adapter->SendLock);
635     NdisAllocateSpinLock(&Adapter->ReceiveLock);
636     NdisAllocateSpinLock(&Adapter->ModeLock);
637 
638     return NDIS_STATUS_SUCCESS;
639 }
640 
641 static
642 CODE_SEG("PAGE")
643 VOID
DcInitTestPacket(_In_ PDC21X4_ADAPTER Adapter)644 DcInitTestPacket(
645     _In_ PDC21X4_ADAPTER Adapter)
646 {
647     ULONG i;
648 
649     PAGED_CODE();
650 
651     for (i = 0; i < DC_LOOPBACK_FRAMES; ++i)
652     {
653         PETH_HEADER PacketBuffer = Adapter->LoopbackFrame[i];
654 
655         NdisZeroMemory(PacketBuffer, DC_LOOPBACK_FRAME_SIZE);
656 
657         /* Destination MAC address */
658         NdisMoveMemory(PacketBuffer->Destination,
659                        Adapter->CurrentMacAddress,
660                        ETH_LENGTH_OF_ADDRESS);
661 
662         /* Source MAC address */
663         NdisMoveMemory(PacketBuffer->Source,
664                        Adapter->CurrentMacAddress,
665                        ETH_LENGTH_OF_ADDRESS);
666 
667         ++PacketBuffer;
668     }
669 }
670 
671 static
672 CODE_SEG("PAGE")
673 NDIS_STATUS
DcInitializeAdapterResources(_In_ PDC21X4_ADAPTER Adapter)674 DcInitializeAdapterResources(
675     _In_ PDC21X4_ADAPTER Adapter)
676 {
677     NDIS_STATUS Status;
678     PNDIS_RESOURCE_LIST AssignedResources = NULL;
679     PCM_PARTIAL_RESOURCE_DESCRIPTOR IoDescriptor = NULL;
680     PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptDescriptor = NULL;
681     UINT i, ResourceListSize = 0;
682 
683     PAGED_CODE();
684 
685     NdisMQueryAdapterResources(&Status,
686                                Adapter->WrapperConfigurationHandle,
687                                AssignedResources,
688                                &ResourceListSize);
689     if (Status != NDIS_STATUS_RESOURCES)
690         return NDIS_STATUS_FAILURE;
691 
692     Status = NdisAllocateMemoryWithTag((PVOID*)&AssignedResources,
693                                        ResourceListSize,
694                                        DC21X4_TAG);
695     if (Status != NDIS_STATUS_SUCCESS)
696         return Status;
697 
698     NdisMQueryAdapterResources(&Status,
699                                Adapter->WrapperConfigurationHandle,
700                                AssignedResources,
701                                &ResourceListSize);
702     if (Status != NDIS_STATUS_SUCCESS)
703         goto Cleanup;
704 
705     for (i = 0; i < AssignedResources->Count; ++i)
706     {
707         PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
708 
709         Descriptor = &AssignedResources->PartialDescriptors[i];
710         switch (Descriptor->Type)
711         {
712             case CmResourceTypePort:
713             case CmResourceTypeMemory:
714             {
715                 if (!IoDescriptor && (Descriptor->u.Port.Length == DC_IO_LENGTH))
716                     IoDescriptor = Descriptor;
717                 break;
718             }
719 
720             case CmResourceTypeInterrupt:
721             {
722                 if (!InterruptDescriptor)
723                     InterruptDescriptor = Descriptor;
724                 break;
725             }
726 
727             default:
728                 break;
729         }
730     }
731 
732     if (!IoDescriptor || !InterruptDescriptor)
733     {
734         Status = NDIS_STATUS_RESOURCES;
735         goto Cleanup;
736     }
737 
738     Adapter->InterruptVector = InterruptDescriptor->u.Interrupt.Vector;
739     Adapter->InterruptLevel = InterruptDescriptor->u.Interrupt.Level;
740     Adapter->InterruptFlags = InterruptDescriptor->Flags;
741     if (InterruptDescriptor->ShareDisposition == CmResourceShareShared)
742         Adapter->Flags |= DC_IRQ_SHARED;
743 
744     Adapter->IoBaseAddress = IoDescriptor->u.Port.Start;
745 
746     if ((IoDescriptor->Type == CmResourceTypePort) &&
747         (IoDescriptor->Flags & CM_RESOURCE_PORT_IO))
748     {
749         Status = NdisMRegisterIoPortRange((PVOID*)&Adapter->IoBase,
750                                           Adapter->AdapterHandle,
751                                           Adapter->IoBaseAddress.LowPart,
752                                           DC_IO_LENGTH);
753     }
754     else
755     {
756         Status = NdisMMapIoSpace((PVOID*)&Adapter->IoBase,
757                                  Adapter->AdapterHandle,
758                                  Adapter->IoBaseAddress,
759                                  DC_IO_LENGTH);
760 
761         Adapter->Flags |= DC_IO_MAPPED;
762     }
763     if (Status != NDIS_STATUS_SUCCESS)
764         goto Cleanup;
765 
766     INFO("IO Base %p\n", Adapter->IoBase);
767     INFO("IRQ Level %u, Vector %u\n",
768          Adapter->InterruptLevel,
769          Adapter->InterruptVector);
770     INFO("IRQ ShareDisposition %u, InterruptFlags %lx\n",
771          InterruptDescriptor->ShareDisposition,
772          InterruptDescriptor->Flags);
773 
774 Cleanup:
775     NdisFreeMemory(AssignedResources, ResourceListSize, 0);
776 
777     return Status;
778 }
779 
780 static
781 CODE_SEG("PAGE")
782 NDIS_STATUS
DcInitializeAdapterLocation(_In_ PDC21X4_ADAPTER Adapter)783 DcInitializeAdapterLocation(
784     _In_ PDC21X4_ADAPTER Adapter)
785 {
786     PDEVICE_OBJECT Pdo;
787     NTSTATUS Status;
788     ULONG PropertyValue, Length;
789 
790     PAGED_CODE();
791 
792     NdisMGetDeviceProperty(Adapter->AdapterHandle,
793                            &Pdo,
794                            NULL,
795                            NULL,
796                            NULL,
797                            NULL);
798 
799     Status = IoGetDeviceProperty(Pdo,
800                                  DevicePropertyAddress,
801                                  sizeof(PropertyValue),
802                                  &PropertyValue,
803                                  &Length);
804     if (!NT_SUCCESS(Status))
805         return NDIS_STATUS_FAILURE;
806 
807     /* We need this for PCI devices only ((DeviceNumber << 16) | Function) */
808     Adapter->DeviceNumber = (PropertyValue >> 16) & 0x000000FF;
809 
810     Status = IoGetDeviceProperty(Pdo,
811                                  DevicePropertyBusNumber,
812                                  sizeof(PropertyValue),
813                                  &Adapter->BusNumber,
814                                  &Length);
815     if (!NT_SUCCESS(Status))
816         return NDIS_STATUS_FAILURE;
817 
818     return NDIS_STATUS_SUCCESS;
819 }
820 
821 static
822 CODE_SEG("PAGE")
823 ULONG
DcGetBusModeParameters(_In_ PDC21X4_ADAPTER Adapter,_In_ PPCI_COMMON_CONFIG PciData)824 DcGetBusModeParameters(
825     _In_ PDC21X4_ADAPTER Adapter,
826     _In_ PPCI_COMMON_CONFIG PciData)
827 {
828     ULONG DefaultMode, NewMode;
829 
830     PAGED_CODE();
831 
832     /* TODO: Other architectures than x86 */
833     DefaultMode = DC_BUS_MODE_CACHE_ALIGNMENT_16 | DC_BUS_MODE_BURST_LENGTH_NO_LIMIT;
834 
835     if (!(Adapter->Features & DC_ENABLE_PCI_COMMANDS))
836         return DefaultMode;
837 
838     INFO("PCI Cache Line Size %u\n", PciData->CacheLineSize * 4);
839     INFO("PCI Command %04lx\n", PciData->Command);
840 
841     /* Use the cache line size if it was set up by firmware */
842     switch (PciData->CacheLineSize)
843     {
844         case 8:
845             NewMode = DC_BUS_MODE_CACHE_ALIGNMENT_8 | DC_BUS_MODE_BURST_LENGTH_8;
846             break;
847         case 16:
848             NewMode = DC_BUS_MODE_CACHE_ALIGNMENT_16 | DC_BUS_MODE_BURST_LENGTH_16;
849             break;
850         case 32:
851             NewMode = DC_BUS_MODE_CACHE_ALIGNMENT_32 | DC_BUS_MODE_BURST_LENGTH_32;
852             break;
853 
854         default:
855             return DefaultMode;
856     }
857 
858     /* Enable one of those commands */
859     if (PciData->Command & PCI_ENABLE_WRITE_AND_INVALIDATE)
860     {
861         NewMode |= DC_BUS_MODE_WRITE_INVALIDATE;
862     }
863     else
864     {
865         NewMode |= DC_BUS_MODE_READ_LINE;
866     }
867 
868     return NewMode;
869 }
870 
871 static
872 CODE_SEG("PAGE")
873 NDIS_STATUS
DcRecognizeHardware(_In_ PDC21X4_ADAPTER Adapter)874 DcRecognizeHardware(
875     _In_ PDC21X4_ADAPTER Adapter)
876 {
877     UCHAR Buffer[RTL_SIZEOF_THROUGH_FIELD(PCI_COMMON_CONFIG, CacheLineSize)];
878     PPCI_COMMON_CONFIG PciConfig = (PPCI_COMMON_CONFIG)Buffer; // Partial PCI header
879     PNDIS_TIMER_FUNCTION MediaMonitorRoutine;
880     ULONG Bytes;
881 
882     PAGED_CODE();
883 
884     Bytes = NdisReadPciSlotInformation(Adapter->AdapterHandle,
885                                        0,
886                                        FIELD_OFFSET(PCI_COMMON_CONFIG, VendorID),
887                                        Buffer,
888                                        sizeof(Buffer));
889     if (Bytes != sizeof(Buffer))
890         return NDIS_STATUS_FAILURE;
891 
892     Adapter->DeviceId = PciConfig->DeviceID;
893     Adapter->RevisionId = PciConfig->RevisionID;
894 
895     switch ((PciConfig->DeviceID << 16) | PciConfig->VendorID)
896     {
897         case DC_DEV_DECCHIP_21040:
898         {
899             Adapter->ChipType = DC21040;
900             Adapter->InterruptMask = DC_GENERIC_IRQ_MASK | DC_IRQ_LINK_FAIL;
901             Adapter->LinkStateChangeMask = DC_IRQ_LINK_FAIL;
902             Adapter->HandleLinkStateChange = MediaLinkStateChange21040;
903             MediaMonitorRoutine = MediaMonitor21040Dpc;
904             break;
905         }
906 
907         case DC_DEV_DECCHIP_21041:
908         {
909             Adapter->ChipType = DC21041;
910             Adapter->Features |= DC_HAS_POWER_SAVING | DC_HAS_TIMER;
911             Adapter->InterruptMask = DC_GENERIC_IRQ_MASK | DC_IRQ_LINK_PASS | DC_IRQ_LINK_FAIL;
912             Adapter->LinkStateChangeMask = DC_IRQ_LINK_PASS | DC_IRQ_LINK_FAIL;
913             Adapter->HandleLinkStateChange = MediaLinkStateChange21041;
914             MediaMonitorRoutine = MediaMonitor21041Dpc;
915             break;
916         }
917 
918         case DC_DEV_DECCHIP_21140:
919         {
920             Adapter->ChipType = DC21140;
921             Adapter->Features |= DC_HAS_TIMER;
922 
923             if ((PciConfig->RevisionID & 0xF0) < 0x20)
924             {
925                 /* 21140 */
926                 Adapter->Features |= DC_PERFECT_FILTERING_ONLY;
927             }
928             else
929             {
930                 /* 21140A */
931                 Adapter->Features |= DC_NEED_RX_OVERFLOW_WORKAROUND | DC_ENABLE_PCI_COMMANDS |
932                                      DC_HAS_POWER_SAVING;
933             }
934 
935             Adapter->OpMode |= DC_OPMODE_PORT_ALWAYS;
936             Adapter->InterruptMask = DC_GENERIC_IRQ_MASK;
937             MediaMonitorRoutine = MediaMonitor21140Dpc;
938             break;
939         }
940 
941         case DC_DEV_INTEL_21143:
942         {
943             Adapter->Features |= DC_NEED_RX_OVERFLOW_WORKAROUND | DC_SIA_GPIO |
944                                  DC_HAS_POWER_SAVING | DC_MII_AUTOSENSE | DC_HAS_TIMER;
945 
946             Adapter->InterruptMask = DC_GENERIC_IRQ_MASK | DC_IRQ_LINK_PASS | DC_IRQ_LINK_FAIL;
947             Adapter->LinkStateChangeMask = DC_IRQ_LINK_PASS | DC_IRQ_LINK_FAIL;
948 
949             Adapter->ChipType = DC21143;
950 
951             if ((PciConfig->RevisionID & 0xF0) < 0x20)
952             {
953                 /* 21142 */
954             }
955             else
956             {
957                 /* 21143 */
958                 Adapter->Features |= DC_ENABLE_PCI_COMMANDS;
959                 Adapter->OpMode |= DC_OPMODE_PORT_ALWAYS;
960                 Adapter->InterruptMask |= DC_IRQ_LINK_CHANGED;
961                 Adapter->LinkStateChangeMask |= DC_IRQ_LINK_CHANGED;
962             }
963 
964             /* 21143 -PD and -TD */
965             if ((PciConfig->RevisionID & 0xF0) > 0x30)
966                 Adapter->Features |= DC_HAS_POWER_MANAGEMENT;
967 
968             Adapter->HandleLinkStateChange = MediaLinkStateChange21143;
969             MediaMonitorRoutine = MediaMonitor21143Dpc;
970             break;
971         }
972 
973         case DC_DEV_INTEL_21145:
974         {
975             Adapter->ChipType = DC21145;
976 
977             Adapter->Features |= DC_NEED_RX_OVERFLOW_WORKAROUND | DC_SIA_GPIO |
978                                  DC_HAS_POWER_MANAGEMENT | DC_HAS_POWER_SAVING |
979                                  DC_SIA_ANALOG_CONTROL | DC_ENABLE_PCI_COMMANDS |
980                                  DC_MII_AUTOSENSE | DC_HAS_TIMER;
981 
982             Adapter->OpMode |= DC_OPMODE_PORT_ALWAYS;
983             Adapter->InterruptMask = DC_GENERIC_IRQ_MASK | DC_IRQ_LINK_CHANGED |
984                                      DC_IRQ_LINK_PASS | DC_IRQ_LINK_FAIL;
985             Adapter->LinkStateChangeMask = DC_IRQ_LINK_CHANGED |
986                                            DC_IRQ_LINK_PASS | DC_IRQ_LINK_FAIL;
987             Adapter->HandleLinkStateChange = MediaLinkStateChange21143;
988             MediaMonitorRoutine = MediaMonitor21143Dpc;
989 
990             Adapter->AnalogControl = DC_HPNA_ANALOG_CTRL;
991 
992             /* Workaround for internal RX errata */
993             Adapter->HpnaRegister[HPNA_NOISE_FLOOR] = 0x10;
994             Adapter->HpnaInitBitmap = (1 << HPNA_NOISE_FLOOR);
995             break;
996         }
997 
998         default:
999             return NDIS_STATUS_NOT_RECOGNIZED;
1000     }
1001 
1002     Adapter->BusMode = DcGetBusModeParameters(Adapter, PciConfig);
1003 
1004     INFO("Bus Mode %08lx\n", Adapter->BusMode);
1005 
1006     /* Errata: hash filtering is broken on some chips */
1007     if (Adapter->Features & DC_PERFECT_FILTERING_ONLY)
1008         Adapter->MulticastMaxEntries = DC_SETUP_FRAME_ADDRESSES;
1009     else
1010         Adapter->MulticastMaxEntries = DC_MULTICAST_LIST_SIZE;
1011 
1012     NdisMInitializeTimer(&Adapter->MediaMonitorTimer,
1013                          Adapter->AdapterHandle,
1014                          MediaMonitorRoutine,
1015                          Adapter);
1016 
1017     return NDIS_STATUS_SUCCESS;
1018 }
1019 
1020 CODE_SEG("PAGE")
1021 VOID
DcFreeAdapter(_In_ __drv_freesMem (Mem)PDC21X4_ADAPTER Adapter)1022 DcFreeAdapter(
1023     _In_ __drv_freesMem(Mem) PDC21X4_ADAPTER Adapter)
1024 {
1025     ULONG i;
1026 
1027     PAGED_CODE();
1028 
1029     DcFreeEeprom(Adapter);
1030 
1031     if (Adapter->Interrupt.InterruptObject)
1032     {
1033         NdisMDeregisterInterrupt(&Adapter->Interrupt);
1034     }
1035 
1036     if (Adapter->IoBase)
1037     {
1038         if (Adapter->Flags & DC_IO_MAPPED)
1039         {
1040             NdisMUnmapIoSpace(Adapter->AdapterHandle,
1041                               Adapter->IoBase,
1042                               DC_IO_LENGTH);
1043         }
1044         else
1045         {
1046             NdisMDeregisterIoPortRange(Adapter->AdapterHandle,
1047                                        Adapter->IoBaseAddress.LowPart,
1048                                        DC_IO_LENGTH,
1049                                        Adapter->IoBase);
1050         }
1051     }
1052 
1053     if (Adapter->HeadTcb)
1054     {
1055         NdisFreeMemory(Adapter->HeadTcb, sizeof(DC_TCB) * DC_TRANSMIT_BLOCKS, 0);
1056     }
1057     if (Adapter->RcbArray)
1058     {
1059         NdisFreeMemory(Adapter->RcbArray, sizeof(PVOID) * Adapter->RcbCount, 0);
1060     }
1061     if (Adapter->SetupFrameSaved)
1062     {
1063         NdisFreeMemory(Adapter->SetupFrameSaved, DC_SETUP_FRAME_SIZE, 0);
1064     }
1065 
1066     while (Adapter->AllocRcbList.Next)
1067     {
1068         PSINGLE_LIST_ENTRY Entry = PopEntryList(&Adapter->AllocRcbList);
1069         PDC_RCB Rcb = CONTAINING_RECORD(Entry, DC_RCB, AllocListEntry);
1070 
1071         DcFreeRcb(Adapter, Rcb);
1072     }
1073 
1074     if (Adapter->RbdOriginal)
1075     {
1076         NdisMFreeSharedMemory(Adapter->AdapterHandle,
1077                               DC_MEM_BLOCK_SIZE_RBD,
1078                               FALSE, /* Non-cached */
1079                               Adapter->RbdOriginal,
1080                               Adapter->RbdPhysOriginal);
1081     }
1082     if (Adapter->TbdOriginal)
1083     {
1084         NdisMFreeSharedMemory(Adapter->AdapterHandle,
1085                               DC_MEM_BLOCK_SIZE_TBD_AUX,
1086                               FALSE, /* Non-cached */
1087                               Adapter->TbdOriginal,
1088                               Adapter->TbdPhysOriginal);
1089     }
1090     if (Adapter->CoalesceBuffer)
1091     {
1092         for (i = 0; i < DC_TRANSMIT_BUFFERS; ++i)
1093         {
1094             PDC_TX_BUFFER_DATA SendBufferData = &Adapter->SendBufferData[i];
1095 
1096             if (!SendBufferData->VirtualAddress)
1097                 continue;
1098 
1099             NdisMFreeSharedMemory(Adapter->AdapterHandle,
1100                                   DC_MEM_BLOCK_SIZE_TX_BUFFER,
1101                                   FALSE, /* Non-cached */
1102                                   SendBufferData->VirtualAddress,
1103                                   SendBufferData->PhysicalAddress);
1104         }
1105     }
1106 
1107     if (Adapter->PacketPool)
1108         NdisFreePacketPool(Adapter->PacketPool);
1109     if (Adapter->BufferPool)
1110         NdisFreeBufferPool(Adapter->BufferPool);
1111 
1112     if (Adapter->SendLock.SpinLock)
1113         NdisFreeSpinLock(&Adapter->SendLock);
1114     if (Adapter->ReceiveLock.SpinLock)
1115         NdisFreeSpinLock(&Adapter->ReceiveLock);
1116     if (Adapter->ModeLock.SpinLock)
1117         NdisFreeSpinLock(&Adapter->ModeLock);
1118 
1119     NdisFreeMemory(Adapter->AdapterOriginal, sizeof(*Adapter), 0);
1120 }
1121 
1122 CODE_SEG("PAGE")
1123 NDIS_STATUS
1124 NTAPI
DcInitialize(_Out_ PNDIS_STATUS OpenErrorStatus,_Out_ PUINT SelectedMediumIndex,_In_ PNDIS_MEDIUM MediumArray,_In_ UINT MediumArraySize,_In_ NDIS_HANDLE MiniportAdapterHandle,_In_ NDIS_HANDLE WrapperConfigurationContext)1125 DcInitialize(
1126     _Out_ PNDIS_STATUS OpenErrorStatus,
1127     _Out_ PUINT SelectedMediumIndex,
1128     _In_ PNDIS_MEDIUM MediumArray,
1129     _In_ UINT MediumArraySize,
1130     _In_ NDIS_HANDLE MiniportAdapterHandle,
1131     _In_ NDIS_HANDLE WrapperConfigurationContext)
1132 {
1133     PDC21X4_ADAPTER Adapter;
1134     PVOID UnalignedAdapter;
1135     NDIS_STATUS Status;
1136     ULONG Alignment, AdapterSize, OpMode;
1137     BOOLEAN Success;
1138     UINT i;
1139 
1140     INFO("Called\n");
1141 
1142     PAGED_CODE();
1143 
1144     for (i = 0; i < MediumArraySize; ++i)
1145     {
1146         if (MediumArray[i] == NdisMedium802_3)
1147         {
1148             *SelectedMediumIndex = i;
1149             break;
1150         }
1151     }
1152     if (i == MediumArraySize)
1153     {
1154         ERR("No supported media\n");
1155         return NDIS_STATUS_UNSUPPORTED_MEDIA;
1156     }
1157 
1158     Alignment = NdisGetSharedDataAlignment();
1159     AdapterSize = sizeof(*Adapter) + Alignment;
1160 
1161     Status = NdisAllocateMemoryWithTag((PVOID*)&UnalignedAdapter, AdapterSize, DC21X4_TAG);
1162     if (Status != NDIS_STATUS_SUCCESS)
1163     {
1164         ERR("Failed to allocate adapter context\n");
1165         return NDIS_STATUS_RESOURCES;
1166     }
1167     NdisZeroMemory(UnalignedAdapter, AdapterSize);
1168 
1169     Adapter = ALIGN_UP_POINTER_BY(UnalignedAdapter, Alignment);
1170     Adapter->AdapterOriginal = UnalignedAdapter;
1171     Adapter->AdapterSize = AdapterSize;
1172     Adapter->AdapterHandle = MiniportAdapterHandle;
1173     Adapter->WrapperConfigurationHandle = WrapperConfigurationContext;
1174 
1175     NdisInitializeWorkItem(&Adapter->ResetWorkItem, DcResetWorker, Adapter);
1176     NdisInitializeWorkItem(&Adapter->PowerWorkItem, DcPowerWorker, Adapter);
1177     NdisInitializeWorkItem(&Adapter->TxRecoveryWorkItem, DcTransmitTimeoutRecoveryWorker, Adapter);
1178 
1179     NdisMSetAttributesEx(MiniportAdapterHandle,
1180                          Adapter,
1181                          2, /* CheckForHangTimeInSeconds */
1182                          NDIS_ATTRIBUTE_BUS_MASTER |
1183                          NDIS_ATTRIBUTE_DESERIALIZE |
1184                          NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS,
1185                          NdisInterfacePci);
1186 
1187     Status = DcRecognizeHardware(Adapter);
1188     if (Status != NDIS_STATUS_SUCCESS)
1189     {
1190         return Status;
1191     }
1192 
1193     Status = DcInitializeAdapterResources(Adapter);
1194     if (Status != NDIS_STATUS_SUCCESS)
1195     {
1196         goto Failure;
1197     }
1198 
1199     Status = DcInitializeAdapterLocation(Adapter);
1200     if (Status != NDIS_STATUS_SUCCESS)
1201     {
1202         goto Failure;
1203     }
1204 
1205     /* Bring the chip out of sleep mode */
1206     DcPowerSave(Adapter, FALSE);
1207 
1208     OpMode = DC_READ(Adapter, DcCsr6_OpMode);
1209     OpMode &= ~(DC_OPMODE_RX_ENABLE | DC_OPMODE_TX_ENABLE);
1210     DC_WRITE(Adapter, DcCsr6_OpMode, OpMode);
1211 
1212     MediaInitMediaList(Adapter);
1213 
1214     Status = DcReadEeprom(Adapter);
1215     if (Status != NDIS_STATUS_SUCCESS)
1216     {
1217         goto Failure;
1218     }
1219 
1220     NdisMoveMemory(Adapter->CurrentMacAddress, Adapter->PermanentMacAddress, ETH_LENGTH_OF_ADDRESS);
1221 
1222     Status = DcReadConfiguration(Adapter);
1223     if (Status != NDIS_STATUS_SUCCESS)
1224     {
1225         goto Failure;
1226     }
1227 
1228     Status = DcAllocateMemory(Adapter);
1229     if (Status != NDIS_STATUS_SUCCESS)
1230     {
1231         goto Failure;
1232     }
1233 
1234     DcInitTestPacket(Adapter);
1235 
1236     DcCreateRxRing(Adapter);
1237 
1238     /* Execute the reset sequence */
1239     if (Adapter->ResetStreamLength)
1240     {
1241         for (i = 0; i < Adapter->ResetStreamLength; ++i)
1242         {
1243             DcWriteGpio(Adapter, Adapter->ResetStream[i]);
1244             NdisMSleep(100);
1245         }
1246 
1247         /* Give the PHY some time to reset */
1248         NdisMSleep(5000);
1249     }
1250 
1251     /* Perform a software reset */
1252     DC_WRITE(Adapter, DcCsr0_BusMode, DC_BUS_MODE_SOFT_RESET);
1253     NdisMSleep(100);
1254     DC_WRITE(Adapter, DcCsr0_BusMode, Adapter->BusMode);
1255 
1256     /* Try to detect a MII PHY */
1257     if (Adapter->Features & DC_HAS_MII)
1258     {
1259         MediaSelectMiiPort(Adapter, TRUE);
1260 
1261         Success = DcFindMiiPhy(Adapter);
1262         if (Success)
1263         {
1264             /* Disable all link interrupts when the MII PHY media is found */
1265             Adapter->InterruptMask &= ~(DC_IRQ_LINK_CHANGED | DC_IRQ_LINK_FAIL | DC_IRQ_LINK_PASS);
1266             Adapter->LinkStateChangeMask = 0;
1267         }
1268         else
1269         {
1270             /* Incorrect EEPROM table or PHY is not connected, switch to a serial transceiver */
1271             WARN("No PHY devices found\n");
1272             Adapter->Features &= ~DC_HAS_MII;
1273         }
1274     }
1275 
1276     MediaInitDefaultMedia(Adapter, Adapter->DefaultMedia);
1277 
1278     /* Set the MAC address */
1279     DcSetupFrameInitialize(Adapter);
1280 
1281     /* Clear statistics */
1282     DC_READ(Adapter, DcCsr8_RxCounters);
1283 
1284     Adapter->Flags |= DC_FIRST_SETUP;
1285 
1286     Status = DcSetupAdapter(Adapter);
1287     if (Status != NDIS_STATUS_SUCCESS)
1288     {
1289         ERR("Failed to initialize the NIC\n");
1290         goto Disable;
1291     }
1292 
1293     Adapter->Flags &= ~DC_FIRST_SETUP;
1294 
1295     Status = NdisMRegisterInterrupt(&Adapter->Interrupt,
1296                                     Adapter->AdapterHandle,
1297                                     Adapter->InterruptVector,
1298                                     Adapter->InterruptLevel,
1299                                     TRUE, /* Request ISR calls */
1300                                     !!(Adapter->Flags & DC_IRQ_SHARED),
1301                                     (Adapter->InterruptFlags & CM_RESOURCE_INTERRUPT_LATCHED) ?
1302                                     NdisInterruptLatched : NdisInterruptLevelSensitive);
1303     if (Status != NDIS_STATUS_SUCCESS)
1304     {
1305         ERR("Unable to register interrupt\n");
1306         goto Disable;
1307     }
1308 
1309     DcStartAdapter(Adapter);
1310 
1311     return NDIS_STATUS_SUCCESS;
1312 
1313 Disable:
1314     DcDisableHw(Adapter);
1315 Failure:
1316     ERR("Initialization failed with status %08lx\n", Status);
1317 
1318     DcFreeAdapter(Adapter);
1319 
1320     return Status;
1321 }
1322