sync to trunk revision 36500
[reactos.git] / reactos / 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 \f
17 VOID NTAPI HandleDeferredProcessing(
18 IN PKDPC Dpc,
19 IN PVOID DeferredContext,
20 IN PVOID SystemArgument1,
21 IN PVOID SystemArgument2)
22 /*
23 * FUNCTION: Deferred interrupt processing routine
24 * ARGUMENTS:
25 * Dpc = Pointer to DPC object
26 * DeferredContext = Pointer to context information (LOGICAL_ADAPTER)
27 * SystemArgument1 = Unused
28 * SystemArgument2 = Unused
29 */
30 {
31 PLOGICAL_ADAPTER Adapter = GET_LOGICAL_ADAPTER(DeferredContext);
32
33 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
34
35 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
36
37 /* Call the deferred interrupt service handler for this adapter */
38 (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.HandleInterruptHandler)(
39 Adapter->NdisMiniportBlock.MiniportAdapterContext);
40
41 /* re-enable the interrupt */
42 NDIS_DbgPrint(MAX_TRACE, ("re-enabling the interrupt\n"));
43 if(Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.EnableInterruptHandler)
44 (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.EnableInterruptHandler)(
45 Adapter->NdisMiniportBlock.MiniportAdapterContext);
46
47 NDIS_DbgPrint(MAX_TRACE, ("Leaving.\n"));
48 }
49
50 \f
51 BOOLEAN NTAPI ServiceRoutine(
52 IN PKINTERRUPT Interrupt,
53 IN PVOID ServiceContext)
54 /*
55 * FUNCTION: Interrupt service routine
56 * ARGUMENTS:
57 * Interrupt = Pointer to interrupt object
58 * ServiceContext = Pointer to context information (LOGICAL_ADAPTER)
59 * RETURNS
60 * TRUE if a miniport controlled device generated the interrupt
61 */
62 {
63 BOOLEAN InterruptRecognized;
64 BOOLEAN QueueMiniportHandleInterrupt;
65 PNDIS_MINIPORT_BLOCK Adapter = (PNDIS_MINIPORT_BLOCK)ServiceContext;
66
67 NDIS_DbgPrint(MAX_TRACE, ("Called. Adapter (0x%X)\n", Adapter));
68
69 (*Adapter->DriverHandle->MiniportCharacteristics.ISRHandler)(
70 &InterruptRecognized,
71 &QueueMiniportHandleInterrupt,
72 Adapter->MiniportAdapterContext);
73
74 if (QueueMiniportHandleInterrupt)
75 {
76 NDIS_DbgPrint(MAX_TRACE, ("Queueing DPC.\n"));
77 KeInsertQueueDpc(&Adapter->Interrupt->InterruptDpc, NULL, NULL);
78 }
79
80 NDIS_DbgPrint(MAX_TRACE, ("Leaving.\n"));
81
82 return InterruptRecognized;
83 }
84
85 \f
86 /*
87 * @unimplemented
88 */
89 VOID
90 EXPORT
91 NdisCompleteDmaTransfer(
92 OUT PNDIS_STATUS Status,
93 IN PNDIS_HANDLE NdisDmaHandle,
94 IN PNDIS_BUFFER Buffer,
95 IN ULONG Offset,
96 IN ULONG Length,
97 IN BOOLEAN WriteToDevice)
98 {
99 UNIMPLEMENTED
100 }
101
102 \f
103 /*
104 * @implemented
105 */
106 VOID
107 EXPORT
108 NdisImmediateReadPortUchar(
109 IN NDIS_HANDLE WrapperConfigurationContext,
110 IN ULONG Port,
111 OUT PUCHAR Data)
112 {
113 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
114 *Data = READ_PORT_UCHAR(UlongToPtr(Port)); // FIXME: What to do with WrapperConfigurationContext?
115 }
116
117 \f
118 /*
119 * @implemented
120 */
121 VOID
122 EXPORT
123 NdisImmediateReadPortUlong(
124 IN NDIS_HANDLE WrapperConfigurationContext,
125 IN ULONG Port,
126 OUT PULONG Data)
127 {
128 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
129 *Data = READ_PORT_ULONG(UlongToPtr(Port)); // FIXME: What to do with WrapperConfigurationContext?
130 }
131
132 \f
133 /*
134 * @implemented
135 */
136 VOID
137 EXPORT
138 NdisImmediateReadPortUshort(
139 IN NDIS_HANDLE WrapperConfigurationContext,
140 IN ULONG Port,
141 OUT PUSHORT Data)
142 {
143 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
144 *Data = READ_PORT_USHORT(UlongToPtr(Port)); // FIXME: What to do with WrapperConfigurationContext?
145 }
146
147 \f
148 /*
149 * @implemented
150 */
151 VOID
152 EXPORT
153 NdisImmediateWritePortUchar(
154 IN NDIS_HANDLE WrapperConfigurationContext,
155 IN ULONG Port,
156 IN UCHAR Data)
157 {
158 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
159 WRITE_PORT_UCHAR(UlongToPtr(Port), Data); // FIXME: What to do with WrapperConfigurationContext?
160 }
161
162 \f
163 /*
164 * @implemented
165 */
166 VOID
167 EXPORT
168 NdisImmediateWritePortUlong(
169 IN NDIS_HANDLE WrapperConfigurationContext,
170 IN ULONG Port,
171 IN ULONG Data)
172 {
173 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
174 WRITE_PORT_ULONG(UlongToPtr(Port), Data); // FIXME: What to do with WrapperConfigurationContext?
175 }
176
177 \f
178 /*
179 * @implemented
180 */
181 VOID
182 EXPORT
183 NdisImmediateWritePortUshort(
184 IN NDIS_HANDLE WrapperConfigurationContext,
185 IN ULONG Port,
186 IN USHORT Data)
187 {
188 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
189 WRITE_PORT_USHORT(UlongToPtr(Port), Data); // FIXME: What to do with WrapperConfigurationContext?
190 }
191
192 \f
193 IO_ALLOCATION_ACTION NTAPI NdisMapRegisterCallback (
194 IN PDEVICE_OBJECT DeviceObject,
195 IN PIRP Irp,
196 IN PVOID MapRegisterBase,
197 IN PVOID Context)
198 /*
199 * FUNCTION: Called back during reservation of map registers
200 * ARGUMENTS:
201 * DeviceObject: Device object of the deivce setting up DMA
202 * Irp: Reserved; must be ignored
203 * MapRegisterBase: Map registers assigned for transfer
204 * Context: LOGICAL_ADAPTER object of the requesting miniport
205 * NOTES:
206 * - Called once per BaseMapRegister (see NdisMAllocateMapRegisters)
207 * - Called at IRQL = DISPATCH_LEVEL
208 */
209 {
210 PNDIS_MINIPORT_BLOCK Adapter = (PNDIS_MINIPORT_BLOCK)Context;
211
212 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
213
214 Adapter->MapRegisters[Adapter->CurrentMapRegister].MapRegister = MapRegisterBase;
215
216 NDIS_DbgPrint(MAX_TRACE, ("setting event and leaving.\n"));
217
218 KeSetEvent(Adapter->AllocationEvent, 0, FALSE);
219
220 /* this is only the thing to do for busmaster NICs */
221 return DeallocateObjectKeepRegisters;
222 }
223
224 \f
225 /*
226 * @implemented
227 */
228 NDIS_STATUS
229 EXPORT
230 NdisMAllocateMapRegisters(
231 IN NDIS_HANDLE MiniportAdapterHandle,
232 IN UINT DmaChannel,
233 IN BOOLEAN DmaSize,
234 IN ULONG BaseMapRegistersNeeded,
235 IN ULONG MaximumBufferSize)
236 /*
237 * FUNCTION: Allocate map registers for use in DMA transfers
238 * ARGUMENTS:
239 * MiniportAdapterHandle: Passed in to MiniportInitialize
240 * DmaChannel: DMA channel to use
241 * DmaSize: bit width of DMA transfers
242 * BaseMapRegistersNeeded: number of base map registers requested
243 * MaximumBufferSize: largest single buffer transferred
244 * RETURNS:
245 * NDIS_STATUS_SUCCESS on success
246 * NDIS_STATUS_RESOURCES on failure
247 * NOTES:
248 * - the win2k ddk and the nt4 ddk have conflicting prototypes for this.
249 * I'm implementing the 2k one.
250 * - do not confuse a "base map register" with a "map register" - they
251 * are different. Only NDIS seems to use the base concept. The idea
252 * is that a miniport supplies the number of base map registers it will
253 * need, which is equal to the number of DMA send buffers it manages.
254 * NDIS then allocates a number of map registers to go with each base
255 * map register, so that a driver just has to send the base map register
256 * number during dma operations and NDIS can find the group of real
257 * map registers that represent the transfer.
258 * - Because of the above sillyness, you can only specify a few base map
259 * registers at most. a 1514-byte packet is two map registers at 4k
260 * page size.
261 * - NDIS limits the total number of allocated map registers to 64,
262 * which (in the case of the above example) limits the number of base
263 * map registers to 32.
264 */
265 {
266 DEVICE_DESCRIPTION Description;
267 PDMA_ADAPTER AdapterObject = 0;
268 UINT MapRegistersPerBaseRegister = 0;
269 ULONG AvailableMapRegisters;
270 NTSTATUS NtStatus;
271 PLOGICAL_ADAPTER Adapter;
272 PDEVICE_OBJECT DeviceObject = 0;
273 KEVENT AllocationEvent;
274 KIRQL OldIrql;
275
276 NDIS_DbgPrint(MAX_TRACE, ("called: Handle 0x%x, DmaChannel 0x%x, DmaSize 0x%x, BaseMapRegsNeeded: 0x%x, MaxBuffer: 0x%x.\n",
277 MiniportAdapterHandle, DmaChannel, DmaSize, BaseMapRegistersNeeded, MaximumBufferSize));
278
279 memset(&Description,0,sizeof(Description));
280
281 Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle;
282
283 ASSERT(Adapter);
284
285 /* only bus masters may call this routine */
286 ASSERT(Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_BUS_MASTER);
287 if(!(Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_BUS_MASTER))
288 return NDIS_STATUS_SUCCESS;
289
290 DeviceObject = Adapter->NdisMiniportBlock.DeviceObject;
291
292 KeInitializeEvent(&AllocationEvent, NotificationEvent, FALSE);
293 Adapter->NdisMiniportBlock.AllocationEvent = &AllocationEvent;
294
295 /*
296 * map registers correlate to physical pages. ndis documents a
297 * maximum of 64 map registers that it will return.
298 * at 4k pages, a 1514-byte buffer can span not more than 2 pages.
299 *
300 * the number of registers required for a given physical mapping
301 * is (first register + last register + one per page size),
302 * given that physical mapping is > 2.
303 */
304
305 /* unhandled corner case: {1,2}-byte max buffer size */
306 ASSERT(MaximumBufferSize > 2);
307 MapRegistersPerBaseRegister = ((MaximumBufferSize-2) / (2*PAGE_SIZE)) + 2;
308
309 Description.Version = DEVICE_DESCRIPTION_VERSION;
310 Description.Master = TRUE; /* implied by calling this function */
311 Description.ScatterGather = TRUE; /* XXX UNTRUE: All BM DMA are S/G (ms seems to do this) */
312 Description.Dma32BitAddresses = DmaSize;
313 Description.BusNumber = Adapter->NdisMiniportBlock.BusNumber;
314 Description.InterfaceType = Adapter->NdisMiniportBlock.BusType;
315 Description.DmaChannel = DmaChannel;
316 Description.MaximumLength = MaximumBufferSize;
317
318 if(Adapter->NdisMiniportBlock.AdapterType == Isa)
319 {
320 /* system dma */
321 if(DmaChannel < 4)
322 Description.DmaWidth = Width8Bits;
323 else
324 Description.DmaWidth = Width16Bits;
325
326 Description.DmaSpeed = Compatible;
327 }
328 else if(Adapter->NdisMiniportBlock.AdapterType == PCIBus)
329 {
330 if(DmaSize == NDIS_DMA_64BITS)
331 Description.Dma64BitAddresses = TRUE;
332 else
333 Description.Dma32BitAddresses = TRUE;
334 }
335 else
336 {
337 NDIS_DbgPrint(MIN_TRACE, ("Unsupported bus type\n"));
338 ASSERT(0);
339 }
340
341 AdapterObject = IoGetDmaAdapter(
342 Adapter->NdisMiniportBlock.PhysicalDeviceObject, &Description, &AvailableMapRegisters);
343
344 if(!AdapterObject)
345 {
346 NDIS_DbgPrint(MIN_TRACE, ("Unable to allocate an adapter object; bailing out\n"));
347 return NDIS_STATUS_RESOURCES;
348 }
349
350 Adapter->NdisMiniportBlock.SystemAdapterObject = AdapterObject;
351
352 if(AvailableMapRegisters < MapRegistersPerBaseRegister)
353 {
354 NDIS_DbgPrint(MIN_TRACE, ("Didn't get enough map registers from hal - requested 0x%x, got 0x%x\n",
355 MapRegistersPerBaseRegister, AvailableMapRegisters));
356
357 return NDIS_STATUS_RESOURCES;
358 }
359
360 /* allocate & zero space in the miniport block for the registers */
361 Adapter->NdisMiniportBlock.MapRegisters = ExAllocatePool(NonPagedPool, BaseMapRegistersNeeded * sizeof(MAP_REGISTER_ENTRY));
362 if(!Adapter->NdisMiniportBlock.MapRegisters)
363 {
364 NDIS_DbgPrint(MIN_TRACE, ("insufficient resources.\n"));
365 return NDIS_STATUS_RESOURCES;
366 }
367
368 memset(Adapter->NdisMiniportBlock.MapRegisters, 0, BaseMapRegistersNeeded * sizeof(MAP_REGISTER_ENTRY));
369 Adapter->NdisMiniportBlock.BaseMapRegistersNeeded = (USHORT)BaseMapRegistersNeeded;
370
371 while(BaseMapRegistersNeeded)
372 {
373 NDIS_DbgPrint(MAX_TRACE, ("iterating, basemapregistersneeded = %d\n", BaseMapRegistersNeeded));
374
375 BaseMapRegistersNeeded--;
376 Adapter->NdisMiniportBlock.CurrentMapRegister = (USHORT)BaseMapRegistersNeeded;
377 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
378 {
379 NtStatus = AdapterObject->DmaOperations->AllocateAdapterChannel(
380 AdapterObject, DeviceObject, MapRegistersPerBaseRegister,
381 NdisMapRegisterCallback, Adapter);
382 }
383 KeLowerIrql(OldIrql);
384
385 if(!NT_SUCCESS(NtStatus))
386 {
387 NDIS_DbgPrint(MIN_TRACE, ("IoAllocateAdapterChannel failed: 0x%x\n", NtStatus));
388 ExFreePool(Adapter->NdisMiniportBlock.MapRegisters);
389 return NDIS_STATUS_RESOURCES;
390 }
391
392 NDIS_DbgPrint(MAX_TRACE, ("waiting on event\n"));
393
394 NtStatus = KeWaitForSingleObject(&AllocationEvent, Executive, KernelMode, FALSE, 0);
395
396 if(!NT_SUCCESS(NtStatus))
397 {
398 NDIS_DbgPrint(MIN_TRACE, ("KeWaitForSingleObject failed: 0x%x\n", NtStatus));
399 ExFreePool(Adapter->NdisMiniportBlock.MapRegisters);
400 return NDIS_STATUS_RESOURCES;
401 }
402
403 NDIS_DbgPrint(MAX_TRACE, ("resetting event\n"));
404
405 KeResetEvent(&AllocationEvent);
406 }
407
408 NDIS_DbgPrint(MAX_TRACE, ("returning success\n"));
409 return NDIS_STATUS_SUCCESS;
410 }
411
412 \f
413 /*
414 * @implemented
415 */
416 VOID
417 EXPORT
418 NdisMStartBufferPhysicalMapping(
419 IN NDIS_HANDLE MiniportAdapterHandle,
420 IN PNDIS_BUFFER Buffer,
421 IN ULONG PhysicalMapRegister,
422 IN BOOLEAN WriteToDevice,
423 OUT PNDIS_PHYSICAL_ADDRESS_UNIT PhysicalAddressArray,
424 OUT PUINT ArraySize)
425 /*
426 * FUNCTION: Sets up map registers for a bus-master DMA transfer
427 * ARGUMENTS:
428 * MiniportAdapterHandle: handle originally input to MiniportInitialize
429 * Buffer: data to be transferred
430 * PhysicalMapRegister: specifies the map register to set up
431 * WriteToDevice: if true, data is being written to the device; else it is being read
432 * PhysicalAddressArray: list of mapped ranges suitable for DMA with the device
433 * ArraySize: number of elements in PhysicalAddressArray
434 * NOTES:
435 * - Must be called at IRQL <= DISPATCH_LEVEL
436 * - The basic idea: call IoMapTransfer() in a loop as many times as it takes
437 * in order to map all of the virtual memory to physical memoroy readable
438 * by the device
439 * - The caller supplies storage for the physical address array.
440 */
441 {
442 PLOGICAL_ADAPTER Adapter;
443 PVOID CurrentVa;
444 ULONG TotalLength;
445 PHYSICAL_ADDRESS ReturnedAddress;
446 UINT LoopCount = 0;
447
448 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
449 ASSERT(MiniportAdapterHandle && Buffer && PhysicalAddressArray && ArraySize);
450
451 Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle;
452 CurrentVa = MmGetMdlVirtualAddress(Buffer);
453 TotalLength = MmGetMdlByteCount(Buffer);
454
455 while(TotalLength)
456 {
457 ULONG Length = TotalLength;
458
459 ReturnedAddress = Adapter->NdisMiniportBlock.SystemAdapterObject->DmaOperations->MapTransfer(
460 Adapter->NdisMiniportBlock.SystemAdapterObject, Buffer,
461 Adapter->NdisMiniportBlock.MapRegisters[PhysicalMapRegister].MapRegister,
462 CurrentVa, &Length, WriteToDevice);
463
464 Adapter->NdisMiniportBlock.MapRegisters[PhysicalMapRegister].WriteToDevice = WriteToDevice;
465
466 PhysicalAddressArray[LoopCount].PhysicalAddress = ReturnedAddress;
467 PhysicalAddressArray[LoopCount].Length = Length;
468
469 TotalLength -= Length;
470 CurrentVa = (PVOID)((ULONG_PTR)CurrentVa + Length);
471
472 LoopCount++;
473 }
474
475 *ArraySize = LoopCount;
476 }
477
478 \f
479 /*
480 * @implemented
481 */
482 VOID
483 EXPORT
484 NdisMCompleteBufferPhysicalMapping(
485 IN NDIS_HANDLE MiniportAdapterHandle,
486 IN PNDIS_BUFFER Buffer,
487 IN ULONG PhysicalMapRegister)
488 /*
489 * FUNCTION: Complete dma action started by NdisMStartBufferPhysicalMapping
490 * ARGUMENTS:
491 * - MiniportAdapterHandle: handle originally input to MiniportInitialize
492 * - Buffer: NDIS_BUFFER to complete the mapping on
493 * - PhyscialMapRegister: the chosen map register
494 * NOTES:
495 * - May be called at IRQL <= DISPATCH_LEVEL
496 */
497 {
498 PLOGICAL_ADAPTER Adapter;
499 VOID *CurrentVa;
500 ULONG Length;
501
502 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
503 ASSERT(MiniportAdapterHandle && Buffer);
504
505 Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle;
506 CurrentVa = MmGetMdlVirtualAddress(Buffer);
507 Length = MmGetMdlByteCount(Buffer);
508
509 Adapter->NdisMiniportBlock.SystemAdapterObject->DmaOperations->FlushAdapterBuffers(
510 Adapter->NdisMiniportBlock.SystemAdapterObject, Buffer,
511 Adapter->NdisMiniportBlock.MapRegisters[PhysicalMapRegister].MapRegister,
512 CurrentVa, Length,
513 Adapter->NdisMiniportBlock.MapRegisters[PhysicalMapRegister].WriteToDevice);
514 }
515
516 \f
517 /*
518 * @unimplemented
519 */
520 VOID
521 EXPORT
522 NdisMDeregisterDmaChannel(
523 IN PNDIS_HANDLE MiniportDmaHandle)
524 {
525 UNIMPLEMENTED
526 }
527
528 \f
529 /*
530 * @implemented
531 */
532 VOID
533 EXPORT
534 NdisMDeregisterInterrupt(
535 IN PNDIS_MINIPORT_INTERRUPT Interrupt)
536 /*
537 * FUNCTION: Releases an interrupt vector
538 * ARGUMENTS:
539 * Interrupt = Pointer to interrupt object
540 */
541 {
542 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
543 IoDisconnectInterrupt(Interrupt->InterruptObject);
544 }
545
546 \f
547 /*
548 * @unimplemented
549 */
550 VOID
551 EXPORT
552 NdisMDeregisterIoPortRange(
553 IN NDIS_HANDLE MiniportAdapterHandle,
554 IN UINT InitialPort,
555 IN UINT NumberOfPorts,
556 IN PVOID PortOffset)
557 /*
558 * FUNCTION: Releases a register mapping to I/O ports
559 * ARGUMENTS:
560 * MiniportAdapterHandle = Specifies handle input to MiniportInitialize
561 * InitialPort = Bus-relative base port address of a range to be mapped
562 * NumberOfPorts = Specifies number of ports to be mapped
563 * PortOffset = Pointer to mapped base port address
564 */
565 {
566 NDIS_DbgPrint(MAX_TRACE, ("called - IMPLEMENT ME.\n"));
567 }
568
569 \f
570 /*
571 * @implemented
572 */
573 VOID
574 EXPORT
575 NdisMFreeMapRegisters(
576 IN NDIS_HANDLE MiniportAdapterHandle)
577 /*
578 * FUNCTION: Free previously allocated map registers
579 * ARGUMENTS:
580 * MiniportAdapterHandle: Handle originally passed in to MiniportInitialize
581 * NOTES:
582 */
583 {
584 KIRQL OldIrql;
585 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle;
586 PDMA_ADAPTER AdapterObject;
587 UINT MapRegistersPerBaseRegister;
588 UINT i;
589
590 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
591
592 ASSERT(Adapter);
593
594 /* only bus masters may call this routine */
595 ASSERT(Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_BUS_MASTER);
596 if(!(Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_BUS_MASTER) ||
597 Adapter->NdisMiniportBlock.SystemAdapterObject == NULL)
598 return;
599
600 MapRegistersPerBaseRegister = ((Adapter->NdisMiniportBlock.MaximumPhysicalMapping - 2) / PAGE_SIZE) + 2;
601
602 AdapterObject = Adapter->NdisMiniportBlock.SystemAdapterObject;
603
604 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
605 {
606 for(i = 0; i < Adapter->NdisMiniportBlock.BaseMapRegistersNeeded; i++)
607 {
608 AdapterObject->DmaOperations->FreeMapRegisters(
609 Adapter->NdisMiniportBlock.SystemAdapterObject,
610 Adapter->NdisMiniportBlock.MapRegisters[i].MapRegister,
611 MapRegistersPerBaseRegister);
612 }
613 }
614 KeLowerIrql(OldIrql);
615
616 AdapterObject->DmaOperations->PutDmaAdapter(AdapterObject);
617 Adapter->NdisMiniportBlock.SystemAdapterObject = NULL;
618
619 ExFreePool(Adapter->NdisMiniportBlock.MapRegisters);
620 }
621
622 \f
623 /*
624 * @implemented
625 */
626 NDIS_STATUS
627 EXPORT
628 NdisMMapIoSpace(
629 OUT PVOID *VirtualAddress,
630 IN NDIS_HANDLE MiniportAdapterHandle,
631 IN NDIS_PHYSICAL_ADDRESS PhysicalAddress,
632 IN UINT Length)
633 /*
634 * FUNCTION: Maps a bus-relative address to a system-wide virtual address
635 * ARGUMENTS:
636 * VirtualAddress: receives virtual address of mapping
637 * MiniportAdapterHandle: Handle originally input to MiniportInitialize
638 * PhysicalAddress: bus-relative address to map
639 * Length: Number of bytes to map
640 * RETURNS:
641 * NDIS_STATUS_SUCCESS: the operation completed successfully
642 * NDIS_STATUS_RESOURCE_CONFLICT: the physical address range is already claimed
643 * NDIS_STATUS_RESOURCES: insufficient resources to complete the mapping
644 * NDIS_STATUS_FAILURE: a general failure has occured
645 * NOTES:
646 * - Must be called at IRQL = PASSIVE_LEVEL
647 * BUGS:
648 * - Only supports things that MmMapIoSpace internally supports - what
649 * about considering bus type, etc?
650 * - doesn't track resources allocated...
651 */
652 {
653 PAGED_CODE();
654 ASSERT(VirtualAddress && MiniportAdapterHandle);
655
656 *VirtualAddress = MmMapIoSpace(PhysicalAddress, Length, MmNonCached);
657
658 if(!*VirtualAddress)
659 return NDIS_STATUS_RESOURCES;
660
661 return NDIS_STATUS_SUCCESS;
662 }
663
664 \f
665 /*
666 * @implemented
667 */
668 ULONG
669 EXPORT
670 NdisMReadDmaCounter(
671 IN NDIS_HANDLE MiniportDmaHandle)
672 {
673 PNDIS_MINIPORT_BLOCK MiniportBlock = (PNDIS_MINIPORT_BLOCK)MiniportDmaHandle;
674 PDMA_ADAPTER AdapterObject = MiniportBlock->SystemAdapterObject;
675
676 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
677
678 if (AdapterObject == NULL)
679 return 0;
680
681 return AdapterObject->DmaOperations->ReadDmaCounter(AdapterObject);
682 }
683
684 \f
685 /*
686 * @implemented
687 */
688 ULONG
689 EXPORT
690 NdisMGetDmaAlignment(
691 IN NDIS_HANDLE MiniportDmaHandle)
692 {
693 PNDIS_MINIPORT_BLOCK MiniportBlock = (PNDIS_MINIPORT_BLOCK)MiniportDmaHandle;
694 PDMA_ADAPTER AdapterObject = MiniportBlock->SystemAdapterObject;
695
696 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
697
698 if (AdapterObject == NULL)
699 return 0;
700
701 return AdapterObject->DmaOperations->GetDmaAlignment(AdapterObject);
702 }
703
704 \f
705 /*
706 * @unimplemented
707 */
708 NDIS_STATUS
709 EXPORT
710 NdisMRegisterDmaChannel(
711 OUT PNDIS_HANDLE MiniportDmaHandle,
712 IN NDIS_HANDLE MiniportAdapterHandle,
713 IN UINT DmaChannel,
714 IN BOOLEAN Dma32BitAddresses,
715 IN PNDIS_DMA_DESCRIPTION DmaDescription,
716 IN ULONG MaximumLength)
717 {
718 UNIMPLEMENTED
719
720 return NDIS_STATUS_FAILURE;
721 }
722
723 \f
724 /*
725 * @implemented
726 */
727 NDIS_STATUS
728 EXPORT
729 NdisMRegisterInterrupt(
730 OUT PNDIS_MINIPORT_INTERRUPT Interrupt,
731 IN NDIS_HANDLE MiniportAdapterHandle,
732 IN UINT InterruptVector,
733 IN UINT InterruptLevel,
734 IN BOOLEAN RequestIsr,
735 IN BOOLEAN SharedInterrupt,
736 IN NDIS_INTERRUPT_MODE InterruptMode)
737 /*
738 * FUNCTION: Claims access to an interrupt vector
739 * ARGUMENTS:
740 * Interrupt = Address of interrupt object to initialize
741 * MiniportAdapterHandle = Specifies handle input to MiniportInitialize
742 * InterruptVector = Specifies bus-relative vector to register
743 * InterruptLevel = Specifies bus-relative DIRQL vector for interrupt
744 * RequestIsr = TRUE if MiniportISR should always be called
745 * SharedInterrupt = TRUE if other devices may use the same interrupt
746 * InterruptMode = Specifies type of interrupt
747 * RETURNS:
748 * Status of operation
749 */
750 {
751 NTSTATUS Status;
752 ULONG MappedIRQ;
753 KIRQL DIrql;
754 KAFFINITY Affinity;
755 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle;
756
757 NDIS_DbgPrint(MAX_TRACE, ("Called. InterruptVector (0x%X) InterruptLevel (0x%X) "
758 "SharedInterrupt (%d) InterruptMode (0x%X)\n",
759 InterruptVector, InterruptLevel, SharedInterrupt, InterruptMode));
760
761 RtlZeroMemory(Interrupt, sizeof(NDIS_MINIPORT_INTERRUPT));
762
763 KeInitializeSpinLock(&Interrupt->DpcCountLock);
764
765 KeInitializeDpc(&Interrupt->InterruptDpc, HandleDeferredProcessing, Adapter);
766
767 KeInitializeEvent(&Interrupt->DpcsCompletedEvent, NotificationEvent, FALSE);
768
769 Interrupt->SharedInterrupt = SharedInterrupt;
770
771 Adapter->NdisMiniportBlock.Interrupt = Interrupt;
772
773 MappedIRQ = HalGetInterruptVector(Adapter->NdisMiniportBlock.BusType, Adapter->NdisMiniportBlock.BusNumber,
774 InterruptLevel, InterruptVector, &DIrql,
775 &Affinity);
776
777 NDIS_DbgPrint(MAX_TRACE, ("Connecting to interrupt vector (0x%X) Affinity (0x%X).\n", MappedIRQ, Affinity));
778
779 Status = IoConnectInterrupt(&Interrupt->InterruptObject, ServiceRoutine, Adapter, &Interrupt->DpcCountLock, MappedIRQ,
780 DIrql, DIrql, InterruptMode, SharedInterrupt, Affinity, FALSE);
781
782 NDIS_DbgPrint(MAX_TRACE, ("Leaving. Status (0x%X).\n", Status));
783
784 if (NT_SUCCESS(Status))
785 return NDIS_STATUS_SUCCESS;
786
787 if (Status == STATUS_INSUFFICIENT_RESOURCES)
788 {
789 /* FIXME: Log error */
790 NDIS_DbgPrint(MIN_TRACE, ("Resource conflict!\n"));
791 return NDIS_STATUS_RESOURCE_CONFLICT;
792 }
793
794 NDIS_DbgPrint(MIN_TRACE, ("Function failed. Status (0x%X).\n", Status));
795 return NDIS_STATUS_FAILURE;
796 }
797
798 \f
799 /*
800 * @implemented
801 */
802 NDIS_STATUS
803 EXPORT
804 NdisMRegisterIoPortRange(
805 OUT PVOID *PortOffset,
806 IN NDIS_HANDLE MiniportAdapterHandle,
807 IN UINT InitialPort,
808 IN UINT NumberOfPorts)
809 /*
810 * FUNCTION: Sets up driver access to device I/O ports
811 * ARGUMENTS:
812 * PortOffset = Address of buffer to place mapped base port address
813 * MiniportAdapterHandle = Specifies handle input to MiniportInitialize
814 * InitialPort = Bus-relative base port address of a range to be mapped
815 * NumberOfPorts = Specifies number of ports to be mapped
816 * RETURNS:
817 * Status of operation
818 */
819 {
820 PHYSICAL_ADDRESS PortAddress, TranslatedAddress;
821 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle;
822 ULONG AddressSpace = 1; /* FIXME The HAL handles this wrong atm */
823
824 *PortOffset = 0;
825
826 NDIS_DbgPrint(MAX_TRACE, ("Called - InitialPort 0x%x, NumberOfPorts 0x%x\n", InitialPort, NumberOfPorts));
827
828 memset(&PortAddress, 0, sizeof(PortAddress));
829
830 /*
831 * FIXME: NDIS 5+ completely ignores the InitialPort parameter, but
832 * we don't have a way to get the I/O base address yet (see
833 * NDIS_MINIPORT_BLOCK->AllocatedResources and
834 * NDIS_MINIPORT_BLOCK->AllocatedResourcesTranslated).
835 */
836 if(InitialPort)
837 PortAddress = RtlConvertUlongToLargeInteger(InitialPort);
838 else
839 ASSERT(FALSE);
840
841 NDIS_DbgPrint(MAX_TRACE, ("Translating address 0x%x 0x%x\n", PortAddress.u.HighPart, PortAddress.u.LowPart));
842
843 if(!HalTranslateBusAddress(Adapter->NdisMiniportBlock.BusType, Adapter->NdisMiniportBlock.BusNumber,
844 PortAddress, &AddressSpace, &TranslatedAddress))
845 {
846 NDIS_DbgPrint(MIN_TRACE, ("Unable to translate address\n"));
847 return NDIS_STATUS_RESOURCES;
848 }
849
850 NDIS_DbgPrint(MAX_TRACE, ("Hal returned AddressSpace=0x%x TranslatedAddress=0x%x 0x%x\n",
851 AddressSpace, TranslatedAddress.u.HighPart, TranslatedAddress.u.LowPart));
852
853 if(AddressSpace)
854 {
855 ASSERT(TranslatedAddress.u.HighPart == 0);
856 *PortOffset = (PVOID)(ULONG_PTR)TranslatedAddress.QuadPart;
857 NDIS_DbgPrint(MAX_TRACE, ("Returning 0x%x\n", *PortOffset));
858 return NDIS_STATUS_SUCCESS;
859 }
860
861 NDIS_DbgPrint(MAX_TRACE, ("calling MmMapIoSpace\n"));
862
863 *PortOffset = MmMapIoSpace(TranslatedAddress, NumberOfPorts, MmNonCached);
864 NDIS_DbgPrint(MAX_TRACE, ("Returning 0x%x for port range\n", *PortOffset));
865
866 if(!*PortOffset)
867 return NDIS_STATUS_RESOURCES;
868
869 return NDIS_STATUS_SUCCESS;
870 }
871
872
873 /*
874 * @implemented
875 */
876 VOID
877 EXPORT
878 NdisMUnmapIoSpace(
879 IN NDIS_HANDLE MiniportAdapterHandle,
880 IN PVOID VirtualAddress,
881 IN UINT Length)
882 /*
883 * FUNCTION: Un-maps space previously mapped with NdisMMapIoSpace
884 * ARGUMENTS:
885 * MiniportAdapterHandle: handle originally passed into MiniportInitialize
886 * VirtualAddress: Address to un-map
887 * Length: length of the mapped memory space
888 * NOTES:
889 * - Must be called at IRQL = PASSIVE_LEVEL
890 * - Must only be called from MiniportInitialize and MiniportHalt
891 * - See also: NdisMMapIoSpace
892 * BUGS:
893 * - Depends on MmUnmapIoSpace to Do The Right Thing in all cases
894 */
895 {
896 PAGED_CODE();
897
898 ASSERT(MiniportAdapterHandle);
899
900 MmUnmapIoSpace(VirtualAddress, Length);
901 }
902
903 /* EOF */
904