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