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