xref: /reactos/drivers/network/ndis/ndis/io.c (revision 34593d93)
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS NDIS library
4  * FILE:        ndis/io.c
5  * PURPOSE:     I/O related routines
6  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7  *              Vizzini (vizzini@plasmic.com)
8  * REVISIONS:
9  *   CSH 01/08-2000 Created
10  *   20 Aug 2003 Vizzini - DMA support
11  *   3  Oct 2003 Vizzini - Formatting and minor bugfixes
12  */
13 
14 #include "ndissys.h"
15 
HandleDeferredProcessing(IN PKDPC Dpc,IN PVOID DeferredContext,IN PVOID SystemArgument1,IN PVOID SystemArgument2)16 VOID NTAPI HandleDeferredProcessing(
17     IN  PKDPC   Dpc,
18     IN  PVOID   DeferredContext,
19     IN  PVOID   SystemArgument1,
20     IN  PVOID   SystemArgument2)
21 /*
22  * FUNCTION: Deferred interrupt processing routine
23  * ARGUMENTS:
24  *     Dpc             = Pointer to DPC object
25  *     DeferredContext = Pointer to context information (LOGICAL_ADAPTER)
26  *     SystemArgument1 = Unused
27  *     SystemArgument2 = Unused
28  */
29 {
30   PLOGICAL_ADAPTER Adapter = GET_LOGICAL_ADAPTER(DeferredContext);
31 
32   NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
33 
34   ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
35 
36   /* Call the deferred interrupt service handler for this adapter */
37   (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.HandleInterruptHandler)(
38       Adapter->NdisMiniportBlock.MiniportAdapterContext);
39 
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);
45 
46   NDIS_DbgPrint(MAX_TRACE, ("Leaving.\n"));
47 }
48 
ServiceRoutine(IN PKINTERRUPT Interrupt,IN PVOID ServiceContext)49 BOOLEAN NTAPI ServiceRoutine(
50     IN  PKINTERRUPT Interrupt,
51     IN  PVOID       ServiceContext)
52 /*
53  * FUNCTION: Interrupt service routine
54  * ARGUMENTS:
55  *     Interrupt      = Pointer to interrupt object
56  *     ServiceContext = Pointer to context information (PNDIS_MINIPORT_INTERRUPT)
57  * RETURNS
58  *     TRUE if a miniport controlled device generated the interrupt
59  */
60 {
61   BOOLEAN InterruptRecognized = FALSE;
62   BOOLEAN QueueMiniportHandleInterrupt = FALSE;
63   PNDIS_MINIPORT_INTERRUPT NdisInterrupt = ServiceContext;
64   PNDIS_MINIPORT_BLOCK NdisMiniportBlock = NdisInterrupt->Miniport;
65   BOOLEAN Initializing;
66 
67   NDIS_DbgPrint(MAX_TRACE, ("Called. Interrupt (0x%X)\n", NdisInterrupt));
68 
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")));
72 
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)(
77           &InterruptRecognized,
78           &QueueMiniportHandleInterrupt,
79           NdisMiniportBlock->MiniportAdapterContext);
80 
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;
87   }
88 
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)
92   {
93       NDIS_DbgPrint(MAX_TRACE, ("Queuing DPC.\n"));
94       KeInsertQueueDpc(&NdisInterrupt->InterruptDpc, NULL, NULL);
95   }
96 
97   NDIS_DbgPrint(MAX_TRACE, ("Leaving.\n"));
98 
99   return InterruptRecognized;
100 }
101 
102 /*
103  * @implemented
104  */
105 VOID
106 EXPORT
NdisImmediateReadPortUchar(IN NDIS_HANDLE WrapperConfigurationContext,IN ULONG Port,OUT PUCHAR Data)107 NdisImmediateReadPortUchar(
108     IN  NDIS_HANDLE WrapperConfigurationContext,
109     IN  ULONG       Port,
110     OUT PUCHAR      Data)
111 {
112   NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
113   *Data = READ_PORT_UCHAR(UlongToPtr(Port)); // FIXME: What to do with WrapperConfigurationContext?
114 }
115 
116 /*
117  * @implemented
118  */
119 VOID
120 EXPORT
NdisImmediateReadPortUlong(IN NDIS_HANDLE WrapperConfigurationContext,IN ULONG Port,OUT PULONG Data)121 NdisImmediateReadPortUlong(
122     IN  NDIS_HANDLE WrapperConfigurationContext,
123     IN  ULONG       Port,
124     OUT PULONG      Data)
125 {
126   NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
127   *Data = READ_PORT_ULONG(UlongToPtr(Port)); // FIXME: What to do with WrapperConfigurationContext?
128 }
129 
130 /*
131  * @implemented
132  */
133 VOID
134 EXPORT
NdisImmediateReadPortUshort(IN NDIS_HANDLE WrapperConfigurationContext,IN ULONG Port,OUT PUSHORT Data)135 NdisImmediateReadPortUshort(
136     IN  NDIS_HANDLE WrapperConfigurationContext,
137     IN  ULONG       Port,
138     OUT PUSHORT     Data)
139 {
140   NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
141   *Data = READ_PORT_USHORT(UlongToPtr(Port)); // FIXME: What to do with WrapperConfigurationContext?
142 }
143 
144 /*
145  * @implemented
146  */
147 VOID
148 EXPORT
NdisImmediateWritePortUchar(IN NDIS_HANDLE WrapperConfigurationContext,IN ULONG Port,IN UCHAR Data)149 NdisImmediateWritePortUchar(
150     IN  NDIS_HANDLE WrapperConfigurationContext,
151     IN  ULONG       Port,
152     IN  UCHAR       Data)
153 {
154   NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
155   WRITE_PORT_UCHAR(UlongToPtr(Port), Data); // FIXME: What to do with WrapperConfigurationContext?
156 }
157 
158 /*
159  * @implemented
160  */
161 VOID
162 EXPORT
NdisImmediateWritePortUlong(IN NDIS_HANDLE WrapperConfigurationContext,IN ULONG Port,IN ULONG Data)163 NdisImmediateWritePortUlong(
164     IN  NDIS_HANDLE WrapperConfigurationContext,
165     IN  ULONG       Port,
166     IN  ULONG       Data)
167 {
168   NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
169   WRITE_PORT_ULONG(UlongToPtr(Port), Data); // FIXME: What to do with WrapperConfigurationContext?
170 }
171 
172 /*
173  * @implemented
174  */
175 VOID
176 EXPORT
NdisImmediateWritePortUshort(IN NDIS_HANDLE WrapperConfigurationContext,IN ULONG Port,IN USHORT Data)177 NdisImmediateWritePortUshort(
178     IN  NDIS_HANDLE WrapperConfigurationContext,
179     IN  ULONG       Port,
180     IN  USHORT      Data)
181 {
182   NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
183   WRITE_PORT_USHORT(UlongToPtr(Port), Data); // FIXME: What to do with WrapperConfigurationContext?
184 }
185 
NdisSubordinateMapRegisterCallback(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID MapRegisterBase,IN PVOID Context)186 IO_ALLOCATION_ACTION NTAPI NdisSubordinateMapRegisterCallback (
187     IN PDEVICE_OBJECT  DeviceObject,
188     IN PIRP            Irp,
189     IN PVOID           MapRegisterBase,
190     IN PVOID           Context)
191 /*
192  * FUNCTION: Called back during reservation of map registers
193  * ARGUMENTS:
194  *     DeviceObject: Device object of the device 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
198  * NOTES:
199  *     - Called at IRQL = DISPATCH_LEVEL
200  */
201 {
202     PNDIS_DMA_BLOCK DmaBlock = Context;
203 
204     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
205 
206     DmaBlock->MapRegisterBase = MapRegisterBase;
207 
208     NDIS_DbgPrint(MAX_TRACE, ("setting event and leaving.\n"));
209 
210     KeSetEvent(&DmaBlock->AllocationEvent, 0, FALSE);
211 
212     /* We have to hold the object open to keep our lock on the system DMA controller */
213     return KeepObject;
214 }
215 
NdisBusMasterMapRegisterCallback(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID MapRegisterBase,IN PVOID Context)216 IO_ALLOCATION_ACTION NTAPI NdisBusMasterMapRegisterCallback (
217     IN PDEVICE_OBJECT  DeviceObject,
218     IN PIRP            Irp,
219     IN PVOID           MapRegisterBase,
220     IN PVOID           Context)
221 /*
222  * FUNCTION: Called back during reservation of map registers
223  * ARGUMENTS:
224  *     DeviceObject: Device object of the device 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
228  * NOTES:
229  *     - Called once per BaseMapRegister (see NdisMAllocateMapRegisters)
230  *     - Called at IRQL = DISPATCH_LEVEL
231  */
232 {
233   PLOGICAL_ADAPTER Adapter = Context;
234 
235   NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
236 
237   Adapter->NdisMiniportBlock.MapRegisters[Adapter->NdisMiniportBlock.CurrentMapRegister].MapRegister = MapRegisterBase;
238 
239   NDIS_DbgPrint(MAX_TRACE, ("setting event and leaving.\n"));
240 
241   KeSetEvent(Adapter->NdisMiniportBlock.AllocationEvent, 0, FALSE);
242 
243   /* We're a bus master so we can go ahead and deallocate the object now */
244   return DeallocateObjectKeepRegisters;
245 }
246 
247 /*
248  * @implemented
249  */
250 NDIS_STATUS
251 EXPORT
NdisMAllocateMapRegisters(IN NDIS_HANDLE MiniportAdapterHandle,IN UINT DmaChannel,IN NDIS_DMA_SIZE DmaSize,IN ULONG BaseMapRegistersNeeded,IN ULONG MaximumBufferSize)252 NdisMAllocateMapRegisters(
253     IN  NDIS_HANDLE   MiniportAdapterHandle,
254     IN  UINT          DmaChannel,
255     IN  NDIS_DMA_SIZE DmaSize,
256     IN  ULONG         BaseMapRegistersNeeded,
257     IN  ULONG         MaximumBufferSize)
258 /*
259  * FUNCTION: Allocate map registers for use in DMA transfers
260  * ARGUMENTS:
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
266  * RETURNS:
267  *     NDIS_STATUS_SUCCESS on success
268  *     NDIS_STATUS_RESOURCES on failure
269  * NOTES:
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
282  *       page size.
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.
286  */
287 {
288   DEVICE_DESCRIPTION   Description;
289   PDMA_ADAPTER         AdapterObject = 0;
290   UINT                 MapRegistersPerBaseRegister = 0;
291   ULONG                AvailableMapRegisters;
292   NTSTATUS             NtStatus;
293   PLOGICAL_ADAPTER     Adapter;
294   PDEVICE_OBJECT       DeviceObject = 0;
295   KEVENT               AllocationEvent;
296   KIRQL                OldIrql;
297 
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));
300 
301   memset(&Description,0,sizeof(Description));
302 
303   Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle;
304 
305   ASSERT(Adapter);
306 
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;
311   }
312 
313   DeviceObject = Adapter->NdisMiniportBlock.DeviceObject;
314 
315   KeInitializeEvent(&AllocationEvent, NotificationEvent, FALSE);
316   Adapter->NdisMiniportBlock.AllocationEvent = &AllocationEvent;
317 
318   /*
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.
322   *
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.
326   */
327 
328   /* unhandled corner case: {1,2}-byte max buffer size */
329   ASSERT(MaximumBufferSize > 2);
330   MapRegistersPerBaseRegister = ((MaximumBufferSize-2) / (2*PAGE_SIZE)) + 2;
331 
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;
339 
340   if(DmaSize == NDIS_DMA_64BITS)
341     Description.Dma64BitAddresses = TRUE;
342   else if(DmaSize == NDIS_DMA_32BITS)
343     Description.Dma32BitAddresses = TRUE;
344 
345   AdapterObject = IoGetDmaAdapter(
346     Adapter->NdisMiniportBlock.PhysicalDeviceObject, &Description, &AvailableMapRegisters);
347 
348   if(!AdapterObject)
349     {
350       NDIS_DbgPrint(MIN_TRACE, ("Unable to allocate an adapter object; bailing out\n"));
351       return NDIS_STATUS_RESOURCES;
352     }
353 
354   Adapter->NdisMiniportBlock.SystemAdapterObject = AdapterObject;
355 
356   if(AvailableMapRegisters < MapRegistersPerBaseRegister)
357     {
358       NDIS_DbgPrint(MIN_TRACE, ("Didn't get enough map registers from hal - requested 0x%x, got 0x%x\n",
359           MapRegistersPerBaseRegister, AvailableMapRegisters));
360 
361       AdapterObject->DmaOperations->PutDmaAdapter(AdapterObject);
362       Adapter->NdisMiniportBlock.SystemAdapterObject = NULL;
363       return NDIS_STATUS_RESOURCES;
364     }
365 
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)
369     {
370       NDIS_DbgPrint(MIN_TRACE, ("insufficient resources.\n"));
371       AdapterObject->DmaOperations->PutDmaAdapter(AdapterObject);
372       Adapter->NdisMiniportBlock.SystemAdapterObject = NULL;
373       return NDIS_STATUS_RESOURCES;
374     }
375 
376   memset(Adapter->NdisMiniportBlock.MapRegisters, 0, BaseMapRegistersNeeded * sizeof(MAP_REGISTER_ENTRY));
377   Adapter->NdisMiniportBlock.BaseMapRegistersNeeded = (USHORT)BaseMapRegistersNeeded;
378 
379   while(BaseMapRegistersNeeded)
380     {
381       NDIS_DbgPrint(MAX_TRACE, ("iterating, basemapregistersneeded = %d\n", BaseMapRegistersNeeded));
382 
383       BaseMapRegistersNeeded--;
384       Adapter->NdisMiniportBlock.CurrentMapRegister = (USHORT)BaseMapRegistersNeeded;
385       KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
386         {
387           NtStatus = AdapterObject->DmaOperations->AllocateAdapterChannel(
388               AdapterObject, DeviceObject, MapRegistersPerBaseRegister,
389               NdisBusMasterMapRegisterCallback, Adapter);
390         }
391       KeLowerIrql(OldIrql);
392 
393       if(!NT_SUCCESS(NtStatus))
394         {
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;
401         }
402 
403       NDIS_DbgPrint(MAX_TRACE, ("waiting on event\n"));
404 
405       NtStatus = KeWaitForSingleObject(&AllocationEvent, Executive, KernelMode, FALSE, 0);
406 
407       if(!NT_SUCCESS(NtStatus))
408         {
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;
415         }
416 
417       NDIS_DbgPrint(MAX_TRACE, ("resetting event\n"));
418 
419       KeClearEvent(&AllocationEvent);
420     }
421 
422   NDIS_DbgPrint(MAX_TRACE, ("returning success\n"));
423   return NDIS_STATUS_SUCCESS;
424 }
425 
426 
427 /*
428  * @implemented
429  */
430 VOID
431 EXPORT
NdisMSetupDmaTransfer(OUT PNDIS_STATUS Status,IN NDIS_HANDLE MiniportDmaHandle,IN PNDIS_BUFFER Buffer,IN ULONG Offset,IN ULONG Length,IN BOOLEAN WriteToDevice)432 NdisMSetupDmaTransfer(OUT PNDIS_STATUS Status,
433                       IN NDIS_HANDLE MiniportDmaHandle,
434                       IN PNDIS_BUFFER Buffer,
435                       IN ULONG Offset,
436                       IN ULONG Length,
437                       IN BOOLEAN WriteToDevice)
438 {
439     PNDIS_DMA_BLOCK DmaBlock = MiniportDmaHandle;
440     NTSTATUS NtStatus;
441     PLOGICAL_ADAPTER Adapter;
442     KIRQL OldIrql;
443     PDMA_ADAPTER AdapterObject;
444     ULONG MapRegistersNeeded;
445 
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));
448 
449     Adapter = (PLOGICAL_ADAPTER)DmaBlock->Miniport;
450     AdapterObject = (PDMA_ADAPTER)DmaBlock->SystemAdapterObject;
451 
452     MapRegistersNeeded = (Length + (PAGE_SIZE - 1)) / PAGE_SIZE;
453 
454     KeFlushIoBuffers(Buffer, !WriteToDevice, TRUE);
455 
456     KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
457     {
458         NtStatus = AdapterObject->DmaOperations->AllocateAdapterChannel(AdapterObject,
459                                                                         Adapter->NdisMiniportBlock.PhysicalDeviceObject,
460                                                                         MapRegistersNeeded,
461                                                                         NdisSubordinateMapRegisterCallback, Adapter);
462     }
463     KeLowerIrql(OldIrql);
464 
465     if(!NT_SUCCESS(NtStatus))
466     {
467         NDIS_DbgPrint(MIN_TRACE, ("AllocateAdapterChannel failed: 0x%x\n", NtStatus));
468         AdapterObject->DmaOperations->FreeAdapterChannel(AdapterObject);
469         *Status = NDIS_STATUS_RESOURCES;
470         return;
471     }
472 
473     NtStatus = KeWaitForSingleObject(&DmaBlock->AllocationEvent, Executive, KernelMode, FALSE, 0);
474 
475     if(!NT_SUCCESS(NtStatus))
476     {
477         NDIS_DbgPrint(MIN_TRACE, ("KeWaitForSingleObject failed: 0x%x\n", NtStatus));
478         AdapterObject->DmaOperations->FreeAdapterChannel(AdapterObject);
479         *Status = NDIS_STATUS_RESOURCES;
480         return;
481     }
482 
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);
487 
488     NDIS_DbgPrint(MAX_TRACE, ("returning success\n"));
489     *Status = NDIS_STATUS_SUCCESS;
490 }
491 
492 /*
493  * @implemented
494  */
495 VOID
496 EXPORT
NdisSetupDmaTransfer(OUT PNDIS_STATUS Status,IN PNDIS_HANDLE NdisDmaHandle,IN PNDIS_BUFFER Buffer,IN ULONG Offset,IN ULONG Length,IN BOOLEAN WriteToDevice)497 NdisSetupDmaTransfer(OUT PNDIS_STATUS    Status,
498                      IN  PNDIS_HANDLE    NdisDmaHandle,
499                      IN  PNDIS_BUFFER    Buffer,
500                      IN  ULONG           Offset,
501                      IN  ULONG           Length,
502                      IN  BOOLEAN         WriteToDevice)
503 /*
504  * FUNCTION:
505  * ARGUMENTS:
506  * NOTES:
507  *    NDIS 4.0
508  */
509 {
510     NdisMSetupDmaTransfer(Status,
511                           NdisDmaHandle,
512                           Buffer,
513                           Offset,
514                           Length,
515                           WriteToDevice);
516 }
517 
518 /*
519  * @implemented
520  */
521 VOID
522 EXPORT
NdisMCompleteDmaTransfer(OUT PNDIS_STATUS Status,IN NDIS_HANDLE MiniportDmaHandle,IN PNDIS_BUFFER Buffer,IN ULONG Offset,IN ULONG Length,IN BOOLEAN WriteToDevice)523 NdisMCompleteDmaTransfer(OUT PNDIS_STATUS Status,
524                          IN NDIS_HANDLE MiniportDmaHandle,
525                          IN PNDIS_BUFFER Buffer,
526                          IN ULONG Offset,
527                          IN ULONG Length,
528                          IN BOOLEAN WriteToDevice)
529 {
530     PNDIS_DMA_BLOCK DmaBlock = MiniportDmaHandle;
531     PDMA_ADAPTER AdapterObject = (PDMA_ADAPTER)DmaBlock->SystemAdapterObject;
532 
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));
535 
536     if (!AdapterObject->DmaOperations->FlushAdapterBuffers(AdapterObject,
537                                                            Buffer,
538                                                            DmaBlock->MapRegisterBase,
539                                                            (PUCHAR)MmGetMdlVirtualAddress(Buffer) + Offset,
540                                                            Length,
541                                                            WriteToDevice))
542     {
543         NDIS_DbgPrint(MIN_TRACE, ("FlushAdapterBuffers failed\n"));
544         *Status = NDIS_STATUS_FAILURE;
545         return;
546     }
547 
548     AdapterObject->DmaOperations->FreeAdapterChannel(AdapterObject);
549 
550     NDIS_DbgPrint(MAX_TRACE, ("returning success\n"));
551     *Status = NDIS_STATUS_SUCCESS;
552 }
553 
554 /*
555  * @implemented
556  */
557 VOID
558 EXPORT
NdisCompleteDmaTransfer(OUT PNDIS_STATUS Status,IN PNDIS_HANDLE NdisDmaHandle,IN PNDIS_BUFFER Buffer,IN ULONG Offset,IN ULONG Length,IN BOOLEAN WriteToDevice)559 NdisCompleteDmaTransfer(OUT PNDIS_STATUS    Status,
560                         IN  PNDIS_HANDLE    NdisDmaHandle,
561                         IN  PNDIS_BUFFER    Buffer,
562                         IN  ULONG           Offset,
563                         IN  ULONG           Length,
564                         IN  BOOLEAN         WriteToDevice)
565 {
566     NdisMCompleteDmaTransfer(Status,
567                              NdisDmaHandle,
568                              Buffer,
569                              Offset,
570                              Length,
571                              WriteToDevice);
572 }
573 
574 /*
575  * @implemented
576  */
577 VOID
578 EXPORT
NdisMStartBufferPhysicalMapping(IN NDIS_HANDLE MiniportAdapterHandle,IN PNDIS_BUFFER Buffer,IN ULONG PhysicalMapRegister,IN BOOLEAN WriteToDevice,OUT PNDIS_PHYSICAL_ADDRESS_UNIT PhysicalAddressArray,OUT PUINT ArraySize)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,
585     OUT PUINT                       ArraySize)
586 /*
587  * FUNCTION: Sets up map registers for a bus-master DMA transfer
588  * ARGUMENTS:
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
595  * NOTES:
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 memory readable
599  *       by the device
600  *     - The caller supplies storage for the physical address array.
601  */
602 {
603   PLOGICAL_ADAPTER Adapter;
604   PVOID CurrentVa;
605   ULONG TotalLength;
606   PHYSICAL_ADDRESS ReturnedAddress;
607   UINT LoopCount =  0;
608 
609   ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
610   ASSERT(MiniportAdapterHandle && Buffer && PhysicalAddressArray && ArraySize);
611 
612   Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle;
613   CurrentVa = MmGetMdlVirtualAddress(Buffer);
614   TotalLength = MmGetMdlByteCount(Buffer);
615 
616   while(TotalLength)
617     {
618       ULONG Length = TotalLength;
619 
620       ReturnedAddress = Adapter->NdisMiniportBlock.SystemAdapterObject->DmaOperations->MapTransfer(
621           Adapter->NdisMiniportBlock.SystemAdapterObject, Buffer,
622           Adapter->NdisMiniportBlock.MapRegisters[PhysicalMapRegister].MapRegister,
623           CurrentVa, &Length, WriteToDevice);
624 
625       Adapter->NdisMiniportBlock.MapRegisters[PhysicalMapRegister].WriteToDevice = WriteToDevice;
626 
627       PhysicalAddressArray[LoopCount].PhysicalAddress = ReturnedAddress;
628       PhysicalAddressArray[LoopCount].Length = Length;
629 
630       TotalLength -= Length;
631       CurrentVa = (PVOID)((ULONG_PTR)CurrentVa + Length);
632 
633       LoopCount++;
634     }
635 
636   *ArraySize = LoopCount;
637 }
638 
639 /*
640  * @implemented
641  */
642 VOID
643 EXPORT
NdisMCompleteBufferPhysicalMapping(IN NDIS_HANDLE MiniportAdapterHandle,IN PNDIS_BUFFER Buffer,IN ULONG PhysicalMapRegister)644 NdisMCompleteBufferPhysicalMapping(
645     IN  NDIS_HANDLE     MiniportAdapterHandle,
646     IN  PNDIS_BUFFER    Buffer,
647     IN  ULONG           PhysicalMapRegister)
648 /*
649  * FUNCTION: Complete dma action started by NdisMStartBufferPhysicalMapping
650  * ARGUMENTS:
651  *     - MiniportAdapterHandle: handle originally input to MiniportInitialize
652  *     - Buffer: NDIS_BUFFER to complete the mapping on
653  *     - PhysicalMapRegister: the chosen map register
654  * NOTES:
655  *     - May be called at IRQL <= DISPATCH_LEVEL
656  */
657 {
658   PLOGICAL_ADAPTER Adapter;
659   VOID *CurrentVa;
660   ULONG Length;
661 
662   ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
663   ASSERT(MiniportAdapterHandle && Buffer);
664 
665   Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle;
666   CurrentVa = MmGetMdlVirtualAddress(Buffer);
667   Length = MmGetMdlByteCount(Buffer);
668 
669   Adapter->NdisMiniportBlock.SystemAdapterObject->DmaOperations->FlushAdapterBuffers(
670       Adapter->NdisMiniportBlock.SystemAdapterObject, Buffer,
671       Adapter->NdisMiniportBlock.MapRegisters[PhysicalMapRegister].MapRegister,
672       CurrentVa, Length,
673       Adapter->NdisMiniportBlock.MapRegisters[PhysicalMapRegister].WriteToDevice);
674 }
675 
676 /*
677  * @implemented
678  */
679 VOID
680 EXPORT
NdisMDeregisterDmaChannel(IN NDIS_HANDLE MiniportDmaHandle)681 NdisMDeregisterDmaChannel(
682     IN  NDIS_HANDLE    MiniportDmaHandle)
683 {
684     PNDIS_DMA_BLOCK DmaBlock = MiniportDmaHandle;
685     PDMA_ADAPTER AdapterObject = (PDMA_ADAPTER)DmaBlock->SystemAdapterObject;
686 
687     if (AdapterObject == ((PLOGICAL_ADAPTER)DmaBlock->Miniport)->NdisMiniportBlock.SystemAdapterObject)
688         ((PLOGICAL_ADAPTER)DmaBlock->Miniport)->NdisMiniportBlock.SystemAdapterObject = NULL;
689 
690     AdapterObject->DmaOperations->PutDmaAdapter(AdapterObject);
691 
692     ExFreePool(DmaBlock);
693 }
694 
695 /*
696  * @implemented
697  */
698 VOID
699 EXPORT
NdisMDeregisterInterrupt(IN PNDIS_MINIPORT_INTERRUPT Interrupt)700 NdisMDeregisterInterrupt(
701     IN  PNDIS_MINIPORT_INTERRUPT    Interrupt)
702 /*
703  * FUNCTION: Releases an interrupt vector
704  * ARGUMENTS:
705  *     Interrupt = Pointer to interrupt object
706  */
707 {
708     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
709     IoDisconnectInterrupt(Interrupt->InterruptObject);
710     Interrupt->Miniport->RegisteredInterrupts--;
711 
712     if (Interrupt->Miniport->Interrupt == Interrupt)
713         Interrupt->Miniport->Interrupt = NULL;
714 }
715 
716 /*
717  * @implemented
718  */
719 VOID
720 EXPORT
NdisMFreeMapRegisters(IN NDIS_HANDLE MiniportAdapterHandle)721 NdisMFreeMapRegisters(
722     IN  NDIS_HANDLE MiniportAdapterHandle)
723 /*
724  * FUNCTION: Free previously allocated map registers
725  * ARGUMENTS:
726  *     MiniportAdapterHandle:  Handle originally passed in to MiniportInitialize
727  * NOTES:
728  */
729 {
730   KIRQL                OldIrql;
731   PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle;
732   PDMA_ADAPTER         AdapterObject;
733   UINT                 MapRegistersPerBaseRegister;
734   UINT                 i;
735 
736   NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
737 
738   ASSERT(Adapter);
739 
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"));
744     return;
745   }
746 
747   MapRegistersPerBaseRegister = ((Adapter->NdisMiniportBlock.MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2;
748 
749   AdapterObject = Adapter->NdisMiniportBlock.SystemAdapterObject;
750 
751   KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
752     {
753       for(i = 0; i < Adapter->NdisMiniportBlock.BaseMapRegistersNeeded; i++)
754         {
755           AdapterObject->DmaOperations->FreeMapRegisters(
756               Adapter->NdisMiniportBlock.SystemAdapterObject,
757               Adapter->NdisMiniportBlock.MapRegisters[i].MapRegister,
758               MapRegistersPerBaseRegister);
759         }
760     }
761  KeLowerIrql(OldIrql);
762 
763  AdapterObject->DmaOperations->PutDmaAdapter(AdapterObject);
764  Adapter->NdisMiniportBlock.SystemAdapterObject = NULL;
765 
766  ExFreePool(Adapter->NdisMiniportBlock.MapRegisters);
767 }
768 
769 /*
770  * @implemented
771  */
772 NDIS_STATUS
773 EXPORT
NdisMMapIoSpace(OUT PVOID * VirtualAddress,IN NDIS_HANDLE MiniportAdapterHandle,IN NDIS_PHYSICAL_ADDRESS PhysicalAddress,IN UINT Length)774 NdisMMapIoSpace(
775     OUT PVOID                   *VirtualAddress,
776     IN  NDIS_HANDLE             MiniportAdapterHandle,
777     IN  NDIS_PHYSICAL_ADDRESS   PhysicalAddress,
778     IN  UINT                    Length)
779 /*
780  * FUNCTION: Maps a bus-relative address to a system-wide virtual address
781  * ARGUMENTS:
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
786  * RETURNS:
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
791  * NOTES:
792  *     - Must be called at IRQL = PASSIVE_LEVEL
793  */
794 {
795   PLOGICAL_ADAPTER Adapter = MiniportAdapterHandle;
796   ULONG AddressSpace = 0; /* Memory Space */
797   NDIS_PHYSICAL_ADDRESS TranslatedAddress;
798 
799   PAGED_CODE();
800   ASSERT(VirtualAddress && MiniportAdapterHandle);
801 
802   NDIS_DbgPrint(MAX_TRACE, ("Called\n"));
803 
804   if(!HalTranslateBusAddress(Adapter->NdisMiniportBlock.BusType, Adapter->NdisMiniportBlock.BusNumber,
805                              PhysicalAddress, &AddressSpace, &TranslatedAddress))
806   {
807       NDIS_DbgPrint(MIN_TRACE, ("Unable to translate address\n"));
808       return NDIS_STATUS_RESOURCES;
809   }
810 
811   *VirtualAddress = MmMapIoSpace(TranslatedAddress, Length, MmNonCached);
812 
813   if(!*VirtualAddress) {
814     NDIS_DbgPrint(MIN_TRACE, ("MmMapIoSpace failed\n"));
815     return NDIS_STATUS_RESOURCES;
816   }
817 
818   return NDIS_STATUS_SUCCESS;
819 }
820 
821 /*
822  * @implemented
823  */
824 ULONG
825 EXPORT
NdisMReadDmaCounter(IN NDIS_HANDLE MiniportDmaHandle)826 NdisMReadDmaCounter(
827     IN  NDIS_HANDLE MiniportDmaHandle)
828 {
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;
832 
833   NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
834 
835   return AdapterObject->DmaOperations->ReadDmaCounter(AdapterObject);
836 }
837 
838 /*
839  * @implemented
840  */
841 ULONG
842 EXPORT
NdisMGetDmaAlignment(IN NDIS_HANDLE MiniportAdapterHandle)843 NdisMGetDmaAlignment(
844     IN  NDIS_HANDLE MiniportAdapterHandle)
845 {
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;
849 
850   NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
851 
852   return AdapterObject->DmaOperations->GetDmaAlignment(AdapterObject);
853 }
854 
855 /*
856  * @implemented
857  */
858 NDIS_STATUS
859 EXPORT
NdisMRegisterDmaChannel(OUT PNDIS_HANDLE MiniportDmaHandle,IN NDIS_HANDLE MiniportAdapterHandle,IN UINT DmaChannel,IN BOOLEAN Dma32BitAddresses,IN PNDIS_DMA_DESCRIPTION DmaDescription,IN ULONG MaximumLength)860 NdisMRegisterDmaChannel(
861     OUT PNDIS_HANDLE            MiniportDmaHandle,
862     IN  NDIS_HANDLE             MiniportAdapterHandle,
863     IN  UINT                    DmaChannel,
864     IN  BOOLEAN                 Dma32BitAddresses,
865     IN  PNDIS_DMA_DESCRIPTION   DmaDescription,
866     IN  ULONG                   MaximumLength)
867 {
868   PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle;
869   DEVICE_DESCRIPTION DeviceDesc;
870   ULONG MapRegisters;
871   PNDIS_DMA_BLOCK DmaBlock;
872 
873   NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
874 
875   RtlZeroMemory(&DeviceDesc, sizeof(DEVICE_DESCRIPTION));
876 
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;
890 
891 
892   DmaBlock = ExAllocatePool(NonPagedPool, sizeof(NDIS_DMA_BLOCK));
893   if (!DmaBlock) {
894       NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n"));
895       return NDIS_STATUS_RESOURCES;
896   }
897 
898   DmaBlock->SystemAdapterObject = (PVOID)IoGetDmaAdapter(Adapter->NdisMiniportBlock.PhysicalDeviceObject, &DeviceDesc, &MapRegisters);
899 
900   if (!DmaBlock->SystemAdapterObject) {
901       NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n"));
902       ExFreePool(DmaBlock);
903       return NDIS_STATUS_RESOURCES;
904   }
905 
906   Adapter->NdisMiniportBlock.SystemAdapterObject = (PDMA_ADAPTER)DmaBlock->SystemAdapterObject;
907 
908   KeInitializeEvent(&DmaBlock->AllocationEvent, NotificationEvent, FALSE);
909 
910   DmaBlock->Miniport = Adapter;
911 
912   *MiniportDmaHandle = DmaBlock;
913 
914   return NDIS_STATUS_SUCCESS;
915 }
916 
917 /*
918  * @implemented
919  */
920 VOID
921 EXPORT
NdisAllocateDmaChannel(OUT PNDIS_STATUS Status,OUT PNDIS_HANDLE NdisDmaHandle,IN NDIS_HANDLE NdisAdapterHandle,IN PNDIS_DMA_DESCRIPTION DmaDescription,IN ULONG MaximumLength)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)
927 {
928     *Status = NdisMRegisterDmaChannel(NdisDmaHandle,
929                                       NdisAdapterHandle,
930                                       0,
931                                       FALSE,
932                                       DmaDescription,
933                                       MaximumLength);
934 }
935 
936 /*
937  * @implemented
938  */
939 NDIS_STATUS
940 EXPORT
NdisMRegisterInterrupt(OUT PNDIS_MINIPORT_INTERRUPT Interrupt,IN NDIS_HANDLE MiniportAdapterHandle,IN UINT InterruptVector,IN UINT InterruptLevel,IN BOOLEAN RequestIsr,IN BOOLEAN SharedInterrupt,IN NDIS_INTERRUPT_MODE InterruptMode)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)
949 /*
950  * FUNCTION: Claims access to an interrupt vector
951  * ARGUMENTS:
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
959  * RETURNS:
960  *     Status of operation
961  */
962 {
963   NTSTATUS Status;
964   ULONG MappedIRQ;
965   KIRQL DIrql;
966   KAFFINITY Affinity;
967   PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle;
968 
969   NDIS_DbgPrint(MAX_TRACE, ("Called. InterruptVector (0x%X)  InterruptLevel (0x%X)  "
970       "SharedInterrupt (%d)  InterruptMode (0x%X)\n",
971       InterruptVector, InterruptLevel, SharedInterrupt, InterruptMode));
972 
973   RtlZeroMemory(Interrupt, sizeof(NDIS_MINIPORT_INTERRUPT));
974 
975   KeInitializeSpinLock(&Interrupt->DpcCountLock);
976 
977   KeInitializeDpc(&Interrupt->InterruptDpc, HandleDeferredProcessing, Adapter);
978 
979   KeInitializeEvent(&Interrupt->DpcsCompletedEvent, NotificationEvent, FALSE);
980 
981   Interrupt->SharedInterrupt = SharedInterrupt;
982   Interrupt->IsrRequested = RequestIsr;
983   Interrupt->Miniport = &Adapter->NdisMiniportBlock;
984 
985   MappedIRQ = HalGetInterruptVector(Adapter->NdisMiniportBlock.BusType, Adapter->NdisMiniportBlock.BusNumber,
986                                     InterruptLevel, InterruptVector, &DIrql,
987                                     &Affinity);
988 
989   NDIS_DbgPrint(MAX_TRACE, ("Connecting to interrupt vector (0x%X)  Affinity (0x%X).\n", MappedIRQ, Affinity));
990 
991   Status = IoConnectInterrupt(&Interrupt->InterruptObject, ServiceRoutine, Interrupt, &Interrupt->DpcCountLock, MappedIRQ,
992       DIrql, DIrql, InterruptMode, SharedInterrupt, Affinity, FALSE);
993 
994   NDIS_DbgPrint(MAX_TRACE, ("Leaving. Status (0x%X).\n", Status));
995 
996   if (NT_SUCCESS(Status)) {
997       Adapter->NdisMiniportBlock.Interrupt = Interrupt;
998       Adapter->NdisMiniportBlock.RegisteredInterrupts++;
999       return NDIS_STATUS_SUCCESS;
1000   }
1001 
1002   if (Status == STATUS_INSUFFICIENT_RESOURCES)
1003     {
1004         /* FIXME: Log error */
1005       NDIS_DbgPrint(MIN_TRACE, ("Resource conflict!\n"));
1006       return NDIS_STATUS_RESOURCE_CONFLICT;
1007     }
1008 
1009   NDIS_DbgPrint(MIN_TRACE, ("Function failed. Status (0x%X).\n", Status));
1010   return NDIS_STATUS_FAILURE;
1011 }
1012 
1013 /*
1014  * @implemented
1015  */
1016 NDIS_STATUS
1017 EXPORT
NdisMRegisterIoPortRange(OUT PVOID * PortOffset,IN NDIS_HANDLE MiniportAdapterHandle,IN UINT InitialPort,IN UINT NumberOfPorts)1018 NdisMRegisterIoPortRange(
1019     OUT PVOID       *PortOffset,
1020     IN  NDIS_HANDLE MiniportAdapterHandle,
1021     IN  UINT        InitialPort,
1022     IN  UINT        NumberOfPorts)
1023 /*
1024  * FUNCTION: Sets up driver access to device I/O ports
1025  * ARGUMENTS:
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
1030  * RETURNS:
1031  *     Status of operation
1032  */
1033 {
1034   PHYSICAL_ADDRESS     PortAddress, TranslatedAddress;
1035   PLOGICAL_ADAPTER Adapter  = (PLOGICAL_ADAPTER)MiniportAdapterHandle;
1036   ULONG                AddressSpace = 1;    /* FIXME The HAL handles this wrong atm */
1037 
1038   *PortOffset = 0;
1039 
1040   NDIS_DbgPrint(MAX_TRACE, ("Called - InitialPort 0x%x, NumberOfPorts 0x%x\n", InitialPort, NumberOfPorts));
1041 
1042   memset(&PortAddress, 0, sizeof(PortAddress));
1043 
1044   /*
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).
1049    */
1050   if(InitialPort)
1051       PortAddress = RtlConvertUlongToLargeInteger(InitialPort);
1052   else
1053       ASSERT(FALSE);
1054 
1055   NDIS_DbgPrint(MAX_TRACE, ("Translating address 0x%x 0x%x\n", PortAddress.u.HighPart, PortAddress.u.LowPart));
1056 
1057   if(!HalTranslateBusAddress(Adapter->NdisMiniportBlock.BusType, Adapter->NdisMiniportBlock.BusNumber,
1058                              PortAddress, &AddressSpace, &TranslatedAddress))
1059     {
1060       NDIS_DbgPrint(MIN_TRACE, ("Unable to translate address\n"));
1061       return NDIS_STATUS_RESOURCES;
1062     }
1063 
1064   NDIS_DbgPrint(MAX_TRACE, ("Hal returned AddressSpace=0x%x TranslatedAddress=0x%x 0x%x\n",
1065                             AddressSpace, TranslatedAddress.u.HighPart, TranslatedAddress.u.LowPart));
1066 
1067   if(AddressSpace)
1068     {
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;
1073     }
1074 
1075   NDIS_DbgPrint(MAX_TRACE, ("calling MmMapIoSpace\n"));
1076 
1077   *PortOffset = MmMapIoSpace(TranslatedAddress, NumberOfPorts, MmNonCached);
1078   NDIS_DbgPrint(MAX_TRACE, ("Returning 0x%x for port range\n", *PortOffset));
1079 
1080   if(!*PortOffset) {
1081     NDIS_DbgPrint(MIN_TRACE, ("MmMapIoSpace failed\n"));
1082     return NDIS_STATUS_RESOURCES;
1083   }
1084 
1085   return NDIS_STATUS_SUCCESS;
1086 }
1087 
1088 /*
1089  * @implemented
1090  */
1091 VOID
1092 EXPORT
NdisMDeregisterIoPortRange(IN NDIS_HANDLE MiniportAdapterHandle,IN UINT InitialPort,IN UINT NumberOfPorts,IN PVOID PortOffset)1093 NdisMDeregisterIoPortRange(IN  NDIS_HANDLE MiniportAdapterHandle,
1094                            IN  UINT        InitialPort,
1095                            IN  UINT        NumberOfPorts,
1096                            IN  PVOID       PortOffset)
1097 /*
1098  * FUNCTION: Releases a register mapping to I/O ports
1099  * ARGUMENTS:
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
1104  */
1105 {
1106     PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle;
1107     PHYSICAL_ADDRESS PortAddress = RtlConvertUlongToLargeInteger(InitialPort);
1108     PHYSICAL_ADDRESS TranslatedAddress;
1109     ULONG AddressSpace = 1;
1110 
1111     NDIS_DbgPrint(MAX_TRACE, ("Called - InitialPort 0x%x, NumberOfPorts 0x%x, Port Offset 0x%x\n", InitialPort, NumberOfPorts, PortOffset));
1112 
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))
1116     {
1117         NDIS_DbgPrint(MIN_TRACE, ("Unable to translate address\n"));
1118         return;
1119     }
1120 
1121     /* Make sure we got the same translation as last time */
1122     ASSERT(TranslatedAddress.QuadPart == (ULONG_PTR)PortOffset);
1123 
1124     /* Check if we're in memory space */
1125     if (!AddressSpace)
1126     {
1127         NDIS_DbgPrint(MAX_TRACE, ("Calling MmUnmapIoSpace\n"));
1128 
1129         /* Unmap the memory */
1130         MmUnmapIoSpace(PortOffset, NumberOfPorts);
1131     }
1132 }
1133 
1134 /*
1135  * @implemented
1136  */
1137 VOID
1138 EXPORT
NdisMUnmapIoSpace(IN NDIS_HANDLE MiniportAdapterHandle,IN PVOID VirtualAddress,IN UINT Length)1139 NdisMUnmapIoSpace(
1140     IN  NDIS_HANDLE MiniportAdapterHandle,
1141     IN  PVOID       VirtualAddress,
1142     IN  UINT        Length)
1143 /*
1144  * FUNCTION: Un-maps space previously mapped with NdisMMapIoSpace
1145  * ARGUMENTS:
1146  *     MiniportAdapterHandle: handle originally passed into MiniportInitialize
1147  *     VirtualAddress: Address to un-map
1148  *     Length: length of the mapped memory space
1149  * NOTES:
1150  *     - Must be called at IRQL = PASSIVE_LEVEL
1151  *     - Must only be called from MiniportInitialize and MiniportHalt
1152  *     - See also: NdisMMapIoSpace
1153  * BUGS:
1154  *     - Depends on MmUnmapIoSpace to Do The Right Thing in all cases
1155  */
1156 {
1157   PAGED_CODE();
1158 
1159   ASSERT(MiniportAdapterHandle);
1160 
1161   MmUnmapIoSpace(VirtualAddress, Length);
1162 }
1163 
1164 /*
1165  * @implemented
1166  */
1167 NDIS_STATUS
1168 EXPORT
NdisMInitializeScatterGatherDma(IN NDIS_HANDLE MiniportAdapterHandle,IN BOOLEAN Dma64BitAddresses,IN ULONG MaximumPhysicalMapping)1169 NdisMInitializeScatterGatherDma(
1170     IN  NDIS_HANDLE MiniportAdapterHandle,
1171     IN  BOOLEAN     Dma64BitAddresses,
1172     IN  ULONG       MaximumPhysicalMapping)
1173 /*
1174  * FUNCTION:
1175  * ARGUMENTS:
1176  * NOTES:
1177  *    NDIS 5.0
1178  */
1179 {
1180     PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle;
1181     ULONG MapRegisters;
1182     DEVICE_DESCRIPTION DeviceDesc;
1183 
1184     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1185 
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;
1189     }
1190 
1191     RtlZeroMemory(&DeviceDesc, sizeof(DEVICE_DESCRIPTION));
1192 
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;
1201 
1202     Adapter->NdisMiniportBlock.SystemAdapterObject =
1203          IoGetDmaAdapter(Adapter->NdisMiniportBlock.PhysicalDeviceObject, &DeviceDesc, &MapRegisters);
1204 
1205     if (!Adapter->NdisMiniportBlock.SystemAdapterObject)
1206         return NDIS_STATUS_RESOURCES;
1207 
1208     /* FIXME: Right now we just use this as a place holder */
1209     Adapter->NdisMiniportBlock.ScatterGatherListSize = 1;
1210 
1211     return NDIS_STATUS_SUCCESS;
1212 }
1213 
1214 
1215 /*
1216  * @implemented
1217  */
1218 VOID
1219 EXPORT
NdisMapIoSpace(OUT PNDIS_STATUS Status,OUT PVOID * VirtualAddress,IN NDIS_HANDLE NdisAdapterHandle,IN NDIS_PHYSICAL_ADDRESS PhysicalAddress,IN UINT Length)1220 NdisMapIoSpace(
1221     OUT PNDIS_STATUS            Status,
1222     OUT PVOID                   *VirtualAddress,
1223     IN  NDIS_HANDLE             NdisAdapterHandle,
1224     IN  NDIS_PHYSICAL_ADDRESS   PhysicalAddress,
1225     IN  UINT                    Length)
1226 /*
1227  * FUNCTION:
1228  * ARGUMENTS:
1229  * NOTES:
1230  *    NDIS 4.0
1231  */
1232 {
1233     *Status = NdisMMapIoSpace(VirtualAddress,
1234                               NdisAdapterHandle,
1235                               PhysicalAddress,
1236                               Length);
1237 }
1238 
1239 
1240 /*
1241  * @implemented
1242  */
1243 VOID
1244 EXPORT
NdisFreeDmaChannel(IN PNDIS_HANDLE NdisDmaHandle)1245 NdisFreeDmaChannel(
1246     IN  PNDIS_HANDLE    NdisDmaHandle)
1247 /*
1248  * FUNCTION:
1249  * ARGUMENTS:
1250  * NOTES:
1251  *    NDIS 4.0
1252  */
1253 {
1254     NdisMDeregisterDmaChannel(NdisDmaHandle);
1255 }
1256 
1257 
1258 
1259 /* EOF */
1260