xref: /reactos/drivers/network/dd/e1000/hardware.c (revision ebad64bc)
1 /*
2  * PROJECT:     ReactOS Intel PRO/1000 Driver
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Hardware specific functions
5  * COPYRIGHT:   Copyright 2018 Mark Jansen (mark.jansen@reactos.org)
6  */
7 
8 #include "nic.h"
9 
10 #include <debug.h>
11 
12 
13 static USHORT SupportedDevices[] =
14 {
15     0x100f,     // Intel 82545EM (VMWare E1000)
16 };
17 
18 
19 static ULONG E1000WriteFlush(IN PE1000_ADAPTER Adapter)
20 {
21     volatile ULONG Value;
22 
23     NdisReadRegisterUlong(Adapter->IoBase + E1000_REG_STATUS, &Value);
24     return Value;
25 }
26 
27 static VOID E1000WriteUlong(IN PE1000_ADAPTER Adapter, IN ULONG Address, IN ULONG Value)
28 {
29     NdisWriteRegisterUlong((PULONG)(Adapter->IoBase + Address), Value);
30 }
31 
32 static VOID E1000ReadUlong(IN PE1000_ADAPTER Adapter, IN ULONG Address, OUT PULONG Value)
33 {
34     NdisReadRegisterUlong((PULONG)(Adapter->IoBase + Address), Value);
35 }
36 
37 static VOID E1000WriteIoUlong(IN PE1000_ADAPTER Adapter, IN ULONG Address, IN ULONG Value)
38 {
39     NdisRawWritePortUlong((PULONG)(Adapter->IoPort), Address);
40     E1000WriteFlush(Adapter);
41     NdisRawWritePortUlong((PULONG)(Adapter->IoPort + 4), Value);
42 }
43 
44 static BOOLEAN E1000ReadMdic(IN PE1000_ADAPTER Adapter, IN ULONG Address, USHORT *Result)
45 {
46     ULONG ResultAddress;
47     ULONG Mdic;
48     UINT n;
49 
50     if (Address > MAX_PHY_REG_ADDRESS)
51     {
52         NDIS_DbgPrint(MIN_TRACE, ("PHY Address %d is invalid\n", Address));
53         return 1;
54     }
55 
56     Mdic = (Address << E1000_MDIC_REGADD_SHIFT);
57     Mdic |= (E1000_MDIC_PHYADD_GIGABIT << E1000_MDIC_PHYADD_SHIFT);
58     Mdic |= E1000_MDIC_OP_READ;
59 
60     E1000WriteUlong(Adapter, E1000_REG_MDIC, Mdic);
61 
62     for (n = 0; n < MAX_PHY_READ_ATTEMPTS; n++)
63     {
64         NdisStallExecution(50);
65         E1000ReadUlong(Adapter, E1000_REG_MDIC, &Mdic);
66         if (Mdic & E1000_MDIC_R)
67             break;
68     }
69     if (!(Mdic & E1000_MDIC_R))
70     {
71         NDIS_DbgPrint(MIN_TRACE, ("MDI Read incomplete\n"));
72         return FALSE;
73     }
74     if (Mdic & E1000_MDIC_E)
75     {
76         NDIS_DbgPrint(MIN_TRACE, ("MDI Read error\n"));
77         return FALSE;
78     }
79 
80     ResultAddress = (Mdic >> E1000_MDIC_REGADD_SHIFT) & MAX_PHY_REG_ADDRESS;
81 
82     if (ResultAddress!= Address)
83     {
84         /* Add locking? */
85         NDIS_DbgPrint(MIN_TRACE, ("MDI Read got wrong address (%d instead of %d)\n",
86                                   ResultAddress, Address));
87         return FALSE;
88     }
89     *Result = (USHORT) Mdic;
90     return TRUE;
91 }
92 
93 
94 static BOOLEAN E1000ReadEeprom(IN PE1000_ADAPTER Adapter, IN UCHAR Address, USHORT *Result)
95 {
96     UINT Value;
97     UINT n;
98 
99     E1000WriteUlong(Adapter, E1000_REG_EERD, E1000_EERD_START | ((UINT)Address << E1000_EERD_ADDR_SHIFT));
100 
101     for (n = 0; n < MAX_EEPROM_READ_ATTEMPTS; ++n)
102     {
103         NdisStallExecution(5);
104 
105         E1000ReadUlong(Adapter, E1000_REG_EERD, &Value);
106 
107         if (Value & E1000_EERD_DONE)
108             break;
109     }
110     if (!(Value & E1000_EERD_DONE))
111     {
112         NDIS_DbgPrint(MIN_TRACE, ("EEPROM Read incomplete\n"));
113         return FALSE;
114     }
115     *Result = (USHORT)(Value >> E1000_EERD_DATA_SHIFT);
116     return TRUE;
117 }
118 
119 BOOLEAN E1000ValidateNvmChecksum(IN PE1000_ADAPTER Adapter)
120 {
121     USHORT Checksum = 0, Data;
122     UINT n;
123 
124     /* 5.6.35 Checksum Word Calculation (Word 3Fh) */
125     for (n = 0; n <= E1000_NVM_REG_CHECKSUM; n++)
126     {
127         if (!E1000ReadEeprom(Adapter, n, &Data))
128         {
129             return FALSE;
130         }
131         Checksum += Data;
132     }
133 
134     if (Checksum != NVM_MAGIC_SUM)
135     {
136         NDIS_DbgPrint(MIN_TRACE, ("EEPROM has an invalid checksum of 0x%x\n", (ULONG)Checksum));
137         return FALSE;
138     }
139 
140     return TRUE;
141 }
142 
143 
144 BOOLEAN
145 NTAPI
146 NICRecognizeHardware(
147     IN PE1000_ADAPTER Adapter)
148 {
149     UINT n;
150     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
151 
152     if (Adapter->VendorID != HW_VENDOR_INTEL)
153     {
154         NDIS_DbgPrint(MIN_TRACE, ("Unknown vendor: 0x%x\n", Adapter->VendorID));
155         return FALSE;
156     }
157 
158     for (n = 0; n < ARRAYSIZE(SupportedDevices); ++n)
159     {
160         if (SupportedDevices[n] == Adapter->DeviceID)
161         {
162             return TRUE;
163         }
164     }
165 
166     NDIS_DbgPrint(MIN_TRACE, ("Unknown device: 0x%x\n", Adapter->DeviceID));
167 
168     return FALSE;
169 }
170 
171 NDIS_STATUS
172 NTAPI
173 NICInitializeAdapterResources(
174     IN PE1000_ADAPTER Adapter,
175     IN PNDIS_RESOURCE_LIST ResourceList)
176 {
177     UINT n;
178     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
179 
180     for (n = 0; n < ResourceList->Count; n++)
181     {
182         PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor = ResourceList->PartialDescriptors + n;
183 
184         switch (ResourceDescriptor->Type)
185         {
186         case CmResourceTypePort:
187             ASSERT(Adapter->IoPortAddress == 0);
188             ASSERT(ResourceDescriptor->u.Port.Start.HighPart == 0);
189 
190             Adapter->IoPortAddress = ResourceDescriptor->u.Port.Start.LowPart;
191             Adapter->IoPortLength = ResourceDescriptor->u.Port.Length;
192 
193             NDIS_DbgPrint(MID_TRACE, ("I/O port range is %p to %p\n",
194                                       Adapter->IoPortAddress,
195                                       Adapter->IoPortAddress + Adapter->IoPortLength));
196             break;
197         case CmResourceTypeInterrupt:
198             ASSERT(Adapter->InterruptVector == 0);
199             ASSERT(Adapter->InterruptLevel == 0);
200 
201             Adapter->InterruptVector = ResourceDescriptor->u.Interrupt.Vector;
202             Adapter->InterruptLevel = ResourceDescriptor->u.Interrupt.Level;
203             Adapter->InterruptShared = (ResourceDescriptor->ShareDisposition == CmResourceShareShared);
204             Adapter->InterruptFlags = ResourceDescriptor->Flags;
205 
206             NDIS_DbgPrint(MID_TRACE, ("IRQ vector is %d\n", Adapter->InterruptVector));
207             break;
208         case CmResourceTypeMemory:
209             /* Internal registers and memories (including PHY) */
210             if (ResourceDescriptor->u.Memory.Length ==  (128 * 1024))
211             {
212                 ASSERT(Adapter->IoAddress.LowPart == 0);
213                 ASSERT(ResourceDescriptor->u.Port.Start.HighPart == 0);
214 
215 
216                 Adapter->IoAddress.QuadPart = ResourceDescriptor->u.Memory.Start.QuadPart;
217                 Adapter->IoLength = ResourceDescriptor->u.Memory.Length;
218                 NDIS_DbgPrint(MID_TRACE, ("Memory range is %I64x to %I64x\n",
219                                           Adapter->IoAddress.QuadPart,
220                                           Adapter->IoAddress.QuadPart + Adapter->IoLength));
221             }
222             break;
223 
224         default:
225             NDIS_DbgPrint(MIN_TRACE, ("Unrecognized resource type: 0x%x\n", ResourceDescriptor->Type));
226             break;
227         }
228     }
229 
230     if (Adapter->IoAddress.QuadPart == 0 || Adapter->IoPortAddress == 0 || Adapter->InterruptVector == 0)
231     {
232         NDIS_DbgPrint(MIN_TRACE, ("Adapter didn't receive enough resources\n"));
233         return NDIS_STATUS_RESOURCES;
234     }
235 
236     return NDIS_STATUS_SUCCESS;
237 }
238 
239 NDIS_STATUS
240 NTAPI
241 NICAllocateIoResources(
242     IN PE1000_ADAPTER Adapter)
243 {
244     NDIS_STATUS Status;
245     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
246 
247     Status = NdisMRegisterIoPortRange((PVOID*)&Adapter->IoPort,
248                                       Adapter->AdapterHandle,
249                                       Adapter->IoPortAddress,
250                                       Adapter->IoPortLength);
251     if (Status != NDIS_STATUS_SUCCESS)
252     {
253         NDIS_DbgPrint(MIN_TRACE, ("Unable to register IO port range (0x%x)\n", Status));
254         return NDIS_STATUS_RESOURCES;
255     }
256 
257     Status = NdisMMapIoSpace((PVOID*)&Adapter->IoBase,
258                              Adapter->AdapterHandle,
259                              Adapter->IoAddress,
260                              Adapter->IoLength);
261 
262 
263     NdisMAllocateSharedMemory(Adapter->AdapterHandle,
264                               sizeof(E1000_TRANSMIT_DESCRIPTOR) * NUM_TRANSMIT_DESCRIPTORS,
265                               FALSE,
266                               (PVOID*)&Adapter->TransmitDescriptors,
267                               &Adapter->TransmitDescriptorsPa);
268     if (Adapter->TransmitDescriptors == NULL)
269     {
270         NDIS_DbgPrint(MIN_TRACE, ("Unable to allocate transmit descriptors\n"));
271         return NDIS_STATUS_RESOURCES;
272     }
273 
274 
275     return NDIS_STATUS_SUCCESS;
276 }
277 
278 NDIS_STATUS
279 NTAPI
280 NICRegisterInterrupts(
281     IN PE1000_ADAPTER Adapter)
282 {
283     NDIS_STATUS Status;
284     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
285 
286     Status = NdisMRegisterInterrupt(&Adapter->Interrupt,
287                                     Adapter->AdapterHandle,
288                                     Adapter->InterruptVector,
289                                     Adapter->InterruptLevel,
290                                     TRUE, // We always want ISR calls
291                                     Adapter->InterruptShared,
292                                     (Adapter->InterruptFlags & CM_RESOURCE_INTERRUPT_LATCHED) ?
293                                     NdisInterruptLatched : NdisInterruptLevelSensitive);
294 
295     if (Status == NDIS_STATUS_SUCCESS)
296     {
297         Adapter->InterruptRegistered = TRUE;
298     }
299 
300     return Status;
301 }
302 
303 NDIS_STATUS
304 NTAPI
305 NICUnregisterInterrupts(
306     IN PE1000_ADAPTER Adapter)
307 {
308     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
309 
310     if (Adapter->InterruptRegistered)
311     {
312         NdisMDeregisterInterrupt(&Adapter->Interrupt);
313         Adapter->InterruptRegistered = FALSE;
314     }
315 
316     return NDIS_STATUS_SUCCESS;
317 }
318 
319 NDIS_STATUS
320 NTAPI
321 NICReleaseIoResources(
322     IN PE1000_ADAPTER Adapter)
323 {
324     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
325 
326     if (Adapter->TransmitDescriptors != NULL)
327     {
328         /* Disassociate our shared buffer before freeing it to avoid NIC-induced memory corruption */
329         //E1000WriteUlong(Adapter, E1000_REG_TDH, 0);
330         //E1000WriteUlong(Adapter, E1000_REG_TDT, 0);
331 
332         NdisMFreeSharedMemory(Adapter->AdapterHandle,
333                               sizeof(E1000_TRANSMIT_DESCRIPTOR) * NUM_TRANSMIT_DESCRIPTORS,
334                               FALSE,
335                               Adapter->TransmitDescriptors,
336                               Adapter->TransmitDescriptorsPa);
337 
338         Adapter->TransmitDescriptors = NULL;
339     }
340 
341 
342 
343     if (Adapter->IoPort)
344     {
345         NdisMDeregisterIoPortRange(Adapter->AdapterHandle,
346                                    Adapter->IoPortAddress,
347                                    Adapter->IoPortLength,
348                                    Adapter->IoPort);
349     }
350 
351     if (Adapter->IoBase)
352     {
353         NdisMUnmapIoSpace(Adapter->AdapterHandle, Adapter->IoBase, Adapter->IoLength);
354     }
355 
356 
357     return NDIS_STATUS_SUCCESS;
358 }
359 
360 
361 NDIS_STATUS
362 NTAPI
363 NICPowerOn(
364     IN PE1000_ADAPTER Adapter)
365 {
366     NDIS_STATUS Status;
367     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
368 
369     Status = NICSoftReset(Adapter);
370     if (Status != NDIS_STATUS_SUCCESS)
371     {
372         return Status;
373     }
374 
375     if (!E1000ValidateNvmChecksum(Adapter))
376     {
377         return NDIS_STATUS_INVALID_DATA;
378     }
379 
380     return NDIS_STATUS_SUCCESS;
381 }
382 
383 NDIS_STATUS
384 NTAPI
385 NICSoftReset(
386     IN PE1000_ADAPTER Adapter)
387 {
388     ULONG Value, ResetAttempts;
389     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
390 
391     //em_get_hw_control(adapter);
392 
393     NICDisableInterrupts(Adapter);
394     E1000WriteUlong(Adapter, E1000_REG_RCTL, 0);
395     E1000ReadUlong(Adapter, E1000_REG_CTRL, &Value);
396     /* Write this using IO port, some devices cannot ack this otherwise */
397     E1000WriteIoUlong(Adapter, E1000_REG_CTRL, Value | E1000_CTRL_RST);
398 
399 
400     for (ResetAttempts = 0; ResetAttempts < MAX_RESET_ATTEMPTS; ResetAttempts++)
401     {
402         NdisStallExecution(100);
403         E1000ReadUlong(Adapter, E1000_REG_CTRL, &Value);
404 
405         if (!(Value & E1000_CTRL_RST))
406         {
407             NDIS_DbgPrint(MAX_TRACE, ("Device is back (%u)\n", ResetAttempts));
408 
409             NICDisableInterrupts(Adapter);
410             /* Clear out interrupts */
411             E1000ReadUlong(Adapter, E1000_REG_ICR, &Value);
412 
413             //NdisWriteRegisterUlong(Adapter->IoBase + E1000_REG_WUFC, 0);
414             //NdisWriteRegisterUlong(Adapter->IoBase + E1000_REG_VET, E1000_VET_VLAN);
415 
416             return NDIS_STATUS_SUCCESS;
417         }
418     }
419 
420     NDIS_DbgPrint(MIN_TRACE, ("Device did not recover\n"));
421     return NDIS_STATUS_FAILURE;
422 }
423 
424 NDIS_STATUS
425 NTAPI
426 NICEnableTxRx(
427     IN PE1000_ADAPTER Adapter)
428 {
429     ULONG Value;
430 
431     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
432 
433     /* Transmit descriptor ring buffer */
434     E1000WriteUlong(Adapter, E1000_REG_TDBAH, Adapter->TransmitDescriptorsPa.HighPart);
435     E1000WriteUlong(Adapter, E1000_REG_TDBAL, Adapter->TransmitDescriptorsPa.LowPart);
436 
437     /* Transmit descriptor buffer size */
438     E1000WriteUlong(Adapter, E1000_REG_TDLEN, sizeof(E1000_TRANSMIT_DESCRIPTOR) * NUM_TRANSMIT_DESCRIPTORS);
439 
440     /* Transmit descriptor tail / head */
441     E1000WriteUlong(Adapter, E1000_REG_TDH, 0);
442     E1000WriteUlong(Adapter, E1000_REG_TDT, 0);
443     Adapter->CurrentTxDesc = 0;
444 
445 
446     Value = E1000_TCTL_EN | E1000_TCTL_PSP;
447     E1000WriteUlong(Adapter, E1000_REG_TCTL, Value);
448 
449 
450 
451 
452     //E1000ReadUlong(Adapter, E1000_REG_RCTL, &Value);
453     //Value = E1000_RCTL_BSIZE_2048 | E1000_RCTL_SECRC | E1000_RCTL_EN;
454     //E1000WriteUlong(Adapter, E1000_REG_RCTL, Value);
455 
456 
457     return NDIS_STATUS_SUCCESS;
458 }
459 
460 NDIS_STATUS
461 NTAPI
462 NICDisableTxRx(
463     IN PE1000_ADAPTER Adapter)
464 {
465     ULONG Value;
466 
467     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
468 
469     E1000ReadUlong(Adapter, E1000_REG_TCTL, &Value);
470     Value &= ~E1000_TCTL_EN;
471     E1000WriteUlong(Adapter, E1000_REG_TCTL, Value);
472 
473     //E1000ReadUlong(Adapter, E1000_REG_RCTL, &Value);
474     //Value &= ~E1000_RCTL_EN;
475     //E1000WriteUlong(Adapter, E1000_REG_RCTL, Value);
476 
477     return NDIS_STATUS_SUCCESS;
478 }
479 
480 NDIS_STATUS
481 NTAPI
482 NICGetPermanentMacAddress(
483     IN PE1000_ADAPTER Adapter,
484     OUT PUCHAR MacAddress)
485 {
486     USHORT AddrWord;
487     UINT n;
488 
489     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
490 
491     /* Should we read from RAL/RAH first? */
492     for (n = 0; n < (IEEE_802_ADDR_LENGTH / 2); ++n)
493     {
494         if (!E1000ReadEeprom(Adapter, (UCHAR)n, &AddrWord))
495             return NDIS_STATUS_FAILURE;
496         Adapter->PermanentMacAddress[n * 2 + 0] = AddrWord & 0xff;
497         Adapter->PermanentMacAddress[n * 2 + 1] = (AddrWord >> 8) & 0xff;
498     }
499 
500     NDIS_DbgPrint(MIN_TRACE, ("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
501                               Adapter->PermanentMacAddress[0],
502                               Adapter->PermanentMacAddress[1],
503                               Adapter->PermanentMacAddress[2],
504                               Adapter->PermanentMacAddress[3],
505                               Adapter->PermanentMacAddress[4],
506                               Adapter->PermanentMacAddress[5]));
507     return NDIS_STATUS_SUCCESS;
508 }
509 
510 NDIS_STATUS
511 NTAPI
512 NICUpdateMulticastList(
513     IN PE1000_ADAPTER Adapter)
514 {
515     UINT n;
516     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
517 
518     for (n = 0; n < MAXIMUM_MULTICAST_ADDRESSES; ++n)
519     {
520         ULONG Ral = *(ULONG *)Adapter->MulticastList[n].MacAddress;
521         ULONG Rah = *(USHORT *)&Adapter->MulticastList[n].MacAddress[4];
522 
523         if (Rah || Ral)
524         {
525             Rah |= E1000_RAH_AV;
526 
527             E1000WriteUlong(Adapter, E1000_REG_RAL + (8*n), Ral);
528             E1000WriteUlong(Adapter, E1000_REG_RAH + (8*n), Rah);
529         }
530         else
531         {
532             E1000WriteUlong(Adapter, E1000_REG_RAH + (8*n), 0);
533             E1000WriteUlong(Adapter, E1000_REG_RAL + (8*n), 0);
534         }
535     }
536 
537     return NDIS_STATUS_SUCCESS;
538 }
539 
540 NDIS_STATUS
541 NTAPI
542 NICApplyPacketFilter(
543     IN PE1000_ADAPTER Adapter)
544 {
545     ULONG FilterMask = 0;
546 
547     E1000ReadUlong(Adapter, E1000_REG_RCTL, &FilterMask);
548 
549     FilterMask &= ~E1000_RCTL_FILTER_BITS;
550 
551     if (Adapter->PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST)
552     {
553         /* Multicast Promiscuous Enabled */
554         FilterMask |= E1000_RCTL_MPE;
555     }
556     if (Adapter->PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS)
557     {
558         /* Unicast Promiscuous Enabled */
559         FilterMask |= E1000_RCTL_UPE;
560         /* Multicast Promiscuous Enabled */
561         FilterMask |= E1000_RCTL_MPE;
562     }
563     if (Adapter->PacketFilter & NDIS_PACKET_TYPE_MAC_FRAME)
564     {
565         /* Pass MAC Control Frames */
566         FilterMask |= E1000_RCTL_PMCF;
567     }
568     if (Adapter->PacketFilter & NDIS_PACKET_TYPE_BROADCAST)
569     {
570         /* Broadcast Accept Mode */
571         FilterMask |= E1000_RCTL_BAM;
572     }
573 
574     E1000WriteUlong(Adapter, E1000_REG_RCTL, FilterMask);
575 
576     return NDIS_STATUS_SUCCESS;
577 }
578 
579 NDIS_STATUS
580 NTAPI
581 NICApplyInterruptMask(
582     IN PE1000_ADAPTER Adapter)
583 {
584     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
585 
586     E1000WriteUlong(Adapter, E1000_REG_IMS, Adapter->InterruptMask);
587     return NDIS_STATUS_SUCCESS;
588 }
589 
590 NDIS_STATUS
591 NTAPI
592 NICDisableInterrupts(
593     IN PE1000_ADAPTER Adapter)
594 {
595     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
596 
597     E1000WriteUlong(Adapter, E1000_REG_IMC, ~0);
598     return NDIS_STATUS_SUCCESS;
599 }
600 
601 ULONG
602 NTAPI
603 NICInterruptRecognized(
604     IN PE1000_ADAPTER Adapter,
605     OUT PBOOLEAN InterruptRecognized)
606 {
607     ULONG Value;
608 
609     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
610 
611     /* Reading the interrupt acknowledges them */
612     E1000ReadUlong(Adapter, E1000_REG_ICR, &Value);
613 
614     *InterruptRecognized = (Value & Adapter->InterruptMask) != 0;
615 
616     return (Value & Adapter->InterruptMask);
617 }
618 
619 VOID
620 NTAPI
621 NICUpdateLinkStatus(
622     IN PE1000_ADAPTER Adapter)
623 {
624     ULONG SpeedIndex;
625     USHORT PhyStatus;
626     static ULONG SpeedValues[] = { 10, 100, 1000, 1000 };
627 
628     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
629 
630 #if 0
631     /* This does not work */
632     E1000ReadUlong(Adapter, E1000_REG_STATUS, &DeviceStatus);
633     E1000ReadUlong(Adapter, E1000_REG_STATUS, &DeviceStatus);
634     Adapter->MediaState = (DeviceStatus & E1000_STATUS_LU) ? NdisMediaStateConnected : NdisMediaStateDisconnected;
635     SpeedIndex = (DeviceStatus & E1000_STATUS_SPEEDMASK) >> E1000_STATUS_SPEEDSHIFT;
636     Adapter->LinkSpeedMbps = SpeedValues[SpeedIndex];
637 #else
638     /* Link bit can be sticky on some boards, read it twice */
639     if (!E1000ReadMdic(Adapter, E1000_PHY_STATUS, &PhyStatus))
640         NdisStallExecution(100);
641 
642     Adapter->MediaState = NdisMediaStateDisconnected;
643     Adapter->LinkSpeedMbps = 0;
644 
645     if (!E1000ReadMdic(Adapter, E1000_PHY_STATUS, &PhyStatus))
646         return;
647 
648     if (!(PhyStatus & E1000_PS_LINK_STATUS))
649         return;
650 
651     Adapter->MediaState = NdisMediaStateConnected;
652 
653     if (E1000ReadMdic(Adapter, E1000_PHY_SPECIFIC_STATUS, &PhyStatus))
654     {
655         if (PhyStatus & E1000_PSS_SPEED_AND_DUPLEX)
656         {
657             SpeedIndex = (PhyStatus & E1000_PSS_SPEEDMASK) >> E1000_PSS_SPEEDSHIFT;
658             Adapter->LinkSpeedMbps = SpeedValues[SpeedIndex];
659         }
660         else
661         {
662             NDIS_DbgPrint(MIN_TRACE, ("Speed and duplex not yet resolved, retry?.\n"));
663         }
664     }
665 #endif
666 }
667 
668 NDIS_STATUS
669 NTAPI
670 NICTransmitPacket(
671     IN PE1000_ADAPTER Adapter,
672     IN ULONG PhysicalAddress,
673     IN ULONG Length)
674 {
675     volatile PE1000_TRANSMIT_DESCRIPTOR TransmitDescriptor;
676 
677     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
678 
679     TransmitDescriptor = Adapter->TransmitDescriptors + Adapter->CurrentTxDesc;
680     TransmitDescriptor->Address = PhysicalAddress;
681     TransmitDescriptor->Length = Length;
682     TransmitDescriptor->ChecksumOffset = 0;
683     TransmitDescriptor->Command = E1000_TDESC_CMD_RS | E1000_TDESC_CMD_IFCS | E1000_TDESC_CMD_EOP;
684     TransmitDescriptor->Status = 0;
685     TransmitDescriptor->ChecksumStartField = 0;
686     TransmitDescriptor->Special = 0;
687 
688     Adapter->CurrentTxDesc = (Adapter->CurrentTxDesc + 1) % NUM_TRANSMIT_DESCRIPTORS;
689 
690     E1000WriteUlong(Adapter, E1000_REG_TDT, Adapter->CurrentTxDesc);
691 
692     NDIS_DbgPrint(MAX_TRACE, ("CurrentTxDesc:%u, LastTxDesc:%u\n", Adapter->CurrentTxDesc, Adapter->LastTxDesc));
693 
694     if (Adapter->CurrentTxDesc == Adapter->LastTxDesc)
695     {
696         NDIS_DbgPrint(MID_TRACE, ("All TX descriptors are full now\n"));
697         Adapter->TxFull = TRUE;
698     }
699 
700     return NDIS_STATUS_SUCCESS;
701 }
702