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!");
}
NTSTATUS 
SetBarGraphState(
    _In_ PDEVICE_CONTEXT DevContext, 
    _In_ PBAR_GRAPH_STATE BarGraphState
    )
/*++

Routine Description

    This routine sets the state of the bar graph on the board

Arguments:

    DevContext - One of our device extensions

    BarGraphState - Struct that describes the bar graph's desired state

Return Value:

    NT status value

--*/
{
    NTSTATUS status;
    WDF_USB_CONTROL_SETUP_PACKET    controlSetupPacket;
    WDF_REQUEST_SEND_OPTIONS        sendOptions;
    WDF_MEMORY_DESCRIPTOR memDesc;
    ULONG    bytesTransferred;

    PAGED_CODE();

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "--> SetBarGraphState\n");

    WDF_REQUEST_SEND_OPTIONS_INIT(
                                  &sendOptions,
                                  WDF_REQUEST_SEND_OPTION_TIMEOUT
                                  );

    WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(
                                         &sendOptions,
                                         DEFAULT_CONTROL_TRANSFER_TIMEOUT
                                         );

    WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket,
                                        BmRequestHostToDevice,
                                        BmRequestToDevice,
                                        USBFX2LK_SET_BARGRAPH_DISPLAY, // Request
                                        0, // Value
                                        0); // Index

    WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc,
                                                BarGraphState,
                                                sizeof(BAR_GRAPH_STATE));

    status = WdfUsbTargetDeviceSendControlTransferSynchronously(
                                        DevContext->UsbDevice,
                                        NULL, // Optional WDFREQUEST
                                        &sendOptions,
                                        &controlSetupPacket,
                                        &memDesc,
                                        &bytesTransferred);

    if(!NT_SUCCESS(status)) {

        TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL,
                        "SetBarGraphState: Failed - 0x%x \n", status);

    } else {

        TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL,
            "SetBarGraphState: LED mask is 0x%x\n", BarGraphState->BarsAsUChar);
    }

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "<-- SetBarGraphState\n");

    return status;

}
NTSTATUS 
SetSevenSegmentState(
    _In_ PDEVICE_CONTEXT DevContext, 
    _In_ PUCHAR SevenSegment
    )
/*++

Routine Description

    This routine sets the state of the 7 segment display on the board

Arguments:

    DevContext - One of our device extensions

    SevenSegment - desired state of the 7 segment display

Return Value:

    NT status value

--*/
{
    NTSTATUS status;
    WDF_USB_CONTROL_SETUP_PACKET    controlSetupPacket;
    WDF_REQUEST_SEND_OPTIONS        sendOptions;
    WDF_MEMORY_DESCRIPTOR memDesc;
    ULONG    bytesTransferred;

    PAGED_CODE();

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "--> SetSevenSegmentState\n");

    WDF_REQUEST_SEND_OPTIONS_INIT(
                                  &sendOptions,
                                  WDF_REQUEST_SEND_OPTION_TIMEOUT
                                  );

    WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(
                                         &sendOptions,
                                         DEFAULT_CONTROL_TRANSFER_TIMEOUT
                                         );

    WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket,
                                        BmRequestHostToDevice,
                                        BmRequestToDevice,
                                        USBFX2LK_SET_7SEGMENT_DISPLAY, // Request
                                        0, // Value
                                        0); // Index

    WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc,
                                    SevenSegment,
                                    sizeof(UCHAR));

    status = WdfUsbTargetDeviceSendControlTransferSynchronously(
                                                DevContext->UsbDevice,
                                                NULL, // Optional WDFREQUEST
                                                &sendOptions,
                                                &controlSetupPacket,
                                                &memDesc,
                                                &bytesTransferred);

    if(!NT_SUCCESS(status)) {

        TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL,
            "SetSevenSegmentState: Failed to set 7 Segment state - 0x%x \n", status);

    } else {

        TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL,
            "SetSevenSegmentState: 7 Segment mask is 0x%x\n", *SevenSegment);

    }

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "<-- SetSevenSegmentState\n");

    return status;

}
static NTSTATUS VirtQueueAddBuffer(IN PDEVICE_CONTEXT Context,
                                   IN WDFREQUEST Request,
                                   IN size_t Length)
{
    PREAD_BUFFER_ENTRY entry;
    size_t length;
    struct virtqueue *vq = Context->VirtQueue;
    struct VirtIOBufferDescriptor sg;
    int ret;

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

    entry = (PREAD_BUFFER_ENTRY)ExAllocatePoolWithTag(NonPagedPool,
        sizeof(READ_BUFFER_ENTRY), VIRT_RNG_MEMORY_TAG);

    if (entry == NULL)
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_READ,
            "Failed to allocate a read entry.");
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    length = min(Length, PAGE_SIZE);
    entry->Buffer = ExAllocatePoolWithTag(NonPagedPool, length,
        VIRT_RNG_MEMORY_TAG);

    if (entry->Buffer == NULL)
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_READ,
            "Failed to allocate a read buffer.");
        ExFreePoolWithTag(entry, VIRT_RNG_MEMORY_TAG);
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    entry->Request = Request;

    sg.physAddr = MmGetPhysicalAddress(entry->Buffer);
    sg.length = (unsigned)length;

    WdfSpinLockAcquire(Context->VirtQueueLock);

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

    PushEntryList(&Context->ReadBuffersList, &entry->ListEntry);

    ret = virtqueue_add_buf(vq, &sg, 0, 1, entry, NULL, 0);
    if (ret < 0)
    {
        PSINGLE_LIST_ENTRY removed;

        TraceEvents(TRACE_LEVEL_ERROR, DBG_READ,
            "Failed to add buffer to virt queue.");

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

        removed = PopEntryList(&Context->ReadBuffersList);
        NT_ASSERT(entry == CONTAINING_RECORD(
            removed, READ_BUFFER_ENTRY, ListEntry));

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

        WdfSpinLockRelease(Context->VirtQueueLock);

        return STATUS_UNSUCCESSFUL;
    }

    WdfSpinLockRelease(Context->VirtQueueLock);

    virtqueue_kick(vq);

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "<-- %!FUNC!");

    return STATUS_SUCCESS;
}
VOID
OsrFxEvtIoDeviceControl(
    _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

--*/
{
    WDFDEVICE           device;
    PDEVICE_CONTEXT     pDevContext;
    size_t              bytesReturned = 0;
    PBAR_GRAPH_STATE    barGraphState = NULL;
    PSWITCH_STATE       switchState = NULL;
    PUCHAR              sevenSegment = NULL;
    BOOLEAN             requestPending = FALSE;
    NTSTATUS            status = STATUS_INVALID_DEVICE_REQUEST;

    UNREFERENCED_PARAMETER(InputBufferLength);
    UNREFERENCED_PARAMETER(OutputBufferLength);

    PAGED_CODE();

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "--> OsrFxEvtIoDeviceControl\n");
    //
    // initialize variables
    //
    device = WdfIoQueueGetDevice(Queue);
    pDevContext = GetDeviceContext(device);

    switch(IoControlCode) {

    case IOCTL_OSRUSBFX2_GET_CONFIG_DESCRIPTOR: {

        PUSB_CONFIGURATION_DESCRIPTOR   configurationDescriptor = NULL;
        USHORT                          requiredSize = 0;

        //
        // First get the size of the config descriptor
        //
        status = WdfUsbTargetDeviceRetrieveConfigDescriptor(
                                    pDevContext->UsbDevice,
                                    NULL,
                                    &requiredSize);

        if (status != STATUS_BUFFER_TOO_SMALL) {
            TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL,
                "WdfUsbTargetDeviceRetrieveConfigDescriptor failed 0x%x\n", status);
            break;
        }

        //
        // Get the buffer - make sure the buffer is big enough
        //
        status = WdfRequestRetrieveOutputBuffer(Request,
                                        (size_t)requiredSize,  // MinimumRequired
                                        &configurationDescriptor,
                                        NULL);
        if(!NT_SUCCESS(status)){
            TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL,
                "WdfRequestRetrieveOutputBuffer failed 0x%x\n", status);
            break;
        }

        status = WdfUsbTargetDeviceRetrieveConfigDescriptor(
                                        pDevContext->UsbDevice,
                                        configurationDescriptor,
                                        &requiredSize);
        if (!NT_SUCCESS(status)) {
            TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL,
                "WdfUsbTargetDeviceRetrieveConfigDescriptor failed 0x%x\n", status);
            break;
        }

        bytesReturned = requiredSize;

        }
        break;

    case IOCTL_OSRUSBFX2_RESET_DEVICE:

        status = ResetDevice(device);
        break;

    case IOCTL_OSRUSBFX2_REENUMERATE_DEVICE:

        //
        // Otherwise, call our function to reenumerate the
        //  device
        //
        status = ReenumerateDevice(pDevContext);

        bytesReturned = 0;
        break;

    case IOCTL_OSRUSBFX2_GET_BAR_GRAPH_DISPLAY:

        //
        // Make sure the caller's output buffer is large enough
        //  to hold the state of the bar graph
        //
        status = WdfRequestRetrieveOutputBuffer(Request,
                            sizeof(BAR_GRAPH_STATE),
                            &barGraphState,
                            NULL);

        if (!NT_SUCCESS(status)) {
            TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL,
                "User's output buffer is too small for this IOCTL, expecting an BAR_GRAPH_STATE\n");
            break;
        }
        //
        // Call our function to get the bar graph state
        //
        status = GetBarGraphState(pDevContext, barGraphState);

        //
        // If we succeeded return the user their data
        //
        if (NT_SUCCESS(status)) {

            bytesReturned = sizeof(BAR_GRAPH_STATE);

        } else {

            bytesReturned = 0;

        }
        break;

    case IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY:

        status = WdfRequestRetrieveInputBuffer(Request,
                            sizeof(BAR_GRAPH_STATE),
                            &barGraphState,
                            NULL);
        if (!NT_SUCCESS(status)) {
            TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL,
                "User's input buffer is too small for this IOCTL, expecting an BAR_GRAPH_STATE\n");
            break;
        }

        //
        // Call our routine to set the bar graph state
        //
        status = SetBarGraphState(pDevContext, barGraphState);

        //
        // There's no data returned for this call
        //
        bytesReturned = 0;
        break;

    case IOCTL_OSRUSBFX2_GET_7_SEGMENT_DISPLAY:

        status = WdfRequestRetrieveOutputBuffer(Request,
                            sizeof(UCHAR),
                            &sevenSegment,
                            NULL);

        if (!NT_SUCCESS(status)) {
            TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL,
                "User's output buffer is too small for this IOCTL, expecting an UCHAR\n");
            break;
        }

        //
        // Call our function to get the 7 segment state
        //
        status = GetSevenSegmentState(pDevContext, sevenSegment);

        //
        // If we succeeded return the user their data
        //
        if (NT_SUCCESS(status)) {

            bytesReturned = sizeof(UCHAR);

        } else {

            bytesReturned = 0;

        }
        break;

    case IOCTL_OSRUSBFX2_SET_7_SEGMENT_DISPLAY:

        status = WdfRequestRetrieveInputBuffer(Request,
                            sizeof(UCHAR),
                            &sevenSegment,
                            NULL);
        if (!NT_SUCCESS(status)) {
            TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL,
                "User's input buffer is too small for this IOCTL, expecting an UCHAR\n");
            bytesReturned = sizeof(UCHAR);
            break;
        }

        //
        // Call our routine to set the 7 segment state
        //
        status = SetSevenSegmentState(pDevContext, sevenSegment);

        //
        // There's no data returned for this call
        //
        bytesReturned = 0;
        break;

    case IOCTL_OSRUSBFX2_READ_SWITCHES:

        status = WdfRequestRetrieveOutputBuffer(Request,
                            sizeof(SWITCH_STATE),
                            &switchState,
                            NULL);// BufferLength

        if (!NT_SUCCESS(status)) {
            TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL,
                "User's output buffer is too small for this IOCTL, expecting a SWITCH_STATE\n");
            bytesReturned = sizeof(SWITCH_STATE);
            break;

        }

        //
        // Call our routine to get the state of the switches
        //
        status = GetSwitchState(pDevContext, switchState);

        //
        // If successful, return the user their data
        //
        if (NT_SUCCESS(status)) {

            bytesReturned = sizeof(SWITCH_STATE);

        } else {
            //
            // Don't return any data
            //
            bytesReturned = 0;
        }
        break;

    case IOCTL_OSRUSBFX2_GET_INTERRUPT_MESSAGE:

        //
        // Forward the request to an interrupt message queue and dont complete
        // the request until an interrupt from the USB device occurs.
        //
        status = WdfRequestForwardToIoQueue(Request, pDevContext->InterruptMsgQueue);
        if (NT_SUCCESS(status)) {
            requestPending = TRUE;
        }

        break;

    default :
        status = STATUS_INVALID_DEVICE_REQUEST;
        break;
    }

    if (requestPending == FALSE) {
        WdfRequestCompleteWithInformation(Request, status, bytesReturned);
    }

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "<-- OsrFxEvtIoDeviceControl\n");

    return;
}
NTSTATUS
BthEchoCliRetrieveServerBthAddress(
    _In_ PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx
    )
/*++

Description:

    Retrieve server Bth address

Arguments:

    DevCtx - Client context where we store bth address

Return Value:

    NTSTATUS Status code.

--*/
{
    NTSTATUS status, statusReuse;
    WDF_MEMORY_DESCRIPTOR outMemDesc;
    WDF_REQUEST_REUSE_PARAMS ReuseParams;
    BTH_DEVICE_INFO serverDeviceInfo;
    
    WDF_REQUEST_REUSE_PARAMS_INIT(&ReuseParams, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_NOT_SUPPORTED);
    statusReuse = WdfRequestReuse(DevCtx->Header.Request, &ReuseParams);    
    NT_ASSERT(NT_SUCCESS(statusReuse));
    UNREFERENCED_PARAMETER(statusReuse);

    RtlZeroMemory( &serverDeviceInfo, sizeof(serverDeviceInfo) );
    
    WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(
        &outMemDesc,
        &serverDeviceInfo,
        sizeof(serverDeviceInfo)
        );

    status = WdfIoTargetSendInternalIoctlSynchronously(
        DevCtx->Header.IoTarget,
        DevCtx->Header.Request,
        IOCTL_INTERNAL_BTHENUM_GET_DEVINFO,
        NULL,   //inMemDesc
        &outMemDesc,
        NULL,   //sendOptions
        NULL    //bytesReturned
        );

    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, 
            "Failed to obtain server device info, Status code %!STATUS!\n", status);

        goto exit;
    }

    DevCtx->ServerBthAddress = serverDeviceInfo.address;

exit:
    return status;
}
Beispiel #7
0
NTSTATUS
OsrFxEvtDevicePrepareHardware(
    IN WDFDEVICE    Device,
    IN WDFCMRESLIST ResourceList,
    IN WDFCMRESLIST ResourceListTranslated
    )
/*++

Routine Description:

    In this callback, the driver does whatever is necessary to make the
    hardware ready to use.  In the case of a USB device, this involves
    reading descriptors and selecting interfaces.

Arguments:

    Device - handle to a device

Return Value:

    NT status value

--*/
{
    NTSTATUS                            status, tempStatus;
    PDEVICE_CONTEXT                     pDeviceContext;
    WDF_USB_DEVICE_SELECT_CONFIG_PARAMS configParams;

    UNREFERENCED_PARAMETER(ResourceList);
    UNREFERENCED_PARAMETER(ResourceListTranslated);

    PAGED_CODE();

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> EvtDevicePrepareHardware\n");

    pDeviceContext = GetDeviceContext(Device);

    //
    // Create a USB device handle so that we can communicate with the
    // underlying USB stack. The WDFUSBDEVICE handle is used to query,
    // configure, and manage all aspects of the USB device.
    // These aspects include device properties, bus properties,
    // and I/O creation and synchronization. We only create device the first
    // the PrepareHardware is called. If the device is restarted by pnp manager
    // for resource rebalance, we will use the same device handle but then select
    // the interfaces again because the USB stack could reconfigure the device on
    // restart.
    //
    if (pDeviceContext->UsbDevice == NULL) {
        status = WdfUsbTargetDeviceCreate(Device,
                                    WDF_NO_OBJECT_ATTRIBUTES,
                                    &pDeviceContext->UsbDevice);
        if (!NT_SUCCESS(status)) {
            TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
                 "WdfUsbTargetDeviceCreate failed with Status code %!STATUS!\n", status);
            return status;
        }
    }


    WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE( &configParams);

    status = WdfUsbTargetDeviceSelectConfig(pDeviceContext->UsbDevice,
                                        WDF_NO_OBJECT_ATTRIBUTES,
                                        &configParams);
    if(!NT_SUCCESS(status)) {
        WDF_USB_DEVICE_INFORMATION  deviceInfo;

        TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
                        "WdfUsbTargetDeviceSelectConfig failed %!STATUS! \n",
                        status);
        //
        // detect if we are connected to a 1.1 USB port 
        //
        WDF_USB_DEVICE_INFORMATION_INIT(&deviceInfo);
        tempStatus = WdfUsbTargetDeviceRetrieveInformation(pDeviceContext->UsbDevice, &deviceInfo);

        if (NT_SUCCESS(tempStatus)) {
            //
            // Since the Osr USB fx2 device is capable of working at high speed, the only reason 
            // the device would not be working at high speed is if the port doesn't 
            // support it. If the port doesn't support high speed it is a 1.1 port
            //
            if ((deviceInfo.Traits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED) == 0) {
                TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
                                " On a 1.1 USB port on Windows Vista" 
                                " this is expected as the OSR USB Fx2 board's Interrupt EndPoint descriptor" 
                                " doesn't conform to the USB specification. Windows Vista detects this and"
                                " returns an error. \n"
                                );
            }
        }

        return status;
    }

    pDeviceContext->UsbInterface =
                configParams.Types.SingleInterface.ConfiguredUsbInterface;

    status = OsrFxConfigContReaderForInterruptEndPoint(pDeviceContext);

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- EvtDevicePrepareHardware\n");

    return status;
}
Beispiel #8
0
CMyReadWriteQueue::OnRead(
    __in IWDFIoQueue *pWdfQueue,
    __in IWDFIoRequest *pWdfRequest,
    __in SIZE_T BytesToRead
    )
/*++

Routine Description:


    Read dispatch routine
    IQueueCallbackRead

Aruments:

    pWdfQueue - Framework Queue instance
    pWdfRequest - Framework Request  instance
    BytesToRead - Lenth of bytes in the read buffer

    Copy available data into the read buffer
Return Value:

    VOID

--*/
{
    UNREFERENCED_PARAMETER(pWdfQueue);

    TraceEvents(TRACE_LEVEL_INFORMATION,
                TEST_TRACE_QUEUE,
                "%!FUNC!: Queue %p Request %p BytesToTransfer %d\n",
                this,
                pWdfRequest,
                (ULONG)(ULONG_PTR)BytesToRead
                );

    HRESULT hr = S_OK;
    IWDFMemory * pOutputMemory = NULL;

    pWdfRequest->GetOutputMemory(&pOutputMemory);

    hr = m_Device->GetInputPipe()->FormatRequestForRead(
                                pWdfRequest,
                                NULL, //pFile
                                pOutputMemory,
                                NULL, //Memory offset
                                NULL  //DeviceOffset
                                );

    if (FAILED(hr))
    {
        pWdfRequest->Complete(hr);
    }
    else
    {
        ForwardFormattedRequest(pWdfRequest, m_Device->GetInputPipe());
    }

    SAFE_RELEASE(pOutputMemory);

    return;
}
Beispiel #9
0
HRESULT
CMyDevice::SetPowerManagement(
    VOID
    )
/*++

  Routine Description:

    This method enables the idle and wake functionality
    using UMDF. UMDF has been set as the power policy
    owner (PPO) for the device stack and we are using power
    managed queues.

  Arguments:

    None

  Return Value:
    
    Status

--*/
{ 
    HRESULT hr;

    //
    // Enable USB selective suspend on the device.    
    // 
    
    hr = m_FxDevice->AssignS0IdleSettings( IdleUsbSelectiveSuspend,
                                PowerDeviceMaximum,
                                IDLE_TIMEOUT_IN_MSEC,
                                IdleAllowUserControl,
                                WdfUseDefault);                                                                                                   

    if (FAILED(hr))
    {
        TraceEvents(TRACE_LEVEL_ERROR, 
                    TEST_TRACE_DEVICE, 
                    "%!FUNC! Unable to assign S0 idle settings for the device %!HRESULT!",
                    hr
                    );
    }

    //
    // Enable Sx wake settings
    //

    if (SUCCEEDED(hr))
    {
        hr = m_FxDevice->AssignSxWakeSettings( PowerDeviceMaximum,
                                    WakeAllowUserControl,
                                    WdfUseDefault);
                                    
        if (FAILED(hr))
        {
            TraceEvents(TRACE_LEVEL_ERROR, 
                        TEST_TRACE_DEVICE, 
                        "%!FUNC! Unable to set Sx Wake Settings for the device %!HRESULT!",
                        hr
                        );
        }
        
    }


    return hr;
}
NTSTATUS
DriverEntry(
    IN PDRIVER_OBJECT  DriverObject,
    IN PUNICODE_STRING RegistryPath
    )
/*++

Routine Description:

    Driver initialization entry point.
    This entry point is called directly by the I/O system.

Arguments:

    DriverObject - pointer to the driver object

    RegistryPath - pointer to a unicode string representing the path,
                   to driver-specific key in the registry.

Return Value:

    NTSTATUS    - if the status value is not STATUS_SUCCESS,
                        the driver will get unloaded immediately.

--*/
{
    NTSTATUS            status = STATUS_SUCCESS;
    WDF_DRIVER_CONFIG   config;
    WDF_OBJECT_ATTRIBUTES attributes;

    //
    // Initialize WDF WPP tracing.
    //
    WPP_INIT_TRACING( DriverObject, RegistryPath );

    //
    // TraceEvents function is mapped to DoTraceMessage provided by
    // WPP by using a directive in the sources file.
    //
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT,
                "Pci9656 Sample - Driver Framework Edition.");

    //
    // Initialize the Driver Config structure.
    //
    WDF_DRIVER_CONFIG_INIT( &config, PLxEvtDeviceAdd );

    //
    // Register a cleanup callback so that we can call WPP_CLEANUP when
    // the framework driver object is deleted during driver unload.
    //
    WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
    attributes.EvtCleanupCallback = PlxEvtDriverContextCleanup;

    status = WdfDriverCreate( DriverObject,
                              RegistryPath,
                              &attributes,
                              &config,
                              WDF_NO_HANDLE);

    if (!NT_SUCCESS(status)) {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
                    "WdfDriverCreate failed with status %!STATUS!", status);
        //
        // Cleanup tracing here because DriverContextCleanup will not be called
        // as we have failed to create WDFDRIVER object itself.
        // Please note that if your return failure from DriverEntry after the
        // WDFDRIVER object is created successfully, you don't have to
        // call WPP cleanup because in those cases DriverContextCleanup
        // will be executed when the framework deletes the DriverObject.
        //
        WPP_CLEANUP(DriverObject);
    }

    return status;
}
Beispiel #11
0
CMyReadWriteQueue::OnWrite(
    __in IWDFIoQueue *pWdfQueue,
    __in IWDFIoRequest *pWdfRequest,
    __in SIZE_T BytesToWrite
     )
/*++

Routine Description:


    Write dispatch routine
    IQueueCallbackWrite

Aruments:

    pWdfQueue - Framework Queue instance
    pWdfRequest - Framework Request  instance
    BytesToWrite - Lenth of bytes in the write buffer

    Allocate and copy data to local buffer
Return Value:

    VOID

--*/
{
    UNREFERENCED_PARAMETER(pWdfQueue);

    TraceEvents(TRACE_LEVEL_INFORMATION,
                TEST_TRACE_QUEUE,
                "%!FUNC!: Queue %p Request %p BytesToTransfer %d\n",
                this,
                pWdfRequest,
                (ULONG)(ULONG_PTR)BytesToWrite
                );

    HRESULT hr = S_OK;
    IWDFMemory * pInputMemory = NULL;
    IWDFUsbTargetPipe * pOutputPipe = m_Device->GetOutputPipe();

    pWdfRequest->GetInputMemory(&pInputMemory);

    hr = pOutputPipe->FormatRequestForWrite(
                                pWdfRequest,
                                NULL, //pFile
                                pInputMemory,
                                NULL, //Memory offset
                                NULL  //DeviceOffset
                                );

    if (FAILED(hr))
    {
        pWdfRequest->Complete(hr);
    }
    else
    {
        ForwardFormattedRequest(pWdfRequest, pOutputPipe);
    }

    SAFE_RELEASE(pInputMemory);

    return;
}
NTSTATUS
PLxEvtDeviceAdd(
    IN WDFDRIVER        Driver,
    IN PWDFDEVICE_INIT  DeviceInit
    )
/*++

Routine Description:

    EvtDeviceAdd is called by the framework in response to AddDevice
    call from the PnP manager. Here the driver should register all the
    PNP, power and Io callbacks, register interfaces and allocate other
    software resources required by the device. The driver can query
    any interfaces or get the config space information from the bus driver
    but cannot access hardware registers or initialize the device.

Arguments:

Return Value:

--*/
{
    NTSTATUS                   status = STATUS_SUCCESS;
    WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;
    WDF_OBJECT_ATTRIBUTES       attributes;
    WDFDEVICE                   device;
    PDEVICE_EXTENSION           devExt = NULL;

    UNREFERENCED_PARAMETER( Driver );

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,  "--> PLxEvtDeviceAdd");

    PAGED_CODE();

    WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect);

    //
    // Zero out the PnpPowerCallbacks structure.
    //
    WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);

    //
    // Set Callbacks for any of the functions we are interested in.
    // If no callback is set, Framework will take the default action
    // by itself.
    //
    pnpPowerCallbacks.EvtDevicePrepareHardware = PLxEvtDevicePrepareHardware;
    pnpPowerCallbacks.EvtDeviceReleaseHardware = PLxEvtDeviceReleaseHardware;

    //
    // These two callbacks set up and tear down hardware state that must be
    // done every time the device moves in and out of the D0-working state.
    //
    pnpPowerCallbacks.EvtDeviceD0Entry         = PLxEvtDeviceD0Entry;
    pnpPowerCallbacks.EvtDeviceD0Exit          = PLxEvtDeviceD0Exit;

    //
    // Register the PnP Callbacks..
    //
    WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);

    //
    // Initialize Fdo Attributes.
    //
    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_EXTENSION);
    //
    // By opting for SynchronizationScopeDevice, we tell the framework to
    // synchronize callbacks events of all the objects directly associated
    // with the device. In this driver, we will associate queues and
    // and DpcForIsr. By doing that we don't have to worrry about synchronizing
    // access to device-context by Io Events and DpcForIsr because they would
    // not concurrently ever. Framework will serialize them by using an
    // internal device-lock.
    //
    attributes.SynchronizationScope = WdfSynchronizationScopeDevice;

    //
    // Create the device
    //
    status = WdfDeviceCreate( &DeviceInit, &attributes, &device );

    if (!NT_SUCCESS(status)) {
        //
        // Device Initialization failed.
        //
        TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
                    "DeviceCreate failed %!STATUS!", status);
        return status;
    }

    //
    // Get the DeviceExtension and initialize it. PLxGetDeviceContext is an inline function
    // defined by WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro in the
    // private header file. This function will do the type checking and return
    // the device context. If you pass a wrong object a wrong object handle
    // it will return NULL and assert if run under framework verifier mode.
    //
    devExt = PLxGetDeviceContext(device);

    devExt->Device = device;

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
                "     AddDevice PDO (0x%p) FDO (0x%p), DevExt (0x%p)",
                WdfDeviceWdmGetPhysicalDevice(device),
                WdfDeviceWdmGetDeviceObject(device), devExt);

    //
    // Tell the Framework that this device will need an interface
    //
    // NOTE: See the note in Public.h concerning this GUID value.
    //
    status = WdfDeviceCreateDeviceInterface( device,
                                             (LPGUID) &GUID_PLX_INTERFACE,
                                             NULL );

    if (!NT_SUCCESS(status)) {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
                    "<-- DeviceCreateDeviceInterface "
                    "failed %!STATUS!", status);
        return status;
    }

    //
    // Set the idle and wait-wake policy for this device.
    //
    status = PLxSetIdleAndWakeSettings(devExt);

    if (!NT_SUCCESS (status)) {
        //
        // NOTE: The attempt to set the Idle and Wake options
        //       is a best-effort try. Failure is probably due to
        //       the non-driver environmentals, such as the system,
        //       bus or OS indicating that Wake is not supported for
        //       this case.
        //       All that being said, it probably not desirable to
        //       return the failure code as it would cause the
        //       AddDevice to fail and Idle and Wake are probably not
        //       "must-have" options.
        //
        //       You must decide for your case whether Idle/Wake are
        //       "must-have" options...but my guess is probably not.
        //
#if 1
        status = STATUS_SUCCESS;
#else
        return status;
#endif
    }

    //
    // Initalize the Device Extension.
    //
    status = PLxInitializeDeviceExtension(devExt);

    if (!NT_SUCCESS(status)) {
        return status;
    }

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,
                "<-- PLxEvtDeviceAdd %!STATUS!", status);

    return status;
}
VOID
HealthThermometerServiceContent::TemperatureMeasurementEvent(
    _In_ BTH_LE_GATT_EVENT_TYPE EventType,
    _In_ PVOID EventOutParameter
    )
{
    HRESULT hr = S_OK;
    PBLUETOOTH_GATT_VALUE_CHANGED_EVENT ValueChangedEventParameters = NULL;
    TEMPERATURE_MEASUREMENT  Measurement = {0};
    IPortableDeviceValues * pEventParams = NULL;
    BYTE* pBuffer = NULL;
    DWORD cbBuffer = 0;       

    if (CharacteristicValueChangedEvent != EventType) {
        return;
    }

    ValueChangedEventParameters = (PBLUETOOTH_GATT_VALUE_CHANGED_EVENT)EventOutParameter;    


    //
    // Our value is at least 5 bytes
    //
    if (5 > ValueChangedEventParameters->CharacteristicValue->DataSize) {
        hr = E_FAIL;
        CHECK_HR(hr, "Invalid data size: %d, expencting at least 5 bytes",
            ValueChangedEventParameters->CharacteristicValue->DataSize);
    }

    if (SUCCEEDED(hr))
    {
        ULONG mantissa = 0;
        LONG exponent = 0;
        
        mantissa = (ULONG)(((ULONG)ValueChangedEventParameters->CharacteristicValue->Data[3] << (ULONG)16)
                | ((ULONG)ValueChangedEventParameters->CharacteristicValue->Data[2] << (ULONG)8)
                | ((ULONG)ValueChangedEventParameters->CharacteristicValue->Data[1] << (ULONG)0));
        exponent = 0xFFFFFF00 | (LONG)ValueChangedEventParameters->CharacteristicValue->Data[4];

        Measurement.Value = (double)mantissa * pow((double)10.0, (double)exponent);
        TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_FLAG_DEVICE, "Received a value change event, new value [%.2f]", Measurement.Value);
    }
    
    //
    // Get the timestamp
    //
    if (SUCCEEDED(hr))
    {
        FILETIME fTime;

        GetSystemTimeAsFileTime(&fTime);

        ConvertFileTimeToUlonglong(&fTime, &Measurement.TimeStamp);
        
    }

    //
    // CoCreate a collection to store the property set event parameters.
    //
    if (SUCCEEDED(hr))
    {
        hr = CoCreateInstance(CLSID_PortableDeviceValues,
                              NULL,
                              CLSCTX_INPROC_SERVER,
                              IID_IPortableDeviceValues,
                              (VOID**) &pEventParams);
        CHECK_HR(hr, "Failed to CoCreateInstance CLSID_PortableDeviceValues");
    }            

    if (SUCCEEDED(hr))
    {    
        hr = pEventParams->SetGuidValue(WPD_EVENT_PARAMETER_EVENT_ID, EVENT_HealthThermometerService_TemperatureMeasurement);
        CHECK_HR(hr, "Failed to add WPD_EVENT_PARAMETER_EVENT_ID");
    }

    //
    // Set the timestamp
    //
    if (SUCCEEDED(hr))
    {
        hr = pEventParams->SetUnsignedLargeIntegerValue(EVENT_PARAMETER_HealthTemperatureService_Measurement_TimeStamp, Measurement.TimeStamp);
        CHECK_HR(hr, "Failed to add EVENT_PARAMETER_HealthTemperatureService_Measurement_TimeStamp");
    }

    //
    // Set the measurement Value
    //
    if (SUCCEEDED(hr))
    {
        hr = pEventParams->SetFloatValue(EVENT_PARAMETER_HealthTemperatureService_Measurement_Value, (float)Measurement.Value);
        CHECK_HR(hr, "Failed to add EVENT_PARAMETER_HealthTemperatureService_Measurement_Value");
    }
    
    //
    // Adding this event parameter will allow WPD to scope this event to the container functional object    
    //
    if (SUCCEEDED(hr))
    {
        hr = pEventParams->SetStringValue(WPD_EVENT_PARAMETER_OBJECT_PARENT_PERSISTENT_UNIQUE_ID, ParentPersistentUniqueID);
        CHECK_HR(hr, "Failed to add WPD_EVENT_PARAMETER_OBJECT_PARENT_PERSISTENT_UNIQUE_ID");
    }

    //
    // Adding this event parameter will allow WPD to scope this event to the container functional object
    //
    if (SUCCEEDED(hr))
    {
        hr = pEventParams->SetStringValue(WPD_OBJECT_CONTAINER_FUNCTIONAL_OBJECT_ID, SERVICE_OBJECT_ID);
        CHECK_HR(hr, "Failed to add WPD_OBJECT_CONTAINER_FUNCTIONAL_OBJECT_ID");
    }
    
    //
    // Create a buffer with the serialized parameters
    //
    if (SUCCEEDED(hr))
    {
        hr = m_pWpdSerializer->GetBufferFromIPortableDeviceValues(pEventParams, &pBuffer, &cbBuffer);
        CHECK_HR(hr, "Failed to get buffer from IPortableDeviceValues");
    }

    if (SUCCEEDED(hr) && NULL == pBuffer)
    {
        hr = E_FAIL;
        CHECK_HR(hr, "pBuffer is NULL");
    }

    //
    // Send the event
    //
    if (SUCCEEDED(hr))
    {
        hr = m_pDevice->PostEvent(WPD_EVENT_NOTIFICATION, WdfEventBroadcast, pBuffer, cbBuffer);
        CHECK_HR(hr, "Failed to post WPD (broadcast) event");
    }
    
    
    //
    // Cleanup
    //
    if (NULL != pBuffer)
    {
        CoTaskMemFree(pBuffer);
        pBuffer = NULL;
    }

    if (NULL != pEventParams)
    {
        pEventParams->Release();
        pEventParams = NULL;
    }
}
Beispiel #14
0
FORCEINLINE
NTSTATUS
ExecuteOpcode (
    __in PUCHAR SpiBar,
    __in UCHAR OpcodeIndex,
    __in ULONG Offset
    )
{
    NTSTATUS Status;
    ULONG SwSeqRegs;
    LONG Timeout;

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "--> ExecuteOpcode\n");

    Timeout = TIMEOUT;

    TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "SSFS_SSFC: 0x%08x.\n", READ_REGISTER_ULONG((PULONG) (SpiBar + SSFS_SSFC_OFFSET)));

    do {
        SwSeqRegs = READ_REGISTER_ULONG((PULONG) (SpiBar + SSFS_SSFC_OFFSET));
        
        if ((SwSeqRegs & SSFS_SCIP) == 0) {
            break;
        }
        
        KeStallExecutionProcessor(10);
    } while (--Timeout > 0);

    if (Timeout == 0) {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "SCIP was not cleared.\n");
        Status = STATUS_DEVICE_BUSY;
        goto End;
    }

    //
    // Program the offset, even if it is not needed (to simplify logic).
    // SPI addresses are 24 bits long.
    //
    
    WRITE_REGISTER_ULONG((PULONG) (SpiBar + FADDR_OFFSET), (Offset & 0x00FFFFFF));

    //
    // Clear error status registers while preserving reserved bits.
    //

    SwSeqRegs &= SSFS_RESERVED_MASK | SSFC_RESERVED_MASK;
    SwSeqRegs |= SSFS_CDS | SSFS_FCERR;
    WRITE_REGISTER_ULONG((PULONG) (SpiBar + SSFS_SSFC_OFFSET), SwSeqRegs);

    //
    // Set the opcode index, relative to the OPMENU register.
    //

    SwSeqRegs |= ((ULONG) (OpcodeIndex & 0x07)) << (8 + 4);

    //
    // Start.
    //

    SwSeqRegs |= SSFC_SCGO;
    WRITE_REGISTER_ULONG((PULONG) (SpiBar + SSFS_SSFC_OFFSET), SwSeqRegs);

    //
    // Wait for any of the Cycle Done Status and Flash Cycle Error registers.
    //

    Timeout = TIMEOUT;

    TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "SSFS_SSFC: 0x%08x.\n", READ_REGISTER_ULONG((PULONG) (SpiBar + SSFS_SSFC_OFFSET)));
    
    while ((READ_REGISTER_ULONG((PULONG) (SpiBar + SSFS_SSFC_OFFSET)) & (SSFS_CDS | SSFS_FCERR)) == 0
           && --Timeout > 0) {
        KeStallExecutionProcessor(10);
    }

    if (Timeout == 0) {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "Timeout while waiting for a cycle to complete.\n");
        Status = STATUS_TIMEOUT;
        goto End;
    }

    SwSeqRegs = READ_REGISTER_ULONG((PULONG) (SpiBar + SSFS_SSFC_OFFSET));

    if (SwSeqRegs & SSFS_FCERR) {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "Transaction error.\n");
        SwSeqRegs &= SSFS_RESERVED_MASK | SSFC_RESERVED_MASK;
        WRITE_REGISTER_ULONG((PULONG) (SpiBar + SSFS_SSFC_OFFSET), SwSeqRegs | SSFS_FCERR);
        Status = STATUS_DEVICE_DATA_ERROR;
        goto End;
    }

End:
    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "<-- ExecuteOpcode\n");
    return Status;
}
Beispiel #15
0
NTSTATUS
BthEchoCliRetrievePsmFromSdpRecord(
    _In_ PBTHDDI_SDP_PARSE_INTERFACE SdpParseInterface,
    _In_ PBTH_SDP_STREAM_RESPONSE ServerSdpRecord,
    _Out_ USHORT * Psm
    )
/*++

Description:

    Retrieve PSM from the SDP record

Arguments:

    sdpParseInterface - Parse interface used for sdp parse functions
    ServerSdpRecord - SDP record to obtain Psm from
    Psm - Psm retrieved

Return Value:

    NTSTATUS Status code.

--*/
{
    NTSTATUS    status = STATUS_SUCCESS;
    PUCHAR      nextElement;
    ULONG       nextElementSize;

    PSDP_TREE_ROOT_NODE sdpTree = NULL;
    PSDP_NODE           nodeProtoDescList = NULL;
    PSDP_NODE           nodeProto0 = NULL;
    PSDP_NODE           nodeProto0UUID = NULL;
    PSDP_NODE           nodeProto0SParam0 = NULL;

    SdpParseInterface->SdpGetNextElement(
         &(ServerSdpRecord->response[0]),
         ServerSdpRecord->responseSize,
         NULL,
         &nextElement,
         &nextElementSize
         );
    
    if(nextElementSize == 0)
    {
        status = STATUS_DEVICE_DATA_ERROR;
        TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, 
            "Getting first element from SDP record failed, returning status code %!STATUS!\n", status);
        goto exit;
    }

    status = SdpParseInterface->SdpConvertStreamToTree(
        nextElement,
        nextElementSize,
        &sdpTree,
        POOLTAG_BTHECHOSAMPLE
        );
    
    if(!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, 
            "Converting SDP record to tree failed, status code %!STATUS!\n", status);
        goto exit;
    }

    //
    //Find PROTOCOL_DESCRIPTOR_LIST in the tree
    //
    status = SdpParseInterface->SdpFindAttributeInTree(
        sdpTree,
        (USHORT)SDP_ATTRIB_PROTOCOL_DESCRIPTOR_LIST,
        &nodeProtoDescList
        );
    
    if(!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, 
            "FindAttribute failed for SDP_ATTRIB_PROTOCOL_DESCRIPTOR_LIST, status code %!STATUS!\n", status);
        goto exit0;
    }

    if(nodeProtoDescList->hdr.Type != SDP_TYPE_SEQUENCE)
    {
        goto SdpFormatError;
    }

    //
    // Get the next sequence.
    //
    
    if(nodeProtoDescList->u.sequence.Link.Flink == NULL)
    {
        goto SdpFormatError;
    }

    nodeProto0 = CONTAINING_RECORD(nodeProtoDescList->u.sequence.Link.Flink, SDP_NODE, hdr.Link);

    if(nodeProto0->hdr.Type != SDP_TYPE_SEQUENCE)
    {
        goto SdpFormatError;
    }

    if(nodeProto0->u.sequence.Link.Flink == NULL)
    {
        goto SdpFormatError;
    }

    //
    // Get the first GUID, (L2CAP)
    //
    
    nodeProto0UUID = CONTAINING_RECORD(nodeProto0->u.sequence.Link.Flink, SDP_NODE, hdr.Link);

    if(nodeProto0UUID->hdr.Type != SDP_TYPE_UUID)
    {
        goto SdpFormatError;
    }
    
    if(nodeProto0UUID->hdr.Link.Flink == NULL)
    {
        goto SdpFormatError;
    }

    //
    // Get the PSM
    //
    
    nodeProto0SParam0 = CONTAINING_RECORD(nodeProto0UUID->hdr.Link.Flink, SDP_NODE, hdr.Link);
    if(nodeProto0SParam0->hdr.SpecificType != SDP_ST_UINT16)
    {
        goto SdpFormatError;
    }
        
    *Psm = nodeProto0SParam0->u.uint16;

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_SDP, 
        "Psm: %d", *Psm);
    
    goto exit0;

SdpFormatError:

    status = STATUS_DEVICE_DATA_ERROR;

    TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, 
        "Parsing error due to invalid SDP record, returning status code %!STATUS!\n", status);
    
exit0:

    SdpParseInterface->SdpFreeTree(sdpTree);

exit:    
    return status;    
}
Beispiel #16
0
VOID
FireShockEvtIoDeviceControl(
    _In_ WDFQUEUE Queue,
    _In_ WDFREQUEST Request,
    _In_ size_t OutputBufferLength,
    _In_ size_t InputBufferLength,
    _In_ ULONG IoControlCode
)
/*++

Routine Description:

    This event is invoked when the framework receives IRP_MJ_DEVICE_CONTROL request.

Arguments:

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

    Request - Handle to a framework request object.

    OutputBufferLength - Size of the output buffer in bytes

    InputBufferLength - Size of the input buffer in bytes

    IoControlCode - I/O control code.

Return Value:

    VOID

--*/
{
    NTSTATUS                        status = STATUS_SUCCESS;
    size_t                          bufferLength;
    size_t                          transferred = 0;
    PDEVICE_CONTEXT                 pDeviceContext;
    PFIRESHOCK_GET_HOST_BD_ADDR     pGetHostAddr;
    PFIRESHOCK_GET_DEVICE_BD_ADDR   pGetDeviceAddr;
    PFIRESHOCK_SET_HOST_BD_ADDR     pSetHostAddr;
    PFIRESHOCK_GET_DEVICE_TYPE      pGetDeviceType;

    TraceEvents(TRACE_LEVEL_INFORMATION,
        TRACE_QUEUE,
        "%!FUNC! Queue 0x%p, Request 0x%p OutputBufferLength %d InputBufferLength %d IoControlCode %d",
        Queue, Request, (int)OutputBufferLength, (int)InputBufferLength, IoControlCode);

    pDeviceContext = DeviceGetContext(WdfIoQueueGetDevice(Queue));

    switch (IoControlCode)
    {
#pragma region IOCTL_FIRESHOCK_GET_HOST_BD_ADDR

    case IOCTL_FIRESHOCK_GET_HOST_BD_ADDR:

        TraceEvents(TRACE_LEVEL_INFORMATION,
            TRACE_QUEUE, "IOCTL_FIRESHOCK_GET_HOST_BD_ADDR");

        status = WdfRequestRetrieveOutputBuffer(
            Request,
            sizeof(FIRESHOCK_GET_HOST_BD_ADDR),
            (LPVOID)&pGetHostAddr,
            &bufferLength);

        if (NT_SUCCESS(status) && OutputBufferLength == sizeof(FIRESHOCK_GET_HOST_BD_ADDR))
        {
            transferred = OutputBufferLength;
            RtlCopyMemory(&pGetHostAddr->Host, &pDeviceContext->HostAddress, sizeof(BD_ADDR));
        }

        break;

#pragma endregion

#pragma region IOCTL_FIRESHOCK_GET_DEVICE_BD_ADDR

    case IOCTL_FIRESHOCK_GET_DEVICE_BD_ADDR:

        TraceEvents(TRACE_LEVEL_INFORMATION,
            TRACE_QUEUE, "IOCTL_FIRESHOCK_GET_DEVICE_BD_ADDR");

        status = WdfRequestRetrieveOutputBuffer(
            Request,
            sizeof(FIRESHOCK_GET_DEVICE_BD_ADDR),
            (LPVOID)&pGetDeviceAddr,
            &bufferLength);

        if (NT_SUCCESS(status) && OutputBufferLength == sizeof(FIRESHOCK_GET_DEVICE_BD_ADDR))
        {
            transferred = OutputBufferLength;
            RtlCopyMemory(&pGetDeviceAddr->Device, &pDeviceContext->DeviceAddress, sizeof(BD_ADDR));
        }

        break;

#pragma endregion

#pragma region IOCTL_FIRESHOCK_SET_HOST_BD_ADDR

    case IOCTL_FIRESHOCK_SET_HOST_BD_ADDR:

        TraceEvents(TRACE_LEVEL_INFORMATION,
            TRACE_QUEUE, "IOCTL_FIRESHOCK_SET_HOST_BD_ADDR");

        status = WdfRequestRetrieveInputBuffer(
            Request,
            sizeof(FIRESHOCK_SET_HOST_BD_ADDR),
            (LPVOID)&pSetHostAddr,
            &bufferLength);

        if (NT_SUCCESS(status) && InputBufferLength == sizeof(FIRESHOCK_SET_HOST_BD_ADDR))
        {
            UCHAR controlBuffer[SET_HOST_BD_ADDR_CONTROL_BUFFER_LENGTH];
            RtlZeroMemory(controlBuffer, SET_HOST_BD_ADDR_CONTROL_BUFFER_LENGTH);

            RtlCopyMemory(&controlBuffer[2], &pSetHostAddr->Host, sizeof(BD_ADDR));

            status = SendControlRequest(
                pDeviceContext,
                BmRequestHostToDevice,
                BmRequestClass,
                SetReport,
                Ds3FeatureHostAddress,
                0,
                controlBuffer,
                SET_HOST_BD_ADDR_CONTROL_BUFFER_LENGTH);

            if (!NT_SUCCESS(status))
            {
                TraceEvents(TRACE_LEVEL_ERROR, TRACE_QUEUE,
                    "Setting host address failed with %!STATUS!", status);
                break;
            }

            RtlCopyMemory(&pDeviceContext->HostAddress, &pSetHostAddr->Host, sizeof(BD_ADDR));
        }

        break;

#pragma endregion

#pragma region IOCTL_FIRESHOCK_GET_DEVICE_TYPE

    case IOCTL_FIRESHOCK_GET_DEVICE_TYPE:

        TraceEvents(TRACE_LEVEL_INFORMATION,
            TRACE_QUEUE, "IOCTL_FIRESHOCK_GET_DEVICE_TYPE");

        status = WdfRequestRetrieveOutputBuffer(
            Request,
            sizeof(FIRESHOCK_GET_DEVICE_TYPE),
            (LPVOID)&pGetDeviceType,
            &bufferLength);

        if (NT_SUCCESS(status) && OutputBufferLength == sizeof(FIRESHOCK_GET_DEVICE_TYPE))
        {
            transferred = OutputBufferLength;
            pGetDeviceType->DeviceType = pDeviceContext->DeviceType;
        }

        break;

#pragma endregion
    }

    WdfRequestCompleteWithInformation(Request, status, transferred);
}
Beispiel #17
0
_IRQL_requires_same_
NTSTATUS
BthEchoCliOpenRemoteConnection(
    _In_ PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx,
    _In_ WDFFILEOBJECT FileObject,
    _In_ WDFREQUEST Request
    )
/*++

Description:

    This routine is invoked by BthEchoCliEvtDeviceFileCreate.
    In this routine we send down open channel BRB.

    This routine allocates open channel BRB. If the request
    is sent down successfully completion routine needs to free
    this BRB.
    
Arguments:

    _In_ PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx - 
    _In_ WDFFILEOBJECT FileObject - 
    _In_ WDFREQUEST Request - 

Return Value:

    NTSTATUS Status code.

--*/
{
    NTSTATUS status;
    WDFOBJECT connectionObject;    
    struct _BRB_L2CA_OPEN_ENHANCED_CHANNEL *brb = NULL;
    PBTHECHO_CONNECTION connection = NULL;
    PBTHECHOSAMPLE_CLIENT_FILE_CONTEXT fileCtx = GetFileContext(FileObject);
    ULONG modeConfigFlag = CM_BASIC;

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT, 
        "Connect request");        

    //
    // Create the connection object that would store information
    // about the open channel
    //
    // Set file object as the parent for this connection object
    //
    status = BthEchoConnectionObjectCreate(
        &DevCtx->Header,
        FileObject, //parent
        &connectionObject
        );

    if (!NT_SUCCESS(status))
    {
        goto exit;
    }

    connection = GetConnectionObjectContext(connectionObject);

    connection->ConnectionState = ConnectionStateConnecting;

    //
    // Get the BRB from request context and initialize it as
    // BRB_L2CA_OPEN_CHANNEL BRB
    //
    brb = (struct _BRB_L2CA_OPEN_ENHANCED_CHANNEL *)GetRequestContext(Request);

    DevCtx->Header.ProfileDrvInterface.BthReuseBrb(
        (PBRB)brb, 
        BRB_L2CA_OPEN_ENHANCED_CHANNEL
        );
    
    brb->Hdr.ClientContext[0] = connection;
    brb->BtAddress = DevCtx->ServerBthAddress;
    brb->Psm = fileCtx->ServerPsm;

    brb->ChannelFlags = CF_ROLE_EITHER;

    brb->ConfigOut.Flags = CFG_ENHANCED;
    //
    // Open an ERTM channel if the local host supports it
    //
    if (DevCtx->Header.LocalFeatures.Mask & BTH_HOST_FEATURE_ENHANCED_RETRANSMISSION_MODE) {
        modeConfigFlag |= CM_RETRANSMISSION_AND_FLOW;
        brb->ConfigOut.ModeConfig.Flags = modeConfigFlag;

        //
        // Mode is specified using Flags above and this should be 0.
        //
        brb->ConfigOut.ModeConfig.RetransmissionAndFlow.Mode = 0;
        brb->ConfigOut.ModeConfig.RetransmissionAndFlow.MaxTransmit = L2CAP_RAF_DEFAULT_MAXTRANSMIT;
        brb->ConfigOut.ModeConfig.RetransmissionAndFlow.MaxPDUSize = L2CAP_RAF_DEFAULT_MAX_PDU_SIZE;
        brb->ConfigOut.ModeConfig.RetransmissionAndFlow.TxWindowSize = L2CAP_RAF_DEFAULT_TX_WINDOW_SIZE;
    }

    brb->ConfigOut.Flags |= CFG_MTU;
    brb->ConfigOut.Mtu.Max = L2CAP_DEFAULT_MTU;
    brb->ConfigOut.Mtu.Min = L2CAP_MIN_MTU;
    brb->ConfigOut.Mtu.Preferred = L2CAP_DEFAULT_MTU;

    brb->ConfigIn.Flags = CFG_MTU;
    brb->ConfigIn.Mtu.Max = brb->ConfigOut.Mtu.Max;
    brb->ConfigIn.Mtu.Min = brb->ConfigOut.Mtu.Min;
    brb->ConfigIn.Mtu.Preferred = brb->ConfigOut.Mtu.Max;

    //
    // Get notificaiton about remote disconnect 
    //
    brb->CallbackFlags = CALLBACK_DISCONNECT;                                                   

    brb->Callback = &BthEchoCliIndicationCallback;
    brb->CallbackContext = connection;
    brb->ReferenceObject = (PVOID) WdfDeviceWdmGetDeviceObject(DevCtx->Header.Device);
    brb->IncomingQueueDepth = 50;

    status = BthEchoSharedSendBrbAsync(
        DevCtx->Header.IoTarget,
        Request,
        (PBRB) brb,
        sizeof(*brb),
        BthEchoCliRemoteConnectCompletion,
        brb    //Context
        );

    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_CONNECT, 
            "Sending brb for opening connection failed, returning status code %!STATUS!\n", status);

        goto exit;
    }            

exit:

    if(!NT_SUCCESS(status))
    {
        if (connection)
        {
            //
            // Set the right state to facilitate debugging
            //
            connection->ConnectionState = ConnectionStateConnectFailed;            
        }

        //
        // In case of failure of this routine we will fail
        // Create which will delete file object and since connection object
        // is child of the file object, it will be deleted too
        //
    }
    
    return status;
}
NTSTATUS
BalloonEvtDevicePrepareHardware(
    IN WDFDEVICE    Device,
    IN WDFCMRESLIST ResourceList,
    IN WDFCMRESLIST ResourceListTranslated
    )
{
    NTSTATUS            status         = STATUS_SUCCESS;
    BOOLEAN             foundPort      = FALSE;
    PHYSICAL_ADDRESS    PortBasePA     = {0};
    ULONG               PortLength     = 0;
    ULONG               i;
    WDF_INTERRUPT_INFO  interruptInfo;
    PDEVICE_CONTEXT     devCtx = NULL;

    PCM_PARTIAL_RESOURCE_DESCRIPTOR  desc;

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

    UNREFERENCED_PARAMETER(ResourceList);

    PAGED_CODE();

    devCtx = GetDeviceContext(Device);

    for (i=0; i < WdfCmResourceListGetCount(ResourceListTranslated); i++) {

        desc = WdfCmResourceListGetDescriptor( ResourceListTranslated, i );

        if(!desc) {
            TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
                        "WdfResourceCmGetDescriptor failed\n");
            return STATUS_DEVICE_CONFIGURATION_ERROR;
        }

        switch (desc->Type) {

            case CmResourceTypePort:
                if (!foundPort &&
                     desc->u.Port.Length >= 0x20) {

                    devCtx->PortMapped =
                         (desc->Flags & CM_RESOURCE_PORT_IO) ? FALSE : TRUE;

                    PortBasePA = desc->u.Port.Start;
                    PortLength = desc->u.Port.Length;
                    foundPort = TRUE;

                    if (devCtx->PortMapped) {
                         devCtx->PortBase =
                             (PUCHAR) MmMapIoSpace( PortBasePA, PortLength, MmNonCached );

                      if (!devCtx->PortBase) {
                         TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, " Unable to map port range %08I64X, length %d\n",
                                        PortBasePA.QuadPart, PortLength);

                         return STATUS_INSUFFICIENT_RESOURCES;
                      }
                      devCtx->PortCount = PortLength;

                    } else {
                         devCtx->PortBase  = (PUCHAR)(ULONG_PTR) PortBasePA.QuadPart;
                         devCtx->PortCount = PortLength;
                    }
                }

                TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-> Port   Resource [%08I64X-%08I64X]\n",
                            desc->u.Port.Start.QuadPart,
                            desc->u.Port.Start.QuadPart +
                            desc->u.Port.Length);
                break;

            default:
                break;
        }
    }

    if (!foundPort) {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, " Missing resources\n");
        return STATUS_DEVICE_CONFIGURATION_ERROR;
    }

    WDF_INTERRUPT_INFO_INIT(&interruptInfo);
    WdfInterruptGetInfo(devCtx->WdfInterrupt, &interruptInfo);

    VirtIODeviceInitialize(&devCtx->VDevice, (ULONG_PTR)devCtx->PortBase, sizeof(devCtx->VDevice));
    VirtIODeviceSetMSIXUsed(&devCtx->VDevice, interruptInfo.MessageSignaled);

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- %s\n", __FUNCTION__);
    return status;
}
Beispiel #19
0
VOID
BthEchoCliRemoteConnectCompletion(
    _In_ WDFREQUEST  Request,
    _In_ WDFIOTARGET  Target,
    _In_ PWDF_REQUEST_COMPLETION_PARAMS  Params,
    _In_ WDFCONTEXT  Context
    )

/*++
Description:

    Completion routine for Create request which we format as open
    channel BRB and send down the stack. We complete the Create request 
    in this routine.

    We receive open channel BRB as the context. This BRB
    is part of the request context and doesn't need to be freed
    explicitly.

    Connection is part of the context in the BRB.

Arguments:

    Request - Create request that we formatted with open channel BRB
    Target - Target to which we sent the request
    Params - Completion params
    Context - We receive BRB as the context          

Return Value:

    NTSTATUS Status code.
--*/

{
    NTSTATUS status;
    struct _BRB_L2CA_OPEN_CHANNEL *brb;    
    PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx;
    PBTHECHO_CONNECTION connection;
    
    DevCtx = GetClientDeviceContext(WdfIoTargetGetDevice(Target));

    status = Params->IoStatus.Status;

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT, 
        "Connection completion, status: %!STATUS!", status);        

    brb = (struct _BRB_L2CA_OPEN_CHANNEL *) Context;

    connection = (PBTHECHO_CONNECTION) brb->Hdr.ClientContext[0];

    //
    // In the client we don't check for ConnectionStateDisconnecting state 
    // because only file close generates disconnect which
    // cannot happen before create completes. And we complete Create
    // only after we process this completion.
    //

    if(NT_SUCCESS(status))
    {
        connection->OutMTU = brb->OutResults.Params.Mtu;
        connection->InMTU = brb->InResults.Params.Mtu;
        connection->ChannelHandle = brb->ChannelHandle;
        connection->RemoteAddress = brb->BtAddress;

        connection->ConnectionState = ConnectionStateConnected;

        TraceEvents(TRACE_LEVEL_INFORMATION, DBG_CONNECT, 
            "Connection established to server"); 

        //
        // Call the function in device.c (BthEchoCliConnectionStateConnected)
        // for any post processing after connection has been established
        //
        status = BthEchoCliConnectionStateConnected(WdfRequestGetFileObject(Request), connection);
        if (!NT_SUCCESS(status))
        {
            //
            // If such post processing fails we disconnect
            //
            BthEchoConnectionObjectRemoteDisconnect(
                &(DevCtx->Header),
                connection
                );
        }            
    }
    else
    {
        connection->ConnectionState = ConnectionStateConnectFailed;
    }

    //
    // Complete the Create request
    //
    WdfRequestComplete(Request, status);

    return;    
}
NTSTATUS
BalloonDeviceAdd(
    IN WDFDRIVER  Driver,
    IN PWDFDEVICE_INIT  DeviceInit)
{
    NTSTATUS                     status = STATUS_SUCCESS;
    WDFDEVICE                    device;
    PDEVICE_CONTEXT              devCtx = NULL;
    WDF_INTERRUPT_CONFIG         interruptConfig;
    WDF_FILEOBJECT_CONFIG        fileConfig;
    WDF_OBJECT_ATTRIBUTES        attributes;
    WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;

    UNREFERENCED_PARAMETER(Driver);
    PAGED_CODE();

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

    WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);

    pnpPowerCallbacks.EvtDevicePrepareHardware      = BalloonEvtDevicePrepareHardware;
    pnpPowerCallbacks.EvtDeviceReleaseHardware      = BalloonEvtDeviceReleaseHardware;
    pnpPowerCallbacks.EvtDeviceD0Entry              = BalloonEvtDeviceD0Entry;
    pnpPowerCallbacks.EvtDeviceD0Exit               = BalloonEvtDeviceD0Exit;
    pnpPowerCallbacks.EvtDeviceD0ExitPreInterruptsDisabled = BalloonEvtDeviceD0ExitPreInterruptsDisabled;

    WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);

    WDF_FILEOBJECT_CONFIG_INIT(
                            &fileConfig,
                            WDF_NO_EVENT_CALLBACK,
                            BalloonEvtFileClose,
                            WDF_NO_EVENT_CALLBACK
                            );

    WdfDeviceInitSetFileObjectConfig(DeviceInit,
                            &fileConfig,
                            WDF_NO_OBJECT_ATTRIBUTES);

    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_CONTEXT);
    attributes.EvtCleanupCallback = BalloonEvtDeviceContextCleanup;
    status = WdfDeviceCreate(&DeviceInit, &attributes, &device);
    if(!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
           "WdfDeviceCreate failed with status 0x%08x\n", status);
        return status;
    }

    devCtx = GetDeviceContext(device);

    WDF_INTERRUPT_CONFIG_INIT(&interruptConfig,
                            BalloonInterruptIsr,
                            BalloonInterruptDpc);

    interruptConfig.EvtInterruptEnable  = BalloonInterruptEnable;
    interruptConfig.EvtInterruptDisable = BalloonInterruptDisable;

    status = WdfInterruptCreate(device,
                            &interruptConfig,
                            WDF_NO_OBJECT_ATTRIBUTES,
                            &devCtx->WdfInterrupt);
    if (!NT_SUCCESS (status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
           "WdfInterruptCreate failed: 0x%08x\n", status);
        return status;
    }

    status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_BALLOON, NULL);
    if(!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
           "WdfDeviceCreateDeviceInterface failed with status 0x%08x\n", status);
        return status;
    }
    devCtx->bShutDown = FALSE;
    devCtx->num_pages = 0;
    devCtx->PageListHead.Next = NULL;
    ExInitializeNPagedLookasideList(
                      &devCtx->LookAsideList,
                      NULL,
                      NULL,
                      0,
                      sizeof(PAGE_LIST_ENTRY),
                      BALLOON_MGMT_POOL_TAG,
                      0
                      );
    devCtx->bListInitialized = TRUE;
    devCtx->pfns_table = (PPFN_NUMBER)
              ExAllocatePoolWithTag(
                      NonPagedPool,
                      PAGE_SIZE,
                      BALLOON_MGMT_POOL_TAG
                      );

    if(devCtx->pfns_table == NULL)
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,"ExAllocatePoolWithTag failed\n");
        status = STATUS_INSUFFICIENT_RESOURCES;
        return status;
    }

    devCtx->MemStats = (PBALLOON_STAT)
              ExAllocatePoolWithTag(
                      NonPagedPool,
                      sizeof (BALLOON_STAT) * VIRTIO_BALLOON_S_NR,
                      BALLOON_MGMT_POOL_TAG
                      );

    if(devCtx->MemStats == NULL)
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,"ExAllocatePoolWithTag failed\n");
        status = STATUS_INSUFFICIENT_RESOURCES;
        return status;
    }

    RtlFillMemory (devCtx->MemStats, sizeof (BALLOON_STAT) * VIRTIO_BALLOON_S_NR, -1);

    KeInitializeEvent(&devCtx->HostAckEvent,
                      SynchronizationEvent,
                      FALSE
                      );

    status = BalloonQueueInitialize(device);
    if(!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
           "BalloonQueueInitialize failed with status 0x%08x\n", status);
        return status;
    }

    KeInitializeEvent(&devCtx->WakeUpThread,
                      SynchronizationEvent,
                      FALSE
                      );

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- %s\n", __FUNCTION__);
    return status;
}
Beispiel #21
0
NTSTATUS
OsrFxEvtDeviceAdd(
    IN WDFDRIVER        Driver,
    IN PWDFDEVICE_INIT  DeviceInit
    )
/*++
Routine Description:

    EvtDeviceAdd is called by the framework in response to AddDevice
    call from the PnP manager. We create and initialize a device object to
    represent a new instance of the device. All the software resources
    should be allocated in this callback.

Arguments:

    Driver - Handle to a framework driver object created in DriverEntry

    DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.

Return Value:

    NTSTATUS

--*/
{
    WDF_PNPPOWER_EVENT_CALLBACKS        pnpPowerCallbacks;
    WDF_OBJECT_ATTRIBUTES               attributes;
    NTSTATUS                            status;
    WDFDEVICE                           device;

    UNREFERENCED_PARAMETER(Driver);

    PAGED_CODE();

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,"--> OsrFxEvtDeviceAdd routine\n");

    //
    // Initialize the pnpPowerCallbacks structure.  Callback events for PNP
    // and Power are specified here.  If you don't supply any callbacks,
    // the Framework will take appropriate default actions based on whether
    // DeviceInit is initialized to be an FDO, a PDO or a filter device
    // object.
    //

    WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);
    //
    // For usb devices, PrepareHardware callback is the to place select the
    // interface and configure the device.
    //
    pnpPowerCallbacks.EvtDevicePrepareHardware = OsrFxEvtDevicePrepareHardware;

    //
    // These two callbacks start and stop the WDFUSBPIPE continuous reader
    // as we go in and out of the D0-working state.
    //

    pnpPowerCallbacks.EvtDeviceD0Entry = OsrFxEvtDeviceD0Entry;
    pnpPowerCallbacks.EvtDeviceD0Exit  = OsrFxEvtDeviceD0Exit;

    WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);

    OsrFxInitChildList(DeviceInit);

    //
    // Now specify the size of device extension where we track per device
    // context.DeviceInit is completely initialized. So call the framework
    // to create the device and attach it to the lower stack.
    //
    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_CONTEXT);

    status = WdfDeviceCreate(&DeviceInit, &attributes, &device);
    if (!NT_SUCCESS(status)) {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
            "WdfDeviceCreate failed with Status code %!STATUS!\n", status);
        return status;
    }

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "OsrFxEvtDeviceAdd  - ends\n");

    return status;
}
Beispiel #22
0
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
VOID
HSACEvtIoDeviceControl(
    __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 output buffer,
                        if an output buffer is available.
    InputBufferLength - length of the request 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

--*/
{
    PDEVICE_EXTENSION		devExt;
    size_t                  length = 0;
    NTSTATUS                status = STATUS_SUCCESS;
    PVOID                   pInputBuffer = NULL;
	PVOID					pOutputBuffer = NULL;

	ULONG a1 = 0,a2 = 0;
	ULONG readIndex = 0, readNum = 0;

    UNREFERENCED_PARAMETER( InputBufferLength  );
    UNREFERENCED_PARAMETER( OutputBufferLength  );

    //
    // Get the device extension.
    //
    devExt = HSACGetDeviceContext(WdfIoQueueGetDevice( Queue ));
#if (DBG != 0)
	TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,
		"HSACEvtIoDeviceControl InputBufferLength: 0x%x, OutputBufferLength: 0x%x\n", 
		InputBufferLength, OutputBufferLength);
#endif
    //
    // Handle this request specific code.
    //
    switch (IoControlCode) {
	case IOCTL_GET_REGISTER:
		{
#if (DBG != 0)
			TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,
				"IOCTL_GET_REGISTER-->require length: 0x%x\n", sizeof(ULONG));
#endif

			status = WdfRequestRetrieveInputBuffer(Request, 0, &pInputBuffer, &length);
			if( !NT_SUCCESS(status)) {
#if (DBG != 0)
				TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
					"WdfRequestRetrieveInputBuffer failed 0x%x\n", status);
#endif
				break;
			}

			status = WdfRequestRetrieveOutputBuffer(Request, 0, &pOutputBuffer, &length);
			if( !NT_SUCCESS(status)) {
#if (DBG != 0)
				TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
					"WdfRequestRetrieveOutputBuffer failed 0x%x\n", status);
#endif
				break;
			}

			readIndex = *(PULONG)pInputBuffer;
			readNum = *((PULONG)pInputBuffer + 1);
#if (DBG != 0)
			TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
				"readIndex: %d, readNum: %d\n", readIndex, readNum);
#endif
			if (readNum == 0)
			{
				length = 0;
				break;
			}
			//if (readNum > 1)
			//{
				if (readIndex + readNum > (sizeof(HSAC_REGS)/sizeof(unsigned int) ))
				{
					readNum = (sizeof(HSAC_REGS)/sizeof(unsigned int) ) - readIndex;
				}
				WdfInterruptAcquireLock( devExt->Interrupt );
				READ_REGISTER_BUFFER_ULONG(((PULONG) devExt->Regs) + readIndex, (PULONG)pOutputBuffer, readNum);
				WdfInterruptReleaseLock( devExt->Interrupt );
			//}
			//else
			//{
			//	*(PULONG)pOutputBuffer = READ_REGISTER_ULONG( ((PULONG) devExt->Regs) + readIndex );
			//}
			
			length = readNum;
			break;
		}
	case IOCTL_GET_SINGLE_REGISTER:
		{
#if (DBG != 0)
			TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,
				"IOCTL_GET_REGISTER-->require length: 0x%x\n", sizeof(ULONG));
#endif

			status = WdfRequestRetrieveInputBuffer(Request, 0, &pInputBuffer, &length);
			if( !NT_SUCCESS(status)) {
#if (DBG != 0)
				TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
					"WdfRequestRetrieveInputBuffer failed 0x%x\n", status);
#endif
				break;
			}

			status = WdfRequestRetrieveOutputBuffer(Request, 0, &pOutputBuffer, &length);
			if( !NT_SUCCESS(status)) {
#if (DBG != 0)
				TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
					"WdfRequestRetrieveOutputBuffer failed 0x%x\n", status);
#endif
				break;
			}

			readIndex = *(PULONG)pInputBuffer;
#if (DBG != 0)
			TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
				"readIndex: %d\n", readIndex);
#endif
			WdfInterruptAcquireLock( devExt->Interrupt );
			*(PULONG)pOutputBuffer = READ_REGISTER_ULONG( ((PULONG) devExt->Regs) + readIndex );
			WdfInterruptReleaseLock( devExt->Interrupt );

			length = sizeof(ULONG);
			break;
		}
	case IOCTL_SET_REGISTER:
		{
			status = WdfRequestRetrieveInputBuffer(Request, 0, &pInputBuffer, &length);
			if( !NT_SUCCESS(status)) {
#if (DBG != 0)
				TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
					"WdfRequestRetrieveInputBuffer failed 0x%x\n", status);
#endif
				break;
			}
			WdfInterruptAcquireLock( devExt->Interrupt );
			WRITE_REGISTER_ULONG( ((PULONG) devExt->Regs) + (*(PULONG)pInputBuffer), *((PULONG)pInputBuffer + 1) );
			WdfInterruptReleaseLock( devExt->Interrupt );

//			//a1 = *(PULONG)pInputBuffer;
//			//a2 = *((PULONG)pInputBuffer + 1);
//
//#if (DBG != 0)
//			TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,
//				"IOCTL_SET_REGISTER-->offset:0x%x, value:0x%x\n", a1, a2);
//#endif
//
//			//a2 = READ_REGISTER_ULONG( ((PULONG) devExt->Regs) + (*(PULONG)pInputBuffer) );
//
//#if (DBG != 0)
//			TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,
//				"IOCTL_SET_REGISTER-->offset:0x%x, value:0x%x\n", a1, a2);
//#endif

			length = 0;
			break;
		}
	case IOCTL_GET_SRAM:
		{
#if (DBG != 0)
			TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,
				"IOCTL_GET_SRAM-->require length: 0x%x\n", sizeof(ULONG));
#endif

			status = WdfRequestRetrieveInputBuffer(Request, 0, &pInputBuffer, &length);
			if( !NT_SUCCESS(status)) {
#if (DBG != 0)
				TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
					"WdfRequestRetrieveInputBuffer failed 0x%x\n", status);
#endif
				break;
			}

			status = WdfRequestRetrieveOutputBuffer(Request, 0, &pOutputBuffer, &length);
			if( !NT_SUCCESS(status)) {
#if (DBG != 0)
				TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
					"WdfRequestRetrieveOutputBuffer failed 0x%x\n", status);
#endif
				break;
			}

			readIndex = *(PULONG)pInputBuffer;
			readNum = *((PULONG)pInputBuffer + 1);

			if (readNum == 0)
			{
				length = 0;
				break;
			}
			//if (readNum > 1)
			//{
			if (readIndex + readNum > (devExt->SRAMLength/sizeof(ULONG) ))
			{
				readNum = (devExt->SRAMLength/sizeof(ULONG) ) - readIndex;
			}

#if (DBG != 0)
			TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
				"readIndex: %d, readNum: %d\n", readIndex, readNum);
#endif

			WdfInterruptAcquireLock( devExt->Interrupt );
			READ_REGISTER_BUFFER_ULONG(((PULONG) devExt->SRAMBase) + readIndex, (PULONG)pOutputBuffer, readNum);
			WdfInterruptReleaseLock( devExt->Interrupt );
			//}
			//else
			//{
			//	*(PULONG)pOutputBuffer = READ_REGISTER_ULONG( ((PULONG) devExt->Regs) + readIndex );
			//}

			length = readNum;
			break;
		}
	case IOCTL_SET_SRAM:
		{
			status = WdfRequestRetrieveInputBuffer(Request, 0, &pInputBuffer, &length);
			if( !NT_SUCCESS(status)) {
#if (DBG != 0)
				TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
					"WdfRequestRetrieveInputBuffer failed 0x%x\n", status);
#endif
				break;
			}

			readIndex = *(PULONG)pInputBuffer;
			readNum = *((PULONG)pInputBuffer + 1);

			if (readNum == 0)
			{
				length = 0;
				break;
			}
			//if (readNum > 1)
			//{
			if (readIndex + readNum > (devExt->SRAMLength/sizeof(ULONG) ))
			{
				readNum = (devExt->SRAMLength/sizeof(ULONG) ) - readIndex;
			}

#if (DBG != 0)
			TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
				"readIndex: %d, readNum: %d\n", readIndex, readNum);
#endif

			WdfInterruptAcquireLock( devExt->Interrupt );
			WRITE_REGISTER_BUFFER_ULONG( ((PULONG) devExt->SRAMBase) + readIndex, (PULONG)pInputBuffer + 2, readNum);
			WdfInterruptReleaseLock( devExt->Interrupt );
			//			//a1 = *(PULONG)pInputBuffer;
			//			//a2 = *((PULONG)pInputBuffer + 1);
			//
			//#if (DBG != 0)
			//			TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,
			//				"IOCTL_SET_REGISTER-->offset:0x%x, value:0x%x\n", a1, a2);
			//#endif
			//
			//			//a2 = READ_REGISTER_ULONG( ((PULONG) devExt->Regs) + (*(PULONG)pInputBuffer) );
			//
			//#if (DBG != 0)
			//			TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,
			//				"IOCTL_SET_REGISTER-->offset:0x%x, value:0x%x\n", a1, a2);
			//#endif

			length = readNum;
			break;
		}
	case IOCTL_MAP_DMA_BUF_ADDR:
		{
			ULONG_PTR address = 0;

			status = WdfRequestRetrieveInputBuffer(Request, 0, &pInputBuffer, &length);
			if( !NT_SUCCESS(status)) {
#if (DBG != 0)
				TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
					"WdfRequestRetrieveInputBuffer failed 0x%x\n", status);
#endif
				break;
			}
			status = WdfRequestRetrieveOutputBuffer(Request, 0, &pOutputBuffer, &length);
			if( !NT_SUCCESS(status)) {
#if (DBG != 0)
				TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
					"WdfRequestRetrieveOutputBuffer failed 0x%x\n", status);
#endif
				break;
			}

			if (devExt->MapFlag == 1)
			{
				HSACUnmapUserAddress(devExt);
				devExt->MapFlag = 0;
			}
			HSACMapUserAddress( devExt );
			devExt->MapFlag = 1;

#if (CACHE_MODE == MULTI_DISCRETE_CACHE)
			if (*(PULONG)pInputBuffer == 0)
			{
				length = devExt->readCommonBufferNum * sizeof(PVOID);
				RtlCopyMemory(pOutputBuffer, devExt->pReadUserAddress, length);
			} 
			else if (*(PULONG)pInputBuffer == 1)
			{
				length = devExt->writeCommonBufferNum * sizeof(PVOID);
				RtlCopyMemory(pOutputBuffer, devExt->pWriteUserAddress, length);
			}
			else
			{
				status = STATUS_INVALID_DEVICE_REQUEST;
			}
#else
			if (*(PULONG)pInputBuffer == 0)
			{
				address = (ULONG_PTR)devExt->ReadUserAddress0;
			} 
			else if (*(PULONG)pInputBuffer == 1)
			{
				address = (ULONG_PTR)devExt->WriteUserAddress0;
			}
			else
			{
				status = STATUS_INVALID_DEVICE_REQUEST;
			}

#if (DBG != 0)
			TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
				"UserAddress: 0x%I64x", address);
#endif

			RtlCopyMemory(pOutputBuffer, &address, sizeof(PVOID));
#endif
			break;
		}
	case IOCTL_UNMAP_DMA_BUF_ADDR:
		{
			if (devExt->MapFlag == 1)
			{
				HSACUnmapUserAddress(devExt);
				devExt->MapFlag = 0;
			}
			break;
		}
	case IOCTL_SET_DMA_PROFILE:
		{
			status = WdfRequestRetrieveInputBuffer(Request, 0, &pInputBuffer, &length);
			if( !NT_SUCCESS(status)) {
#if (DBG != 0)
				TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
					"WdfRequestRetrieveInputBuffer failed 0x%x\n", status);
#endif
				break;
			}

			devExt->dmaProfile = (WDF_DMA_PROFILE)(*(PULONG)pInputBuffer);

#if (DBG != 0)
			TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
				"dmaProfile: %d\n", devExt->dmaProfile);
#endif
			length = 0;
			break;
		}
	case IOCTL_DIRECT_DMA_READ:
		{
//			ULONG dma1Ctl = 0;
//			status = WdfRequestRetrieveInputBuffer(Request, 0, &pInputBuffer, &length);
//			devExt->ReadSize = *(PULONG)pInputBuffer;
//
//#if (DBG != 0)
//			TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
//				"devExt->ReadSize: %d\n", devExt->ReadSize);
//#endif
//
//			WdfInterruptAcquireLock( devExt->Interrupt );
//
//			WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->DMA1_ADDR32,
//				devExt->ReadCommonBufferBaseLA.LowPart);
//			WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->DMA1_ADDR64,
//				devExt->ReadCommonBufferBaseLA.HighPart );
//
//			WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->DMA1_SIZE, devExt->ReadSize);
//			devExt->ReadSize = 0;
//
//			dma1Ctl = DMA_CTRL_START;
//			//WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->DMA1_CTRL, dma1Ctl);
//
//			WdfInterruptReleaseLock( devExt->Interrupt );
			break;
		}
	case IOCTL_DIRECT_DMA_WRITE:
		{
			//ULONG dma0Ctl = 0;
			//status = WdfRequestRetrieveInputBuffer(Request, 0, &pInputBuffer, &length);
			//devExt->WriteSize = *(PULONG)pInputBuffer;

			//WdfInterruptAcquireLock( devExt->Interrupt );

			//WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->DMA0_ADDR32,
			//	devExt->WriteCommonBufferBaseLA.LowPart );
			//WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->DMA0_ADDR64,
			//	devExt->WriteCommonBufferBaseLA.HighPart );

			//WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->DMA0_SIZE, devExt->WriteSize);

			//dma0Ctl = DMA_CTRL_START;
			//WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->DMA0_CTRL, dma0Ctl);

			//WdfInterruptReleaseLock( devExt->Interrupt );
			break;
		}
	case IOCTL_RESET: // code == 0x801
		{
			status = WdfRequestRetrieveOutputBuffer(Request, 0, &pOutputBuffer, &length);
			if( !NT_SUCCESS(status)) {
#if (DBG != 0)
				TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
								"WdfRequestRetrieveOutputBuffer failed 0x%x\n", status);
#endif
				break;
			}
			//*(PULONG) buffer = 0x0004000A;

			//status = STATUS_SUCCESS;
			length = sizeof(ULONG);
			break;
		}

	default:
		status = STATUS_INVALID_DEVICE_REQUEST;
		break;
    }

    WdfRequestCompleteWithInformation(Request, status, length);
}
Beispiel #23
0
VOID
ProcessExplorerEvtIoStop(
    _In_ WDFQUEUE Queue,
    _In_ WDFREQUEST Request,
    _In_ ULONG ActionFlags
)
/*++

Routine Description:

    This event is invoked for a power-managed queue before the device leaves the working state (D0).

Arguments:

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

    Request - Handle to a framework request object.

    ActionFlags - A bitwise OR of one or more WDF_REQUEST_STOP_ACTION_FLAGS-typed flags
                  that identify the reason that the callback function is being called
                  and whether the request is cancelable.

Return Value:

    VOID

--*/
{
    TraceEvents(TRACE_LEVEL_INFORMATION, 
                TRACE_QUEUE, 
                "%!FUNC! Queue 0x%p, Request 0x%p ActionFlags %d", 
                Queue, Request, ActionFlags);

    //
    // In most cases, the EvtIoStop callback function completes, cancels, or postpones
    // further processing of the I/O request.
    //
    // Typically, the driver uses the following rules:
    //
    // - If the driver owns the I/O request, it calls WdfRequestUnmarkCancelable
    //   (if the request is cancelable) and either calls WdfRequestStopAcknowledge
    //   with a Requeue value of TRUE, or it calls WdfRequestComplete with a
    //   completion status value of STATUS_SUCCESS or STATUS_CANCELLED.
    //
    //   Before it can call these methods safely, the driver must make sure that
    //   its implementation of EvtIoStop has exclusive access to the request.
    //
    //   In order to do that, the driver must synchronize access to the request
    //   to prevent other threads from manipulating the request concurrently.
    //   The synchronization method you choose will depend on your driver's design.
    //
    //   For example, if the request is held in a shared context, the EvtIoStop callback
    //   might acquire an internal driver lock, take the request from the shared context,
    //   and then release the lock. At this point, the EvtIoStop callback owns the request
    //   and can safely complete or requeue the request.
    //
    // - If the driver has forwarded the I/O request to an I/O target, it either calls
    //   WdfRequestCancelSentRequest to attempt to cancel the request, or it postpones
    //   further processing of the request and calls WdfRequestStopAcknowledge with
    //   a Requeue value of FALSE.
    //
    // A driver might choose to take no action in EvtIoStop for requests that are
    // guaranteed to complete in a small amount of time.
    //
    // In this case, the framework waits until the specified request is complete
    // before moving the device (or system) to a lower power state or removing the device.
    // Potentially, this inaction can prevent a system from entering its hibernation state
    // or another low system power state. In extreme cases, it can cause the system
    // to crash with bugcheck code 9F.
    //

    return;
}
NTSTATUS PVPanicEvtDeviceAdd(IN WDFDRIVER Driver,
                             IN PWDFDEVICE_INIT DeviceInit)
{
    NTSTATUS status;
    WDFDEVICE device;
    WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;
	WDF_FILEOBJECT_CONFIG fileConfig;
    WDF_OBJECT_ATTRIBUTES attributes;
    WDF_IO_QUEUE_CONFIG queueConfig;
    PDEVICE_CONTEXT context;
    DECLARE_CONST_UNICODE_STRING(dosDeviceName, PVPANIC_DOS_DEVICE_NAME);

    UNREFERENCED_PARAMETER(Driver);

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "--> %!FUNC!");

    PAGED_CODE();

    WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);

    pnpPowerCallbacks.EvtDevicePrepareHardware = PVPanicEvtDevicePrepareHardware;
    pnpPowerCallbacks.EvtDeviceReleaseHardware = PVPanicEvtDeviceReleaseHardware;
	pnpPowerCallbacks.EvtDeviceD0Entry = PVPanicEvtDeviceD0Entry;
	pnpPowerCallbacks.EvtDeviceD0Exit = PVPanicEvtDeviceD0Exit;

    WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);

	WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_CONTEXT);

	WDF_FILEOBJECT_CONFIG_INIT(&fileConfig, PVPanicEvtDeviceFileCreate,
		WDF_NO_EVENT_CALLBACK, WDF_NO_EVENT_CALLBACK);

	WdfDeviceInitSetFileObjectConfig(DeviceInit, &fileConfig,
		WDF_NO_OBJECT_ATTRIBUTES);

    status = WdfDeviceCreate(&DeviceInit, &attributes, &device);
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
            "WdfDeviceCreate failed: %!STATUS!", status);
        return status;
    }

    status = WdfDeviceCreateSymbolicLink(device, &dosDeviceName);
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
            "WdfDeviceCreateSymbolicLink failed: %!STATUS!", status);
        return status;
    }

    WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchSequential);
    queueConfig.EvtIoDeviceControl = PVPanicEvtQueueDeviceControl;

    context = GetDeviceContext(device);
    status = WdfIoQueueCreate(device,
                              &queueConfig,
                              WDF_NO_OBJECT_ATTRIBUTES,
                              &context->IoctlQueue);
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
            "WdfIoQueueCreate failed: %!STATUS!", status);
        return status;
    }

    status = WdfDeviceConfigureRequestDispatching(device,
                                                  context->IoctlQueue,
                                                  WdfRequestTypeDeviceControl);
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
            "WdfDeviceConfigureRequestDispatching failed: %!STATUS!", status);
        return status;
    }

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "<-- %!FUNC!");

    return status;
}
NTSTATUS 
ReenumerateDevice(
    _In_ PDEVICE_CONTEXT DevContext
    )
/*++

Routine Description

    This routine re-enumerates the USB device.

Arguments:

    pDevContext - One of our device extensions

Return Value:

    NT status value

--*/
{
    NTSTATUS status;
    WDF_USB_CONTROL_SETUP_PACKET    controlSetupPacket;
    WDF_REQUEST_SEND_OPTIONS        sendOptions;
    GUID                            activity;
    
    PAGED_CODE();

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL,"--> ReenumerateDevice\n");

    WDF_REQUEST_SEND_OPTIONS_INIT(
                                  &sendOptions,
                                  WDF_REQUEST_SEND_OPTION_TIMEOUT
                                  );

    WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(
                                         &sendOptions,
                                         DEFAULT_CONTROL_TRANSFER_TIMEOUT
                                         );
              
    WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket,
                                        BmRequestHostToDevice,
                                        BmRequestToDevice,
                                        USBFX2LK_REENUMERATE, // Request
                                        0, // Value
                                        0); // Index


    status = WdfUsbTargetDeviceSendControlTransferSynchronously(
                                        DevContext->UsbDevice,
                                        WDF_NO_HANDLE, // Optional WDFREQUEST
                                        &sendOptions,
                                        &controlSetupPacket,
                                        NULL, // MemoryDescriptor
                                        NULL); // BytesTransferred

    if(!NT_SUCCESS(status)) {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL,
                    "ReenumerateDevice: Failed to Reenumerate - 0x%x \n", status);
    }

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL,"<-- ReenumerateDevice\n");

    //
    // Send event to eventlog
    //

    activity = DeviceToActivityId(WdfObjectContextGetObject(DevContext));
    EventWriteDeviceReenumerated(DevContext->DeviceName,
                                 DevContext->Location,
                                 status);
   
    return status;

}
NTSTATUS
DriverEntry(
    PDRIVER_OBJECT  DriverObject,
    PUNICODE_STRING RegistryPath
    )
/*++

Routine Description:
    DriverEntry initializes the driver and is the first routine called by the
    system after the driver is loaded.

Parameters Description:

    DriverObject - represents the instance of the function driver that is loaded
    into memory. DriverEntry must initialize members of DriverObject before it
    returns to the caller. DriverObject is allocated by the system before the
    driver is loaded, and it is released by the system after the system unloads
    the function driver from memory.

    RegistryPath - represents the driver specific path in the Registry.
    The function driver can use the path to store driver related data between
    reboots. The path does not store hardware instance specific data.

Return Value:

    STATUS_SUCCESS if successful,
    STATUS_UNSUCCESSFUL otherwise.

--*/
{
    WDF_DRIVER_CONFIG       config;
    NTSTATUS                status;
    WDF_OBJECT_ATTRIBUTES   attributes;

    //
    // Initialize WPP Tracing
    //
    WPP_INIT_TRACING(DriverObject, RegistryPath);

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT,
                       "OSRUSBFX2 Driver Sample - Driver Framework Edition.\n");

    //
    // Initiialize driver config to control the attributes that
    // are global to the driver. Note that framework by default
    // provides a driver unload routine. If you create any resources
    // in the DriverEntry and want to be cleaned in driver unload,
    // you can override that by manually setting the EvtDriverUnload in the
    // config structure. In general xxx_CONFIG_INIT macros are provided to
    // initialize most commonly used members.
    //

    WDF_DRIVER_CONFIG_INIT(
        &config,
        OsrFxEvtDeviceAdd
        );

    //
    // Register a cleanup callback so that we can call WPP_CLEANUP when
    // the framework driver object is deleted during driver unload.
    //
    WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
    attributes.EvtCleanupCallback = OsrFxEvtDriverContextCleanup;

    //
    // Create a framework driver object to represent our driver.
    //
    status = WdfDriverCreate(
        DriverObject,
        RegistryPath,
        &attributes, // Driver Attributes
        &config,          // Driver Config Info
        WDF_NO_HANDLE // hDriver
        );

    if (!NT_SUCCESS(status)) {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT,
                "WdfDriverCreate failed with status 0x%x\n", status);
        //
        // Cleanup tracing here because DriverContextCleanup will not be called
        // as we have failed to create WDFDRIVER object itself.
        // Please note that if your return failure from DriverEntry after the
        // WDFDRIVER object is created successfully, you don't have to
        // call WPP cleanup because in those cases DriverContextCleanup
        // will be executed when the framework deletes the DriverObject.
        //
        WPP_CLEANUP(DriverObject);
    }

    return status;
}
NTSTATUS 
GetSevenSegmentState(
    _In_ PDEVICE_CONTEXT DevContext, 
    _Out_ PUCHAR SevenSegment
    )
/*++

Routine Description

    This routine gets the state of the 7 segment display on the board
    by sending a synchronous control command.

    NOTE: It's not a good practice to send a synchronous request in the
          context of the user thread because if the transfer takes long
          time to complete, you end up holding the user thread.

          I'm choosing to do synchronous transfer because a) I know this one
          completes immediately b) and for demonstration.

Arguments:

    DevContext - One of our device extensions

    SevenSegment - receives the state of the 7 segment display

Return Value:

    NT status value

--*/
{
    NTSTATUS status;
    WDF_USB_CONTROL_SETUP_PACKET    controlSetupPacket;
    WDF_REQUEST_SEND_OPTIONS        sendOptions;
    
    WDF_MEMORY_DESCRIPTOR memDesc;
    ULONG    bytesTransferred;

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "GetSetSevenSegmentState: Enter\n");

    PAGED_CODE();

    WDF_REQUEST_SEND_OPTIONS_INIT(
                                  &sendOptions,
                                  WDF_REQUEST_SEND_OPTION_TIMEOUT
                                  );

    WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(
                                         &sendOptions,
                                         DEFAULT_CONTROL_TRANSFER_TIMEOUT
                                         );

    WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket,
                                        BmRequestDeviceToHost,
                                        BmRequestToDevice,
                                        USBFX2LK_READ_7SEGMENT_DISPLAY, // Request
                                        0, // Value
                                        0); // Index

    //
    // Set the buffer to 0, the board will OR in everything that is set
    //
    *SevenSegment = 0;

    WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc,
                                    SevenSegment,
                                    sizeof(UCHAR));

    status = WdfUsbTargetDeviceSendControlTransferSynchronously(
                                    DevContext->UsbDevice,
                                    NULL, // Optional WDFREQUEST
                                    &sendOptions,
                                    &controlSetupPacket,
                                    &memDesc,
                                    &bytesTransferred);

    if(!NT_SUCCESS(status)) {

        TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL,
            "GetSevenSegmentState: Failed to get 7 Segment state - 0x%x \n", status);
    } else {

        TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL,
            "GetSevenSegmentState: 7 Segment mask is 0x%x\n", *SevenSegment);
    }

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "GetSetSevenSegmentState: Exit\n");

    return status;

}
Beispiel #28
0
NTSTATUS
BthEchoCliRetrieveServerSdpRecord(
    _In_ PBTHECHOSAMPLE_CLIENT_CONTEXT DevCtx,
    _Out_ PBTH_SDP_STREAM_RESPONSE * ServerSdpRecord    
    )
/*++

Description:

    Retrive server SDP record.
    We call this function on every file open to get the PSM

Arguments:

    DevCtx - Client context
    ServerSdpRecord - SDP record retrieved

Return Value:

    NTSTATUS Status code.

--*/
{
    NTSTATUS status, statusReuse, disconnectStatus;
    WDF_MEMORY_DESCRIPTOR inMemDesc;
    WDF_MEMORY_DESCRIPTOR outMemDesc;
    WDF_REQUEST_REUSE_PARAMS ReuseParams;    
    BTH_SDP_CONNECT connect = {0};
    BTH_SDP_DISCONNECT disconnect = {0};
    BTH_SDP_SERVICE_ATTRIBUTE_SEARCH_REQUEST requestSdp = {0};
    BTH_SDP_STREAM_RESPONSE responseSdp = {0};
    ULONG requestSize;
    PBTH_SDP_STREAM_RESPONSE serverSdpRecord = NULL;
    WDFREQUEST request;
    WDF_OBJECT_ATTRIBUTES attributes;
    

    PAGED_CODE();

    //
    // Allocate the request we will use for obtaining sdp record
    // NOTE that we do it for every file open, hence we
    //
    // can't use reserve request from the context
    //
    
    WDF_OBJECT_ATTRIBUTES_INIT(&attributes);

    status = WdfRequestCreate(
        &attributes,
        DevCtx->Header.IoTarget,
        &request
        );

    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, 
            "Failed to allocate request for retriving server sdp record, Status code %!STATUS!\n", status);

        goto exit;        
    }

    connect.bthAddress = DevCtx->ServerBthAddress;
    connect.requestTimeout = SDP_REQUEST_TO_DEFAULT;
    connect.fSdpConnect = 0;

    //
    // Connect to the SDP service.
    //

    WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(
        &inMemDesc,
        &connect,
        sizeof(connect)
        );
    
    WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(
        &outMemDesc,
        &connect,
        sizeof(connect)
        );

    status = WdfIoTargetSendIoctlSynchronously(
        DevCtx->Header.IoTarget,
        request,
        IOCTL_BTH_SDP_CONNECT,
        &inMemDesc,
        &outMemDesc,
        NULL,   //sendOptions
        NULL    //bytesReturned
        );

    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, 
            "IOCTL_BTH_SDP_CONNECT failed, Status code %!STATUS!\n", status);

        goto exit1;
    }

    //
    // Obtain the required size of the SDP record
    //
    requestSdp.hConnection = connect.hConnection;
    requestSdp.uuids[0].u.uuid128 = BTHECHOSAMPLE_SVC_GUID;
    requestSdp.uuids[0].uuidType = SDP_ST_UUID128;
    requestSdp.range[0].minAttribute = 0;
    requestSdp.range[0].maxAttribute = 0xFFFF;

    WDF_REQUEST_REUSE_PARAMS_INIT(&ReuseParams, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_NOT_SUPPORTED);
    statusReuse = WdfRequestReuse(request, &ReuseParams);    
    NT_ASSERT(NT_SUCCESS(statusReuse));
    UNREFERENCED_PARAMETER(statusReuse);

    WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(
        &inMemDesc,
        &requestSdp,
        sizeof(requestSdp)
        );
    
    WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(
        &outMemDesc,
        &responseSdp,
        sizeof(responseSdp)
        );

    status = WdfIoTargetSendIoctlSynchronously(
        DevCtx->Header.IoTarget,
        request,
        IOCTL_BTH_SDP_SERVICE_ATTRIBUTE_SEARCH,
        &inMemDesc,
        &outMemDesc,
        NULL,   //sendOptions
        NULL    //bytesReturned
        );

    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, 
            "IOCTL_BTH_SDP_SERVICE_ATTRIBUTE_SEARCH failed while querying response size, "
            "status code %!STATUS!\n", status);

        goto exit2;
    }

    //
    // Allocate the required size for SDP record
    //

    status = RtlULongAdd(
        responseSdp.requiredSize, 
        sizeof(BTH_SDP_STREAM_RESPONSE), 
        &requestSize
        );

    if(!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, 
            "SDP record size too large, status code %!STATUS!\n", status);

        goto exit2;
    }

    serverSdpRecord = ExAllocatePoolWithTag(NonPagedPoolNx, requestSize, POOLTAG_BTHECHOSAMPLE);
    if (NULL == serverSdpRecord)
    {
        status = STATUS_INSUFFICIENT_RESOURCES;
        TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, 
            "Allocating SDP record failed, returning status code %!STATUS!\n", status); 

        goto exit2;
    }

    //
    // Send request with required size
    //
    
    WDF_REQUEST_REUSE_PARAMS_INIT(&ReuseParams, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_NOT_SUPPORTED);
    statusReuse = WdfRequestReuse(request, &ReuseParams);    
    NT_ASSERT(NT_SUCCESS(statusReuse));
    UNREFERENCED_PARAMETER(statusReuse);

    WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(
        &inMemDesc,
        &requestSdp,
        sizeof(requestSdp)
        );
    
    WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(
        &outMemDesc,
        serverSdpRecord,
        requestSize
        );

    status = WdfIoTargetSendIoctlSynchronously(
        DevCtx->Header.IoTarget,
        request,
        IOCTL_BTH_SDP_SERVICE_ATTRIBUTE_SEARCH,
        &inMemDesc,
        &outMemDesc,
        NULL,   //sendOptions
        NULL    //bytesReturned
        );

    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_SDP, 
            "IOCTL_BTH_SDP_SERVICE_ATTRIBUTE_SEARCH failed, status code %!STATUS!\n", status);

        ExFreePoolWithTag(serverSdpRecord, POOLTAG_BTHECHOSAMPLE);
    }
    else
    {
        *ServerSdpRecord = serverSdpRecord;
    }
    
exit2:
    
    //
    // Disconnect from SDP service.
    //
    
    WDF_REQUEST_REUSE_PARAMS_INIT(&ReuseParams, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_NOT_SUPPORTED);
    statusReuse = WdfRequestReuse(request, &ReuseParams);    
    NT_ASSERT(NT_SUCCESS(statusReuse));
    UNREFERENCED_PARAMETER(statusReuse);

    disconnect.hConnection = connect.hConnection;

    WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(
        &inMemDesc,
        &disconnect,
        sizeof(disconnect)
        );
    
    disconnectStatus = WdfIoTargetSendIoctlSynchronously(
        DevCtx->Header.IoTarget,
        request,
        IOCTL_BTH_SDP_DISCONNECT,
        &inMemDesc,
        NULL,   //outMemDesc
        NULL,   //sendOptions
        NULL    //bytesReturned
        );

    NT_ASSERT(NT_SUCCESS(disconnectStatus)); //Disconnect should not fail

    if (!NT_SUCCESS(disconnectStatus))
    {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, 
            "IOCTL_BTH_SDP_DISCONNECT failed, Status code %!STATUS!\n", status);
    }
    
exit1:    
    WdfObjectDelete(request);
exit:
    return status;
}
NTSTATUS 
GetSwitchState(
    _In_ PDEVICE_CONTEXT DevContext, 
    _In_ PSWITCH_STATE SwitchState
    )
/*++

Routine Description

    This routine gets the state of the switches on the board

Arguments:

    DevContext - One of our device extensions

Return Value:

    NT status value

--*/
{
    NTSTATUS status;
    WDF_USB_CONTROL_SETUP_PACKET    controlSetupPacket;
    WDF_REQUEST_SEND_OPTIONS        sendOptions;
    WDF_MEMORY_DESCRIPTOR memDesc;
    ULONG    bytesTransferred;

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "--> GetSwitchState\n");

    PAGED_CODE();

    WDF_REQUEST_SEND_OPTIONS_INIT(
                                  &sendOptions,
                                  WDF_REQUEST_SEND_OPTION_TIMEOUT
                                  );

    WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(
                                         &sendOptions,
                                         DEFAULT_CONTROL_TRANSFER_TIMEOUT
                                         );

    WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket,
                                        BmRequestDeviceToHost,
                                        BmRequestToDevice,
                                        USBFX2LK_READ_SWITCHES, // Request
                                        0, // Value
                                        0); // Index

    SwitchState->SwitchesAsUChar = 0;

    WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc,
                                    SwitchState,
                                    sizeof(SWITCH_STATE));

    status = WdfUsbTargetDeviceSendControlTransferSynchronously(
                                                DevContext->UsbDevice,
                                                NULL, // Optional WDFREQUEST
                                                &sendOptions,
                                                &controlSetupPacket,
                                                &memDesc,
                                                &bytesTransferred);

    if(!NT_SUCCESS(status)) {
        TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL,
                "GetSwitchState: Failed to Get switches - 0x%x \n", status);

    } else {
        TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL,
            "GetSwitchState: Switch mask is 0x%x\n", SwitchState->SwitchesAsUChar);
    }

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTL, "<-- GetSwitchState\n");

    return status;

}
Beispiel #30
0
/**
 * @brief DPC callback.
 * Calls the Xen interface api to process the ringbuffer until the ringbuffer is empty,
 * then completes all requests provided by the Xen api.
 *
 * @todo consider completion within the XenDpc() loop. However this would release the device
 * lock.
 *
 * @param[in] Dpc The WDFDPC handle.
 *  
 */
VOID
FdoEvtDeviceDpcFunc(
    IN VOID *Context)
{
    // --XT-- FDO context passed directly now.
    PUSB_FDO_CONTEXT fdoContext = (PUSB_FDO_CONTEXT)Context;
    //
    // this stuff needs to be done at DPC level in order to complete irps.
    //
    ULONG passes = 0;
    AcquireFdoLock(fdoContext);

    if (fdoContext->InDpc)
    {
        fdoContext->DpcOverLapCount++;
        ReleaseFdoLock(fdoContext);
        return;
    }
    fdoContext->InDpc = TRUE;

    BOOLEAN moreWork;
    do
    {
        moreWork = XenDpc(fdoContext, fdoContext->RequestCollection);
        passes++;
        if (fdoContext->DpcOverLapCount)
        {
            fdoContext->totalDpcOverLapCount += fdoContext->DpcOverLapCount;
            fdoContext->DpcOverLapCount = 0;
            moreWork = TRUE;
        }
        if (moreWork & (passes >= KeQueryActiveProcessorCount(NULL)))
        {
            //
            // reschedule the dpc to prevent starvation.
            //
            // --XT-- WdfDpcEnqueue(fdoContext->WdfDpc);
            //
            // --XT-- Schedule through the Xen interface now.
            //
            XenScheduleDPC(fdoContext->Xen);
            TraceEvents(TRACE_LEVEL_VERBOSE, TRACE_DPC,
                __FUNCTION__": enqueue dpc at %d passes\n",
                passes);
            fdoContext->totalDpcReQueueCount++;
            break;
        }

    } while (moreWork);
 
    fdoContext->InDpc = FALSE; // allow another dpc instance to run and add to the collection.
    if (passes > fdoContext->maxDpcPasses)
    {
        fdoContext->maxDpcPasses = passes;
    }
    //
    // complete all queued Irps. Note that this section is re-entrant.
    // Note also that all of these requests have been "uncanceled" and ahve
    // been marked as completed in their request contexts and that the
    // additional reference on the request object has been removed.
    // The collection can be safely completed with no race conditions.
    //
    ULONG responseCount = 0;
    WDFREQUEST Request;
    while ((Request = (WDFREQUEST) WdfCollectionGetFirstItem(fdoContext->RequestCollection)) != NULL)
    {
        WdfCollectionRemoveItem(fdoContext->RequestCollection, 0);

        TraceEvents(TRACE_LEVEL_VERBOSE, TRACE_DPC,
            __FUNCTION__": complete Request %p Status %x\n",
            Request,
            WdfRequestWdmGetIrp(Request)->IoStatus.Status);
        
        ReleaseFdoLock(fdoContext);

        WdfRequestCompleteWithPriorityBoost(Request,
            WdfRequestWdmGetIrp(Request)->IoStatus.Status,
            IO_SOUND_INCREMENT);
        
        AcquireFdoLock(fdoContext);

        responseCount++;
    }

    if (responseCount > fdoContext->maxRequestsProcessed)
    {
        fdoContext->maxRequestsProcessed = responseCount;
    }
    //
    // fire up any queued requests
    //    
    DrainRequestQueue(fdoContext, FALSE);

    ReleaseFdoLock(fdoContext);

    // --XT-- this trace was way too noisy, made it verbose.
    TraceEvents(TRACE_LEVEL_VERBOSE, TRACE_DPC,
        __FUNCTION__": exit responses processed %d passes %d\n",
        responseCount,
        passes);
}