VOID VioCryptIoStop(IN WDFQUEUE Queue,
    IN WDFREQUEST Request,
    IN ULONG ActionFlags)
{
    BOOLEAN bCancellable = (ActionFlags & WdfRequestStopRequestCancelable) != 0;
    UNREFERENCED_PARAMETER(Queue);

    Trace(TRACE_LEVEL_INFORMATION, "[%s] Req %p, action %X, the request is %scancellable",
        __FUNCTION__, Request, ActionFlags, bCancellable ? "" : "not ");

    if (ActionFlags & WdfRequestStopActionSuspend)
    {
        // the driver owns the request and it will not be able to process it
        Trace(TRACE_LEVEL_INFORMATION, "[%s] Req %p can't be suspended", __FUNCTION__, Request);
        if (!bCancellable || WdfRequestUnmarkCancelable(Request) != STATUS_CANCELLED)
        {
            WdfRequestComplete(Request, STATUS_CANCELLED);
        }
    }
    else if (ActionFlags & WdfRequestStopActionPurge)
    {
        Trace(TRACE_LEVEL_INFORMATION, "[%s] Req %p purged", __FUNCTION__, Request);
        if (!bCancellable || WdfRequestUnmarkCancelable(Request) != STATUS_CANCELLED)
        {
            WdfRequestComplete(Request, STATUS_CANCELLED);
        }
    }
}
VOID
VIOSerialPortIoStop(
    IN WDFQUEUE   Queue,
    IN WDFREQUEST Request,
    IN ULONG      ActionFlags
    )
{
    PRAWPDO_VIOSERIAL_PORT  pdoData = RawPdoSerialPortGetData(WdfIoQueueGetDevice(Queue));
    PVIOSERIAL_PORT    pport = pdoData->port;

    ASSERT(pport->PendingReadRequest == Request);
    TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "-->%s\n", __FUNCTION__);

    WdfSpinLockAcquire(pport->InBufLock);
    if (ActionFlags &  WdfRequestStopActionSuspend )
    {
        WdfRequestStopAcknowledge(Request, FALSE);
    }
    else if(ActionFlags &  WdfRequestStopActionPurge)
    {
        if (WdfRequestUnmarkCancelable(Request) != STATUS_CANCELLED)
        {
           pport->PendingReadRequest = NULL;
           WdfRequestCompleteWithInformation(Request , STATUS_CANCELLED, 0L);
        }
    }
    WdfSpinLockRelease(pport->InBufLock);
    return;
}
VOID VIOSerialPortWriteIoStop(IN WDFQUEUE Queue,
                              IN WDFREQUEST Request,
                              IN ULONG ActionFlags)
{
   PRAWPDO_VIOSERIAL_PORT pdoData = RawPdoSerialPortGetData(
      WdfIoQueueGetDevice(Queue));
   PVIOSERIAL_PORT pport = pdoData->port;

   TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "--> %s\n", __FUNCTION__);

   WdfSpinLockAcquire(pport->OutVqLock);
   if (ActionFlags & WdfRequestStopActionSuspend)
   {
      WdfRequestStopAcknowledge(Request, FALSE);
   }
   else if (ActionFlags & WdfRequestStopActionPurge)
   {
      if (WdfRequestUnmarkCancelable(Request) != STATUS_CANCELLED)
      {
         pport->PendingWriteRequest = NULL;
         WdfRequestComplete(Request, STATUS_OBJECT_NO_LONGER_EXISTS);
      }
   }
   WdfSpinLockRelease(pport->OutVqLock);

   TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "<-- %s\n", __FUNCTION__);
}
VOID
BalloonInterruptDpc(
    IN WDFINTERRUPT WdfInterrupt,
    IN WDFOBJECT    WdfDevice
    )
{
    unsigned int          len;
    PDEVICE_CONTEXT       devCtx = GetDeviceContext(WdfDevice);

    BOOLEAN               bHostAck = FALSE;
    UNREFERENCED_PARAMETER( WdfInterrupt );

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC, "--> %s\n", __FUNCTION__);

    if (virtqueue_get_buf(devCtx->InfVirtQueue, &len))
    {
        bHostAck = TRUE;
    }
    if (virtqueue_get_buf(devCtx->DefVirtQueue, &len))
    {
        bHostAck = TRUE;
    }

    if(bHostAck)
    {
        KeSetEvent (&devCtx->HostAckEvent, IO_NO_INCREMENT, FALSE);
    }

    if (devCtx->StatVirtQueue &&
        virtqueue_get_buf(devCtx->StatVirtQueue, &len))
    {
        WDFREQUEST request = devCtx->PendingWriteRequest;

        devCtx->HandleWriteRequest = TRUE;

        if ((request != NULL) &&
            (WdfRequestUnmarkCancelable(request) != STATUS_CANCELLED))
        {
            NTSTATUS status;
            PVOID buffer;
            size_t length = 0;

            devCtx->PendingWriteRequest = NULL;

            status = WdfRequestRetrieveInputBuffer(request, 0, &buffer, &length);
            if (!NT_SUCCESS(status))
            {
                length = 0;
            }
            WdfRequestCompleteWithInformation(request, status, length);
        }
    }

    if(devCtx->Thread)
    {
       KeSetEvent(&devCtx->WakeUpThread, 0, FALSE);
    }
}
VOID VIOSerialReclaimConsumedBuffers(IN PVIOSERIAL_PORT Port)
{
    WDFREQUEST request;
    PSINGLE_LIST_ENTRY iter;
    PVOID buffer;
    UINT len;
    struct virtqueue *vq = GetOutQueue(Port);

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_QUEUEING, "--> %s\n", __FUNCTION__);

    if (vq)
    {
        while ((buffer = virtqueue_get_buf(vq, &len)) != NULL)
        {
            if (Port->PendingWriteRequest != NULL)
            {
                request = Port->PendingWriteRequest;
                Port->PendingWriteRequest = NULL;

                if (WdfRequestUnmarkCancelable(request) != STATUS_CANCELLED)
                {
                    WdfRequestCompleteWithInformation(request, STATUS_SUCCESS,
                                                      (size_t)WdfRequestGetInformation(request));
                }
                else
                {
                    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_QUEUEING,
                                "Request %p was cancelled.\n", request);
                }
            }

            iter = &Port->WriteBuffersList;
            while (iter->Next != NULL)
            {
                PWRITE_BUFFER_ENTRY entry = CONTAINING_RECORD(iter->Next,
                                            WRITE_BUFFER_ENTRY, ListEntry);

                if (buffer == entry->Buffer)
                {
                    iter->Next = entry->ListEntry.Next;

                    ExFreePoolWithTag(buffer, VIOSERIAL_DRIVER_MEMORY_TAG);
                    ExFreePoolWithTag(entry, VIOSERIAL_DRIVER_MEMORY_TAG);
                }
                else
                {
                    iter = iter->Next;
                }
            };

            Port->OutVqFull = FALSE;
        }
    }

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_QUEUEING, "<-- %s Full: %d\n",
                __FUNCTION__, Port->OutVqFull);
}
VOID
SimSensorQueueIoStop (
    _In_ WDFQUEUE Queue,
    _In_ WDFREQUEST Request,
    _In_ ULONG ActionFlags
    )

/*++

Routine Description:

    This routine is called when the framework is stopping the request's I/O
    queue.

Arguments:

    Queue - Supplies handle to the framework queue object that is associated
            with the I/O request.

    Request - Supplies handle to a framework request object.

    ActionFlags - Supplies the reason that the callback is being called.

Return Value:

    None.

--*/

{

    NTSTATUS Status;

    UNREFERENCED_PARAMETER(Queue);

    if(ActionFlags & WdfRequestStopRequestCancelable) {
        Status = WdfRequestUnmarkCancelable(Request);
        if (Status == STATUS_CANCELLED) {
            goto SimSensorQueueIoStopEnd;
        }

        NT_ASSERT(NT_SUCCESS(Status));
    }

    WdfRequestStopAcknowledge(Request, FALSE);

SimSensorQueueIoStopEnd:

    return;
}
VOID VirtRngEvtIoRead(IN WDFQUEUE Queue,
                      IN WDFREQUEST Request,
                      IN size_t Length)
{
    PDEVICE_CONTEXT context = GetDeviceContext(WdfIoQueueGetDevice(Queue));
    NTSTATUS status;
    PVOID buffer;

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ,
        "--> %!FUNC! Queue: %p Request: %p Length: %d",
        Queue, Request, (ULONG)Length);

    status = WdfRequestRetrieveOutputBuffer(Request, Length, &buffer, NULL);
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_READ,
            "WdfRequestRetrieveOutputBuffer failed: %!STATUS!", status);
        WdfRequestComplete(Request, status);
        return;
    }

    status = WdfRequestMarkCancelableEx(Request, VirtRngEvtRequestCancel);
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_READ,
            "WdfRequestMarkCancelableEx failed: %!STATUS!", status);
        WdfRequestComplete(Request, status);
        return;
    }

    status = VirtQueueAddBuffer(context, Request, Length);
    if (!NT_SUCCESS(status))
    {
        if (WdfRequestUnmarkCancelable(Request) != STATUS_CANCELLED)
        {
            WdfRequestComplete(Request, status);
        }
    }

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "<-- %!FUNC!");
}
VOID VirtRngEvtIoStop(IN WDFQUEUE Queue,
                      IN WDFREQUEST Request,
                      IN ULONG ActionFlags)
{
    UNREFERENCED_PARAMETER(Queue);

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ,
        "--> %!FUNC! Request: %p", Request);

    if (ActionFlags & WdfRequestStopActionSuspend)
    {
        WdfRequestStopAcknowledge(Request, FALSE);
    }
    else if (ActionFlags & WdfRequestStopActionPurge)
    {
        if (WdfRequestUnmarkCancelable(Request) != STATUS_CANCELLED)
        {
            WdfRequestComplete(Request , STATUS_CANCELLED);
        }
    }

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "<-- %!FUNC!");
}
VOID VIOSerialPortWriteIoStop(IN WDFQUEUE Queue,
                              IN WDFREQUEST Request,
                              IN ULONG ActionFlags)
{
   PRAWPDO_VIOSERIAL_PORT pdoData = RawPdoSerialPortGetData(
      WdfIoQueueGetDevice(Queue));
   PVIOSERIAL_PORT pport = pdoData->port;

   TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "--> %s\n", __FUNCTION__);

   WdfSpinLockAcquire(pport->OutVqLock);
   if (ActionFlags & WdfRequestStopActionSuspend)
   {
      WdfRequestStopAcknowledge(Request, FALSE);
   }
   else if (ActionFlags & WdfRequestStopActionPurge)
   {
      if (WdfRequestUnmarkCancelable(Request) != STATUS_CANCELLED)
      {
         PSINGLE_LIST_ENTRY iter = &pport->WriteBuffersList;
         while ((iter = iter->Next) != NULL)
         {
            PWRITE_BUFFER_ENTRY entry = CONTAINING_RECORD(iter, WRITE_BUFFER_ENTRY, ListEntry);
            if (entry->Request == Request)
            {
               entry->Request = NULL;
               break;
            }
         }
         WdfRequestComplete(Request, STATUS_OBJECT_NO_LONGER_EXISTS);
      }
   }
   WdfSpinLockRelease(pport->OutVqLock);

   TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "<-- %s\n", __FUNCTION__);
}
Exemple #10
0
VOID
EchoEvtTimerFunc(
    IN WDFTIMER     Timer
    )
/*++

Routine Description:

    This is the TimerDPC the driver sets up to complete requests.
    This function is registered when the WDFTIMER object is created, and
    will automatically synchronize with the I/O Queue callbacks
    and cancel routine.

Arguments:

    Timer - Handle to a framework Timer object.

Return Value:

    VOID

--*/
{
    NTSTATUS      Status;
    WDFREQUEST     Request;
    WDFQUEUE queue;
    PQUEUE_CONTEXT queueContext ;

    queue = WdfTimerGetParentObject(Timer);
    queueContext = QueueGetContext(queue);

    //
    // DPC is automatically synchronized to the Queue lock,
    // so this is race free without explicit driver managed locking.
    //
    Request = queueContext->CurrentRequest;
    if( Request != NULL ) {

        //
        // Attempt to remove cancel status from the request.
        //
        // The request is not completed if it is already cancelled
        // since the EchoEvtIoCancel function has run, or is about to run
        // and we are racing with it.
        //
        Status = WdfRequestUnmarkCancelable(Request);
        if( Status != STATUS_CANCELLED ) {

            queueContext->CurrentRequest = NULL;
            Status = queueContext->CurrentStatus;

            KdPrint(("CustomTimerDPC Completing request 0x%p, Status 0x%x \n", Request,Status));

            WdfRequestComplete(Request, Status);
        }
        else {
            KdPrint(("CustomTimerDPC Request 0x%p is STATUS_CANCELLED, not completing\n",
                                Request));
        }
    }

    //
    // Restart the Timer since WDF does not allow periodic timer 
    // with autosynchronization at passive level
    //
    WdfTimerStart(Timer, TIMER_PERIOD);

    return;
}
VOID
ControllerCompleteTransfer(
    _In_  PPBC_DEVICE   pDevice,
    _In_  PPBC_REQUEST  pRequest,
    _In_  BOOLEAN       AbortSequence
    )
/*++
 
  Routine Description:

    This routine completes a data transfer. Unless there are
    more transfers remaining in the sequence, the request is
    completed.

  Arguments:

    pDevice - a pointer to the PBC device context
    pRequest - a pointer to the PBC request context
    AbortSequence - specifies whether the driver should abort the
        ongoing sequence or begin the next transfer

  Return Value:

    None. The request is completed asynchronously.

--*/
{
    FuncEntry(TRACE_FLAG_TRANSFER);

    NT_ASSERT(pDevice  != NULL);
    NT_ASSERT(pRequest != NULL);

    Trace(
        TRACE_LEVEL_INFORMATION,
        TRACE_FLAG_TRANSFER,
        "Transfer (index %lu) %s with %Iu bytes for address 0x%lx "
        "(SPBREQUEST %p)",
        pRequest->TransferIndex,
        NT_SUCCESS(pRequest->Status) ? "complete" : "error",
        pRequest->Information,
        pDevice->pCurrentTarget->Settings.Address,
        pRequest->SpbRequest);

    //
    // Update request context with information from this transfer.
    //

    pRequest->TotalInformation += pRequest->Information;
    pRequest->Information = 0;

    //
    // Check if there are more transfers
    // in the sequence.
    //

    if (!AbortSequence)
    {
        pRequest->TransferIndex++;

        if (pRequest->TransferIndex < pRequest->TransferCount)
        {
            //
            // Configure the request for the next transfer.
            //

            pRequest->Status = PbcRequestConfigureForIndex(
                pRequest, 
                pRequest->TransferIndex);

            if (NT_SUCCESS(pRequest->Status))
            {
                //
                // Configure controller and kick-off read.
                // Request will be completed asynchronously.
                //

                PbcRequestDoTransfer(pDevice,pRequest);
                goto exit;
            }
        }
    }

    //
    // If not already cancelled, unmark request cancellable.
    //

    if (pRequest->Status != STATUS_CANCELLED)
    {
        NTSTATUS cancelStatus;
        cancelStatus = WdfRequestUnmarkCancelable(pRequest->SpbRequest);

        if (!NT_SUCCESS(cancelStatus))
        {
            //
            // WdfRequestUnmarkCancelable should only fail if the request
            // has already been or is about to be cancelled. If it does fail 
            // the request must NOT be completed - the cancel callback will do
            // this.
            //

            NT_ASSERTMSG("WdfRequestUnmarkCancelable should only fail if the request has already been or is about to be cancelled",
                cancelStatus == STATUS_CANCELLED);

            Trace(
                TRACE_LEVEL_INFORMATION,
                TRACE_FLAG_TRANSFER,
                "Failed to unmark SPBREQUEST %p as cancelable - %!STATUS!",
                pRequest->SpbRequest,
                cancelStatus);

            goto exit;
        }
    }

    //
    // Done or error occurred. Set interrupt mask to 0.
    // Doing this keeps the DPC from re-enabling interrupts.
    //

    PbcDeviceSetInterruptMask(pDevice, 0);

    //
    // Clear the target's current request. This will prevent
    // the request context from being accessed once the request
    // is completed (and the context is invalid).
    //

    pDevice->pCurrentTarget->pCurrentRequest = NULL;

    //
    // Clear the controller's current target if any of
    //   1. request is type sequence
    //   2. request position is single 
    //      (did not come between lock/unlock)
    // Otherwise wait until unlock.
    //

    if ((pRequest->Type == SpbRequestTypeSequence) ||
        (pRequest->SequencePosition == SpbRequestSequencePositionSingle))
    {
        pDevice->pCurrentTarget = NULL;
    }

    //
    // Mark the IO complete. Request not
    // completed here.
    //

    pRequest->bIoComplete = TRUE;

exit:

    FuncExit(TRACE_FLAG_TRANSFER);
}
VOID
NfcCxSCPresentAbsentDispatcherCompleteRequest(
    _In_ PNFCCX_FDO_CONTEXT FdoContext,
    _In_ PNFCCX_SC_PRESENT_ABSENT_DISPATCHER Dispatcher
    )
/*++

Routine Description:

    If there is a request in the dispatcher, the request is completed.

Arguments:

    FdoContext - Pointer to the FDO Context
    Dispatcher - Pointer to the Dispatcher

Return Value:

    VOID

--*/
{
    NTSTATUS status = STATUS_SUCCESS;

    TRACE_FUNCTION_ENTRY(LEVEL_VERBOSE);

    // Remove the current request from the dispatcher.
    WDFREQUEST request = (WDFREQUEST)InterlockedExchangePointer((void**)&Dispatcher->CurrentRequest, nullptr);

    // Check if another thread has already completed the request.
    if (request == nullptr)
    {
        // Nothing to do.
        goto Done;
    }

    WDFFILEOBJECT fileObject = WdfRequestGetFileObject(request);
    PNFCCX_FILE_CONTEXT fileContext = NfcCxFileGetContext(fileObject);

    // Try to unset the request's cancel callback.
    status = WdfRequestUnmarkCancelable(request);
    if (status != STATUS_CANCELLED)
    {
        // The cancel callback will not be called.
        // So we have to release its ref-count for it.
        WdfObjectDereference(request);

        if (!NT_SUCCESS(status))
        {
            // Something is pretty wrong.
            NT_ASSERT(false);

            TRACE_LINE(LEVEL_ERROR, "Failed to unset request canceled callback. %!STATUS!", status);
            goto Done;
        }
    }

    // Release power reference (if required).
    if (Dispatcher->PowerManaged)
    {
        NfcCxPowerFileRemoveReference(FdoContext->Power, fileContext, NfcCxPowerReferenceType_Proximity);
    }

    // Complete the request
    WdfRequestComplete(request, STATUS_SUCCESS);

Done:
    TRACE_FUNCTION_EXIT(LEVEL_VERBOSE);
    return;
}
VOID VIOSerialPortWrite(IN WDFQUEUE Queue,
                        IN WDFREQUEST Request,
                        IN size_t Length)
{
    NTSTATUS status;
    PVOID InBuf;
    PVOID buffer;
    PVIOSERIAL_PORT Port;
    PWRITE_BUFFER_ENTRY entry;
    WDFDEVICE Device;
    PDRIVER_CONTEXT Context;
    WDFMEMORY EntryHandle;

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,
        "--> %s Request: %p Length: %d\n", __FUNCTION__, Request, Length);

    PAGED_CODE();

    Device = WdfIoQueueGetDevice(Queue);
    Port = RawPdoSerialPortGetData(Device)->port;
    if (Port->Removed)
    {
        TraceEvents(TRACE_LEVEL_WARNING, DBG_WRITE,
            "Write request on a removed port %d\n", Port->PortId);
        WdfRequestComplete(Request, STATUS_OBJECT_NO_LONGER_EXISTS);
        return;
    }

    status = WdfRequestRetrieveInputBuffer(Request, Length, &InBuf, NULL);
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE,
            "Failed to retrieve input buffer: %x\n", status);
        WdfRequestComplete(Request, status);
        return;
    }

    if (VIOSerialWillWriteBlock(Port))
    {
        WdfRequestComplete(Request, STATUS_CANT_WAIT);
        return;
    }

    buffer = ExAllocatePoolWithTag(NonPagedPool, Length,
        VIOSERIAL_DRIVER_MEMORY_TAG);

    if (buffer == NULL)
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "Failed to allocate.\n");
        WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES);
        return;
    }

    Context = GetDriverContext(WdfDeviceGetDriver(Device));
    status = WdfMemoryCreateFromLookaside(Context->WriteBufferLookaside, &EntryHandle);
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE,
            "Failed to allocate write buffer entry: %x.\n", status);
        ExFreePoolWithTag(buffer, VIOSERIAL_DRIVER_MEMORY_TAG);
        WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES);
        return;
    }

    status = WdfRequestMarkCancelableEx(Request,
        VIOSerialPortWriteRequestCancel);

    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE,
            "Failed to mark request as cancelable: %x\n", status);
        ExFreePoolWithTag(buffer, VIOSERIAL_DRIVER_MEMORY_TAG);
        WdfObjectDelete(EntryHandle);
        WdfRequestComplete(Request, status);
        return;
    }

    RtlCopyMemory(buffer, InBuf, Length);
    WdfRequestSetInformation(Request, (ULONG_PTR)Length);

    entry = (PWRITE_BUFFER_ENTRY)WdfMemoryGetBuffer(EntryHandle, NULL);
    entry->EntryHandle = EntryHandle;
    entry->Buffer = buffer;
    entry->Request = Request;

    if (VIOSerialSendBuffers(Port, entry, Length) <= 0)
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE,
            "Failed to send user's buffer.\n");

        ExFreePoolWithTag(buffer, VIOSERIAL_DRIVER_MEMORY_TAG);
        WdfObjectDelete(EntryHandle);

        if (WdfRequestUnmarkCancelable(Request) != STATUS_CANCELLED)
        {
            WdfRequestComplete(Request, Port->Removed ?
                STATUS_INVALID_DEVICE_STATE : STATUS_INSUFFICIENT_RESOURCES);
        }
    }

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,"<-- %s\n", __FUNCTION__);
}
static VOID
XenUsb_HandleEventDpc(PKDPC dpc, PVOID context, PVOID arg1, PVOID arg2) {
  NTSTATUS status;
  PXENUSB_DEVICE_DATA xudd = context;
  RING_IDX prod, cons;
  usbif_urb_response_t *urb_rsp;
  usbif_conn_response_t *conn_rsp;
  usbif_conn_request_t *conn_req;
  int more_to_do;
  pvurb_t *pvurb, *complete_head = NULL, *complete_tail = NULL;
  partial_pvurb_t *partial_pvurb;
  BOOLEAN port_changed = FALSE;

  UNREFERENCED_PARAMETER(dpc);
  UNREFERENCED_PARAMETER(arg1);
  UNREFERENCED_PARAMETER(arg2);

  FUNCTION_ENTER();

  more_to_do = TRUE;
  KeAcquireSpinLockAtDpcLevel(&xudd->urb_ring_lock);
  while (more_to_do)
  {
    prod = xudd->urb_ring.sring->rsp_prod;
    KeMemoryBarrier();
    for (cons = xudd->urb_ring.rsp_cons; cons != prod; cons++)
    {
      urb_rsp = RING_GET_RESPONSE(&xudd->urb_ring, cons);
//      FUNCTION_MSG("urb_rsp->id = %d\n", urb_rsp->id);
      partial_pvurb = xudd->partial_pvurbs[urb_rsp->id];
      RemoveEntryList(&partial_pvurb->entry);
      partial_pvurb->rsp = *urb_rsp;
//      FUNCTION_MSG("shadow = %p\n", shadow);
//      FUNCTION_MSG("shadow->rsp = %p\n", shadow->rsp);
      if (usbif_pipeunlink(partial_pvurb->req.pipe)) {
        FUNCTION_MSG("is a cancel request for request %p\n", partial_pvurb->pvurb->request);
        FUNCTION_MSG("urb_ring rsp status = %d\n", urb_rsp->status);
        // status should be 115 == EINPROGRESS
      } else {
        partial_pvurb->pvurb->total_length += urb_rsp->actual_length;
        if (!partial_pvurb->pvurb->rsp.status)
          partial_pvurb->pvurb->rsp.status = urb_rsp->status;
        partial_pvurb->pvurb->rsp.error_count += urb_rsp->error_count;;
        if (partial_pvurb->mdl) {
          int i;
          for (i = 0; i < partial_pvurb->req.nr_buffer_segs; i++) {
            XnEndAccess(xudd->handle, partial_pvurb->req.seg[i].gref, FALSE, (ULONG)'XUSB');
          }
        }

        FUNCTION_MSG("urb_ring rsp id = %d\n", partial_pvurb->rsp.id);
        FUNCTION_MSG("urb_ring rsp start_frame = %d\n", partial_pvurb->rsp.start_frame);
        FUNCTION_MSG("urb_ring rsp status = %d\n", partial_pvurb->rsp.status);
        FUNCTION_MSG("urb_ring rsp actual_length = %d\n", partial_pvurb->rsp.actual_length);
        FUNCTION_MSG("urb_ring rsp error_count = %d\n", partial_pvurb->rsp.error_count);
      }
      if (partial_pvurb->other_partial_pvurb) {
        if (!partial_pvurb->other_partial_pvurb->on_ring) {
          /* cancel hasn't been put on the ring yet - remove it */
          RemoveEntryList(&partial_pvurb->other_partial_pvurb->entry);
          ASSERT(usbif_pipeunlink(partial_pvurb->other_partial_pvurb->req.pipe));
          partial_pvurb->pvurb->ref--;
          ExFreePoolWithTag(partial_pvurb->other_partial_pvurb, XENUSB_POOL_TAG);
        }
      }
      partial_pvurb->pvurb->ref--;
      switch (partial_pvurb->rsp.status) {
      case EINPROGRESS: /* unlink request */
      case ECONNRESET:  /* cancelled request */
        ASSERT(partial_pvurb->pvurb->status == STATUS_CANCELLED);
        break;
      default:
        break;
      }
      put_id_on_freelist(xudd->req_id_ss, partial_pvurb->rsp.id);
      partial_pvurb->pvurb->next = NULL;
      if (!partial_pvurb->pvurb->ref) {
        if (complete_tail) {
          complete_tail->next = partial_pvurb->pvurb;
        } else {
          complete_head = partial_pvurb->pvurb;
        }
        complete_tail = partial_pvurb->pvurb;
      }
    }

    xudd->urb_ring.rsp_cons = cons;
    if (cons != xudd->urb_ring.req_prod_pvt) {
      RING_FINAL_CHECK_FOR_RESPONSES(&xudd->urb_ring, more_to_do);
    } else {
      xudd->urb_ring.sring->rsp_event = cons + 1;
      more_to_do = FALSE;
    }
  }
  PutRequestsOnRing(xudd);
  KeReleaseSpinLockFromDpcLevel(&xudd->urb_ring_lock);

  pvurb = complete_head;
  while (pvurb != NULL) {
    complete_head = pvurb->next;
    status = WdfRequestUnmarkCancelable(pvurb->request);
    if (status == STATUS_CANCELLED) {
      FUNCTION_MSG("Cancel was called\n");
    }
    
    WdfRequestCompleteWithInformation(pvurb->request, pvurb->status, pvurb->total_length); /* the WDFREQUEST is always successfull here even if the pvurb->rsp has an error */
    pvurb = complete_head;
  }

  more_to_do = TRUE;
  KeAcquireSpinLockAtDpcLevel(&xudd->conn_ring_lock);
  while (more_to_do)
  {
    prod = xudd->conn_ring.sring->rsp_prod;
    KeMemoryBarrier();
    for (cons = xudd->conn_ring.rsp_cons; cons != prod; cons++)
    {
      USHORT old_port_status;
      conn_rsp = RING_GET_RESPONSE(&xudd->conn_ring, cons);
      FUNCTION_MSG("conn_rsp->portnum = %d\n", conn_rsp->portnum);
      FUNCTION_MSG("conn_rsp->speed = %d\n", conn_rsp->speed);
      
      old_port_status = xudd->ports[conn_rsp->portnum - 1].port_status;
      xudd->ports[conn_rsp->portnum - 1].port_type = conn_rsp->speed;
      xudd->ports[conn_rsp->portnum - 1].port_status &= ~((1 << PORT_LOW_SPEED) | (1 << PORT_HIGH_SPEED) | (1 << PORT_CONNECTION));
      switch (conn_rsp->speed)
      {
      case USB_PORT_TYPE_NOT_CONNECTED:
        xudd->ports[conn_rsp->portnum - 1].port_status &= ~(1 << PORT_ENABLE);
        break;
      case USB_PORT_TYPE_LOW_SPEED:
        xudd->ports[conn_rsp->portnum - 1].port_status |= (1 << PORT_LOW_SPEED) | (1 << PORT_CONNECTION);
        break;
      case USB_PORT_TYPE_FULL_SPEED:
        xudd->ports[conn_rsp->portnum - 1].port_status |= (1 << PORT_CONNECTION);
        break;
      case USB_PORT_TYPE_HIGH_SPEED:
        xudd->ports[conn_rsp->portnum - 1].port_status |= (1 << PORT_HIGH_SPEED) | (1 << PORT_CONNECTION);
        break;
      }      
      xudd->ports[conn_rsp->portnum - 1].port_change |= (xudd->ports[conn_rsp->portnum - 1].port_status ^ old_port_status) & ((1 << PORT_ENABLE) | (1 << PORT_CONNECTION));
      if (xudd->ports[conn_rsp->portnum - 1].port_change)
        port_changed = TRUE;
      conn_req = RING_GET_REQUEST(&xudd->conn_ring, xudd->conn_ring.req_prod_pvt);
      conn_req->id = conn_rsp->id;
      xudd->conn_ring.req_prod_pvt++;
    }

    xudd->conn_ring.rsp_cons = cons;
    if (cons != xudd->conn_ring.req_prod_pvt)
    {
      RING_FINAL_CHECK_FOR_RESPONSES(&xudd->conn_ring, more_to_do);
    }
    else
    {
      xudd->conn_ring.sring->rsp_event = cons + 1;
      more_to_do = FALSE;
    }
  }
  KeReleaseSpinLockFromDpcLevel(&xudd->conn_ring_lock);

  if (port_changed) {
    PXENUSB_PDO_DEVICE_DATA xupdd = GetXupdd(xudd->root_hub_device);
    XenUsbHub_ProcessHubInterruptEvent(xupdd->usb_device->configs[0]->interfaces[0]->endpoints[0]);
  }
      
  FUNCTION_EXIT();

  return;
}
NTSTATUS
NfcCxSCPresentAbsentDispatcherSetRequest(
    _In_ PNFCCX_FDO_CONTEXT FdoContext,
    _In_ PNFCCX_SC_PRESENT_ABSENT_DISPATCHER Dispatcher,
    _In_ WDFREQUEST Request
    )
/*++

Routine Description:

    Stores a request in the dispatcher. If a request is already pending in the dispatcher, the new request will
    be completed with STATUS_DEVICE_BUSY.

Arguments:

    FdoContext - Pointer to the FDO Context
    Dispatcher - Pointer to the Dispatcher.
    Request - The request to store in the dispatcher.

Return Value:

    NTSTATUS

--*/
{
    NTSTATUS status;
    bool powerReferenceAcquired = false;
    bool cancelCallbackSet = false;

    TRACE_FUNCTION_ENTRY(LEVEL_VERBOSE);

    WDFFILEOBJECT fileObject = WdfRequestGetFileObject(Request);
    PNFCCX_FILE_CONTEXT fileContext = NfcCxFileGetContext(fileObject);

    // Pre-check if there is a current request.
    if (ReadPointerAcquire((void**)&Dispatcher->CurrentRequest) != nullptr)
    {
        status = STATUS_DEVICE_BUSY;
        TRACE_LINE(LEVEL_ERROR, "An Is Present/Absent request is already pending. %!STATUS!", status);
        goto Done;
    }

    // Allocate and initialize the request context
    PNFCCX_SC_REQUEST_CONTEXT requestContext = nullptr;

    WDF_OBJECT_ATTRIBUTES contextAttributes;
    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&contextAttributes, NFCCX_SC_REQUEST_CONTEXT);

    status = WdfObjectAllocateContext(Request, &contextAttributes, (void**)&requestContext);
    if (!NT_SUCCESS(status))
    {
        TRACE_LINE(LEVEL_ERROR, "Failed to set request's context. %!STATUS!", status);
        goto Done;
    }

    requestContext->Dispatcher = Dispatcher;

    // Add a power reference (if required).
    if (Dispatcher->PowerManaged)
    {
        status = NfcCxPowerFileAddReference(FdoContext->Power, fileContext, NfcCxPowerReferenceType_Proximity);
        if (!NT_SUCCESS(status))
        {
            TRACE_LINE(LEVEL_VERBOSE, "Failed to acquire power reference. %!STATUS!", status);
            goto Done;
        }

        powerReferenceAcquired = true;
    }

    // Setup cancel callback.
    status = WdfRequestMarkCancelableEx(Request, NfcCxSCPresentAbsentDispatcherRequestCanceled);
    if (!NT_SUCCESS(status))
    {
        TRACE_LINE(LEVEL_ERROR, "Failed to set request canceled callback. %!STATUS!", status);
        goto Done;
    }

    // Add a ref-count to the request, which is owned by the cancel callback.
    WdfObjectReference(Request);
    cancelCallbackSet = true;

    // Try to set the current request.
    void* previousRequest = InterlockedCompareExchangePointer((void**)&Dispatcher->CurrentRequest, /*exchange*/ Request, /*compare*/ nullptr);

    // Check if we already have a pending request.
    if (previousRequest != nullptr)
    {
        status = STATUS_DEVICE_BUSY;
        TRACE_LINE(LEVEL_ERROR, "An Is Present/Absent request is already pending. %!STATUS!", status);
        goto Done;
    }

Done:
    if (!NT_SUCCESS(status))
    {
        if (cancelCallbackSet)
        {
            NTSTATUS unmarkStatus = WdfRequestUnmarkCancelable(Request);
            if (unmarkStatus != STATUS_CANCELLED)
            {
                // Cancel callback will not be called.
                // So release cancel callback's request ref-count.
                WdfObjectDereference(Request);
            }
        }

        if (powerReferenceAcquired)
        {
            NfcCxPowerFileRemoveReference(FdoContext->Power, fileContext, NfcCxPowerReferenceType_Proximity);
        }
    }

    TRACE_FUNCTION_EXIT_NTSTATUS(LEVEL_VERBOSE, status);
    return status;
}
VOID VirtRngEvtInterruptDpc(IN WDFINTERRUPT Interrupt,
                            IN WDFOBJECT AssociatedObject)
{
    PDEVICE_CONTEXT context = GetDeviceContext(
        WdfInterruptGetDevice(Interrupt));
    struct virtqueue *vq = context->VirtQueue;
    PREAD_BUFFER_ENTRY entry;
    PSINGLE_LIST_ENTRY iter;
    NTSTATUS status;
    PVOID buffer;
    size_t bufferLen;
    unsigned int length;

    UNREFERENCED_PARAMETER(AssociatedObject);

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_DPC,
        "--> %!FUNC! Interrupt: %p", Interrupt);

    for (;;)
    {
        WdfSpinLockAcquire(context->VirtQueueLock);

        entry = (PREAD_BUFFER_ENTRY)virtqueue_get_buf(vq, &length);
        if (entry == NULL)
        {
            WdfSpinLockRelease(context->VirtQueueLock);
            break;
        }

        TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ,
            "Got %p Request: %p Buffer: %p",
            entry, entry->Request, entry->Buffer);

        iter = &context->ReadBuffersList;
        while (iter->Next != NULL)
        {
            PREAD_BUFFER_ENTRY current = CONTAINING_RECORD(iter->Next,
                READ_BUFFER_ENTRY, ListEntry);

            if (entry == current)
            {
                TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ,
                    "Delete %p Request: %p Buffer: %p",
                    entry, entry->Request, entry->Buffer);

                iter->Next = current->ListEntry.Next;
                break;
            }
            else
            {
                iter = iter->Next;
            }
        };

        if ((entry->Request == NULL) ||
            (WdfRequestUnmarkCancelable(entry->Request) == STATUS_CANCELLED))
        {
            TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC,
                "Ignoring a canceled read request: %p", entry->Request);

            entry->Request = NULL;
        }

        WdfSpinLockRelease(context->VirtQueueLock);

        if (entry->Request != NULL)
        {
            status = WdfRequestRetrieveOutputBuffer(entry->Request, length,
                &buffer, &bufferLen);

            if (NT_SUCCESS(status))
            {
                length = min(length, (unsigned)bufferLen);
                RtlCopyMemory(buffer, entry->Buffer, length);

                TraceEvents(TRACE_LEVEL_VERBOSE, DBG_DPC,
                    "Complete Request: %p Length: %d", entry->Request, length);

                WdfRequestCompleteWithInformation(entry->Request,
                    STATUS_SUCCESS, (ULONG_PTR)length);
            }
            else
            {
                TraceEvents(TRACE_LEVEL_ERROR, DBG_READ,
                    "WdfRequestRetrieveOutputBuffer failed: %!STATUS!", status);
                WdfRequestComplete(entry->Request, status);
            }
        }

        ExFreePoolWithTag(entry->Buffer, VIRT_RNG_MEMORY_TAG);
        ExFreePoolWithTag(entry, VIRT_RNG_MEMORY_TAG);
    }

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_DPC, "<-- %!FUNC!");
}
Exemple #17
0
VOID
CleanupDisconnectedDevice(
    PUSB_FDO_CONTEXT fdoContext)
{    
    AcquireFdoLock(fdoContext);
    if (fdoContext->CtlrDisconnected)
    {
        ReleaseFdoLock(fdoContext);
        return;
    }
    fdoContext->CtlrDisconnected = TRUE; 
    
    ReleaseFdoLock(fdoContext);
    WdfTimerStop(fdoContext->WatchdogTimer, TRUE);
    // --XT-- WdfDpcCancel(fdoContext->WdfDpc, TRUE);
    //
    // --XT-- This also looks like a reasonable place to turn off the event channel.
    //
    XenDisconnectDPC(fdoContext->Xen);

    AcquireFdoLock(fdoContext);

    FdoUnplugDevice(fdoContext);

    BOOLEAN completeRequest = TRUE;

    if (fdoContext->IdleRequest)
    {
        if (RequestGetRequestContext(fdoContext->IdleRequest)->RequestCompleted)
        {
            // should never happen if fdoContext->IdleRequest is not NULL.

            TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
                __FUNCTION__": Device %p Request %p marked completed\n",
                fdoContext->WdfDevice,
                fdoContext->IdleRequest);
            completeRequest = FALSE;
        }
        else if (RequestGetRequestContext(fdoContext->IdleRequest)->CancelSet)
        {
            NTSTATUS Status = WdfRequestUnmarkCancelable(fdoContext->IdleRequest);
            if (!NT_SUCCESS(Status))
            {
                if (Status == STATUS_CANCELLED)
                {
                    //
                    // don't complete the request here it is owned by the
                    // cancel routine.
                    XXX_TODO("Trace level probably too high");

                    TraceEvents(TRACE_LEVEL_WARNING, TRACE_DEVICE,
                        __FUNCTION__": Device %p Request %p Cancelled\n",
                        fdoContext->WdfDevice,
                        fdoContext->IdleRequest);
                    completeRequest = FALSE;
                }
                else
                {
                    //
                    // note but ignore. 
                    //
                    TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
                        __FUNCTION__": Device %p Request %p WdfRequestUnmarkCancelable error %x\n",
                        fdoContext->WdfDevice,
                        fdoContext->IdleRequest,
                        Status);
                }
            }
        }
        WDFREQUEST idleRequest = fdoContext->IdleRequest;
        fdoContext->IdleRequest = NULL;
        if (completeRequest)
        {
            RequestGetRequestContext(idleRequest)->RequestCompleted = 0;
            ReleaseFdoLock(fdoContext);
            WdfRequestComplete(idleRequest, STATUS_CANCELLED);
            AcquireFdoLock(fdoContext);
        }
    }
    ReleaseFdoLock(fdoContext);
    if (fdoContext->XenConfigured)
    {
        CompleteRequestsFromShadow(fdoContext);
    }
}
VOID VIOSerialPortWrite(IN WDFQUEUE Queue,
                        IN WDFREQUEST Request,
                        IN size_t Length)
{
    NTSTATUS status;
    PVOID InBuf;
    PVOID buffer;
    PVIOSERIAL_PORT Port;
    PWRITE_BUFFER_ENTRY entry;

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,
        "--> %s Request: %p Length: %d\n", __FUNCTION__, Request, Length);

    PAGED_CODE();

    Port = RawPdoSerialPortGetData(WdfIoQueueGetDevice(Queue))->port;
    if (Port->Removed)
    {
        TraceEvents(TRACE_LEVEL_WARNING, DBG_WRITE,
            "Write request on a removed port %d\n", Port->PortId);
        WdfRequestComplete(Request, STATUS_OBJECT_NO_LONGER_EXISTS);
        return;
    }

    status = WdfRequestRetrieveInputBuffer(Request, Length, &InBuf, NULL);
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE,
            "Failed to retrieve input buffer: %x\n", status);
        WdfRequestComplete(Request, status);
        return;
    }

    if (VIOSerialWillWriteBlock(Port))
    {
        WdfRequestComplete(Request, STATUS_CANT_WAIT);
        return;
    }

    buffer = ExAllocatePoolWithTag(NonPagedPool, Length,
        VIOSERIAL_DRIVER_MEMORY_TAG);

    if (buffer == NULL)
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "Failed to allocate.\n");
        WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES);
        return;
    }

    entry = (PWRITE_BUFFER_ENTRY)ExAllocatePoolWithTag(NonPagedPool,
        sizeof(WRITE_BUFFER_ENTRY), VIOSERIAL_DRIVER_MEMORY_TAG);

    if (entry == NULL)
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE,
            "Failed to allocate write buffer entry.\n");
        ExFreePoolWithTag(buffer, VIOSERIAL_DRIVER_MEMORY_TAG);
        WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES);
        return;
    }

    status = WdfRequestMarkCancelableEx(Request,
        VIOSerialPortWriteRequestCancel);

    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE,
            "Failed to mark request as cancelable: %x\n", status);
        ExFreePoolWithTag(entry, VIOSERIAL_DRIVER_MEMORY_TAG);
        ExFreePoolWithTag(buffer, VIOSERIAL_DRIVER_MEMORY_TAG);
        WdfRequestComplete(Request, status);
        return;
    }

    RtlCopyMemory(buffer, InBuf, Length);
    WdfRequestSetInformation(Request, (ULONG_PTR)Length);

    entry->Buffer = buffer;
    PushEntryList(&Port->WriteBuffersList, &entry->ListEntry);

    Port->PendingWriteRequest = Request;

    if (VIOSerialSendBuffers(Port, buffer, Length) <= 0)
    {
        PSINGLE_LIST_ENTRY removed;

        TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE,
            "Failed to send user's buffer.\n");

        ExFreePoolWithTag(buffer, VIOSERIAL_DRIVER_MEMORY_TAG);

        removed = PopEntryList(&Port->WriteBuffersList);
        NT_ASSERT(entry == CONTAINING_RECORD(removed, WRITE_BUFFER_ENTRY, ListEntry));
        ExFreePoolWithTag(entry, VIOSERIAL_DRIVER_MEMORY_TAG);

        if ((Port->PendingWriteRequest != NULL) &&
            (WdfRequestUnmarkCancelable(Request) != STATUS_CANCELLED))
        {
            Port->PendingWriteRequest = NULL;

            WdfRequestComplete(Request, Port->Removed ?
                STATUS_INVALID_DEVICE_STATE : STATUS_INSUFFICIENT_RESOURCES);
        }
    }

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,"<-- %s\n", __FUNCTION__);
}