diff --git a/reactos/drivers/net/ndis/ndis/io.c b/reactos/drivers/net/ndis/ndis/io.c index 2ee4f526861..e193bc9106c 100644 --- a/reactos/drivers/net/ndis/ndis/io.c +++ b/reactos/drivers/net/ndis/ndis/io.c @@ -4,13 +4,14 @@ * 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 + * 8-20-2003 Vizzini - DMA support */ #include #include - VOID STDCALL HandleDeferredProcessing( IN PKDPC Dpc, IN PVOID DeferredContext, @@ -138,6 +139,7 @@ NdisImmediateReadPortUchar( IN ULONG Port, OUT PUCHAR Data) { + NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); *Data = READ_PORT_UCHAR((PUCHAR)Port); // FIXME: What to do with WrapperConfigurationContext? } @@ -152,6 +154,7 @@ NdisImmediateReadPortUlong( IN ULONG Port, OUT PULONG Data) { + NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); *Data = READ_PORT_ULONG((PULONG)Port); // FIXME: What to do with WrapperConfigurationContext? } @@ -166,6 +169,7 @@ NdisImmediateReadPortUshort( IN ULONG Port, OUT PUSHORT Data) { + NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); *Data = READ_PORT_USHORT((PUSHORT)Port); // FIXME: What to do with WrapperConfigurationContext? } @@ -180,6 +184,7 @@ NdisImmediateWritePortUchar( IN ULONG Port, IN UCHAR Data) { + NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); WRITE_PORT_UCHAR((PUCHAR)Port, Data); // FIXME: What to do with WrapperConfigurationContext? } @@ -194,6 +199,7 @@ NdisImmediateWritePortUlong( IN ULONG Port, IN ULONG Data) { + NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); WRITE_PORT_ULONG((PULONG)Port, Data); // FIXME: What to do with WrapperConfigurationContext? } @@ -208,25 +214,173 @@ NdisImmediateWritePortUshort( 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 NdisMapRegisterCallback ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID MapRegisterBase, + IN PVOID Context) /* - * @unimplemented + * FUNCTION: Called back during reservation of map registers + */ +{ + PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)Context; + PADAPTER_MAP_REGISTER_LIST Register = ExAllocatePool(NonPagedPool, sizeof(ADAPTER_MAP_REGISTER_LIST)); + + NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); + + if(!Register) + { + NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n")); + KeSetEvent(&Adapter->DmaEvent, 0, FALSE); + return DeallocateObject; + } + + Register->MapRegister = MapRegisterBase; + Register->NumRegisters = Adapter->MapRegistersRequested; + + ExInterlockedInsertTailList(&Adapter->MapRegisterList.ListEntry, &Register->ListEntry, &Adapter->DmaLock); + + KeSetEvent(&Adapter->DmaEvent, 0, FALSE); + + /* XXX 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 Dma32BitAddresses, - IN ULONG PhysicalMapRegistersNeeded, - IN ULONG MaximumPhysicalMapping) + 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 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. + */ { - UNIMPLEMENTED + DEVICE_DESCRIPTION Description; + PADAPTER_OBJECT AdapterObject = 0; + UINT MapRegistersRequired = 0; + UINT MapRegistersPerBaseRegister = 0; + ULONG AvailableMapRegisters; + NTSTATUS NtStatus; + PLOGICAL_ADAPTER Adapter = 0; + PDEVICE_OBJECT DeviceObject = 0; + KIRQL OldIrql; - return NDIS_STATUS_FAILURE; + 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 = (PLOGICAL_ADAPTER)MiniportAdapterHandle; + DeviceObject = Adapter->NdisMiniportBlock.DeviceObject; + + InitializeListHead(&Adapter->MapRegisterList.ListEntry); + KeInitializeEvent(&Adapter->DmaEvent, NotificationEvent, FALSE); + KeInitializeSpinLock(&Adapter->DmaLock); + + /* + * 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-byte max buffer size */ + MapRegistersPerBaseRegister = 2 + MaximumBufferSize / PAGE_SIZE; + MapRegistersRequired = BaseMapRegistersNeeded * MapRegistersPerBaseRegister; + + if(MapRegistersRequired > 64) + { + NDIS_DbgPrint(MID_TRACE, ("Request for too many map registers: %d\n", MapRegistersRequired)); + return NDIS_STATUS_RESOURCES; + } + + Description.Version = DEVICE_DESCRIPTION_VERSION; + Description.Master = TRUE; /* implied by calling this function */ + Description.ScatterGather = FALSE; /* implied by calling this function */ + Description.DemandMode = 0; /* unused due to bus master */ + Description.AutoInitialize = 0; /* unused due to bus master */ + Description.Dma32BitAddresses = DmaSize; + Description.IgnoreCount = 0; /* unused due to bus master */ + Description.Reserved1 = 0; + Description.Reserved2 = 0; + Description.BusNumber = Adapter->BusNumber; + Description.DmaChannel = 0; /* unused due to bus master */ + Description.InterfaceType = Adapter->BusType; + Description.DmaChannel = 0; /* unused due to bus master */ + Description.DmaWidth = 0; /* unused (i think) due to bus master */ + Description.DmaSpeed = 0; /* unused (i think) due to bus master */ + Description.MaximumLength = 0; /* unused (i think) due to bus master */ + Description.DmaPort = 0; /* unused due to bus type */ + + AvailableMapRegisters = MapRegistersRequired; + AdapterObject = HalGetAdapter(&Description, &AvailableMapRegisters); + + if(!AdapterObject) + { + NDIS_DbgPrint(MIN_TRACE, ("Unable to allocate an adapter object; bailing out\n")); + return NDIS_STATUS_RESOURCES; + } + + Adapter->AdapterObject = AdapterObject; + + if(AvailableMapRegisters < MapRegistersRequired) + { + NDIS_DbgPrint(MIN_TRACE, ("Didn't get enough map registers from hal - requested 0x%x, got 0x%x\n", + MapRegistersRequired, AvailableMapRegisters)); + return NDIS_STATUS_RESOURCES; + } + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + Adapter->MapRegistersRequested = MapRegistersRequired; + + NtStatus = IoAllocateAdapterChannel(AdapterObject, DeviceObject, + MapRegistersRequired, NdisMapRegisterCallback, Adapter); + + KeLowerIrql(OldIrql); + + if(!NT_SUCCESS(NtStatus)) + { + NDIS_DbgPrint(MIN_TRACE, ("IoAllocateAdapterChannel failed: 0x%x\n", NtStatus)); + return NDIS_STATUS_RESOURCES; + } + + NtStatus = KeWaitForSingleObject(&Adapter->DmaEvent, 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, ("returning success\n")); + return NDIS_STATUS_SUCCESS; } @@ -272,6 +426,7 @@ NdisMDeregisterInterrupt( * Interrupt = Pointer to interrupt object */ { + NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); IoDisconnectInterrupt(Interrupt->InterruptObject); } @@ -296,20 +451,44 @@ NdisMDeregisterIoPortRange( */ { NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); - - /* Thank you */ } /* - * @unimplemented + * @implemented */ VOID EXPORT NdisMFreeMapRegisters( IN NDIS_HANDLE MiniportAdapterHandle) +/* + * FUNCTION: Free previously allocated map registers + * ARGUMENTS: + * MiniportAdapterHandle: Handle originally passed in to MiniportInitialize + * NOTES: + */ { - UNIMPLEMENTED + KIRQL OldIrql; + PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle; + PADAPTER_OBJECT AdapterObject = Adapter->AdapterObject; + + NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + while(!IsListEmpty(&Adapter->MapRegisterList.ListEntry)) + { + PADAPTER_MAP_REGISTER_LIST Register = (PADAPTER_MAP_REGISTER_LIST)RemoveTailList(&Adapter->MapRegisterList.ListEntry); + if(Register) + { + IoFreeMapRegisters(AdapterObject, Register->MapRegister, Register->NumRegisters); + ExFreePool(Register); + } + else + NDIS_DbgPrint(MIN_TRACE,("Internal NDIS error - Register is 0\n")); + } + + KeLowerIrql(OldIrql); } @@ -362,7 +541,6 @@ NdisMRegisterDmaChannel( return NDIS_STATUS_FAILURE; } - /* * @implemented */ @@ -416,8 +594,8 @@ NdisMRegisterInterrupt( Adapter->NdisMiniportBlock.Interrupt = Interrupt; - MappedIRQ = HalGetInterruptVector(Internal, /* Adapter->AdapterType, */ - 0, + MappedIRQ = HalGetInterruptVector(Adapter->BusType, + Adapter->BusNumber, InterruptLevel, InterruptVector, &DIrql, @@ -472,34 +650,52 @@ NdisMRegisterIoPortRange( * Status of operation */ { -#if 0 - NTSTATUS Status; - BOOLEAN ConflictDetected; - PLOGICAL_ADAPTER Adapter = GET_LOGICAL_ADAPTER(MiniportAdapterHandle); - PMINIPORT_DRIVER Miniport = Adapter->Miniport; + PHYSICAL_ADDRESS PortAddress, TranslatedAddress; + PLOGICAL_ADAPTER Adapter = GET_LOGICAL_ADAPTER(MiniportAdapterHandle); + ULONG AddressSpace = 1; /* FIXME The HAL handles this wrong atm */ - NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); + NDIS_DbgPrint(MAX_TRACE, ("Called - InitialPort 0x%x, NumberOfPorts 0x%x\n", InitialPort, NumberOfPorts)); - /* Non-PnP hardware. NT5 function */ - Status = IoReportResourceForDetection(Miniport->DriverObject, - NULL, - 0, - NULL, - NULL, - 0, - &ConflictDetected); - return NDIS_STATUS_FAILURE; -#else - NDIS_DbgPrint(MAX_TRACE, ("Called.\n")); + memset(&PortAddress, 0, sizeof(PortAddress)); - /* It's yours! */ - *PortOffset = (PVOID)InitialPort; + /* this might be a hack - ndis5 miniports seem to specify 0 */ + if(InitialPort) + PortAddress = RtlConvertUlongToLargeInteger(InitialPort); + else + PortAddress = Adapter->BaseIoAddress; - return NDIS_STATUS_SUCCESS; -#endif + NDIS_DbgPrint(MAX_TRACE, ("Translating address 0x%x 0x%x\n", PortAddress.u.HighPart, PortAddress.u.LowPart)); + + /* FIXME: hard-coded bus number */ + if(!HalTranslateBusAddress(Adapter->BusType, 0, PortAddress, &AddressSpace, &TranslatedAddress)) + { + NDIS_DbgPrint(MIN_TRACE, ("Unable to translate address\n")); + return NDIS_STATUS_RESOURCES; + } + + NDIS_DbgPrint(MAX_TRACE, ("Hal returned AddressSpace=0x%x TranslatedAddress=0x%x 0x%x\n", + AddressSpace, TranslatedAddress.u.HighPart, TranslatedAddress.u.LowPart)); + + if(AddressSpace) + { + ASSERT(TranslatedAddress.u.HighPart == 0); + *PortOffset = (PVOID) TranslatedAddress.u.LowPart; + NDIS_DbgPrint(MAX_TRACE, ("Returning 0x%x\n", *PortOffset)); + return NDIS_STATUS_SUCCESS; + } + + NDIS_DbgPrint(MAX_TRACE, ("calling MmMapIoSpace\n")); + + *PortOffset = 0; + *PortOffset = MmMapIoSpace(TranslatedAddress, NumberOfPorts, 0); + NDIS_DbgPrint(MAX_TRACE, ("Returning 0x%x for port range\n", *PortOffset)); + + if(!*PortOffset) + return NDIS_STATUS_RESOURCES; + + return NDIS_STATUS_SUCCESS; } - /* * @unimplemented */