📄 io.c
字号:
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS NDIS library
* FILE: ndis/io.c
* PURPOSE: I/O related routines
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
* Vizzini (vizzini@plasmic.com)
* REVISIONS:
* CSH 01/08-2000 Created
* 20 Aug 2003 Vizzini - DMA support
* 3 Oct 2003 Vizzini - Formatting and minor bugfixes
*/
#include "ndissys.h"
VOID NTAPI HandleDeferredProcessing(
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2)
/*
* FUNCTION: Deferred interrupt processing routine
* ARGUMENTS:
* Dpc = Pointer to DPC object
* DeferredContext = Pointer to context information (LOGICAL_ADAPTER)
* SystemArgument1 = Unused
* SystemArgument2 = Unused
*/
{
BOOLEAN WasBusy;
PLOGICAL_ADAPTER Adapter = GET_LOGICAL_ADAPTER(DeferredContext);
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
/* XXX try to grok WasBusy */
KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
{
WasBusy = Adapter->MiniportBusy;
Adapter->MiniportBusy = TRUE;
}
KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
/* Call the deferred interrupt service handler for this adapter */
(*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.HandleInterruptHandler)(
Adapter->NdisMiniportBlock.MiniportAdapterContext);
KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
{
if ((!WasBusy) && (Adapter->WorkQueueHead))
{
KeInsertQueueDpc(&Adapter->NdisMiniportBlock.DeferredDpc, NULL, NULL);
}
else
{
Adapter->MiniportBusy = WasBusy;
}
}
KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
/* re-enable the interrupt */
NDIS_DbgPrint(MAX_TRACE, ("re-enabling the interrupt\n"));
if(Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.EnableInterruptHandler)
(*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.EnableInterruptHandler)(
Adapter->NdisMiniportBlock.MiniportAdapterContext);
NDIS_DbgPrint(MAX_TRACE, ("Leaving.\n"));
}
BOOLEAN NTAPI ServiceRoutine(
IN PKINTERRUPT Interrupt,
IN PVOID ServiceContext)
/*
* FUNCTION: Interrupt service routine
* ARGUMENTS:
* Interrupt = Pointer to interrupt object
* ServiceContext = Pointer to context information (LOGICAL_ADAPTER)
* RETURNS
* TRUE if a miniport controlled device generated the interrupt
*/
{
BOOLEAN InterruptRecognized;
BOOLEAN QueueMiniportHandleInterrupt;
PNDIS_MINIPORT_BLOCK Adapter = (PNDIS_MINIPORT_BLOCK)ServiceContext;
NDIS_DbgPrint(MAX_TRACE, ("Called. Adapter (0x%X)\n", Adapter));
(*Adapter->DriverHandle->MiniportCharacteristics.ISRHandler)(
&InterruptRecognized,
&QueueMiniportHandleInterrupt,
Adapter->MiniportAdapterContext);
if (QueueMiniportHandleInterrupt)
{
NDIS_DbgPrint(MAX_TRACE, ("Queueing DPC.\n"));
KeInsertQueueDpc(&Adapter->Interrupt->InterruptDpc, NULL, NULL);
}
NDIS_DbgPrint(MAX_TRACE, ("Leaving.\n"));
return InterruptRecognized;
}
/*
* @unimplemented
*/
VOID
EXPORT
NdisCompleteDmaTransfer(
OUT PNDIS_STATUS Status,
IN PNDIS_HANDLE NdisDmaHandle,
IN PNDIS_BUFFER Buffer,
IN ULONG Offset,
IN ULONG Length,
IN BOOLEAN WriteToDevice)
{
UNIMPLEMENTED
}
/*
* @implemented
*/
VOID
EXPORT
NdisImmediateReadPortUchar(
IN NDIS_HANDLE WrapperConfigurationContext,
IN ULONG Port,
OUT PUCHAR Data)
{
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
*Data = READ_PORT_UCHAR((PUCHAR)Port); // FIXME: What to do with WrapperConfigurationContext?
}
/*
* @implemented
*/
VOID
EXPORT
NdisImmediateReadPortUlong(
IN NDIS_HANDLE WrapperConfigurationContext,
IN ULONG Port,
OUT PULONG Data)
{
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
*Data = READ_PORT_ULONG((PULONG)Port); // FIXME: What to do with WrapperConfigurationContext?
}
/*
* @implemented
*/
VOID
EXPORT
NdisImmediateReadPortUshort(
IN NDIS_HANDLE WrapperConfigurationContext,
IN ULONG Port,
OUT PUSHORT Data)
{
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
*Data = READ_PORT_USHORT((PUSHORT)Port); // FIXME: What to do with WrapperConfigurationContext?
}
/*
* @implemented
*/
VOID
EXPORT
NdisImmediateWritePortUchar(
IN NDIS_HANDLE WrapperConfigurationContext,
IN ULONG Port,
IN UCHAR Data)
{
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
WRITE_PORT_UCHAR((PUCHAR)Port, Data); // FIXME: What to do with WrapperConfigurationContext?
}
/*
* @implemented
*/
VOID
EXPORT
NdisImmediateWritePortUlong(
IN NDIS_HANDLE WrapperConfigurationContext,
IN ULONG Port,
IN ULONG Data)
{
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
WRITE_PORT_ULONG((PULONG)Port, Data); // FIXME: What to do with WrapperConfigurationContext?
}
/*
* @unimplemented
*/
VOID
EXPORT
NdisImmediateWritePortUshort(
IN NDIS_HANDLE WrapperConfigurationContext,
IN ULONG Port,
IN USHORT Data)
{
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
WRITE_PORT_USHORT((PUSHORT)Port, Data); // FIXME: What to do with WrapperConfigurationContext?
}
IO_ALLOCATION_ACTION NTAPI NdisMapRegisterCallback (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID MapRegisterBase,
IN PVOID Context)
/*
* FUNCTION: Called back during reservation of map registers
* ARGUMENTS:
* DeviceObject: Device object of the deivce setting up DMA
* Irp: Reserved; must be ignored
* MapRegisterBase: Map registers assigned for transfer
* Context: LOGICAL_ADAPTER object of the requesting miniport
* NOTES:
* - Called once per BaseMapRegister (see NdisMAllocateMapRegisters)
* - Called at IRQL = DISPATCH_LEVEL
*/
{
PNDIS_MINIPORT_BLOCK Adapter = (PNDIS_MINIPORT_BLOCK)Context;
NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
Adapter->MapRegisters[Adapter->CurrentMapRegister].MapRegister = MapRegisterBase;
NDIS_DbgPrint(MAX_TRACE, ("setting event and leaving.\n"));
KeSetEvent(Adapter->AllocationEvent, 0, FALSE);
/* this is only the thing to do for busmaster NICs */
return DeallocateObjectKeepRegisters;
}
/*
* @implemented
*/
NDIS_STATUS
EXPORT
NdisMAllocateMapRegisters(
IN NDIS_HANDLE MiniportAdapterHandle,
IN UINT DmaChannel,
IN BOOLEAN DmaSize,
IN ULONG BaseMapRegistersNeeded,
IN ULONG MaximumBufferSize)
/*
* FUNCTION: Allocate map registers for use in DMA transfers
* ARGUMENTS:
* MiniportAdapterHandle: Passed in to MiniportInitialize
* DmaChannel: DMA channel to use
* DmaSize: bit width of DMA transfers
* BaseMapRegistersNeeded: number of base map registers requested
* MaximumBufferSize: largest single buffer transferred
* RETURNS:
* NDIS_STATUS_SUCCESS on success
* NDIS_STATUS_RESOURCES on failure
* NOTES:
* - the win2k ddk and the nt4 ddk have conflicting prototypes for this.
* I'm implementing the 2k one.
* - do not confuse a "base map register" with a "map register" - they
* are different. Only NDIS seems to use the base concept. The idea
* is that a miniport supplies the number of base map registers it will
* need, which is equal to the number of DMA send buffers it manages.
* NDIS then allocates a number of map registers to go with each base
* map register, so that a driver just has to send the base map register
* number during dma operations and NDIS can find the group of real
* map registers that represent the transfer.
* - Because of the above sillyness, you can only specify a few base map
* registers at most. a 1514-byte packet is two map registers at 4k
* page size.
* - NDIS limits the total number of allocated map registers to 64,
* which (in the case of the above example) limits the number of base
* map registers to 32.
*/
{
DEVICE_DESCRIPTION Description;
PDMA_ADAPTER AdapterObject = 0;
UINT MapRegistersPerBaseRegister = 0;
ULONG AvailableMapRegisters;
NTSTATUS NtStatus;
PNDIS_MINIPORT_BLOCK Adapter = 0;
PDEVICE_OBJECT DeviceObject = 0;
KEVENT AllocationEvent;
KIRQL OldIrql;
NDIS_DbgPrint(MAX_TRACE, ("called: Handle 0x%x, DmaChannel 0x%x, DmaSize 0x%x, BaseMapRegsNeeded: 0x%x, MaxBuffer: 0x%x.\n",
MiniportAdapterHandle, DmaChannel, DmaSize, BaseMapRegistersNeeded, MaximumBufferSize));
memset(&Description,0,sizeof(Description));
Adapter = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
ASSERT(Adapter);
/* only bus masters may call this routine */
ASSERT(Adapter->Flags & NDIS_ATTRIBUTE_BUS_MASTER);
if(!(Adapter->Flags & NDIS_ATTRIBUTE_BUS_MASTER))
return NDIS_STATUS_SUCCESS;
DeviceObject = Adapter->DeviceObject;
KeInitializeEvent(&AllocationEvent, NotificationEvent, FALSE);
Adapter->AllocationEvent = &AllocationEvent;
/*
* map registers correlate to physical pages. ndis documents a
* maximum of 64 map registers that it will return.
* at 4k pages, a 1514-byte buffer can span not more than 2 pages.
*
* the number of registers required for a given physical mapping
* is (first register + last register + one per page size),
* given that physical mapping is > 2.
*/
/* unhandled corner case: {1,2}-byte max buffer size */
ASSERT(MaximumBufferSize > 2);
MapRegistersPerBaseRegister = ((MaximumBufferSize-2) / (2*PAGE_SIZE)) + 2;
Description.Version = DEVICE_DESCRIPTION_VERSION;
Description.Master = TRUE; /* implied by calling this function */
Description.ScatterGather = TRUE; /* XXX UNTRUE: All BM DMA are S/G (ms seems to do this) */
Description.Dma32BitAddresses = DmaSize;
Description.BusNumber = Adapter->BusNumber;
Description.InterfaceType = Adapter->BusType;
Description.DmaChannel = DmaChannel;
Description.MaximumLength = MaximumBufferSize;
if(Adapter->AdapterType == Isa)
{
/* system dma */
if(DmaChannel < 4)
Description.DmaWidth = Width8Bits;
else
Description.DmaWidth = Width16Bits;
Description.DmaSpeed = Compatible;
}
else if(Adapter->AdapterType == PCIBus)
{
if(DmaSize == NDIS_DMA_64BITS)
Description.Dma64BitAddresses = TRUE;
else
Description.Dma32BitAddresses = TRUE;
}
else
{
NDIS_DbgPrint(MIN_TRACE, ("Unsupported bus type\n"));
ASSERT(0);
}
AdapterObject = IoGetDmaAdapter(
Adapter->PhysicalDeviceObject, &Description, &AvailableMapRegisters);
if(!AdapterObject)
{
NDIS_DbgPrint(MIN_TRACE, ("Unable to allocate an adapter object; bailing out\n"));
return NDIS_STATUS_RESOURCES;
}
Adapter->SystemAdapterObject = AdapterObject;
if(AvailableMapRegisters < MapRegistersPerBaseRegister)
{
NDIS_DbgPrint(MIN_TRACE, ("Didn't get enough map registers from hal - requested 0x%x, got 0x%x\n",
MapRegistersPerBaseRegister, AvailableMapRegisters));
return NDIS_STATUS_RESOURCES;
}
/* allocate & zero space in the miniport block for the registers */
Adapter->MapRegisters = ExAllocatePool(NonPagedPool, BaseMapRegistersNeeded * sizeof(MAP_REGISTER_ENTRY));
if(!Adapter->MapRegisters)
{
NDIS_DbgPrint(MIN_TRACE, ("insufficient resources.\n"));
return NDIS_STATUS_RESOURCES;
}
memset(Adapter->MapRegisters, 0, BaseMapRegistersNeeded * sizeof(MAP_REGISTER_ENTRY));
Adapter->BaseMapRegistersNeeded = (USHORT)BaseMapRegistersNeeded;
while(BaseMapRegistersNeeded)
{
NDIS_DbgPrint(MAX_TRACE, ("iterating, basemapregistersneeded = %d\n", BaseMapRegistersNeeded));
BaseMapRegistersNeeded--;
Adapter->CurrentMapRegister = (USHORT)BaseMapRegistersNeeded;
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
{
NtStatus = AdapterObject->DmaOperations->AllocateAdapterChannel(
AdapterObject, DeviceObject, MapRegistersPerBaseRegister,
NdisMapRegisterCallback, Adapter);
}
KeLowerIrql(OldIrql);
if(!NT_SUCCESS(NtStatus))
{
NDIS_DbgPrint(MIN_TRACE, ("IoAllocateAdapterChannel failed: 0x%x\n", NtStatus));
return NDIS_STATUS_RESOURCES;
}
NDIS_DbgPrint(MAX_TRACE, ("waiting on event\n"));
NtStatus = KeWaitForSingleObject(&AllocationEvent, Executive, KernelMode, FALSE, 0);
if(!NT_SUCCESS(NtStatus))
{
NDIS_DbgPrint(MIN_TRACE, ("KeWaitForSingleObject failed: 0x%x\n", NtStatus));
return NDIS_STATUS_RESOURCES;
}
NDIS_DbgPrint(MAX_TRACE, ("resetting event\n"));
KeResetEvent(&AllocationEvent);
}
NDIS_DbgPrint(MAX_TRACE, ("returning success\n"));
return NDIS_STATUS_SUCCESS;
}
/*
* @implemented
*/
VOID
EXPORT
NdisMStartBufferPhysicalMapping(
IN NDIS_HANDLE MiniportAdapterHandle,
IN PNDIS_BUFFER Buffer,
IN ULONG PhysicalMapRegister,
IN BOOLEAN WriteToDevice,
OUT PNDIS_PHYSICAL_ADDRESS_UNIT PhysicalAddressArray,
OUT PUINT ArraySize)
/*
* FUNCTION: Sets up map registers for a bus-master DMA transfer
* ARGUMENTS:
* MiniportAdapterHandle: handle originally input to MiniportInitialize
* Buffer: data to be transferred
* PhysicalMapRegister: specifies the map register to set up
* WriteToDevice: if true, data is being written to the device; else it is being read
* PhysicalAddressArray: list of mapped ranges suitable for DMA with the device
* ArraySize: number of elements in PhysicalAddressArray
* NOTES:
* - Must be called at IRQL <= DISPATCH_LEVEL
* - The basic idea: call IoMapTransfer() in a loop as many times as it takes
* in order to map all of the virtual memory to physical memoroy readable
* by the device
* - The caller supplies storage for the physical address array.
*/
{
PNDIS_MINIPORT_BLOCK Adapter;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -