예제 #1
0
파일: io.c 프로젝트: GYGit/reactos
/*
 * @implemented
 */
NDIS_STATUS
EXPORT
NdisMRegisterDmaChannel(
    OUT PNDIS_HANDLE            MiniportDmaHandle,
    IN  NDIS_HANDLE             MiniportAdapterHandle,
    IN  UINT                    DmaChannel,
    IN  BOOLEAN                 Dma32BitAddresses,
    IN  PNDIS_DMA_DESCRIPTION   DmaDescription,
    IN  ULONG                   MaximumLength)
{
  PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle;
  DEVICE_DESCRIPTION DeviceDesc;
  ULONG MapRegisters;
  PNDIS_DMA_BLOCK DmaBlock;

  NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));

  RtlZeroMemory(&DeviceDesc, sizeof(DEVICE_DESCRIPTION));

  DeviceDesc.Version = DEVICE_DESCRIPTION_VERSION;
  DeviceDesc.Master = (Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_BUS_MASTER);
  DeviceDesc.ScatterGather = FALSE;
  DeviceDesc.DemandMode = DmaDescription->DemandMode;
  DeviceDesc.AutoInitialize = DmaDescription->AutoInitialize;
  DeviceDesc.Dma32BitAddresses = Dma32BitAddresses;
  DeviceDesc.Dma64BitAddresses = FALSE;
  DeviceDesc.BusNumber = Adapter->NdisMiniportBlock.BusNumber;
  DeviceDesc.DmaChannel = DmaDescription->DmaChannel;
  DeviceDesc.InterfaceType = Adapter->NdisMiniportBlock.BusType;
  DeviceDesc.DmaWidth = DmaDescription->DmaWidth;
  DeviceDesc.DmaSpeed = DmaDescription->DmaSpeed;
  DeviceDesc.MaximumLength = MaximumLength;


  DmaBlock = ExAllocatePool(NonPagedPool, sizeof(NDIS_DMA_BLOCK));
  if (!DmaBlock) {
      NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n"));
      return NDIS_STATUS_RESOURCES;
  }

  DmaBlock->SystemAdapterObject = (PVOID)IoGetDmaAdapter(Adapter->NdisMiniportBlock.PhysicalDeviceObject, &DeviceDesc, &MapRegisters);

  if (!DmaBlock->SystemAdapterObject) {
      NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources\n"));
      ExFreePool(DmaBlock);
      return NDIS_STATUS_RESOURCES;
  }

  Adapter->NdisMiniportBlock.SystemAdapterObject = (PDMA_ADAPTER)DmaBlock->SystemAdapterObject;
    
  KeInitializeEvent(&DmaBlock->AllocationEvent, NotificationEvent, FALSE);

  DmaBlock->Miniport = Adapter;

  *MiniportDmaHandle = DmaBlock;

  return NDIS_STATUS_SUCCESS;
}
예제 #2
0
파일: io.c 프로젝트: GYGit/reactos
/*
 * @implemented
 */
NDIS_STATUS
EXPORT
NdisMInitializeScatterGatherDma(
    IN  NDIS_HANDLE MiniportAdapterHandle,
    IN  BOOLEAN     Dma64BitAddresses,
    IN  ULONG       MaximumPhysicalMapping)
/*
 * FUNCTION:
 * ARGUMENTS:
 * NOTES:
 *    NDIS 5.0
 */
{
    PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle;
    ULONG MapRegisters;
    DEVICE_DESCRIPTION DeviceDesc;

    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));

    if (!(Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_BUS_MASTER)) {
        NDIS_DbgPrint(MIN_TRACE, ("Not a bus master\n"));
        return NDIS_STATUS_NOT_SUPPORTED;
    }

    RtlZeroMemory(&DeviceDesc, sizeof(DEVICE_DESCRIPTION));

    DeviceDesc.Version = DEVICE_DESCRIPTION_VERSION;
    DeviceDesc.Master = TRUE;
    DeviceDesc.ScatterGather = TRUE;
    DeviceDesc.Dma32BitAddresses = TRUE; // All callers support 32-bit addresses
    DeviceDesc.Dma64BitAddresses = Dma64BitAddresses;
    DeviceDesc.BusNumber = Adapter->NdisMiniportBlock.BusNumber;
    DeviceDesc.InterfaceType = Adapter->NdisMiniportBlock.BusType;
    DeviceDesc.MaximumLength = MaximumPhysicalMapping;

    Adapter->NdisMiniportBlock.SystemAdapterObject = 
         IoGetDmaAdapter(Adapter->NdisMiniportBlock.PhysicalDeviceObject, &DeviceDesc, &MapRegisters);

    if (!Adapter->NdisMiniportBlock.SystemAdapterObject)
        return NDIS_STATUS_RESOURCES;

    /* FIXME: Right now we just use this as a place holder */
    Adapter->NdisMiniportBlock.ScatterGatherListSize = 1;

    return NDIS_STATUS_SUCCESS;
}
예제 #3
0
NTSTATUS
CCaptureDevice::
PnpStart (
    IN PCM_RESOURCE_LIST TranslatedResourceList,
    IN PCM_RESOURCE_LIST UntranslatedResourceList
    )

/*++

Routine Description:

    Called at Pnp start.  We start up our virtual hardware simulation.

Arguments:

    TranslatedResourceList -
        The translated resource list from Pnp

    UntranslatedResourceList -
        The untranslated resource list from Pnp

Return Value:

    Success / Failure

--*/

{

    PAGED_CODE();

    //
    // Normally, we'd do things here like parsing the resource lists and
    // connecting our interrupt.  Since this is a simulation, there isn't
    // much to parse.  The parsing and connection should be the same as
    // any WDM driver.  The sections that will differ are illustrated below
    // in setting up a simulated DMA.
    //

    NTSTATUS Status = STATUS_SUCCESS;

    if (!m_Device -> Started) {
        // Create the Filter for the device
        KsAcquireDevice(m_Device);
        Status = KsCreateFilterFactory( m_Device->FunctionalDeviceObject,
                                        &CaptureFilterDescriptor,
                                        L"GLOBAL",
                                        NULL,
                                        KSCREATE_ITEM_FREEONSTOP,
                                        NULL,
                                        NULL,
                                        NULL );
        KsReleaseDevice(m_Device);

    }
    //
    // By PnP, it's possible to receive multiple starts without an intervening
    // stop (to reevaluate resources, for example).  Thus, we only perform
    // creations of the simulation on the initial start and ignore any 
    // subsequent start.  Hardware drivers with resources should evaluate
    // resources and make changes on 2nd start.
    //
    if (NT_SUCCESS(Status) && (!m_Device -> Started)) {

        m_HardwareSimulation = new (NonPagedPool) CHardwareSimulation (this);
        if (!m_HardwareSimulation) {
            //
            // If we couldn't create the hardware simulation, fail.
            //
            Status = STATUS_INSUFFICIENT_RESOURCES;
    
        } else {
            Status = KsAddItemToObjectBag (
                m_Device -> Bag,
                reinterpret_cast <PVOID> (m_HardwareSimulation),
                reinterpret_cast <PFNKSFREE> (CHardwareSimulation::Cleanup)
                );

            if (!NT_SUCCESS (Status)) {
                delete m_HardwareSimulation;
            }
        }
#if defined(_X86_)
        //
        // DMA operations illustrated in this sample are applicable only for 32bit platform.
        //
        INTERFACE_TYPE InterfaceBuffer;
        ULONG InterfaceLength;
        DEVICE_DESCRIPTION DeviceDescription;

        if (NT_SUCCESS (Status)) {
            //
            // Set up DMA...
            //
            // Ordinarilly, we'd be using InterfaceBuffer or 
            // InterfaceTypeUndefined if !NT_SUCCESS (IfStatus) as the 
            // InterfaceType below; however, for the purposes of this sample, 
            // we lie and say we're on the PCI Bus.  Otherwise, we're using map
            // registers on x86 32 bit physical to 32 bit logical and this isn't
            // what I want to show in this sample.
            //
            //
            // NTSTATUS IfStatus = 

            IoGetDeviceProperty (
                m_Device -> PhysicalDeviceObject,
                DevicePropertyLegacyBusType,
                sizeof (INTERFACE_TYPE),
                &InterfaceBuffer,
                &InterfaceLength
                );

            //
            // Initialize our fake device description.  We claim to be a 
            // bus-mastering 32-bit scatter/gather capable piece of hardware.
            //
            DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
            DeviceDescription.DmaChannel = ((ULONG) ~0);
            DeviceDescription.InterfaceType = PCIBus;
            DeviceDescription.DmaWidth = Width32Bits;
            DeviceDescription.DmaSpeed = Compatible;
            DeviceDescription.ScatterGather = TRUE;
            DeviceDescription.Master = TRUE;
            DeviceDescription.Dma32BitAddresses = TRUE;
            DeviceDescription.AutoInitialize = FALSE;
            DeviceDescription.MaximumLength = (ULONG) -1;
    
            //
            // Get a DMA adapter object from the system.
            //
            m_DmaAdapterObject = IoGetDmaAdapter (
                m_Device -> PhysicalDeviceObject,
                &DeviceDescription,
                &m_NumberOfMapRegisters
                );
    
            if (!m_DmaAdapterObject) {
                Status = STATUS_UNSUCCESSFUL;
            }
    
        }
    
        if (NT_SUCCESS (Status)) {
            //
            // Initialize our DMA adapter object with AVStream.  This is 
            // **ONLY** necessary **IF** you are doing DMA directly into
            // capture buffers as this sample does.  For this,
            // KSPIN_FLAG_GENERATE_MAPPINGS must be specified on a queue.
            //
    
            //
            // The (1 << 20) below is the maximum size of a single s/g mapping
            // that this hardware can handle.  Note that I have pulled this
            // number out of thin air for the "fake" hardware.
            //
            KsDeviceRegisterAdapterObject (
                m_Device,
                m_DmaAdapterObject,
                (1 << 20),
                sizeof (KSMAPPING)
                );
    
        }
#endif
    }
    
    return Status;

}
예제 #4
0
NTSTATUS
StartDevice(PDEVICE_OBJECT DeviceObject, PCM_PARTIAL_RESOURCE_LIST raw, PCM_PARTIAL_RESOURCE_LIST translated)
{
    PFDO_DEVICE_EXTENSION FdoDeviceExtension;
    PCM_PARTIAL_RESOURCE_DESCRIPTOR resource;
    DEVICE_DESCRIPTION DeviceDescription;
    PEHCI_HOST_CONTROLLER hcd;
    ULONG NumberResources;
    ULONG iCount;
    ULONG DeviceAddress;
    ULONG PropertySize;
    ULONG BusNumber;
    NTSTATUS Status;

    FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
    hcd = &FdoDeviceExtension->hcd;

    /* Sanity Checks */
    Status = IoGetDeviceProperty(FdoDeviceExtension->LowerDevice,
                                 DevicePropertyAddress,
                                 sizeof(ULONG),
                                 &DeviceAddress,
                                 &PropertySize);

    Status = IoGetDeviceProperty(FdoDeviceExtension->LowerDevice,
                                 DevicePropertyBusNumber,
                                 sizeof(ULONG),
                                 &BusNumber,
                                 &PropertySize);


    /* Get the resources the PNP Manager gave */
    NumberResources = translated->Count;
    DPRINT("NumberResources %d\n", NumberResources);
    for (iCount = 0; iCount < NumberResources; iCount++)
    {
        DPRINT("Resource Info %d:\n", iCount);
        resource = &translated->PartialDescriptors[iCount];
        switch(resource->Type)
        {
            case CmResourceTypePort:
            {
                DPRINT("Port Start: %x\n", resource->u.Port.Start);
                DPRINT("Port Length %d\n", resource->u.Port.Length);
                /* FIXME: Handle Ports */
                break;
            }
            case CmResourceTypeInterrupt:
            {
                DPRINT("Interrupt Vector: %x\n", resource->u.Interrupt.Vector);
                FdoDeviceExtension->Vector = resource->u.Interrupt.Vector;
                FdoDeviceExtension->Irql = resource->u.Interrupt.Level;
                FdoDeviceExtension->Affinity = resource->u.Interrupt.Affinity;
                FdoDeviceExtension->Mode = (resource->Flags == CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive;
                FdoDeviceExtension->IrqShared = resource->ShareDisposition == CmResourceShareShared;
                break;
            }
            case CmResourceTypeMemory:
            {
                PVOID ResourceBase = 0;

                DPRINT("Mem Start: %x\n", resource->u.Memory.Start);
                DPRINT("Mem Length: %d\n", resource->u.Memory.Length);

                ResourceBase = MmMapIoSpace(resource->u.Memory.Start, resource->u.Memory.Length, FALSE);
                DPRINT("ResourceBase %x\n", ResourceBase);
                if (ResourceBase  == NULL)
                {
                    DPRINT1("MmMapIoSpace failed!!!!!!!!!\n");
                }

                GetCapabilities(&FdoDeviceExtension->hcd.ECHICaps, (ULONG)ResourceBase);
                DPRINT1("hcd.ECHICaps.Length %x\n", FdoDeviceExtension->hcd.ECHICaps.Length);
                FdoDeviceExtension->hcd.OpRegisters = (ULONG)((ULONG)ResourceBase + FdoDeviceExtension->hcd.ECHICaps.Length);
                break;
            }
            case CmResourceTypeDma:
            {
                DPRINT("Dma Channel: %x\n", resource->u.Dma.Channel);
                DPRINT("Dma Port: %d\n", resource->u.Dma.Port);
                break;
            }
            case CmResourceTypeDevicePrivate:
            {
                /* Windows does this. */
                DPRINT1("CmResourceTypeDevicePrivate not handled\n");
                break;
            }
            default:
            {
                DPRINT1("PNP Manager gave resource type not handled!! Notify Developers!\n");
                break;
            }
        }
    }

    for (iCount = 0; iCount < hcd->ECHICaps.HCSParams.PortCount; iCount++)
    {
        hcd->Ports[iCount].PortStatus = 0x8000;
        hcd->Ports[iCount].PortChange = 0;
        
        if (hcd->ECHICaps.HCSParams.PortPowerControl)
            hcd->Ports[iCount].PortStatus |= USB_PORT_STATUS_POWER;
    }

    KeInitializeDpc(&FdoDeviceExtension->DpcObject,
                    EhciDefferedRoutine,
                    FdoDeviceExtension);

    RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));

    DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
    DeviceDescription.Master = TRUE;
    DeviceDescription.ScatterGather = TRUE;
    DeviceDescription.Dma32BitAddresses = TRUE;
    DeviceDescription.DmaWidth = 2;
    DeviceDescription.InterfaceType = PCIBus;
    DeviceDescription.MaximumLength = EHCI_MAX_SIZE_TRANSFER;

    hcd->pDmaAdapter = IoGetDmaAdapter(FdoDeviceExtension->LowerDevice,
                                       &DeviceDescription,
                                       &hcd->MapRegisters);

    if (hcd->pDmaAdapter == NULL)
    {
        DPRINT1("Ehci: IoGetDmaAdapter failed!\n");
        ASSERT(FALSE);
    }

    DPRINT1("MapRegisters %x\n", hcd->MapRegisters);

    /* Allocate Common Buffer for Periodic Frame List */
    FdoDeviceExtension->PeriodicFrameList.VirtualAddr =
        hcd->pDmaAdapter->DmaOperations->AllocateCommonBuffer(hcd->pDmaAdapter,
                                                              sizeof(ULONG) * 1024,
                                                              &FdoDeviceExtension->PeriodicFrameList.PhysicalAddr,
                                                              FALSE);

    if (FdoDeviceExtension->PeriodicFrameList.VirtualAddr == NULL)
    {
        DPRINT1("Ehci: FdoDeviceExtension->PeriodicFramList is null\n");
        return STATUS_UNSUCCESSFUL;
    }

    /* Zeroize it */
    RtlZeroMemory(FdoDeviceExtension->PeriodicFrameList.VirtualAddr, sizeof(ULONG) * 1024);

    ExInitializeFastMutex(&FdoDeviceExtension->FrameListMutex);

    /* Allocate initial page for queueheads and descriptors */
    FdoDeviceExtension->hcd.CommonBufferVA[0] =
        hcd->pDmaAdapter->DmaOperations->AllocateCommonBuffer(hcd->pDmaAdapter,
                                                              PAGE_SIZE,
                                                              &FdoDeviceExtension->hcd.CommonBufferPA[0],
                                                              FALSE);

    if (FdoDeviceExtension->hcd.CommonBufferVA[0] == 0)
    {
        DPRINT1("Ehci: Failed to allocate common buffer!\n");
        return STATUS_UNSUCCESSFUL;
    }

    hcd->CommonBufferSize = PAGE_SIZE * 16;

    /* Zeroize it */
    RtlZeroMemory(FdoDeviceExtension->hcd.CommonBufferVA[0],
                  PAGE_SIZE);

    /* Init SpinLock for host controller device lock */
    KeInitializeSpinLock(&hcd->Lock);

    /* Reserved a Queue Head that will always be in the AsyncList Address Register. By setting it as the Head of Reclamation
       the controller can know when it has reached the end of the QueueHead list */
    hcd->AsyncListQueue = CreateQueueHead(hcd);

    hcd->AsyncListQueue->HorizontalLinkPointer = hcd->AsyncListQueue->PhysicalAddr | QH_TYPE_QH;
    hcd->AsyncListQueue->EndPointCharacteristics.QEDTDataToggleControl = FALSE;
    hcd->AsyncListQueue->Token.Bits.InterruptOnComplete = FALSE;
    hcd->AsyncListQueue->EndPointCharacteristics.HeadOfReclamation = TRUE;
    hcd->AsyncListQueue->Token.Bits.Halted = TRUE;
    hcd->AsyncListQueue->NextQueueHead = hcd->AsyncListQueue;
    hcd->AsyncListQueue->PreviousQueueHead = hcd->AsyncListQueue;
    
    /* Reserve a Queue Head thats only purpose is for linking completed Queue Heads.
       Completed QueueHeads are moved to this temporary. As the memory must still be valid
       up until the controllers doorbell is rang to let it know info has been removed from QueueHead list */
    hcd->CompletedListQueue = CreateQueueHead(hcd);
    hcd->CompletedListQueue->NextQueueHead = hcd->CompletedListQueue;
    hcd->CompletedListQueue->PreviousQueueHead = hcd->CompletedListQueue;
    
    /* Ensure the controller is stopped */
    StopEhci(hcd);
    
    SetAsyncListQueueRegister(hcd, hcd->AsyncListQueue->PhysicalAddr);

    /* FIXME: Implement Periodic Frame List */

    Status = IoConnectInterrupt(&FdoDeviceExtension->EhciInterrupt,
                                InterruptService,
                                FdoDeviceExtension->DeviceObject,
                                NULL,
                                FdoDeviceExtension->Vector,
                                FdoDeviceExtension->Irql,
                                FdoDeviceExtension->Irql,
                                FdoDeviceExtension->Mode,
                                FdoDeviceExtension->IrqShared,
                                FdoDeviceExtension->Affinity,
                                FALSE);

    StartEhci(hcd);
    FdoDeviceExtension->DeviceState = DEVICESTARTED;
    return STATUS_SUCCESS;
}
예제 #5
0
파일: io.c 프로젝트: GYGit/reactos
/*
 * @implemented
 */
NDIS_STATUS
EXPORT
NdisMAllocateMapRegisters(
    IN  NDIS_HANDLE   MiniportAdapterHandle,
    IN  UINT          DmaChannel,
    IN  NDIS_DMA_SIZE 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;
  PLOGICAL_ADAPTER     Adapter;
  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 = (PLOGICAL_ADAPTER)MiniportAdapterHandle;

  ASSERT(Adapter);

  /* only bus masters may call this routine */
  if(!(Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_BUS_MASTER)) {
    NDIS_DbgPrint(MIN_TRACE, ("Not a bus master\n"));
    return NDIS_STATUS_NOT_SUPPORTED;
  }

  DeviceObject = Adapter->NdisMiniportBlock.DeviceObject;

  KeInitializeEvent(&AllocationEvent, NotificationEvent, FALSE);
  Adapter->NdisMiniportBlock.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.BusNumber = Adapter->NdisMiniportBlock.BusNumber;
  Description.InterfaceType = Adapter->NdisMiniportBlock.BusType;
  Description.DmaChannel = DmaChannel;
  Description.MaximumLength = MaximumBufferSize;
  
  if(DmaSize == NDIS_DMA_64BITS)
    Description.Dma64BitAddresses = TRUE;
  else if(DmaSize == NDIS_DMA_32BITS)
    Description.Dma32BitAddresses = TRUE;

  AdapterObject = IoGetDmaAdapter(
    Adapter->NdisMiniportBlock.PhysicalDeviceObject, &Description, &AvailableMapRegisters);

  if(!AdapterObject)
    {
      NDIS_DbgPrint(MIN_TRACE, ("Unable to allocate an adapter object; bailing out\n"));
      return NDIS_STATUS_RESOURCES;
    }

  Adapter->NdisMiniportBlock.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));

      AdapterObject->DmaOperations->PutDmaAdapter(AdapterObject);
      Adapter->NdisMiniportBlock.SystemAdapterObject = NULL;
      return NDIS_STATUS_RESOURCES;
    }

  /* allocate & zero space in the miniport block for the registers */
  Adapter->NdisMiniportBlock.MapRegisters = ExAllocatePool(NonPagedPool, BaseMapRegistersNeeded * sizeof(MAP_REGISTER_ENTRY));
  if(!Adapter->NdisMiniportBlock.MapRegisters)
    {
      NDIS_DbgPrint(MIN_TRACE, ("insufficient resources.\n"));
      AdapterObject->DmaOperations->PutDmaAdapter(AdapterObject);
      Adapter->NdisMiniportBlock.SystemAdapterObject = NULL;
      return NDIS_STATUS_RESOURCES;
    }

  memset(Adapter->NdisMiniportBlock.MapRegisters, 0, BaseMapRegistersNeeded * sizeof(MAP_REGISTER_ENTRY));
  Adapter->NdisMiniportBlock.BaseMapRegistersNeeded = (USHORT)BaseMapRegistersNeeded;

  while(BaseMapRegistersNeeded)
    {
      NDIS_DbgPrint(MAX_TRACE, ("iterating, basemapregistersneeded = %d\n", BaseMapRegistersNeeded));

      BaseMapRegistersNeeded--;
      Adapter->NdisMiniportBlock.CurrentMapRegister = (USHORT)BaseMapRegistersNeeded;
      KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
        {
          NtStatus = AdapterObject->DmaOperations->AllocateAdapterChannel(
              AdapterObject, DeviceObject, MapRegistersPerBaseRegister,
              NdisBusMasterMapRegisterCallback, Adapter);
        }
      KeLowerIrql(OldIrql);

      if(!NT_SUCCESS(NtStatus))
        {
          NDIS_DbgPrint(MIN_TRACE, ("IoAllocateAdapterChannel failed: 0x%x\n", NtStatus));
          ExFreePool(Adapter->NdisMiniportBlock.MapRegisters);
          AdapterObject->DmaOperations->PutDmaAdapter(AdapterObject);
          Adapter->NdisMiniportBlock.CurrentMapRegister = Adapter->NdisMiniportBlock.BaseMapRegistersNeeded = 0;
          Adapter->NdisMiniportBlock.SystemAdapterObject = NULL;
          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));
          ExFreePool(Adapter->NdisMiniportBlock.MapRegisters);
          AdapterObject->DmaOperations->PutDmaAdapter(AdapterObject);
          Adapter->NdisMiniportBlock.CurrentMapRegister = Adapter->NdisMiniportBlock.BaseMapRegistersNeeded = 0;
          Adapter->NdisMiniportBlock.SystemAdapterObject = NULL;
          return NDIS_STATUS_RESOURCES;
        }

      NDIS_DbgPrint(MAX_TRACE, ("resetting event\n"));

      KeResetEvent(&AllocationEvent);
    }

  NDIS_DbgPrint(MAX_TRACE, ("returning success\n"));
  return NDIS_STATUS_SUCCESS;
}