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