Пример #1
0
//this function is called by the hcd's
//dispatch when they have done their job.
NTSTATUS
dev_mgr_dispatch(IN PUSB_DEV_MANAGER dev_mgr, IN PIRP irp)
{
    PIO_STACK_LOCATION irp_stack;
    NTSTATUS status;
    ULONG ctrl_code;
    USE_NON_PENDING_IRQL;

    ASSERT(irp);
    if (dev_mgr == NULL)
    {
        EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
    }

    status = STATUS_SUCCESS;
    irp_stack = IoGetCurrentIrpStackLocation(irp);
    ctrl_code = irp_stack->Parameters.DeviceIoControl.IoControlCode;

    switch (irp_stack->MajorFunction)
    {
    case IRP_MJ_CREATE:
        {
            InterlockedIncrement(&dev_mgr->open_count);
            EXIT_DISPATCH(STATUS_SUCCESS, irp);
        }
    case IRP_MJ_CLOSE:
        {
            InterlockedDecrement(&dev_mgr->open_count);
            EXIT_DISPATCH(STATUS_SUCCESS, irp);
        }
    case IRP_MJ_INTERNAL_DEVICE_CONTROL:
    case IRP_MJ_DEVICE_CONTROL:
        {
            switch (ctrl_code)
            {
            case IOCTL_GET_DEV_COUNT:
                {
                    LONG dev_count;

                    irp->IoStatus.Information = 0;
                    if (irp_stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(LONG))
                    {
                        EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
                    }

                    KeAcquireSpinLock(&dev_mgr->dev_list_lock, &old_irql);
                    dev_count = usb_count_list(&dev_mgr->dev_list);
                    KeReleaseSpinLock(&dev_mgr->dev_list_lock, old_irql);

                    *((PLONG) irp->AssociatedIrp.SystemBuffer) = dev_count;
                    irp->IoStatus.Information = sizeof(LONG);
                    EXIT_DISPATCH(STATUS_SUCCESS, irp);
                }
            case IOCTL_ENUM_DEVICES:
                {
                    PLIST_ENTRY pthis, pnext;
                    LONG dev_count, array_size, i, j = 0;
                    PUSB_DEV pdev;
                    PENUM_DEV_ARRAY peda;

                    irp->IoStatus.Information = 0;
                    if (irp_stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(LONG))
                    {
                        EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
                    }
                    if (irp_stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ENUM_DEV_ARRAY))
                    {
                        EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
                    }
                    array_size = *((PULONG) irp->AssociatedIrp.SystemBuffer);

                    KeAcquireSpinLock(&dev_mgr->dev_list_lock, &old_irql);
                    dev_count = usb_count_list(&dev_mgr->dev_list);
                    dev_count = dev_count > array_size ? array_size : dev_count;
                    peda = (PENUM_DEV_ARRAY) irp->AssociatedIrp.SystemBuffer;
                    RtlZeroMemory(peda, sizeof(ENUM_DEV_ARRAY) + (dev_count - 1) * sizeof(ENUM_DEV_ELEMENT));

                    if (dev_count)
                    {
                        ListFirst(&dev_mgr->dev_list, pthis);
                        for(i = 0, j = 0; i < dev_count; i++)
                        {
                            pdev = struct_ptr(pthis, USB_DEV, dev_link);
                            ListNext(&dev_mgr->dev_list, pthis, pnext);
                            pthis = pnext;

                            lock_dev(pdev, FALSE);
                            if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
                            {
                                unlock_dev(pdev, FALSE);
                                continue;
                            }

                            if (dev_state(pdev) < USB_DEV_STATE_ADDRESSED)
                            {
                                unlock_dev(pdev, FALSE);
                                continue;
                            }

                            peda->dev_arr[i].dev_handle = (pdev->dev_id << 16);
                            //may not get the desc yet
                            if (pdev->pusb_dev_desc)
                            {
                                peda->dev_arr[i].product_id = pdev->pusb_dev_desc->idProduct;
                                peda->dev_arr[i].vendor_id = pdev->pusb_dev_desc->idVendor;
                            }
                            else
                            {
                                peda->dev_arr[i].product_id = 0xffff;
                                peda->dev_arr[i].vendor_id = 0xffff;
                            }
                            peda->dev_arr[i].dev_addr = pdev->dev_addr;
                            unlock_dev(pdev, FALSE);
                            j++;
                        }
                    }
                    peda->dev_count = dev_count ? j : 0;
                    KeReleaseSpinLock(&dev_mgr->dev_list_lock, old_irql);

                    irp->IoStatus.Information =
                        sizeof(ENUM_DEV_ARRAY) + (dev_count - 1) * sizeof(ENUM_DEV_ELEMENT);
                    EXIT_DISPATCH(STATUS_SUCCESS, irp);
                }
            case IOCTL_GET_DEV_DESC:
                {
                    GET_DEV_DESC_REQ gddr;
                    PUSB_DESC_HEADER pusb_desc_header;
                    PUSB_DEV pdev;
                    LONG buf_size;

                    if (irp_stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(GET_DEV_DESC_REQ))
                    {
                        EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
                    }

                    if (irp_stack->Parameters.DeviceIoControl.OutputBufferLength < 8)
                    {
                        EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
                    }

                    status = STATUS_SUCCESS;
                    buf_size = irp_stack->Parameters.DeviceIoControl.OutputBufferLength;
                    RtlCopyMemory(&gddr, irp->AssociatedIrp.SystemBuffer, sizeof(GET_DEV_DESC_REQ));
                    pusb_desc_header = irp->AssociatedIrp.SystemBuffer;

                    if (gddr.desc_type != USB_DT_CONFIG && gddr.desc_type != USB_DT_DEVICE)
                    {
                        EXIT_DISPATCH(STATUS_INVALID_DEVICE_REQUEST, irp);
                    }

                    if (usb_query_and_lock_dev(dev_mgr, gddr.dev_handle, &pdev) != STATUS_SUCCESS)
                    {
                        EXIT_DISPATCH(STATUS_IO_DEVICE_ERROR, irp);
                    }

                    lock_dev(pdev, FALSE);
                    if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
                    {
                        status = STATUS_INVALID_DEVICE_STATE;
                        goto ERROR_OUT;
                    }
                    if (dev_state(pdev) != USB_DEV_STATE_ADDRESSED &&
                        dev_state(pdev) != USB_DEV_STATE_CONFIGURED)
                    {
                        status = STATUS_DEVICE_NOT_READY;
                        goto ERROR_OUT;
                    }

                    if (pdev->pusb_dev_desc == NULL)
                    {
                        status = STATUS_DEVICE_NOT_READY;
                        goto ERROR_OUT;
                    }

                    if (gddr.desc_type == USB_DT_DEVICE)
                    {
                        RtlCopyMemory(pusb_desc_header,
                                      pdev->pusb_dev_desc,
                                      buf_size > sizeof(USB_DEVICE_DESC)
                                      ? sizeof(USB_DEVICE_DESC) : buf_size);

                        irp->IoStatus.Information =
                            buf_size >= sizeof(USB_DEVICE_DESC) ? sizeof(USB_DEVICE_DESC) : buf_size;
                    }
                    else if (gddr.desc_type == USB_DT_CONFIG)
                    {
                        PUSB_CONFIGURATION_DESC pusb_config_desc;
                        if (pdev->pusb_dev_desc->bNumConfigurations <= gddr.desc_idx)
                        {
                            status = STATUS_INVALID_PARAMETER;
                            goto ERROR_OUT;
                        }

                        pusb_config_desc = usb_find_config_desc_by_idx((PUCHAR) & pdev->pusb_dev_desc[1],
                                                                       gddr.desc_idx,
                                                                       pdev->pusb_dev_desc->
                                                                       bNumConfigurations);

                        if (pusb_config_desc == NULL)
                        {
                            status = STATUS_DEVICE_NOT_READY;
                            goto ERROR_OUT;
                        }

                        RtlCopyMemory(pusb_desc_header,
                                      pusb_config_desc,
                                      buf_size >= pusb_config_desc->wTotalLength
                                      ? pusb_config_desc->wTotalLength : buf_size);

                        irp->IoStatus.Information =
                            buf_size >= pusb_config_desc->wTotalLength
                            ? pusb_config_desc->wTotalLength : buf_size;
                    }
                  ERROR_OUT:
                    unlock_dev(pdev, FALSE);
                    usb_unlock_dev(pdev);
                    EXIT_DISPATCH(status, irp);
                }
            case IOCTL_SUBMIT_URB_RD:
            case IOCTL_SUBMIT_URB_WR:
            case IOCTL_SUBMIT_URB_NOIO:
                {
                    PURB purb;
                    ULONG endp_idx, if_idx, user_buffer_length = 0;
                    PUCHAR user_buffer = NULL;
                    PUSB_DEV pdev;
                    DEV_HANDLE endp_handle;
                    PUSB_ENDPOINT pendp;

                    if (irp_stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(URB))
                    {
                        EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
                    }

                    purb = (PURB) irp->AssociatedIrp.SystemBuffer;
                    endp_handle = purb->endp_handle;

                    if (ctrl_code == IOCTL_SUBMIT_URB_RD || ctrl_code == IOCTL_SUBMIT_URB_WR)
                    {
                        if (irp_stack->MajorFunction == IRP_MJ_DEVICE_CONTROL)
                        {
                            user_buffer_length = irp_stack->Parameters.DeviceIoControl.OutputBufferLength;
                            if (user_buffer_length == 0)
                                EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
                            user_buffer = MmGetSystemAddressForMdl(irp->MdlAddress);
                        }
                        else
                        {
                            if (purb->data_buffer == NULL || purb->data_length == 0)
                                EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
                            user_buffer_length = purb->data_length;
                            user_buffer = purb->data_buffer;
                        }
                    }

                    if (usb_query_and_lock_dev(dev_mgr, endp_handle & ~0xffff, &pdev) != STATUS_SUCCESS)
                    {
                        EXIT_DISPATCH(STATUS_IO_DEVICE_ERROR, irp);
                    }


                    lock_dev(pdev, FALSE);
                    if (dev_state(pdev) == USB_DEV_STATE_ZOMB || (dev_state(pdev) < USB_DEV_STATE_ADDRESSED))

                    {
                        status = STATUS_INVALID_DEVICE_STATE;
                        goto ERROR_OUT1;
                    }

                    if (dev_state(pdev) == USB_DEV_STATE_ADDRESSED && !default_endp_handle(endp_handle))
                    {
                        status = STATUS_DEVICE_NOT_READY;
                        goto ERROR_OUT1;
                    }

                    if_idx = if_idx_from_handle(endp_handle);
                    endp_idx = endp_idx_from_handle(endp_handle);

                    //if_idx exceeds the upper limit
                    if (pdev->usb_config)
                    {
                        if (if_idx >= pdev->usb_config->if_count
                            || endp_idx >= pdev->usb_config->interf[if_idx].endp_count)
                        {
                            if (!default_endp_handle(endp_handle))
                            {
                                status = STATUS_INVALID_DEVICE_STATE;
                                goto ERROR_OUT1;
                            }
                        }
                    }

                    endp_from_handle(pdev, endp_handle, pendp);
                    // FIXME: don't know what evil will let loose
                    if (endp_type(pendp) != USB_ENDPOINT_XFER_CONTROL)
                    {
                        if (user_buffer_length > 0x100000)
                        {
                            status = STATUS_INVALID_PARAMETER;
                            goto ERROR_OUT1;
                        }
                    }

                    purb->pirp = irp;
                    purb->context = dev_mgr;
                    purb->reference = ctrl_code;

                    if (ctrl_code == IOCTL_SUBMIT_URB_RD || ctrl_code == IOCTL_SUBMIT_URB_WR)
                    {
                        if (ctrl_code == IOCTL_SUBMIT_URB_RD)
                            KeFlushIoBuffers(irp->MdlAddress, TRUE, TRUE);
                        else
                            KeFlushIoBuffers(irp->MdlAddress, FALSE, TRUE);

                        purb->data_buffer = user_buffer;
                        purb->data_length = user_buffer_length;
                        purb->completion = disp_urb_completion;
                    }
                    else
                    {
                        purb->completion = disp_noio_urb_completion;
                    }

                    unlock_dev(pdev, FALSE);

                    // we have to mark irp before the urb is scheduled to
                    // avoid race condition
                    IoMarkIrpPending(irp);
                    ASSERT(dev_mgr_register_irp(dev_mgr, irp, purb));
                    status = usb_submit_urb(dev_mgr, purb);
                    if (status != STATUS_PENDING)
                    {
                        IoGetCurrentIrpStackLocation((irp))->Control &= ~SL_PENDING_RETURNED;
                        dev_mgr_remove_irp(dev_mgr, irp);
                    }
                    usb_unlock_dev(pdev);
                    if (status != STATUS_PENDING)
                    {
                        irp->IoStatus.Status = status;
                        IoCompleteRequest(irp, IO_NO_INCREMENT);
                    }
                    return status;
                  ERROR_OUT1:
                    unlock_dev(pdev, FALSE);
                    usb_unlock_dev(pdev);
                    irp->IoStatus.Information = 0;
                    EXIT_DISPATCH(status, irp);
                }
            default:
                {
                    irp->IoStatus.Information = 0;
                    EXIT_DISPATCH(STATUS_NOT_IMPLEMENTED, irp);
                }
            }
        }
    default:
        {
            irp->IoStatus.Information = 0;
            break;
        }
    }
    EXIT_DISPATCH(STATUS_INVALID_DEVICE_REQUEST, irp);
}
Пример #2
0
NDIS_STATUS NTAPI
ProSend(
    IN  NDIS_HANDLE     MacBindingHandle,
    IN  PNDIS_PACKET    Packet)
/*
 * FUNCTION: Forwards a request to send a packet to an NDIS miniport
 * ARGUMENTS:
 *     MacBindingHandle = Adapter binding handle
 *     Packet           = Pointer to NDIS packet descriptor
 * RETURNS:
 *     NDIS_STATUS_SUCCESS if the packet was successfully sent
 *     NDIS_STATUS_PENDING if the miniport was busy or a serialized miniport returned NDIS_STATUS_RESOURCES
 */
{
  PADAPTER_BINDING AdapterBinding;
  PLOGICAL_ADAPTER Adapter;
  PNDIS_BUFFER NdisBuffer;
  PDMA_CONTEXT Context;
  NDIS_STATUS NdisStatus;
  UINT PacketLength;
  KIRQL OldIrql;

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

  ASSERT(MacBindingHandle);
  AdapterBinding = GET_ADAPTER_BINDING(MacBindingHandle);

  ASSERT(AdapterBinding);
  Adapter = AdapterBinding->Adapter;

  ASSERT(Adapter);

  /* if the following is not true, KeRaiseIrql() below will break */
  ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);

  /* XXX what is this crazy black magic? */
  Packet->Reserved[1] = (ULONG_PTR)MacBindingHandle;

  /*
   * Test the packet to see if it is a MAC loopback.
   *
   * We may have to loop this packet if miniport cannot.
   * If dest MAC address of packet == MAC address of adapter,
   * this is a loopback frame.
   */

  if ((Adapter->NdisMiniportBlock.MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK) &&
      MiniAdapterHasAddress(Adapter, Packet))
    {
#if WORKER_TEST
        MiniQueueWorkItem(Adapter, NdisWorkItemSendLoopback, Packet, FALSE);
        return NDIS_STATUS_PENDING;
#else
        return ProIndicatePacket(Adapter, Packet);
#endif
    } else {
        if (Adapter->NdisMiniportBlock.ScatterGatherListSize != 0)
        {
            NDIS_DbgPrint(MID_TRACE, ("Using Scatter/Gather DMA\n"));

            NdisQueryPacket(Packet,
                            NULL,
                            NULL,
                            &NdisBuffer,
                            &PacketLength);

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

            Context->Adapter = Adapter;
            Context->Packet = Packet;

            KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);

            KeFlushIoBuffers(NdisBuffer, FALSE, TRUE);

            NdisStatus = Adapter->NdisMiniportBlock.SystemAdapterObject->DmaOperations->GetScatterGatherList(
                          Adapter->NdisMiniportBlock.SystemAdapterObject,
                          Adapter->NdisMiniportBlock.PhysicalDeviceObject,
                          NdisBuffer,
                          MmGetMdlVirtualAddress(NdisBuffer),
                          PacketLength,
                          ScatterGatherSendPacket,
                          Context,
                          TRUE);

            KeLowerIrql(OldIrql);

            if (!NT_SUCCESS(NdisStatus)) {
                NDIS_DbgPrint(MIN_TRACE, ("GetScatterGatherList failed! (%x)\n", NdisStatus));
                return NdisStatus;
            }

            return NDIS_STATUS_PENDING;
        }


        return proSendPacketToMiniport(Adapter, Packet);
    }
}
Пример #3
0
/*
 *   BUGBUG: Need to provide the miniport an IOCTL that causes this to be called
 *   when the transaction is really done.
 *   IOCTL_VIDEO_DMA_COMPLETED
 *   BUGBUG: need to provide a mechanism to miniport so it can determine when
 *   to free the map registers, unlock the pages, etc.
 *
 */
VOID
pVideoProcessCompletedRequest(
    PDEVICE_EXTENSION   pDE,
    PDMA_PARAMETERS     pIoVrb
    )
{

    PIRP                            pIrp      = pIoVrb->pIrp;
    PIO_STACK_LOCATION              pIrpStack = IoGetNextIrpStackLocation(pIrp);
    PPUBLIC_VIDEO_REQUEST_BLOCK     pPVRB     = pIoVrb->pVideoRequestBlock;
    LONG                            interlockResult;

    //
    // Map the buffers if indicated and flush.
    //

    if ((pDE->bMapBuffers) && (pIrp->MdlAddress)) {

        pPVRB->vrp.InputBuffer = (PCHAR)MmGetMdlVirtualAddress(pIrp->MdlAddress) +
            ((PCHAR)pPVRB->vrp.InputBuffer - pIoVrb->DataOffset);

        KeFlushIoBuffers(pIrp->MdlAddress, TRUE, FALSE);
    }

    //
    // Flush the adapter buffers if necessary.
    //

    if (pIoVrb->pMapRegisterBase) {

        //
        // Since we are a master call I/O flush adapter buffers with a NULL
        // adapter.
        //

        IoFlushAdapterBuffers(NULL,
                              pIrp->MdlAddress,
                              pIoVrb->pMapRegisterBase,
                              pPVRB->vrp.InputBuffer,
                              pPVRB->vrp.InputBufferLength,
                              FALSE);

        //
        // Free the map registers.
        //

        IoFreeMapRegisters(pDE->DmaAdapterObject,
                           pIoVrb->pMapRegisterBase,
                           pIoVrb->NumberOfMapRegisters);

        //
        // Clear the MapRegisterBase.
        //

        pIoVrb->pMapRegisterBase = NULL;

    }

    //
    // If miniport wants so unlock memory, do so here. At this point release
    // the DMA_PARAMETERs.
    //

    if (pPVRB->bUnlock) {

        //
        // Unlock
        //

        MmUnlockPages(pIrp->MdlAddress);

        //
        // Free Mdls
        //

        IoFreeMdl(pIrp->MdlAddress);
        pIrp->MdlAddress = NULL;

        //
        // Free Scattergather list if indicated and clear flag.
        //

        if (pPVRB->VRBFlags & VRB_FLAGS_SGLIST_FROM_POOL) {

            ExFreePool(pIoVrb->pScatterGather);

            pPVRB->VRBFlags & ~VRB_FLAGS_SGLIST_FROM_POOL;
        }

        pVideoPortReleaseDmaParameters(pDE, pIoVrb);

    }

    //
    // Move bytes transferred into Io structure.
    //

    pIrp->IoStatus.Information = pPVRB->vrp.InputBufferLength;

    //
    // BUGBUG: Check for pending io request???
    //


}
Пример #4
0
BOOLEAN
VideoPortDoDma(
    IN PVOID                        HwDeviceExtension,
    IN PVIDEO_REQUEST_PACKET        pVrp
    )
{
    PDEVICE_EXTENSION            deviceExtension =
                                ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
    PPUBLIC_VIDEO_REQUEST_BLOCK pPVRB;
    PDMA_PARAMETERS             pIoVrb;
    PIRP                        pIrp;

    GET_PVRB_FROM_PVRP(pPVRB, pVrp);

    pIoVrb = pVideoPortGetDmaParameters(deviceExtension, pPVRB);

    if (!pIoVrb) {

        //
        // Can't get DmaParameter storage. set flag and return
        //

        deviceExtension->VRBFlags |= INSUFFICIENT_DMA_RESOURCES;
        return FALSE;
    }

    pIrp                              = pPVRB->pIrp;
    deviceExtension->MapDmaParameters = pIoVrb;

    //
    // Get Mdl for user buffer.
    //

    if (!pPVRB || !IoAllocateMdl(pPVRB->vrp.InputBuffer,
                       pPVRB->vrp.InputBufferLength,
                       FALSE,
                       FALSE,
                       pIrp)) {

            VideoPortDebugPrint(0,
                        "VideoPortIoStartRequest: Can't allocate Mdl\n");

            pPVRB->vrp.StatusBlock->Status = VRB_STATUS_INVALID_REQUEST;

            VideoPortNotification(RequestComplete,
                                 deviceExtension,
                                 pIoVrb);

            VideoPortNotification(NextRequest,
                                 deviceExtension);

            //
            // Queue a DPC to process the work that was just indicated.
            //

            IoRequestDpc(deviceExtension->DeviceObject, NULL, NULL);
            return FALSE;
    }

    //
    // Save the Mdl virtual address
    //

    pIoVrb->DataOffset = MmGetMdlVirtualAddress(pIrp->MdlAddress);

    //
    // Determine if the device needs mapped memory.
    //

    if (deviceExtension->bMapBuffers) {

        if (pIrp->MdlAddress) {
            pIoVrb->DataOffset = MmGetSystemAddressForMdl(pIrp->MdlAddress);

            pPVRB->vrp.InputBuffer  = ((PUCHAR)pIoVrb->DataOffset) +
                                 (ULONG)(((PUCHAR)pPVRB->vrp.InputBuffer) - ((PUCHAR)MmGetMdlVirtualAddress(pIrp->MdlAddress)));
        }
    }

    if (deviceExtension->DmaAdapterObject) {

        //
        // If the buffer is not mapped then the I/O buffer must be flushed
        // to aid in cache coherency.
        //

        KeFlushIoBuffers(pIrp->MdlAddress, TRUE, TRUE);
    }

    //
    // Determine if this adapter needs map registers
    //

    if (deviceExtension->bMasterWithAdapter) {

        //
        // Calculate the number of map registers needed for this transfer.
        // Note that this may be recalculated if the miniport really wants
        // to do DMA
        //

        pIoVrb->NumberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
                pPVRB->vrp.InputBuffer,
                pPVRB->vrp.InputBufferLength
                );
    }

    //
    // The miniport may have requested too big of a buffer, so iteratively
    // chop it in half until we find one we can do. This changes the
    // vrp.InputBufferLength, which the miniport must check to see how much
    // is actually sent and queue up the remainder.
    //

    while (pIoVrb->NumberOfMapRegisters >
        deviceExtension->Capabilities.MaximumPhysicalPages) {

        pPVRB->vrp.InputBufferLength /= 2;

        pIoVrb->NumberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
            pPVRB->vrp.InputBuffer,
            pPVRB->vrp.InputBufferLength
            );

    }

    //
    // Allocate the adapter channel with sufficient map registers
    // for the transfer.
    //

    IoAllocateAdapterChannel(
        deviceExtension->DmaAdapterObject,  // AdapterObject
        deviceExtension->DeviceObject,      // DeviceObject
        pIoVrb->NumberOfMapRegisters,       // NumberOfMapRegisters
        pVideoPortBuildScatterGather,       // ExecutionRoutine (Must return DeallocateObjectKeepRegisters)
        pIoVrb);                            // Context

    //
    // The execution routine called via IoAllocateChannel will do the
    // rest of the work so just return.
    //

    return TRUE;

}
Пример #5
0
VOID
NICHandleRecvInterrupt(
    IN  PFDO_DATA  FdoData
    )
/*++
Routine Description:

    Interrupt handler for receive processing. Put the received packets
    into an array and call NICServiceReadIrps. If we run low on
    RFDs, allocate another one.

    Assumption: This function is called with the Rcv SPINLOCK held.

Arguments:

    FdoData     Pointer to our FdoData

Return Value:

    None

--*/
{
    PMP_RFD         pMpRfd = NULL;
    PHW_RFD         pHwRfd = NULL;

    PMP_RFD         PacketArray[NIC_DEF_RFDS];
    PMP_RFD         PacketFreeArray[NIC_DEF_RFDS];
    UINT            PacketArrayCount;
    UINT            PacketFreeCount;
    UINT            Index;
    UINT            LoopIndex = 0;
    UINT            LoopCount = NIC_MAX_RFDS / NIC_DEF_RFDS + 1;    // avoid staying here too long

    BOOLEAN         bContinue = TRUE;
    BOOLEAN         bAllocNewRfd = FALSE;
    USHORT          PacketStatus;

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "---> NICHandleRecvInterrupt\n");

    ASSERT(FdoData->nReadyRecv >= NIC_MIN_RFDS);

    while (LoopIndex++ < LoopCount && bContinue)
    {
        PacketArrayCount = 0;
        PacketFreeCount = 0;

        //
        // Process up to the array size RFD's
        //
        while (PacketArrayCount < NIC_DEF_RFDS)
        {
            if (IsListEmpty(&FdoData->RecvList))
            {
                ASSERT(FdoData->nReadyRecv == 0);
                bContinue = FALSE;
                break;
            }

            //
            // Get the next MP_RFD to process
            //
            pMpRfd = (PMP_RFD)GetListHeadEntry(&FdoData->RecvList);

            //
            // Get the associated HW_RFD
            //
            pHwRfd = pMpRfd->HwRfd;

            //
            // Is this packet completed?
            //
            PacketStatus = NIC_RFD_GET_STATUS(pHwRfd);
            if (!NIC_RFD_STATUS_COMPLETED(PacketStatus))
            {
                bContinue = FALSE;
                break;
            }

            //
            // HW specific - check if actual count field has been updated
            //
            if (!NIC_RFD_VALID_ACTUALCOUNT(pHwRfd))
            {
                bContinue = FALSE;
                break;
            }


            //
            // Remove the RFD from the head of the List
            //
            RemoveEntryList((PLIST_ENTRY)pMpRfd);
            FdoData->nReadyRecv--;

            ASSERT(MP_TEST_FLAG(pMpRfd, fMP_RFD_RECV_READY));
            MP_CLEAR_FLAG(pMpRfd, fMP_RFD_RECV_READY);

            //
            // A good packet? drop it if not.
            //
            if (!NIC_RFD_STATUS_SUCCESS(PacketStatus))
            {
                TraceEvents(TRACE_LEVEL_WARNING, DBG_READ,
                            "Receive failure = %x\n", PacketStatus);
                NICReturnRFD(FdoData, pMpRfd);
                continue;
            }

            //
            // Do not receive any packets until a filter has been set
            //
            if (!FdoData->PacketFilter)
            {
                NICReturnRFD(FdoData, pMpRfd);
                continue;
            }

            //
            // Do not receive any packets until we are at D0
            //
            if (FdoData->DevicePowerState != PowerDeviceD0)
            {
                NICReturnRFD(FdoData, pMpRfd);
                continue;
            }

            pMpRfd->PacketSize = NIC_RFD_GET_PACKET_SIZE(pHwRfd);

            KeFlushIoBuffers(pMpRfd->Mdl, TRUE, TRUE);

            //
            // set the status on the packet, either resources or success
            //
            if (FdoData->nReadyRecv >= MIN_NUM_RFD)
            {
                MP_SET_FLAG(pMpRfd, fMP_RFD_RECV_PEND);

            }
            else
            {
                MP_SET_FLAG(pMpRfd, fMP_RFD_RESOURCES);

                _Analysis_assume_(PacketFreeCount <= PacketArrayCount);
                PacketFreeArray[PacketFreeCount] = pMpRfd;
                PacketFreeCount++;

                //
                // Reset the RFD shrink count - don't attempt to shrink RFD
                //
                FdoData->RfdShrinkCount = 0;

                //
                // Remember to allocate a new RFD later
                //
                bAllocNewRfd = TRUE;
            }

            PacketArray[PacketArrayCount] = pMpRfd;
            PacketArrayCount++;
        }

        //
        // if we didn't process any receives, just return from here
        //
        if (PacketArrayCount == 0)
        {
            break;
        }


        WdfSpinLockRelease(FdoData->RcvLock);

        WdfSpinLockAcquire(FdoData->Lock);
        //
        // if we have a Recv interrupt and have reported a media disconnect status
        // time to indicate the new status
        //

        if (Disconnected == FdoData->MediaState)
        {
            TraceEvents(TRACE_LEVEL_WARNING, DBG_READ, "Media state changed to Connected\n");

            MP_CLEAR_FLAG(FdoData, fMP_ADAPTER_NO_CABLE);

            FdoData->MediaState = Connected;


            WdfSpinLockRelease(FdoData->Lock);
            //
            // Indicate the media event
            //
            NICServiceIndicateStatusIrp(FdoData);
        }

        else
        {

            WdfSpinLockRelease(FdoData->Lock);
        }


        NICServiceReadIrps(
            FdoData,
            PacketArray,
            PacketArrayCount);


        WdfSpinLockAcquire(FdoData->RcvLock);

        //
        // Return all the RFDs to the pool.
        //
        for (Index = 0; Index < PacketFreeCount; Index++)
        {

            //
            // Get the MP_RFD saved in this packet, in NICAllocRfd
            //
            pMpRfd = PacketFreeArray[Index];

            ASSERT(MP_TEST_FLAG(pMpRfd, fMP_RFD_RESOURCES));
            MP_CLEAR_FLAG(pMpRfd, fMP_RFD_RESOURCES);

            NICReturnRFD(FdoData, pMpRfd);
        }

    }

    //
    // If we ran low on RFD's, we need to allocate a new RFD
    //
    if (bAllocNewRfd)
    {
        //
        // Allocate one more RFD only if it doesn't exceed the max RFD limit
        //
        if (FdoData->CurrNumRfd < FdoData->MaxNumRfd
                    && !FdoData->AllocNewRfd)
        {
            NTSTATUS status;

            FdoData->AllocNewRfd = TRUE;

            //
            // Since we are running at DISPATCH_LEVEL, we will queue a workitem
            // to allocate RFD memory at PASSIVE_LEVEL. Note that
            // AllocateCommonBuffer and FreeCommonBuffer can be called only at
            // PASSIVE_LEVEL.
            //
            status = PciDrvQueuePassiveLevelCallback(FdoData,
                                        NICAllocRfdWorkItem,
                                        NULL, NULL);
            if(!NT_SUCCESS(status)){
                FdoData->AllocNewRfd = FALSE;
            }
        }
    }

    ASSERT(FdoData->nReadyRecv >= NIC_MIN_RFDS);

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "<--- NICHandleRecvInterrupt\n");
}
Пример #6
0
Файл: io.c Проект: GYGit/reactos
/*
 * @implemented
 */
VOID
EXPORT
NdisMSetupDmaTransfer(OUT PNDIS_STATUS Status,
                      IN NDIS_HANDLE MiniportDmaHandle,
                      IN PNDIS_BUFFER Buffer,
                      IN ULONG Offset,
                      IN ULONG Length,
                      IN BOOLEAN WriteToDevice)
{
    PNDIS_DMA_BLOCK DmaBlock = MiniportDmaHandle;
    NTSTATUS NtStatus;
    PLOGICAL_ADAPTER Adapter;
    KIRQL OldIrql;
    PDMA_ADAPTER AdapterObject;
    ULONG MapRegistersNeeded;
    
    NDIS_DbgPrint(MAX_TRACE, ("called: Handle 0x%x, Buffer 0x%x, Offset 0x%x, Length 0x%x, WriteToDevice 0x%x\n",
                              MiniportDmaHandle, Buffer, Offset, Length, WriteToDevice));
    
    Adapter = (PLOGICAL_ADAPTER)DmaBlock->Miniport;
    AdapterObject = (PDMA_ADAPTER)DmaBlock->SystemAdapterObject;
    
    MapRegistersNeeded = (Length + (PAGE_SIZE - 1)) / PAGE_SIZE;
    
    KeFlushIoBuffers(Buffer, !WriteToDevice, TRUE);

    KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
    {
        NtStatus = AdapterObject->DmaOperations->AllocateAdapterChannel(AdapterObject,
                                                                        Adapter->NdisMiniportBlock.PhysicalDeviceObject,
                                                                        MapRegistersNeeded,
                                                                        NdisSubordinateMapRegisterCallback, Adapter);
    }
    KeLowerIrql(OldIrql);
        
    if(!NT_SUCCESS(NtStatus))
    {
        NDIS_DbgPrint(MIN_TRACE, ("AllocateAdapterChannel failed: 0x%x\n", NtStatus));
        AdapterObject->DmaOperations->FreeAdapterChannel(AdapterObject);
        *Status = NDIS_STATUS_RESOURCES;
        return;
    }
    
    NtStatus = KeWaitForSingleObject(&DmaBlock->AllocationEvent, Executive, KernelMode, FALSE, 0);
        
    if(!NT_SUCCESS(NtStatus))
    {
        NDIS_DbgPrint(MIN_TRACE, ("KeWaitForSingleObject failed: 0x%x\n", NtStatus));
        AdapterObject->DmaOperations->FreeAdapterChannel(AdapterObject);
        *Status = NDIS_STATUS_RESOURCES;
        return;
    }
    
    /* We must throw away the return value of MapTransfer for a system DMA device */
    AdapterObject->DmaOperations->MapTransfer(AdapterObject, Buffer,
                                              DmaBlock->MapRegisterBase,
                                              (PUCHAR)MmGetMdlVirtualAddress(Buffer) + Offset, &Length, WriteToDevice);
    
    NDIS_DbgPrint(MAX_TRACE, ("returning success\n"));
    *Status = NDIS_STATUS_SUCCESS;
}
Пример #7
0
///////////////////////////////////////////////////////////////////////////////
//
//  OsrStartWriteIrp
//
//    This is routine is called by the OsrWrite and DpcForIsr routine to
//    start a new Write operation.  The request started is the IRP located
//    at the head of the write queue.
//
//  INPUTS:
//
//      DeviceObject - Address of the DEVICE_OBJECT for our device.
//  
//      Irp - Address of the IRP representing the IRP_MJ_WRITE call.
//
//  OUTPUTS:
//
//      None.
//
//  RETURNS:
//
//      None.
//
//  IRQL:
//
//      This routine is called at IRQL_DISPATCH_LEVEL.
//
//  NOTES:
//      *** Called (and returns) with the WriteQueueLock held.
//
///////////////////////////////////////////////////////////////////////////////
VOID
OsrStartWriteIrp(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
    POSR_DEVICE_EXT devExt = DeviceObject->DeviceExtension;
    PIO_STACK_LOCATION ioStack;
    ULONG mapRegsNeeded;
    
    ioStack = IoGetCurrentIrpStackLocation(Irp);

    //
    // In progress IRPs cannot be cancelled
    //
    IoSetCancelRoutine(Irp, NULL);

#if DBG
    DbgPrint("OsrWrite: Transfer length %d.\n",
                                ioStack->Parameters.Write.Length);
#endif

    //
    // We're starting a request... therefore, we clear the StopEvent
    // flag.
    //
    KeClearEvent(&devExt->StopEvent);

    //
    // There is no in-progress request.  Start this request on the
    // device.
    //
    devExt->CurrentWriteIrp = Irp;

    devExt->WriteTotalLength = ioStack->Parameters.Write.Length;

    devExt->WriteSoFar = 0;

    devExt->WriteStartingOffset = 0;

    //
    // Start the watchdog timer on this IRP
    //
    (ULONG)Irp->Tail.Overlay.DriverContext[0] = OSR_WATCHDOG_INTERVAL;

    //
    // Since we're about to initiate a DMA operation, ensure the user's data
    // buffer is flushed from the cache back into memory, on processors that
    // are non-DMA cache coherent.
    //
    KeFlushIoBuffers(Irp->MdlAddress, FALSE, TRUE);

    //
    // Determine the number of map registers we'll need for this transfer
    //
    mapRegsNeeded = 
        ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
                                        ioStack->Parameters.Write.Length);
        
#if DBG
    DbgPrint("StartWrite: %d. map regs needed\n", mapRegsNeeded);
#endif

    //
    // If the number of map registers required for this transfer exceeds the
    // maximum we're allowed to use (as reported to us from HalGetAdapter() ),
    // we'll need to limit ourselves to the maximum we're allowed.
    //
    devExt->MapRegsThisWrite = ((mapRegsNeeded > devExt->WriteMapRegsGot) ? 
                              devExt->WriteMapRegsGot : mapRegsNeeded);

#if DBG
    DbgPrint("StartWrite: %d. map regs this xfer\n", devExt->MapRegsThisWrite);
#endif

    //
    // Ready to GO! Allocate the appropriate Adapter Object and map registers.
    //
    IoAllocateAdapterChannel(devExt->WriteAdapter,
                             DeviceObject, 
                             devExt->MapRegsThisWrite,
                             OsrAdapterControlWrite,
                             Irp);
}
Пример #8
0
///////////////////////////////////////////////////////////////////////////////
//
//  OsrStartReadIrp
//
//    This is routine is called by the OsrRead and Dpc routine in order to
//    begin a new Read operation.
//
//  INPUTS:
//
//      DeviceObject - Address of the DEVICE_OBJECT for our device.
//  
//      Irp - Address of the IRP representing the IRP_MJ_READ call.
//
//  OUTPUTS:
//
//      None.
//
//  RETURNS:
//
//      None.
//
//  IRQL:
//
//      This routine is called at IRQL_DISPATCH_LEVEL.
//
//  NOTES:
//      *** Called (and returns) with the WriteQueueLock held.
//
///////////////////////////////////////////////////////////////////////////////
VOID
OsrStartReadIrp(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
    POSR_DEVICE_EXT devExt = DeviceObject->DeviceExtension;
    PIO_STACK_LOCATION ioStack;
    ULONG mapRegsNeeded;

    ioStack = IoGetCurrentIrpStackLocation(Irp);

    //
    // In progress IRPs cannot be cancelled
    //
    IoSetCancelRoutine(Irp, NULL);

#if DBG
    DbgPrint("OsrRead: Transfer length %d.\n",
                                ioStack->Parameters.Read.Length);
#endif

    //
    // We're starting a request... therefore, we clear the StopEvent
    // flag.
    //
    KeClearEvent(&devExt->StopEvent);

    //
    // There is no in-progress request.  Start this request on the
    // device.
    //
    devExt->CurrentReadIrp = Irp;

    devExt->ReadTotalLength = ioStack->Parameters.Read.Length;

    devExt->ReadSoFar = 0;

    devExt->ReadStartingOffset = 0;

    //
    // Start the watchdog timer on this IRP
    //
    (ULONG)Irp->Tail.Overlay.DriverContext[0] = OSR_WATCHDOG_INTERVAL;

    //
    // Flush the requestor's buffer back from cache on non-dma coherent
    // machines.
    //
    KeFlushIoBuffers(Irp->MdlAddress, TRUE, TRUE);

    //
    // Determine number of map registers required by this read
    //
    mapRegsNeeded = 
        ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
                                        ioStack->Parameters.Read.Length);
        
#if DBG
    DbgPrint("StartReadIrp: %d. map regs needed\n", mapRegsNeeded);
#endif

    //
    // Limit the number of map registers used to the maximum allowed by the
    // HAL.  We determined this max when we called HalGetAdapter() during
    // our DriverEntry processing.
    //
    devExt->MapRegsThisRead = ((mapRegsNeeded > devExt->ReadMapRegsGot) ? 
                              devExt->ReadMapRegsGot : mapRegsNeeded);

#if DBG
    DbgPrint("StartReadIrp: %d. map regs this xfer\n", devExt->MapRegsThisRead);
#endif

    IoAllocateAdapterChannel(devExt->ReadAdapter,
                             DeviceObject, 
                             devExt->MapRegsThisRead,
                             OsrAdapterControlRead,
                             Irp);


}
Пример #9
0
VOID
sndReStartDMA(
    IN PGLOBAL_DEVICE_INFO pGDI,
    IN int WhichBuffer
    )
/*++

Routine Description:

    Restart the DMA on a given channel

Arguments:

    pGDI -  Supplies pointer to global device info.
    WhichBuffer - which channel to use

Return Value:

    Returns FALSE

--*/
{
    ULONG length;


    length = pGDI->DmaHalfBufferSize;

    //
    // Increment count of pending interrupts.
    //

    pGDI->SoundHardware.TcInterruptsPending += 1;

    dprintf5("sndReStartDMA(): incremented pending interrupts %d",
             pGDI->SoundHardware.TcInterruptsPending);

    //
    // Program the DMA controller registers for the transfer
    // Set the direction of transfer by whether we're wave in or
    // wave out.
    //

    KeFlushIoBuffers( pGDI->pDMABufferMDL[WhichBuffer],
                     (pGDI->Usage == SoundInterruptUsageWaveIn),
                                         TRUE);

    dprintf4("sndReStartDMA(): calling IoMapTransfer BUFFER = %d", WhichBuffer);

    if (pGDI->Usage == SoundInterruptUsageWaveIn) {

        IoMapTransfer(pGDI->pAdapterObject[(WhichBuffer) ? 3 : 2],
                  pGDI->pDMABufferMDL[WhichBuffer],
                  pGDI->pMRB[WhichBuffer],
                  pGDI->DMABuffer[WhichBuffer].Buf,
                  &length,
                  (BOOLEAN)(pGDI->Usage != SoundInterruptUsageWaveIn));

    } else {

        IoMapTransfer(pGDI->pAdapterObject[WhichBuffer],
                  pGDI->pDMABufferMDL[WhichBuffer],
                  pGDI->pMRB[WhichBuffer],
                  pGDI->DMABuffer[WhichBuffer].Buf,
                  &length,
                  (BOOLEAN)(pGDI->Usage != SoundInterruptUsageWaveIn));

    }
}
Пример #10
0
NTSTATUS
SpWmiPassToMiniPort(
    IN     PDEVICE_OBJECT  DeviceObject,
    IN     UCHAR           WmiMinorCode,
    IN OUT PWMI_PARAMETERS WmiParameters
    )
/*++

Routine Description:

   This function pass a WMI request to the miniport driver for processing.
   It creates an SRB which is processed normally by the port driver.  This
   call is synchronous.

   Callers of SpWmiPassToMiniPort must be running at IRQL PASSIVE_LEVEL.

Arguments:

   DeviceObject  - Pointer to the functional or physical device object.

   WmiMinorCode  - WMI action to perform.

   WmiParameters - WMI parameters.

Return Value:

   An NTSTATUS code describing the result of handling the WMI request.
   Complete the IRP with this status.

Notes:

   If this WMI request is completed with STATUS_SUCCESS, the WmiParameters
   BufferSize field will reflect the actual size of the WMI return buffer.

--*/
{
    PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
    PADAPTER_EXTENSION fdoExtension;
    SCSI_WMI_REQUEST_BLOCK   srb;
    LARGE_INTEGER            startingOffset;
    PLOGICAL_UNIT_EXTENSION  logicalUnit;

    ULONG                    commonBufferSize;
    PUCHAR                   commonBuffer;
    PHYSICAL_ADDRESS         physicalAddress;
    PVOID                    removeTag = (PVOID)((ULONG_PTR)WmiParameters+3);
    PWNODE_HEADER            wnode;

    NTSTATUS status;

    PAGED_CODE();

    startingOffset.QuadPart = (LONGLONG) 1;

    //
    // Zero out the SRB.
    //
    RtlZeroMemory(&srb, sizeof(SCSI_WMI_REQUEST_BLOCK));

    //
    // Initialize the SRB for a WMI request.
    //
    if (commonExtension->IsPdo) {                                       // [PDO]

        //
        // Set the logical unit addressing from this PDO's device extension.
        //
        logicalUnit = DeviceObject->DeviceExtension;

        SpAcquireRemoveLock(DeviceObject, removeTag);

        srb.PathId      = logicalUnit->PathId;
        srb.TargetId    = logicalUnit->TargetId;
        srb.Lun         = logicalUnit->Lun;

        fdoExtension = logicalUnit->AdapterExtension;

    } else {                                                            // [FDO]

        //
        // Set the logical unit addressing to the first logical unit.  This is
        // merely used for addressing purposes for adapter requests only.
        // NOTE: SpFindSafeLogicalUnit will acquire the remove lock
        //

        logicalUnit = SpFindSafeLogicalUnit(DeviceObject,
                                            0xff,
                                            removeTag);

        if (logicalUnit == NULL) {
            return(STATUS_DEVICE_DOES_NOT_EXIST);
        }

        fdoExtension = DeviceObject->DeviceExtension;

        srb.WMIFlags    = SRB_WMI_FLAGS_ADAPTER_REQUEST;
        srb.PathId      = logicalUnit->PathId;
        srb.TargetId    = logicalUnit->TargetId;
        srb.Lun         = logicalUnit->Lun;
    }

    //
    // HACK - allocate a chunk of common buffer for the actual request to
    // get processed in. We need to determine the size of buffer to allocate
    // this is the larger of the input or output buffers
    //

    if (WmiMinorCode == IRP_MN_EXECUTE_METHOD)
    {
        wnode = (PWNODE_HEADER)WmiParameters->Buffer;
        commonBufferSize = (WmiParameters->BufferSize > wnode->BufferSize) ?
                            WmiParameters->BufferSize :
                            wnode->BufferSize;
    } else {
        commonBufferSize = WmiParameters->BufferSize;
    }
                        
    commonBuffer = HalAllocateCommonBuffer(fdoExtension->DmaAdapterObject,
                                           commonBufferSize,
                                           &physicalAddress,
                                           FALSE);

    if(commonBuffer == NULL) {
        DebugPrint((1, "SpWmiPassToMiniPort: Unable to allocate %#x bytes of "
                       "common buffer\n", commonBufferSize));
        
        SpReleaseRemoveLock(logicalUnit->DeviceObject, removeTag);

        return STATUS_INSUFFICIENT_RESOURCES;
    }

    try {
        KEVENT event;
        PIRP irp;
        PMDL mdl;
        PIO_STACK_LOCATION irpStack;

        RtlCopyMemory(commonBuffer, WmiParameters->Buffer, commonBufferSize);
    
        srb.DataBuffer         = commonBuffer;       // [already non-paged]
        srb.DataTransferLength = WmiParameters->BufferSize;
        srb.Function           = SRB_FUNCTION_WMI;
        srb.Length             = sizeof(SCSI_REQUEST_BLOCK);
        srb.WMISubFunction     = WmiMinorCode;
        srb.DataPath           = WmiParameters->DataPath;
        srb.SrbFlags           = SRB_FLAGS_DATA_IN | SRB_FLAGS_NO_QUEUE_FREEZE;
        srb.TimeOutValue       = 10;                                // [ten seconds]
    
        //
        // Note that the value in DataBuffer may be used regardless of the value
        // of the MapBuffers field.
        //
    
        //
        // Initialize the notification event.
        //

        KeInitializeEvent(&event, NotificationEvent, FALSE);
    
        //
        // Build IRP for this request.
        // Note we do this synchronously for two reasons.  If it was done
        // asynchonously then the completion code would have to make a special
        // check to deallocate the buffer.  Second if a completion routine were
        // used then an additional IRP stack location would be needed.
        //

        irp = IoAllocateIrp(logicalUnit->DeviceObject->StackSize, FALSE);

        if(irp == NULL) {
            status = STATUS_INSUFFICIENT_RESOURCES;
            leave;
        }

        mdl = IoAllocateMdl(commonBuffer,
                            WmiParameters->BufferSize,
                            FALSE,
                            FALSE,
                            irp);

        if(mdl == NULL) {
            IoFreeIrp(irp);
            status = STATUS_INSUFFICIENT_RESOURCES;
            leave;
        }

        MmBuildMdlForNonPagedPool(mdl);

        srb.OriginalRequest = irp;
    
        irpStack = IoGetNextIrpStackLocation(irp);
    
        //
        // Set major code.
        //
        irpStack->MajorFunction = IRP_MJ_SCSI;
    
        //
        // Set SRB pointer.
        //
        irpStack->Parameters.Scsi.Srb = (PSCSI_REQUEST_BLOCK)&srb;
    
        //
        // Setup a completion routine so we know when the request has completed.
        //

        IoSetCompletionRoutine(irp,
                               SpSignalCompletion,
                               &event,
                               TRUE,
                               TRUE,
                               TRUE);

        //
        // Flush the data buffer for output.  This will insure that the data is
        // written back to memory.  Since the data-in flag is the the port driver
        // will flush the data again for input which will ensure the data is not
        // in the cache.
        //
        KeFlushIoBuffers(irp->MdlAddress, FALSE, TRUE);
    
        //
        // Call port driver to handle this request.
        //
        IoCallDriver(logicalUnit->CommonExtension.DeviceObject, irp);
    
        //
        // Wait for request to complete.
        //
        KeWaitForSingleObject(&event,
                              Executive,
                              KernelMode,
                              FALSE,
                              NULL);
    
        status = irp->IoStatus.Status;

        //
        // Relay the return buffer's size to the caller on success.
        //
        if (NT_SUCCESS(status)) {
            WmiParameters->BufferSize = srb.DataTransferLength;
        }
    
        //
        // Copy back the correct number of bytes into the caller provided buffer.
        //
    
        RtlCopyMemory(WmiParameters->Buffer,
                      commonBuffer,
                      WmiParameters->BufferSize);

        //
        // Free the irp and MDL.
        //

        IoFreeMdl(mdl);
        IoFreeIrp(irp);

    } finally {

        HalFreeCommonBuffer(fdoExtension->DmaAdapterObject,
                            commonBufferSize,
                            physicalAddress,
                            commonBuffer,
                            FALSE);
    
        SpReleaseRemoveLock(logicalUnit->CommonExtension.DeviceObject,
                            removeTag);
    }

    //
    // Return the IRP's status.
    //
    return status;
}
Пример #11
0
dVoid kdi_ProgramDMA
(
/* INPUT PARAMETERS:  */

	dVoidPtr		context,
	dBoolean		write_operation,
	dVoidPtr		phy_data_ptr,
	dUDWord		bytes_transferred_so_far,

/* UPDATE PARAMETERS: */

	dUDWordPtr	total_bytes_of_transfer_ptr

/* OUTPUT PARAMETERS: */

)
/* COMMENTS: *****************************************************************
 *
 * DEFINITIONS: *************************************************************/
{

/* DATA: ********************************************************************/

   PHYSICAL_ADDRESS val;
    KdiContextPtr   kdi_context = (KdiContextPtr)context;

/* CODE: ********************************************************************/


   kdi_LockUnlockDMA(kdi_context, dTRUE);

   //
   // Map the transfer through the DMA hardware.
   //

   KeFlushIoBuffers( phy_data_ptr, !write_operation, dTRUE );

/*
   DbgAddEntry(0x1234567a);
   DbgAddEntry((dUDWord)kdi_context->adapter_object);
   DbgAddEntry((dUDWord)phy_data_ptr);
   DbgAddEntry((dUDWord)kdi_context->map_register_base);
   DbgAddEntry((dUDWord) MmGetMdlVirtualAddress(phy_data_ptr)
            + bytes_transferred_so_far );
   DbgAddEntry(*total_bytes_of_transfer_ptr);
   DbgAddEntry(write_operation);
*/

   val = IoMapTransfer(
      kdi_context->adapter_object,
      phy_data_ptr,
      kdi_context->map_register_base,
      (dVoidPtr)( (dUDWord) MmGetMdlVirtualAddress((PMDL)phy_data_ptr)
            + bytes_transferred_so_far ),
      total_bytes_of_transfer_ptr,
      write_operation );
/*
   DbgAddEntry(val.HighPart);
   DbgAddEntry(val.LowPart);
   DbgAddEntry(*total_bytes_of_transfer_ptr);
*/
}
Пример #12
0
VOID
NICHandleRecvInterrupt(
    IN  PFDO_DATA  FdoData
    )
/*++
Routine Description:

    Interrupt handler for receive processing. Put the received packets
    into an array and call NICServiceReadIrps. If we run low on
    RFDs, allocate another one.

    Assumption: This function is called with the Rcv SPINLOCK held.

Arguments:

    FdoData     Pointer to our FdoData

Return Value:

    None

--*/
{
    PMP_RFD         pMpRfd = NULL;
    PULONG          pHwRfd = NULL;

    PMP_RFD         PacketArray[NIC_DEF_RFDS];
    PMP_RFD         PacketFreeArray[NIC_DEF_RFDS];
    UINT            PacketArrayCount;
    UINT            PacketFreeCount;
    UINT            Index;
    UINT            LoopIndex = 0;
    UINT            LoopCount = NIC_MAX_RFDS / NIC_DEF_RFDS + 1;    // avoid staying here too long

    BOOLEAN         bContinue = TRUE;
    BOOLEAN         bAllocNewRfd = FALSE;

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "---> NICHandleRecvInterrupt\n");

    ASSERT(FdoData->nReadyRecv >= NIC_MIN_RFDS);

    while (LoopIndex++ < LoopCount && bContinue)
    {
        PacketArrayCount = 0;
        PacketFreeCount = 0;

        //
        // Process up to the array size RFD's
        //
        while (PacketArrayCount < NIC_DEF_RFDS)
        {
            if (IsListEmpty(&FdoData->RecvList))
            {
                ASSERT(FdoData->nReadyRecv == 0);
                bContinue = FALSE;
                break;
            }

            //
            // Get the next MP_RFD to process
            //
            pMpRfd = (PMP_RFD)GetListHeadEntry(&FdoData->RecvList);

            //
            // Get the associated HW_RFD
            //
            pHwRfd = pMpRfd->HwRfd;

            //
            // Remove the RFD from the head of the List
            //
            RemoveEntryList((PLIST_ENTRY)pMpRfd);
            FdoData->nReadyRecv--;

            ASSERT(MP_TEST_FLAG(pMpRfd, fMP_RFD_RECV_READY));
            MP_CLEAR_FLAG(pMpRfd, fMP_RFD_RECV_READY);

            pMpRfd->PacketSize = 4;

            KeFlushIoBuffers(pMpRfd->Mdl, TRUE, TRUE);

            MP_SET_FLAG(pMpRfd, fMP_RFD_RECV_PEND);

            PacketArray[PacketArrayCount] = pMpRfd;
            PacketArrayCount++;
        }

        //
        // if we didn't process any receives, just return from here
        //
        if (PacketArrayCount == 0)
        {
            break;
        }


        WdfSpinLockRelease(FdoData->RcvLock);

        NICServiceReadIrps(
            FdoData,
            PacketArray,
            PacketArrayCount);


        WdfSpinLockAcquire(FdoData->RcvLock);

        //
        // Return all the RFDs to the pool.
        //
        for (Index = 0; Index < PacketFreeCount; Index++)
        {

            //
            // Get the MP_RFD saved in this packet, in NICAllocRfd
            //
            pMpRfd = PacketFreeArray[Index];

            ASSERT(MP_TEST_FLAG(pMpRfd, fMP_RFD_RESOURCES));
            MP_CLEAR_FLAG(pMpRfd, fMP_RFD_RESOURCES);

            NICReturnRFD(FdoData, pMpRfd);
        }

    }

    ASSERT(FdoData->nReadyRecv >= NIC_MIN_RFDS);

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "<--- NICHandleRecvInterrupt\n");
}
Пример #13
0
VOID NTAPI
ReadWritePassive(PDRIVE_INFO DriveInfo, PIRP Irp)
/*
 * FUNCTION: Handle the first phase of a read or write IRP
 * ARGUMENTS:
 *     DeviceObject: DeviceObject that is the target of the IRP
 *     Irp: IRP to process
 * RETURNS:
 *     STATUS_VERIFY_REQUIRED if the media has changed and we need the filesystems to re-synch
 *     STATUS_SUCCESS otherwise
 * NOTES:
 *     - Must be called at PASSIVE_LEVEL
 *     - This function is about 250 lines longer than I wanted it to be.  Sorry.
 *
 * DETAILS:
 *  This routine manages the whole process of servicing a read or write request.  It goes like this:
 *    1) Check the DO_VERIFY_VOLUME flag and return if it's set
 *    2) Check the disk change line and notify the OS if it's set and return
 *    3) Detect the media if we haven't already
 *    4) Set up DiskByteOffset, Length, and WriteToDevice parameters
 *    5) Get DMA map registers
 *    6) Then, in a loop for each track, until all bytes are transferred:
 *      a) Compute the current CHS to set the read/write head to
 *      b) Seek to that spot
 *      c) Compute the last sector to transfer on that track
 *      d) Map the transfer through DMA
 *      e) Send the read or write command to the controller
 *      f) Read the results of the command
 */
{
    PDEVICE_OBJECT DeviceObject = DriveInfo->DeviceObject;
    PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
    BOOLEAN WriteToDevice;
    ULONG Length;
    ULONG DiskByteOffset;
    KIRQL OldIrql;
    NTSTATUS Status;
    BOOLEAN DiskChanged;
    ULONG_PTR TransferByteOffset;
    UCHAR Gap;

    PAGED_CODE();

    TRACE_(FLOPPY, "ReadWritePassive called to %s 0x%x bytes from offset 0x%x\n",
           (Stack->MajorFunction == IRP_MJ_READ ? "read" : "write"),
           (Stack->MajorFunction == IRP_MJ_READ ? Stack->Parameters.Read.Length : Stack->Parameters.Write.Length),
           (Stack->MajorFunction == IRP_MJ_READ ? Stack->Parameters.Read.ByteOffset.u.LowPart :
            Stack->Parameters.Write.ByteOffset.u.LowPart));

    /* Default return codes */
    Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
    Irp->IoStatus.Information = 0;

    /*
     * Check to see if the volume needs to be verified.  If so,
     * we can get out of here quickly.
     */
    if(DeviceObject->Flags & DO_VERIFY_VOLUME && !(Stack->Flags & SL_OVERRIDE_VERIFY_VOLUME))
    {
        INFO_(FLOPPY, "ReadWritePassive(): DO_VERIFY_VOLUME set; Completing with  STATUS_VERIFY_REQUIRED\n");
        Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
        IoCompleteRequest(Irp, IO_NO_INCREMENT);
        return;
    }

    /*
     * Check the change line, and if it's set, return
     */
    StartMotor(DriveInfo);
    if(HwDiskChanged(DeviceObject->DeviceExtension, &DiskChanged) != STATUS_SUCCESS)
    {
        WARN_(FLOPPY, "ReadWritePassive(): unable to detect disk change; Completing with STATUS_UNSUCCESSFUL\n");
        IoCompleteRequest(Irp, IO_NO_INCREMENT);
        StopMotor(DriveInfo->ControllerInfo);
        return;
    }

    if(DiskChanged)
    {
        INFO_(FLOPPY, "ReadWritePhase1(): signalling media changed; Completing with STATUS_MEDIA_CHANGED\n");

        /* The following call sets IoStatus.Status and IoStatus.Information */
        SignalMediaChanged(DeviceObject, Irp);

        /*
         * Guessing at something... see ioctl.c for more info
         */
        if(ResetChangeFlag(DriveInfo) == STATUS_NO_MEDIA_IN_DEVICE)
            Irp->IoStatus.Status = STATUS_NO_MEDIA_IN_DEVICE;

        IoCompleteRequest(Irp, IO_NO_INCREMENT);
        StopMotor(DriveInfo->ControllerInfo);
        return;
    }

    /*
     * Figure out the media type, if we don't know it already
     */
    if(DriveInfo->DiskGeometry.MediaType == Unknown)
    {
        if(RWDetermineMediaType(DriveInfo) != STATUS_SUCCESS)
        {
            WARN_(FLOPPY, "ReadWritePassive(): unable to determine media type; completing with STATUS_UNSUCCESSFUL\n");
            IoCompleteRequest(Irp, IO_NO_INCREMENT);
            StopMotor(DriveInfo->ControllerInfo);
            return;
        }

        if(DriveInfo->DiskGeometry.MediaType == Unknown)
        {
            WARN_(FLOPPY, "ReadWritePassive(): Unknown media in drive; completing with STATUS_UNRECOGNIZED_MEDIA\n");
            Irp->IoStatus.Status = STATUS_UNRECOGNIZED_MEDIA;
            IoCompleteRequest(Irp, IO_NO_INCREMENT);
            StopMotor(DriveInfo->ControllerInfo);
            return;
        }
    }

    /* Set up parameters for read or write */
    if(Stack->MajorFunction == IRP_MJ_READ)
    {
        Length = Stack->Parameters.Read.Length;
        DiskByteOffset = Stack->Parameters.Read.ByteOffset.u.LowPart;
        WriteToDevice = FALSE;
    }
    else
    {
        Length = Stack->Parameters.Write.Length;
        DiskByteOffset = Stack->Parameters.Write.ByteOffset.u.LowPart;
        WriteToDevice = TRUE;
    }

    /*
     * FIXME:
     *   FloppyDeviceData.ReadWriteGapLength specify the value for the physical drive.
     *   We should set this value depend on the format of the inserted disk and possible
     *   depend on the request (read or write). A value of 0 results in one rotation
     *   between the sectors (7.2sec for reading a track).
     */
    Gap = DriveInfo->FloppyDeviceData.ReadWriteGapLength;

    /*
     * Set up DMA transfer
     *
     * This is as good of a place as any to document something that used to confuse me
     * greatly (and I even wrote some of the kernel's DMA code, so if it confuses me, it
     * probably confuses at least a couple of other people too).
     *
     * MmGetMdlVirtualAddress() returns the virtal address, as mapped in the buffer's original
     * process context, of the MDL.  In other words:  say you start with a buffer at address X, then
     * you build an MDL out of that buffer called Mdl. If you call MmGetMdlVirtualAddress(Mdl), it
     * will return X.
     *
     * There are two parameters that the function looks at to produce X again, given the MDL:  the
     * first is the StartVa, which is the base virtual address of the page that the buffer starts
     * in.  If your buffer's virtual address is 0x12345678, StartVa will be 0x12345000, assuming 4K pages
     * (which is (almost) always the case on x86).  Note well: this address is only valid in the
     * process context that you initially built the MDL from.  The physical pages that make up
     * the MDL might perhaps be mapped in other process contexts too (or even in the system space,
     * above 0x80000000 (default; 0xc0000000 on current Odyssey or /3GB Windows)), but it will
     * (possibly) be mapped at a different address.
     *
     * The second parameter is the ByteOffset.  Given an original buffer address of 0x12345678,
     * the ByteOffset would be 0x678.  Because MDLs can only describe full pages (and therefore
     * StartVa always points to the start address of a page), the ByteOffset must be used to
     * find the real start of the buffer.
     *
     * In general, if you add the StartVa and ByteOffset together, you get back your original
     * buffer pointer, which you are free to use if you're sure you're in the right process
     * context.  You could tell by accessing the (hidden and not-to-be-used) Process member of
     * the MDL, but in general, if you have to ask whether or not you are in the right context,
     * then you shouldn't be using this address for anything anyway.  There are also security implications
     * (big ones, really, I wouldn't kid about this) to directly accessing a user's buffer by VA, so
     * Don't Do That.
     *
     * There is a somewhat weird but very common use of the virtual address associated with a MDL
     * that pops up often in the context of DMA.  DMA APIs (particularly MapTransfer()) need to
     * know where the memory is that they should DMA into and out of.  This memory is described
     * by a MDL.  The controller eventually needs to know a physical address on the host side,
     * which is generally a 32-bit linear address (on x86), and not just a page address.  Therefore,
     * the DMA APIs look at the ByteOffset field of the MDL to reconstruct the real address that
     * should be programmed into the DMA controller.
     *
     * It is often the case that a transfer needs to be broken down over more than one DMA operation,
     * particularly when it is a big transfer and the HAL doesn't give you enough map registers
     * to map the whole thing at once.  Therefore, the APIs need a way to tell how far into the MDL
     * they should look to transfer the next chunk of bytes.  Now, Microsoft could have designed
     * MapTransfer to take a  "MDL offset" argument, starting with 0, for how far into the buffer to
     * start, but it didn't.  Instead, MapTransfer asks for the virtual address of the MDL as an "index" into
     * the MDL.  The way it computes how far into the page to start the transfer is by masking off all but
     * the bottom 12 bits (on x86) of the number you supply as the CurrentVa and using *that* as the
     * ByteOffset instead of the one in the MDL.  (OK, this varies a bit by OS and version, but this
     * is the effect).
     *
     * In other words, you get a number back from MmGetMdlVirtualAddress that represents the start of your
     * buffer, and you pass it to the first MapTransfer call.  Then, for each successive operation
     * on the same buffer, you increment that address to point to the next spot in the MDL that
     * you want to DMA to/from.  The fact that the virtual address you're manipulating is probably not
     * mapped into the process context that you're running in is irrelevant, since it's only being
     * used to index into the MDL.
     */

    /* Get map registers for DMA */
    KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
    Status = IoAllocateAdapterChannel(DriveInfo->ControllerInfo->AdapterObject, DeviceObject,
                                      DriveInfo->ControllerInfo->MapRegisters, MapRegisterCallback, DriveInfo->ControllerInfo);
    KeLowerIrql(OldIrql);

    if(Status != STATUS_SUCCESS)
    {
        WARN_(FLOPPY, "ReadWritePassive(): unable allocate an adapter channel; completing with STATUS_UNSUCCESSFUL\n");
        IoCompleteRequest(Irp, IO_NO_INCREMENT);
        StopMotor(DriveInfo->ControllerInfo);
        return ;
    }


    /*
     * Read from (or write to) the device
     *
     * This has to be called in a loop, as you can only transfer data to/from a single track at
     * a time.
     */
    TransferByteOffset = 0;
    while(TransferByteOffset < Length)
    {
        UCHAR Cylinder;
        UCHAR Head;
        UCHAR StartSector;
        ULONG CurrentTransferBytes;
        UCHAR CurrentTransferSectors;

        INFO_(FLOPPY, "ReadWritePassive(): iterating in while (TransferByteOffset = 0x%x of 0x%x total) - allocating %d registers\n",
              TransferByteOffset, Length, DriveInfo->ControllerInfo->MapRegisters);

        KeClearEvent(&DriveInfo->ControllerInfo->SynchEvent);

        /*
         * Compute starting CHS
         */
        if(RWComputeCHS(DriveInfo, DiskByteOffset+TransferByteOffset, &Cylinder, &Head, &StartSector) != STATUS_SUCCESS)
        {
            WARN_(FLOPPY, "ReadWritePassive(): unable to compute CHS; completing with STATUS_UNSUCCESSFUL\n");
            RWFreeAdapterChannel(DriveInfo->ControllerInfo->AdapterObject);
            IoCompleteRequest(Irp, IO_NO_INCREMENT);
            StopMotor(DriveInfo->ControllerInfo);
            return;
        }

        /*
         * Seek to the right track
         */
        if(!DriveInfo->ControllerInfo->ImpliedSeeks)
        {
            if(RWSeekToCylinder(DriveInfo, Cylinder) != STATUS_SUCCESS)
            {
                WARN_(FLOPPY, "ReadWritePassive(): unable to seek; completing with STATUS_UNSUCCESSFUL\n");
                RWFreeAdapterChannel(DriveInfo->ControllerInfo->AdapterObject);
                IoCompleteRequest(Irp, IO_NO_INCREMENT);
                StopMotor(DriveInfo->ControllerInfo);
                return ;
            }
        }

        /*
         * Compute last sector
         *
         * We can only ask for a transfer up to the end of the track.  Then we have to re-seek and do more.
         * TODO: Support the MT bit
         */
        INFO_(FLOPPY, "ReadWritePassive(): computing number of sectors to transfer (StartSector 0x%x): ", StartSector);

        /* 1-based sector number */
        if( (((DriveInfo->DiskGeometry.TracksPerCylinder - Head) * DriveInfo->DiskGeometry.SectorsPerTrack - StartSector) + 1 ) <
                (Length - TransferByteOffset) / DriveInfo->DiskGeometry.BytesPerSector)
        {
            CurrentTransferSectors = (UCHAR)((DriveInfo->DiskGeometry.TracksPerCylinder - Head) * DriveInfo->DiskGeometry.SectorsPerTrack - StartSector) + 1;
        }
        else
        {
            CurrentTransferSectors = (UCHAR)((Length - TransferByteOffset) / DriveInfo->DiskGeometry.BytesPerSector);
        }

        INFO_(FLOPPY, "0x%x\n", CurrentTransferSectors);

        CurrentTransferBytes = CurrentTransferSectors * DriveInfo->DiskGeometry.BytesPerSector;

        /*
         * Adjust to map registers
         * BUG: Does this take into account page crossings?
         */
        INFO_(FLOPPY, "ReadWritePassive(): Trying to transfer 0x%x bytes\n", CurrentTransferBytes);

        ASSERT(CurrentTransferBytes);

        if(BYTES_TO_PAGES(CurrentTransferBytes) > DriveInfo->ControllerInfo->MapRegisters)
        {
            CurrentTransferSectors = (UCHAR)((DriveInfo->ControllerInfo->MapRegisters * PAGE_SIZE) /
                                             DriveInfo->DiskGeometry.BytesPerSector);

            CurrentTransferBytes = CurrentTransferSectors * DriveInfo->DiskGeometry.BytesPerSector;

            INFO_(FLOPPY, "ReadWritePassive: limiting transfer to 0x%x bytes (0x%x sectors) due to map registers\n",
                  CurrentTransferBytes, CurrentTransferSectors);
        }

        /* set up this round's dma operation */
        /* param 2 is ReadOperation --> opposite of WriteToDevice that IoMapTransfer takes.  BAD MS. */
        KeFlushIoBuffers(Irp->MdlAddress, !WriteToDevice, TRUE);

        IoMapTransfer(DriveInfo->ControllerInfo->AdapterObject, Irp->MdlAddress,
                      DriveInfo->ControllerInfo->MapRegisterBase,
                      (PVOID)((ULONG_PTR)MmGetMdlVirtualAddress(Irp->MdlAddress) + TransferByteOffset),
                      &CurrentTransferBytes, WriteToDevice);

        /*
         * Read or Write
         */
        KeClearEvent(&DriveInfo->ControllerInfo->SynchEvent);

        /* Issue the read/write command to the controller.  Note that it expects the opposite of WriteToDevice. */
        if(HwReadWriteData(DriveInfo->ControllerInfo, !WriteToDevice, DriveInfo->UnitNumber, Cylinder, Head, StartSector,
                           DriveInfo->BytesPerSectorCode, DriveInfo->DiskGeometry.SectorsPerTrack, Gap, 0xff) != STATUS_SUCCESS)
        {
            WARN_(FLOPPY, "ReadWritePassive(): HwReadWriteData returned failure; unable to read; completing with STATUS_UNSUCCESSFUL\n");
            RWFreeAdapterChannel(DriveInfo->ControllerInfo->AdapterObject);
            IoCompleteRequest(Irp, IO_NO_INCREMENT);
            StopMotor(DriveInfo->ControllerInfo);
            return ;
        }

        INFO_(FLOPPY, "ReadWritePassive(): HwReadWriteData returned -- waiting on event\n");

        /*
         * At this point, we block and wait for an interrupt
         * FIXME: this seems to take too long
         */
        WaitForControllerInterrupt(DriveInfo->ControllerInfo);

        /* Read is complete; flush & free adapter channel */
        IoFlushAdapterBuffers(DriveInfo->ControllerInfo->AdapterObject, Irp->MdlAddress,
                              DriveInfo->ControllerInfo->MapRegisterBase,
                              (PVOID)((ULONG_PTR)MmGetMdlVirtualAddress(Irp->MdlAddress) + TransferByteOffset),
                              CurrentTransferBytes, WriteToDevice);

        /* Read the results from the drive */
        if(HwReadWriteResult(DriveInfo->ControllerInfo) != STATUS_SUCCESS)
        {
            WARN_(FLOPPY, "ReadWritePassive(): HwReadWriteResult returned failure; unable to read; completing with STATUS_UNSUCCESSFUL\n");
            HwDumpRegisters(DriveInfo->ControllerInfo);
            RWFreeAdapterChannel(DriveInfo->ControllerInfo->AdapterObject);
            IoCompleteRequest(Irp, IO_NO_INCREMENT);
            StopMotor(DriveInfo->ControllerInfo);
            return ;
        }

        TransferByteOffset += CurrentTransferBytes;
    }

    RWFreeAdapterChannel(DriveInfo->ControllerInfo->AdapterObject);

    /* That's all folks! */
    INFO_(FLOPPY, "ReadWritePassive(): success; Completing with STATUS_SUCCESS\n");
    Irp->IoStatus.Status = STATUS_SUCCESS;
    Irp->IoStatus.Information = Length;
    IoCompleteRequest(Irp, IO_DISK_INCREMENT);
    StopMotor(DriveInfo->ControllerInfo);
}