1 /* 2 * ReactOS Realtek 8139 Driver 3 * 4 * Copyright (C) 2013 Cameron Gutman 5 * 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. 10 * 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. 15 * 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. 19 * 20 */ 21 22 #include "nic.h" 23 24 #define NDEBUG 25 #include <debug.h> 26 27 ULONG DebugTraceLevel = MIN_TRACE; 28 29 NDIS_STATUS 30 NTAPI 31 MiniportReset ( 32 OUT PBOOLEAN AddressingReset, 33 IN NDIS_HANDLE MiniportAdapterContext 34 ) 35 { 36 *AddressingReset = FALSE; 37 return NDIS_STATUS_FAILURE; 38 } 39 40 NDIS_STATUS 41 NTAPI 42 MiniportSend ( 43 IN NDIS_HANDLE MiniportAdapterContext, 44 IN PNDIS_PACKET Packet, 45 IN UINT Flags 46 ) 47 { 48 PRTL_ADAPTER adapter = (PRTL_ADAPTER)MiniportAdapterContext; 49 NDIS_STATUS status; 50 PSCATTER_GATHER_LIST sgList = NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, 51 ScatterGatherListPacketInfo); 52 ULONG transmitLength; 53 ULONG transmitBuffer; 54 PNDIS_BUFFER firstBuffer; 55 PVOID firstBufferVa; 56 UINT firstBufferLength, totalBufferLength; 57 PUCHAR runtBuffer; 58 59 ASSERT(sgList != NULL); 60 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); 65 66 NDIS_DbgPrint(MAX_TRACE, ("Sending %d byte packet\n", sgList->Elements[0].Length)); 67 68 NdisAcquireSpinLock(&adapter->Lock); 69 70 if (adapter->TxFull) 71 { 72 NDIS_DbgPrint(MIN_TRACE, ("All TX descriptors are full\n")); 73 NdisReleaseSpinLock(&adapter->Lock); 74 return NDIS_STATUS_RESOURCES; 75 } 76 77 NDIS_DbgPrint(MAX_TRACE, ("Sending packet on TX desc %d\n", adapter->CurrentTxDesc)); 78 79 // 80 // If this is a runt, we need to pad it manually for the RTL8139 81 // 82 if (sgList->Elements[0].Length < MINIMUM_FRAME_SIZE) 83 { 84 transmitLength = MINIMUM_FRAME_SIZE; 85 transmitBuffer = adapter->RuntTxBuffersPa.LowPart + 86 (MINIMUM_FRAME_SIZE * adapter->CurrentTxDesc); 87 88 NdisGetFirstBufferFromPacketSafe(Packet, 89 &firstBuffer, 90 &firstBufferVa, 91 &firstBufferLength, 92 &totalBufferLength, 93 NormalPagePriority); 94 if (firstBufferVa == NULL) 95 { 96 NDIS_DbgPrint(MIN_TRACE, ("Unable to get buffer from packet\n")); 97 NdisReleaseSpinLock(&adapter->Lock); 98 return NDIS_STATUS_RESOURCES; 99 } 100 101 ASSERT(firstBufferLength == totalBufferLength); 102 103 runtBuffer = adapter->RuntTxBuffers + (MINIMUM_FRAME_SIZE * adapter->CurrentTxDesc); 104 RtlCopyMemory(runtBuffer, firstBufferVa, firstBufferLength); 105 RtlFillMemory(runtBuffer + firstBufferLength, MINIMUM_FRAME_SIZE - firstBufferLength, 0x00); 106 } 107 else 108 { 109 transmitLength = sgList->Elements[0].Length; 110 transmitBuffer = sgList->Elements[0].Address.LowPart; 111 } 112 113 status = NICTransmitPacket(adapter, adapter->CurrentTxDesc, transmitBuffer, transmitLength); 114 if (status != NDIS_STATUS_SUCCESS) 115 { 116 NDIS_DbgPrint(MIN_TRACE, ("Transmit packet failed\n")); 117 NdisReleaseSpinLock(&adapter->Lock); 118 return status; 119 } 120 121 adapter->CurrentTxDesc++; 122 adapter->CurrentTxDesc %= TX_DESC_COUNT; 123 124 if (adapter->CurrentTxDesc == adapter->DirtyTxDesc) 125 { 126 NDIS_DbgPrint(MID_TRACE, ("All TX descriptors are full now\n")); 127 adapter->TxFull = TRUE; 128 } 129 130 NdisReleaseSpinLock(&adapter->Lock); 131 132 return NDIS_STATUS_SUCCESS; 133 } 134 135 VOID 136 NTAPI 137 MiniportHalt ( 138 IN NDIS_HANDLE MiniportAdapterContext 139 ) 140 { 141 PRTL_ADAPTER adapter = (PRTL_ADAPTER)MiniportAdapterContext; 142 143 ASSERT(adapter != NULL); 144 145 // 146 // Interrupts need to stop first 147 // 148 if (adapter->InterruptRegistered != FALSE) 149 { 150 NdisMDeregisterInterrupt(&adapter->Interrupt); 151 } 152 153 // 154 // If we have a mapped IO port range, we can talk to the NIC 155 // 156 if (adapter->IoBase != NULL) 157 { 158 if (adapter->ReceiveBuffer != NULL) 159 { 160 // 161 // Disassociate our shared buffer before freeing it to avoid 162 // NIC-induced memory corruption 163 // 164 NICRemoveReceiveBuffer(adapter); 165 166 NdisMFreeSharedMemory(adapter->MiniportAdapterHandle, 167 adapter->ReceiveBufferLength, 168 FALSE, 169 adapter->ReceiveBuffer, 170 adapter->ReceiveBufferPa); 171 } 172 173 if (adapter->RuntTxBuffers != NULL) 174 { 175 NdisMFreeSharedMemory(adapter->MiniportAdapterHandle, 176 MINIMUM_FRAME_SIZE * TX_DESC_COUNT, 177 FALSE, 178 adapter->RuntTxBuffers, 179 adapter->RuntTxBuffersPa); 180 } 181 182 // 183 // Unregister the IO range 184 // 185 NdisMDeregisterIoPortRange(adapter->MiniportAdapterHandle, 186 adapter->IoRangeStart, 187 adapter->IoRangeLength, 188 adapter->IoBase); 189 } 190 191 // 192 // Destroy the adapter context 193 // 194 NdisFreeMemory(adapter, sizeof(*adapter), 0); 195 } 196 197 NDIS_STATUS 198 NTAPI 199 MiniportInitialize ( 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 206 ) 207 { 208 PRTL_ADAPTER adapter; 209 NDIS_STATUS status; 210 UINT i; 211 PNDIS_RESOURCE_LIST resourceList; 212 UINT resourceListSize; 213 214 // 215 // Make sure the medium is supported 216 // 217 for (i = 0; i < MediumArraySize; i++) 218 { 219 if (MediumArray[i] == NdisMedium802_3) 220 { 221 *SelectedMediumIndex = i; 222 break; 223 } 224 } 225 226 if (i == MediumArraySize) 227 { 228 NDIS_DbgPrint(MIN_TRACE, ("802.3 medium was not found in the medium array\n")); 229 return NDIS_STATUS_UNSUPPORTED_MEDIA; 230 } 231 232 // 233 // Allocate our adapter context 234 // 235 status = NdisAllocateMemoryWithTag((PVOID*)&adapter, 236 sizeof(*adapter), 237 ADAPTER_TAG); 238 if (status != NDIS_STATUS_SUCCESS) 239 { 240 NDIS_DbgPrint(MIN_TRACE, ("Failed to allocate adapter context\n")); 241 return NDIS_STATUS_RESOURCES; 242 } 243 244 RtlZeroMemory(adapter, sizeof(*adapter)); 245 adapter->MiniportAdapterHandle = MiniportAdapterHandle; 246 NdisAllocateSpinLock(&adapter->Lock); 247 248 // 249 // Notify NDIS of some characteristics of our NIC 250 // 251 NdisMSetAttributesEx(MiniportAdapterHandle, 252 adapter, 253 0, 254 NDIS_ATTRIBUTE_BUS_MASTER, 255 NdisInterfacePci); 256 257 // 258 // Get our resources for IRQ and IO base information 259 // 260 resourceList = NULL; 261 resourceListSize = 0; 262 NdisMQueryAdapterResources(&status, 263 WrapperConfigurationContext, 264 resourceList, 265 &resourceListSize); 266 if (status != NDIS_STATUS_RESOURCES) 267 { 268 NDIS_DbgPrint(MIN_TRACE, ("Unexpected failure of NdisMQueryAdapterResources #1\n")); 269 status = NDIS_STATUS_FAILURE; 270 goto Cleanup; 271 } 272 273 status = NdisAllocateMemoryWithTag((PVOID*)&resourceList, 274 resourceListSize, 275 RESOURCE_LIST_TAG); 276 if (status != NDIS_STATUS_SUCCESS) 277 { 278 NDIS_DbgPrint(MIN_TRACE, ("Failed to allocate resource list\n")); 279 goto Cleanup; 280 } 281 282 NdisMQueryAdapterResources(&status, 283 WrapperConfigurationContext, 284 resourceList, 285 &resourceListSize); 286 if (status != NDIS_STATUS_SUCCESS) 287 { 288 NDIS_DbgPrint(MIN_TRACE, ("Unexpected failure of NdisMQueryAdapterResources #2\n")); 289 goto Cleanup; 290 } 291 292 ASSERT(resourceList->Version == 1); 293 ASSERT(resourceList->Revision == 1); 294 295 for (i = 0; i < resourceList->Count; i++) 296 { 297 switch (resourceList->PartialDescriptors[i].Type) 298 { 299 case CmResourceTypePort: 300 ASSERT(adapter->IoRangeStart == 0); 301 302 ASSERT(resourceList->PartialDescriptors[i].u.Port.Start.HighPart == 0); 303 304 adapter->IoRangeStart = resourceList->PartialDescriptors[i].u.Port.Start.LowPart; 305 adapter->IoRangeLength = resourceList->PartialDescriptors[i].u.Port.Length; 306 307 NDIS_DbgPrint(MID_TRACE, ("I/O port range is %p to %p\n", 308 adapter->IoRangeStart, adapter->IoRangeStart + adapter->IoRangeLength)); 309 break; 310 311 case CmResourceTypeInterrupt: 312 ASSERT(adapter->InterruptVector == 0); 313 ASSERT(adapter->InterruptLevel == 0); 314 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; 319 320 NDIS_DbgPrint(MID_TRACE, ("IRQ vector is %d\n", adapter->InterruptVector)); 321 break; 322 323 default: 324 NDIS_DbgPrint(MIN_TRACE, ("Unrecognized resource type: 0x%x\n", resourceList->PartialDescriptors[i].Type)); 325 break; 326 } 327 } 328 329 NdisFreeMemory(resourceList, resourceListSize, 0); 330 resourceList = NULL; 331 332 if (adapter->IoRangeStart == 0 || adapter->InterruptVector == 0) 333 { 334 NDIS_DbgPrint(MIN_TRACE, ("Adapter didn't receive enough resources\n")); 335 goto Cleanup; 336 } 337 338 // 339 // Allocate the DMA resources 340 // 341 status = NdisMInitializeScatterGatherDma(MiniportAdapterHandle, 342 FALSE, // RTL8139 only supports 32-bit addresses 343 MAXIMUM_FRAME_SIZE); 344 if (status != NDIS_STATUS_SUCCESS) 345 { 346 NDIS_DbgPrint(MIN_TRACE, ("Unable to configure DMA\n")); 347 goto Cleanup; 348 } 349 350 adapter->ReceiveBufferLength = FULL_RECEIVE_BUFFER_SIZE; 351 NdisMAllocateSharedMemory(MiniportAdapterHandle, 352 adapter->ReceiveBufferLength, 353 FALSE, 354 (PVOID*)&adapter->ReceiveBuffer, 355 &adapter->ReceiveBufferPa); 356 if (adapter->ReceiveBuffer == NULL) 357 { 358 NDIS_DbgPrint(MIN_TRACE, ("Unable to allocate receive buffer\n")); 359 status = NDIS_STATUS_RESOURCES; 360 goto Cleanup; 361 } 362 363 NdisMAllocateSharedMemory(MiniportAdapterHandle, 364 MINIMUM_FRAME_SIZE * TX_DESC_COUNT, 365 FALSE, 366 (PVOID*)&adapter->RuntTxBuffers, 367 &adapter->RuntTxBuffersPa); 368 if (adapter->RuntTxBuffers == NULL) 369 { 370 NDIS_DbgPrint(MIN_TRACE, ("Unable to allocate runt TX buffer\n")); 371 status = NDIS_STATUS_RESOURCES; 372 goto Cleanup; 373 } 374 375 // 376 // Register the I/O port range and configure the NIC 377 // 378 status = NdisMRegisterIoPortRange((PVOID*)&adapter->IoBase, 379 MiniportAdapterHandle, 380 adapter->IoRangeStart, 381 adapter->IoRangeLength); 382 if (status != NDIS_STATUS_SUCCESS) 383 { 384 NDIS_DbgPrint(MIN_TRACE, ("Unable to register IO port range (0x%x)\n", status)); 385 goto Cleanup; 386 } 387 388 // 389 // Adapter setup 390 // 391 status = NICPowerOn(adapter); 392 if (status != NDIS_STATUS_SUCCESS) 393 { 394 NDIS_DbgPrint(MIN_TRACE, ("Unable to power on NIC (0x%x)\n", status)); 395 goto Cleanup; 396 } 397 398 status = NICSoftReset(adapter); 399 if (status != NDIS_STATUS_SUCCESS) 400 { 401 NDIS_DbgPrint(MIN_TRACE, ("Unable to reset the NIC (0x%x)\n", status)); 402 goto Cleanup; 403 } 404 405 status = NICGetPermanentMacAddress(adapter, adapter->PermanentMacAddress); 406 if (status != NDIS_STATUS_SUCCESS) 407 { 408 NDIS_DbgPrint(MIN_TRACE, ("Unable to get the fixed MAC address (0x%x)\n", status)); 409 goto Cleanup; 410 } 411 412 RtlCopyMemory(adapter->CurrentMacAddress, adapter->PermanentMacAddress, IEEE_802_ADDR_LENGTH); 413 414 // 415 // Update link state and speed 416 // 417 NICUpdateLinkStatus(adapter); 418 419 status = NICRegisterReceiveBuffer(adapter); 420 if (status != NDIS_STATUS_SUCCESS) 421 { 422 NDIS_DbgPrint(MIN_TRACE, ("Unable to setup receive buffer (0x%x)\n", status)); 423 goto Cleanup; 424 } 425 426 // 427 // We're ready to handle interrupts now 428 // 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) 438 { 439 NDIS_DbgPrint(MIN_TRACE, ("Unable to register interrupt (0x%x)\n", status)); 440 goto Cleanup; 441 } 442 443 adapter->InterruptRegistered = TRUE; 444 445 // 446 // Enable interrupts on the NIC 447 // 448 adapter->InterruptMask = DEFAULT_INTERRUPT_MASK; 449 status = NICApplyInterruptMask(adapter); 450 if (status != NDIS_STATUS_SUCCESS) 451 { 452 NDIS_DbgPrint(MIN_TRACE, ("Unable to apply interrupt mask (0x%x)\n", status)); 453 goto Cleanup; 454 } 455 456 // 457 // Turn on TX and RX now 458 // 459 status = NICEnableTxRx(adapter); 460 if (status != NDIS_STATUS_SUCCESS) 461 { 462 NDIS_DbgPrint(MIN_TRACE, ("Unable to enable TX and RX (0x%x)\n", status)); 463 goto Cleanup; 464 } 465 466 return NDIS_STATUS_SUCCESS; 467 468 Cleanup: 469 if (resourceList != NULL) 470 { 471 NdisFreeMemory(resourceList, resourceListSize, 0); 472 } 473 if (adapter != NULL) 474 { 475 MiniportHalt(adapter); 476 } 477 478 return status; 479 } 480 481 NTSTATUS 482 NTAPI 483 DriverEntry ( 484 IN PDRIVER_OBJECT DriverObject, 485 IN PUNICODE_STRING RegistryPath 486 ) 487 { 488 NDIS_HANDLE wrapperHandle; 489 NDIS_MINIPORT_CHARACTERISTICS characteristics; 490 NDIS_STATUS status; 491 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; 511 512 NdisMInitializeWrapper(&wrapperHandle, DriverObject, RegistryPath, NULL); 513 if (!wrapperHandle) 514 { 515 return NDIS_STATUS_FAILURE; 516 } 517 518 status = NdisMRegisterMiniport(wrapperHandle, &characteristics, sizeof(characteristics)); 519 if (status != NDIS_STATUS_SUCCESS) 520 { 521 NdisTerminateWrapper(wrapperHandle, 0); 522 return NDIS_STATUS_FAILURE; 523 } 524 525 return NDIS_STATUS_SUCCESS; 526 } 527