1 /* 2 * ReactOS AMD PCNet Driver 3 * 4 * Copyright (C) 2003 Vizzini <vizzini@plasmic.com> 5 * Copyright (C) 2004 Filip Navara <navaraf@reactos.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License along 18 * with this program; if not, write to the Free Software Foundation, Inc., 19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * REVISIONS: 22 * 09-Sep-2003 vizzini - Created 23 * 10-Oct-2004 navaraf - Fix receive to work on VMware adapters ( 24 * need to set busmaster bit on PCI). 25 * - Indicate receive completion. 26 * - Implement packet transmitting. 27 * - Don't read slot number from registry and 28 * report itself as NDIS 5.0 miniport. 29 * 11-Oct-2004 navaraf - Fix nasty bugs in halt code path. 30 * 17-Oct-2004 navaraf - Add multicast support. 31 * - Add media state detection support. 32 * - Protect the adapter context with spinlock 33 * and move code talking to card to inside 34 * NdisMSynchronizeWithInterrupt calls where 35 * necessary. 36 * 37 * NOTES: 38 * - this assumes a 32-bit machine 39 */ 40 41 #include "pcnet.h" 42 43 #define NDEBUG 44 #include <debug.h> 45 46 NTSTATUS 47 NTAPI 48 DriverEntry( 49 IN PDRIVER_OBJECT DriverObject, 50 IN PUNICODE_STRING RegistryPath); 51 52 static VOID 53 NTAPI 54 MiniportHandleInterrupt( 55 IN NDIS_HANDLE MiniportAdapterContext) 56 /* 57 * FUNCTION: Handle an interrupt if told to by MiniportISR 58 * ARGUMENTS: 59 * MiniportAdapterContext: context specified to NdisMSetAttributes 60 * NOTES: 61 * - Called by NDIS at DISPATCH_LEVEL 62 */ 63 { 64 PADAPTER Adapter = (PADAPTER)MiniportAdapterContext; 65 USHORT Data; 66 UINT i = 0; 67 68 DPRINT("Called\n"); 69 70 ASSERT_IRQL_EQUAL(DISPATCH_LEVEL); 71 72 NdisDprAcquireSpinLock(&Adapter->Lock); 73 74 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0); 75 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data); 76 77 DPRINT("CSR0 is 0x%x\n", Data); 78 79 while((Data & CSR0_INTR) && i++ < INTERRUPT_LIMIT) 80 { 81 /* Clear interrupt flags early to avoid race conditions. */ 82 NdisRawWritePortUshort(Adapter->PortOffset + RDP, Data); 83 84 if(Data & CSR0_ERR) 85 { 86 DPRINT("error: %x\n", Data & (CSR0_MERR|CSR0_BABL|CSR0_CERR|CSR0_MISS)); 87 if (Data & CSR0_CERR) 88 Adapter->Statistics.XmtCollisions++; 89 } 90 if(Data & CSR0_IDON) 91 { 92 DPRINT("IDON\n"); 93 } 94 if(Data & CSR0_RINT) 95 { 96 BOOLEAN IndicatedData = FALSE; 97 98 DPRINT("receive interrupt\n"); 99 100 while(1) 101 { 102 PRECEIVE_DESCRIPTOR Descriptor = Adapter->ReceiveDescriptorRingVirt + Adapter->CurrentReceiveDescriptorIndex; 103 PCHAR Buffer; 104 ULONG ByteCount; 105 106 if(Descriptor->FLAGS & RD_OWN) 107 { 108 DPRINT("no more receive descriptors to process\n"); 109 break; 110 } 111 112 if(Descriptor->FLAGS & RD_ERR) 113 { 114 DPRINT("receive descriptor error: 0x%x\n", Descriptor->FLAGS); 115 if (Descriptor->FLAGS & RD_BUFF) 116 Adapter->Statistics.RcvBufferErrors++; 117 if (Descriptor->FLAGS & RD_CRC) 118 Adapter->Statistics.RcvCrcErrors++; 119 if (Descriptor->FLAGS & RD_OFLO) 120 Adapter->Statistics.RcvOverflowErrors++; 121 if (Descriptor->FLAGS & RD_FRAM) 122 Adapter->Statistics.RcvFramingErrors++; 123 break; 124 } 125 126 if(!((Descriptor->FLAGS & RD_STP) && (Descriptor->FLAGS & RD_ENP))) 127 { 128 DPRINT("receive descriptor not start&end: 0x%x\n", Descriptor->FLAGS); 129 break; 130 } 131 132 Buffer = Adapter->ReceiveBufferPtrVirt + Adapter->CurrentReceiveDescriptorIndex * BUFFER_SIZE; 133 ByteCount = Descriptor->MCNT & 0xfff; 134 135 DPRINT("Indicating a %d-byte packet (index %d)\n", ByteCount, Adapter->CurrentReceiveDescriptorIndex); 136 137 NdisMEthIndicateReceive(Adapter->MiniportAdapterHandle, 0, Buffer, 14, Buffer+14, ByteCount-14, ByteCount-14); 138 139 IndicatedData = TRUE; 140 141 RtlZeroMemory(Descriptor, sizeof(RECEIVE_DESCRIPTOR)); 142 Descriptor->RBADR = Adapter->ReceiveBufferPtrPhys.QuadPart + 143 (Adapter->CurrentReceiveDescriptorIndex * BUFFER_SIZE); 144 Descriptor->BCNT = (-BUFFER_SIZE) | 0xf000; 145 Descriptor->FLAGS |= RD_OWN; 146 147 Adapter->CurrentReceiveDescriptorIndex++; 148 Adapter->CurrentReceiveDescriptorIndex %= Adapter->BufferCount; 149 150 Adapter->Statistics.RcvGoodFrames++; 151 } 152 153 if (IndicatedData) 154 NdisMEthIndicateReceiveComplete(Adapter->MiniportAdapterHandle); 155 } 156 if(Data & CSR0_TINT) 157 { 158 PTRANSMIT_DESCRIPTOR Descriptor; 159 160 DPRINT("transmit interrupt\n"); 161 162 while (Adapter->CurrentTransmitStartIndex != 163 Adapter->CurrentTransmitEndIndex) 164 { 165 Descriptor = Adapter->TransmitDescriptorRingVirt + Adapter->CurrentTransmitStartIndex; 166 167 DPRINT("buffer %d flags %x flags2 %x\n", 168 Adapter->CurrentTransmitStartIndex, 169 Descriptor->FLAGS, Descriptor->FLAGS2); 170 171 if (Descriptor->FLAGS & TD1_OWN) 172 { 173 DPRINT("non-TXed buffer\n"); 174 break; 175 } 176 177 if (Descriptor->FLAGS & TD1_STP) 178 { 179 if (Descriptor->FLAGS & TD1_ONE) 180 Adapter->Statistics.XmtOneRetry++; 181 else if (Descriptor->FLAGS & TD1_MORE) 182 Adapter->Statistics.XmtMoreThanOneRetry++; 183 } 184 185 if (Descriptor->FLAGS & TD1_ERR) 186 { 187 DPRINT("major error: %x\n", Descriptor->FLAGS2); 188 if (Descriptor->FLAGS2 & TD2_RTRY) 189 Adapter->Statistics.XmtRetryErrors++; 190 if (Descriptor->FLAGS2 & TD2_LCAR) 191 Adapter->Statistics.XmtLossesOfCarrier++; 192 if (Descriptor->FLAGS2 & TD2_LCOL) 193 Adapter->Statistics.XmtLateCollisions++; 194 if (Descriptor->FLAGS2 & TD2_EXDEF) 195 Adapter->Statistics.XmtExcessiveDeferrals++; 196 if (Descriptor->FLAGS2 & TD2_UFLO) 197 Adapter->Statistics.XmtBufferUnderflows++; 198 if (Descriptor->FLAGS2 & TD2_BUFF) 199 Adapter->Statistics.XmtBufferErrors++; 200 break; 201 } 202 203 Adapter->CurrentTransmitStartIndex++; 204 Adapter->CurrentTransmitStartIndex %= Adapter->BufferCount; 205 206 Adapter->Statistics.XmtGoodFrames++; 207 } 208 NdisMSendResourcesAvailable(Adapter->MiniportAdapterHandle); 209 } 210 if(Data & ~(CSR0_ERR | CSR0_IDON | CSR0_RINT | CSR0_TINT)) 211 { 212 DPRINT("UNHANDLED INTERRUPT CSR0 0x%x\n", Data); 213 } 214 215 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data); 216 } 217 218 /* re-enable interrupts */ 219 NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_IENA); 220 221 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data); 222 DPRINT("CSR0 is now 0x%x\n", Data); 223 224 NdisDprReleaseSpinLock(&Adapter->Lock); 225 } 226 227 static NDIS_STATUS 228 MiQueryCard( 229 IN PADAPTER Adapter) 230 /* 231 * FUNCTION: Detect the PCNET NIC in the configured slot and query its I/O address and interrupt vector 232 * ARGUMENTS: 233 * MiniportAdapterContext: context supplied to NdisMSetAttributes 234 * RETURNS: 235 * NDIS_STATUS_FAILURE on a general error 236 * NDIS_STATUS_ADAPTER_NOT_FOUND on not finding the adapter 237 * NDIS_STATUS_SUCCESS on succes 238 */ 239 { 240 ULONG buf32 = 0; 241 UCHAR buf8 = 0; 242 NDIS_STATUS Status; 243 244 /* Detect the card in the configured slot */ 245 Status = NdisReadPciSlotInformation(Adapter->MiniportAdapterHandle, 0, PCI_PCIID, &buf32, 4); 246 if(Status != 4) 247 { 248 Status = NDIS_STATUS_FAILURE; 249 DPRINT1("NdisReadPciSlotInformation failed\n"); 250 return Status; 251 } 252 253 if(buf32 != PCI_ID) 254 { 255 Status = NDIS_STATUS_ADAPTER_NOT_FOUND; 256 DPRINT1("card in slot isn't our: 0x%x\n", 0, buf32); 257 return Status; 258 } 259 260 /* set busmaster and io space enable bits */ 261 buf32 = PCI_BMEN | PCI_IOEN; 262 NdisWritePciSlotInformation(Adapter->MiniportAdapterHandle, 0, PCI_COMMAND, &buf32, 4); 263 264 /* get IO base physical address */ 265 buf32 = 0; 266 Status = NdisReadPciSlotInformation(Adapter->MiniportAdapterHandle, 0, PCI_IOBAR, &buf32, 4); 267 if(Status != 4) 268 { 269 Status = NDIS_STATUS_FAILURE; 270 DPRINT1("NdisReadPciSlotInformation failed\n"); 271 return Status; 272 } 273 274 if(!buf32) 275 { 276 DPRINT1("No base i/o address set\n"); 277 return NDIS_STATUS_FAILURE; 278 } 279 280 buf32 &= ~1; /* even up address - comes out odd for some reason */ 281 282 DPRINT("detected io address 0x%x\n", buf32); 283 Adapter->IoBaseAddress = buf32; 284 285 /* get interrupt vector */ 286 Status = NdisReadPciSlotInformation(Adapter->MiniportAdapterHandle, 0, PCI_ILR, &buf8, 1); 287 if(Status != 1) 288 { 289 Status = NDIS_STATUS_FAILURE; 290 DPRINT1("NdisReadPciSlotInformation failed\n"); 291 return Status; 292 } 293 294 DPRINT("interrupt: 0x%x\n", buf8); 295 Adapter->InterruptVector = buf8; 296 297 return NDIS_STATUS_SUCCESS; 298 } 299 300 static VOID 301 MiFreeSharedMemory( 302 PADAPTER Adapter) 303 /* 304 * FUNCTION: Free all allocated shared memory 305 * ARGUMENTS: 306 * Adapter: pointer to the miniport's adapter struct 307 */ 308 { 309 NDIS_PHYSICAL_ADDRESS PhysicalAddress; 310 311 if(Adapter->InitializationBlockVirt) 312 { 313 PhysicalAddress = Adapter->InitializationBlockPhys; 314 NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->InitializationBlockLength, 315 FALSE, Adapter->InitializationBlockVirt, PhysicalAddress); 316 Adapter->InitializationBlockVirt = NULL; 317 } 318 319 if(Adapter->TransmitDescriptorRingVirt) 320 { 321 PhysicalAddress = Adapter->TransmitDescriptorRingPhys; 322 NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitDescriptorRingLength, 323 FALSE, Adapter->TransmitDescriptorRingVirt, PhysicalAddress); 324 Adapter->TransmitDescriptorRingVirt = NULL; 325 } 326 327 if(Adapter->ReceiveDescriptorRingVirt) 328 { 329 PhysicalAddress = Adapter->ReceiveDescriptorRingPhys; 330 NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveDescriptorRingLength, 331 FALSE, Adapter->ReceiveDescriptorRingVirt, PhysicalAddress); 332 Adapter->ReceiveDescriptorRingVirt = NULL; 333 } 334 335 if(Adapter->TransmitBufferPtrVirt) 336 { 337 PhysicalAddress = Adapter->TransmitBufferPtrPhys; 338 NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitBufferLength, 339 TRUE, Adapter->TransmitBufferPtrVirt, PhysicalAddress); 340 Adapter->TransmitBufferPtrVirt = NULL; 341 } 342 343 if(Adapter->ReceiveBufferPtrVirt) 344 { 345 PhysicalAddress = Adapter->ReceiveBufferPtrPhys; 346 NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveBufferLength, 347 TRUE, Adapter->ReceiveBufferPtrVirt, PhysicalAddress); 348 Adapter->ReceiveBufferPtrVirt = NULL; 349 } 350 } 351 352 static NDIS_STATUS 353 MiAllocateSharedMemory( 354 PADAPTER Adapter) 355 /* 356 * FUNCTION: Allocate all shared memory used by the miniport 357 * ARGUMENTS: 358 * Adapter: Pointer to the miniport's adapter object 359 * RETURNS: 360 * NDIS_STATUS_RESOURCES on insufficient memory 361 * NDIS_STATUS_SUCCESS on success 362 */ 363 { 364 PTRANSMIT_DESCRIPTOR TransmitDescriptor; 365 PRECEIVE_DESCRIPTOR ReceiveDescriptor; 366 NDIS_PHYSICAL_ADDRESS PhysicalAddress; 367 ULONG i; 368 ULONG BufferCount = NUMBER_OF_BUFFERS; 369 ULONG LogBufferCount = LOG_NUMBER_OF_BUFFERS; 370 371 while (BufferCount != 0) 372 { 373 /* allocate the initialization block (we have this in the loop so we can use MiFreeSharedMemory) */ 374 Adapter->InitializationBlockLength = sizeof(INITIALIZATION_BLOCK); 375 NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->InitializationBlockLength, 376 FALSE, (PVOID *)&Adapter->InitializationBlockVirt, &PhysicalAddress); 377 if(!Adapter->InitializationBlockVirt) 378 { 379 /* Buffer backoff won't help us here */ 380 DPRINT1("insufficient resources\n"); 381 return NDIS_STATUS_RESOURCES; 382 } 383 384 if (((ULONG_PTR)Adapter->InitializationBlockVirt & 0x00000003) != 0) 385 { 386 DPRINT1("address 0x%x not dword-aligned\n", Adapter->InitializationBlockVirt); 387 return NDIS_STATUS_RESOURCES; 388 } 389 390 Adapter->InitializationBlockPhys = PhysicalAddress; 391 392 /* allocate the transport descriptor ring */ 393 Adapter->TransmitDescriptorRingLength = sizeof(TRANSMIT_DESCRIPTOR) * BufferCount; 394 NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitDescriptorRingLength, 395 FALSE, (PVOID *)&Adapter->TransmitDescriptorRingVirt, &PhysicalAddress); 396 if (!Adapter->TransmitDescriptorRingVirt) 397 { 398 DPRINT1("Backing off buffer count by %d buffers due to allocation failure\n", (BufferCount >> 1)); 399 BufferCount = BufferCount >> 1; 400 LogBufferCount--; 401 MiFreeSharedMemory(Adapter); 402 continue; 403 } 404 405 if (((ULONG_PTR)Adapter->TransmitDescriptorRingVirt & 0x00000003) != 0) 406 { 407 DPRINT1("address 0x%x not dword-aligned\n", Adapter->TransmitDescriptorRingVirt); 408 return NDIS_STATUS_RESOURCES; 409 } 410 411 Adapter->TransmitDescriptorRingPhys = PhysicalAddress; 412 RtlZeroMemory(Adapter->TransmitDescriptorRingVirt, sizeof(TRANSMIT_DESCRIPTOR) * BufferCount); 413 414 /* allocate the receive descriptor ring */ 415 Adapter->ReceiveDescriptorRingLength = sizeof(RECEIVE_DESCRIPTOR) * BufferCount; 416 NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveDescriptorRingLength, 417 FALSE, (PVOID *)&Adapter->ReceiveDescriptorRingVirt, &PhysicalAddress); 418 if (!Adapter->ReceiveDescriptorRingVirt) 419 { 420 DPRINT1("Backing off buffer count by %d buffers due to allocation failure\n", (BufferCount >> 1)); 421 BufferCount = BufferCount >> 1; 422 LogBufferCount--; 423 MiFreeSharedMemory(Adapter); 424 continue; 425 } 426 427 if (((ULONG_PTR)Adapter->ReceiveDescriptorRingVirt & 0x00000003) != 0) 428 { 429 DPRINT1("address 0x%x not dword-aligned\n", Adapter->ReceiveDescriptorRingVirt); 430 return NDIS_STATUS_RESOURCES; 431 } 432 433 Adapter->ReceiveDescriptorRingPhys = PhysicalAddress; 434 RtlZeroMemory(Adapter->ReceiveDescriptorRingVirt, sizeof(RECEIVE_DESCRIPTOR) * BufferCount); 435 436 /* allocate transmit buffers */ 437 Adapter->TransmitBufferLength = BUFFER_SIZE * BufferCount; 438 NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitBufferLength, 439 TRUE, (PVOID *)&Adapter->TransmitBufferPtrVirt, &PhysicalAddress); 440 if(!Adapter->TransmitBufferPtrVirt) 441 { 442 DPRINT1("Backing off buffer count by %d buffers due to allocation failure\n", (BufferCount >> 1)); 443 BufferCount = BufferCount >> 1; 444 LogBufferCount--; 445 MiFreeSharedMemory(Adapter); 446 continue; 447 } 448 449 if(((ULONG_PTR)Adapter->TransmitBufferPtrVirt & 0x00000003) != 0) 450 { 451 DPRINT1("address 0x%x not dword-aligned\n", Adapter->TransmitBufferPtrVirt); 452 return NDIS_STATUS_RESOURCES; 453 } 454 455 Adapter->TransmitBufferPtrPhys = PhysicalAddress; 456 RtlZeroMemory(Adapter->TransmitBufferPtrVirt, BUFFER_SIZE * BufferCount); 457 458 /* allocate receive buffers */ 459 Adapter->ReceiveBufferLength = BUFFER_SIZE * BufferCount; 460 NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveBufferLength, 461 TRUE, (PVOID *)&Adapter->ReceiveBufferPtrVirt, &PhysicalAddress); 462 if(!Adapter->ReceiveBufferPtrVirt) 463 { 464 DPRINT1("Backing off buffer count by %d buffers due to allocation failure\n", (BufferCount >> 1)); 465 BufferCount = BufferCount >> 1; 466 LogBufferCount--; 467 MiFreeSharedMemory(Adapter); 468 continue; 469 } 470 471 if (((ULONG_PTR)Adapter->ReceiveBufferPtrVirt & 0x00000003) != 0) 472 { 473 DPRINT1("address 0x%x not dword-aligned\n", Adapter->ReceiveBufferPtrVirt); 474 return NDIS_STATUS_RESOURCES; 475 } 476 477 Adapter->ReceiveBufferPtrPhys = PhysicalAddress; 478 RtlZeroMemory(Adapter->ReceiveBufferPtrVirt, BUFFER_SIZE * BufferCount); 479 480 break; 481 } 482 483 if (!BufferCount) 484 { 485 DPRINT1("Failed to allocate adapter buffers\n"); 486 return NDIS_STATUS_RESOURCES; 487 } 488 489 Adapter->BufferCount = BufferCount; 490 Adapter->LogBufferCount = LogBufferCount; 491 492 /* initialize tx descriptors */ 493 TransmitDescriptor = Adapter->TransmitDescriptorRingVirt; 494 for(i = 0; i < BufferCount; i++) 495 { 496 (TransmitDescriptor+i)->TBADR = Adapter->TransmitBufferPtrPhys.QuadPart + i * BUFFER_SIZE; 497 (TransmitDescriptor+i)->BCNT = 0xf000 | -BUFFER_SIZE; /* 2's compliment + set top 4 bits */ 498 (TransmitDescriptor+i)->FLAGS = TD1_STP | TD1_ENP; 499 } 500 501 DPRINT("transmit ring initialized\n"); 502 503 /* initialize rx */ 504 ReceiveDescriptor = Adapter->ReceiveDescriptorRingVirt; 505 for(i = 0; i < BufferCount; i++) 506 { 507 (ReceiveDescriptor+i)->RBADR = Adapter->ReceiveBufferPtrPhys.QuadPart + i * BUFFER_SIZE; 508 (ReceiveDescriptor+i)->BCNT = 0xf000 | -BUFFER_SIZE; /* 2's compliment + set top 4 bits */ 509 (ReceiveDescriptor+i)->FLAGS = RD_OWN; 510 } 511 512 DPRINT("receive ring initialized\n"); 513 514 return NDIS_STATUS_SUCCESS; 515 } 516 517 static VOID 518 MiPrepareInitializationBlock( 519 PADAPTER Adapter) 520 /* 521 * FUNCTION: Initialize the initialization block 522 * ARGUMENTS: 523 * Adapter: pointer to the miniport's adapter object 524 */ 525 { 526 ULONG i = 0; 527 528 RtlZeroMemory(Adapter->InitializationBlockVirt, sizeof(INITIALIZATION_BLOCK)); 529 530 /* read burned-in address from card */ 531 for(i = 0; i < 6; i++) 532 NdisRawReadPortUchar(Adapter->PortOffset + i, Adapter->InitializationBlockVirt->PADR + i); 533 DPRINT("MAC address: %02x-%02x-%02x-%02x-%02x-%02x\n", 534 Adapter->InitializationBlockVirt->PADR[0], 535 Adapter->InitializationBlockVirt->PADR[1], 536 Adapter->InitializationBlockVirt->PADR[2], 537 Adapter->InitializationBlockVirt->PADR[3], 538 Adapter->InitializationBlockVirt->PADR[4], 539 Adapter->InitializationBlockVirt->PADR[5]); 540 541 /* set up receive ring */ 542 DPRINT("Receive ring physical address: 0x%x\n", Adapter->ReceiveDescriptorRingPhys); 543 Adapter->InitializationBlockVirt->RDRA = Adapter->ReceiveDescriptorRingPhys.QuadPart; 544 Adapter->InitializationBlockVirt->RLEN = (Adapter->LogBufferCount << 4) & 0xf0; 545 546 /* set up transmit ring */ 547 DPRINT("Transmit ring physical address: 0x%x\n", Adapter->TransmitDescriptorRingPhys); 548 Adapter->InitializationBlockVirt->TDRA = Adapter->TransmitDescriptorRingPhys.QuadPart; 549 Adapter->InitializationBlockVirt->TLEN = (Adapter->LogBufferCount << 4) & 0xf0; 550 } 551 552 static BOOLEAN 553 NTAPI 554 MiSyncStop( 555 IN PVOID SynchronizeContext) 556 /* 557 * FUNCTION: Stop the adapter 558 * ARGUMENTS: 559 * SynchronizeContext: Adapter context 560 */ 561 { 562 PADAPTER Adapter = (PADAPTER)SynchronizeContext; 563 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0); 564 NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_STOP); 565 return TRUE; 566 } 567 568 static VOID 569 NTAPI 570 MiniportHalt( 571 IN NDIS_HANDLE MiniportAdapterContext) 572 /* 573 * FUNCTION: Stop the adapter and release any per-adapter resources 574 * ARGUMENTS: 575 * MiniportAdapterContext: context specified to NdisMSetAttributes 576 * NOTES: 577 * - Called by NDIS at PASSIVE_LEVEL 578 */ 579 { 580 PADAPTER Adapter = (PADAPTER)MiniportAdapterContext; 581 BOOLEAN TimerCancelled; 582 583 DPRINT("Called\n"); 584 ASSERT(Adapter); 585 586 /* stop the media detection timer */ 587 NdisMCancelTimer(&Adapter->MediaDetectionTimer, &TimerCancelled); 588 589 /* stop the chip */ 590 NdisMSynchronizeWithInterrupt(&Adapter->InterruptObject, MiSyncStop, Adapter); 591 592 /* deregister the interrupt */ 593 NdisMDeregisterInterrupt(&Adapter->InterruptObject); 594 595 /* deregister i/o port range */ 596 NdisMDeregisterIoPortRange(Adapter->MiniportAdapterHandle, Adapter->IoBaseAddress, NUMBER_OF_PORTS, (PVOID)Adapter->PortOffset); 597 598 /* deregister the shutdown routine */ 599 NdisMDeregisterAdapterShutdownHandler(Adapter->MiniportAdapterHandle); 600 601 /* free shared memory */ 602 MiFreeSharedMemory(Adapter); 603 604 /* free map registers */ 605 NdisMFreeMapRegisters(Adapter->MiniportAdapterHandle); 606 607 /* free the lock */ 608 NdisFreeSpinLock(&Adapter->Lock); 609 610 /* free the adapter */ 611 NdisFreeMemory(Adapter, 0, 0); 612 } 613 614 static BOOLEAN 615 NTAPI 616 MiSyncMediaDetection( 617 IN PVOID SynchronizeContext) 618 /* 619 * FUNCTION: Stop the adapter 620 * ARGUMENTS: 621 * SynchronizeContext: Adapter context 622 */ 623 { 624 PADAPTER Adapter = (PADAPTER)SynchronizeContext; 625 NDIS_MEDIA_STATE MediaState = MiGetMediaState(Adapter); 626 UINT MediaSpeed = MiGetMediaSpeed(Adapter); 627 BOOLEAN FullDuplex = MiGetMediaDuplex(Adapter); 628 629 DPRINT("Called\n"); 630 DPRINT("MediaState: %d\n", MediaState); 631 if (MediaState != Adapter->MediaState || 632 MediaSpeed != Adapter->MediaSpeed || 633 FullDuplex != Adapter->FullDuplex) 634 { 635 Adapter->MediaState = MediaState; 636 Adapter->MediaSpeed = MediaSpeed; 637 Adapter->FullDuplex = FullDuplex; 638 return TRUE; 639 } 640 return FALSE; 641 } 642 643 static VOID 644 NTAPI 645 MiniportMediaDetectionTimer( 646 IN PVOID SystemSpecific1, 647 IN PVOID FunctionContext, 648 IN PVOID SystemSpecific2, 649 IN PVOID SystemSpecific3) 650 /* 651 * FUNCTION: Periodically query media state 652 * ARGUMENTS: 653 * FunctionContext: Adapter context 654 * NOTES: 655 * - Called by NDIS at DISPATCH_LEVEL 656 */ 657 { 658 PADAPTER Adapter = (PADAPTER)FunctionContext; 659 660 ASSERT_IRQL_EQUAL(DISPATCH_LEVEL); 661 662 if (NdisMSynchronizeWithInterrupt(&Adapter->InterruptObject, 663 MiSyncMediaDetection, 664 FunctionContext)) 665 { 666 NdisMIndicateStatus(Adapter->MiniportAdapterHandle, 667 Adapter->MediaState == NdisMediaStateConnected ? 668 NDIS_STATUS_MEDIA_CONNECT : NDIS_STATUS_MEDIA_DISCONNECT, 669 (PVOID)0, 0); 670 NdisMIndicateStatusComplete(Adapter->MiniportAdapterHandle); 671 } 672 } 673 674 static VOID 675 MiInitChip( 676 PADAPTER Adapter) 677 /* 678 * FUNCTION: Initialize and start the PCNET chip 679 * ARGUMENTS: 680 * Adapter: pointer to the miniport's adapter struct 681 * NOTES: 682 * - should be coded to detect failure and return an error 683 * - the vmware virtual lance chip doesn't support 32-bit i/o so don't do that. 684 */ 685 { 686 USHORT Data = 0; 687 688 DPRINT("Called\n"); 689 690 /* 691 * first reset the chip - 32-bit reset followed by 16-bit reset. if it's in 32-bit mode, it'll reset 692 * twice. if it's in 16-bit mode, the first read will be nonsense and the second will be a reset. the 693 * card is reset by reading from the reset register. on reset it's in 16-bit i/o mode. 694 */ 695 NdisRawReadPortUshort(Adapter->PortOffset + RESET32, &Data); 696 NdisRawReadPortUshort(Adapter->PortOffset + RESET16, &Data); 697 698 /* stop the chip */ 699 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0); 700 NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_STOP); 701 702 /* pause for 1ms so the chip will have time to reset */ 703 NdisStallExecution(1); 704 705 DPRINT("chip stopped\n"); 706 707 /* set the software style to 2 (32 bits) */ 708 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR58); 709 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data); 710 711 Data |= SW_STYLE_2; 712 713 NdisRawWritePortUshort(Adapter->PortOffset + RDP, Data); 714 715 /* set up csr4: auto transmit pad, disable polling, disable transmit interrupt, dmaplus */ 716 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR4); 717 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data); 718 719 Data |= CSR4_APAD_XMT | /* CSR4_DPOLL |*/ CSR4_TXSTRTM | CSR4_DMAPLUS; 720 NdisRawWritePortUshort(Adapter->PortOffset + RDP, Data); 721 722 /* set up bcr18: burst read/write enable */ 723 NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR18); 724 NdisRawReadPortUshort(Adapter->PortOffset + BDP, &Data); 725 726 Data |= BCR18_BREADE | BCR18_BWRITE ; 727 NdisRawWritePortUshort(Adapter->PortOffset + BDP, Data); 728 729 /* set up csr1 and csr2 with init block */ 730 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR1); 731 NdisRawWritePortUshort(Adapter->PortOffset + RDP, (USHORT)(Adapter->InitializationBlockPhys.LowPart & 0xffff)); 732 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR2); 733 NdisRawWritePortUshort(Adapter->PortOffset + RDP, (USHORT)(Adapter->InitializationBlockPhys.LowPart >> 16) & 0xffff); 734 735 DPRINT("programmed with init block\n"); 736 737 /* Set mode to 0 */ 738 Data = 0; 739 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR15); 740 NdisRawWritePortUshort(Adapter->PortOffset + RDP, Data); 741 742 /* load init block and start the card */ 743 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0); 744 NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_STRT|CSR0_INIT|CSR0_IENA); 745 746 /* Allow LED programming */ 747 NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR2); 748 NdisRawWritePortUshort(Adapter->PortOffset + BDP, BCR2_LEDPE); 749 750 /* LED0 is configured for link status (on = up, off = down) */ 751 NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR4); 752 NdisRawWritePortUshort(Adapter->PortOffset + BDP, BCR4_LNKSTE | BCR4_PSE); 753 754 /* LED1 is configured for link duplex (on = full, off = half) */ 755 NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR5); 756 NdisRawWritePortUshort(Adapter->PortOffset + BDP, BCR5_FDLSE | BCR5_PSE); 757 758 /* LED2 is configured for link speed (on = 100M, off = 10M) */ 759 NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR6); 760 NdisRawWritePortUshort(Adapter->PortOffset + BDP, BCR6_E100 | BCR6_PSE); 761 762 /* LED3 is configured for trasmit/receive activity */ 763 NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR7); 764 NdisRawWritePortUshort(Adapter->PortOffset + BDP, BCR7_XMTE | BCR7_RCVE | BCR7_PSE); 765 766 Adapter->MediaState = MiGetMediaState(Adapter); 767 Adapter->FullDuplex = MiGetMediaDuplex(Adapter); 768 Adapter->MediaSpeed = MiGetMediaSpeed(Adapter); 769 770 DPRINT("card started\n"); 771 772 Adapter->Flags &= ~RESET_IN_PROGRESS; 773 } 774 775 #if DBG 776 static BOOLEAN 777 MiTestCard( 778 PADAPTER Adapter) 779 /* 780 * FUNCTION: Test the NIC 781 * ARGUMENTS: 782 * Adapter: pointer to the miniport's adapter struct 783 * RETURNS: 784 * TRUE if the test succeeds 785 * FALSE otherwise 786 * NOTES: 787 * - this is where to add diagnostics. This is called 788 * at the very end of initialization. 789 */ 790 { 791 int i = 0; 792 UCHAR address[6]; 793 USHORT Data = 0; 794 795 /* see if we can read/write now */ 796 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0); 797 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data); 798 DPRINT("Port 0x%x RAP 0x%x CSR0 0x%x RDP 0x%x, Interrupt status register is 0x%x\n", Adapter->PortOffset, RAP, CSR0, RDP, Data); 799 800 /* read the BIA */ 801 for(i = 0; i < 6; i++) 802 NdisRawReadPortUchar(Adapter->PortOffset + i, &address[i]); 803 804 DPRINT("burned-in address: %02x:%02x:%02x:%02x:%02x:%02x\n", address[0], address[1], address[2], address[3], address[4], address[5]); 805 /* Read status flags from CSR0 */ 806 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0); 807 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data); 808 DPRINT("CSR0: 0x%x\n", Data); 809 810 /* Read status flags from CSR3 */ 811 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR3); 812 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data); 813 DPRINT("CSR3: 0x%x\n", Data); 814 815 /* Read status flags from CSR4 */ 816 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR4); 817 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data); 818 DPRINT("CSR4: 0x%x\n", Data); 819 820 /* Read status flags from CSR5 */ 821 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR5); 822 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data); 823 DPRINT("CSR5: 0x%x\n", Data); 824 825 /* Read status flags from CSR6 */ 826 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR6); 827 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data); 828 DPRINT("CSR6: 0x%x\n", Data); 829 830 /* Read status flags from BCR4 */ 831 NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR4); 832 NdisRawReadPortUshort(Adapter->PortOffset + BDP, &Data); 833 DPRINT("BCR4: 0x%x\n", Data); 834 835 return TRUE; 836 } 837 #endif 838 839 VOID 840 NTAPI 841 MiniportShutdown( PVOID Context ) 842 { 843 PADAPTER Adapter = Context; 844 845 DPRINT("Stopping the chip\n"); 846 847 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0); 848 NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_STOP); 849 } 850 851 static NDIS_STATUS 852 NTAPI 853 MiniportInitialize( 854 OUT PNDIS_STATUS OpenErrorStatus, 855 OUT PUINT SelectedMediumIndex, 856 IN PNDIS_MEDIUM MediumArray, 857 IN UINT MediumArraySize, 858 IN NDIS_HANDLE MiniportAdapterHandle, 859 IN NDIS_HANDLE WrapperConfigurationContext) 860 /* 861 * FUNCTION: Initialize a new miniport 862 * ARGUMENTS: 863 * OpenErrorStatus: pointer to a var to return status info in 864 * SelectedMediumIndex: index of the selected medium (will be NdisMedium802_3) 865 * MediumArray: array of media that we can pick from 866 * MediumArraySize: size of MediumArray 867 * MiniportAdapterHandle: NDIS-assigned handle for this miniport instance 868 * WrapperConfigurationContext: temporary NDIS-assigned handle for passing 869 * to configuration APIs 870 * RETURNS: 871 * NDIS_STATUS_SUCCESS on success 872 * NDIS_STATUS_FAILURE on general failure 873 * NDIS_STATUS_UNSUPPORTED_MEDIA on not finding 802_3 in the MediaArray 874 * NDIS_STATUS_RESOURCES on insufficient system resources 875 * NDIS_STATUS_ADAPTER_NOT_FOUND on not finding the adapter 876 * NOTES: 877 * - Called by NDIS at PASSIVE_LEVEL, once per detected card 878 * - Will int 3 on failure of MiTestCard if DBG=1 879 */ 880 { 881 UINT i = 0; 882 PADAPTER Adapter = 0; 883 NDIS_STATUS Status = NDIS_STATUS_FAILURE; 884 BOOLEAN InterruptRegistered = FALSE, MapRegistersAllocated = FALSE; 885 NDIS_HANDLE ConfigurationHandle; 886 UINT *RegNetworkAddress = 0; 887 UINT RegNetworkAddressLength = 0; 888 889 ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 890 891 /* Pick a medium */ 892 for(i = 0; i < MediumArraySize; i++) 893 if(MediumArray[i] == NdisMedium802_3) 894 break; 895 896 if(i == MediumArraySize) 897 { 898 Status = NDIS_STATUS_UNSUPPORTED_MEDIA; 899 DPRINT1("unsupported media\n"); 900 *OpenErrorStatus = Status; 901 return Status; 902 } 903 904 *SelectedMediumIndex = i; 905 906 /* allocate our adapter struct */ 907 Status = NdisAllocateMemoryWithTag((PVOID *)&Adapter, sizeof(ADAPTER), PCNET_TAG); 908 if(Status != NDIS_STATUS_SUCCESS) 909 { 910 Status = NDIS_STATUS_RESOURCES; 911 DPRINT1("Insufficient resources\n"); 912 *OpenErrorStatus = Status; 913 return Status; 914 } 915 916 RtlZeroMemory(Adapter, sizeof(ADAPTER)); 917 918 Adapter->MiniportAdapterHandle = MiniportAdapterHandle; 919 920 /* register our adapter structwith ndis */ 921 NdisMSetAttributesEx(Adapter->MiniportAdapterHandle, Adapter, 0, NDIS_ATTRIBUTE_BUS_MASTER, NdisInterfacePci); 922 923 do 924 { 925 /* Card-specific detection and setup */ 926 Status = MiQueryCard(Adapter); 927 if(Status != NDIS_STATUS_SUCCESS) 928 { 929 DPRINT1("MiQueryCard failed\n"); 930 Status = NDIS_STATUS_ADAPTER_NOT_FOUND; 931 break; 932 } 933 934 /* register an IO port range */ 935 Status = NdisMRegisterIoPortRange((PVOID*)&Adapter->PortOffset, Adapter->MiniportAdapterHandle, 936 (UINT)Adapter->IoBaseAddress, NUMBER_OF_PORTS); 937 if(Status != NDIS_STATUS_SUCCESS) 938 { 939 DPRINT1("NdisMRegisterIoPortRange failed: 0x%x\n", Status); 940 break; 941 } 942 943 /* Allocate map registers */ 944 Status = NdisMAllocateMapRegisters(Adapter->MiniportAdapterHandle, 0, 945 NDIS_DMA_32BITS, 8, BUFFER_SIZE); 946 if(Status != NDIS_STATUS_SUCCESS) 947 { 948 DPRINT1("NdisMAllocateMapRegisters failed: 0x%x\n", Status); 949 break; 950 } 951 952 MapRegistersAllocated = TRUE; 953 954 /* set up the interrupt */ 955 Status = NdisMRegisterInterrupt(&Adapter->InterruptObject, Adapter->MiniportAdapterHandle, Adapter->InterruptVector, 956 Adapter->InterruptVector, TRUE, TRUE, NdisInterruptLevelSensitive); 957 if(Status != NDIS_STATUS_SUCCESS) 958 { 959 DPRINT1("NdisMRegisterInterrupt failed: 0x%x\n", Status); 960 break; 961 } 962 963 InterruptRegistered = TRUE; 964 965 /* Allocate and initialize shared data structures */ 966 Status = MiAllocateSharedMemory(Adapter); 967 if(Status != NDIS_STATUS_SUCCESS) 968 { 969 Status = NDIS_STATUS_RESOURCES; 970 DPRINT1("MiAllocateSharedMemory failed\n", Status); 971 break; 972 } 973 974 /* set up the initialization block */ 975 MiPrepareInitializationBlock(Adapter); 976 977 /* see if someone set a network address manually */ 978 NdisOpenConfiguration(&Status, &ConfigurationHandle, WrapperConfigurationContext); 979 if (Status == NDIS_STATUS_SUCCESS) 980 { 981 NdisReadNetworkAddress(&Status, (PVOID *)&RegNetworkAddress, &RegNetworkAddressLength, ConfigurationHandle); 982 if(Status == NDIS_STATUS_SUCCESS && RegNetworkAddressLength == 6) 983 { 984 int i; 985 DPRINT("NdisReadNetworkAddress returned successfully, address %x:%x:%x:%x:%x:%x\n", 986 RegNetworkAddress[0], RegNetworkAddress[1], RegNetworkAddress[2], RegNetworkAddress[3], 987 RegNetworkAddress[4], RegNetworkAddress[5]); 988 989 for(i = 0; i < 6; i++) 990 Adapter->InitializationBlockVirt->PADR[i] = RegNetworkAddress[i]; 991 } 992 993 NdisCloseConfiguration(ConfigurationHandle); 994 } 995 996 DPRINT("Interrupt registered successfully\n"); 997 998 /* Initialize and start the chip */ 999 MiInitChip(Adapter); 1000 1001 NdisAllocateSpinLock(&Adapter->Lock); 1002 1003 Status = NDIS_STATUS_SUCCESS; 1004 } 1005 while(0); 1006 1007 if(Status != NDIS_STATUS_SUCCESS && Adapter) 1008 { 1009 DPRINT("Error; freeing stuff\n"); 1010 1011 MiFreeSharedMemory(Adapter); 1012 1013 if(MapRegistersAllocated) 1014 NdisMFreeMapRegisters(Adapter->MiniportAdapterHandle); 1015 1016 if(Adapter->PortOffset) 1017 NdisMDeregisterIoPortRange(Adapter->MiniportAdapterHandle, Adapter->IoBaseAddress, NUMBER_OF_PORTS, (PVOID)Adapter->PortOffset); 1018 1019 if(InterruptRegistered) 1020 NdisMDeregisterInterrupt(&Adapter->InterruptObject); 1021 1022 NdisFreeMemory(Adapter, 0, 0); 1023 } 1024 1025 if(Status == NDIS_STATUS_SUCCESS) 1026 { 1027 NdisMInitializeTimer(&Adapter->MediaDetectionTimer, 1028 Adapter->MiniportAdapterHandle, 1029 MiniportMediaDetectionTimer, 1030 Adapter); 1031 NdisMSetPeriodicTimer(&Adapter->MediaDetectionTimer, 1032 MEDIA_DETECTION_INTERVAL); 1033 NdisMRegisterAdapterShutdownHandler(Adapter->MiniportAdapterHandle, 1034 Adapter, 1035 MiniportShutdown); 1036 } 1037 1038 #if DBG 1039 if(!MiTestCard(Adapter)) 1040 ASSERT(0); 1041 #endif 1042 1043 DPRINT("returning 0x%x\n", Status); 1044 *OpenErrorStatus = Status; 1045 return Status; 1046 } 1047 1048 static VOID 1049 NTAPI 1050 MiniportISR( 1051 OUT PBOOLEAN InterruptRecognized, 1052 OUT PBOOLEAN QueueMiniportHandleInterrupt, 1053 IN NDIS_HANDLE MiniportAdapterContext) 1054 /* 1055 * FUNCTION: Miniport interrupt service routine 1056 * ARGUMENTS: 1057 * InterruptRecognized: the interrupt was ours 1058 * QueueMiniportHandleInterrupt: whether to queue a DPC to handle this interrupt 1059 * MiniportAdapterContext: the context originally passed to NdisMSetAttributes 1060 * NOTES: 1061 * - called by NDIS at DIRQL 1062 * - by setting QueueMiniportHandleInterrupt to TRUE, MiniportHandleInterrupt 1063 * will be called 1064 */ 1065 { 1066 USHORT Data; 1067 USHORT Rap; 1068 PADAPTER Adapter = (PADAPTER)MiniportAdapterContext; 1069 1070 DPRINT("Called\n"); 1071 1072 /* save the old RAP value */ 1073 NdisRawReadPortUshort(Adapter->PortOffset + RAP, &Rap); 1074 1075 /* is this ours? */ 1076 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0); 1077 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data); 1078 1079 if(!(Data & CSR0_INTR)) 1080 { 1081 DPRINT("not our interrupt.\n"); 1082 *InterruptRecognized = FALSE; 1083 *QueueMiniportHandleInterrupt = FALSE; 1084 } 1085 else 1086 { 1087 DPRINT("detected our interrupt\n"); 1088 1089 /* disable interrupts */ 1090 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0); 1091 NdisRawWritePortUshort(Adapter->PortOffset + RDP, 0); 1092 1093 *InterruptRecognized = TRUE; 1094 *QueueMiniportHandleInterrupt = TRUE; 1095 } 1096 1097 /* restore the rap */ 1098 NdisRawWritePortUshort(Adapter->PortOffset + RAP, Rap); 1099 } 1100 1101 static NDIS_STATUS 1102 NTAPI 1103 MiniportReset( 1104 OUT PBOOLEAN AddressingReset, 1105 IN NDIS_HANDLE MiniportAdapterContext) 1106 /* 1107 * FUNCTION: Reset the miniport 1108 * ARGUMENTS: 1109 * AddressingReset: Whether or not we want NDIS to subsequently call MiniportSetInformation 1110 * to reset our addresses and filters 1111 * MiniportAdapterContext: context originally passed to NdisMSetAttributes 1112 * RETURNS: 1113 * NDIS_STATUS_SUCCESS on all requests 1114 * Notes: 1115 * - Called by NDIS at PASSIVE_LEVEL when it thinks we need a reset 1116 */ 1117 { 1118 DPRINT("Called\n"); 1119 1120 /* MiniportReset doesn't do anything at the moment... perhaps this should be fixed. */ 1121 1122 *AddressingReset = FALSE; 1123 return NDIS_STATUS_SUCCESS; 1124 } 1125 1126 static BOOLEAN 1127 NTAPI 1128 MiSyncStartTransmit( 1129 IN PVOID SynchronizeContext) 1130 /* 1131 * FUNCTION: Stop the adapter 1132 * ARGUMENTS: 1133 * SynchronizeContext: Adapter context 1134 */ 1135 { 1136 PADAPTER Adapter = (PADAPTER)SynchronizeContext; 1137 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0); 1138 NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_IENA | CSR0_TDMD); 1139 return TRUE; 1140 } 1141 1142 static NDIS_STATUS 1143 NTAPI 1144 MiniportSend( 1145 IN NDIS_HANDLE MiniportAdapterContext, 1146 IN PNDIS_PACKET Packet, 1147 IN UINT Flags) 1148 /* 1149 * FUNCTION: Called by NDIS when it has a packet for the NIC to send out 1150 * ARGUMENTS: 1151 * MiniportAdapterContext: context originally input to NdisMSetAttributes 1152 * Packet: The NDIS_PACKET to be sent 1153 * Flags: Flags associated with Packet 1154 * RETURNS: 1155 * NDIS_STATUS_SUCCESS on processed requests 1156 * NDIS_STATUS_RESOURCES if there's no place in buffer ring 1157 * NOTES: 1158 * - Called by NDIS at DISPATCH_LEVEL 1159 */ 1160 { 1161 PADAPTER Adapter = (PADAPTER)MiniportAdapterContext; 1162 PTRANSMIT_DESCRIPTOR Desc; 1163 PNDIS_BUFFER NdisBuffer; 1164 PVOID SourceBuffer; 1165 UINT TotalPacketLength, SourceLength, Position = 0; 1166 1167 DPRINT("Called\n"); 1168 1169 ASSERT_IRQL_EQUAL(DISPATCH_LEVEL); 1170 1171 NdisDprAcquireSpinLock(&Adapter->Lock); 1172 1173 /* Check if we have free entry in our circular buffer. */ 1174 if ((Adapter->CurrentTransmitEndIndex + 1 == 1175 Adapter->CurrentTransmitStartIndex) || 1176 (Adapter->CurrentTransmitEndIndex == Adapter->BufferCount - 1 && 1177 Adapter->CurrentTransmitStartIndex == 0)) 1178 { 1179 DPRINT1("No free space in circular buffer\n"); 1180 NdisDprReleaseSpinLock(&Adapter->Lock); 1181 return NDIS_STATUS_RESOURCES; 1182 } 1183 1184 Desc = Adapter->TransmitDescriptorRingVirt + Adapter->CurrentTransmitEndIndex; 1185 1186 NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, &TotalPacketLength); 1187 ASSERT(TotalPacketLength <= BUFFER_SIZE); 1188 1189 DPRINT("TotalPacketLength: %x\n", TotalPacketLength); 1190 1191 while (NdisBuffer) 1192 { 1193 NdisQueryBuffer(NdisBuffer, &SourceBuffer, &SourceLength); 1194 1195 DPRINT("Buffer: %x Length: %x\n", SourceBuffer, SourceLength); 1196 1197 RtlCopyMemory(Adapter->TransmitBufferPtrVirt + 1198 Adapter->CurrentTransmitEndIndex * BUFFER_SIZE + Position, 1199 SourceBuffer, SourceLength); 1200 1201 Position += SourceLength; 1202 1203 NdisGetNextBuffer(NdisBuffer, &NdisBuffer); 1204 } 1205 1206 #if DBG && 0 1207 { 1208 PUCHAR Ptr = Adapter->TransmitBufferPtrVirt + 1209 Adapter->CurrentTransmitEndIndex * BUFFER_SIZE; 1210 for (Position = 0; Position < TotalPacketLength; Position++) 1211 { 1212 if (Position % 16 == 0) 1213 DbgPrint("\n"); 1214 DbgPrint("%x ", *Ptr++); 1215 } 1216 } 1217 DbgPrint("\n"); 1218 #endif 1219 1220 Adapter->CurrentTransmitEndIndex++; 1221 Adapter->CurrentTransmitEndIndex %= Adapter->BufferCount; 1222 1223 Desc->FLAGS = TD1_OWN | TD1_STP | TD1_ENP; 1224 Desc->BCNT = 0xf000 | -(INT)TotalPacketLength; 1225 1226 NdisMSynchronizeWithInterrupt(&Adapter->InterruptObject, MiSyncStartTransmit, Adapter); 1227 1228 NdisDprReleaseSpinLock(&Adapter->Lock); 1229 1230 return NDIS_STATUS_SUCCESS; 1231 } 1232 1233 static ULONG 1234 NTAPI 1235 MiEthernetCrc(UCHAR *Address) 1236 /* 1237 * FUNCTION: Calculate Ethernet CRC32 1238 * ARGUMENTS: 1239 * Address: 6-byte ethernet address 1240 * RETURNS: 1241 * The calculated CRC32 value. 1242 */ 1243 { 1244 UINT Counter, Length; 1245 ULONG Value = ~0; 1246 1247 for (Length = 0; Length < 6; Length++) 1248 { 1249 Value ^= *Address++; 1250 for (Counter = 0; Counter < 8; Counter++) 1251 { 1252 Value >>= 1; 1253 Value ^= (Value & 1) * 0xedb88320; 1254 } 1255 } 1256 1257 return Value; 1258 } 1259 1260 NDIS_STATUS 1261 NTAPI 1262 MiSetMulticast( 1263 PADAPTER Adapter, 1264 UCHAR *Addresses, 1265 UINT AddressCount) 1266 { 1267 UINT Index; 1268 ULONG CrcIndex; 1269 1270 NdisZeroMemory(Adapter->InitializationBlockVirt->LADR, 8); 1271 for (Index = 0; Index < AddressCount; Index++) 1272 { 1273 CrcIndex = MiEthernetCrc(Addresses) >> 26; 1274 Adapter->InitializationBlockVirt->LADR[CrcIndex >> 3] |= 1 << (CrcIndex & 15); 1275 Addresses += 6; 1276 } 1277 1278 /* FIXME: The specification mentions we need to reload the init block here. */ 1279 1280 return NDIS_STATUS_SUCCESS; 1281 } 1282 1283 BOOLEAN 1284 NTAPI 1285 MiGetMediaDuplex(PADAPTER Adapter) 1286 { 1287 ULONG Data; 1288 1289 NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR5); 1290 NdisRawReadPortUshort(Adapter->PortOffset + BDP, &Data); 1291 1292 return (Data & BCR5_LEDOUT) != 0; 1293 } 1294 1295 UINT 1296 NTAPI 1297 MiGetMediaSpeed(PADAPTER Adapter) 1298 { 1299 ULONG Data; 1300 1301 NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR6); 1302 NdisRawReadPortUshort(Adapter->PortOffset + BDP, &Data); 1303 1304 return Data & BCR6_LEDOUT ? 100 : 10; 1305 } 1306 1307 NDIS_MEDIA_STATE 1308 NTAPI 1309 MiGetMediaState(PADAPTER Adapter) 1310 /* 1311 * FUNCTION: Determine the link state 1312 * ARGUMENTS: 1313 * Adapter: Adapter context 1314 * RETURNS: 1315 * NdisMediaStateConnected if the cable is connected 1316 * NdisMediaStateDisconnected if the cable is disconnected 1317 */ 1318 { 1319 ULONG Data; 1320 NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR4); 1321 NdisRawReadPortUshort(Adapter->PortOffset + BDP, &Data); 1322 return Data & BCR4_LEDOUT ? NdisMediaStateConnected : NdisMediaStateDisconnected; 1323 } 1324 1325 NTSTATUS 1326 NTAPI 1327 DriverEntry( 1328 IN PDRIVER_OBJECT DriverObject, 1329 IN PUNICODE_STRING RegistryPath) 1330 /* 1331 * FUNCTION: Start this driver 1332 * ARGUMENTS: 1333 * DriverObject: Pointer to the system-allocated driver object 1334 * RegistryPath: Pointer to our SCM database entry 1335 * RETURNS: 1336 * NDIS_STATUS_SUCCESS on success 1337 * NDIS_STATUS_FAILURE on failure 1338 * NOTES: 1339 * - Called by the I/O manager when the driver starts at PASSIVE_LEVEL 1340 * - TODO: convert this to NTSTATUS return values 1341 */ 1342 { 1343 NDIS_HANDLE WrapperHandle; 1344 NDIS_MINIPORT_CHARACTERISTICS Characteristics; 1345 NDIS_STATUS Status; 1346 1347 RtlZeroMemory(&Characteristics, sizeof(Characteristics)); 1348 Characteristics.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION; 1349 Characteristics.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION; 1350 Characteristics.HaltHandler = MiniportHalt; 1351 Characteristics.HandleInterruptHandler = MiniportHandleInterrupt; 1352 Characteristics.InitializeHandler = MiniportInitialize; 1353 Characteristics.ISRHandler = MiniportISR; 1354 Characteristics.QueryInformationHandler = MiniportQueryInformation; 1355 Characteristics.ResetHandler = MiniportReset; 1356 Characteristics.SetInformationHandler = MiniportSetInformation; 1357 Characteristics.SendHandler = MiniportSend; 1358 1359 NdisMInitializeWrapper(&WrapperHandle, DriverObject, RegistryPath, 0); 1360 if (!WrapperHandle) return NDIS_STATUS_FAILURE; 1361 1362 Status = NdisMRegisterMiniport(WrapperHandle, &Characteristics, sizeof(Characteristics)); 1363 if(Status != NDIS_STATUS_SUCCESS) 1364 { 1365 NdisTerminateWrapper(WrapperHandle, 0); 1366 return NDIS_STATUS_FAILURE; 1367 } 1368 1369 return NDIS_STATUS_SUCCESS; 1370 } 1371