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