Exemple #1
0
/*++

Routine Description:

    Write to mail box in a serialize manner

Arguments:

    DeviceContextPtr - Pointer to device context

    Channel - Mailbox Channel

    Value - Value to be written

    Request - Optional WDF request object associated with this mailbox 
        transaction

Return Value:

    NTSTATUS

--*/
_Use_decl_annotations_
NTSTATUS RpiqMailboxWrite (
    DEVICE_CONTEXT* DeviceContextPtr,
    ULONG Channel,
    ULONG Value,
    WDFREQUEST Request
    )
{
    NTSTATUS status;
    ULONG count = 0, reg;
    LARGE_INTEGER timeOut = { 0 };

    PAGED_CODE();
    
    WdfWaitLockAcquire(DeviceContextPtr->WriteLock, NULL);

    timeOut.QuadPart = WDF_REL_TIMEOUT_IN_MS(1);

    reg = READ_REGISTER_NOFENCE_ULONG(&DeviceContextPtr->Mailbox->Status);

    // Poll until mailbox is available. It doesn't seem like
    // the mailbox is full often so polling is sufficient for now
    // rather than enable mailbox empty interrupt
    while (reg & MAILBOX_STATUS_FULL) {
        if (count > MAX_POLL) {
            RPIQ_LOG_ERROR(
                "Exit Fail Status 0x%08x", 
                DeviceContextPtr->Mailbox->Status);
            status = STATUS_IO_TIMEOUT;
            goto End;
        }

        KeDelayExecutionThread(KernelMode, FALSE, &timeOut);
        reg = READ_REGISTER_NOFENCE_ULONG(&DeviceContextPtr->Mailbox->Status);
        ++count;
    }

    if (Request) {
        status = WdfRequestForwardToIoQueue(
            Request,
            DeviceContextPtr->ChannelQueue[Channel]);
        if (!NT_SUCCESS(status)) {
            RPIQ_LOG_ERROR(
                "WdfRequestForwardToIoQueue failed ( %!STATUS!)",
                status);
            goto End;
        }
    }

    WRITE_REGISTER_NOFENCE_ULONG(
        &DeviceContextPtr->Mailbox->Write, 
        (Value & ~MAILBOX_CHANNEL_MASK) | Channel);

    status = STATUS_SUCCESS;

End:
    WdfWaitLockRelease(DeviceContextPtr->WriteLock);

    return status;
}
Exemple #2
0
VOID
OnTopLevelIoDefault(
    _In_  WDFQUEUE    FxQueue,
    _In_  WDFREQUEST  FxRequest
    )
/*++

  Routine Description:

    Accepts all incoming requests and pends or forwards appropriately.

  Arguments:

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

  Return Value:

    None.

--*/
{
    FuncEntry(TRACE_FLAG_SPBAPI);
    
    UNREFERENCED_PARAMETER(FxQueue);

    WDFDEVICE device;
    PDEVICE_CONTEXT pDevice;
    WDF_REQUEST_PARAMETERS params;
    NTSTATUS status;

    device = WdfIoQueueGetDevice(FxQueue);
    pDevice = GetDeviceContext(device);

    WDF_REQUEST_PARAMETERS_INIT(&params);

    WdfRequestGetParameters(FxRequest, &params);

	status = WdfRequestForwardToIoQueue(FxRequest, pDevice->SpbQueue);

	if (!NT_SUCCESS(status))
	{
		CyapaPrint(
			DEBUG_LEVEL_ERROR,
			DBG_IOCTL,
			"Failed to forward WDFREQUEST %p to SPB queue %p - %!STATUS!",
			FxRequest,
			pDevice->SpbQueue,
			status);
		
		WdfRequestComplete(FxRequest, status);
	}

    FuncExit(TRACE_FLAG_SPBAPI);
}
static VOID
XenBus_EvtIoRead(WDFQUEUE queue, WDFREQUEST request, size_t length)
{
  NTSTATUS status;
  WDFFILEOBJECT file_object = WdfRequestGetFileObject(request);
  PXENPCI_DEVICE_INTERFACE_DATA xpdid = GetXpdid(file_object);
  KIRQL old_irql;

  UNREFERENCED_PARAMETER(queue);
  
  FUNCTION_ENTER();
  status = WdfRequestForwardToIoQueue(request, xpdid->xenbus.io_queue);
  if (!NT_SUCCESS(status))
  {
    KdPrint((__DRIVER_NAME "     could not forward request (%08x)\n", status));
  }
  KeAcquireSpinLock(&xpdid->lock, &old_irql);
  if (!IsListEmpty(&xpdid->xenbus.read_list_head))
  {
    status = WdfIoQueueRetrieveNextRequest(xpdid->xenbus.io_queue, &request);
    if (NT_SUCCESS(status))
    {
      KdPrint((__DRIVER_NAME "     found pending read\n"));
      XenBus_ProcessReadRequest(xpdid->xenbus.io_queue, request, length);
      KeReleaseSpinLock(&xpdid->lock, old_irql);
      WdfRequestComplete(request, STATUS_SUCCESS);
    }
    else
    {
      KdPrint((__DRIVER_NAME "     no pending read (%08x)\n", status));
      KeReleaseSpinLock(&xpdid->lock, old_irql);
    }
  }
  else
  {
    KdPrint((__DRIVER_NAME "     no data to read\n"));
    KeReleaseSpinLock(&xpdid->lock, old_irql);
  }
  
  FUNCTION_EXIT();
  return;
}
Exemple #4
0
VOID FireShockEvtIoRead(
    _In_ WDFQUEUE   Queue,
    _In_ WDFREQUEST Request,
    _In_ size_t     Length
)
{
    NTSTATUS            status;
    PDEVICE_CONTEXT     pDeviceContext;

    UNREFERENCED_PARAMETER(Length);

    pDeviceContext = DeviceGetContext(WdfIoQueueGetDevice(Queue));

    status = WdfRequestForwardToIoQueue(Request, pDeviceContext->IoReadQueue);
    if (!NT_SUCCESS(status))
    {
        TraceEvents(TRACE_LEVEL_ERROR,
            TRACE_QUEUE, "WdfRequestForwardToIoQueue failed with status %!STATUS!", status);
        WdfRequestComplete(Request, status);
    }
}
static VOID
XenUsb_EvtIoInternalDeviceControl(
  WDFQUEUE queue,
  WDFREQUEST request,
  size_t output_buffer_length,
  size_t input_buffer_length,
  ULONG io_control_code)
{
  WDFDEVICE device = WdfIoQueueGetDevice(queue);
  PXENUSB_DEVICE_DATA xudd = GetXudd(device);
  //WDF_REQUEST_PARAMETERS wrp;
  //pvusb_urb_t *urb;

  UNREFERENCED_PARAMETER(input_buffer_length);
  UNREFERENCED_PARAMETER(output_buffer_length);

  FUNCTION_ENTER();

  //WDF_REQUEST_PARAMETERS_INIT(&wrp);
  //WdfRequestGetParameters(request, &wrp);

  switch(io_control_code)
  {
  case IOCTL_INTERNAL_PVUSB_SUBMIT_URB:
    FUNCTION_MSG("IOCTL_INTERNAL_PVUSB_SUBMIT_URB\n");
    //urb = (pvusb_urb_t *)wrp.Parameters.Others.Arg1;
    //FUNCTION_MSG("urb = %p\n", urb);
    WdfRequestForwardToIoQueue(request, xudd->pvurb_queue);
    break;
  default:
    FUNCTION_MSG("Unknown IOCTL %08x\n", io_control_code);
    WdfRequestComplete(request, WdfRequestGetStatus(request));
    break;
  }
  FUNCTION_EXIT();
}
Exemple #6
0
VOID
SerialStartOrQueue(
    IN PSERIAL_DEVICE_EXTENSION Extension,
    IN WDFREQUEST Request,
    IN WDFQUEUE QueueToExamine,
    IN WDFREQUEST *CurrentOpRequest,
    IN PSERIAL_START_ROUTINE Starter
    )

/*++

Routine Description:

    This routine is used to either start or queue any requst
    that can be queued in the driver.

Arguments:

    Extension - Points to the serial device extension.

    Request - The request to either queue or start.  In either
          case the request will be marked pending.

    QueueToExamine - The queue the request will be place on if there
                     is already an operation in progress.

    CurrentOpRequest - Pointer to a pointer to the request the is current
                   for the queue.  The pointer pointed to will be
                   set with to Request if what CurrentOpRequest points to
                   is NULL.

    Starter - The routine to call if the queue is empty.

Return Value:


--*/

{

    NTSTATUS status;
    PREQUEST_CONTEXT reqContext;
    WDF_REQUEST_PARAMETERS  params;

    reqContext = SerialGetRequestContext(Request);

    WDF_REQUEST_PARAMETERS_INIT(&params);

    WdfRequestGetParameters(
             Request,
             &params);

    //
    // If this is a write request then take the amount of characters
    // to write and add it to the count of characters to write.
    //

    if (params.Type == WdfRequestTypeWrite) {

        Extension->TotalCharsQueued += reqContext->Length;

    } else if ((params.Type == WdfRequestTypeDeviceControl) &&
               ((params.Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_IMMEDIATE_CHAR) ||
                (params.Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_XOFF_COUNTER))) {

        reqContext->IoctlCode = params.Parameters.DeviceIoControl.IoControlCode; // We need this in the destroy callback

        Extension->TotalCharsQueued++;

    }

    if (IsQueueEmpty(QueueToExamine) &&  !(*CurrentOpRequest)) {

        //
        // There were no current operation.  Mark this one as
        // current and start it up.
        //

        *CurrentOpRequest = Request;

        Starter(Extension);

        return;

    } else {

        //
        // We don't know how long the request will be in the
        // queue.  If it gets cancelled while waiting in the queue, we will
        // be notified by EvtCanceledOnQueue callback so that we can readjust
        // the lenght or free the buffer.
        //
        reqContext->Extension = Extension; // We need this in the destroy callback

        status = WdfRequestForwardToIoQueue(Request,  QueueToExamine);
        if(!NT_SUCCESS(status)) {
            TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "WdfRequestForwardToIoQueue failed%X\n", status);
            ASSERTMSG("WdfRequestForwardToIoQueue failed ", FALSE);
            SerialCompleteRequest(Request, status, 0);
        }

        return;
    }
}
// This event is called when the framework receives IRP_MJ_INTERNAL DEVICE_CONTROL requests from the system.
//
void HidFx2EvtInternalDeviceControl(
    _In_ WDFQUEUE     hQueue,
    _In_ WDFREQUEST   hRequest,
    _In_ size_t       cOutputBufferLength,
    _In_ size_t       cInputBufferLength,
    _In_ ULONG        ulIoControlCode
   )
{
    NTSTATUS            status = STATUS_SUCCESS;
    WDFDEVICE           hDevice;
    PDEVICE_EXTENSION   pDevContext = NULL;

    UNREFERENCED_PARAMETER(cOutputBufferLength);
    UNREFERENCED_PARAMETER(cInputBufferLength);

    TraceVerbose(DBG_IOCTL, "(%!FUNC!) Enter\n");

    hDevice = WdfIoQueueGetDevice(hQueue);
    pDevContext = GetDeviceContext(hDevice);

    TraceInfo(DBG_IOCTL, "(%!FUNC!) Queue:0x%p, Request:0x%p\n", hQueue, hRequest);

    switch (ulIoControlCode)
    {
    case IOCTL_HID_GET_DEVICE_DESCRIPTOR:
        TraceInfo(DBG_IOCTL, "IOCTL_HID_GET_DEVICE_DESCRIPTOR\n");
        status = HidFx2GetHidDescriptor(hDevice, hRequest);
        WdfRequestComplete(hRequest, status);
        break;

    case IOCTL_HID_GET_DEVICE_ATTRIBUTES:
        TraceInfo(DBG_IOCTL, "IOCTL_HID_GET_DEVICE_ATTRIBUTES\n");
        status = HidFx2GetDeviceAttributes(hRequest);
        WdfRequestComplete(hRequest, status);
        break;

    case IOCTL_HID_GET_REPORT_DESCRIPTOR:
        TraceInfo(DBG_IOCTL, "IOCTL_HID_GET_REPORT_DESCRIPTOR\n");
        status = HidFx2GetReportDescriptor(hDevice, hRequest);
        WdfRequestComplete(hRequest, status);
        break;

    case IOCTL_HID_READ_REPORT:
        TraceInfo(DBG_IOCTL, "IOCTL_HID_READ_REPORT\n");
        status = WdfRequestForwardToIoQueue(hRequest, pDevContext->hInterruptMsgQueue);
        if (!NT_SUCCESS(status))
        {
            TraceErr(DBG_IOCTL, "WdfRequestForwardToIoQueue failed with status: %!STATUS!\n", status);
            WdfRequestComplete(hRequest, status);
        }
        break;

    case IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST:
        TraceInfo(DBG_IOCTL, "IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST\n");
        status = HidFx2SendIdleNotification(hRequest);
        if (!NT_SUCCESS(status))
        {
            TraceErr(DBG_IOCTL, "SendIdleNotification failed with status: %!STATUS!\n", status);
            WdfRequestComplete(hRequest, status);
        }
        break;

    case IOCTL_HID_GET_INPUT_REPORT:
        TraceInfo(DBG_IOCTL, "IOCTL_HID_GET_INPUT_REPORT\n");
        HidFx2GetInput(hRequest);
        WdfRequestComplete(hRequest, status);
        break;

    case IOCTL_HID_SET_OUTPUT_REPORT:
        TraceInfo(DBG_IOCTL, "IOCTL_HID_SET_OUTPUT_REPORT\n");
        status = HidFx2SetOutput(hRequest);
        WdfRequestComplete(hRequest, status);
        break;

    default:
        TraceInfo(DBG_IOCTL, "IOCTL Not Supported 0x%X\n", ulIoControlCode);
        status = STATUS_NOT_SUPPORTED;
        WdfRequestComplete(hRequest, status);
        break;
    }

    TraceVerbose(DBG_IOCTL, "(%!FUNC!) Exit\n");
    return;
}
Exemple #8
0
///////////////////////////////////////////////////////////////////////////////
//
//  BasicUsbEvtDeviceControl
//
//    This routine is called by the framework when there is a
//    device control request for us to process
//
//  INPUTS:
//
//      Queue    - Our default queue
//
//      Request  - A device control request
//
//      OutputBufferLength - The length of the output buffer
//
//      InputBufferLength  - The length of the input buffer
//
//      IoControlCode      - The operation being performed
//
//  OUTPUTS:
//
//      None.
//
//  RETURNS:
//
//      None.
//
//  IRQL:
//
//      This routine is called at IRQL == PASSIVE_LEVEL, due to
//      our PASSIVE_LEVEL execution level contraint
//
//  NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
VOID
BasicUsbEvtDeviceControl(WDFQUEUE Queue,
            WDFREQUEST Request,
            size_t OutputBufferLength,
            size_t InputBufferLength,
            ULONG IoControlCode)
{

    NTSTATUS                     status;
    WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket;
    WDFMEMORY                    inputMemory;
    WDF_MEMORY_DESCRIPTOR        inputMemoryDescriptor;
    PBASICUSB_DEVICE_CONTEXT     devContext;
   
#if DBG
    DbgPrint("BasicUsbEvtDeviceControl\n");
#endif

    devContext = BasicUsbGetContextFromDevice(
                                WdfIoQueueGetDevice(Queue) );

    switch (IoControlCode) {
        case IOCTL_OSR_BASICUSB_SET_BAR_GRAPH: {

            //
            // Validate the buffers for this request:
            //
            // OutputBufferLength - Must be zero
            //
            if (OutputBufferLength != 0) {
#if DBG
                DbgPrint("Invalid parameter - output buffer supplied in "\
                         "SET_BAR_GRAPH IOCTL (%u bytes)\n",
                         (ULONG)OutputBufferLength);
#endif
                WdfRequestComplete(Request, STATUS_INVALID_PARAMETER);
                return;
            }

            //
            // InputBufferLength  - Must be at least 1 byte
            //
            if (InputBufferLength == 0) {
#if DBG
                DbgPrint("No input buffer supplied in SET_BAR_GRAPH IOCTL\n");
#endif
                WdfRequestCompleteWithInformation(Request,
                                                  STATUS_BUFFER_TOO_SMALL,
                                                  sizeof(UCHAR));
                return;
            }

            //
            // We need the input memory from the request so that we can pass
            // it to the bus driver.
            //
            status = WdfRequestRetrieveInputMemory(Request,
                                                   &inputMemory);

            if (!NT_SUCCESS(status)) {
#if DBG
                DbgPrint("WdfRequestRetrieveInputMemory failed 0x%0x\n", status);
#endif
                WdfRequestComplete(Request, status);
                return;
            }

            //
            // The routine we want to call takes a memory descriptor, so
            // initialize that now with the handle to the user memory.
            //
            WDF_MEMORY_DESCRIPTOR_INIT_HANDLE(&inputMemoryDescriptor,
                                              inputMemory,
                                              NULL);

            //
            // Initialize the vendor command (defined by the device) that
            // allows us to light the bar graph.
            //
            WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(
                                               &controlSetupPacket,
                                               BmRequestHostToDevice,
                                               BmRequestToDevice,
                                               USBFX2LK_SET_BARGRAPH_DISPLAY,
                                               0,
                                               0);


            //
            // And send the vendor command as a control transfer. This
            // shouldn't take very long, so we'll just send it synchronously
            // to the device.
            //

            //
            // We've specified an execution level restraint of
            // PASSIVE_LEVEL, so we're allowed to send this request
            // synchronously.
            //
            ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
            status = WdfUsbTargetDeviceSendControlTransferSynchronously(
                                        devContext->BasicUsbUsbDevice,
                                        WDF_NO_HANDLE,
                                        NULL,
                                        &controlSetupPacket,
                                        &inputMemoryDescriptor,
                                        NULL);
            if (NT_SUCCESS(status)) {
                //
                // If the request succeeded, complete the request with success
                // and indicate to the user how much data was transferred (in
                // this case a single byte was sent to the device)
                //
                WdfRequestCompleteWithInformation(Request,
                                                  status,
                                                  sizeof(UCHAR));

            } else {
                //
                // Bad news! Just complete the request with the failure status.
                //
#if DBG
                DbgPrint("WdfUsbTargetDeviceSendControlTransferSynchronously "\
                         "failed 0x%0x\n", status); 
#endif

                WdfRequestComplete(Request, status);
            }
            return;
        }
        case IOCTL_OSR_BASICUSB_GET_SWITCHPACK_STATE: {

            //
            // Validate the buffers for this request:
            //
            // InputBufferLength - Must be zero
            //
            if (InputBufferLength != 0) {
#if DBG
                DbgPrint("Invalid parameter - input buffer supplied in "\
                         "SWITCHPACK_STATE_CHANGE_NOTIFY IOCTL (%u bytes)\n",
                         (ULONG)InputBufferLength);
#endif
                WdfRequestComplete(Request, STATUS_INVALID_PARAMETER);
                return;
            }

            //
            // OutputBufferLength  - Must be at least 1 byte
            //
            if (OutputBufferLength == 0) {
#if DBG
                DbgPrint("No input buffer supplied in "\
                         "SWITCHPACK_STATE_CHANGE_NOTIFY IOCTL\n"); 
#endif
                WdfRequestCompleteWithInformation(Request,
                                                  STATUS_BUFFER_TOO_SMALL,
                                                  sizeof(UCHAR));
                return;
            }

            //
            // Forward the request to our switchpack state change requests
            // queue
            //
            status = WdfRequestForwardToIoQueue(
                                        Request, 
                                        devContext->SwitchPackStateChangeQueue);


            if (!NT_SUCCESS(status)) {

                //
                // Bad news! Print out the status and fail the request.
                //
#if DBG
                DbgPrint("WdfRequestForwardToIoQueue failed with Status "\
                         "code 0x%x", status);
#endif
                WdfRequestComplete(Request, status);
                return;
            }
            return;
        }

        default:  {
#if DBG
            DbgPrint("Unknown IOCTL: 0x%x\n", IoControlCode);
#endif
            WdfRequestCompleteWithInformation(Request,
                                              STATUS_INVALID_DEVICE_REQUEST,
                                              0);
            return;
        }
    }

    return;
}
VOID
XenUsb_EvtIoInternalDeviceControl_ROOTHUB_SUBMIT_URB(
  WDFQUEUE queue,
  WDFREQUEST request,
  size_t output_buffer_length,
  size_t input_buffer_length,
  ULONG io_control_code)
{
  //NTSTATUS status;
  WDFDEVICE device = WdfIoQueueGetDevice(queue);
  PXENUSB_PDO_DEVICE_DATA xupdd = GetXupdd(device);
  PXENUSB_DEVICE_DATA xudd = GetXudd(xupdd->wdf_device_bus_fdo);
  WDF_REQUEST_PARAMETERS wrp;
  PURB urb;
  PUSBD_INTERFACE_INFORMATION interface_information;
  ULONG i, j;
  xenusb_device_t *usb_device;
  xenusb_endpoint_t *endpoint;
  //USB_DEFAULT_PIPE_SETUP_PACKET setup_packet;
  urb_decode_t decode_data;
  ULONG decode_retval;

  UNREFERENCED_PARAMETER(input_buffer_length);
  UNREFERENCED_PARAMETER(output_buffer_length);
  UNREFERENCED_PARAMETER(io_control_code);

  //FUNCTION_ENTER();

  WDF_REQUEST_PARAMETERS_INIT(&wrp);
  WdfRequestGetParameters(request, &wrp);

  urb = (PURB)wrp.Parameters.Others.Arg1;
  ASSERT(urb);
#if 0
  FUNCTION_MSG("urb = %p\n", urb);
  FUNCTION_MSG(" Length = %d\n", urb->UrbHeader.Length);
  FUNCTION_MSG(" Function = %d\n", urb->UrbHeader.Function);
  FUNCTION_MSG(" Status = %d\n", urb->UrbHeader.Status);
  FUNCTION_MSG(" UsbdDeviceHandle = %p\n", urb->UrbHeader.UsbdDeviceHandle);
  FUNCTION_MSG(" UsbdFlags = %08x\n", urb->UrbHeader.UsbdFlags);
#endif
  usb_device = urb->UrbHeader.UsbdDeviceHandle;

  if (!usb_device)
    usb_device = xupdd->usb_device;

  decode_retval = XenUsb_DecodeControlUrb(urb, &decode_data);
  if (decode_retval == URB_DECODE_UNKNOWN)
  {
    FUNCTION_MSG("Unknown URB - Calling WdfRequestCompletestatus with status = %08x\n", STATUS_UNSUCCESSFUL); //STATUS_UNSUCCESSFUL);
    urb->UrbHeader.Status = USBD_STATUS_INVALID_URB_FUNCTION;
    WdfRequestComplete(request, STATUS_UNSUCCESSFUL);
    return;
  }

  urb->UrbHeader.Status = USBD_STATUS_INVALID_URB_FUNCTION;
  
  if (decode_retval != URB_DECODE_NOT_CONTROL)
  {
    FUNCTION_MSG("bmRequestType = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.B);
    FUNCTION_MSG(" Recipient = %x\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient);
    FUNCTION_MSG(" Type = %x\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Type);
    FUNCTION_MSG(" Dir = %x\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Dir);
    FUNCTION_MSG("bRequest = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.bRequest);
    FUNCTION_MSG("wValue = %04x\n", decode_data.setup_packet.default_pipe_setup_packet.wValue.W);
    FUNCTION_MSG(" Low = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.wValue.LowByte);
    FUNCTION_MSG(" High = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.wValue.HiByte);
    FUNCTION_MSG("wIndex = %04x\n", decode_data.setup_packet.default_pipe_setup_packet.wIndex);
    FUNCTION_MSG(" Low = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte);
    FUNCTION_MSG(" High = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.wIndex.HiByte);
    FUNCTION_MSG("wLength = %04x\n", decode_data.setup_packet.default_pipe_setup_packet.wLength);
  }
  
  switch(urb->UrbHeader.Function)
  {
  case URB_FUNCTION_SELECT_CONFIGURATION:
    FUNCTION_MSG("URB_FUNCTION_SELECT_CONFIGURATION\n");
    FUNCTION_MSG(" ConfigurationDescriptor = %p\n", urb->UrbSelectConfiguration.ConfigurationDescriptor);
    if (urb->UrbSelectConfiguration.ConfigurationDescriptor)
    {
      FUNCTION_MSG("  bLength = %d\n", urb->UrbSelectConfiguration.ConfigurationDescriptor->bLength);
      FUNCTION_MSG("  bDescriptorType = %d\n", urb->UrbSelectConfiguration.ConfigurationDescriptor->bDescriptorType);
      FUNCTION_MSG("  wTotalLength = %d\n", urb->UrbSelectConfiguration.ConfigurationDescriptor->wTotalLength);
      FUNCTION_MSG("  bNumInterfaces = %d\n", urb->UrbSelectConfiguration.ConfigurationDescriptor->bNumInterfaces);
      FUNCTION_MSG("  bConfigurationValue = %d\n", urb->UrbSelectConfiguration.ConfigurationDescriptor->bConfigurationValue);
      FUNCTION_MSG("  iConfiguration = %d\n", urb->UrbSelectConfiguration.ConfigurationDescriptor->iConfiguration);
      FUNCTION_MSG("  bmAttributes = %04x\n", urb->UrbSelectConfiguration.ConfigurationDescriptor->bmAttributes);
      FUNCTION_MSG("  MaxPower = %d\n", urb->UrbSelectConfiguration.ConfigurationDescriptor->MaxPower);
    }
    FUNCTION_MSG(" ConfigurationHandle = %p\n", urb->UrbSelectConfiguration.ConfigurationHandle);
    if (urb->UrbSelectConfiguration.ConfigurationDescriptor)
    {
      urb->UrbSelectConfiguration.ConfigurationHandle = xupdd->usb_device->configs[0];
      interface_information = &urb->UrbSelectConfiguration.Interface;
      for (i = 0; i < urb->UrbSelectConfiguration.ConfigurationDescriptor->bNumInterfaces; i++)
      {
        FUNCTION_MSG("InterfaceInformation[%d]\n", i);
        FUNCTION_MSG(" Length = %d\n", interface_information->Length);
        FUNCTION_MSG(" InterfaceNumber = %d\n", interface_information->InterfaceNumber);
        FUNCTION_MSG(" AlternateSetting = %d\n", interface_information->AlternateSetting);
        FUNCTION_MSG(" Class = %02x\n", (ULONG)interface_information->Class);
        FUNCTION_MSG(" SubClass = %02x\n", (ULONG)interface_information->SubClass);
        FUNCTION_MSG(" Protocol = %02x\n", (ULONG)interface_information->Protocol);
        FUNCTION_MSG(" Reserved = %02x\n", (ULONG)interface_information->Reserved);
        FUNCTION_MSG(" InterfaceHandle = %p\n", interface_information->InterfaceHandle);
        FUNCTION_MSG(" NumberOfPipes = %d\n", interface_information->NumberOfPipes);
        interface_information->InterfaceHandle = xupdd->usb_device->configs[0]->interfaces[0];
        interface_information->Class = 0x09;
        interface_information->SubClass = 0x00;
        interface_information->SubClass = 0x00;
        for (j = 0; j < interface_information->NumberOfPipes; j++)
        {
          FUNCTION_MSG(" Pipe[%d]\n", i);
          FUNCTION_MSG("  MaximumPacketSize = %d\n", interface_information->Pipes[j].MaximumPacketSize);
          FUNCTION_MSG("  EndpointAddress = %d\n", interface_information->Pipes[j].EndpointAddress);
          FUNCTION_MSG("  Interval = %d\n", interface_information->Pipes[j].Interval);
          FUNCTION_MSG("  PipeType = %d\n", interface_information->Pipes[j].PipeType);
          FUNCTION_MSG("  PipeHandle = %d\n", interface_information->Pipes[j].PipeHandle);
          FUNCTION_MSG("  MaximumTransferSize = %d\n", interface_information->Pipes[j].MaximumTransferSize);
          FUNCTION_MSG("  PipeFlags = %08x\n", interface_information->Pipes[j].PipeFlags);
          interface_information->Pipes[j].MaximumPacketSize = 2;
          interface_information->Pipes[j].EndpointAddress = 0x81;
          interface_information->Pipes[j].Interval = 12;
          interface_information->Pipes[j].PipeType = UsbdPipeTypeInterrupt;
          interface_information->Pipes[j].PipeHandle = xupdd->usb_device->configs[0]->interfaces[0]->endpoints[j];
          interface_information->Pipes[j].MaximumTransferSize = 4096; /* made up number - possibly not used */
          // this is input actually interface_information->Pipes[j].PipeFlags = 0;
        }
        interface_information = (PUSBD_INTERFACE_INFORMATION)((PUCHAR)interface_information + interface_information->Length);
      }
    }
    urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
    break;
  case URB_FUNCTION_SELECT_INTERFACE:
    FUNCTION_MSG("URB_FUNCTION_SELECT_INTERFACE\n");
    interface_information = &urb->UrbSelectInterface.Interface;
    FUNCTION_MSG("InterfaceInformation\n");
    FUNCTION_MSG(" Length = %d\n", interface_information->Length);
    FUNCTION_MSG(" InterfaceNumber = %d\n", interface_information->InterfaceNumber);
    FUNCTION_MSG(" AlternateSetting = %d\n", interface_information->AlternateSetting);
    FUNCTION_MSG(" Class = %02x\n", (ULONG)interface_information->Class);
    FUNCTION_MSG(" SubClass = %02x\n", (ULONG)interface_information->SubClass);
    FUNCTION_MSG(" Protocol = %02x\n", (ULONG)interface_information->Protocol);
    FUNCTION_MSG(" Reserved = %02x\n", (ULONG)interface_information->Reserved);
    FUNCTION_MSG(" InterfaceHandle = %p\n", interface_information->InterfaceHandle);
    FUNCTION_MSG(" NumberOfPipes = %d\n", interface_information->NumberOfPipes);
    for (i = 0; i < interface_information->NumberOfPipes; i++)
    {
      FUNCTION_MSG(" Pipe[%d]\n", i);
      FUNCTION_MSG("  MaximumPacketSize = %d\n", interface_information->Pipes[i].MaximumPacketSize);
      FUNCTION_MSG("  EndpointAddress = %d\n", interface_information->Pipes[i].EndpointAddress);
      FUNCTION_MSG("  Interval = %d\n", interface_information->Pipes[i].Interval);
      FUNCTION_MSG("  PipeType = %d\n", interface_information->Pipes[i].PipeType);
      FUNCTION_MSG("  PipeHandle = %d\n", interface_information->Pipes[i].PipeHandle);
      FUNCTION_MSG("  MaximumTransferSize = %d\n", interface_information->Pipes[i].MaximumTransferSize);
      FUNCTION_MSG("  PipeFlags = %08x\n", interface_information->Pipes[i].PipeFlags);
    }
    urb->UrbHeader.Status = USBD_STATUS_INVALID_URB_FUNCTION;
    break;
#if (NTDDI_VERSION >= NTDDI_VISTA)  
  case URB_FUNCTION_CONTROL_TRANSFER_EX:
#endif
  case URB_FUNCTION_CONTROL_TRANSFER:
  case URB_FUNCTION_CLASS_DEVICE:
  case URB_FUNCTION_CLASS_OTHER:
  case URB_FUNCTION_CLASS_INTERFACE:
  case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
  case URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE:
  case URB_FUNCTION_GET_STATUS_FROM_DEVICE:
    switch(decode_data.setup_packet.default_pipe_setup_packet.bRequest)
    {
    case USB_REQUEST_GET_STATUS:
      // switch device, interface, endpoint
      switch (decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Type)
      {
      case BMREQUEST_STANDARD:
        FUNCTION_MSG(" USB_REQUEST_GET_STATUS\n");
        FUNCTION_MSG(" Type=Standard\n");
        switch (decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient)
        {
        case BMREQUEST_TO_DEVICE:
          FUNCTION_MSG("  Recipient=Device\n");
          ((PUSHORT)decode_data.buffer)[0] = 0x0001; /* self powered */
          urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
          break;
        default:
          FUNCTION_MSG(" Recipient=%d\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient);
          break;
        }
        break;
      case BMREQUEST_CLASS:
        switch (decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient)
        {
        case BMREQUEST_TO_DEVICE:
          ((PUSHORT)decode_data.buffer)[0] = 0x0000;
          ((PUSHORT)decode_data.buffer)[1] = 0x0000;
          urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
          break;
        case BMREQUEST_TO_OTHER:
          FUNCTION_MSG(" USB_REQUEST_GET_STATUS\n");
          FUNCTION_MSG(" Type=Class\n");
          FUNCTION_MSG("  Recipient=Other (port = %d)\n", decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte);
          ((PUSHORT)decode_data.buffer)[0] = xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_status;
          ((PUSHORT)decode_data.buffer)[1] = xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_change;
          urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
          FUNCTION_MSG(" status = %04x, change = %04x\n",
            xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_status,
            xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_change);
          break;
        default:
          FUNCTION_MSG(" USB_REQUEST_GET_STATUS\n");
          FUNCTION_MSG(" Type=Class\n");
          FUNCTION_MSG(" Recipient=%d\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient);
          break;
        }
        break;
      default:
        FUNCTION_MSG(" USB_REQUEST_GET_STATUS\n");
        FUNCTION_MSG(" Type=%d\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Type);
        break;
      }
      break;      
    case USB_REQUEST_GET_DESCRIPTOR:
      FUNCTION_MSG(" USB_REQUEST_GET_DESCRIPTOR\n");
      // should separate into Standard and Class
      switch (decode_data.setup_packet.default_pipe_setup_packet.wValue.HiByte)
      {
      case USB_DEVICE_DESCRIPTOR_TYPE:
        FUNCTION_MSG(" USB_DEVICE_DESCRIPTOR_TYPE\n");
        FUNCTION_MSG(" length = %d\n", *decode_data.length);
        memcpy(decode_data.buffer, &usb_device->device_descriptor, sizeof(USB_DEVICE_DESCRIPTOR));
        *decode_data.length = sizeof(USB_DEVICE_DESCRIPTOR);
        urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
        break;
      case USB_CONFIGURATION_DESCRIPTOR_TYPE:
      {
        xenusb_config_t *usb_config;
        PUCHAR ptr;

        FUNCTION_MSG(" USB_CONFIGURATION_DESCRIPTOR_TYPE\n");
        FUNCTION_MSG(" length = %d\n", *decode_data.length);
        usb_config = usb_device->active_config;
        ptr = (PUCHAR)decode_data.buffer;
        memcpy(ptr, &usb_config->config_descriptor, sizeof(USB_CONFIGURATION_DESCRIPTOR));
        ptr += sizeof(USB_CONFIGURATION_DESCRIPTOR);
        ((PUSB_CONFIGURATION_DESCRIPTOR)decode_data.buffer)->wTotalLength = sizeof(USB_CONFIGURATION_DESCRIPTOR);
        if (*decode_data.length > 9)
        {
          for (i = 0; i < usb_config->config_descriptor.bNumInterfaces; i++)
          {
            memcpy(ptr, &usb_config->interfaces[i]->interface_descriptor, sizeof(USB_INTERFACE_DESCRIPTOR));
            ptr += sizeof(USB_INTERFACE_DESCRIPTOR);
            ((PUSB_CONFIGURATION_DESCRIPTOR)decode_data.buffer)->wTotalLength += sizeof(USB_INTERFACE_DESCRIPTOR);
            for (j = 0; j < usb_config->interfaces[i]->interface_descriptor.bNumEndpoints; j++)
            {
              memcpy(ptr, &usb_config->interfaces[i]->endpoints[j]->endpoint_descriptor, sizeof(USB_ENDPOINT_DESCRIPTOR));
              ptr += sizeof(USB_ENDPOINT_DESCRIPTOR);
              ((PUSB_CONFIGURATION_DESCRIPTOR)decode_data.buffer)->wTotalLength += sizeof(USB_ENDPOINT_DESCRIPTOR);
            }
          }
        }
        *decode_data.length = ((PUSB_CONFIGURATION_DESCRIPTOR)decode_data.buffer)->wTotalLength;
        //if (urb->UrbControlDescriptorRequest.TransferBufferLength == 9)
        //  ((PUSB_CONFIGURATION_DESCRIPTOR)decode_data.buffer)->wTotalLength = 32;
        urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
        break;
      } 
      case 0x00: // unknown... doing the same as 0x29 seems to work
        FUNCTION_MSG(" USB_00_DESCRIPTOR_TYPE (doesn't exist)\n");
        urb->UrbHeader.Status = USBD_STATUS_BAD_DESCRIPTOR;
        break;
      case 0x29: // Hub Descriptor
      {
        PUSB_HUB_DESCRIPTOR uhd;
        
        FUNCTION_MSG(" USB_HUB_DESCRIPTOR_TYPE\n", decode_data.setup_packet.default_pipe_setup_packet.wValue.HiByte);
        FUNCTION_MSG(" length = %d\n", *decode_data.length);
        uhd = decode_data.buffer;
        // TODO adjust for real number of ports
        *decode_data.length = FIELD_OFFSET(USB_HUB_DESCRIPTOR, bRemoveAndPowerMask[0]) + 2 + 1;
        uhd->bDescriptorLength = (UCHAR)*decode_data.length;
        uhd->bDescriptorType = 0x29;
        uhd->bNumberOfPorts = (UCHAR)xudd->num_ports;
        uhd->wHubCharacteristics = 0x0012; // no power switching no overcurrent protection
        uhd->bPowerOnToPowerGood = 1; // 2ms units
        uhd->bHubControlCurrent = 0;
        // DeviceRemovable bits (includes an extra bit at the start)
        uhd->bRemoveAndPowerMask[0] = 0;
        uhd->bRemoveAndPowerMask[1] = 0;
        // PortPwrCtrlMask
        uhd->bRemoveAndPowerMask[2] = 0xFF;
        urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
        break;
      }
      default:
        FUNCTION_MSG(" USB_%02x_DESCRIPTOR_TYPE\n", (ULONG)decode_data.setup_packet.default_pipe_setup_packet.wValue.HiByte);
        FUNCTION_MSG("bmRequestType = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.B);
        FUNCTION_MSG(" Recipient = %x\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient);
        FUNCTION_MSG(" Type = %x\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Type);
        FUNCTION_MSG(" Dir = %x\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Dir);
        FUNCTION_MSG("bRequest = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.bRequest);
        FUNCTION_MSG("wValue = %04x\n", decode_data.setup_packet.default_pipe_setup_packet.wValue.W);
        FUNCTION_MSG(" Low = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.wValue.LowByte);
        FUNCTION_MSG(" High = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.wValue.HiByte);
        FUNCTION_MSG("wIndex = %04x\n", decode_data.setup_packet.default_pipe_setup_packet.wIndex);
        FUNCTION_MSG(" Low = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte);
        FUNCTION_MSG(" High = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.wIndex.HiByte);
        FUNCTION_MSG("wLength = %04x\n", decode_data.setup_packet.default_pipe_setup_packet.wLength);
        break;
      }
      break;
    case USB_REQUEST_CLEAR_FEATURE:
      FUNCTION_MSG(" USB_REQUEST_CLEAR_FEATURE\n");
      switch (decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Type)
      {
      case BMREQUEST_STANDARD: /* Standard */
        FUNCTION_MSG("  Type=Standard\n");
        switch (decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient)
        {
        case BMREQUEST_TO_DEVICE:
          FUNCTION_MSG("  Recipient=Device\n");
          switch (decode_data.setup_packet.default_pipe_setup_packet.wValue.W)
          {
          case 1: /* DEVICE_REMOTE_WAKEUP */
            FUNCTION_MSG("  Feature=DEVICE_REMOTE_WAKEUP\n");
            /* fake this */
            urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
            break;
          default:
            FUNCTION_MSG(__DRIVER_NAME "       Feature=%d (not valid)\n", decode_data.setup_packet.default_pipe_setup_packet.wValue.W);
            break;
          }
          break;
        default:
          FUNCTION_MSG(__DRIVER_NAME "       Recipient=%d (not valid)\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient);
          break;
        }
        break;
        break;
      case BMREQUEST_CLASS: /* Class */
        FUNCTION_MSG("  Type=Class\n");
        switch (decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient)
        {
        case BMREQUEST_TO_OTHER:
          FUNCTION_MSG("  Recipient=Other (port = %d)\n", decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte);
          switch (urb->UrbControlVendorClassRequest.Value)
          {
          case PORT_ENABLE:
            FUNCTION_MSG("   PORT_ENABLE\n");
            xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_status &= ~(1 << PORT_ENABLE);
            urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
            break;
          case PORT_SUSPEND:
            FUNCTION_MSG("   PORT_SUSPEND (NOOP)\n");
            /* do something here */
            urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
            break;
          case C_PORT_CONNECTION:
            FUNCTION_MSG("   C_PORT_CONNECTION\n");
            xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_change &= ~(1 << PORT_CONNECTION);
            urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
            break;
          case C_PORT_ENABLE:
            FUNCTION_MSG("   C_PORT_ENABLE\n");
            xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_change &= ~(1 << PORT_ENABLE);
            urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
            break;
          case C_PORT_RESET:
            FUNCTION_MSG("   C_PORT_RESET\n");
            xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_change &= ~(1 << PORT_RESET);
            urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
            break;
          default:
            FUNCTION_MSG("   Unknown Value %04X\n", urb->UrbControlVendorClassRequest.Value);
            break;
          }
          FUNCTION_MSG("   status = %04x, change = %04x\n",
            xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_status,
            xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_change);
          break;
        default:
          FUNCTION_MSG(" Recipient=%d\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient);
          break;
        }
        break;
      default:
        FUNCTION_MSG("  Type=%d\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Type);
        break;
      }
      break;
    case USB_REQUEST_SET_FEATURE:
      FUNCTION_MSG(" USB_REQUEST_SET_FEATURE\n");
      FUNCTION_MSG("  SetPortFeature\n");
      switch (decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Type)
      {
      case 0: /* Standard */
        FUNCTION_MSG("  Type=Standard\n");
        switch (decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient)
        {
        case BMREQUEST_TO_DEVICE:
          FUNCTION_MSG("  Recipient=Device\n");
          switch (decode_data.setup_packet.default_pipe_setup_packet.wValue.W)
          {
          case 1: /* DEVICE_REMOTE_WAKEUP */
            FUNCTION_MSG("  Feature=DEVICE_REMOTE_WAKEUP\n");
            /* fake this */
            urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
            break;
          default:
            FUNCTION_MSG(__DRIVER_NAME "       Feature=%d (not valid)\n", decode_data.setup_packet.default_pipe_setup_packet.wValue.W);
            break;
          }
          break;
        default:
          FUNCTION_MSG(__DRIVER_NAME "       Recipient=%d (not valid)\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient);
          break;
        }
        break;
      case 1: /* Class */
        FUNCTION_MSG("  Type=Class\n");
        switch (decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient)
        {
        case BMREQUEST_TO_OTHER:
          FUNCTION_MSG("  Recipient=Other (port = %d)\n", decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte);
          switch (decode_data.setup_packet.default_pipe_setup_packet.wValue.W)
          {
          case PORT_ENABLE:
            FUNCTION_MSG("   PORT_ENABLE (NOOP)\n");
            /* do something here */
            urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
            break;
          case PORT_SUSPEND:
            FUNCTION_MSG("   PORT_SUSPEND (NOOP)\n");
            /* do something here */
            urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
            break;
          case PORT_RESET:
            FUNCTION_MSG("   PORT_RESET\n");
            /* just fake the reset by setting the status bit to indicate that the reset is complete*/
            //xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_status |= (1 << PORT_RESET);
            //xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].reset_counter = 10;
            // TODO: maybe fake a 10ms time here...
            xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_status &= ~(1 << PORT_RESET);
            xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_status |= (1 << PORT_ENABLE);
            xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_change |= (1 << PORT_RESET);
            urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
            endpoint = xupdd->usb_device->configs[0]->interfaces[0]->endpoints[0];
            XenUsbHub_ProcessHubInterruptEvent(endpoint);
            break;
          case PORT_POWER:
            FUNCTION_MSG("   PORT_POWER\n");
            xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_status |= (1 << PORT_POWER);
            urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
            break;
          default:
            FUNCTION_MSG("   PORT_%04X\n", decode_data.setup_packet.default_pipe_setup_packet.wValue.W);
            break;
          }
          FUNCTION_MSG("   status = %04x, change = %04x\n",
            xudd->ports[urb->UrbControlVendorClassRequest.Index - 1].port_status,
            xudd->ports[urb->UrbControlVendorClassRequest.Index - 1].port_change);
          break;
        default:
          FUNCTION_MSG(__DRIVER_NAME "       Recipient=%d (not valid)\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient);
          break;
        }
        break;
      }
      break;
    default:
      FUNCTION_MSG(" USB_REQUEST_%02x\n", (ULONG)decode_data.setup_packet.default_pipe_setup_packet.bRequest);
      FUNCTION_MSG(" TransferBufferLength returned = %d\n", urb->UrbControlDescriptorRequest.TransferBufferLength);
      break;
    }
    break;
  case URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL:
    FUNCTION_MSG("URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL\n");
    FUNCTION_MSG(" PipeHandle = %p\n", urb->UrbPipeRequest.PipeHandle);
    urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
    break;
  case URB_FUNCTION_ABORT_PIPE:
    FUNCTION_MSG("URB_FUNCTION_ABORT_PIPE\n");
    FUNCTION_MSG(" PipeHandle = %p\n", urb->UrbPipeRequest.PipeHandle);
    urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
    break;
  case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER: /* 11.12.4 */
#if 0
    FUNCTION_MSG("URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER\n");
    FUNCTION_MSG(" PipeHandle = %p\n", urb->UrbBulkOrInterruptTransfer.PipeHandle);
    FUNCTION_MSG(" TransferFlags = %08x\n", urb->UrbBulkOrInterruptTransfer.TransferFlags);
    FUNCTION_MSG(" TransferBufferLength = %d\n", urb->UrbBulkOrInterruptTransfer.TransferBufferLength);
    FUNCTION_MSG(" TransferBuffer = %p\n", urb->UrbBulkOrInterruptTransfer.TransferBuffer);
    FUNCTION_MSG(" TransferBufferMdl = %p\n", urb->UrbBulkOrInterruptTransfer.TransferBufferMDL);
#endif
    endpoint = urb->UrbBulkOrInterruptTransfer.PipeHandle;
    //WdfSpinLockAcquire(endpoint->lock);
    WdfRequestForwardToIoQueue(request, endpoint->queue);
    XenUsbHub_ProcessHubInterruptEvent(endpoint);
    //WdfSpinLockRelease(endpoint->lock);
    //FUNCTION_EXIT();
    return;
    
  default:
    FUNCTION_MSG("URB_FUNCTION_%04x\n", urb->UrbHeader.Function);
    if (decode_retval != URB_DECODE_NOT_CONTROL)
    {
      FUNCTION_MSG("bmRequestType = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.B);
      FUNCTION_MSG(" Recipient = %x\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient);
      FUNCTION_MSG(" Type = %x\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Type);
      FUNCTION_MSG(" Dir = %x\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Dir);
      FUNCTION_MSG("bRequest = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.bRequest);
      FUNCTION_MSG("wValue = %04x\n", decode_data.setup_packet.default_pipe_setup_packet.wValue.W);
      FUNCTION_MSG(" Low = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.wValue.LowByte);
      FUNCTION_MSG(" High = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.wValue.HiByte);
      FUNCTION_MSG("wIndex = %04x\n", decode_data.setup_packet.default_pipe_setup_packet.wIndex);
      FUNCTION_MSG(" Low = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte);
      FUNCTION_MSG(" High = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.wIndex.HiByte);
      FUNCTION_MSG("wLength = %04x\n", decode_data.setup_packet.default_pipe_setup_packet.wLength);
    }
    urb->UrbHeader.Status = USBD_STATUS_INVALID_URB_FUNCTION;
    break;
  }
  if (urb->UrbHeader.Status == USBD_STATUS_SUCCESS)
  {
    //FUNCTION_MSG("Calling WdfRequestCompletestatus with status = %08x\n", STATUS_SUCCESS);
    WdfRequestComplete(request, STATUS_SUCCESS);
  }
  else
  {
    FUNCTION_MSG("Calling WdfRequestCompletestatus with status = %08x\n", STATUS_UNSUCCESSFUL);
    WdfRequestComplete(request, STATUS_UNSUCCESSFUL);
  }

  //FUNCTION_EXIT();
  return;
}
Exemple #10
0
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;
}
Exemple #11
0
BOOLEAN
NICEvtProgramDmaFunction(
    IN  WDFDMATRANSACTION       Transaction,
    IN  WDFDEVICE               Device,
    IN  PVOID                   Context,
    IN  WDF_DMA_DIRECTION       Direction,
    IN  PSCATTER_GATHER_LIST    ScatterGather
    )
/*++

Routine Description:

Arguments:

Return Value:

--*/
{
    PFDO_DATA           fdoData;
    WDFREQUEST          request;
    NTSTATUS            status;

    UNREFERENCED_PARAMETER( Context );
    UNREFERENCED_PARAMETER( Direction );

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,
                "--> NICEvtProgramDmaFunction\n");

    fdoData = FdoGetData(Device);
    request = WdfDmaTransactionGetRequest(Transaction);


    WdfSpinLockAcquire(fdoData->SendLock);

    //
    // If tcb or link is not available, queue the request
    //
    if (!MP_TCB_RESOURCES_AVAIABLE(fdoData))
    {
        TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,
                "Resource is not available: queue Request %p\n", request);

        //
        // Must abort the transaction before deleting.
        //
        (VOID) WdfDmaTransactionDmaCompletedFinal(Transaction, 0, &status);
        ASSERT(NT_SUCCESS(status));
        WdfObjectDelete( Transaction );

        //
        // Queue the request for later processing.
        //
        status = WdfRequestForwardToIoQueue(request,
                                           fdoData->PendingWriteQueue);

        if(!NT_SUCCESS(status)) {
            ASSERTMSG(" WdfRequestForwardToIoQueue failed ", FALSE);
            WdfSpinLockRelease(fdoData->SendLock);
            WdfRequestCompleteWithInformation(request, STATUS_UNSUCCESSFUL, 0);
            return FALSE;
        }
        fdoData->nWaitSend++;

    } else {

        status = NICWritePacket(fdoData, Transaction, ScatterGather);

        if(!NT_SUCCESS(status)) {
            TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE,
                        "<-- NICEvtProgramDmaFunction returning %!STATUS!\n",
                        status);
            //
            // Must abort the transaction before deleting.
            //
            (VOID )WdfDmaTransactionDmaCompletedFinal(Transaction, 0, &status);
            ASSERT(NT_SUCCESS(status));
            WdfObjectDelete( Transaction );

            WdfSpinLockRelease(fdoData->SendLock);
            WdfRequestCompleteWithInformation(request, STATUS_UNSUCCESSFUL, 0);
            return FALSE;
        }
    }


    WdfSpinLockRelease(fdoData->SendLock);

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,
                "<-- NICEvtProgramDmaFunction\n");

    return TRUE;
}
VOID
NdisProtEvtIoDeviceControl(
    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

--*/
{
    NTSTATUS                NtStatus;
    NDIS_STATUS             Status;
    PNDISPROT_OPEN_CONTEXT  pOpenContext;
    ULONG                   BytesReturned;
    PVOID                   sysBuffer;
    WDFFILEOBJECT           fileObject = WdfRequestGetFileObject(Request);
    size_t                  bufSize;

    UNREFERENCED_PARAMETER(Queue);
    UNREFERENCED_PARAMETER(OutputBufferLength);
    UNREFERENCED_PARAMETER(InputBufferLength);

    DEBUGP(DL_LOUD, ("IoControl: Irp %p\n", Request));

    pOpenContext = GetFileObjectContext(fileObject)->OpenContext;

    BytesReturned = 0;


    switch (IoControlCode)
    {
        case IOCTL_NDISPROT_BIND_WAIT:
            //
            //  Block until we have seen a NetEventBindsComplete event,
            //  meaning that we have finished binding to all running
            //  adapters that we are supposed to bind to.
            //
            //  If we don't get this event in 5 seconds, time out.
            //
            NPROT_ASSERT((IoControlCode & 0x3) == METHOD_BUFFERED);

            if (NPROT_WAIT_EVENT(&Globals.BindsComplete, 5000))
            {
                NtStatus = STATUS_SUCCESS;
            }
            else
            {
                NtStatus = STATUS_TIMEOUT;
            }
            DEBUGP(DL_INFO, ("IoControl: BindWait returning %x\n", NtStatus));
            break;

        case IOCTL_NDISPROT_QUERY_BINDING:

            NPROT_ASSERT((IoControlCode & 0x3) == METHOD_BUFFERED);

            NtStatus = WdfRequestRetrieveOutputBuffer(Request,
                                        sizeof(NDISPROT_QUERY_BINDING),
                                        &sysBuffer,
                                        &bufSize);
            if( !NT_SUCCESS(NtStatus) ) {
                DEBUGP(DL_FATAL, ("WdfRequestRetrieveOutputBuffer failed %x\n", NtStatus));
                break;
            }

            Status = ndisprotQueryBinding(
                            sysBuffer,
                            (ULONG) bufSize,
                            (ULONG) bufSize,
                            &BytesReturned
                            );

            NDIS_STATUS_TO_NT_STATUS(Status, &NtStatus);

            DEBUGP(DL_LOUD, ("IoControl: QueryBinding returning %x\n", NtStatus));

            break;

        case IOCTL_NDISPROT_OPEN_DEVICE:

            NPROT_ASSERT((IoControlCode & 0x3) == METHOD_BUFFERED);
            if (pOpenContext != NULL)
            {
                NPROT_STRUCT_ASSERT(pOpenContext, oc);
                DEBUGP(DL_WARN, ("IoControl: OPEN_DEVICE: FileObj %p already"
                    " associated with open %p\n", fileObject, pOpenContext));

                NtStatus = STATUS_DEVICE_BUSY;
                break;
            }

            NtStatus = WdfRequestRetrieveInputBuffer(Request,
                                        0,
                                        &sysBuffer,
                                        &bufSize);
            if( !NT_SUCCESS(NtStatus) ) {
                DEBUGP(DL_FATAL, ("WdfRequestRetrieveInputBuffer failed %x\n", NtStatus));
                break;
            }

            NtStatus = ndisprotOpenDevice(
                            sysBuffer,
                            (ULONG)bufSize,
                            fileObject,
                            &pOpenContext
                            );

            if (NT_SUCCESS(NtStatus))
            {

                DEBUGP(DL_VERY_LOUD, ("IoControl OPEN_DEVICE: Open %p <-> FileObject %p\n",
                        pOpenContext,  fileObject));
            }

            break;

        case IOCTL_NDISPROT_QUERY_OID_VALUE:

            NPROT_ASSERT((IoControlCode & 0x3) == METHOD_BUFFERED);

            NtStatus = WdfRequestRetrieveOutputBuffer(Request,
                                        sizeof(NDISPROT_QUERY_OID),
                                        &sysBuffer,
                                        &bufSize);
            if( !NT_SUCCESS(NtStatus) ) {
                DEBUGP(DL_FATAL, ("WdfRequestRetrieveOutputBuffer failed %x\n", NtStatus));
                break;
            }

            if (pOpenContext != NULL)
            {
                Status = ndisprotQueryOidValue(
                            pOpenContext,
                            sysBuffer,
                            (ULONG)bufSize,
                            &BytesReturned
                            );

                NDIS_STATUS_TO_NT_STATUS(Status, &NtStatus);
            }
            else
            {
                NtStatus = STATUS_DEVICE_NOT_CONNECTED;
            }
            break;

        case IOCTL_NDISPROT_SET_OID_VALUE:

            NPROT_ASSERT((IoControlCode & 0x3) == METHOD_BUFFERED);

            NtStatus = WdfRequestRetrieveInputBuffer(Request,
                                        sizeof(NDISPROT_SET_OID),
                                        &sysBuffer,
                                        &bufSize);
            if( !NT_SUCCESS(NtStatus) ) {
                DEBUGP(DL_FATAL, ("WdfRequestRetrieveInputBuffer failed %x\n", NtStatus));
                break;
            }


            if (pOpenContext != NULL)
            {
                Status = ndisprotSetOidValue(
                            pOpenContext,
                            sysBuffer,
                            (ULONG)bufSize
                            );

                BytesReturned = 0;

                NDIS_STATUS_TO_NT_STATUS(Status, &NtStatus);
            }
            else
            {
                NtStatus = STATUS_DEVICE_NOT_CONNECTED;
            }
            break;

        case IOCTL_NDISPROT_INDICATE_STATUS:

            NPROT_ASSERT((IoControlCode & 0x3) == METHOD_BUFFERED);

            if (pOpenContext != NULL)
            {
                NtStatus = WdfRequestForwardToIoQueue(Request,
                                            pOpenContext->StatusIndicationQueue
                                            );
                if(NT_SUCCESS(NtStatus)) {
                    NtStatus = STATUS_PENDING;
                }
            }
            else
            {
                NtStatus = STATUS_DEVICE_NOT_CONNECTED;
            }
            break;

         default:

            NtStatus = STATUS_NOT_SUPPORTED;
            break;
    }

    if (NtStatus != STATUS_PENDING)
    {
        WdfRequestCompleteWithInformation(Request, NtStatus, BytesReturned);
    }

    return;
}
Exemple #13
0
VOID
vJoy_EvtIoDeviceControlForRawPdo(
    IN WDFQUEUE      Queue,
    IN WDFREQUEST    Request,
    IN size_t        OutputBufferLength,
    IN size_t        InputBufferLength,
    IN ULONG         IoControlCode
    )
/*++

Routine Description:

    This routine is the dispatch routine for device control requests.

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

--*/
{
    NTSTATUS status = STATUS_SUCCESS;
    WDFDEVICE parent;
    WDF_REQUEST_FORWARD_OPTIONS forwardOptions;
    PDEVICE_EXTENSION    pDevContext = NULL;
	WDFMEMORY  inMemory, outMemory;
    PVOID  buffer;
    size_t  bufSize;
    WDFDEVICE            hRawDevice = WdfIoQueueGetDevice(Queue);
	PRPDO_DEVICE_DATA pdoData = PdoGetData(hRawDevice);
	WDF_REQUEST_SEND_OPTIONS RequestOptions;
	WDFIOTARGET TargetOnParent;

	JOYSTICK_POSITION_V2 * iReport;
	WDFFILEOBJECT FileObj;
	USHORT id=0;
	PFILEOBJECT_EXTENSION pExtension=NULL;

    WDFREQUEST				requestForceFeedback;
	PHID_XFER_PACKET		transferPacket = NULL;
	PVOID					ForceFeedbackBuffer = NULL;
	PVOID					GenBuffer = NULL;
	size_t					bytesReturned = 0;
	WDF_REQUEST_PARAMETERS	Params;
	BOOLEAN					FfbStat = FALSE;
	ULONG					bytesToCopy = 0;
	BYTE					Byte_tmp;




    
    UNREFERENCED_PARAMETER(OutputBufferLength);
    UNREFERENCED_PARAMETER(InputBufferLength);

	TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "Entered vJoy_EvtIoDeviceControlForRawPdo\n");

    //
    // Process the ioctl and complete it when you are done.
    // Since the queue is configured for serial dispatch, you will
    // not receive another ioctl request until you complete this one.
    //

	  switch (IoControlCode) {
 	case 1234: // TODO: Remove for production
		//RequestOptions.Flags =	WDF_REQUEST_SEND_OPTION_TIMEOUT;
		//RequestOptions.Size =	sizeof(WDF_REQUEST_SEND_OPTIONS);
		//WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&RequestOptions,  WDF_REL_TIMEOUT_IN_SEC(1));
		//status = WdfIoTargetSendInternalIoctlSynchronously(pdoData->IoTargetToParent, Request, IoControlCode , NULL, NULL, &RequestOptions, NULL);
		break; // Testing 

	case GET_DEV_STAT:
		// Get information for a device by device ID
		TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: Case GET_DEV_STAT\n");

		// Get the buffer from the request
		// Get the data from the request
		WDF_REQUEST_PARAMETERS_INIT(&Params);
		WdfRequestGetParameters(Request, &Params);
		bytesToCopy = Params.Parameters.DeviceIoControl.OutputBufferLength;
		if (bytesToCopy<5)
		{
			TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo[GET_DEV_STAT]: failed - bytesToCopy=%d\n", bytesToCopy);
			WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE);
			return;
		};

		// Get the buffer
		status = WdfRequestRetrieveOutputBuffer(Request, bytesToCopy, &GenBuffer, &bytesReturned);
		if (bytesReturned<5)
		{
			TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo[GET_DEV_STAT]: failed - bytesReturned=%d\n", bytesReturned);
			WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE);
			return;
		};

		// Get the id number from input buffer
		status = WdfRequestRetrieveInputBuffer(Request, sizeof(BYTE), &buffer, &bufSize);
		if (!NT_SUCCESS(status) || (bufSize!=1))
		{
			TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo[GET_DEV_STAT]: failed to retrieve input buffer\n");
			WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE);
			return;
		};

		// Get target ID
		id = *(BYTE *)buffer;
		TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo[GET_DEV_STAT]: id=%d\n", id);

		// Put data into output buffer
		// Byte 1:
		// Bit 0: Implemented?
		// Bit 1: FFB Device Enabled?
		// Bit 2: File Object associated with this device?
		pDevContext = GetDeviceContext(pdoData->hParentDevice);
		Byte_tmp = 0;

		// Implemented mask
		if (pDevContext->DeviceImplemented[id - 1])
			Byte_tmp |= 1;
		else
			Byte_tmp &= 0xFE;
		TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo[GET_DEV_STAT]: Dev Implemented=%x\n", pDevContext->DeviceImplemented[id - 1]);

		// FFB mask
		TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo[GET_DEV_STAT]: Dev Enabled=%x\n", pDevContext->FfbEnable[id - 1]);
		if (pDevContext->FfbEnable[id - 1])
			Byte_tmp |= 2;
		else
			Byte_tmp &= 0xFD;

		// File Object
		if (pDevContext->DeviceFileObject[id - 1])
			Byte_tmp |= 4;
		else
			Byte_tmp &= 0xFB;

		((BYTE *)GenBuffer)[0] = Byte_tmp;
		TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo[GET_DEV_STAT]: Buffer[0]=%x\n", ((BYTE *)GenBuffer)[0]);

		// Byte2-5: Process ID
		// Get the context
		FileObj = pDevContext->DeviceFileObject[id - 1];
		if (FileObj)
			*(DWORD *)(&((BYTE *)GenBuffer)[1]) = GetFileObjectContext(FileObj)->CallingProcessId;
		else
			*(DWORD *)(&((BYTE *)GenBuffer)[1]) = 0;
		TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo[GET_DEV_STAT]: ProcessID=%x\n", *(DWORD *)(&((BYTE *)GenBuffer)[1]));

		// Complete the transaction
		WdfRequestCompleteWithInformation(Request, status, bytesReturned);
		return;



	case GET_DRV_INFO:
		// Get information for this driver
		TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: [GET_DRV_INFO]\n");
		// Get the buffer from the request
		// Get the data from the request
		WDF_REQUEST_PARAMETERS_INIT(&Params);
		WdfRequestGetParameters(Request, &Params);

		// Number of bytes to copy must be at least one byte
		bytesToCopy = Params.Parameters.DeviceIoControl.OutputBufferLength;
		if (bytesToCopy <1 )
		{
			TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: [GET_DRV_INFO] - bytesToCopy <1\n");
			WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE);
			return;
		};


		// Output buffer must be at least one byte
		status = WdfRequestRetrieveOutputBuffer(Request, bytesToCopy, &GenBuffer, &bytesReturned);
		if (bytesReturned<1)
		{
			TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: [GET_DRV_INFO] - bytesReturned <1\n");
			WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE);
			return;
		};

		pDevContext = GetDeviceContext(pdoData->hParentDevice);

		// Return the data in the output buffer
		// BYTE 0 //////////////////////////////
		// Bit 0	: Supports FFB?
		// Bit 1	: Reserved
		// Bit 2	: Mode: Multi-device 
		// Bit 3	: Mode: FFB 
		// BYTE 1 //////////////////////////////
		// Bits 0-7	: Maximum number of possible devices (16 ==> 255)  not regarding to mode
		// BYTE 2 //////////////////////////////
		// Bits 0-7	: Number of existing devices
		// BYTE 3 //////////////////////////////
		// Bits 0-7	: Number of devices that can still be implemented (This is the number of possible devices for the current mode minus the number of already existing devices).

		//////////////////////////////////
		// Byte 0
		Byte_tmp = 0;
		Byte_tmp |= 0x01; // FFB Supported
		Byte_tmp |= 0x00; // Default Mode (TODO: Change to real mode when Implemented) Multi-Device=0x04; FFB=0x80
		((BYTE *)GenBuffer)[0] = Byte_tmp;

		// Byte 1
		if (bytesToCopy >= 2 && bytesReturned >= 2)
		{
			((BYTE *)GenBuffer)[1] = MAX_N_DEVICES;
			TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: [GET_DRV_INFO] - Data byte[1]=%02x\n", ((BYTE *)GenBuffer)[1]);
		}

		// Byte 2
		if (bytesToCopy >= 3 && bytesReturned >= 3)
		{
			((BYTE *)GenBuffer)[2] = (BYTE)(pDevContext->nDevices);
			TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: [GET_DRV_INFO] - Data byte[2]=%02x\n", ((BYTE *)GenBuffer)[2]);
		}

		// Byte 3 - TODO: Change according to mode
		if (bytesToCopy >= 4 && bytesReturned >= 4)
		{
			((BYTE *)GenBuffer)[3] = MAX_N_DEVICES - (BYTE)(pDevContext->nDevices);
			TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: [GET_DRV_INFO] - Data byte[3]=%02x\n", ((BYTE *)GenBuffer)[3]);
		}
		//////////////////////////////////

		// Complete the transaction
		WdfRequestCompleteWithInformation(Request, status, bytesReturned);
		return;


	case GET_DEV_INFO:
		// Get information for this device (and for the driver)

		// Get the buffer from the request
		// Get the data from the request
		WDF_REQUEST_PARAMETERS_INIT(&Params);
		WdfRequestGetParameters(Request, &Params);
		bytesToCopy = Params.Parameters.DeviceIoControl.OutputBufferLength;
		if (bytesToCopy<6)
		{
			WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE);
			return;
		};

		status = WdfRequestRetrieveOutputBuffer(Request, bytesToCopy, &GenBuffer, &bytesReturned);
		if (bytesReturned<6)
		{
			WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE);
			return;
		};

		// Get the context, id and the status
		id = GetIdFromRawPdoRequest(Request, pExtension);

		// Illegal ID
		if (id == 0xFFFF)
		{
			WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE);
			return;
		};

		// Copy the state to the buffer
		pDevContext = GetDeviceContext(pdoData->hParentDevice);
		((BYTE *)GenBuffer)[0] = (BYTE)id;
		((BYTE *)GenBuffer)[1] = (BYTE)(pDevContext->nDevices);
		((BYTE *)GenBuffer)[2] = pDevContext->DeviceImplemented ? 1:0;
		((BYTE *)GenBuffer)[3] = MAX_N_DEVICES; 
 		((BYTE *)GenBuffer)[4] = 1; // Driver does support FFB
		((BYTE *)GenBuffer)[5] = pDevContext->FfbEnable[id - 1]; // Device support FFB

		// Complete the transaction
		WdfRequestCompleteWithInformation(Request, status, bytesReturned);
		return;

	case 0x910: // Backward compatibility value of 	LOAD_POSITIONS
	case LOAD_POSITIONS:
		// KdBreakPoint(); Break When loading position
		status = WdfRequestRetrieveInputBuffer( Request, sizeof(JOYSTICK_POSITION), &buffer, &bufSize);
		if(!NT_SUCCESS(status))
			break;

		// Get interface that this IRP came from,
		// then get the implicated id of the top-level collection
		id = GetIdFromRawPdoRequest(Request, pExtension);


		// Illegal ID
		if (id==0xFFFF)
		{
			WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE);
			return;
		};

		// Get the incoming report and compare the id in the report
		// to the implicated id of the top-level collection
		// They should match
		iReport = buffer;
		if (iReport->bDevice != id)
		{
			WdfRequestComplete(Request, STATUS_CANCELLED);
			return;
		};

		pDevContext = GetDeviceContext(pdoData->hParentDevice);
		LoadPositions(iReport, pDevContext, bufSize);
		status = vJoyCompleteReadReport(pdoData->hParentDevice, (BYTE)id);
		break;   

	case GET_FFB_STAT:
		/* Get the status of the FFB mechanism */

		// Get the buffer from the request
		// Get the data from the request
		WDF_REQUEST_PARAMETERS_INIT(&Params);
		WdfRequestGetParameters(Request, &Params);
		bytesToCopy = Params.Parameters.DeviceIoControl.OutputBufferLength;
		status = WdfRequestRetrieveOutputBuffer(Request, bytesToCopy, &GenBuffer, &bytesReturned);
		if (!bytesReturned)
		{
			WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE);
			return;
		};

		// Get the context, id and the status
		id = GetIdFromRawPdoRequest(Request, pExtension);


		// Illegal ID
		if (id == 0xFFFF)
		{
			WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE);
			return;
		};

		// Copy the state to the buffer
		pDevContext = GetDeviceContext(pdoData->hParentDevice);
		((BYTE *)GenBuffer)[0] =  pDevContext->FfbEnable[id-1];

		// Complete the transaction
		WdfRequestCompleteWithInformation(Request, status, bytesReturned);
		return;

	case SET_FFB_STAT:
		/*Set the status of the FFB mechanism - Obsolete*/

		// Get the data from the request
		WDF_REQUEST_PARAMETERS_INIT(&Params);
		WdfRequestGetParameters(Request, &Params);

		// Get interface that this IRP came from,
		// then get the implicated id of the top-level collection
		// Get the context, id and the status
		id = GetIdFromRawPdoRequest(Request, pExtension);
		// Illegal ID
		if (id == 0xFFFF)
		{
			WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE);
			return;
		};


		// Get the data, process the data and complete the transaction
		//pDevContext = GetDeviceContext(pdoData->hParentDevice);	   - Obsolete
		//FfbActiveSet(*(BOOLEAN *)Params.Parameters.DeviceIoControl.Type3InputBuffer, id, pDevContext);   - Obsolete
		WdfRequestComplete(Request, status);
		return;

	case GET_FFB_DATA:
		// Get interface that this IRP came from,
		// then get the implicated id of the top-level collection
		id = GetIdFromRawPdoRequest(Request, pExtension);


		// If FFB is not active then just reject this request
		pDevContext = GetDeviceContext(pdoData->hParentDevice);
		if (id == 0xFFFF || !pDevContext->FfbEnable[id - 1])
		{
			WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE);
			return;
		};

		// If FFB is active then forward this request to the ReadQ and return
		status = WdfRequestForwardToIoQueue(Request, pDevContext->FfbReadQ[id - 1]);
        if(!NT_SUCCESS(status)){
            TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL,
				"WdfRequestForwardToIoQueue (FfbWriteQ[%d]) failed with status: 0x%x\n", id - 1, status);
            WdfRequestComplete(Request, status);
        }
        return;

	case GET_DRV_DEV_EN:
		// Get the number of devices that are currently enabled
		TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: Case GET_DRV_DEV_EN\n");

		// Get the buffer from the request
		// Get the data from the request
		WDF_REQUEST_PARAMETERS_INIT(&Params);
		WdfRequestGetParameters(Request, &Params);
		bytesToCopy = Params.Parameters.DeviceIoControl.OutputBufferLength;
		TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: bytesToCopy=%d\n", bytesToCopy);
		if (bytesToCopy<1)
		{
			WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE);
			return;
		};

		status = WdfRequestRetrieveOutputBuffer(Request, bytesToCopy, &GenBuffer, &bytesReturned);
		TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: bytesReturned=%d\n", bytesReturned);
		if (bytesReturned<1)
		{
			WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE);
			return;
		};

		if (!pdoData) break;
		pDevContext = GetDeviceContext(pdoData->hParentDevice);
		if (!pDevContext) break;
		// The number of the max supported devices
		((BYTE *)GenBuffer)[0] = (BYTE)(pDevContext->nDevices);

		// Complete the transaction
		WdfRequestCompleteWithInformation(Request, status, bytesReturned);
		TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: GenBuffer[0]=%d\n", ((BYTE *)GenBuffer)[0]);
		return;

	case GET_DRV_DEV_MAX:
		// Get the max possible number of devices that this driver supports
		TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: Case GET_DRV_DEV_MAX\n");

		// Get the buffer from the request
		// Get the data from the request
		WDF_REQUEST_PARAMETERS_INIT(&Params);
		WdfRequestGetParameters(Request, &Params);
		bytesToCopy = Params.Parameters.DeviceIoControl.OutputBufferLength;
		TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: bytesToCopy=%d\n", bytesToCopy);
		if (bytesToCopy<1)
		{
			WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE);
			return;
		};

		status = WdfRequestRetrieveOutputBuffer(Request, bytesToCopy, &GenBuffer, &bytesReturned);
		TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: bytesReturned=%d\n", bytesReturned);
		if (bytesReturned<1)
		{
			WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE);
			return;
		};

		// The number of the max supported devices
		((BYTE *)GenBuffer)[0] = MAX_N_DEVICES;

		// Complete the transaction
		WdfRequestCompleteWithInformation(Request, status, bytesReturned);
		TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: GenBuffer[0]=%d\n", ((BYTE *)GenBuffer)[0]);
		return;


	case IS_DRV_FFB_CAP:
		// Test is this version of vJoy driver supports FFB
		TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: Case IS_DRV_FFB_CAP\n");

		// Get the data from the request (Bytes to copy)
		WDF_REQUEST_PARAMETERS_INIT(&Params);
		WdfRequestGetParameters(Request, &Params);
		bytesToCopy = Params.Parameters.DeviceIoControl.OutputBufferLength;
		TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: bytesToCopy=%d\n", bytesToCopy);
		if (bytesToCopy<1)
		{
			TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: bytesToCopy=%d (Failed)\n", bytesToCopy);
			WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE);
			return;
		};

		// Get the buffer from the request
		status = WdfRequestRetrieveOutputBuffer(Request, bytesToCopy, &GenBuffer, &bytesReturned);
		TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: bytesReturned=%d\n", bytesReturned);
		if (bytesReturned<1)
		{
			TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: bytesReturned=%d (Failed)\n", bytesReturned);
			WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE);
			return;
		};

		// Yes, this driver supports FFB
		((BYTE *)GenBuffer)[0] = 1;

		// Complete the transaction
		WdfRequestCompleteWithInformation(Request, status, bytesReturned);
		TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: GenBuffer[0]=%d\n", ((BYTE *)GenBuffer)[0]);
		return;
	case RESET_DEV:
		/* Resets device(s) to predefined values */
		TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: Case RESET_DEV\n");

		// then get the implicated id of the top-level collection
		id = GetIdFromRawPdoRequest(Request, pExtension);
		TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: ID=%d\n", id);

		// Sanity check
		if (id == 0xFFFF)
		{
			WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE);
			return;
		};

		// Get the context of vJoy device
		pDevContext = GetDeviceContext(pdoData->hParentDevice);		
		
		// Reset device(s)
		status = ResetDevice(id, pDevContext);
		WdfRequestCompleteWithInformation(Request, status, 0);
		return;

	default:
        break;
    }
	  WdfRequestComplete(Request, status);

    return;
}
VOID
EvtIoDeviceControl(
    WDFQUEUE   Queue,
    WDFREQUEST Request,
    size_t     OutputBufferLength,
    size_t     InputBufferLength,
    ULONG      IoControlCode)
{
    NTSTATUS        status;
    BOOLEAN         completeRequest = TRUE;
    WDFDEVICE       device = WdfIoQueueGetDevice(Queue);
    PINPUT_DEVICE   pContext = GetDeviceContext(device);
    ULONG           uReportSize;
    HID_XFER_PACKET Packet;
    WDF_REQUEST_PARAMETERS params;
    UNREFERENCED_PARAMETER(OutputBufferLength);
    UNREFERENCED_PARAMETER(InputBufferLength);

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS,
                "--> %s, code = %d\n", __FUNCTION__, IoControlCode);

    switch (IoControlCode)
    {
    case IOCTL_HID_GET_DEVICE_DESCRIPTOR:
        TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "IOCTL_HID_GET_DEVICE_DESCRIPTOR\n");
        //
        // Return the device's HID descriptor.
        //
        ASSERT(pContext->HidDescriptor.bLength != 0);
        status = RequestCopyFromBuffer(Request,
            &pContext->HidDescriptor,
            pContext->HidDescriptor.bLength);
        break;

    case IOCTL_HID_GET_DEVICE_ATTRIBUTES:
        TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "IOCTL_HID_GET_DEVICE_ATTRIBUTES\n");
        //
        // Return the device's attributes in a HID_DEVICE_ATTRIBUTES structure.
        //
        status = RequestCopyFromBuffer(Request,
            &pContext->HidDeviceAttributes,
            sizeof(HID_DEVICE_ATTRIBUTES));
        break;

    case IOCTL_HID_GET_REPORT_DESCRIPTOR:
        TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "IOCTL_HID_GET_REPORT_DESCRIPTOR\n");
        //
        // Return the report descriptor for the HID device.
        //
        status = RequestCopyFromBuffer(Request,
            pContext->HidReportDescriptor,
            pContext->HidDescriptor.DescriptorList[0].wReportLength);
        break;

    case IOCTL_HID_READ_REPORT:
        TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "IOCTL_HID_READ_REPORT\n");
        //
        // Queue up a report request. We'll complete it when we actually
        // receive data from the device.
        //

        status = WdfRequestForwardToIoQueue(
            Request,
            pContext->HidQueue);
        if (NT_SUCCESS(status))
        {
            completeRequest = FALSE;
        }
        else
        {
            TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS,
                        "WdfRequestForwardToIoQueue failed with 0x%x\n", status);
        }
        break;

    case IOCTL_HID_WRITE_REPORT:
        TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "IOCTL_HID_WRITE_REPORT\n");
        //
        // Write a report to the device, commonly used for controlling keyboard
        // LEDs. We'll complete the request after the host processes all virtio
        // buffers we add to the status queue.
        //

        WDF_REQUEST_PARAMETERS_INIT(&params);
        WdfRequestGetParameters(Request, &params);

        if (params.Parameters.DeviceIoControl.InputBufferLength < sizeof(HID_XFER_PACKET))
        {
            status = STATUS_BUFFER_TOO_SMALL;
        }
        else
        {
            RtlCopyMemory(&Packet, WdfRequestWdmGetIrp(Request)->UserBuffer,
                          sizeof(HID_XFER_PACKET));
            WdfRequestSetInformation(Request, Packet.reportBufferLen);

            status = ProcessOutputReport(pContext, Request, &Packet);
            if (NT_SUCCESS(status))
            {
                completeRequest = FALSE;
            }
        }
        break;

    default:
        TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTLS,
                    "Unrecognized IOCTL %d\n", IoControlCode);
        status = STATUS_NOT_IMPLEMENTED;
        break;
    }

    if (completeRequest)
    {
        WdfRequestComplete(Request, status);
    }

    TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "<-- %s\n", __FUNCTION__);
}
Exemple #15
0
VOID
tgwinkEvtIoDeviceControl(
    _In_ WDFQUEUE Queue,
    _In_ WDFREQUEST Request,
    _In_ size_t OutputBufferLength,
    _In_ size_t InputBufferLength,
    _In_ ULONG IoControlCode
    )
{
    WDFMEMORY mem;
    NTSTATUS status;
    WDFDEVICE dev;
    PDEVICE_CONTEXT context;
    void *uBase = NULL;
    LARGE_INTEGER offset;
    size_t size;

    dev = WdfIoQueueGetDevice(Queue);
    context = DeviceGetContext(dev);

    switch (IoControlCode) {
    case IOCTL_TGWINK_SAY_HELLO:
        
        if (OutputBufferLength != 4) {
            WdfRequestComplete(Request, STATUS_BAD_DATA);
            break;
        }

        status = WdfRequestRetrieveOutputMemory(Request, &mem);
        if (!NT_SUCCESS(status)) {
            KdPrint("tgwinkEvtIoDeviceControl could not get request memory buffer, status 0x%x\n", status);
            WdfVerifierDbgBreakPoint();
            WdfRequestComplete(Request, status);
            break;
        }

        *((DWORD32 *)(WdfMemoryGetBuffer(mem, NULL))) = 0x5a5aa5a5;
        WdfRequestComplete(Request, STATUS_SUCCESS);
        break;

    case IOCTL_TGWINK_MAP_BAR_0:
        if (sizeof(void *) > OutputBufferLength) {
            KdPrint("tgwinkEvtIoDeviceControl needs a larger buffer (%d > %d)!\n", sizeof(void *), OutputBufferLength);
            WdfRequestComplete(Request, STATUS_BUFFER_TOO_SMALL);
            break;
        }

        offset = context->bar[0].phyAddr;
        size = context->bar[0].length;

        status = ZwMapViewOfSection(context->hMemory, ZwCurrentProcess(), &uBase, 0, 0, &offset, &size, ViewUnmap, 0, PAGE_READWRITE);
        if (!NT_SUCCESS(status)) {

            KdPrint("tgwinkEvtIoDeviceControl could not map view of section, status ");
            switch (status) {
            case STATUS_CONFLICTING_ADDRESSES: 
                KdPrint("STATUS_CONFLICTING_ADDRESSES\n"); 
                break;
            case STATUS_INVALID_PAGE_PROTECTION: 
                KdPrint("STATUS_INVALID_PAGE_PROTECTION\n"); 
                break;
            case STATUS_SECTION_PROTECTION: 
                KdPrint("STATUS_SECTION_PROTECTION\n"); 
                break;
            default: 
                KdPrint("0x % x\n", status); 
                break;
            }
            WdfRequestComplete(Request, status);
            break;
        }

        status = WdfRequestRetrieveOutputMemory(Request, &mem);
        if (!NT_SUCCESS(status)) {
            KdPrint("tgwinkEvtIoDeviceControl could not get request memory buffer, status 0x%x\n", status);
            WdfVerifierDbgBreakPoint();
            WdfRequestComplete(Request, status);
            break;
        }

        *((void **)(WdfMemoryGetBuffer(mem, NULL))) = uBase;

        WdfRequestComplete(Request, STATUS_SUCCESS);
        break;

    case IOCTL_TGWINK_READ_PHYS:
    {
        PVOID buf;
        ULONG_PTR page, ofs, vtgt = 0;
        SIZE_T vsz = 0;

        if (InputBufferLength != sizeof(PVOID)) {
            KdPrint("tgwinkEvtIoDeviceControl requires a %d-byte buffer for this ioctl (got %d)\n", sizeof(PVOID), OutputBufferLength);
            WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES);
            break;
        }
        
        status = WdfRequestRetrieveInputBuffer(Request, sizeof(PVOID), &buf, NULL);
        if (!NT_SUCCESS(status)) {
            KdPrint("tgwinkEvtIoDeviceControl could not get request memory buffer, status 0x%x\n", status);
            WdfRequestComplete(Request, status);
            break;
        }

        ofs = *((ULONG_PTR *)buf);
        page = ofs & ~0xfff;
        vsz = OutputBufferLength + (page ^ ofs);
        buf = NULL;

        status = WdfRequestRetrieveOutputMemory(Request, &mem);
        if (!NT_SUCCESS(status)) {
            KdPrint("tgwinkEvtIoDeviceControl could not get request memory buffer, status 0x%x\n", status);
            WdfRequestComplete(Request, status);
            break;
        }

        status = ZwMapViewOfSection(context->hMemory, (HANDLE)-1, (PVOID *)&vtgt, 0, 0, (PLARGE_INTEGER)&page, &vsz, ViewUnmap, 0, PAGE_READONLY);
        if (!NT_SUCCESS(status)) {
            KdPrint("tgwinkEvtIoDeviceControl could not map view of physical memory section, status 0x%x\n", status);
            WdfRequestComplete(Request, status);
            break;
        }

        ofs -= page;
        status = WdfMemoryCopyFromBuffer(mem, 0, (PVOID)(vtgt + ofs), OutputBufferLength);
        if (!NT_SUCCESS(status)) {
            KdPrint("tgwinkEvtIoDeviceControl failed to copy data from memory to buffer, status 0x%x\n", status);
            WdfRequestComplete(Request, status);
            break;
        }

        status = ZwUnmapViewOfSection((HANDLE)-1, (PVOID)vtgt);
        if (!NT_SUCCESS(status)) {
            KdPrint("tgwinkEvtIoDeviceControl failed to unmap view of physical memory section, status 0x%x\n", status);
            WdfRequestComplete(Request, status);
            break;
        }
    
        WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, OutputBufferLength);
    } break;

    case IOCTL_TGWINK_PEND_INTR:
    {
        WdfWaitLockAcquire(context->nnLock, NULL);
        if (context->notifyNext) {
            PINTERRUPT_CONTEXT pCtx = InterruptGetContext(context->hIrq);
            status = WdfRequestRetrieveOutputMemory(Request, &mem);
            if (!NT_SUCCESS(status)) {
                KdPrint("tgwinkEvtIoDeviceControl failed to retrieve output memory, status 0x%x\n", status);
                WdfRequestComplete(Request, status);
            }
            status = WdfMemoryCopyFromBuffer(mem, 0, &pCtx->serial, 8);
            if (!NT_SUCCESS(status)) {
                KdPrint("tgwinkEvtIoDeviceControl failed to copy interrupt number to buffer, status 0x%x\n", status);
                WdfRequestComplete(Request, status);
            }
            WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, 8);
            context->notifyNext = 0;
            KdPrint("tgwinkEvtIoDeviceControl satisfied interrupt notification request synchronously.\n");
            //WdfInterruptEnable(context->hIrq);
        } else {
            KdPrint("tgwinkEvtIoDeviceControl forwarding PEND_INTR request to notification queue\n");
            WdfRequestForwardToIoQueue(Request, context->NotificationQueue);
        }
        WdfWaitLockRelease(context->nnLock);
    } break;

    default:
        WdfRequestComplete(Request, STATUS_UNSUCCESSFUL);
    }
}
// 并行处理
VOID CY001Drv::DeviceIoControlParallel(IN WDFQUEUE  Queue,
						IN WDFREQUEST  Request,
						IN size_t  OutputBufferLength,
						IN size_t  InputBufferLength,
						IN ULONG  IoControlCode)
{
	NTSTATUS status = STATUS_SUCCESS;
	ULONG ulRetLen = 0;

	size_t size = 0;
	void* pBufferInput = NULL;
	void* pBufferOutput = NULL;

	KDBG(DPFLTR_INFO_LEVEL, "[DeviceIoControlParallel] CtlCode:0x%0.8X", IoControlCode);

	// 取得输入缓冲区,判断其有效性
	if(InputBufferLength){
		status = WdfRequestRetrieveInputBuffer(Request, InputBufferLength, &pBufferInput, &size);
		if(status != STATUS_SUCCESS || pBufferInput == NULL || size < InputBufferLength){
			WdfRequestComplete(Request, STATUS_INVALID_PARAMETER);
			return;
		}
	}

	// 取得输出缓冲区,判断其有效性
	if(OutputBufferLength){
		status = WdfRequestRetrieveOutputBuffer(Request, OutputBufferLength, &pBufferOutput, &size);
		if(status != STATUS_SUCCESS || pBufferOutput == NULL || size < OutputBufferLength){
			WdfRequestComplete(Request, STATUS_INVALID_PARAMETER);
			return;
		}
	}

	//
	// 下面是主处理过程。
	//
	switch(IoControlCode)
	{
		// 取得驱动的版本信息
	case IOCTL_GET_DRIVER_VERSION:
		{
			PDRIVER_VERSION pVersion = (PDRIVER_VERSION)pBufferOutput;
			ULONG length;
			char tcsBuffer[120];
			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_GET_DRIVER_VERSION");

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

			pVersion->DriverType = DR_WDF;
			pVersion->FirmwareType = FW_NOT_CY001;
			ulRetLen = sizeof(DRIVER_VERSION);// 告示返回长度

			// 根据String描述符,判断Firmware代码是否已经被加载。
			GetStringDes(2, 0, tcsBuffer, 120, &length);

			if(length){
				WCHAR* pCyName = L"CY001 V";
				size_t len;
				int nIndex;

				if(length < 8)
					break;

				RtlStringCchLengthW(pCyName, 7, &len);
				for(nIndex = 0; nIndex < len; nIndex++){
					if(pCyName[nIndex] != ((WCHAR*)tcsBuffer)[nIndex])
						break;
				}

				if(nIndex == len)
					pVersion->FirmwareType = FW_CY001; // 完全相符,说明新版Firmware已经加载到开发板。
			}
			break;
		}
		
		// 收到App发送过来的一个同步Request,我们应该把它保存到同步Queue中,等到有同步事件发生的时候再从Queue中取出并完成。
	case IOCTL_USB_SYNC:
		KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_SYNC");
		status = WdfRequestForwardToIoQueue(Request, m_hAppSyncManualQueue);

		// 直接返回,不调用WdfRequestComplete函数。
		// 请求者将不会为此而等待;请求的完成在将来的某个时刻。
		// 这就是所谓的异步处理之要义了。
		if(NT_SUCCESS(status))
			return;
		break;

		// 清空同步队列中的所有请求
	case IOCTL_USB_SYNC_RELEASE:
		KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_SYNC");
		ClearSyncQueue();
		break;

		// 应用程序退出,取消所有被阻塞的请求。
	case IOCTL_APP_EXIT_CANCEL: 
			
		// 取消USB设备的所有IO操作。它将连带取消所有Pipe的IO操作。
		//WdfIoTargetStop(WdfUsbTargetDeviceGetIoTarget(m_hUsbDevice), WdfIoTargetCancelSentIo);
		break;

		// 取得当前的配置号.总是设置为0,因为在WDF框架中,0以外的配置是不被支持的。
	case IOCTL_USB_GET_CURRENT_CONFIG:
		{
			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_CURRENT_CONFIG");
			if(InputBufferLength < 4){
				status = STATUS_INVALID_PARAMETER;
				break;
			}

			*(PULONG)pBufferInput = 0;// 直接赋值0,即总是选择0号配置。也可以发送URB到总线获取当前配置选项。
			ulRetLen = sizeof(ULONG);
			break;
		}

	case IOCTL_USB_ABORTPIPE:
		{
			ULONG pipenum = *((PULONG) pBufferOutput);
			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_ABORTPIPE");

			status = AbortPipe(pipenum);
		}      
		break;

		// 获取Pipe信息
	case IOCTL_USB_GET_PIPE_INFO:
		{
			// 遍历获取Pipe信息,复制到输出缓冲中。
			BYTE byCurSettingIndex = 0;
			BYTE byPipeNum = 0;
			BYTE index;
			USB_INTERFACE_DESCRIPTOR  interfaceDescriptor;
			WDF_USB_PIPE_INFORMATION  pipeInfor;

			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_PIPE_INFO");

			// 取得Pipe数。根据Pipe数计算缓冲区长度
			byCurSettingIndex = WdfUsbInterfaceGetConfiguredSettingIndex(m_hUsbInterface); 
			WdfUsbInterfaceGetDescriptor(m_hUsbInterface, byCurSettingIndex, &interfaceDescriptor);
			byPipeNum = WdfUsbInterfaceGetNumConfiguredPipes(m_hUsbInterface);		

			if(OutputBufferLength < byPipeNum * sizeof(pipeInfor)){
				status = STATUS_BUFFER_TOO_SMALL; // 缓冲区不足
			}else{

				ulRetLen = byPipeNum*sizeof(pipeInfor);

				// 遍历获取全部管道信息,拷贝到输出缓冲中。
				// 应用程序得到输出缓冲的时候,也应该使用WDF_USB_PIPE_INFORMATION结构体解析缓冲区。
				for(index = 0; index < byPipeNum; index++)
				{
					WDF_USB_PIPE_INFORMATION_INIT(&pipeInfor);
					WdfUsbInterfaceGetEndpointInformation(m_hUsbInterface, byCurSettingIndex, index, &pipeInfor);
					RtlCopyMemory((PUCHAR)pBufferOutput + index*pipeInfor.Size, &pipeInfor, sizeof(pipeInfor));
				}
			}
		}

		break;

		// 获取设备描述符
	case IOCTL_USB_GET_DEVICE_DESCRIPTOR:
		{
			USB_DEVICE_DESCRIPTOR  UsbDeviceDescriptor;
			WdfUsbTargetDeviceGetDeviceDescriptor(m_hUsbDevice, &UsbDeviceDescriptor);
			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_DEVICE_DESCRIPTOR");

			// 判断输入缓冲区的长度是否足够长
			if(OutputBufferLength < UsbDeviceDescriptor.bLength)
				status = STATUS_BUFFER_TOO_SMALL;
			else{
				RtlCopyMemory(pBufferOutput, &UsbDeviceDescriptor, UsbDeviceDescriptor.bLength);
				ulRetLen = UsbDeviceDescriptor.bLength;
			}

			break;
		}

		// 获取字符串描述符
	case IOCTL_USB_GET_STRING_DESCRIPTOR:
		{
			PGET_STRING_DESCRIPTOR Input = (PGET_STRING_DESCRIPTOR)pBufferInput;
			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_STRING_DESCRIPTOR");
			status = GetStringDes(Input->Index, Input->LanguageId, pBufferOutput, OutputBufferLength, &ulRetLen);
			
			// 由字符长度调整为字节长度
			if(NT_SUCCESS(status) && ulRetLen > 0)
				ulRetLen *= (sizeof(WCHAR)/sizeof(char));
			break;
		}

		// 获取配置描述信息。
	case IOCTL_USB_GET_CONFIGURATION_DESCRIPTOR:
		{
			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_CONFIGURATION_DESCRIPTOR");

			// 首先获得配置描述符的长度。
			status = WdfUsbTargetDeviceRetrieveConfigDescriptor(m_hUsbDevice, NULL, (USHORT*)&size);
			if(!NT_SUCCESS(status) && status != STATUS_BUFFER_TOO_SMALL)
				break;

			// 输出缓冲区不够长
			if(OutputBufferLength < size)
				break;

			// 正式取得配置描述符。
			status = WdfUsbTargetDeviceRetrieveConfigDescriptor(m_hUsbDevice, pBufferOutput, (USHORT*)&size);
			if(!NT_SUCCESS(status))
				break;

			ulRetLen = size;
			break;
		}

		// 根据可选值配置接口
	case IOCTL_USB_SET_INTERFACE:
		{
			BYTE byAlterSetting = *(BYTE*)pBufferInput;
			BYTE byCurSetting = WdfUsbInterfaceGetConfiguredSettingIndex(m_hUsbInterface); // 当前Alternate值

			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_SETINTERFACE");

			if(InputBufferLength < 1 || OutputBufferLength < 1)
			{
				status = STATUS_BUFFER_TOO_SMALL;
				break;
			}
			
			// 如果传入的可选值与当前的不同,则重新配置接口;
			// 否则直接返回。
			if(byCurSetting != byAlterSetting)
			{
				WDF_USB_INTERFACE_SELECT_SETTING_PARAMS par;
				WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_INIT_SETTING(&par, byAlterSetting);
				status = WdfUsbInterfaceSelectSetting(m_hUsbInterface, NULL, &par);
			}

			*(BYTE*)pBufferOutput = byCurSetting;
			break;
		}

		// 固件Rest。自定义命令,与Port Rest是两码事。
	case IOCTL_USB_FIRMWRAE_RESET:
		{
			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_FIRMWRAE_RESET");
			if(InputBufferLength < 1 || pBufferInput == NULL)
				status = STATUS_INVALID_PARAMETER;
			else
				status = FirmwareReset(*(char*)pBufferInput);

			break;
		}

		// 重置USB总线端口
	case IOCTL_USB_PORT_RESET:
		{
			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_PORT_RESET");			
			WdfUsbTargetDeviceResetPortSynchronously(m_hUsbDevice);
			break;
		}

		// 管道重置
	case IOCTL_USB_PIPE_RESET:
		{
			UCHAR uchPipe;
			WDFUSBPIPE pipe = NULL;

			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_PIPE_RESET");			

			if(InputBufferLength < 1){
				status = STATUS_INVALID_PARAMETER;
				break;
			}

			// 根据ID找到对应的Pipe
			uchPipe = *(UCHAR*)pBufferInput;
			pipe = WdfUsbInterfaceGetConfiguredPipe(m_hUsbInterface, uchPipe, NULL);
			if(pipe == NULL){ 
				status = STATUS_INVALID_PARAMETER;
				break;
			}

			status = WdfUsbTargetPipeResetSynchronously(pipe, NULL, NULL);
			break;
		}

		// 中断管道,放弃管道当前正在进行的操作
	case IOCTL_USB_PIPE_ABORT:
		{
			UCHAR uchPipe;
			WDFUSBPIPE pipe = NULL;

			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_PIPE_ABORT");

			if(InputBufferLength < 1){
				status = STATUS_INVALID_PARAMETER;
				break;
			}

			// 根据ID找到对应的Pipe
			uchPipe = *(UCHAR*)pBufferInput;
			pipe = WdfUsbInterfaceGetConfiguredPipe(m_hUsbInterface, uchPipe, NULL);
			if(pipe == NULL){ 
				status = STATUS_INVALID_PARAMETER;
				break;
			}
			
			status = WdfUsbTargetPipeAbortSynchronously(pipe, NULL, NULL);
			break;
		}

		// 取得驱动错误信息,驱动总是把最后一次发现的错误保存在设备对象的环境块中。
		// 这个逻辑虽然实现了,但目前的版本中,应用程序并没有利用这个接口。
	case IOCTL_USB_GET_LAST_ERROR:
		{
			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_LAST_ERROR");

			if (OutputBufferLength >= sizeof(ULONG))
				*((PULONG)pBufferOutput) = m_ulLastUSBErrorStatusValue;
			else
				status = STATUS_BUFFER_TOO_SMALL;

			ulRetLen = sizeof(ULONG);
			break;
		}

		// Clear feature命令
	case IOCTL_USB_SET_CLEAR_FEATURE:
		{
			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_SET_CLEAR_FEATURE");
			status = UsbSetOrClearFeature(Request);
			break;
		}

		// 为USB设备加载固件程序。带有偏移量参数,用这个分支;不带偏移量,可用下一个分支。
		// 带偏移量的情况下,固件代码是一段一段地加载;
		// 不带偏移量的情况,固件代码作为一整块一次性被加载。
	case IOCTL_FIRMWARE_UPLOAD_OFFSET:
		{
			void* pData = pBufferOutput;
			WORD offset = 0;

			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_FIRMWARE_UPLOAD_OFFSET");

			if(InputBufferLength < sizeof(WORD)){
				status = STATUS_INVALID_PARAMETER;
				break;
			}

			offset = *(WORD*)pBufferInput;
			status = FirmwareUpload((PUCHAR)pData, OutputBufferLength, offset);
			break;
		}

		// 为USB设备加载固件程序。
	case IOCTL_FIRMWARE_UPLOAD:
		{
			void* pData = pBufferOutput;
			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_FIRMWARE_UPLOAD");
			status = FirmwareUpload((PUCHAR)pData, InputBufferLength, 0);
			break;
		}

		// 读取开发板设备的RAM内容。RAM也就是内存。
		// 每次从同一地址读取的内容可能不尽相同,开发板中固件程序在不断运行,RAM被用来储数据(包括临时数据)。
	case IOCTL_FIRMWARE_READ_RAM:
		{
			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_FIRMWARE_READ_RAM");
			status = ReadRAM(Request, &ulRetLen);// inforVal中保存读取的长度
			break;
		}

		// 其他的请求
	default:
		{
			// 一律转发到SerialQueue中去。			
			WdfRequestForwardToIoQueue(Request, m_hIoCtlSerialQueue);

			// 命令转发之后,这里必须直接返回,千万不可调用WdfRequestComplete函数。
			// 否则会导致一个Request被完成两次的错误。
			return;
		}
	}

	// 完成请求
	WdfRequestCompleteWithInformation(Request, status, ulRetLen);
}
// 这里面的IO操作是经过序列化的。一个挨着一个,所以绝不会发生重入问题。
//
VOID CY001Drv::DeviceIoControlSerial(IN WDFQUEUE  Queue,
						 IN WDFREQUEST  Request,
						 IN size_t  OutputBufferLength,
						 IN size_t  InputBufferLength,
						 IN ULONG  IoControlCode)
{
	NTSTATUS ntStatus = STATUS_SUCCESS;
	ULONG ulRetLen = 0;
	size_t size;

	void* pBufferInput = NULL;
	void* pBufferOutput = NULL;

	KDBG(DPFLTR_INFO_LEVEL, "[DeviceIoControlSerial]");

	// 取得输入/输出缓冲区
	if(InputBufferLength)WdfRequestRetrieveInputBuffer(Request, InputBufferLength, &pBufferInput, &size);
	if(OutputBufferLength)WdfRequestRetrieveOutputBuffer(Request, OutputBufferLength, &pBufferOutput, &size);

	switch(IoControlCode)
	{
		// 设置数码管
	case IOCTL_USB_SET_DIGITRON:
		{
			CHAR ch = *(CHAR*)pBufferInput;
			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_SET_DIGITRON");
			SetDigitron(ch);
			break;
		}

		// 读数码管
	case IOCTL_USB_GET_DIGITRON:
		{
			UCHAR* pCh = (UCHAR*)pBufferOutput;
			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_DIGITRON");
			GetDigitron(pCh);
			ulRetLen = 1;
			break;
		}

		// 设置LED灯(共4盏)
	case IOCTL_USB_SET_LEDs:
		{
			CHAR ch = *(CHAR*)pBufferInput;
			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_SET_LEDs");
			SetLEDs(ch);
			break;
		}

		// 读取LED灯(共4盏)的当前状态
	case IOCTL_USB_GET_LEDs:
		{
			UCHAR* pCh = (UCHAR*)pBufferOutput;
			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_LEDs");
			GetLEDs(pCh);
			ulRetLen = 1;
			break;
		}

		// 控制命令。
		// 分为:USB协议预定义命令、Vendor自定义命令、特殊类(class)命令。
	case IOCTL_USB_CTL_REQUEST:
		{
			KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_CTL_REQUEST");
			ntStatus = UsbControlRequest(Request);
			if(NT_SUCCESS(ntStatus))return;
			break;
		}

		// 开启中断读
	case IOCTL_START_INT_READ:	
		KDBG(DPFLTR_INFO_LEVEL, "IOCTL_START_INT_READ");	
		ntStatus = InterruptReadStart();
		break;

		// 控制程序发送读请求。它们是被阻塞的,放至Queue中排队,所以不要即可完成他们。
	case IOCTL_INT_READ_KEYs:
		KDBG(DPFLTR_INFO_LEVEL, "IOCTL_INT_READ_KEYs");
		ntStatus = WdfRequestForwardToIoQueue(Request, m_hInterruptManualQueue);

		if(NT_SUCCESS(ntStatus))
			return;// 成功,直接返回;异步完成。
		break;

		// 终止中断读
	case IOCTL_STOP_INT_READ:
		KDBG(DPFLTR_INFO_LEVEL, "IOCTL_STOP_INT_READ");
		InterruptReadStop();
		ntStatus = STATUS_SUCCESS;
		break;

	default:
		// 不应该到这里。
		// 对于不能识别的IO控制命令,这里做错误处理。
		KDBG(DPFLTR_INFO_LEVEL, "Unknown Request: %08x(%d)!!!", IoControlCode, IoControlCode);
		ntStatus = STATUS_INVALID_PARAMETER;
		break;
	}

	WdfRequestCompleteWithInformation(Request, ntStatus, ulRetLen);
	return;
}
NTSTATUS
CBCardTracking(
              PSMARTCARD_EXTENSION SmartcardExtension
              )
/*++

CBCardTracking:
        callback handler for SMCLIB RDF_CARD_TRACKING. the requested event was
        validated by the smclib (i.e. a card removal request will only be passed
        if a card is present).
        for a win95 build STATUS_PENDING will be returned without any other action.
        for NT the cancel routine for the irp will be set to the drivers cancel
        routine.

Arguments:
        SmartcardExtension      context of call

Return Value:
        STATUS_PENDING

--*/
{
    WDFREQUEST request;
    PDEVICE_EXTENSION       DeviceExtension;
    NTSTATUS status;

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

    request = GET_WDFREQUEST_FROM_IRP(SmartcardExtension->OsData->NotificationIrp);

    DeviceExtension = GetDeviceExtension(WdfIoQueueGetDevice(WdfRequestGetIoQueue(request)));

    IoMarkIrpPending(SmartcardExtension->OsData->NotificationIrp);

    //
    // Move the stack pointer back to where it was when the IRP
    // was delivered to the driver. This compensates for the 
    // IoSetNextIrpStackLocation that we did when we presented the IRP 
    // to the smartcard libarary. 
    //
    IoSkipCurrentIrpStackLocation(SmartcardExtension->OsData->NotificationIrp);

    status = WdfRequestForwardToIoQueue(request,
                               DeviceExtension->NotificationQueue);
    if (!NT_SUCCESS(status)) {
        NT_ASSERT(NT_SUCCESS(status));
        InterlockedExchangePointer(
                                 &(SmartcardExtension->OsData->NotificationIrp),
                                 NULL
                                 );
        WdfRequestComplete(request, status);
    }

    status = STATUS_PENDING;

    SmartcardDebug(
                  DEBUG_TRACE,
                  ( "PSCR!CBCardTracking: Exit \n" )
                  );

    return status;
}
VOID
SimSensorAddReadRequest (
    _In_ WDFDEVICE Device,
    _In_ WDFREQUEST ReadRequest
    )

/*++

Routine Description:

    Handles IOCTL_THERMAL_READ_TEMPERATURE. If the request can be satisfied,
    it is completed immediately. Else, adds request to pending request queue.

Arguments:

    Device - Supplies a handle to the device that received the request.

    ReadRequest - Supplies a handle to the request.

--*/

{
    ULONG BytesReturned;
    PREAD_REQUEST_CONTEXT Context;
    WDF_OBJECT_ATTRIBUTES ContextAttributes;
    PFDO_DATA DevExt;
    LARGE_INTEGER ExpirationTime;
    size_t Length;
    BOOLEAN LockHeld;
    PULONG RequestTemperature;
    NTSTATUS Status;
    ULONG Temperature;
    WDFTIMER Timer;
    WDF_OBJECT_ATTRIBUTES TimerAttributes;
    WDF_TIMER_CONFIG TimerConfig;
    PTHERMAL_WAIT_READ ThermalWaitRead;


    DebugEnter();
    PAGED_CODE();

    DevExt = GetDeviceExtension(Device);
    BytesReturned = 0;
    LockHeld = FALSE;
    Status = WdfRequestRetrieveInputBuffer(ReadRequest,
                                           sizeof(THERMAL_WAIT_READ),
                                           &ThermalWaitRead,
                                           &Length);

    if (!NT_SUCCESS(Status) || Length != sizeof(THERMAL_WAIT_READ)) {

        //
        // This request is malformed, bail.
        //

        WdfRequestCompleteWithInformation(ReadRequest, Status, BytesReturned);
        goto AddReadRequestEnd;
    }


    if (ThermalWaitRead->Timeout != -1 /* INFINITE */ ) {

        //
        // Estimate the system time this request will expire at.
        //

        KeQuerySystemTime(&ExpirationTime);
        ExpirationTime.QuadPart += ThermalWaitRead->Timeout * 10000;

    } else {

        //
        // Value which indicates the request never expires.
        //

        ExpirationTime.QuadPart = -1LL /* INFINITE */;
    }

    //
    // Handle the immediate timeout case in the fast path.
    //

    Temperature = SimSensorReadVirtualTemperature(Device);
    if (SimSensorAreConstraintsSatisfied(Temperature,
                                         ThermalWaitRead->LowTemperature,
                                         ThermalWaitRead->HighTemperature,
                                         ExpirationTime)) {

        Status = WdfRequestRetrieveOutputBuffer(ReadRequest,
                                                sizeof(ULONG),
                                                &RequestTemperature,
                                                &Length);

        if(NT_SUCCESS(Status) && Length == sizeof(ULONG)) {
            *RequestTemperature = Temperature;
            BytesReturned = sizeof(ULONG);

        } else {
            Status = STATUS_INVALID_PARAMETER;
            DebugPrint(SIMSENSOR_ERROR,
                       "WdfRequestRetrieveOutputBuffer() Failed. 0x%x",
                       Status);

        }

        WdfRequestCompleteWithInformation(ReadRequest, Status, BytesReturned);
    } else {

        WdfWaitLockAcquire(DevExt->QueueLock, NULL);
        LockHeld = TRUE;

        //
        // Create a context to store request-specific information.
        //

        WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&ContextAttributes,
                                                READ_REQUEST_CONTEXT);

        Status = WdfObjectAllocateContext(ReadRequest,
                                          &ContextAttributes,
                                          &Context);

        if(!NT_SUCCESS(Status)) {
            DebugPrint(SIMSENSOR_ERROR,
                       "WdfObjectAllocateContext() Failed. 0x%x",
                       Status);

            WdfRequestCompleteWithInformation(ReadRequest,
                                              Status,
                                              BytesReturned);

            goto AddReadRequestEnd;
        }

        Context->ExpirationTime.QuadPart = ExpirationTime.QuadPart;
        Context->LowTemperature = ThermalWaitRead->LowTemperature;
        Context->HighTemperature = ThermalWaitRead->HighTemperature;
        if(Context->ExpirationTime.QuadPart != -1LL /* INFINITE */ ) {

            //
            // This request eventually expires, create a timer to complete it.
            //

            WDF_TIMER_CONFIG_INIT(&TimerConfig, SimSensorExpiredRequestTimer);
            WDF_OBJECT_ATTRIBUTES_INIT(&TimerAttributes);
            TimerAttributes.ExecutionLevel = WdfExecutionLevelPassive;
            TimerAttributes.SynchronizationScope = WdfSynchronizationScopeNone;
            TimerAttributes.ParentObject = Device;
            Status = WdfTimerCreate(&TimerConfig,
                                    &TimerAttributes,
                                    &Timer);

            if(!NT_SUCCESS(Status)) {
                DebugPrint(SIMSENSOR_ERROR,
                        "WdfTimerCreate() Failed. 0x%x",
                        Status);

                WdfRequestCompleteWithInformation(ReadRequest,
                                                  Status,
                                                  BytesReturned);

                goto AddReadRequestEnd;
            }

            WdfTimerStart(Timer,
                          WDF_REL_TIMEOUT_IN_MS(ThermalWaitRead->Timeout));

        }

        Status = WdfRequestForwardToIoQueue(ReadRequest,
                                            DevExt->PendingRequestQueue);

        if(!NT_SUCCESS(Status)) {
            DebugPrint(SIMSENSOR_ERROR,
                       "WdfRequestForwardToIoQueue() Failed. 0x%x",
                       Status);

            WdfRequestCompleteWithInformation(ReadRequest,
                                              Status,
                                              BytesReturned);

            goto AddReadRequestEnd;
        }

        //
        // Force a rescan of the queue to update the interrupt thresholds.
        //

        SimSensorScanPendingQueue(Device);
    }

AddReadRequestEnd:

    if(LockHeld == TRUE) {
        WdfWaitLockRelease(DevExt->QueueLock);
    }

    DebugExitStatus(Status);
}