2 * ReactOS Realtek 8139 Driver
4 * Copyright (C) 2013 Cameron Gutman
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 ULONG DebugTraceLevel
= MIN_TRACE
;
32 OUT PBOOLEAN AddressingReset
,
33 IN NDIS_HANDLE MiniportAdapterContext
36 *AddressingReset
= FALSE
;
37 return NDIS_STATUS_FAILURE
;
43 IN NDIS_HANDLE MiniportAdapterContext
,
44 IN PNDIS_PACKET Packet
,
48 PRTL_ADAPTER adapter
= (PRTL_ADAPTER
)MiniportAdapterContext
;
50 PSCATTER_GATHER_LIST sgList
= NDIS_PER_PACKET_INFO_FROM_PACKET(Packet
,
51 ScatterGatherListPacketInfo
);
54 PNDIS_BUFFER firstBuffer
;
56 UINT firstBufferLength
, totalBufferLength
;
59 ASSERT(sgList
!= NULL
);
61 ASSERT(sgList
->NumberOfElements
== 1);
62 ASSERT(sgList
->Elements
[0].Address
.HighPart
== 0);
63 ASSERT((sgList
->Elements
[0].Address
.LowPart
& 3) == 0);
64 ASSERT(sgList
->Elements
[0].Length
<= MAXIMUM_FRAME_SIZE
);
66 NDIS_DbgPrint(MAX_TRACE
, ("Sending %d byte packet\n", sgList
->Elements
[0].Length
));
68 NdisAcquireSpinLock(&adapter
->Lock
);
72 NDIS_DbgPrint(MIN_TRACE
, ("All TX descriptors are full\n"));
73 NdisReleaseSpinLock(&adapter
->Lock
);
74 return NDIS_STATUS_RESOURCES
;
77 NDIS_DbgPrint(MAX_TRACE
, ("Sending packet on TX desc %d\n", adapter
->CurrentTxDesc
));
80 // If this is a runt, we need to pad it manually for the RTL8139
82 if (sgList
->Elements
[0].Length
< MINIMUM_FRAME_SIZE
)
84 transmitLength
= MINIMUM_FRAME_SIZE
;
85 transmitBuffer
= adapter
->RuntTxBuffersPa
.LowPart
+
86 (MINIMUM_FRAME_SIZE
* adapter
->CurrentTxDesc
);
88 NdisGetFirstBufferFromPacketSafe(Packet
,
94 if (firstBufferVa
== NULL
)
96 NDIS_DbgPrint(MIN_TRACE
, ("Unable to get buffer from packet\n"));
97 NdisReleaseSpinLock(&adapter
->Lock
);
98 return NDIS_STATUS_RESOURCES
;
101 ASSERT(firstBufferLength
== totalBufferLength
);
103 runtBuffer
= adapter
->RuntTxBuffers
+ (MINIMUM_FRAME_SIZE
* adapter
->CurrentTxDesc
);
104 RtlCopyMemory(runtBuffer
, firstBufferVa
, firstBufferLength
);
105 RtlFillMemory(runtBuffer
+ firstBufferLength
, MINIMUM_FRAME_SIZE
- firstBufferLength
, 0x00);
109 transmitLength
= sgList
->Elements
[0].Length
;
110 transmitBuffer
= sgList
->Elements
[0].Address
.LowPart
;
113 status
= NICTransmitPacket(adapter
, adapter
->CurrentTxDesc
, transmitBuffer
, transmitLength
);
114 if (status
!= NDIS_STATUS_SUCCESS
)
116 NDIS_DbgPrint(MIN_TRACE
, ("Transmit packet failed\n"));
117 NdisReleaseSpinLock(&adapter
->Lock
);
121 adapter
->CurrentTxDesc
++;
122 adapter
->CurrentTxDesc
%= TX_DESC_COUNT
;
124 if (adapter
->CurrentTxDesc
== adapter
->DirtyTxDesc
)
126 NDIS_DbgPrint(MID_TRACE
, ("All TX descriptors are full now\n"));
127 adapter
->TxFull
= TRUE
;
130 NdisReleaseSpinLock(&adapter
->Lock
);
132 return NDIS_STATUS_SUCCESS
;
138 IN NDIS_HANDLE MiniportAdapterContext
141 PRTL_ADAPTER adapter
= (PRTL_ADAPTER
)MiniportAdapterContext
;
143 ASSERT(adapter
!= NULL
);
146 // Interrupts need to stop first
148 if (adapter
->InterruptRegistered
!= FALSE
)
150 NdisMDeregisterInterrupt(&adapter
->Interrupt
);
154 // If we have a mapped IO port range, we can talk to the NIC
156 if (adapter
->IoBase
!= NULL
)
158 if (adapter
->ReceiveBuffer
!= NULL
)
161 // Disassociate our shared buffer before freeing it to avoid
162 // NIC-induced memory corruption
164 NICRemoveReceiveBuffer(adapter
);
166 NdisMFreeSharedMemory(adapter
->MiniportAdapterHandle
,
167 adapter
->ReceiveBufferLength
,
169 adapter
->ReceiveBuffer
,
170 adapter
->ReceiveBufferPa
);
173 if (adapter
->RuntTxBuffers
!= NULL
)
175 NdisMFreeSharedMemory(adapter
->MiniportAdapterHandle
,
176 MINIMUM_FRAME_SIZE
* TX_DESC_COUNT
,
178 adapter
->RuntTxBuffers
,
179 adapter
->RuntTxBuffersPa
);
183 // Unregister the IO range
185 NdisMDeregisterIoPortRange(adapter
->MiniportAdapterHandle
,
186 adapter
->IoRangeStart
,
187 adapter
->IoRangeLength
,
192 // Destroy the adapter context
194 NdisFreeMemory(adapter
, sizeof(*adapter
), 0);
200 OUT PNDIS_STATUS OpenErrorStatus
,
201 OUT PUINT SelectedMediumIndex
,
202 IN PNDIS_MEDIUM MediumArray
,
203 IN UINT MediumArraySize
,
204 IN NDIS_HANDLE MiniportAdapterHandle
,
205 IN NDIS_HANDLE WrapperConfigurationContext
208 PRTL_ADAPTER adapter
;
211 PNDIS_RESOURCE_LIST resourceList
;
212 UINT resourceListSize
;
215 // Make sure the medium is supported
217 for (i
= 0; i
< MediumArraySize
; i
++)
219 if (MediumArray
[i
] == NdisMedium802_3
)
221 *SelectedMediumIndex
= i
;
226 if (i
== MediumArraySize
)
228 NDIS_DbgPrint(MIN_TRACE
, ("802.3 medium was not found in the medium array\n"));
229 return NDIS_STATUS_UNSUPPORTED_MEDIA
;
233 // Allocate our adapter context
235 status
= NdisAllocateMemoryWithTag((PVOID
*)&adapter
,
238 if (status
!= NDIS_STATUS_SUCCESS
)
240 NDIS_DbgPrint(MIN_TRACE
, ("Failed to allocate adapter context\n"));
241 return NDIS_STATUS_RESOURCES
;
244 RtlZeroMemory(adapter
, sizeof(*adapter
));
245 adapter
->MiniportAdapterHandle
= MiniportAdapterHandle
;
246 NdisAllocateSpinLock(&adapter
->Lock
);
249 // Notify NDIS of some characteristics of our NIC
251 NdisMSetAttributesEx(MiniportAdapterHandle
,
254 NDIS_ATTRIBUTE_BUS_MASTER
,
258 // Get our resources for IRQ and IO base information
261 resourceListSize
= 0;
262 NdisMQueryAdapterResources(&status
,
263 WrapperConfigurationContext
,
266 if (status
!= NDIS_STATUS_RESOURCES
)
268 NDIS_DbgPrint(MIN_TRACE
, ("Unexpected failure of NdisMQueryAdapterResources #1\n"));
269 status
= NDIS_STATUS_FAILURE
;
273 status
= NdisAllocateMemoryWithTag((PVOID
*)&resourceList
,
276 if (status
!= NDIS_STATUS_SUCCESS
)
278 NDIS_DbgPrint(MIN_TRACE
, ("Failed to allocate resource list\n"));
282 NdisMQueryAdapterResources(&status
,
283 WrapperConfigurationContext
,
286 if (status
!= NDIS_STATUS_SUCCESS
)
288 NDIS_DbgPrint(MIN_TRACE
, ("Unexpected failure of NdisMQueryAdapterResources #2\n"));
292 ASSERT(resourceList
->Version
== 1);
293 ASSERT(resourceList
->Revision
== 1);
295 for (i
= 0; i
< resourceList
->Count
; i
++)
297 switch (resourceList
->PartialDescriptors
[i
].Type
)
299 case CmResourceTypePort
:
300 ASSERT(adapter
->IoRangeStart
== 0);
302 ASSERT(resourceList
->PartialDescriptors
[i
].u
.Port
.Start
.HighPart
== 0);
304 adapter
->IoRangeStart
= resourceList
->PartialDescriptors
[i
].u
.Port
.Start
.LowPart
;
305 adapter
->IoRangeLength
= resourceList
->PartialDescriptors
[i
].u
.Port
.Length
;
307 NDIS_DbgPrint(MID_TRACE
, ("I/O port range is %p to %p\n",
308 adapter
->IoRangeStart
, adapter
->IoRangeStart
+ adapter
->IoRangeLength
));
311 case CmResourceTypeInterrupt
:
312 ASSERT(adapter
->InterruptVector
== 0);
313 ASSERT(adapter
->InterruptLevel
== 0);
315 adapter
->InterruptVector
= resourceList
->PartialDescriptors
[i
].u
.Interrupt
.Vector
;
316 adapter
->InterruptLevel
= resourceList
->PartialDescriptors
[i
].u
.Interrupt
.Level
;
317 adapter
->InterruptShared
= (resourceList
->PartialDescriptors
[i
].ShareDisposition
== CmResourceShareShared
);
318 adapter
->InterruptFlags
= resourceList
->PartialDescriptors
[i
].Flags
;
320 NDIS_DbgPrint(MID_TRACE
, ("IRQ vector is %d\n", adapter
->InterruptVector
));
324 NDIS_DbgPrint(MIN_TRACE
, ("Unrecognized resource type: 0x%x\n", resourceList
->PartialDescriptors
[i
].Type
));
329 NdisFreeMemory(resourceList
, resourceListSize
, 0);
332 if (adapter
->IoRangeStart
== 0 || adapter
->InterruptVector
== 0)
334 NDIS_DbgPrint(MIN_TRACE
, ("Adapter didn't receive enough resources\n"));
339 // Allocate the DMA resources
341 status
= NdisMInitializeScatterGatherDma(MiniportAdapterHandle
,
342 FALSE
, // RTL8139 only supports 32-bit addresses
344 if (status
!= NDIS_STATUS_SUCCESS
)
346 NDIS_DbgPrint(MIN_TRACE
, ("Unable to configure DMA\n"));
350 adapter
->ReceiveBufferLength
= FULL_RECEIVE_BUFFER_SIZE
;
351 NdisMAllocateSharedMemory(MiniportAdapterHandle
,
352 adapter
->ReceiveBufferLength
,
354 (PVOID
*)&adapter
->ReceiveBuffer
,
355 &adapter
->ReceiveBufferPa
);
356 if (adapter
->ReceiveBuffer
== NULL
)
358 NDIS_DbgPrint(MIN_TRACE
, ("Unable to allocate receive buffer\n"));
359 status
= NDIS_STATUS_RESOURCES
;
363 NdisMAllocateSharedMemory(MiniportAdapterHandle
,
364 MINIMUM_FRAME_SIZE
* TX_DESC_COUNT
,
366 (PVOID
*)&adapter
->RuntTxBuffers
,
367 &adapter
->RuntTxBuffersPa
);
368 if (adapter
->RuntTxBuffers
== NULL
)
370 NDIS_DbgPrint(MIN_TRACE
, ("Unable to allocate runt TX buffer\n"));
371 status
= NDIS_STATUS_RESOURCES
;
376 // Register the I/O port range and configure the NIC
378 status
= NdisMRegisterIoPortRange((PVOID
*)&adapter
->IoBase
,
379 MiniportAdapterHandle
,
380 adapter
->IoRangeStart
,
381 adapter
->IoRangeLength
);
382 if (status
!= NDIS_STATUS_SUCCESS
)
384 NDIS_DbgPrint(MIN_TRACE
, ("Unable to register IO port range (0x%x)\n", status
));
391 status
= NICPowerOn(adapter
);
392 if (status
!= NDIS_STATUS_SUCCESS
)
394 NDIS_DbgPrint(MIN_TRACE
, ("Unable to power on NIC (0x%x)\n", status
));
398 status
= NICSoftReset(adapter
);
399 if (status
!= NDIS_STATUS_SUCCESS
)
401 NDIS_DbgPrint(MIN_TRACE
, ("Unable to reset the NIC (0x%x)\n", status
));
405 status
= NICGetPermanentMacAddress(adapter
, adapter
->PermanentMacAddress
);
406 if (status
!= NDIS_STATUS_SUCCESS
)
408 NDIS_DbgPrint(MIN_TRACE
, ("Unable to get the fixed MAC address (0x%x)\n", status
));
412 RtlCopyMemory(adapter
->CurrentMacAddress
, adapter
->PermanentMacAddress
, IEEE_802_ADDR_LENGTH
);
415 // Update link state and speed
417 NICUpdateLinkStatus(adapter
);
419 status
= NICRegisterReceiveBuffer(adapter
);
420 if (status
!= NDIS_STATUS_SUCCESS
)
422 NDIS_DbgPrint(MIN_TRACE
, ("Unable to setup receive buffer (0x%x)\n", status
));
427 // We're ready to handle interrupts now
429 status
= NdisMRegisterInterrupt(&adapter
->Interrupt
,
430 MiniportAdapterHandle
,
431 adapter
->InterruptVector
,
432 adapter
->InterruptLevel
,
433 TRUE
, // We always want ISR calls
434 adapter
->InterruptShared
,
435 (adapter
->InterruptFlags
& CM_RESOURCE_INTERRUPT_LATCHED
) ?
436 NdisInterruptLatched
: NdisInterruptLevelSensitive
);
437 if (status
!= NDIS_STATUS_SUCCESS
)
439 NDIS_DbgPrint(MIN_TRACE
, ("Unable to register interrupt (0x%x)\n", status
));
443 adapter
->InterruptRegistered
= TRUE
;
446 // Enable interrupts on the NIC
448 adapter
->InterruptMask
= DEFAULT_INTERRUPT_MASK
;
449 status
= NICApplyInterruptMask(adapter
);
450 if (status
!= NDIS_STATUS_SUCCESS
)
452 NDIS_DbgPrint(MIN_TRACE
, ("Unable to apply interrupt mask (0x%x)\n", status
));
457 // Turn on TX and RX now
459 status
= NICEnableTxRx(adapter
);
460 if (status
!= NDIS_STATUS_SUCCESS
)
462 NDIS_DbgPrint(MIN_TRACE
, ("Unable to enable TX and RX (0x%x)\n", status
));
466 return NDIS_STATUS_SUCCESS
;
469 if (resourceList
!= NULL
)
471 NdisFreeMemory(resourceList
, resourceListSize
, 0);
475 MiniportHalt(adapter
);
484 IN PDRIVER_OBJECT DriverObject
,
485 IN PUNICODE_STRING RegistryPath
488 NDIS_HANDLE wrapperHandle
;
489 NDIS_MINIPORT_CHARACTERISTICS characteristics
;
492 RtlZeroMemory(&characteristics
, sizeof(characteristics
));
493 characteristics
.MajorNdisVersion
= NDIS_MINIPORT_MAJOR_VERSION
;
494 characteristics
.MinorNdisVersion
= NDIS_MINIPORT_MINOR_VERSION
;
495 characteristics
.CheckForHangHandler
= NULL
;
496 characteristics
.DisableInterruptHandler
= NULL
;
497 characteristics
.EnableInterruptHandler
= NULL
;
498 characteristics
.HaltHandler
= MiniportHalt
;
499 characteristics
.HandleInterruptHandler
= MiniportHandleInterrupt
;
500 characteristics
.InitializeHandler
= MiniportInitialize
;
501 characteristics
.ISRHandler
= MiniportISR
;
502 characteristics
.QueryInformationHandler
= MiniportQueryInformation
;
503 characteristics
.ReconfigureHandler
= NULL
;
504 characteristics
.ResetHandler
= MiniportReset
;
505 characteristics
.SendHandler
= MiniportSend
;
506 characteristics
.SetInformationHandler
= MiniportSetInformation
;
507 characteristics
.TransferDataHandler
= NULL
;
508 characteristics
.ReturnPacketHandler
= NULL
;
509 characteristics
.SendPacketsHandler
= NULL
;
510 characteristics
.AllocateCompleteHandler
= NULL
;
512 NdisMInitializeWrapper(&wrapperHandle
, DriverObject
, RegistryPath
, NULL
);
515 return NDIS_STATUS_FAILURE
;
518 status
= NdisMRegisterMiniport(wrapperHandle
, &characteristics
, sizeof(characteristics
));
519 if (status
!= NDIS_STATUS_SUCCESS
)
521 NdisTerminateWrapper(wrapperHandle
, 0);
522 return NDIS_STATUS_FAILURE
;
525 return NDIS_STATUS_SUCCESS
;