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 * 20 Aug 2003 Vizzini - DMA support
11 * 3 Oct 2003 Vizzini - Formatting and minor bugfixes
17 VOID NTAPI
HandleDeferredProcessing(
19 IN PVOID DeferredContext
,
20 IN PVOID SystemArgument1
,
21 IN PVOID SystemArgument2
)
23 * FUNCTION: Deferred interrupt processing routine
25 * Dpc = Pointer to DPC object
26 * DeferredContext = Pointer to context information (LOGICAL_ADAPTER)
27 * SystemArgument1 = Unused
28 * SystemArgument2 = Unused
31 PLOGICAL_ADAPTER Adapter
= GET_LOGICAL_ADAPTER(DeferredContext
);
33 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
35 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
37 /* Call the deferred interrupt service handler for this adapter */
38 (*Adapter
->NdisMiniportBlock
.DriverHandle
->MiniportCharacteristics
.HandleInterruptHandler
)(
39 Adapter
->NdisMiniportBlock
.MiniportAdapterContext
);
41 /* re-enable the interrupt */
42 NDIS_DbgPrint(MAX_TRACE
, ("re-enabling the interrupt\n"));
43 if(Adapter
->NdisMiniportBlock
.DriverHandle
->MiniportCharacteristics
.EnableInterruptHandler
)
44 (*Adapter
->NdisMiniportBlock
.DriverHandle
->MiniportCharacteristics
.EnableInterruptHandler
)(
45 Adapter
->NdisMiniportBlock
.MiniportAdapterContext
);
47 NDIS_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
51 BOOLEAN NTAPI
ServiceRoutine(
52 IN PKINTERRUPT Interrupt
,
53 IN PVOID ServiceContext
)
55 * FUNCTION: Interrupt service routine
57 * Interrupt = Pointer to interrupt object
58 * ServiceContext = Pointer to context information (PNDIS_MINIPORT_INTERRUPT)
60 * TRUE if a miniport controlled device generated the interrupt
63 BOOLEAN InterruptRecognized
= FALSE
;
64 BOOLEAN QueueMiniportHandleInterrupt
= FALSE
;
65 PNDIS_MINIPORT_INTERRUPT NdisInterrupt
= ServiceContext
;
66 PNDIS_MINIPORT_BLOCK NdisMiniportBlock
= NdisInterrupt
->Miniport
;
68 NDIS_DbgPrint(MAX_TRACE
, ("Called. Interrupt (0x%X)\n", NdisInterrupt
));
70 if (NdisInterrupt
->IsrRequested
) {
71 NDIS_DbgPrint(MAX_TRACE
, ("Calling MiniportISR\n"));
72 (*NdisMiniportBlock
->DriverHandle
->MiniportCharacteristics
.ISRHandler
)(
74 &QueueMiniportHandleInterrupt
,
75 NdisMiniportBlock
->MiniportAdapterContext
);
77 } else if (NdisMiniportBlock
->DriverHandle
->MiniportCharacteristics
.DisableInterruptHandler
) {
78 NDIS_DbgPrint(MAX_TRACE
, ("Calling MiniportDisableInterrupt\n"));
79 (*NdisMiniportBlock
->DriverHandle
->MiniportCharacteristics
.DisableInterruptHandler
)(
80 NdisMiniportBlock
->MiniportAdapterContext
);
81 QueueMiniportHandleInterrupt
= TRUE
;
82 InterruptRecognized
= TRUE
;
86 if (QueueMiniportHandleInterrupt
)
88 NDIS_DbgPrint(MAX_TRACE
, ("Queuing DPC.\n"));
89 KeInsertQueueDpc(&NdisInterrupt
->InterruptDpc
, NULL
, NULL
);
92 NDIS_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
94 return InterruptRecognized
;
103 NdisImmediateReadPortUchar(
104 IN NDIS_HANDLE WrapperConfigurationContext
,
108 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
109 *Data
= READ_PORT_UCHAR(UlongToPtr(Port
)); // FIXME: What to do with WrapperConfigurationContext?
118 NdisImmediateReadPortUlong(
119 IN NDIS_HANDLE WrapperConfigurationContext
,
123 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
124 *Data
= READ_PORT_ULONG(UlongToPtr(Port
)); // FIXME: What to do with WrapperConfigurationContext?
133 NdisImmediateReadPortUshort(
134 IN NDIS_HANDLE WrapperConfigurationContext
,
138 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
139 *Data
= READ_PORT_USHORT(UlongToPtr(Port
)); // FIXME: What to do with WrapperConfigurationContext?
148 NdisImmediateWritePortUchar(
149 IN NDIS_HANDLE WrapperConfigurationContext
,
153 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
154 WRITE_PORT_UCHAR(UlongToPtr(Port
), Data
); // FIXME: What to do with WrapperConfigurationContext?
163 NdisImmediateWritePortUlong(
164 IN NDIS_HANDLE WrapperConfigurationContext
,
168 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
169 WRITE_PORT_ULONG(UlongToPtr(Port
), Data
); // FIXME: What to do with WrapperConfigurationContext?
178 NdisImmediateWritePortUshort(
179 IN NDIS_HANDLE WrapperConfigurationContext
,
183 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
184 WRITE_PORT_USHORT(UlongToPtr(Port
), Data
); // FIXME: What to do with WrapperConfigurationContext?
187 IO_ALLOCATION_ACTION NTAPI
NdisSubordinateMapRegisterCallback (
188 IN PDEVICE_OBJECT DeviceObject
,
190 IN PVOID MapRegisterBase
,
193 * FUNCTION: Called back during reservation of map registers
195 * DeviceObject: Device object of the deivce setting up DMA
196 * Irp: Reserved; must be ignored
197 * MapRegisterBase: Map registers assigned for transfer
198 * Context: LOGICAL_ADAPTER object of the requesting miniport
200 * - Called at IRQL = DISPATCH_LEVEL
203 PNDIS_DMA_BLOCK DmaBlock
= Context
;
205 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
207 DmaBlock
->MapRegisterBase
= MapRegisterBase
;
209 NDIS_DbgPrint(MAX_TRACE
, ("setting event and leaving.\n"));
211 KeSetEvent(&DmaBlock
->AllocationEvent
, 0, FALSE
);
213 /* We have to hold the object open to keep our lock on the system DMA controller */
216 IO_ALLOCATION_ACTION NTAPI
NdisBusMasterMapRegisterCallback (
217 IN PDEVICE_OBJECT DeviceObject
,
219 IN PVOID MapRegisterBase
,
222 * FUNCTION: Called back during reservation of map registers
224 * DeviceObject: Device object of the deivce setting up DMA
225 * Irp: Reserved; must be ignored
226 * MapRegisterBase: Map registers assigned for transfer
227 * Context: LOGICAL_ADAPTER object of the requesting miniport
229 * - Called once per BaseMapRegister (see NdisMAllocateMapRegisters)
230 * - Called at IRQL = DISPATCH_LEVEL
233 PLOGICAL_ADAPTER Adapter
= Context
;
235 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
237 Adapter
->NdisMiniportBlock
.MapRegisters
[Adapter
->NdisMiniportBlock
.CurrentMapRegister
].MapRegister
= MapRegisterBase
;
239 NDIS_DbgPrint(MAX_TRACE
, ("setting event and leaving.\n"));
241 KeSetEvent(Adapter
->NdisMiniportBlock
.AllocationEvent
, 0, FALSE
);
243 /* We're a bus master so we can go ahead and deallocate the object now */
244 return DeallocateObjectKeepRegisters
;
251 NdisMAllocateMapRegisters(
252 IN NDIS_HANDLE MiniportAdapterHandle
,
254 IN NDIS_DMA_SIZE DmaSize
,
255 IN ULONG BaseMapRegistersNeeded
,
256 IN ULONG MaximumBufferSize
)
258 * FUNCTION: Allocate map registers for use in DMA transfers
260 * MiniportAdapterHandle: Passed in to MiniportInitialize
261 * DmaChannel: DMA channel to use
262 * DmaSize: bit width of DMA transfers
263 * BaseMapRegistersNeeded: number of base map registers requested
264 * MaximumBufferSize: largest single buffer transferred
266 * NDIS_STATUS_SUCCESS on success
267 * NDIS_STATUS_RESOURCES on failure
269 * - the win2k ddk and the nt4 ddk have conflicting prototypes for this.
270 * I'm implementing the 2k one.
271 * - do not confuse a "base map register" with a "map register" - they
272 * are different. Only NDIS seems to use the base concept. The idea
273 * is that a miniport supplies the number of base map registers it will
274 * need, which is equal to the number of DMA send buffers it manages.
275 * NDIS then allocates a number of map registers to go with each base
276 * map register, so that a driver just has to send the base map register
277 * number during dma operations and NDIS can find the group of real
278 * map registers that represent the transfer.
279 * - Because of the above sillyness, you can only specify a few base map
280 * registers at most. a 1514-byte packet is two map registers at 4k
282 * - NDIS limits the total number of allocated map registers to 64,
283 * which (in the case of the above example) limits the number of base
284 * map registers to 32.
287 DEVICE_DESCRIPTION Description
;
288 PDMA_ADAPTER AdapterObject
= 0;
289 UINT MapRegistersPerBaseRegister
= 0;
290 ULONG AvailableMapRegisters
;
292 PLOGICAL_ADAPTER Adapter
;
293 PDEVICE_OBJECT DeviceObject
= 0;
294 KEVENT AllocationEvent
;
297 NDIS_DbgPrint(MAX_TRACE
, ("called: Handle 0x%x, DmaChannel 0x%x, DmaSize 0x%x, BaseMapRegsNeeded: 0x%x, MaxBuffer: 0x%x.\n",
298 MiniportAdapterHandle
, DmaChannel
, DmaSize
, BaseMapRegistersNeeded
, MaximumBufferSize
));
300 memset(&Description
,0,sizeof(Description
));
302 Adapter
= (PLOGICAL_ADAPTER
)MiniportAdapterHandle
;
306 /* only bus masters may call this routine */
307 if(!(Adapter
->NdisMiniportBlock
.Flags
& NDIS_ATTRIBUTE_BUS_MASTER
)) {
308 NDIS_DbgPrint(MIN_TRACE
, ("Not a bus master\n"));
309 return NDIS_STATUS_NOT_SUPPORTED
;
312 DeviceObject
= Adapter
->NdisMiniportBlock
.DeviceObject
;
314 KeInitializeEvent(&AllocationEvent
, NotificationEvent
, FALSE
);
315 Adapter
->NdisMiniportBlock
.AllocationEvent
= &AllocationEvent
;
318 * map registers correlate to physical pages. ndis documents a
319 * maximum of 64 map registers that it will return.
320 * at 4k pages, a 1514-byte buffer can span not more than 2 pages.
322 * the number of registers required for a given physical mapping
323 * is (first register + last register + one per page size),
324 * given that physical mapping is > 2.
327 /* unhandled corner case: {1,2}-byte max buffer size */
328 ASSERT(MaximumBufferSize
> 2);
329 MapRegistersPerBaseRegister
= ((MaximumBufferSize
-2) / (2*PAGE_SIZE
)) + 2;
331 Description
.Version
= DEVICE_DESCRIPTION_VERSION
;
332 Description
.Master
= TRUE
; /* implied by calling this function */
333 Description
.ScatterGather
= TRUE
; /* XXX UNTRUE: All BM DMA are S/G (ms seems to do this) */
334 Description
.BusNumber
= Adapter
->NdisMiniportBlock
.BusNumber
;
335 Description
.InterfaceType
= Adapter
->NdisMiniportBlock
.BusType
;
336 Description
.DmaChannel
= DmaChannel
;
337 Description
.MaximumLength
= MaximumBufferSize
;
339 if(DmaSize
== NDIS_DMA_64BITS
)
340 Description
.Dma64BitAddresses
= TRUE
;
341 else if(DmaSize
== NDIS_DMA_32BITS
)
342 Description
.Dma32BitAddresses
= TRUE
;
344 AdapterObject
= IoGetDmaAdapter(
345 Adapter
->NdisMiniportBlock
.PhysicalDeviceObject
, &Description
, &AvailableMapRegisters
);
349 NDIS_DbgPrint(MIN_TRACE
, ("Unable to allocate an adapter object; bailing out\n"));
350 return NDIS_STATUS_RESOURCES
;
353 Adapter
->NdisMiniportBlock
.SystemAdapterObject
= AdapterObject
;
355 if(AvailableMapRegisters
< MapRegistersPerBaseRegister
)
357 NDIS_DbgPrint(MIN_TRACE
, ("Didn't get enough map registers from hal - requested 0x%x, got 0x%x\n",
358 MapRegistersPerBaseRegister
, AvailableMapRegisters
));
360 AdapterObject
->DmaOperations
->PutDmaAdapter(AdapterObject
);
361 Adapter
->NdisMiniportBlock
.SystemAdapterObject
= NULL
;
362 return NDIS_STATUS_RESOURCES
;
365 /* allocate & zero space in the miniport block for the registers */
366 Adapter
->NdisMiniportBlock
.MapRegisters
= ExAllocatePool(NonPagedPool
, BaseMapRegistersNeeded
* sizeof(MAP_REGISTER_ENTRY
));
367 if(!Adapter
->NdisMiniportBlock
.MapRegisters
)
369 NDIS_DbgPrint(MIN_TRACE
, ("insufficient resources.\n"));
370 AdapterObject
->DmaOperations
->PutDmaAdapter(AdapterObject
);
371 Adapter
->NdisMiniportBlock
.SystemAdapterObject
= NULL
;
372 return NDIS_STATUS_RESOURCES
;
375 memset(Adapter
->NdisMiniportBlock
.MapRegisters
, 0, BaseMapRegistersNeeded
* sizeof(MAP_REGISTER_ENTRY
));
376 Adapter
->NdisMiniportBlock
.BaseMapRegistersNeeded
= (USHORT
)BaseMapRegistersNeeded
;
378 while(BaseMapRegistersNeeded
)
380 NDIS_DbgPrint(MAX_TRACE
, ("iterating, basemapregistersneeded = %d\n", BaseMapRegistersNeeded
));
382 BaseMapRegistersNeeded
--;
383 Adapter
->NdisMiniportBlock
.CurrentMapRegister
= (USHORT
)BaseMapRegistersNeeded
;
384 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
386 NtStatus
= AdapterObject
->DmaOperations
->AllocateAdapterChannel(
387 AdapterObject
, DeviceObject
, MapRegistersPerBaseRegister
,
388 NdisBusMasterMapRegisterCallback
, Adapter
);
390 KeLowerIrql(OldIrql
);
392 if(!NT_SUCCESS(NtStatus
))
394 NDIS_DbgPrint(MIN_TRACE
, ("IoAllocateAdapterChannel failed: 0x%x\n", NtStatus
));
395 ExFreePool(Adapter
->NdisMiniportBlock
.MapRegisters
);
396 AdapterObject
->DmaOperations
->PutDmaAdapter(AdapterObject
);
397 Adapter
->NdisMiniportBlock
.CurrentMapRegister
= Adapter
->NdisMiniportBlock
.BaseMapRegistersNeeded
= 0;
398 Adapter
->NdisMiniportBlock
.SystemAdapterObject
= NULL
;
399 return NDIS_STATUS_RESOURCES
;
402 NDIS_DbgPrint(MAX_TRACE
, ("waiting on event\n"));
404 NtStatus
= KeWaitForSingleObject(&AllocationEvent
, Executive
, KernelMode
, FALSE
, 0);
406 if(!NT_SUCCESS(NtStatus
))
408 NDIS_DbgPrint(MIN_TRACE
, ("KeWaitForSingleObject failed: 0x%x\n", NtStatus
));
409 ExFreePool(Adapter
->NdisMiniportBlock
.MapRegisters
);
410 AdapterObject
->DmaOperations
->PutDmaAdapter(AdapterObject
);
411 Adapter
->NdisMiniportBlock
.CurrentMapRegister
= Adapter
->NdisMiniportBlock
.BaseMapRegistersNeeded
= 0;
412 Adapter
->NdisMiniportBlock
.SystemAdapterObject
= NULL
;
413 return NDIS_STATUS_RESOURCES
;
416 NDIS_DbgPrint(MAX_TRACE
, ("resetting event\n"));
418 KeResetEvent(&AllocationEvent
);
421 NDIS_DbgPrint(MAX_TRACE
, ("returning success\n"));
422 return NDIS_STATUS_SUCCESS
;
431 NdisMSetupDmaTransfer(OUT PNDIS_STATUS Status
,
432 IN NDIS_HANDLE MiniportDmaHandle
,
433 IN PNDIS_BUFFER Buffer
,
436 IN BOOLEAN WriteToDevice
)
438 PNDIS_DMA_BLOCK DmaBlock
= MiniportDmaHandle
;
440 PLOGICAL_ADAPTER Adapter
;
442 PDMA_ADAPTER AdapterObject
;
443 ULONG MapRegistersNeeded
;
445 NDIS_DbgPrint(MAX_TRACE
, ("called: Handle 0x%x, Buffer 0x%x, Offset 0x%x, Length 0x%x, WriteToDevice 0x%x\n",
446 MiniportDmaHandle
, Buffer
, Offset
, Length
, WriteToDevice
));
448 Adapter
= (PLOGICAL_ADAPTER
)DmaBlock
->Miniport
;
449 AdapterObject
= (PDMA_ADAPTER
)DmaBlock
->SystemAdapterObject
;
451 MapRegistersNeeded
= (Length
+ (PAGE_SIZE
- 1)) / PAGE_SIZE
;
453 KeFlushIoBuffers(Buffer
, !WriteToDevice
, TRUE
);
455 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
457 NtStatus
= AdapterObject
->DmaOperations
->AllocateAdapterChannel(AdapterObject
,
458 Adapter
->NdisMiniportBlock
.PhysicalDeviceObject
,
460 NdisSubordinateMapRegisterCallback
, Adapter
);
462 KeLowerIrql(OldIrql
);
464 if(!NT_SUCCESS(NtStatus
))
466 NDIS_DbgPrint(MIN_TRACE
, ("AllocateAdapterChannel failed: 0x%x\n", NtStatus
));
467 AdapterObject
->DmaOperations
->FreeAdapterChannel(AdapterObject
);
468 *Status
= NDIS_STATUS_RESOURCES
;
472 NtStatus
= KeWaitForSingleObject(&DmaBlock
->AllocationEvent
, Executive
, KernelMode
, FALSE
, 0);
474 if(!NT_SUCCESS(NtStatus
))
476 NDIS_DbgPrint(MIN_TRACE
, ("KeWaitForSingleObject failed: 0x%x\n", NtStatus
));
477 AdapterObject
->DmaOperations
->FreeAdapterChannel(AdapterObject
);
478 *Status
= NDIS_STATUS_RESOURCES
;
482 /* We must throw away the return value of MapTransfer for a system DMA device */
483 AdapterObject
->DmaOperations
->MapTransfer(AdapterObject
, Buffer
,
484 DmaBlock
->MapRegisterBase
,
485 (PUCHAR
)MmGetMdlVirtualAddress(Buffer
) + Offset
, &Length
, WriteToDevice
);
487 NDIS_DbgPrint(MAX_TRACE
, ("returning success\n"));
488 *Status
= NDIS_STATUS_SUCCESS
;
496 NdisSetupDmaTransfer(OUT PNDIS_STATUS Status
,
497 IN PNDIS_HANDLE NdisDmaHandle
,
498 IN PNDIS_BUFFER Buffer
,
501 IN BOOLEAN WriteToDevice
)
509 NdisMSetupDmaTransfer(Status
,
522 NdisMCompleteDmaTransfer(OUT PNDIS_STATUS Status
,
523 IN NDIS_HANDLE MiniportDmaHandle
,
524 IN PNDIS_BUFFER Buffer
,
527 IN BOOLEAN WriteToDevice
)
529 PNDIS_DMA_BLOCK DmaBlock
= MiniportDmaHandle
;
530 PDMA_ADAPTER AdapterObject
= (PDMA_ADAPTER
)DmaBlock
->SystemAdapterObject
;
532 NDIS_DbgPrint(MAX_TRACE
, ("called: Handle 0x%x, Buffer 0x%x, Offset 0x%x, Length 0x%x, WriteToDevice 0x%x\n",
533 MiniportDmaHandle
, Buffer
, Offset
, Length
, WriteToDevice
));
535 if (!AdapterObject
->DmaOperations
->FlushAdapterBuffers(AdapterObject
,
537 DmaBlock
->MapRegisterBase
,
538 (PUCHAR
)MmGetMdlVirtualAddress(Buffer
) + Offset
,
542 NDIS_DbgPrint(MIN_TRACE
, ("FlushAdapterBuffers failed\n"));
543 *Status
= NDIS_STATUS_FAILURE
;
547 AdapterObject
->DmaOperations
->FreeAdapterChannel(AdapterObject
);
549 NDIS_DbgPrint(MAX_TRACE
, ("returning success\n"));
550 *Status
= NDIS_STATUS_SUCCESS
;
558 NdisCompleteDmaTransfer(OUT PNDIS_STATUS Status
,
559 IN PNDIS_HANDLE NdisDmaHandle
,
560 IN PNDIS_BUFFER Buffer
,
563 IN BOOLEAN WriteToDevice
)
565 NdisMCompleteDmaTransfer(Status
,
578 NdisMStartBufferPhysicalMapping(
579 IN NDIS_HANDLE MiniportAdapterHandle
,
580 IN PNDIS_BUFFER Buffer
,
581 IN ULONG PhysicalMapRegister
,
582 IN BOOLEAN WriteToDevice
,
583 OUT PNDIS_PHYSICAL_ADDRESS_UNIT PhysicalAddressArray
,
586 * FUNCTION: Sets up map registers for a bus-master DMA transfer
588 * MiniportAdapterHandle: handle originally input to MiniportInitialize
589 * Buffer: data to be transferred
590 * PhysicalMapRegister: specifies the map register to set up
591 * WriteToDevice: if true, data is being written to the device; else it is being read
592 * PhysicalAddressArray: list of mapped ranges suitable for DMA with the device
593 * ArraySize: number of elements in PhysicalAddressArray
595 * - Must be called at IRQL <= DISPATCH_LEVEL
596 * - The basic idea: call IoMapTransfer() in a loop as many times as it takes
597 * in order to map all of the virtual memory to physical memoroy readable
599 * - The caller supplies storage for the physical address array.
602 PLOGICAL_ADAPTER Adapter
;
605 PHYSICAL_ADDRESS ReturnedAddress
;
608 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL
);
609 ASSERT(MiniportAdapterHandle
&& Buffer
&& PhysicalAddressArray
&& ArraySize
);
611 Adapter
= (PLOGICAL_ADAPTER
)MiniportAdapterHandle
;
612 CurrentVa
= MmGetMdlVirtualAddress(Buffer
);
613 TotalLength
= MmGetMdlByteCount(Buffer
);
617 ULONG Length
= TotalLength
;
619 ReturnedAddress
= Adapter
->NdisMiniportBlock
.SystemAdapterObject
->DmaOperations
->MapTransfer(
620 Adapter
->NdisMiniportBlock
.SystemAdapterObject
, Buffer
,
621 Adapter
->NdisMiniportBlock
.MapRegisters
[PhysicalMapRegister
].MapRegister
,
622 CurrentVa
, &Length
, WriteToDevice
);
624 Adapter
->NdisMiniportBlock
.MapRegisters
[PhysicalMapRegister
].WriteToDevice
= WriteToDevice
;
626 PhysicalAddressArray
[LoopCount
].PhysicalAddress
= ReturnedAddress
;
627 PhysicalAddressArray
[LoopCount
].Length
= Length
;
629 TotalLength
-= Length
;
630 CurrentVa
= (PVOID
)((ULONG_PTR
)CurrentVa
+ Length
);
635 *ArraySize
= LoopCount
;
644 NdisMCompleteBufferPhysicalMapping(
645 IN NDIS_HANDLE MiniportAdapterHandle
,
646 IN PNDIS_BUFFER Buffer
,
647 IN ULONG PhysicalMapRegister
)
649 * FUNCTION: Complete dma action started by NdisMStartBufferPhysicalMapping
651 * - MiniportAdapterHandle: handle originally input to MiniportInitialize
652 * - Buffer: NDIS_BUFFER to complete the mapping on
653 * - PhyscialMapRegister: the chosen map register
655 * - May be called at IRQL <= DISPATCH_LEVEL
658 PLOGICAL_ADAPTER Adapter
;
662 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL
);
663 ASSERT(MiniportAdapterHandle
&& Buffer
);
665 Adapter
= (PLOGICAL_ADAPTER
)MiniportAdapterHandle
;
666 CurrentVa
= MmGetMdlVirtualAddress(Buffer
);
667 Length
= MmGetMdlByteCount(Buffer
);
669 Adapter
->NdisMiniportBlock
.SystemAdapterObject
->DmaOperations
->FlushAdapterBuffers(
670 Adapter
->NdisMiniportBlock
.SystemAdapterObject
, Buffer
,
671 Adapter
->NdisMiniportBlock
.MapRegisters
[PhysicalMapRegister
].MapRegister
,
673 Adapter
->NdisMiniportBlock
.MapRegisters
[PhysicalMapRegister
].WriteToDevice
);
682 NdisMDeregisterDmaChannel(
683 IN NDIS_HANDLE MiniportDmaHandle
)
685 PNDIS_DMA_BLOCK DmaBlock
= MiniportDmaHandle
;
686 PDMA_ADAPTER AdapterObject
= (PDMA_ADAPTER
)DmaBlock
->SystemAdapterObject
;
688 if (AdapterObject
== ((PLOGICAL_ADAPTER
)DmaBlock
->Miniport
)->NdisMiniportBlock
.SystemAdapterObject
)
689 ((PLOGICAL_ADAPTER
)DmaBlock
->Miniport
)->NdisMiniportBlock
.SystemAdapterObject
= NULL
;
691 AdapterObject
->DmaOperations
->PutDmaAdapter(AdapterObject
);
693 ExFreePool(DmaBlock
);
702 NdisMDeregisterInterrupt(
703 IN PNDIS_MINIPORT_INTERRUPT Interrupt
)
705 * FUNCTION: Releases an interrupt vector
707 * Interrupt = Pointer to interrupt object
710 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
711 IoDisconnectInterrupt(Interrupt
->InterruptObject
);
712 Interrupt
->Miniport
->RegisteredInterrupts
--;
714 if (Interrupt
->Miniport
->Interrupt
== Interrupt
)
715 Interrupt
->Miniport
->Interrupt
= NULL
;
724 NdisMFreeMapRegisters(
725 IN NDIS_HANDLE MiniportAdapterHandle
)
727 * FUNCTION: Free previously allocated map registers
729 * MiniportAdapterHandle: Handle originally passed in to MiniportInitialize
734 PLOGICAL_ADAPTER Adapter
= (PLOGICAL_ADAPTER
)MiniportAdapterHandle
;
735 PDMA_ADAPTER AdapterObject
;
736 UINT MapRegistersPerBaseRegister
;
739 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
743 /* only bus masters may call this routine */
744 if(!(Adapter
->NdisMiniportBlock
.Flags
& NDIS_ATTRIBUTE_BUS_MASTER
) ||
745 Adapter
->NdisMiniportBlock
.SystemAdapterObject
== NULL
) {
746 NDIS_DbgPrint(MIN_TRACE
, ("Not bus master or bad adapter object\n"));
750 MapRegistersPerBaseRegister
= ((Adapter
->NdisMiniportBlock
.MaximumPhysicalMapping
- 2) / PAGE_SIZE
) + 2;
752 AdapterObject
= Adapter
->NdisMiniportBlock
.SystemAdapterObject
;
754 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
756 for(i
= 0; i
< Adapter
->NdisMiniportBlock
.BaseMapRegistersNeeded
; i
++)
758 AdapterObject
->DmaOperations
->FreeMapRegisters(
759 Adapter
->NdisMiniportBlock
.SystemAdapterObject
,
760 Adapter
->NdisMiniportBlock
.MapRegisters
[i
].MapRegister
,
761 MapRegistersPerBaseRegister
);
764 KeLowerIrql(OldIrql
);
766 AdapterObject
->DmaOperations
->PutDmaAdapter(AdapterObject
);
767 Adapter
->NdisMiniportBlock
.SystemAdapterObject
= NULL
;
769 ExFreePool(Adapter
->NdisMiniportBlock
.MapRegisters
);
779 OUT PVOID
*VirtualAddress
,
780 IN NDIS_HANDLE MiniportAdapterHandle
,
781 IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
,
784 * FUNCTION: Maps a bus-relative address to a system-wide virtual address
786 * VirtualAddress: receives virtual address of mapping
787 * MiniportAdapterHandle: Handle originally input to MiniportInitialize
788 * PhysicalAddress: bus-relative address to map
789 * Length: Number of bytes to map
791 * NDIS_STATUS_SUCCESS: the operation completed successfully
792 * NDIS_STATUS_RESOURCE_CONFLICT: the physical address range is already claimed
793 * NDIS_STATUS_RESOURCES: insufficient resources to complete the mapping
794 * NDIS_STATUS_FAILURE: a general failure has occured
796 * - Must be called at IRQL = PASSIVE_LEVEL
799 PLOGICAL_ADAPTER Adapter
= MiniportAdapterHandle
;
800 ULONG AddressSpace
= 0; /* Memory Space */
801 NDIS_PHYSICAL_ADDRESS TranslatedAddress
;
804 ASSERT(VirtualAddress
&& MiniportAdapterHandle
);
806 NDIS_DbgPrint(MAX_TRACE
, ("Called\n"));
808 if(!HalTranslateBusAddress(Adapter
->NdisMiniportBlock
.BusType
, Adapter
->NdisMiniportBlock
.BusNumber
,
809 PhysicalAddress
, &AddressSpace
, &TranslatedAddress
))
811 NDIS_DbgPrint(MIN_TRACE
, ("Unable to translate address\n"));
812 return NDIS_STATUS_RESOURCES
;
815 *VirtualAddress
= MmMapIoSpace(TranslatedAddress
, Length
, MmNonCached
);
817 if(!*VirtualAddress
) {
818 NDIS_DbgPrint(MIN_TRACE
, ("MmMapIoSpace failed\n"));
819 return NDIS_STATUS_RESOURCES
;
822 return NDIS_STATUS_SUCCESS
;
832 IN NDIS_HANDLE MiniportDmaHandle
)
834 /* NOTE: Unlike NdisMGetDmaAlignment() below, this is a handle to the DMA block */
835 PNDIS_DMA_BLOCK DmaBlock
= MiniportDmaHandle
;
836 PDMA_ADAPTER AdapterObject
= (PDMA_ADAPTER
)DmaBlock
->SystemAdapterObject
;
838 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
840 return AdapterObject
->DmaOperations
->ReadDmaCounter(AdapterObject
);
849 NdisMGetDmaAlignment(
850 IN NDIS_HANDLE MiniportAdapterHandle
)
852 /* NOTE: Unlike NdisMReadDmaCounter() above, this is a handle to the NDIS miniport block */
853 PLOGICAL_ADAPTER Adapter
= MiniportAdapterHandle
;
854 PDMA_ADAPTER AdapterObject
= (PDMA_ADAPTER
)Adapter
->NdisMiniportBlock
.SystemAdapterObject
;
856 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
858 return AdapterObject
->DmaOperations
->GetDmaAlignment(AdapterObject
);
867 NdisMRegisterDmaChannel(
868 OUT PNDIS_HANDLE MiniportDmaHandle
,
869 IN NDIS_HANDLE MiniportAdapterHandle
,
871 IN BOOLEAN Dma32BitAddresses
,
872 IN PNDIS_DMA_DESCRIPTION DmaDescription
,
873 IN ULONG MaximumLength
)
875 PLOGICAL_ADAPTER Adapter
= (PLOGICAL_ADAPTER
)MiniportAdapterHandle
;
876 DEVICE_DESCRIPTION DeviceDesc
;
878 PNDIS_DMA_BLOCK DmaBlock
;
880 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
882 RtlZeroMemory(&DeviceDesc
, sizeof(DEVICE_DESCRIPTION
));
884 DeviceDesc
.Version
= DEVICE_DESCRIPTION_VERSION
;
885 DeviceDesc
.Master
= (Adapter
->NdisMiniportBlock
.Flags
& NDIS_ATTRIBUTE_BUS_MASTER
);
886 DeviceDesc
.ScatterGather
= FALSE
;
887 DeviceDesc
.DemandMode
= DmaDescription
->DemandMode
;
888 DeviceDesc
.AutoInitialize
= DmaDescription
->AutoInitialize
;
889 DeviceDesc
.Dma32BitAddresses
= Dma32BitAddresses
;
890 DeviceDesc
.Dma64BitAddresses
= FALSE
;
891 DeviceDesc
.BusNumber
= Adapter
->NdisMiniportBlock
.BusNumber
;
892 DeviceDesc
.DmaChannel
= DmaDescription
->DmaChannel
;
893 DeviceDesc
.InterfaceType
= Adapter
->NdisMiniportBlock
.BusType
;
894 DeviceDesc
.DmaWidth
= DmaDescription
->DmaWidth
;
895 DeviceDesc
.DmaSpeed
= DmaDescription
->DmaSpeed
;
896 DeviceDesc
.MaximumLength
= MaximumLength
;
899 DmaBlock
= ExAllocatePool(NonPagedPool
, sizeof(NDIS_DMA_BLOCK
));
901 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources\n"));
902 return NDIS_STATUS_RESOURCES
;
905 DmaBlock
->SystemAdapterObject
= (PVOID
)IoGetDmaAdapter(Adapter
->NdisMiniportBlock
.PhysicalDeviceObject
, &DeviceDesc
, &MapRegisters
);
907 if (!DmaBlock
->SystemAdapterObject
) {
908 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources\n"));
909 ExFreePool(DmaBlock
);
910 return NDIS_STATUS_RESOURCES
;
913 Adapter
->NdisMiniportBlock
.SystemAdapterObject
= (PDMA_ADAPTER
)DmaBlock
->SystemAdapterObject
;
915 KeInitializeEvent(&DmaBlock
->AllocationEvent
, NotificationEvent
, FALSE
);
917 DmaBlock
->Miniport
= Adapter
;
919 *MiniportDmaHandle
= DmaBlock
;
921 return NDIS_STATUS_SUCCESS
;
929 NdisAllocateDmaChannel(OUT PNDIS_STATUS Status
,
930 OUT PNDIS_HANDLE NdisDmaHandle
,
931 IN NDIS_HANDLE NdisAdapterHandle
,
932 IN PNDIS_DMA_DESCRIPTION DmaDescription
,
933 IN ULONG MaximumLength
)
935 *Status
= NdisMRegisterDmaChannel(NdisDmaHandle
,
947 NdisMRegisterInterrupt(
948 OUT PNDIS_MINIPORT_INTERRUPT Interrupt
,
949 IN NDIS_HANDLE MiniportAdapterHandle
,
950 IN UINT InterruptVector
,
951 IN UINT InterruptLevel
,
952 IN BOOLEAN RequestIsr
,
953 IN BOOLEAN SharedInterrupt
,
954 IN NDIS_INTERRUPT_MODE InterruptMode
)
956 * FUNCTION: Claims access to an interrupt vector
958 * Interrupt = Address of interrupt object to initialize
959 * MiniportAdapterHandle = Specifies handle input to MiniportInitialize
960 * InterruptVector = Specifies bus-relative vector to register
961 * InterruptLevel = Specifies bus-relative DIRQL vector for interrupt
962 * RequestIsr = TRUE if MiniportISR should always be called
963 * SharedInterrupt = TRUE if other devices may use the same interrupt
964 * InterruptMode = Specifies type of interrupt
966 * Status of operation
973 PLOGICAL_ADAPTER Adapter
= (PLOGICAL_ADAPTER
)MiniportAdapterHandle
;
975 NDIS_DbgPrint(MAX_TRACE
, ("Called. InterruptVector (0x%X) InterruptLevel (0x%X) "
976 "SharedInterrupt (%d) InterruptMode (0x%X)\n",
977 InterruptVector
, InterruptLevel
, SharedInterrupt
, InterruptMode
));
979 RtlZeroMemory(Interrupt
, sizeof(NDIS_MINIPORT_INTERRUPT
));
981 KeInitializeSpinLock(&Interrupt
->DpcCountLock
);
983 KeInitializeDpc(&Interrupt
->InterruptDpc
, HandleDeferredProcessing
, Adapter
);
985 KeInitializeEvent(&Interrupt
->DpcsCompletedEvent
, NotificationEvent
, FALSE
);
987 Interrupt
->SharedInterrupt
= SharedInterrupt
;
988 Interrupt
->IsrRequested
= RequestIsr
;
989 Interrupt
->Miniport
= &Adapter
->NdisMiniportBlock
;
991 MappedIRQ
= HalGetInterruptVector(Adapter
->NdisMiniportBlock
.BusType
, Adapter
->NdisMiniportBlock
.BusNumber
,
992 InterruptLevel
, InterruptVector
, &DIrql
,
995 NDIS_DbgPrint(MAX_TRACE
, ("Connecting to interrupt vector (0x%X) Affinity (0x%X).\n", MappedIRQ
, Affinity
));
997 Status
= IoConnectInterrupt(&Interrupt
->InterruptObject
, ServiceRoutine
, Interrupt
, &Interrupt
->DpcCountLock
, MappedIRQ
,
998 DIrql
, DIrql
, InterruptMode
, SharedInterrupt
, Affinity
, FALSE
);
1000 NDIS_DbgPrint(MAX_TRACE
, ("Leaving. Status (0x%X).\n", Status
));
1002 if (NT_SUCCESS(Status
)) {
1003 Adapter
->NdisMiniportBlock
.Interrupt
= Interrupt
;
1004 Adapter
->NdisMiniportBlock
.RegisteredInterrupts
++;
1005 return NDIS_STATUS_SUCCESS
;
1008 if (Status
== STATUS_INSUFFICIENT_RESOURCES
)
1010 /* FIXME: Log error */
1011 NDIS_DbgPrint(MIN_TRACE
, ("Resource conflict!\n"));
1012 return NDIS_STATUS_RESOURCE_CONFLICT
;
1015 NDIS_DbgPrint(MIN_TRACE
, ("Function failed. Status (0x%X).\n", Status
));
1016 return NDIS_STATUS_FAILURE
;
1025 NdisMRegisterIoPortRange(
1026 OUT PVOID
*PortOffset
,
1027 IN NDIS_HANDLE MiniportAdapterHandle
,
1028 IN UINT InitialPort
,
1029 IN UINT NumberOfPorts
)
1031 * FUNCTION: Sets up driver access to device I/O ports
1033 * PortOffset = Address of buffer to place mapped base port address
1034 * MiniportAdapterHandle = Specifies handle input to MiniportInitialize
1035 * InitialPort = Bus-relative base port address of a range to be mapped
1036 * NumberOfPorts = Specifies number of ports to be mapped
1038 * Status of operation
1041 PHYSICAL_ADDRESS PortAddress
, TranslatedAddress
;
1042 PLOGICAL_ADAPTER Adapter
= (PLOGICAL_ADAPTER
)MiniportAdapterHandle
;
1043 ULONG AddressSpace
= 1; /* FIXME The HAL handles this wrong atm */
1047 NDIS_DbgPrint(MAX_TRACE
, ("Called - InitialPort 0x%x, NumberOfPorts 0x%x\n", InitialPort
, NumberOfPorts
));
1049 memset(&PortAddress
, 0, sizeof(PortAddress
));
1052 * FIXME: NDIS 5+ completely ignores the InitialPort parameter, but
1053 * we don't have a way to get the I/O base address yet (see
1054 * NDIS_MINIPORT_BLOCK->AllocatedResources and
1055 * NDIS_MINIPORT_BLOCK->AllocatedResourcesTranslated).
1058 PortAddress
= RtlConvertUlongToLargeInteger(InitialPort
);
1062 NDIS_DbgPrint(MAX_TRACE
, ("Translating address 0x%x 0x%x\n", PortAddress
.u
.HighPart
, PortAddress
.u
.LowPart
));
1064 if(!HalTranslateBusAddress(Adapter
->NdisMiniportBlock
.BusType
, Adapter
->NdisMiniportBlock
.BusNumber
,
1065 PortAddress
, &AddressSpace
, &TranslatedAddress
))
1067 NDIS_DbgPrint(MIN_TRACE
, ("Unable to translate address\n"));
1068 return NDIS_STATUS_RESOURCES
;
1071 NDIS_DbgPrint(MAX_TRACE
, ("Hal returned AddressSpace=0x%x TranslatedAddress=0x%x 0x%x\n",
1072 AddressSpace
, TranslatedAddress
.u
.HighPart
, TranslatedAddress
.u
.LowPart
));
1076 ASSERT(TranslatedAddress
.u
.HighPart
== 0);
1077 *PortOffset
= (PVOID
)(ULONG_PTR
)TranslatedAddress
.QuadPart
;
1078 NDIS_DbgPrint(MAX_TRACE
, ("Returning 0x%x\n", *PortOffset
));
1079 return NDIS_STATUS_SUCCESS
;
1082 NDIS_DbgPrint(MAX_TRACE
, ("calling MmMapIoSpace\n"));
1084 *PortOffset
= MmMapIoSpace(TranslatedAddress
, NumberOfPorts
, MmNonCached
);
1085 NDIS_DbgPrint(MAX_TRACE
, ("Returning 0x%x for port range\n", *PortOffset
));
1088 NDIS_DbgPrint(MIN_TRACE
, ("MmMapIoSpace failed\n"));
1089 return NDIS_STATUS_RESOURCES
;
1092 return NDIS_STATUS_SUCCESS
;
1100 NdisMDeregisterIoPortRange(IN NDIS_HANDLE MiniportAdapterHandle
,
1101 IN UINT InitialPort
,
1102 IN UINT NumberOfPorts
,
1103 IN PVOID PortOffset
)
1105 * FUNCTION: Releases a register mapping to I/O ports
1107 * MiniportAdapterHandle = Specifies handle input to MiniportInitialize
1108 * InitialPort = Bus-relative base port address of a range to be mapped
1109 * NumberOfPorts = Specifies number of ports to be mapped
1110 * PortOffset = Pointer to mapped base port address
1113 PLOGICAL_ADAPTER Adapter
= (PLOGICAL_ADAPTER
)MiniportAdapterHandle
;
1114 PHYSICAL_ADDRESS PortAddress
= RtlConvertUlongToLargeInteger(InitialPort
);
1115 PHYSICAL_ADDRESS TranslatedAddress
;
1116 ULONG AddressSpace
= 1;
1118 NDIS_DbgPrint(MAX_TRACE
, ("Called - InitialPort 0x%x, NumberOfPorts 0x%x, Port Offset 0x%x\n", InitialPort
, NumberOfPorts
, PortOffset
));
1120 /* Translate the initial port again to find the address space of the translated address */
1121 if(!HalTranslateBusAddress(Adapter
->NdisMiniportBlock
.BusType
, Adapter
->NdisMiniportBlock
.BusNumber
,
1122 PortAddress
, &AddressSpace
, &TranslatedAddress
))
1124 NDIS_DbgPrint(MIN_TRACE
, ("Unable to translate address\n"));
1128 /* Make sure we got the same translation as last time */
1129 ASSERT(TranslatedAddress
.QuadPart
== (ULONG_PTR
)PortOffset
);
1131 /* Check if we're in memory space */
1134 NDIS_DbgPrint(MAX_TRACE
, ("Calling MmUnmapIoSpace\n"));
1136 /* Unmap the memory */
1137 MmUnmapIoSpace(PortOffset
, NumberOfPorts
);
1147 IN NDIS_HANDLE MiniportAdapterHandle
,
1148 IN PVOID VirtualAddress
,
1151 * FUNCTION: Un-maps space previously mapped with NdisMMapIoSpace
1153 * MiniportAdapterHandle: handle originally passed into MiniportInitialize
1154 * VirtualAddress: Address to un-map
1155 * Length: length of the mapped memory space
1157 * - Must be called at IRQL = PASSIVE_LEVEL
1158 * - Must only be called from MiniportInitialize and MiniportHalt
1159 * - See also: NdisMMapIoSpace
1161 * - Depends on MmUnmapIoSpace to Do The Right Thing in all cases
1166 ASSERT(MiniportAdapterHandle
);
1168 MmUnmapIoSpace(VirtualAddress
, Length
);
1176 NdisMInitializeScatterGatherDma(
1177 IN NDIS_HANDLE MiniportAdapterHandle
,
1178 IN BOOLEAN Dma64BitAddresses
,
1179 IN ULONG MaximumPhysicalMapping
)
1187 PLOGICAL_ADAPTER Adapter
= (PLOGICAL_ADAPTER
)MiniportAdapterHandle
;
1189 DEVICE_DESCRIPTION DeviceDesc
;
1191 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
1193 if (!(Adapter
->NdisMiniportBlock
.Flags
& NDIS_ATTRIBUTE_BUS_MASTER
)) {
1194 NDIS_DbgPrint(MIN_TRACE
, ("Not a bus master\n"));
1195 return NDIS_STATUS_NOT_SUPPORTED
;
1198 RtlZeroMemory(&DeviceDesc
, sizeof(DEVICE_DESCRIPTION
));
1200 DeviceDesc
.Version
= DEVICE_DESCRIPTION_VERSION
;
1201 DeviceDesc
.Master
= TRUE
;
1202 DeviceDesc
.ScatterGather
= TRUE
;
1203 DeviceDesc
.Dma32BitAddresses
= !Dma64BitAddresses
;
1204 DeviceDesc
.Dma64BitAddresses
= Dma64BitAddresses
;
1205 DeviceDesc
.BusNumber
= Adapter
->NdisMiniportBlock
.BusNumber
;
1206 DeviceDesc
.InterfaceType
= Adapter
->NdisMiniportBlock
.BusType
;
1207 DeviceDesc
.MaximumLength
= MaximumPhysicalMapping
;
1209 Adapter
->NdisMiniportBlock
.SystemAdapterObject
=
1210 IoGetDmaAdapter(Adapter
->NdisMiniportBlock
.PhysicalDeviceObject
, &DeviceDesc
, &MapRegisters
);
1212 if (!Adapter
->NdisMiniportBlock
.SystemAdapterObject
)
1213 return NDIS_STATUS_RESOURCES
;
1215 /* FIXME: Right now we just use this as a place holder */
1216 Adapter
->NdisMiniportBlock
.ScatterGatherListSize
= 1;
1218 return NDIS_STATUS_SUCCESS
;
1228 OUT PNDIS_STATUS Status
,
1229 OUT PVOID
*VirtualAddress
,
1230 IN NDIS_HANDLE NdisAdapterHandle
,
1231 IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
,
1240 *Status
= NdisMMapIoSpace(VirtualAddress
,
1253 IN PNDIS_HANDLE NdisDmaHandle
)
1261 NdisMDeregisterDmaChannel(NdisDmaHandle
);