2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NDIS library
5 * PURPOSE: I/O related routines
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Vizzini (vizzini@plasmic.com)
9 * CSH 01/08-2000 Created
10 * 8-20-2003 Vizzini - DMA support
15 VOID STDCALL HandleDeferredProcessing(
17 IN PVOID DeferredContext,
18 IN PVOID SystemArgument1,
19 IN PVOID SystemArgument2)
21 * FUNCTION: Deferred interrupt processing routine
23 * Dpc = Pointer to DPC object
24 * DeferredContext = Pointer to context information (LOGICAL_ADAPTER)
25 * SystemArgument1 = Unused
26 * SystemArgument2 = Unused
30 PLOGICAL_ADAPTER Adapter = GET_LOGICAL_ADAPTER(DeferredContext);
32 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
34 KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
35 WasBusy = Adapter->MiniportBusy;
36 Adapter->MiniportBusy = TRUE;
37 KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
39 /* Call the deferred interrupt service handler for this adapter */
40 (*Adapter->Miniport->Chars.HandleInterruptHandler)(
41 Adapter->NdisMiniportBlock.MiniportAdapterContext);
43 KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
44 if ((!WasBusy) && (Adapter->WorkQueueHead)) {
45 KeInsertQueueDpc(&Adapter->MiniportDpc, NULL, NULL);
47 Adapter->MiniportBusy = WasBusy;
49 KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
51 NDIS_DbgPrint(MAX_TRACE, ("Leaving.\n"));
55 BOOLEAN STDCALL ServiceRoutine(
56 IN PKINTERRUPT Interrupt,
57 IN PVOID ServiceContext)
59 * FUNCTION: Interrupt service routine
61 * Interrupt = Pointer to interrupt object
62 * ServiceContext = Pointer to context information (LOGICAL_ADAPTER)
64 * TRUE if a miniport controlled device generated the interrupt
67 BOOLEAN InterruptRecognized;
68 BOOLEAN QueueMiniportHandleInterrupt;
69 PLOGICAL_ADAPTER Adapter = GET_LOGICAL_ADAPTER(ServiceContext);
71 NDIS_DbgPrint(MAX_TRACE, ("Called. Adapter (0x%X)\n", Adapter));
73 (*Adapter->Miniport->Chars.ISRHandler)(&InterruptRecognized,
74 &QueueMiniportHandleInterrupt,
75 Adapter->NdisMiniportBlock.MiniportAdapterContext);
77 if (QueueMiniportHandleInterrupt) {
78 NDIS_DbgPrint(MAX_TRACE, ("Queueing DPC.\n"));
79 KeInsertQueueDpc(&Adapter->NdisMiniportBlock.Interrupt->InterruptDpc, NULL, NULL);
82 NDIS_DbgPrint(MAX_TRACE, ("Leaving.\n"));
84 return InterruptRecognized;
93 NdisCompleteDmaTransfer(
94 OUT PNDIS_STATUS Status,
95 IN PNDIS_HANDLE NdisDmaHandle,
96 IN PNDIS_BUFFER Buffer,
99 IN BOOLEAN WriteToDevice)
111 IN PNDIS_BUFFER Buffer,
112 IN BOOLEAN WriteToDevice)
123 NdisGetCacheFillSize(
137 NdisImmediateReadPortUchar(
138 IN NDIS_HANDLE WrapperConfigurationContext,
142 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
143 *Data = READ_PORT_UCHAR((PUCHAR)Port); // FIXME: What to do with WrapperConfigurationContext?
152 NdisImmediateReadPortUlong(
153 IN NDIS_HANDLE WrapperConfigurationContext,
157 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
158 *Data = READ_PORT_ULONG((PULONG)Port); // FIXME: What to do with WrapperConfigurationContext?
167 NdisImmediateReadPortUshort(
168 IN NDIS_HANDLE WrapperConfigurationContext,
172 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
173 *Data = READ_PORT_USHORT((PUSHORT)Port); // FIXME: What to do with WrapperConfigurationContext?
182 NdisImmediateWritePortUchar(
183 IN NDIS_HANDLE WrapperConfigurationContext,
187 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
188 WRITE_PORT_UCHAR((PUCHAR)Port, Data); // FIXME: What to do with WrapperConfigurationContext?
197 NdisImmediateWritePortUlong(
198 IN NDIS_HANDLE WrapperConfigurationContext,
202 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
203 WRITE_PORT_ULONG((PULONG)Port, Data); // FIXME: What to do with WrapperConfigurationContext?
212 NdisImmediateWritePortUshort(
213 IN NDIS_HANDLE WrapperConfigurationContext,
217 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
218 WRITE_PORT_USHORT((PUSHORT)Port, Data); // FIXME: What to do with WrapperConfigurationContext?
222 IO_ALLOCATION_ACTION NdisMapRegisterCallback (
223 IN PDEVICE_OBJECT DeviceObject,
225 IN PVOID MapRegisterBase,
228 * FUNCTION: Called back during reservation of map registers
231 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)Context;
232 PADAPTER_MAP_REGISTER_LIST Register = ExAllocatePool(NonPagedPool, sizeof(ADAPTER_MAP_REGISTER_LIST));
234 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
238 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n"));
239 KeSetEvent(&Adapter->DmaEvent, 0, FALSE);
240 return DeallocateObject;
243 Register->MapRegister = MapRegisterBase;
244 Register->NumRegisters = Adapter->MapRegistersRequested;
246 ExInterlockedInsertTailList(&Adapter->MapRegisterList.ListEntry, &Register->ListEntry, &Adapter->DmaLock);
248 KeSetEvent(&Adapter->DmaEvent, 0, FALSE);
250 /* XXX this is only the thing to do for busmaster NICs */
251 return DeallocateObjectKeepRegisters;
259 NdisMAllocateMapRegisters(
260 IN NDIS_HANDLE MiniportAdapterHandle,
263 IN ULONG BaseMapRegistersNeeded,
264 IN ULONG MaximumBufferSize)
266 * FUNCTION: Allocate map registers for use in DMA transfers
268 * MiniportAdapterHandle: Passed in to MiniportInitialize
269 * DmaChannel: DMA channel to use
270 * DmaSize: bit width of DMA transfers
271 * BaseMapRegistersNeeded: number of map registers requested
272 * MaximumBufferSize: largest single buffer transferred
274 * NDIS_STATUS_SUCCESS on success
275 * NDIS_STATUS_RESOURCES on failure
277 * - the win2k ddk and the nt4 ddk have conflicting prototypes for this.
278 * I'm implementing the 2k one.
281 DEVICE_DESCRIPTION Description;
282 PADAPTER_OBJECT AdapterObject = 0;
283 UINT MapRegistersRequired = 0;
284 UINT MapRegistersPerBaseRegister = 0;
285 ULONG AvailableMapRegisters;
287 PLOGICAL_ADAPTER Adapter = 0;
288 PDEVICE_OBJECT DeviceObject = 0;
291 NDIS_DbgPrint(MAX_TRACE, ("called: Handle 0x%x, DmaChannel 0x%x, DmaSize 0x%x, BaseMapRegsNeeded: 0x%x, MaxBuffer: 0x%x.\n",
292 MiniportAdapterHandle, DmaChannel, DmaSize, BaseMapRegistersNeeded, MaximumBufferSize));
294 memset(&Description,0,sizeof(Description));
296 Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle;
297 DeviceObject = Adapter->NdisMiniportBlock.DeviceObject;
299 InitializeListHead(&Adapter->MapRegisterList.ListEntry);
300 KeInitializeEvent(&Adapter->DmaEvent, NotificationEvent, FALSE);
301 KeInitializeSpinLock(&Adapter->DmaLock);
304 * map registers correlate to physical pages. ndis documents a
305 * maximum of 64 map registers that it will return.
306 * at 4k pages, a 1514-byte buffer can span not more than 2 pages.
308 * the number of registers required for a given physical mapping
309 * is (first register + last register + one per page size),
310 * given that physical mapping is > 2.
313 /* unhandled corner case: 1-byte max buffer size */
314 MapRegistersPerBaseRegister = 2 + MaximumBufferSize / PAGE_SIZE;
315 MapRegistersRequired = BaseMapRegistersNeeded * MapRegistersPerBaseRegister;
317 if(MapRegistersRequired > 64)
319 NDIS_DbgPrint(MID_TRACE, ("Request for too many map registers: %d\n", MapRegistersRequired));
320 return NDIS_STATUS_RESOURCES;
323 Description.Version = DEVICE_DESCRIPTION_VERSION;
324 Description.Master = TRUE; /* implied by calling this function */
325 Description.ScatterGather = FALSE; /* implied by calling this function */
326 Description.DemandMode = 0; /* unused due to bus master */
327 Description.AutoInitialize = 0; /* unused due to bus master */
328 Description.Dma32BitAddresses = DmaSize;
329 Description.IgnoreCount = 0; /* unused due to bus master */
330 Description.Reserved1 = 0;
331 Description.Reserved2 = 0;
332 Description.BusNumber = Adapter->BusNumber;
333 Description.DmaChannel = 0; /* unused due to bus master */
334 Description.InterfaceType = Adapter->BusType;
335 Description.DmaChannel = 0; /* unused due to bus master */
336 Description.DmaWidth = 0; /* unused (i think) due to bus master */
337 Description.DmaSpeed = 0; /* unused (i think) due to bus master */
338 Description.MaximumLength = 0; /* unused (i think) due to bus master */
339 Description.DmaPort = 0; /* unused due to bus type */
341 AvailableMapRegisters = MapRegistersRequired;
342 AdapterObject = HalGetAdapter(&Description, &AvailableMapRegisters);
346 NDIS_DbgPrint(MIN_TRACE, ("Unable to allocate an adapter object; bailing out\n"));
347 return NDIS_STATUS_RESOURCES;
350 Adapter->AdapterObject = AdapterObject;
352 if(AvailableMapRegisters < MapRegistersRequired)
354 NDIS_DbgPrint(MIN_TRACE, ("Didn't get enough map registers from hal - requested 0x%x, got 0x%x\n",
355 MapRegistersRequired, AvailableMapRegisters));
356 return NDIS_STATUS_RESOURCES;
359 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
361 Adapter->MapRegistersRequested = MapRegistersRequired;
363 NtStatus = IoAllocateAdapterChannel(AdapterObject, DeviceObject,
364 MapRegistersRequired, NdisMapRegisterCallback, Adapter);
366 KeLowerIrql(OldIrql);
368 if(!NT_SUCCESS(NtStatus))
370 NDIS_DbgPrint(MIN_TRACE, ("IoAllocateAdapterChannel failed: 0x%x\n", NtStatus));
371 return NDIS_STATUS_RESOURCES;
374 NtStatus = KeWaitForSingleObject(&Adapter->DmaEvent, Executive, KernelMode, FALSE, 0);
376 if(!NT_SUCCESS(NtStatus))
378 NDIS_DbgPrint(MIN_TRACE, ("KeWaitForSingleObject failed: 0x%x\n", NtStatus));
379 return NDIS_STATUS_RESOURCES;
382 NDIS_DbgPrint(MAX_TRACE, ("returning success\n"));
383 return NDIS_STATUS_SUCCESS;
392 NdisMCompleteDmaTransfer(
393 OUT PNDIS_STATUS Status,
394 IN PNDIS_HANDLE MiniportDmaHandle,
395 IN PNDIS_BUFFER Buffer,
398 IN BOOLEAN WriteToDevice)
409 NdisMDeregisterDmaChannel(
410 IN PNDIS_HANDLE MiniportDmaHandle)
421 NdisMDeregisterInterrupt(
422 IN PNDIS_MINIPORT_INTERRUPT Interrupt)
424 * FUNCTION: Releases an interrupt vector
426 * Interrupt = Pointer to interrupt object
429 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
430 IoDisconnectInterrupt(Interrupt->InterruptObject);
439 NdisMDeregisterIoPortRange(
440 IN NDIS_HANDLE MiniportAdapterHandle,
442 IN UINT NumberOfPorts,
445 * FUNCTION: Releases a register mapping to I/O ports
447 * MiniportAdapterHandle = Specifies handle input to MiniportInitialize
448 * InitialPort = Bus-relative base port address of a range to be mapped
449 * NumberOfPorts = Specifies number of ports to be mapped
450 * PortOffset = Pointer to mapped base port address
453 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
462 NdisMFreeMapRegisters(
463 IN NDIS_HANDLE MiniportAdapterHandle)
465 * FUNCTION: Free previously allocated map registers
467 * MiniportAdapterHandle: Handle originally passed in to MiniportInitialize
472 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle;
473 PADAPTER_OBJECT AdapterObject = Adapter->AdapterObject;
475 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
477 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
479 while(!IsListEmpty(&Adapter->MapRegisterList.ListEntry))
481 PADAPTER_MAP_REGISTER_LIST Register = (PADAPTER_MAP_REGISTER_LIST)RemoveTailList(&Adapter->MapRegisterList.ListEntry);
484 IoFreeMapRegisters(AdapterObject, Register->MapRegister, Register->NumRegisters);
485 ExFreePool(Register);
488 NDIS_DbgPrint(MIN_TRACE,("Internal NDIS error - Register is 0\n"));
491 KeLowerIrql(OldIrql);
501 OUT PVOID *VirtualAddress,
502 IN NDIS_HANDLE MiniportAdapterHandle,
503 IN NDIS_PHYSICAL_ADDRESS PhysicalAddress,
508 return NDIS_STATUS_FAILURE;
518 IN NDIS_HANDLE MiniportDmaHandle)
531 NdisMRegisterDmaChannel(
532 OUT PNDIS_HANDLE MiniportDmaHandle,
533 IN NDIS_HANDLE MiniportAdapterHandle,
535 IN BOOLEAN Dma32BitAddresses,
536 IN PNDIS_DMA_DESCRIPTION DmaDescription,
537 IN ULONG MaximumLength)
541 return NDIS_STATUS_FAILURE;
549 NdisMRegisterInterrupt(
550 OUT PNDIS_MINIPORT_INTERRUPT Interrupt,
551 IN NDIS_HANDLE MiniportAdapterHandle,
552 IN UINT InterruptVector,
553 IN UINT InterruptLevel,
554 IN BOOLEAN RequestIsr,
555 IN BOOLEAN SharedInterrupt,
556 IN NDIS_INTERRUPT_MODE InterruptMode)
558 * FUNCTION: Claims access to an interrupt vector
560 * Interrupt = Address of interrupt object to initialize
561 * MiniportAdapterHandle = Specifies handle input to MiniportInitialize
562 * InterruptVector = Specifies bus-relative vector to register
563 * InterruptLevel = Specifies bus-relative DIRQL vector for interrupt
564 * RequestIsr = TRUE if MiniportISR should always be called
565 * SharedInterrupt = TRUE if other devices may use the same interrupt
566 * InterruptMode = Specifies type of interrupt
568 * Status of operation
575 PLOGICAL_ADAPTER Adapter = GET_LOGICAL_ADAPTER(MiniportAdapterHandle);
577 NDIS_DbgPrint(MAX_TRACE, ("Called. InterruptVector (0x%X) InterruptLevel (0x%X) "
578 "SharedInterrupt (%d) InterruptMode (0x%X)\n",
579 InterruptVector, InterruptLevel, SharedInterrupt, InterruptMode));
581 RtlZeroMemory(Interrupt, sizeof(NDIS_MINIPORT_INTERRUPT));
583 KeInitializeSpinLock(&Interrupt->DpcCountLock);
585 KeInitializeDpc(&Interrupt->InterruptDpc,
586 HandleDeferredProcessing,
589 KeInitializeEvent(&Interrupt->DpcsCompletedEvent,
593 Interrupt->SharedInterrupt = SharedInterrupt;
595 Adapter->NdisMiniportBlock.Interrupt = Interrupt;
597 MappedIRQ = HalGetInterruptVector(Adapter->BusType,
604 NDIS_DbgPrint(MAX_TRACE, ("Connecting to interrupt vector (0x%X) Affinity (0x%X).\n", MappedIRQ, Affinity));
606 Status = IoConnectInterrupt(&Interrupt->InterruptObject,
609 &Interrupt->DpcCountLock,
618 NDIS_DbgPrint(MAX_TRACE, ("Leaving. Status (0x%X).\n", Status));
620 if (NT_SUCCESS(Status))
621 return NDIS_STATUS_SUCCESS;
623 if (Status == STATUS_INSUFFICIENT_RESOURCES) {
624 /* FIXME: Log error */
625 return NDIS_STATUS_RESOURCE_CONFLICT;
628 return NDIS_STATUS_FAILURE;
637 NdisMRegisterIoPortRange(
638 OUT PVOID *PortOffset,
639 IN NDIS_HANDLE MiniportAdapterHandle,
641 IN UINT NumberOfPorts)
643 * FUNCTION: Sets up driver access to device I/O ports
645 * PortOffset = Address of buffer to place mapped base port address
646 * MiniportAdapterHandle = Specifies handle input to MiniportInitialize
647 * InitialPort = Bus-relative base port address of a range to be mapped
648 * NumberOfPorts = Specifies number of ports to be mapped
650 * Status of operation
653 PHYSICAL_ADDRESS PortAddress, TranslatedAddress;
654 PLOGICAL_ADAPTER Adapter = GET_LOGICAL_ADAPTER(MiniportAdapterHandle);
655 ULONG AddressSpace = 1; /* FIXME The HAL handles this wrong atm */
657 NDIS_DbgPrint(MAX_TRACE, ("Called - InitialPort 0x%x, NumberOfPorts 0x%x\n", InitialPort, NumberOfPorts));
659 memset(&PortAddress, 0, sizeof(PortAddress));
661 /* this might be a hack - ndis5 miniports seem to specify 0 */
663 PortAddress = RtlConvertUlongToLargeInteger(InitialPort);
665 PortAddress = Adapter->BaseIoAddress;
667 NDIS_DbgPrint(MAX_TRACE, ("Translating address 0x%x 0x%x\n", PortAddress.u.HighPart, PortAddress.u.LowPart));
669 /* FIXME: hard-coded bus number */
670 if(!HalTranslateBusAddress(Adapter->BusType, 0, PortAddress, &AddressSpace, &TranslatedAddress))
672 NDIS_DbgPrint(MIN_TRACE, ("Unable to translate address\n"));
673 return NDIS_STATUS_RESOURCES;
676 NDIS_DbgPrint(MAX_TRACE, ("Hal returned AddressSpace=0x%x TranslatedAddress=0x%x 0x%x\n",
677 AddressSpace, TranslatedAddress.u.HighPart, TranslatedAddress.u.LowPart));
681 ASSERT(TranslatedAddress.u.HighPart == 0);
682 *PortOffset = (PVOID) TranslatedAddress.u.LowPart;
683 NDIS_DbgPrint(MAX_TRACE, ("Returning 0x%x\n", *PortOffset));
684 return NDIS_STATUS_SUCCESS;
687 NDIS_DbgPrint(MAX_TRACE, ("calling MmMapIoSpace\n"));
690 *PortOffset = MmMapIoSpace(TranslatedAddress, NumberOfPorts, 0);
691 NDIS_DbgPrint(MAX_TRACE, ("Returning 0x%x for port range\n", *PortOffset));
694 return NDIS_STATUS_RESOURCES;
696 return NDIS_STATUS_SUCCESS;
704 NdisMSetupDmaTransfer(
705 OUT PNDIS_STATUS Status,
706 IN PNDIS_HANDLE MiniportDmaHandle,
707 IN PNDIS_BUFFER Buffer,
710 IN BOOLEAN WriteToDevice)
722 IN NDIS_HANDLE MiniportAdapterHandle,
723 IN PVOID VirtualAddress,