implemented NdisMAllocateMapRegisters, NdisMFreeMapRegisters, NdisMQueryMapRegisterCo...
authorVizzini <vizzini@plasmic.com>
Thu, 4 Sep 2003 06:59:48 +0000 (06:59 +0000)
committerVizzini <vizzini@plasmic.com>
Thu, 4 Sep 2003 06:59:48 +0000 (06:59 +0000)
svn path=/trunk/; revision=5979

reactos/drivers/net/ndis/ndis/io.c

index 2ee4f52..e193bc9 100644 (file)
@@ -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 <ndissys.h>
 #include <miniport.h>
 
-
 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;
+
+  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;
+    }
 
-       return NDIS_STATUS_FAILURE;
+  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,33 +650,51 @@ 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