Beispiel #1
0
    KAFFINITY restrictCurrentThreadToSecondaryCores() throw ()
    {
        //
        // Set thread affinity mask to restrict scheduling of the current thread
        // on any processor but CPU0.
        //
        KAFFINITY callerAffinity;
        NT_ASSERTMSG("IRQL unexpected", KeGetCurrentIrql() < DISPATCH_LEVEL);
        ULONG numCpus = KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
        ULONG noCpu0AffinityMask = (~(ULONG(~0x0) << numCpus) & ULONG(~0x1));
        callerAffinity = KeSetSystemAffinityThreadEx(KAFFINITY(noCpu0AffinityMask));
        NT_ASSERTMSG("Thread affinity not set as requested", KeGetCurrentProcessorNumberEx(NULL) != 0);

        return callerAffinity;
    }
__forceinline
void
PwmCreateRequestGetAccess(
    _In_ WDFREQUEST WdfRequest,
    _Out_ ACCESS_MASK* DesiredAccessPtr,
    _Out_ ULONG* ShareAccessPtr
    )
{
    NT_ASSERT(ARGUMENT_PRESENT(DesiredAccessPtr));
    NT_ASSERT(ARGUMENT_PRESENT(ShareAccessPtr));

    WDF_REQUEST_PARAMETERS wdfRequestParameters;
    WDF_REQUEST_PARAMETERS_INIT(&wdfRequestParameters);
    WdfRequestGetParameters(WdfRequest, &wdfRequestParameters);

    NT_ASSERTMSG(
        "Expected create request",
        wdfRequestParameters.Type == WdfRequestTypeCreate);

    *DesiredAccessPtr =
        wdfRequestParameters.Parameters.Create.SecurityContext->DesiredAccess;
    *ShareAccessPtr = wdfRequestParameters.Parameters.Create.ShareAccess;
}
NTSTATUS
WDFEXPORT(WdfDmaTransactionCreate)(
    __in
    PWDF_DRIVER_GLOBALS DriverGlobals,
    __in
    WDFDMAENABLER DmaEnabler,
    __in_opt
    WDF_OBJECT_ATTRIBUTES * Attributes,
    __out
    WDFDMATRANSACTION * DmaTransactionHandle
    )
{
    NTSTATUS status;
    FxDmaEnabler* pDmaEnabler;
    PFX_DRIVER_GLOBALS pFxDriverGlobals;

    FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals),
                                   DmaEnabler,
                                   FX_TYPE_DMA_ENABLER,
                                   (PVOID *) &pDmaEnabler,
                                   &pFxDriverGlobals);

    FxPointerNotNull(pFxDriverGlobals, DmaTransactionHandle);

    *DmaTransactionHandle = NULL;

    status = FxValidateObjectAttributes(pFxDriverGlobals,
                                        Attributes,
                                        FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED
                                        );
    if (!NT_SUCCESS(status)) {
        return status;
    }

    switch (pDmaEnabler->GetProfile())
    {
        case WdfDmaProfilePacket:
        case WdfDmaProfilePacket64:
            status = FxDmaPacketTransaction::_Create(pFxDriverGlobals, 
                                                     Attributes, 
                                                     pDmaEnabler, 
                                                     DmaTransactionHandle);
            break;
        
        case WdfDmaProfileScatterGather:
        case WdfDmaProfileScatterGather64:
        case WdfDmaProfileScatterGatherDuplex:
        case WdfDmaProfileScatterGather64Duplex:
            status = FxDmaScatterGatherTransaction::_Create(
                                                        pFxDriverGlobals, 
                                                        Attributes, 
                                                        pDmaEnabler, 
                                                        DmaTransactionHandle
                                                        );
            break;

        case WdfDmaProfileSystem:
        case WdfDmaProfileSystemDuplex:
            status = FxDmaSystemTransaction::_Create(pFxDriverGlobals, 
                                                     Attributes, 
                                                     pDmaEnabler, 
                                                     DmaTransactionHandle);
            break;

        default:
            NT_ASSERTMSG("Unknown profile for DMA enabler", FALSE);
            status = STATUS_UNSUCCESSFUL;
            break;
    }

    return status;
}
NTSTATUS
NfcCxEvtNciReadNotification(
    _In_ PNFCCX_DRIVER_GLOBALS NfcCxGlobals,
    _In_ WDFDEVICE    Device,
    _In_ WDFMEMORY    Memory
    )
/*++

Routine Description:

    This routine is called by the CX client to signal a
    read notification.  The implementation of this function forwards
    the content of the notification to the Tml layer which will complete
    a pended read request up to the NfcLib.

Arguments:

    NfcCxGlobal - CX global pointer
    Device - WDF device to initialize
    Memory - A pointer to a WDFMEMORY object that contains the 
             content of the read notification

Return Value:

    NTSTATUS

--*/
{
    NTSTATUS status = STATUS_SUCCESS;
    
    PUCHAR buffer = NULL;
    size_t bufferSize = 0;

    UNREFERENCED_PARAMETER(NfcCxGlobals);

    TRACE_FUNCTION_ENTRY(LEVEL_VERBOSE);

    buffer = (PUCHAR)WdfMemoryGetBuffer(Memory, &bufferSize);

    if (MAX_USHORT < bufferSize) {
        TRACE_LINE(LEVEL_ERROR, "Invalid read notification sent, ignoring!!!");
        NT_ASSERTMSG("ReadNotification too large", FALSE);
        goto Done;
    }

    //
    // Forward the read to the Tml interface
    //
    status = NfcCxTmlDispatchReadNotification((NfcCxFdoGetContext(Device))->TmlInterface,
                                              buffer,
                                              (USHORT)bufferSize);
    if (!NT_SUCCESS(status)) {
        TRACE_LINE(LEVEL_ERROR, "Failed to dispatch read notification, %!STATUS!", status);
        goto Done;
    }

Done:

    TRACE_FUNCTION_EXIT_NTSTATUS(LEVEL_VERBOSE, status);
    return status;
}
Beispiel #5
0
VOID
CBUpdateCardState(
                 PSMARTCARD_EXTENSION SmartcardExtension,
                 UCHAR IccState,
                 BOOLEAN SystemWakeUp
                 )
{
    ULONG oldState;
    NTSTATUS status;
    KIRQL irql;
    WDFREQUEST request;
    PDEVICE_EXTENSION       DeviceExtension;


    KeAcquireSpinLock(
                     &SmartcardExtension->OsData->SpinLock,
                     &irql
                     );

    SmartcardDebug(
                  DEBUG_TRACE,
                  ( "PSCR!CBUpdateCardState: Enter \n" )
                  );

    oldState =
    (SmartcardExtension->ReaderCapabilities.CurrentState > SCARD_ABSENT ?
     SCARD_PRESENT : SCARD_ABSENT);

    SmartcardExtension->ReaderCapabilities.CurrentState =
    (IccState == PSCR_ICC_PRESENT ? SCARD_PRESENT : SCARD_ABSENT);

    SmartcardDebug(
                  DEBUG_DRIVER,
                  ( "PSCR!CBUpdateCardState: Smart card %s\n",
                    IccState == PSCR_ICC_PRESENT ? "inserted" : "removed")
                  );

    if ( SmartcardExtension->OsData->NotificationIrp != NULL &&
         (SystemWakeUp &&
          (oldState == SCARD_PRESENT ||
           SmartcardExtension->ReaderCapabilities.CurrentState == SCARD_PRESENT) ||
          SmartcardExtension->ReaderCapabilities.CurrentState != oldState)) {
        PIRP notificationIrp ;

        notificationIrp = InterlockedExchangePointer(
                                 &(SmartcardExtension->OsData->NotificationIrp),
                                 NULL
                                 );

        DeviceExtension = GetDeviceExtension(WdfWdmDeviceGetWdfDeviceHandle(SmartcardExtension->OsData->DeviceObject));

        KeReleaseSpinLock(
             &SmartcardExtension->OsData->SpinLock,
             irql
             );

        status = WdfIoQueueRetrieveNextRequest(
                            DeviceExtension->NotificationQueue,
                            &request);
        if (NT_SUCCESS(status)) {

            SmartcardDebug(
                          DEBUG_DRIVER,
                          ( "PSCR!CBUpdateCardState: Completing Irp %p\n",
                            notificationIrp)
                          );

            WdfRequestCompleteWithInformation(request, status, 0);
        }
        else {
            NT_ASSERTMSG("WdfIoQueueRetrieveNextRequest failed",
                      status == STATUS_NO_MORE_ENTRIES);
        }
    } else {
        KeReleaseSpinLock(
                          &SmartcardExtension->OsData->SpinLock,
                          irql
                          );
    }

    SmartcardDebug(
                  DEBUG_TRACE,
                  ( "PSCR!CBUpdateCardState: Exit \n" )
                  );
}
//
// Io events callbacks.
//
VOID
MarsEvtIoDeviceControl(
                      IN WDFQUEUE Queue,
                      IN WDFREQUEST Request,
                      IN size_t OutputBufferLength,
                      IN size_t InputBufferLength,
                      IN ULONG IoControlCode
                      )
/*++

Routine Description:

    This event is called when the framework receives IRP_MJ_DEVICE_CONTROL
    requests from the system.

Arguments:

    Queue - Handle to the framework queue object that is associated
            with the I/O request.
    Request - Handle to a framework request object.

    OutputBufferLength - length of the request's output buffer,
                        if an output buffer is available.
    InputBufferLength - length of the request's input buffer,
                        if an input buffer is available.

    IoControlCode - the driver-defined or system-defined I/O control code
                    (IOCTL) that is associated with the request.
Return Value:

    VOID

--*/
{
    PFDO_DATA               fdoData = NULL;
    WDFDEVICE               device;
    NTSTATUS                status = STATUS_SUCCESS;
    PVOID                   inBuffer = NULL, outBuffer = NULL;
    size_t                  bytesReturned = 0;
    size_t                  size = 0;

    PAGED_CODE();

    //DbgPrint(("Started MarsEvtIODeviceControl\n"));

    device = WdfIoQueueGetDevice(Queue);
    fdoData = MarsFdoGetData(device);            //Gets device context

    //
    // Get the ioctl input & output buffers
    //
    if (InputBufferLength != 0) {
        status = WdfRequestRetrieveInputBuffer(Request,
                                               InputBufferLength,
                                               &inBuffer,
                                               &size);

        if (!NT_SUCCESS(status)) {
            WdfRequestComplete(Request, status);
            return;
        }
    }

    if (OutputBufferLength != 0) {
        status = WdfRequestRetrieveOutputBuffer(Request,
                                                OutputBufferLength,
                                                &outBuffer,
                                                &size);
        if (!NT_SUCCESS(status)) {
            WdfRequestComplete(Request, status);
            return;
        }
    }

    switch (IoControlCode) {
    
    case IOCTL_MARS_GET_DRIVER_VERSION:

        if (OutputBufferLength < sizeof(USHORT)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        *(PUSHORT)outBuffer = fdoData->DriverVersion;
        bytesReturned = sizeof(USHORT);
        break;


    case IOCTL_MARS_GET_FUNCTION_NUMBER:

        if (OutputBufferLength < sizeof(UCHAR)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        *(PUCHAR)outBuffer = fdoData->FunctionNumber;
        bytesReturned  = sizeof(UCHAR);
        break;


    case IOCTL_MARS_GET_FUNCTION_FOCUS:

        if (OutputBufferLength < sizeof(UCHAR)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        *(PUCHAR)outBuffer = fdoData->FunctionFocus;
        bytesReturned  = sizeof(UCHAR);
        break;


    case IOCTL_MARS_SET_FUNCTION_FOCUS:

        if (InputBufferLength < sizeof(UCHAR)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        fdoData->FunctionFocus = *(PUCHAR)inBuffer;
        break;


        //---------------------------------------------------
        //
        // SDP_BUS_WIDTH
        //
        //---------------------------------------------------

    case IOCTL_MARS_GET_BUS_WIDTH:

        if (OutputBufferLength < sizeof(UCHAR)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        status = SdioGetProperty(device, SDP_BUS_WIDTH,
                                 outBuffer, sizeof(UCHAR));

        if (NT_SUCCESS(status)) {
            bytesReturned  = sizeof(UCHAR);
        }
        break;


    case IOCTL_MARS_SET_BUS_WIDTH:

        if (InputBufferLength < sizeof(UCHAR)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        status = SdioSetProperty(device, SDP_BUS_WIDTH,
                                 inBuffer, sizeof(UCHAR));
        break;


        //---------------------------------------------------
        //
        // SDP_BUS_CLOCK
        //
        //---------------------------------------------------

    case IOCTL_MARS_GET_BUS_CLOCK:

        if (OutputBufferLength < sizeof(ULONG)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        status = SdioGetProperty(device, SDP_BUS_CLOCK,
                                 outBuffer, sizeof(ULONG));

        if (NT_SUCCESS(status)) {
            bytesReturned  = sizeof(ULONG);
        }
        break;


    case IOCTL_MARS_SET_BUS_CLOCK:

        if (InputBufferLength < sizeof(ULONG)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        status = SdioSetProperty(device, SDP_BUS_CLOCK,
                                 inBuffer, sizeof(ULONG));
        break;


        //---------------------------------------------------
        //
        // SDP_FUNCTION_BLOCK_LENGTH
        //
        //---------------------------------------------------


    case IOCTL_MARS_GET_BLOCKLEN:

        if (OutputBufferLength < sizeof(USHORT)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }
        status = SdioGetProperty(device, SDP_FUNCTION_BLOCK_LENGTH,
                                 outBuffer, sizeof(SHORT));

        if (NT_SUCCESS(status)) {
            bytesReturned  = sizeof(USHORT);
        }
        break;


    case IOCTL_MARS_SET_BLOCKLEN:

        if (InputBufferLength < sizeof(USHORT)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }
        status = SdioSetProperty(device, SDP_FUNCTION_BLOCK_LENGTH,
                                 inBuffer, sizeof(SHORT));
        break;


        //---------------------------------------------------
        //
        // SDP_FN0_BLOCK_LENGTH
        //
        //---------------------------------------------------


    case IOCTL_MARS_GET_FN0_BLOCKLEN:

        if (OutputBufferLength < sizeof(USHORT)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }
        status = SdioGetProperty(device, SDP_FN0_BLOCK_LENGTH,
                                 outBuffer, sizeof(SHORT));

        if (NT_SUCCESS(status)) {
            bytesReturned  = sizeof(USHORT);
        }
        break;


    case IOCTL_MARS_SET_FN0_BLOCKLEN:

        if (InputBufferLength < sizeof(USHORT)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }
        status = SdioSetProperty(device, SDP_FN0_BLOCK_LENGTH,
                                 inBuffer, sizeof(SHORT));
        break;


        //---------------------------------------------------
        //
        // SDP_BUS_INTERFACE_CONTROL
        //
        //---------------------------------------------------


    case IOCTL_MARS_GET_BUS_INTERFACE_CONTROL:

        if (OutputBufferLength < sizeof(UCHAR)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }
        status = SdioGetProperty(device, SDP_BUS_INTERFACE_CONTROL,
                                 outBuffer, sizeof(UCHAR));

        if (NT_SUCCESS(status)) {
            bytesReturned  = sizeof(UCHAR);
        }
        break;


    case IOCTL_MARS_SET_BUS_INTERFACE_CONTROL:

        if (InputBufferLength < sizeof(UCHAR)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }
        status = SdioSetProperty(device, SDP_BUS_INTERFACE_CONTROL,
                                 inBuffer, sizeof(UCHAR));
        break;


        //---------------------------------------------------
        //
        // SDP_FUNCTION_INT_ENABLE
        //
        //---------------------------------------------------


    case IOCTL_MARS_GET_INT_ENABLE:

        if (OutputBufferLength < sizeof(UCHAR)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }
        status = SdioGetProperty(device, SDP_FUNCTION_INT_ENABLE,
                                 outBuffer, sizeof(UCHAR));

        if (NT_SUCCESS(status)) {
            bytesReturned  = sizeof(UCHAR);
        }
        break;


    case IOCTL_MARS_SET_INT_ENABLE:

        if (InputBufferLength < sizeof(UCHAR)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }
        status = SdioSetProperty(device, SDP_FUNCTION_INT_ENABLE,
                                 inBuffer, sizeof(UCHAR));
        break;


        //---------------------------------------------------
        //
        // READ/WRITE BYTE
        //
        //---------------------------------------------------


    case IOCTL_MARS_READ_BYTE:

        if ((InputBufferLength < sizeof(ULONG)) || (OutputBufferLength < sizeof(UCHAR))) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        status = SdioReadWriteByte(device,
                                   fdoData->FunctionFocus,
                                   (PUCHAR)outBuffer,
                                   *(PULONG)inBuffer,
                                   FALSE);

        if (NT_SUCCESS(status)) {
            bytesReturned  = sizeof(UCHAR);
        }

        break;


    case IOCTL_MARS_WRITE_BYTE:

        if ((InputBufferLength < sizeof(ULONG)*2)) {//||(OutputBufferLength < sizeof(UCHAR))) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        // BUGBUG: check for output buffer length

        status = SdioReadWriteByte(device,
                                   fdoData->FunctionFocus,
                                   (PUCHAR)(&((PULONG)inBuffer)[1]),
                                   *(PULONG)inBuffer,
                                   TRUE);

        // BUGBUG: Return the right size

        if (NT_SUCCESS(status)) {
            bytesReturned  = sizeof(UCHAR);
        }


        break;


        //---------------------------------------------------
        //
        // Mode settings
        //
        //---------------------------------------------------

    case IOCTL_MARS_SET_TRANSFER_MODE:

        bytesReturned  = 0;

        break;

    case IOCTL_MARS_TOGGLE_MODE:

        if (OutputBufferLength < sizeof(UCHAR)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        if (fdoData->DriverVersion < SDBUS_DRIVER_VERSION_2) {
            status = STATUS_INVALID_DEVICE_REQUEST;
            break;
        }

        fdoData->BlockMode = fdoData->BlockMode ? 0 : 1;
        *(PUCHAR)outBuffer = fdoData->BlockMode;
        bytesReturned  = sizeof(UCHAR);
        break;


    case IOCTL_MARS_TOGGLE_NOISY:

        if (OutputBufferLength < sizeof(BOOLEAN)) {
            status = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        NoisyMode = NoisyMode ? 0 : 1;
        *(PBOOLEAN)outBuffer = NoisyMode;
        bytesReturned  = sizeof(BOOLEAN);

        if (NoisyMode) {
            KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "MARS: Noisy mode\n"));
        } else {
            KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "MARS: Quiet mode\n"));
        }
        break;


    default:
        NT_ASSERTMSG("Invalid IOCTL request\n", FALSE);

        status = STATUS_INVALID_DEVICE_REQUEST;
    }

    WdfRequestCompleteWithInformation(Request, status, bytesReturned);
    return;
}
Beispiel #7
0
//
// Internal Function: UartCtlSetHandflow
//
VOID
UartCtlSetHandflow(
    _In_ WDFDEVICE Device, 
    _In_ WDFREQUEST Request,
    _In_ size_t OutputBufferLength,
    _In_ size_t InputBufferLength
    )
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    PUART_DEVICE_EXTENSION pDevExt = UartGetDeviceExtension(Device);
    PSERIAL_HANDFLOW pHandFlow = NULL;

    UNREFERENCED_PARAMETER(OutputBufferLength);
    UNREFERENCED_PARAMETER(InputBufferLength);

    FuncEntry(TRACE_FLAG_CONTROL);

    status = WdfRequestRetrieveInputBuffer(Request, 
                    sizeof(SERIAL_HANDFLOW), 
                    (PVOID*)(& pHandFlow), 
                    NULL);

    if (!NT_SUCCESS(status))
    {
        TraceMessage(
            TRACE_LEVEL_ERROR,
            TRACE_FLAG_CONTROL,
            "Failed to retrieve input buffer for WDFREQUEST %p - "
            "%!STATUS!",
            Request,
            status);
    }

    if (NT_SUCCESS(status))
    {
        //
        // Make sure there are no invalid bits set in
        // the control and handshake
        //

        if ((pHandFlow->ControlHandShake & SERIAL_CONTROL_INVALID) ||
            (pHandFlow->FlowReplace & SERIAL_FLOW_INVALID))
        {
            status = STATUS_INVALID_PARAMETER;
            TraceMessage(
                TRACE_LEVEL_ERROR,
                TRACE_FLAG_CONTROL,
                "Invalid bit in SERIAL_HANDFLOW %p - "
                "%!STATUS!",
                pHandFlow,
                status);
        }
    }

    if (NT_SUCCESS(status))
    {
        //
        // Software flow control and in-band signaling 
        // have not been implemented in this sample.
        //

        if ((pHandFlow->ControlHandShake & SERIAL_DSR_SENSITIVITY) ||
            (pHandFlow->ControlHandShake & SERIAL_ERROR_ABORT) ||
            (pHandFlow->ControlHandShake & SERIAL_DCD_HANDSHAKE) ||
            (pHandFlow->FlowReplace & SERIAL_AUTO_TRANSMIT) ||
            (pHandFlow->FlowReplace & SERIAL_AUTO_RECEIVE) ||
            (pHandFlow->FlowReplace & SERIAL_ERROR_CHAR) ||
            (pHandFlow->FlowReplace & SERIAL_NULL_STRIPPING) ||
            (pHandFlow->FlowReplace & SERIAL_BREAK_CHAR) ||
            (pHandFlow->FlowReplace & SERIAL_XOFF_CONTINUE) ||
            ((pHandFlow->FlowReplace & SERIAL_RTS_MASK) == 
                SERIAL_TRANSMIT_TOGGLE))
        {
            status = STATUS_NOT_IMPLEMENTED;
            TraceMessage(
                TRACE_LEVEL_WARNING,
                TRACE_FLAG_CONTROL,
                "Specified SERIAL_HANDFLOW %p has not been implemented - "
                "%!STATUS!",
                pHandFlow,
                status);
        }
    }

    if (NT_SUCCESS(status))
    {
        //
        // Make sure the DTR mode is valid
        //

        if ((pHandFlow->ControlHandShake & SERIAL_DTR_MASK) ==
            SERIAL_DTR_MASK)
        {
            status = STATUS_INVALID_PARAMETER;
            TraceMessage(
                TRACE_LEVEL_ERROR,
                TRACE_FLAG_CONTROL,
                "Cannot set handflow with invalid DTR mode %lu - "
                "%!STATUS!",
                pHandFlow->ControlHandShake,
                status);
        }
    }

    if (NT_SUCCESS(status))
    {
        WdfSpinLockAcquire(pDevExt->ReceiveBufferSpinLock);
        WdfInterruptAcquireLock(pDevExt->WdfInterrupt);

        BOOLEAN newFlowControl;
        BOOLEAN prevFlowControl = UsingRXFlowControl(pDevExt);

        pDevExt->HandFlow = *pHandFlow;

        newFlowControl = UsingRXFlowControl(pDevExt);
        WdfInterruptReleaseLock(pDevExt->WdfInterrupt);

        // Empty software FIFO before changing flow control
        if (newFlowControl != prevFlowControl)
        {
            if (!newFlowControl)
            {
                if (pDevExt->FIFOBufferBytes > 0)
                {
                    // If switching from flow control to no flow control,
                    // read bytes from the software FIFO to ring buffer before
                    // asserting flow control lines.

                    // Shouldn't have a cached buffer and bytes in the software FIFO
                    NT_ASSERT(!HasCachedReceiveBuffer(pDevExt));
                
                    // Using a new status variable so the IOCTL doesn't fail if
                    // the driver can't read the software FIFO to SerCx ring buffer, which
                    // may happen after the file has closed.
                    NTSTATUS fifoStatus = SerCxRetrieveReceiveBuffer(Device, SERIAL_SOFTWARE_FIFO_SIZE, &pDevExt->PIOReceiveBuffer);

                    // Read bytes from software FIFO and return the buffer
                    if (NT_SUCCESS(fifoStatus))
                    {
                        // Read the software FIFO bytes into the ring buffer.
                        // This function won't return the buffer.
                        UartReceiveBytesFromSoftwareFIFO(pDevExt);

                        // The software FIFO has been read out and should be empty now.
                        NT_ASSERT(pDevExt->FIFOBufferBytes == 0);

                        fifoStatus = SerCxProgressReceive(
                            Device, 
                            pDevExt->ReceiveProgress, 
                            SerCxStatusSuccess);

                        if (!NT_SUCCESS(fifoStatus))
                        {
                            TraceMessage(
                                TRACE_LEVEL_ERROR,
                                TRACE_FLAG_CONTROL,
                                "%!FUNC! Failed to return buffer - %!STATUS!",
                                fifoStatus);
                            NT_ASSERTMSG("SerCxProgressReceive shouldn't fail", NT_SUCCESS(fifoStatus));
                        }

                        pDevExt->PerfStats.ReceivedCount += pDevExt->ReceiveProgress;
                        pDevExt->ReceiveProgress = 0;
                        pDevExt->PIOReceiveBuffer.Buffer = NULL;
                    }
                    else
                    {
                        TraceMessage(
                            TRACE_LEVEL_WARNING,
                            TRACE_FLAG_CONTROL,
                            "SerCxRetrieveReceiveBuffer failed - %!STATUS!",
                            fifoStatus);
                    }
                }
            }
            else
            {
                // If switching from no flow control to flow control,
                // the software FIFO should already be empty.
                NT_ASSERT(pDevExt->FIFOBufferBytes == 0);
            }
        }

        WdfInterruptAcquireLock(pDevExt->WdfInterrupt);

        // If software FIFO empty, re-assert flow control
        // Automatic flow control MUST be re-enabled here if it's being used.
        if (pDevExt->FIFOBufferBytes == 0)
        {
            UartFlowReceiveAvailable(Device);
        }        
        
        WdfInterruptReleaseLock(pDevExt->WdfInterrupt);
        WdfSpinLockRelease(pDevExt->ReceiveBufferSpinLock);
    }

    TraceMessage(TRACE_LEVEL_INFORMATION,
                    TRACE_FLAG_CONTROL,
                    "WdfRequestComplete( %!HANDLE! => %!STATUS! )",
                    Request,
                    status);
    WdfRequestComplete(Request, status);

    FuncExit(TRACE_FLAG_CONTROL);
}
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);
}
Beispiel #9
0
NTSTATUS
UpdateBufferLocationAndIoctl(
    _Inout_ PIRP Irp,
    _Out_ PULONG UpdatedIoctl
    )
/*++

Routine Description:

    The buffers are swapped in the following manner.
     
    Incoming Irp:
    ==============
    Irp->UserBuffer contains HID_XFER_PACKET which may have both input and 
        output data/buffer.

        struct HID_XFER_PACKET {
            PUCHAR  reportBuffer;   // output buffer
            ULONG  reportBufferLen; // output buffer length
            UCHAR  reportId;        // input data
        };

    Input/output buffer location: Irp->UserBuffer

    Updated Irp that is sent down:
    ==============================

    For IOCTLs that have both input and output:
        Input buffer location : Type3InputBuffer (= PHID_XFER_PACKET->reportId)
        Output buffer location: Irp->UserBuffer (= PHID_XFER_PACKET->reportBuffer) 
                                

    For IOCTLs that have two inputs:
        Input buffer location: Type3InputBuffer (= PHID_XFER_PACKET->reportBuffer)
        Input data           : Parameters.DeviceIoControl.OutputBufferLength (= PHID_XFER_PACKET->reportId)
    
--*/
{
    PHID_XFER_PACKET hidPacket;
    PIO_STACK_LOCATION currStack, nextStack;
    NTSTATUS status;
    ULONG ioctlCode, newIoctlCode;
    
    currStack = IoGetCurrentIrpStackLocation(Irp);
    nextStack = IoGetNextIrpStackLocation(Irp);
    status = STATUS_SUCCESS;
    ioctlCode = nextStack->Parameters.DeviceIoControl.IoControlCode;

    hidPacket = (PHID_XFER_PACKET) Irp->UserBuffer;
    if (hidPacket == NULL) {
        status = STATUS_INVALID_PARAMETER;
        return status;
    }

    //
    // Store original buffer pointer in current stack location so we can revert 
    // it back in completion routine
    //
    NT_ASSERTMSG("Type3InputBuffer is not NULL, not expected", 
        currStack->Parameters.DeviceIoControl.Type3InputBuffer == NULL);
    currStack->Parameters.DeviceIoControl.Type3InputBuffer = Irp->UserBuffer;

    switch (currStack->Parameters.DeviceIoControl.IoControlCode) {
    case IOCTL_HID_GET_FEATURE:          // METHOD_OUT_DIRECT, KM/UM
    case IOCTL_HID_GET_INPUT_REPORT:     // METHOD_OUT_DIRECT, KM/UM
        //
        // These IOCTLs have input and output buffer combined together
        // we separate them out.
        //

        if (currStack->Parameters.DeviceIoControl.OutputBufferLength 
            < sizeof(HID_XFER_PACKET)) {
            status = STATUS_INVALID_PARAMETER;
            return status;
        }

        //
        // Setup input data
        //
        nextStack->Parameters.DeviceIoControl.Type3InputBuffer =
            (PVOID)&hidPacket->reportId;
        nextStack->Parameters.DeviceIoControl.InputBufferLength = 
            sizeof(hidPacket->reportId);
             
        //
        // Setup output buffer
        //
        Irp->UserBuffer = (PVOID) hidPacket->reportBuffer;
        nextStack->Parameters.DeviceIoControl.OutputBufferLength = 
            hidPacket->reportBufferLen;

        break;
        
    case IOCTL_HID_WRITE_REPORT:        // METHOD_NEITHER, KM
    case IOCTL_HID_SET_FEATURE:         // METHOD_IN_DIRECT, KM/UM
    case IOCTL_HID_SET_OUTPUT_REPORT:   // METHOD_IN_DIRECT, KM/UM
        //
        // These IOCTLS have two inputs: 
        // 1) input buffer (PHID_XFER_PACKET->reportBuffer & reportBufferlength)
        // 2) input data (PHID_XFER_PACKET->reportId)
        // Input buffer is placed in Type3InputBuffer and its size in 
        //     InputBufferLength
        // Input data is placed in outputBufferlength 
        //

        if (currStack->Parameters.DeviceIoControl.InputBufferLength 
            < sizeof(HID_XFER_PACKET)) {
            status = STATUS_INVALID_PARAMETER;
            return status;
        }

        nextStack->Parameters.DeviceIoControl.Type3InputBuffer = 
            (PVOID) hidPacket->reportBuffer;
        nextStack->Parameters.DeviceIoControl.InputBufferLength = 
            hidPacket->reportBufferLen;
        nextStack->Parameters.DeviceIoControl.OutputBufferLength = 
            hidPacket->reportId;

        //
        // Use a scratch buffer allocated as a global buffer, sized 
        // to maximum possible reportlength (MAXUCHAR) and store it temporarily 
        // at Irp->UserBuffer since we've set a non-zero output buffer length. 
        // Note that UMDF will not copy the buffer content to user-mode driver's
        // buffer because it's an output buffer meant to written to, by the 
        // user-mode driver and not read.
        //
        Irp->UserBuffer = G_ScratchBuffer;
        
        break;

    default:
        NT_ASSERTMSG("Unexpected IOCTL", FALSE);
        break;
    }

    //
    // For those IOCTLs that are not METHOD_NEITHER, we map to new IOCTL 
    // code that is METHOD_NEITHER.
    //
    switch(ioctlCode) {
    case IOCTL_HID_SET_FEATURE:                          // METHOD_IN_DIRECT, KM/UM
        newIoctlCode = IOCTL_UMDF_HID_SET_FEATURE;       // METHOD_NEITHER
        break;
    case IOCTL_HID_GET_FEATURE:                          // METHOD_OUT_DIRECT, KM/UM
        newIoctlCode = IOCTL_UMDF_HID_GET_FEATURE;       // METHOD_NEITHER
        break;
    case IOCTL_HID_GET_INPUT_REPORT:                     // METHOD_OUT_DIRECT, KM/UM
        newIoctlCode = IOCTL_UMDF_HID_GET_INPUT_REPORT;  // METHOD_NEITHER 
        break;
    case IOCTL_HID_SET_OUTPUT_REPORT:                    // METHOD_IN_DIRECT, KM/UM
        newIoctlCode = IOCTL_UMDF_HID_SET_OUTPUT_REPORT; // METHOD_NEITHER 
        break;
    default:
        // 
        // keep the ioctl code unchanged
        //
        newIoctlCode = ioctlCode;
        break;
    }

    *UpdatedIoctl = newIoctlCode;

    return status;
}
Beispiel #10
0
NTSTATUS
HidUmdfInternalIoctlWorker(
    _In_ PDEVICE_OBJECT DeviceObject,
    _Inout_ PIRP Irp
    )
/*++

Routine Description:

    IOCTL handler.


Arguments:

   DeviceObject - pointer to a device object.

   Irp - pointer to an I/O Request Packet.

Return Value:

      NT status code

--*/
{
    PIO_STACK_LOCATION currStack, nextStack;
    ULONG ioctlCode, newIoctlCode;
    BOOLEAN setCompletionRoutine = FALSE;
    NTSTATUS status = STATUS_SUCCESS;
    BOOLEAN modeChanged = FALSE;
    PULONG temp = NULL;
    
    currStack = IoGetCurrentIrpStackLocation(Irp);

    //
    // Copy current stack to next instead of skipping. We do this to preserve 
    // current stack information provided by hidclass driver to the minidriver
    //
    IoCopyCurrentIrpStackLocationToNext(Irp);

    //
    // HIDclass uses INTERNAL_IOCTL but since UMDF doesn't yet have support for
    // internal IOCTLS we change the IOCTL type to DEVICE_CONTROL for next stack
    // so that UMDF stack can handle it as normal IOCTL.
    // Note that user mode apps cannot open a handle to minidriver since 
    // HIDClass doesn't allow that (it own's minidriver's dispatch table),
    // and therefore they can't send these IOCTLs to UMDF minidriver by calling 
    // win32 API.
    //
    nextStack = IoGetNextIrpStackLocation(Irp);
    nextStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;

    //
    // Some IOCTLs are not of type METHOD_NEITHER and are forwarded by 
    // HIDClass to minidriver. We modify those IOCTLs to use METHOD_NEITHER
    // and send it down to UMDF driver.
    //
    ioctlCode = nextStack->Parameters.DeviceIoControl.IoControlCode;

    newIoctlCode = ioctlCode;
    
    switch(ioctlCode) {
    case IOCTL_HID_GET_DEVICE_DESCRIPTOR:           // METHOD_NEITHER, KM
    case IOCTL_HID_GET_REPORT_DESCRIPTOR:           // METHOD_NEITHER, KM
    case IOCTL_HID_READ_REPORT:                     // METHOD_NEITHER, KM
    case IOCTL_HID_ACTIVATE_DEVICE:                 // METHOD_NEITHER, KM
    case IOCTL_HID_DEACTIVATE_DEVICE:               // METHOD_NEITHER, KM
    case IOCTL_HID_GET_DEVICE_ATTRIBUTES:           // METHOD_NEITHER, KM
    case IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST:  // METHOD_NEITHER, KM
        //
        // Nothing to do. These IOCTLs have been listed for completeness.
        //
        break;
    case IOCTL_HID_WRITE_REPORT:                    // METHOD_NEITHER, KM
    case IOCTL_HID_SET_FEATURE:                     // METHOD_IN_DIRECT, KM/UM
    case IOCTL_HID_GET_FEATURE:                     // METHOD_OUT_DIRECT, KM/UM
    case IOCTL_HID_GET_INPUT_REPORT:                // METHOD_OUT_DIRECT, KM/UM
    case IOCTL_HID_SET_OUTPUT_REPORT:               // METHOD_IN_DIRECT, KM/UM
        //
        // These IOCTLs use HID_XFER_PACKET. They need their buffer location 
        // updated. See comments in function for IOCTL specific updates.
        //
        status = UpdateBufferLocationAndIoctl(Irp, &newIoctlCode);
        if (!NT_SUCCESS(status)) {
            KdPrint(("HidUmdf: Ioctl %s failed status 0x%x\n", 
                DbgHidInternalIoctlString(ioctlCode), status));
            Irp->IoStatus.Status = status;
            IoCompleteRequest(Irp, IO_NO_INCREMENT);
            return status;
        }

        //
        // set completion routine
        //
        setCompletionRoutine = TRUE;
        break;

    case IOCTL_GET_PHYSICAL_DESCRIPTOR:             // METHOD_OUT_DIRECT, KM/UM 
        //
        // These IOCTLs are not METHOD_NEITHER but hidclass places buffers at
        // locations that are standard locations for METHOD_NEITHER 
        // (Type3InputBuffer and Irp->UserBuffer), so we modify the IOCTL type
        // to use METHOD_NEITHER so that UMDF can provide the buffers from 
        // standard METHOD_NEITHER buffer locations.
        // 
        newIoctlCode = IOCTL_UMDF_GET_PHYSICAL_DESCRIPTOR;
        break;

    case IOCTL_HID_GET_STRING:                      // METHOD_NEITHER, KM     
        //
        // This is a METHOD_NEITHER IOCTL. Hidclass places an input
        // ULONG value, and not a buffer, at Type3inputBuffer location. 
        // We store the input value in Irp->AssocatedIrp.SystemBuffer location
        // and store pointer to Irp->AssocatedIrp.SystemBuffer at 
        // Type3InputBuffer so that lower driver can access it as input buffer. 
        // 

        //
        // swap current SystemBuffer content with Type3inputBuffer
        //
        temp = Irp->AssociatedIrp.SystemBuffer;
        Irp->AssociatedIrp.SystemBuffer = 
            currStack->Parameters.DeviceIoControl.Type3InputBuffer;
        currStack->Parameters.DeviceIoControl.Type3InputBuffer = temp;

        //
        // store the address of SystemBuffer in next stack's Type3InputBuffer
        // and set buffer size
        //
        nextStack->Parameters.DeviceIoControl.Type3InputBuffer = 
            &Irp->AssociatedIrp.SystemBuffer;
        nextStack->Parameters.DeviceIoControl.InputBufferLength = sizeof(ULONG);

        setCompletionRoutine = TRUE;
        break;
    
    case IOCTL_HID_GET_INDEXED_STRING:              // METHOD_OUT_DIRECT, KM/UM
        //
        // This is a METHOD_OUT_DIRECT IOCTL however hidclass places buffer/value
        // in a mix of locations (Type3InputBuffer for input instead of 
        // Irp->AssociatedIrp.SystemBuffer and Irp->MdlAddress for output). 
        // Also, the input is not a buffer but a ULONG value.
        // 
        // We store the address of next stack's Type3InputBuffer that contains 
        // the input value at Irp->AssiciatedIrp.SystemBuffer 
        // (standard location for METHOD_OUT_DIRECT), and keep the output buffer
        // location (Irp->UserBuffer) unchanged  since it's already at standard
        // location. The input buffer location is reverted back to original in 
        // completion routine.
        // 

        //
        // store SystemBuffer in curr stack's Type3inputBuffer so we 
        // can get it back in completion routine.
        //
        currStack->Parameters.DeviceIoControl.Type3InputBuffer = 
            Irp->AssociatedIrp.SystemBuffer;

        //
        // store the address of next stack's Type3InputBuffer in  SystemBuffer
        // and set buffer size.
        //
        Irp->AssociatedIrp.SystemBuffer = 
            &nextStack->Parameters.DeviceIoControl.Type3InputBuffer;
        nextStack->Parameters.DeviceIoControl.InputBufferLength = sizeof(ULONG);

        setCompletionRoutine = TRUE;
        break;

    default:
        NT_ASSERTMSG("Unexpected IOCTL", FALSE);
        break;
    }

    //
    // update ioctl code for next stack location
    //
    nextStack->Parameters.DeviceIoControl.IoControlCode = newIoctlCode;

    if (Irp->RequestorMode == UserMode) {
        Irp->RequestorMode = KernelMode;
        setCompletionRoutine = TRUE;
        modeChanged = TRUE;
    }

    if (setCompletionRoutine) {
        IoSetCompletionRoutine(Irp,
                       UserIoctlCompletion,
                       (modeChanged ? (PVOID)Irp : NULL),  // context
                       TRUE,                       
                       TRUE,
                       TRUE );
    }

    return IoCallDriver(GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp);
}
VOID
CdSetFileObject (
    _In_ PIRP_CONTEXT IrpContext,
    _Inout_ PFILE_OBJECT FileObject,
    _In_ TYPE_OF_OPEN TypeOfOpen,
    PFCB Fcb,
    _In_opt_ PCCB Ccb
)

/*++

Routine Description:

    This routine will initialize the FileObject context fields based on the
    input type and data structures.

Arguments:

    FileObject - Supplies the file object pointer being initialized.

    TypeOfOpen - Sets the type of open.

    Fcb - Fcb for this file object.  Ignored for UnopenedFileObject.

    Ccb - Ccb for the handle corresponding to this file object.  Will not
        be present for stream file objects.

Return Value:

    None.

--*/

{
    PAGED_CODE();

    UNREFERENCED_PARAMETER( IrpContext );

    //
    //  We only have values 0 to 7 available so make sure we didn't
    //  inadvertantly add a new type.
    //

    NT_ASSERTMSG( "FileObject types exceed available bits\n", BeyondValidType <= 8 );

    //
    //  Setting a file object to type UnopenedFileObject means just
    //  clearing all of the context fields.  All the other input
    //

    if (TypeOfOpen == UnopenedFileObject) {

        FileObject->FsContext =
            FileObject->FsContext2 = NULL;

        return;
    }

    //
    //  Check that the 3 low-order bits of the Ccb are clear.
    //

    NT_ASSERTMSG( "Ccb is not quad-aligned\n", !FlagOn( ((ULONG_PTR) Ccb), TYPE_OF_OPEN_MASK ));

    //
    //  We will or the type of open into the low order bits of FsContext2
    //  along with the Ccb value.
    //  The Fcb is stored into the FsContext field.
    //

    FileObject->FsContext = Fcb;
    FileObject->FsContext2 = Ccb;

#pragma warning( suppress: 4213 )
    SetFlag( ((ULONG_PTR) FileObject->FsContext2), TypeOfOpen );

    //
    //  Set the Vpb field in the file object.
    //

    FileObject->Vpb = Fcb->Vcb->Vpb;

    return;
}
Beispiel #12
0
/*++////////////////////////////////////////////////////////////////////////////

ClassAcquireRemoveLockEx()

Routine Description:

    This routine is called to acquire the remove lock on the device object.
    While the lock is held, the caller can assume that no pending pnp REMOVE
    requests will be completed.

    The lock should be acquired immediately upon entering a dispatch routine.
    It should also be acquired before creating any new reference to the
    device object if there's a chance of releasing the reference before the
    new one is done.

    This routine will return TRUE if the lock was successfully acquired or
    FALSE if it cannot be because the device object has already been removed.

Arguments:

    DeviceObject - the device object to lock

    Tag - Used for tracking lock allocation and release.  If an irp is
          specified when acquiring the lock then the same Tag must be
          used to release the lock before the Tag is completed.

Return Value:

    The value of the IsRemoved flag in the device extension.  If this is
    non-zero then the device object has received a Remove irp and non-cleanup
    IRP's should fail.

    If the value is REMOVE_COMPLETE, the caller should not even release the
    lock.

--*/
ULONG
ClassAcquireRemoveLockEx(
    _In_ PDEVICE_OBJECT DeviceObject,
         PVOID Tag,
    _In_ PCSTR File,
    _In_ ULONG Line
    )
// This function implements the acquisition of Tag
#pragma warning(suppress:28104)
{
    PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;

    //
    // Grab the remove lock
    //

    #if DBG

        LONG lockValue;

        lockValue = InterlockedIncrement(&commonExtension->RemoveLock);


        TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_LOCK,  "ClassAcquireRemoveLock: "
                    "Acquired for Object %p & irp %p - count is %d\n",
                    DeviceObject, Tag, lockValue));

        NT_ASSERTMSG("ClassAcquireRemoveLock - lock value was negative : ",
                  (lockValue > 0));

        NT_ASSERTMSG("RemoveLock increased to meet LockHighWatermark",
                  ((LockHighWatermark == 0) ||
                   (lockValue != LockHighWatermark)));

        if (commonExtension->IsRemoved != REMOVE_COMPLETE)
        {
            PRTL_GENERIC_TABLE removeTrackingList = NULL;
            REMOVE_TRACKING_BLOCK trackingBlock;
            PREMOVE_TRACKING_BLOCK insertedTrackingBlock = NULL;
            BOOLEAN newElement = FALSE;

            KIRQL oldIrql;

            trackingBlock.Tag = Tag;

            trackingBlock.File = File;
            trackingBlock.Line = Line;

            KeQueryTickCount((&trackingBlock.TimeLocked));

            KeAcquireSpinLock(&commonExtension->RemoveTrackingSpinlock,
                              &oldIrql);

            removeTrackingList = commonExtension->RemoveTrackingList;

            if (removeTrackingList != NULL)
            {
                insertedTrackingBlock = RtlInsertElementGenericTable(removeTrackingList,
                                                                     &trackingBlock,
                                                                     sizeof(REMOVE_TRACKING_BLOCK),
                                                                     &newElement);
            }

            if (insertedTrackingBlock != NULL)
            {
                if (!newElement)
                {
                    TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_LOCK, ">>>>>ClassAcquireRemoveLock: "
                                "already tracking Tag %p\n", Tag));
                    TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_LOCK, ">>>>>ClassAcquireRemoveLock: "
                                "acquired in file %s on line %d\n",
                                insertedTrackingBlock->File, insertedTrackingBlock->Line));
//                  NT_ASSERT(FALSE);

                }
            }
            else
            {
                commonExtension->RemoveTrackingUntrackedCount++;

                TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_LOCK, ">>>>>ClassAcquireRemoveLock: "
                            "Cannot track Tag %p - currently %d untracked requsts\n",
                            Tag, commonExtension->RemoveTrackingUntrackedCount));
            }

            KeReleaseSpinLock(&commonExtension->RemoveTrackingSpinlock, oldIrql);
        }
    #else

        UNREFERENCED_PARAMETER(Tag);
        UNREFERENCED_PARAMETER(File);
        UNREFERENCED_PARAMETER(Line);

        InterlockedIncrement(&commonExtension->RemoveLock);

    #endif

    return (commonExtension->IsRemoved);
}
Beispiel #13
0
/*++////////////////////////////////////////////////////////////////////////////

ClassReleaseRemoveLock()

Routine Description:

    This routine is called to release the remove lock on the device object.  It
    must be called when finished using a previously locked reference to the
    device object.  If an Tag was specified when acquiring the lock then the
    same Tag must be specified when releasing the lock.

    When the lock count reduces to zero, this routine will signal the waiting
    remove Tag to delete the device object.  As a result the DeviceObject
    pointer should not be used again once the lock has been released.

Arguments:

    DeviceObject - the device object to lock

    Tag - The irp (if any) specified when acquiring the lock.  This is used
          for lock tracking purposes

Return Value:

    none

--*/
VOID
ClassReleaseRemoveLock(
    _In_ PDEVICE_OBJECT DeviceObject,
         PIRP Tag
    )
// This function implements the release of Tag
#pragma warning(suppress:28103)
{
    PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
    LONG lockValue;

    #if DBG
        PRTL_GENERIC_TABLE removeTrackingList = NULL;
        REMOVE_TRACKING_BLOCK searchDataBlock;

        BOOLEAN found = FALSE;

        BOOLEAN isRemoved = (commonExtension->IsRemoved == REMOVE_COMPLETE);

        KIRQL oldIrql;

        if(isRemoved) {
            TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_LOCK, "ClassReleaseRemoveLock: REMOVE_COMPLETE set; this should never happen"));
            InterlockedDecrement(&(commonExtension->RemoveLock));
            return;
        }

        KeAcquireSpinLock(&commonExtension->RemoveTrackingSpinlock,
                          &oldIrql);

        removeTrackingList = commonExtension->RemoveTrackingList;

        if (removeTrackingList != NULL)
        {
            searchDataBlock.Tag = Tag;
            found = RtlDeleteElementGenericTable(removeTrackingList, &searchDataBlock);
        }

        if(!found) {
            if(commonExtension->RemoveTrackingUntrackedCount == 0) {
                TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_LOCK, ">>>>>ClassReleaseRemoveLock: "
                            "Couldn't find Tag %p in the lock tracking list\n", Tag));
                NT_ASSERT(FALSE);
            } else {
                TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_LOCK, ">>>>>ClassReleaseRemoveLock: "
                            "Couldn't find Tag %p in the lock tracking list - "
                            "may be one of the %d untracked requests still outstanding\n",
                            Tag, commonExtension->RemoveTrackingUntrackedCount));

                commonExtension->RemoveTrackingUntrackedCount--;
                NT_ASSERT(commonExtension->RemoveTrackingUntrackedCount >= 0);
            }
        }

        KeReleaseSpinLock(&commonExtension->RemoveTrackingSpinlock,
                          oldIrql);

    #endif

    lockValue = InterlockedDecrement(&commonExtension->RemoveLock);

    TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_LOCK,  "ClassReleaseRemoveLock: "
                "Released for Object %p & irp %p - count is %d\n",
                DeviceObject, Tag, lockValue));

    NT_ASSERT(lockValue >= 0);

    NT_ASSERTMSG("RemoveLock decreased to meet LockLowWatermark",
              ((LockLowWatermark == 0) || !(lockValue == LockLowWatermark)));

    if(lockValue == 0) {

        NT_ASSERT(commonExtension->IsRemoved);

        //
        // The device needs to be removed.  Signal the remove event
        // that it's safe to go ahead.
        //

        TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_LOCK,  "ClassReleaseRemoveLock: "
                    "Release for object %p & irp %p caused lock to go to zero\n",
                    DeviceObject, Tag));

        KeSetEvent(&commonExtension->RemoveEvent,
                   IO_NO_INCREMENT,
                   FALSE);

    }
    return;
}