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
16 VOID NTAPI
HandleDeferredProcessing(
18 IN PVOID DeferredContext
,
19 IN PVOID SystemArgument1
,
20 IN PVOID SystemArgument2
)
22 * FUNCTION: Deferred interrupt processing routine
24 * Dpc = Pointer to DPC object
25 * DeferredContext = Pointer to context information (LOGICAL_ADAPTER)
26 * SystemArgument1 = Unused
27 * SystemArgument2 = Unused
30 PLOGICAL_ADAPTER Adapter
= GET_LOGICAL_ADAPTER(DeferredContext
);
32 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
34 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
36 /* Call the deferred interrupt service handler for this adapter */
37 (*Adapter
->NdisMiniportBlock
.DriverHandle
->MiniportCharacteristics
.HandleInterruptHandler
)(
38 Adapter
->NdisMiniportBlock
.MiniportAdapterContext
);
40 /* re-enable the interrupt */
41 NDIS_DbgPrint(MAX_TRACE
, ("re-enabling the interrupt\n"));
42 if(Adapter
->NdisMiniportBlock
.DriverHandle
->MiniportCharacteristics
.EnableInterruptHandler
)
43 (*Adapter
->NdisMiniportBlock
.DriverHandle
->MiniportCharacteristics
.EnableInterruptHandler
)(
44 Adapter
->NdisMiniportBlock
.MiniportAdapterContext
);
46 NDIS_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
49 BOOLEAN NTAPI
ServiceRoutine(
50 IN PKINTERRUPT Interrupt
,
51 IN PVOID ServiceContext
)
53 * FUNCTION: Interrupt service routine
55 * Interrupt = Pointer to interrupt object
56 * ServiceContext = Pointer to context information (PNDIS_MINIPORT_INTERRUPT)
58 * TRUE if a miniport controlled device generated the interrupt
61 BOOLEAN InterruptRecognized
= FALSE
;
62 BOOLEAN QueueMiniportHandleInterrupt
= FALSE
;
63 PNDIS_MINIPORT_INTERRUPT NdisInterrupt
= ServiceContext
;
64 PNDIS_MINIPORT_BLOCK NdisMiniportBlock
= NdisInterrupt
->Miniport
;
67 NDIS_DbgPrint(MAX_TRACE
, ("Called. Interrupt (0x%X)\n", NdisInterrupt
));
69 /* Certain behavior differs if MiniportInitialize is executing when the interrupt is generated */
70 Initializing
= (NdisMiniportBlock
->PnPDeviceState
!= NdisPnPDeviceStarted
);
71 NDIS_DbgPrint(MAX_TRACE
, ("MiniportInitialize executing: %s\n", (Initializing
? "yes" : "no")));
73 /* MiniportISR is always called for interrupts during MiniportInitialize */
74 if ((Initializing
) || (NdisInterrupt
->IsrRequested
) || (NdisInterrupt
->SharedInterrupt
)) {
75 NDIS_DbgPrint(MAX_TRACE
, ("Calling MiniportISR\n"));
76 (*NdisMiniportBlock
->DriverHandle
->MiniportCharacteristics
.ISRHandler
)(
78 &QueueMiniportHandleInterrupt
,
79 NdisMiniportBlock
->MiniportAdapterContext
);
81 } else if (NdisMiniportBlock
->DriverHandle
->MiniportCharacteristics
.DisableInterruptHandler
) {
82 NDIS_DbgPrint(MAX_TRACE
, ("Calling MiniportDisableInterrupt\n"));
83 (*NdisMiniportBlock
->DriverHandle
->MiniportCharacteristics
.DisableInterruptHandler
)(
84 NdisMiniportBlock
->MiniportAdapterContext
);
85 QueueMiniportHandleInterrupt
= TRUE
;
86 InterruptRecognized
= TRUE
;
89 /* TODO: Figure out if we should call this or not if Initializing is true. It appears
90 * that calling it fixes some NICs, but documentation is contradictory on it. */
91 if (QueueMiniportHandleInterrupt
)
93 NDIS_DbgPrint(MAX_TRACE
, ("Queuing DPC.\n"));
94 KeInsertQueueDpc(&NdisInterrupt
->InterruptDpc
, NULL
, NULL
);
97 NDIS_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
99 return InterruptRecognized
;
107 NdisImmediateReadPortUchar(
108 IN NDIS_HANDLE WrapperConfigurationContext
,
112 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
113 *Data
= READ_PORT_UCHAR(UlongToPtr(Port
)); // FIXME: What to do with WrapperConfigurationContext?
121 NdisImmediateReadPortUlong(
122 IN NDIS_HANDLE WrapperConfigurationContext
,
126 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
127 *Data
= READ_PORT_ULONG(UlongToPtr(Port
)); // FIXME: What to do with WrapperConfigurationContext?
135 NdisImmediateReadPortUshort(
136 IN NDIS_HANDLE WrapperConfigurationContext
,
140 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
141 *Data
= READ_PORT_USHORT(UlongToPtr(Port
)); // FIXME: What to do with WrapperConfigurationContext?
149 NdisImmediateWritePortUchar(
150 IN NDIS_HANDLE WrapperConfigurationContext
,
154 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
155 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?
177 NdisImmediateWritePortUshort(
178 IN NDIS_HANDLE WrapperConfigurationContext
,
182 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
183 WRITE_PORT_USHORT(UlongToPtr(Port
), Data
); // FIXME: What to do with WrapperConfigurationContext?
186 IO_ALLOCATION_ACTION NTAPI
NdisSubordinateMapRegisterCallback (
187 IN PDEVICE_OBJECT DeviceObject
,
189 IN PVOID MapRegisterBase
,
192 * FUNCTION: Called back during reservation of map registers
194 * DeviceObject: Device object of the deivce setting up DMA
195 * Irp: Reserved; must be ignored
196 * MapRegisterBase: Map registers assigned for transfer
197 * Context: LOGICAL_ADAPTER object of the requesting miniport
199 * - Called at IRQL = DISPATCH_LEVEL
202 PNDIS_DMA_BLOCK DmaBlock
= Context
;
204 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
206 DmaBlock
->MapRegisterBase
= MapRegisterBase
;
208 NDIS_DbgPrint(MAX_TRACE
, ("setting event and leaving.\n"));
210 KeSetEvent(&DmaBlock
->AllocationEvent
, 0, FALSE
);
212 /* 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
;
252 NdisMAllocateMapRegisters(
253 IN NDIS_HANDLE MiniportAdapterHandle
,
255 IN NDIS_DMA_SIZE DmaSize
,
256 IN ULONG BaseMapRegistersNeeded
,
257 IN ULONG MaximumBufferSize
)
259 * FUNCTION: Allocate map registers for use in DMA transfers
261 * MiniportAdapterHandle: Passed in to MiniportInitialize
262 * DmaChannel: DMA channel to use
263 * DmaSize: bit width of DMA transfers
264 * BaseMapRegistersNeeded: number of base map registers requested
265 * MaximumBufferSize: largest single buffer transferred
267 * NDIS_STATUS_SUCCESS on success
268 * NDIS_STATUS_RESOURCES on failure
270 * - the win2k ddk and the nt4 ddk have conflicting prototypes for this.
271 * I'm implementing the 2k one.
272 * - do not confuse a "base map register" with a "map register" - they
273 * are different. Only NDIS seems to use the base concept. The idea
274 * is that a miniport supplies the number of base map registers it will
275 * need, which is equal to the number of DMA send buffers it manages.
276 * NDIS then allocates a number of map registers to go with each base
277 * map register, so that a driver just has to send the base map register
278 * number during dma operations and NDIS can find the group of real
279 * map registers that represent the transfer.
280 * - Because of the above sillyness, you can only specify a few base map
281 * registers at most. a 1514-byte packet is two map registers at 4k
283 * - NDIS limits the total number of allocated map registers to 64,
284 * which (in the case of the above example) limits the number of base
285 * map registers to 32.
288 DEVICE_DESCRIPTION Description
;
289 PDMA_ADAPTER AdapterObject
= 0;
290 UINT MapRegistersPerBaseRegister
= 0;
291 ULONG AvailableMapRegisters
;
293 PLOGICAL_ADAPTER Adapter
;
294 PDEVICE_OBJECT DeviceObject
= 0;
295 KEVENT AllocationEvent
;
298 NDIS_DbgPrint(MAX_TRACE
, ("called: Handle 0x%x, DmaChannel 0x%x, DmaSize 0x%x, BaseMapRegsNeeded: 0x%x, MaxBuffer: 0x%x.\n",
299 MiniportAdapterHandle
, DmaChannel
, DmaSize
, BaseMapRegistersNeeded
, MaximumBufferSize
));
301 memset(&Description
,0,sizeof(Description
));
303 Adapter
= (PLOGICAL_ADAPTER
)MiniportAdapterHandle
;
307 /* only bus masters may call this routine */
308 if(!(Adapter
->NdisMiniportBlock
.Flags
& NDIS_ATTRIBUTE_BUS_MASTER
)) {
309 NDIS_DbgPrint(MIN_TRACE
, ("Not a bus master\n"));
310 return NDIS_STATUS_NOT_SUPPORTED
;
313 DeviceObject
= Adapter
->NdisMiniportBlock
.DeviceObject
;
315 KeInitializeEvent(&AllocationEvent
, NotificationEvent
, FALSE
);
316 Adapter
->NdisMiniportBlock
.AllocationEvent
= &AllocationEvent
;
319 * map registers correlate to physical pages. ndis documents a
320 * maximum of 64 map registers that it will return.
321 * at 4k pages, a 1514-byte buffer can span not more than 2 pages.
323 * the number of registers required for a given physical mapping
324 * is (first register + last register + one per page size),
325 * given that physical mapping is > 2.
328 /* unhandled corner case: {1,2}-byte max buffer size */
329 ASSERT(MaximumBufferSize
> 2);
330 MapRegistersPerBaseRegister
= ((MaximumBufferSize
-2) / (2*PAGE_SIZE
)) + 2;
332 Description
.Version
= DEVICE_DESCRIPTION_VERSION
;
333 Description
.Master
= TRUE
; /* implied by calling this function */
334 Description
.ScatterGather
= TRUE
; /* XXX UNTRUE: All BM DMA are S/G (ms seems to do this) */
335 Description
.BusNumber
= Adapter
->NdisMiniportBlock
.BusNumber
;
336 Description
.InterfaceType
= Adapter
->NdisMiniportBlock
.BusType
;
337 Description
.DmaChannel
= DmaChannel
;
338 Description
.MaximumLength
= MaximumBufferSize
;
340 if(DmaSize
== NDIS_DMA_64BITS
)
341 Description
.Dma64BitAddresses
= TRUE
;
342 else if(DmaSize
== NDIS_DMA_32BITS
)
343 Description
.Dma32BitAddresses
= TRUE
;
345 AdapterObject
= IoGetDmaAdapter(
346 Adapter
->NdisMiniportBlock
.PhysicalDeviceObject
, &Description
, &AvailableMapRegisters
);
350 NDIS_DbgPrint(MIN_TRACE
, ("Unable to allocate an adapter object; bailing out\n"));
351 return NDIS_STATUS_RESOURCES
;
354 Adapter
->NdisMiniportBlock
.SystemAdapterObject
= AdapterObject
;
356 if(AvailableMapRegisters
< MapRegistersPerBaseRegister
)
358 NDIS_DbgPrint(MIN_TRACE
, ("Didn't get enough map registers from hal - requested 0x%x, got 0x%x\n",
359 MapRegistersPerBaseRegister
, AvailableMapRegisters
));
361 AdapterObject
->DmaOperations
->PutDmaAdapter(AdapterObject
);
362 Adapter
->NdisMiniportBlock
.SystemAdapterObject
= NULL
;
363 return NDIS_STATUS_RESOURCES
;
366 /* allocate & zero space in the miniport block for the registers */
367 Adapter
->NdisMiniportBlock
.MapRegisters
= ExAllocatePool(NonPagedPool
, BaseMapRegistersNeeded
* sizeof(MAP_REGISTER_ENTRY
));
368 if(!Adapter
->NdisMiniportBlock
.MapRegisters
)
370 NDIS_DbgPrint(MIN_TRACE
, ("insufficient resources.\n"));
371 AdapterObject
->DmaOperations
->PutDmaAdapter(AdapterObject
);
372 Adapter
->NdisMiniportBlock
.SystemAdapterObject
= NULL
;
373 return NDIS_STATUS_RESOURCES
;
376 memset(Adapter
->NdisMiniportBlock
.MapRegisters
, 0, BaseMapRegistersNeeded
* sizeof(MAP_REGISTER_ENTRY
));
377 Adapter
->NdisMiniportBlock
.BaseMapRegistersNeeded
= (USHORT
)BaseMapRegistersNeeded
;
379 while(BaseMapRegistersNeeded
)
381 NDIS_DbgPrint(MAX_TRACE
, ("iterating, basemapregistersneeded = %d\n", BaseMapRegistersNeeded
));
383 BaseMapRegistersNeeded
--;
384 Adapter
->NdisMiniportBlock
.CurrentMapRegister
= (USHORT
)BaseMapRegistersNeeded
;
385 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
387 NtStatus
= AdapterObject
->DmaOperations
->AllocateAdapterChannel(
388 AdapterObject
, DeviceObject
, MapRegistersPerBaseRegister
,
389 NdisBusMasterMapRegisterCallback
, Adapter
);
391 KeLowerIrql(OldIrql
);
393 if(!NT_SUCCESS(NtStatus
))
395 NDIS_DbgPrint(MIN_TRACE
, ("IoAllocateAdapterChannel failed: 0x%x\n", NtStatus
));
396 ExFreePool(Adapter
->NdisMiniportBlock
.MapRegisters
);
397 AdapterObject
->DmaOperations
->PutDmaAdapter(AdapterObject
);
398 Adapter
->NdisMiniportBlock
.CurrentMapRegister
= Adapter
->NdisMiniportBlock
.BaseMapRegistersNeeded
= 0;
399 Adapter
->NdisMiniportBlock
.SystemAdapterObject
= NULL
;
400 return NDIS_STATUS_RESOURCES
;
403 NDIS_DbgPrint(MAX_TRACE
, ("waiting on event\n"));
405 NtStatus
= KeWaitForSingleObject(&AllocationEvent
, Executive
, KernelMode
, FALSE
, 0);
407 if(!NT_SUCCESS(NtStatus
))
409 NDIS_DbgPrint(MIN_TRACE
, ("KeWaitForSingleObject failed: 0x%x\n", NtStatus
));
410 ExFreePool(Adapter
->NdisMiniportBlock
.MapRegisters
);
411 AdapterObject
->DmaOperations
->PutDmaAdapter(AdapterObject
);
412 Adapter
->NdisMiniportBlock
.CurrentMapRegister
= Adapter
->NdisMiniportBlock
.BaseMapRegistersNeeded
= 0;
413 Adapter
->NdisMiniportBlock
.SystemAdapterObject
= NULL
;
414 return NDIS_STATUS_RESOURCES
;
417 NDIS_DbgPrint(MAX_TRACE
, ("resetting event\n"));
419 KeResetEvent(&AllocationEvent
);
422 NDIS_DbgPrint(MAX_TRACE
, ("returning success\n"));
423 return NDIS_STATUS_SUCCESS
;
432 NdisMSetupDmaTransfer(OUT PNDIS_STATUS Status
,
433 IN NDIS_HANDLE MiniportDmaHandle
,
434 IN PNDIS_BUFFER Buffer
,
437 IN BOOLEAN WriteToDevice
)
439 PNDIS_DMA_BLOCK DmaBlock
= MiniportDmaHandle
;
441 PLOGICAL_ADAPTER Adapter
;
443 PDMA_ADAPTER AdapterObject
;
444 ULONG MapRegistersNeeded
;
446 NDIS_DbgPrint(MAX_TRACE
, ("called: Handle 0x%x, Buffer 0x%x, Offset 0x%x, Length 0x%x, WriteToDevice 0x%x\n",
447 MiniportDmaHandle
, Buffer
, Offset
, Length
, WriteToDevice
));
449 Adapter
= (PLOGICAL_ADAPTER
)DmaBlock
->Miniport
;
450 AdapterObject
= (PDMA_ADAPTER
)DmaBlock
->SystemAdapterObject
;
452 MapRegistersNeeded
= (Length
+ (PAGE_SIZE
- 1)) / PAGE_SIZE
;
454 KeFlushIoBuffers(Buffer
, !WriteToDevice
, TRUE
);
456 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
458 NtStatus
= AdapterObject
->DmaOperations
->AllocateAdapterChannel(AdapterObject
,
459 Adapter
->NdisMiniportBlock
.PhysicalDeviceObject
,
461 NdisSubordinateMapRegisterCallback
, Adapter
);
463 KeLowerIrql(OldIrql
);
465 if(!NT_SUCCESS(NtStatus
))
467 NDIS_DbgPrint(MIN_TRACE
, ("AllocateAdapterChannel failed: 0x%x\n", NtStatus
));
468 AdapterObject
->DmaOperations
->FreeAdapterChannel(AdapterObject
);
469 *Status
= NDIS_STATUS_RESOURCES
;
473 NtStatus
= KeWaitForSingleObject(&DmaBlock
->AllocationEvent
, Executive
, KernelMode
, FALSE
, 0);
475 if(!NT_SUCCESS(NtStatus
))
477 NDIS_DbgPrint(MIN_TRACE
, ("KeWaitForSingleObject failed: 0x%x\n", NtStatus
));
478 AdapterObject
->DmaOperations
->FreeAdapterChannel(AdapterObject
);
479 *Status
= NDIS_STATUS_RESOURCES
;
483 /* We must throw away the return value of MapTransfer for a system DMA device */
484 AdapterObject
->DmaOperations
->MapTransfer(AdapterObject
, Buffer
,
485 DmaBlock
->MapRegisterBase
,
486 (PUCHAR
)MmGetMdlVirtualAddress(Buffer
) + Offset
, &Length
, WriteToDevice
);
488 NDIS_DbgPrint(MAX_TRACE
, ("returning success\n"));
489 *Status
= NDIS_STATUS_SUCCESS
;
497 NdisSetupDmaTransfer(OUT PNDIS_STATUS Status
,
498 IN PNDIS_HANDLE NdisDmaHandle
,
499 IN PNDIS_BUFFER Buffer
,
502 IN BOOLEAN WriteToDevice
)
510 NdisMSetupDmaTransfer(Status
,
523 NdisMCompleteDmaTransfer(OUT PNDIS_STATUS Status
,
524 IN NDIS_HANDLE MiniportDmaHandle
,
525 IN PNDIS_BUFFER Buffer
,
528 IN BOOLEAN WriteToDevice
)
530 PNDIS_DMA_BLOCK DmaBlock
= MiniportDmaHandle
;
531 PDMA_ADAPTER AdapterObject
= (PDMA_ADAPTER
)DmaBlock
->SystemAdapterObject
;
533 NDIS_DbgPrint(MAX_TRACE
, ("called: Handle 0x%x, Buffer 0x%x, Offset 0x%x, Length 0x%x, WriteToDevice 0x%x\n",
534 MiniportDmaHandle
, Buffer
, Offset
, Length
, WriteToDevice
));
536 if (!AdapterObject
->DmaOperations
->FlushAdapterBuffers(AdapterObject
,
538 DmaBlock
->MapRegisterBase
,
539 (PUCHAR
)MmGetMdlVirtualAddress(Buffer
) + Offset
,
543 NDIS_DbgPrint(MIN_TRACE
, ("FlushAdapterBuffers failed\n"));
544 *Status
= NDIS_STATUS_FAILURE
;
548 AdapterObject
->DmaOperations
->FreeAdapterChannel(AdapterObject
);
550 NDIS_DbgPrint(MAX_TRACE
, ("returning success\n"));
551 *Status
= NDIS_STATUS_SUCCESS
;
559 NdisCompleteDmaTransfer(OUT PNDIS_STATUS Status
,
560 IN PNDIS_HANDLE NdisDmaHandle
,
561 IN PNDIS_BUFFER Buffer
,
564 IN BOOLEAN WriteToDevice
)
566 NdisMCompleteDmaTransfer(Status
,
579 NdisMStartBufferPhysicalMapping(
580 IN NDIS_HANDLE MiniportAdapterHandle
,
581 IN PNDIS_BUFFER Buffer
,
582 IN ULONG PhysicalMapRegister
,
583 IN BOOLEAN WriteToDevice
,
584 OUT PNDIS_PHYSICAL_ADDRESS_UNIT PhysicalAddressArray
,
587 * FUNCTION: Sets up map registers for a bus-master DMA transfer
589 * MiniportAdapterHandle: handle originally input to MiniportInitialize
590 * Buffer: data to be transferred
591 * PhysicalMapRegister: specifies the map register to set up
592 * WriteToDevice: if true, data is being written to the device; else it is being read
593 * PhysicalAddressArray: list of mapped ranges suitable for DMA with the device
594 * ArraySize: number of elements in PhysicalAddressArray
596 * - Must be called at IRQL <= DISPATCH_LEVEL
597 * - The basic idea: call IoMapTransfer() in a loop as many times as it takes
598 * in order to map all of the virtual memory to physical memoroy readable
600 * - The caller supplies storage for the physical address array.
603 PLOGICAL_ADAPTER Adapter
;
606 PHYSICAL_ADDRESS ReturnedAddress
;
609 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL
);
610 ASSERT(MiniportAdapterHandle
&& Buffer
&& PhysicalAddressArray
&& ArraySize
);
612 Adapter
= (PLOGICAL_ADAPTER
)MiniportAdapterHandle
;
613 CurrentVa
= MmGetMdlVirtualAddress(Buffer
);
614 TotalLength
= MmGetMdlByteCount(Buffer
);
618 ULONG Length
= TotalLength
;
620 ReturnedAddress
= Adapter
->NdisMiniportBlock
.SystemAdapterObject
->DmaOperations
->MapTransfer(
621 Adapter
->NdisMiniportBlock
.SystemAdapterObject
, Buffer
,
622 Adapter
->NdisMiniportBlock
.MapRegisters
[PhysicalMapRegister
].MapRegister
,
623 CurrentVa
, &Length
, WriteToDevice
);
625 Adapter
->NdisMiniportBlock
.MapRegisters
[PhysicalMapRegister
].WriteToDevice
= WriteToDevice
;
627 PhysicalAddressArray
[LoopCount
].PhysicalAddress
= ReturnedAddress
;
628 PhysicalAddressArray
[LoopCount
].Length
= Length
;
630 TotalLength
-= Length
;
631 CurrentVa
= (PVOID
)((ULONG_PTR
)CurrentVa
+ Length
);
636 *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
);
681 NdisMDeregisterDmaChannel(
682 IN NDIS_HANDLE MiniportDmaHandle
)
684 PNDIS_DMA_BLOCK DmaBlock
= MiniportDmaHandle
;
685 PDMA_ADAPTER AdapterObject
= (PDMA_ADAPTER
)DmaBlock
->SystemAdapterObject
;
687 if (AdapterObject
== ((PLOGICAL_ADAPTER
)DmaBlock
->Miniport
)->NdisMiniportBlock
.SystemAdapterObject
)
688 ((PLOGICAL_ADAPTER
)DmaBlock
->Miniport
)->NdisMiniportBlock
.SystemAdapterObject
= NULL
;
690 AdapterObject
->DmaOperations
->PutDmaAdapter(AdapterObject
);
692 ExFreePool(DmaBlock
);
700 NdisMDeregisterInterrupt(
701 IN PNDIS_MINIPORT_INTERRUPT Interrupt
)
703 * FUNCTION: Releases an interrupt vector
705 * Interrupt = Pointer to interrupt object
708 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
709 IoDisconnectInterrupt(Interrupt
->InterruptObject
);
710 Interrupt
->Miniport
->RegisteredInterrupts
--;
712 if (Interrupt
->Miniport
->Interrupt
== Interrupt
)
713 Interrupt
->Miniport
->Interrupt
= NULL
;
721 NdisMFreeMapRegisters(
722 IN NDIS_HANDLE MiniportAdapterHandle
)
724 * FUNCTION: Free previously allocated map registers
726 * MiniportAdapterHandle: Handle originally passed in to MiniportInitialize
731 PLOGICAL_ADAPTER Adapter
= (PLOGICAL_ADAPTER
)MiniportAdapterHandle
;
732 PDMA_ADAPTER AdapterObject
;
733 UINT MapRegistersPerBaseRegister
;
736 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
740 /* only bus masters may call this routine */
741 if(!(Adapter
->NdisMiniportBlock
.Flags
& NDIS_ATTRIBUTE_BUS_MASTER
) ||
742 Adapter
->NdisMiniportBlock
.SystemAdapterObject
== NULL
) {
743 NDIS_DbgPrint(MIN_TRACE
, ("Not bus master or bad adapter object\n"));
747 MapRegistersPerBaseRegister
= ((Adapter
->NdisMiniportBlock
.MaximumPhysicalMapping
- 2) / PAGE_SIZE
) + 2;
749 AdapterObject
= Adapter
->NdisMiniportBlock
.SystemAdapterObject
;
751 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
753 for(i
= 0; i
< Adapter
->NdisMiniportBlock
.BaseMapRegistersNeeded
; i
++)
755 AdapterObject
->DmaOperations
->FreeMapRegisters(
756 Adapter
->NdisMiniportBlock
.SystemAdapterObject
,
757 Adapter
->NdisMiniportBlock
.MapRegisters
[i
].MapRegister
,
758 MapRegistersPerBaseRegister
);
761 KeLowerIrql(OldIrql
);
763 AdapterObject
->DmaOperations
->PutDmaAdapter(AdapterObject
);
764 Adapter
->NdisMiniportBlock
.SystemAdapterObject
= NULL
;
766 ExFreePool(Adapter
->NdisMiniportBlock
.MapRegisters
);
775 OUT PVOID
*VirtualAddress
,
776 IN NDIS_HANDLE MiniportAdapterHandle
,
777 IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
,
780 * FUNCTION: Maps a bus-relative address to a system-wide virtual address
782 * VirtualAddress: receives virtual address of mapping
783 * MiniportAdapterHandle: Handle originally input to MiniportInitialize
784 * PhysicalAddress: bus-relative address to map
785 * Length: Number of bytes to map
787 * NDIS_STATUS_SUCCESS: the operation completed successfully
788 * NDIS_STATUS_RESOURCE_CONFLICT: the physical address range is already claimed
789 * NDIS_STATUS_RESOURCES: insufficient resources to complete the mapping
790 * NDIS_STATUS_FAILURE: a general failure has occured
792 * - Must be called at IRQL = PASSIVE_LEVEL
795 PLOGICAL_ADAPTER Adapter
= MiniportAdapterHandle
;
796 ULONG AddressSpace
= 0; /* Memory Space */
797 NDIS_PHYSICAL_ADDRESS TranslatedAddress
;
800 ASSERT(VirtualAddress
&& MiniportAdapterHandle
);
802 NDIS_DbgPrint(MAX_TRACE
, ("Called\n"));
804 if(!HalTranslateBusAddress(Adapter
->NdisMiniportBlock
.BusType
, Adapter
->NdisMiniportBlock
.BusNumber
,
805 PhysicalAddress
, &AddressSpace
, &TranslatedAddress
))
807 NDIS_DbgPrint(MIN_TRACE
, ("Unable to translate address\n"));
808 return NDIS_STATUS_RESOURCES
;
811 *VirtualAddress
= MmMapIoSpace(TranslatedAddress
, Length
, MmNonCached
);
813 if(!*VirtualAddress
) {
814 NDIS_DbgPrint(MIN_TRACE
, ("MmMapIoSpace failed\n"));
815 return NDIS_STATUS_RESOURCES
;
818 return NDIS_STATUS_SUCCESS
;
827 IN NDIS_HANDLE MiniportDmaHandle
)
829 /* NOTE: Unlike NdisMGetDmaAlignment() below, this is a handle to the DMA block */
830 PNDIS_DMA_BLOCK DmaBlock
= MiniportDmaHandle
;
831 PDMA_ADAPTER AdapterObject
= (PDMA_ADAPTER
)DmaBlock
->SystemAdapterObject
;
833 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
835 return AdapterObject
->DmaOperations
->ReadDmaCounter(AdapterObject
);
843 NdisMGetDmaAlignment(
844 IN NDIS_HANDLE MiniportAdapterHandle
)
846 /* NOTE: Unlike NdisMReadDmaCounter() above, this is a handle to the NDIS miniport block */
847 PLOGICAL_ADAPTER Adapter
= MiniportAdapterHandle
;
848 PDMA_ADAPTER AdapterObject
= (PDMA_ADAPTER
)Adapter
->NdisMiniportBlock
.SystemAdapterObject
;
850 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
852 return AdapterObject
->DmaOperations
->GetDmaAlignment(AdapterObject
);
860 NdisMRegisterDmaChannel(
861 OUT PNDIS_HANDLE MiniportDmaHandle
,
862 IN NDIS_HANDLE MiniportAdapterHandle
,
864 IN BOOLEAN Dma32BitAddresses
,
865 IN PNDIS_DMA_DESCRIPTION DmaDescription
,
866 IN ULONG MaximumLength
)
868 PLOGICAL_ADAPTER Adapter
= (PLOGICAL_ADAPTER
)MiniportAdapterHandle
;
869 DEVICE_DESCRIPTION DeviceDesc
;
871 PNDIS_DMA_BLOCK DmaBlock
;
873 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
875 RtlZeroMemory(&DeviceDesc
, sizeof(DEVICE_DESCRIPTION
));
877 DeviceDesc
.Version
= DEVICE_DESCRIPTION_VERSION
;
878 DeviceDesc
.Master
= (Adapter
->NdisMiniportBlock
.Flags
& NDIS_ATTRIBUTE_BUS_MASTER
);
879 DeviceDesc
.ScatterGather
= FALSE
;
880 DeviceDesc
.DemandMode
= DmaDescription
->DemandMode
;
881 DeviceDesc
.AutoInitialize
= DmaDescription
->AutoInitialize
;
882 DeviceDesc
.Dma32BitAddresses
= Dma32BitAddresses
;
883 DeviceDesc
.Dma64BitAddresses
= FALSE
;
884 DeviceDesc
.BusNumber
= Adapter
->NdisMiniportBlock
.BusNumber
;
885 DeviceDesc
.DmaChannel
= DmaDescription
->DmaChannel
;
886 DeviceDesc
.InterfaceType
= Adapter
->NdisMiniportBlock
.BusType
;
887 DeviceDesc
.DmaWidth
= DmaDescription
->DmaWidth
;
888 DeviceDesc
.DmaSpeed
= DmaDescription
->DmaSpeed
;
889 DeviceDesc
.MaximumLength
= MaximumLength
;
892 DmaBlock
= ExAllocatePool(NonPagedPool
, sizeof(NDIS_DMA_BLOCK
));
894 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources\n"));
895 return NDIS_STATUS_RESOURCES
;
898 DmaBlock
->SystemAdapterObject
= (PVOID
)IoGetDmaAdapter(Adapter
->NdisMiniportBlock
.PhysicalDeviceObject
, &DeviceDesc
, &MapRegisters
);
900 if (!DmaBlock
->SystemAdapterObject
) {
901 NDIS_DbgPrint(MIN_TRACE
, ("Insufficient resources\n"));
902 ExFreePool(DmaBlock
);
903 return NDIS_STATUS_RESOURCES
;
906 Adapter
->NdisMiniportBlock
.SystemAdapterObject
= (PDMA_ADAPTER
)DmaBlock
->SystemAdapterObject
;
908 KeInitializeEvent(&DmaBlock
->AllocationEvent
, NotificationEvent
, FALSE
);
910 DmaBlock
->Miniport
= Adapter
;
912 *MiniportDmaHandle
= DmaBlock
;
914 return NDIS_STATUS_SUCCESS
;
922 NdisAllocateDmaChannel(OUT PNDIS_STATUS Status
,
923 OUT PNDIS_HANDLE NdisDmaHandle
,
924 IN NDIS_HANDLE NdisAdapterHandle
,
925 IN PNDIS_DMA_DESCRIPTION DmaDescription
,
926 IN ULONG MaximumLength
)
928 *Status
= NdisMRegisterDmaChannel(NdisDmaHandle
,
941 NdisMRegisterInterrupt(
942 OUT PNDIS_MINIPORT_INTERRUPT Interrupt
,
943 IN NDIS_HANDLE MiniportAdapterHandle
,
944 IN UINT InterruptVector
,
945 IN UINT InterruptLevel
,
946 IN BOOLEAN RequestIsr
,
947 IN BOOLEAN SharedInterrupt
,
948 IN NDIS_INTERRUPT_MODE InterruptMode
)
950 * FUNCTION: Claims access to an interrupt vector
952 * Interrupt = Address of interrupt object to initialize
953 * MiniportAdapterHandle = Specifies handle input to MiniportInitialize
954 * InterruptVector = Specifies bus-relative vector to register
955 * InterruptLevel = Specifies bus-relative DIRQL vector for interrupt
956 * RequestIsr = TRUE if MiniportISR should always be called
957 * SharedInterrupt = TRUE if other devices may use the same interrupt
958 * InterruptMode = Specifies type of interrupt
960 * Status of operation
967 PLOGICAL_ADAPTER Adapter
= (PLOGICAL_ADAPTER
)MiniportAdapterHandle
;
969 NDIS_DbgPrint(MAX_TRACE
, ("Called. InterruptVector (0x%X) InterruptLevel (0x%X) "
970 "SharedInterrupt (%d) InterruptMode (0x%X)\n",
971 InterruptVector
, InterruptLevel
, SharedInterrupt
, InterruptMode
));
973 RtlZeroMemory(Interrupt
, sizeof(NDIS_MINIPORT_INTERRUPT
));
975 KeInitializeSpinLock(&Interrupt
->DpcCountLock
);
977 KeInitializeDpc(&Interrupt
->InterruptDpc
, HandleDeferredProcessing
, Adapter
);
979 KeInitializeEvent(&Interrupt
->DpcsCompletedEvent
, NotificationEvent
, FALSE
);
981 Interrupt
->SharedInterrupt
= SharedInterrupt
;
982 Interrupt
->IsrRequested
= RequestIsr
;
983 Interrupt
->Miniport
= &Adapter
->NdisMiniportBlock
;
985 MappedIRQ
= HalGetInterruptVector(Adapter
->NdisMiniportBlock
.BusType
, Adapter
->NdisMiniportBlock
.BusNumber
,
986 InterruptLevel
, InterruptVector
, &DIrql
,
989 NDIS_DbgPrint(MAX_TRACE
, ("Connecting to interrupt vector (0x%X) Affinity (0x%X).\n", MappedIRQ
, Affinity
));
991 Status
= IoConnectInterrupt(&Interrupt
->InterruptObject
, ServiceRoutine
, Interrupt
, &Interrupt
->DpcCountLock
, MappedIRQ
,
992 DIrql
, DIrql
, InterruptMode
, SharedInterrupt
, Affinity
, FALSE
);
994 NDIS_DbgPrint(MAX_TRACE
, ("Leaving. Status (0x%X).\n", Status
));
996 if (NT_SUCCESS(Status
)) {
997 Adapter
->NdisMiniportBlock
.Interrupt
= Interrupt
;
998 Adapter
->NdisMiniportBlock
.RegisteredInterrupts
++;
999 return NDIS_STATUS_SUCCESS
;
1002 if (Status
== STATUS_INSUFFICIENT_RESOURCES
)
1004 /* FIXME: Log error */
1005 NDIS_DbgPrint(MIN_TRACE
, ("Resource conflict!\n"));
1006 return NDIS_STATUS_RESOURCE_CONFLICT
;
1009 NDIS_DbgPrint(MIN_TRACE
, ("Function failed. Status (0x%X).\n", Status
));
1010 return NDIS_STATUS_FAILURE
;
1018 NdisMRegisterIoPortRange(
1019 OUT PVOID
*PortOffset
,
1020 IN NDIS_HANDLE MiniportAdapterHandle
,
1021 IN UINT InitialPort
,
1022 IN UINT NumberOfPorts
)
1024 * FUNCTION: Sets up driver access to device I/O ports
1026 * PortOffset = Address of buffer to place mapped base port address
1027 * MiniportAdapterHandle = Specifies handle input to MiniportInitialize
1028 * InitialPort = Bus-relative base port address of a range to be mapped
1029 * NumberOfPorts = Specifies number of ports to be mapped
1031 * Status of operation
1034 PHYSICAL_ADDRESS PortAddress
, TranslatedAddress
;
1035 PLOGICAL_ADAPTER Adapter
= (PLOGICAL_ADAPTER
)MiniportAdapterHandle
;
1036 ULONG AddressSpace
= 1; /* FIXME The HAL handles this wrong atm */
1040 NDIS_DbgPrint(MAX_TRACE
, ("Called - InitialPort 0x%x, NumberOfPorts 0x%x\n", InitialPort
, NumberOfPorts
));
1042 memset(&PortAddress
, 0, sizeof(PortAddress
));
1045 * FIXME: NDIS 5+ completely ignores the InitialPort parameter, but
1046 * we don't have a way to get the I/O base address yet (see
1047 * NDIS_MINIPORT_BLOCK->AllocatedResources and
1048 * NDIS_MINIPORT_BLOCK->AllocatedResourcesTranslated).
1051 PortAddress
= RtlConvertUlongToLargeInteger(InitialPort
);
1055 NDIS_DbgPrint(MAX_TRACE
, ("Translating address 0x%x 0x%x\n", PortAddress
.u
.HighPart
, PortAddress
.u
.LowPart
));
1057 if(!HalTranslateBusAddress(Adapter
->NdisMiniportBlock
.BusType
, Adapter
->NdisMiniportBlock
.BusNumber
,
1058 PortAddress
, &AddressSpace
, &TranslatedAddress
))
1060 NDIS_DbgPrint(MIN_TRACE
, ("Unable to translate address\n"));
1061 return NDIS_STATUS_RESOURCES
;
1064 NDIS_DbgPrint(MAX_TRACE
, ("Hal returned AddressSpace=0x%x TranslatedAddress=0x%x 0x%x\n",
1065 AddressSpace
, TranslatedAddress
.u
.HighPart
, TranslatedAddress
.u
.LowPart
));
1069 ASSERT(TranslatedAddress
.u
.HighPart
== 0);
1070 *PortOffset
= (PVOID
)(ULONG_PTR
)TranslatedAddress
.QuadPart
;
1071 NDIS_DbgPrint(MAX_TRACE
, ("Returning 0x%x\n", *PortOffset
));
1072 return NDIS_STATUS_SUCCESS
;
1075 NDIS_DbgPrint(MAX_TRACE
, ("calling MmMapIoSpace\n"));
1077 *PortOffset
= MmMapIoSpace(TranslatedAddress
, NumberOfPorts
, MmNonCached
);
1078 NDIS_DbgPrint(MAX_TRACE
, ("Returning 0x%x for port range\n", *PortOffset
));
1081 NDIS_DbgPrint(MIN_TRACE
, ("MmMapIoSpace failed\n"));
1082 return NDIS_STATUS_RESOURCES
;
1085 return NDIS_STATUS_SUCCESS
;
1093 NdisMDeregisterIoPortRange(IN NDIS_HANDLE MiniportAdapterHandle
,
1094 IN UINT InitialPort
,
1095 IN UINT NumberOfPorts
,
1096 IN PVOID PortOffset
)
1098 * FUNCTION: Releases a register mapping to I/O ports
1100 * MiniportAdapterHandle = Specifies handle input to MiniportInitialize
1101 * InitialPort = Bus-relative base port address of a range to be mapped
1102 * NumberOfPorts = Specifies number of ports to be mapped
1103 * PortOffset = Pointer to mapped base port address
1106 PLOGICAL_ADAPTER Adapter
= (PLOGICAL_ADAPTER
)MiniportAdapterHandle
;
1107 PHYSICAL_ADDRESS PortAddress
= RtlConvertUlongToLargeInteger(InitialPort
);
1108 PHYSICAL_ADDRESS TranslatedAddress
;
1109 ULONG AddressSpace
= 1;
1111 NDIS_DbgPrint(MAX_TRACE
, ("Called - InitialPort 0x%x, NumberOfPorts 0x%x, Port Offset 0x%x\n", InitialPort
, NumberOfPorts
, PortOffset
));
1113 /* Translate the initial port again to find the address space of the translated address */
1114 if(!HalTranslateBusAddress(Adapter
->NdisMiniportBlock
.BusType
, Adapter
->NdisMiniportBlock
.BusNumber
,
1115 PortAddress
, &AddressSpace
, &TranslatedAddress
))
1117 NDIS_DbgPrint(MIN_TRACE
, ("Unable to translate address\n"));
1121 /* Make sure we got the same translation as last time */
1122 ASSERT(TranslatedAddress
.QuadPart
== (ULONG_PTR
)PortOffset
);
1124 /* Check if we're in memory space */
1127 NDIS_DbgPrint(MAX_TRACE
, ("Calling MmUnmapIoSpace\n"));
1129 /* Unmap the memory */
1130 MmUnmapIoSpace(PortOffset
, NumberOfPorts
);
1140 IN NDIS_HANDLE MiniportAdapterHandle
,
1141 IN PVOID VirtualAddress
,
1144 * FUNCTION: Un-maps space previously mapped with NdisMMapIoSpace
1146 * MiniportAdapterHandle: handle originally passed into MiniportInitialize
1147 * VirtualAddress: Address to un-map
1148 * Length: length of the mapped memory space
1150 * - Must be called at IRQL = PASSIVE_LEVEL
1151 * - Must only be called from MiniportInitialize and MiniportHalt
1152 * - See also: NdisMMapIoSpace
1154 * - Depends on MmUnmapIoSpace to Do The Right Thing in all cases
1159 ASSERT(MiniportAdapterHandle
);
1161 MmUnmapIoSpace(VirtualAddress
, Length
);
1169 NdisMInitializeScatterGatherDma(
1170 IN NDIS_HANDLE MiniportAdapterHandle
,
1171 IN BOOLEAN Dma64BitAddresses
,
1172 IN ULONG MaximumPhysicalMapping
)
1180 PLOGICAL_ADAPTER Adapter
= (PLOGICAL_ADAPTER
)MiniportAdapterHandle
;
1182 DEVICE_DESCRIPTION DeviceDesc
;
1184 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
1186 if (!(Adapter
->NdisMiniportBlock
.Flags
& NDIS_ATTRIBUTE_BUS_MASTER
)) {
1187 NDIS_DbgPrint(MIN_TRACE
, ("Not a bus master\n"));
1188 return NDIS_STATUS_NOT_SUPPORTED
;
1191 RtlZeroMemory(&DeviceDesc
, sizeof(DEVICE_DESCRIPTION
));
1193 DeviceDesc
.Version
= DEVICE_DESCRIPTION_VERSION
;
1194 DeviceDesc
.Master
= TRUE
;
1195 DeviceDesc
.ScatterGather
= TRUE
;
1196 DeviceDesc
.Dma32BitAddresses
= TRUE
; // All callers support 32-bit addresses
1197 DeviceDesc
.Dma64BitAddresses
= Dma64BitAddresses
;
1198 DeviceDesc
.BusNumber
= Adapter
->NdisMiniportBlock
.BusNumber
;
1199 DeviceDesc
.InterfaceType
= Adapter
->NdisMiniportBlock
.BusType
;
1200 DeviceDesc
.MaximumLength
= MaximumPhysicalMapping
;
1202 Adapter
->NdisMiniportBlock
.SystemAdapterObject
=
1203 IoGetDmaAdapter(Adapter
->NdisMiniportBlock
.PhysicalDeviceObject
, &DeviceDesc
, &MapRegisters
);
1205 if (!Adapter
->NdisMiniportBlock
.SystemAdapterObject
)
1206 return NDIS_STATUS_RESOURCES
;
1208 /* FIXME: Right now we just use this as a place holder */
1209 Adapter
->NdisMiniportBlock
.ScatterGatherListSize
= 1;
1211 return NDIS_STATUS_SUCCESS
;
1221 OUT PNDIS_STATUS Status
,
1222 OUT PVOID
*VirtualAddress
,
1223 IN NDIS_HANDLE NdisAdapterHandle
,
1224 IN NDIS_PHYSICAL_ADDRESS PhysicalAddress
,
1233 *Status
= NdisMMapIoSpace(VirtualAddress
,
1246 IN PNDIS_HANDLE NdisDmaHandle
)
1254 NdisMDeregisterDmaChannel(NdisDmaHandle
);