Hi,
I developed a driver to create a virtual Xbox 360 wired controller device for one of our company’s joystick. The driver can be installed successfully and the Device Manage shows the Xbox 360 Controller for Windows which loads the driver XUsb21.sys on Win7. I can test the button/stick in the testing page of the Game Controller settings in the Devices and Printers. However, when I used the XInput application like SimpleController.exe shipped with DirectX SDK, it doesn’t show the device as connected because calling the XInputGetState returns the error ERROR_DEVICE_NOT_CONNECTED. But it’s weird that everything works fine on Win8/Win8.1. The difference is that the Xbox controller’s driver on Win8 is XUsb22.sys. Is it any compatibility issue in my driver?
My driver actually is a bus driver listening to the HID game controller created by our company’s joystick. Once it arrives, the driver plugins one Xbox 360 wired controller device to the virtual bus. I’m not sure which part of the code causes this issue so I paste part of them for your reference.
- The following is the code to create query interface.
//
// Create a custom interface so that other drivers can
// query (IRP_MN_QUERY_INTERFACE) and use our callbacks directly.
//
// Let the framework handle reference counting.
//
RtlZeroMemory(&xusbInterface, sizeof(xusbInterface));
xusbInterface.Size = sizeof(xusbInterface);
xusbInterface.Version = USB_BUSIF_USBDI_VERSION_1;
xusbInterface.BusContext = (PVOID)hChild;
xusbInterface.InterfaceReference = WdfDeviceInterfaceReferenceNoOp;
xusbInterface.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp;
xusbInterface.SubmitIsoOutUrb = Bthxusb_SubmitIsoOutUrb;
xusbInterface.GetUSBDIVersion = Bthxusb_GetUSBDIVersion;
xusbInterface.QueryBusTime = Bthxusb_QueryBusTime;
xusbInterface.QueryBusInformation = Bthxusb_QueryBusInformation;
xusbInterface.IsDeviceHighSpeed = Bthxusb_IsDeviceHighSpeed;
WDF_QUERY_INTERFACE_CONFIG_INIT(
&qiConfig,
(PINTERFACE)&xusbInterface,
&USB_BUS_INTERFACE_USBDI_GUID,
NULL
);
status = WdfDeviceAddQueryInterface(hChild, &qiConfig);
IfFailGoToExit(status, BTHX_PDO, “WdfDeviceAddQueryInterface failed”);
- The following code is to handle the XUsb internal IOCTL.
switch (IoControlCode)
{
case IOCTL_INTERNAL_USB_SUBMIT_URB:
BthxTrace(TRACE_LEVEL_VERBOSE, BTHX_PDO, “>>IOCTL_INTERNAL_USB_SUBMIT_URB”);
pIrp = WdfRequestWdmGetIrp(Request);
if (pIrp != NULL)
{
pCurIoStack = IoGetCurrentIrpStackLocation(pIrp);
if (pCurIoStack != NULL)
{
pUrb = (PURB)pCurIoStack->Parameters.Others.Argument1;
if (pUrb != NULL)
{
switch (pUrb->UrbHeader.Function)
{
case URB_FUNCTION_CONTROL_TRANSFER:
BthxTrace(TRACE_LEVEL_VERBOSE, BTHX_PDO, “URB_FUNCTION_CONTROL_TRANSFER”);
status = STATUS_UNSUCCESSFUL;
break;
case URB_FUNCTION_SELECT_CONFIGURATION:
BthxTrace(TRACE_LEVEL_VERBOSE, BTHX_PDO, “URB_FUNCTION_SELECT_CONFIGURATION”);
status = Bthxusb_SelectConfiguration(pUrb);
break;
case URB_FUNCTION_SELECT_INTERFACE:
BthxTrace(TRACE_LEVEL_VERBOSE, BTHX_PDO, “URB_FUNCTION_SELECT_INTERFACE”);
status = Bthxusb_SelectInterface(pUrb);
break;
case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
BthxTrace(TRACE_LEVEL_VERBOSE, BTHX_PDO, “>>URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE”);
switch (pUrb->UrbControlDescriptorRequest.DescriptorType)
{
case USB_DEVICE_DESCRIPTOR_TYPE:
BthxTrace(TRACE_LEVEL_VERBOSE, BTHX_PDO, “USB_DEVICE_DESCRIPTOR_TYPE”);
status = Bthxusb_GetDeviceDescriptor(pUrb);
break;
case USB_CONFIGURATION_DESCRIPTOR_TYPE:
//
// It will be called several times until it gets the complete configuration
// descriptors including the interface descriptor, endpoint descriptor.
// The length value at the first time is 0x9 and then 0x99.
//
BthxTrace(TRACE_LEVEL_VERBOSE, BTHX_PDO, “USB_CONFIGURATION_DESCRIPTOR_TYPE”);
status = Bthxusb_GetConfigurationDescriptor(pUrb);
break;
case USB_STRING_DESCRIPTOR_TYPE:
BthxTrace(TRACE_LEVEL_VERBOSE, BTHX_PDO, “USB_STRING_DESCRIPTOR_TYPE”);
status = Bthxusb_GetStringDescriptor(pUrb);
break;
default:
BthxTrace(TRACE_LEVEL_VERBOSE, BTHX_PDO, “The descriptor type is 0x%x”, pUrb->UrbControlDescriptorRequest.DescriptorType);
break;
}
BthxTrace(TRACE_LEVEL_VERBOSE, BTHX_PDO, "<<urb_function_get_descriptor_from_device> break;
case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
BthxTrace(TRACE_LEVEL_VERBOSE, BTHX_PDO, “>>URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER”);
if (pUrb->UrbBulkOrInterruptTransfer.PipeHandle == BTHXUSB_PIPE_HANDLE(BTHXUSB_PIPE_ADDRESS_GAME))
{
status = WdfRequestForwardToIoQueue(Request, pContext->hGameInputQueue);
if (!NT_SUCCESS(status))
{
BthxTrace(TRACE_LEVEL_ERROR, BTHX_PDO, “WdfRequestForwardToIoQueue for game input request failed”);
}
}
else
{
status = WdfRequestForwardToIoQueue(Request, pContext->hOtherRequestQueue);
if (!NT_SUCCESS(status))
{
BthxTrace(TRACE_LEVEL_ERROR, BTHX_PDO, “WdfRequestForwardToIoQueue for other requests failed”);
}
}
//
// Not to be completed because it has been pushed into the manual queue
//
if (NT_SUCCESS(status))
{
status = STATUS_PENDING;
}
BthxTrace(TRACE_LEVEL_VERBOSE, BTHX_PDO, "<<urb_function_bulk_or_interrupt_transfer> break;
default:
BthxTrace(TRACE_LEVEL_VERBOSE, BTHX_PDO, “The URB function code is 0x%x”, pUrb->UrbHeader.Function);
break;
}
}
}
}
BthxTrace(TRACE_LEVEL_VERBOSE, BTHX_PDO, "<<ioctl_internal_usb_submit_urb> break;
case IOCTL_INTERNAL_USB_GET_PORT_STATUS:
BthxTrace(TRACE_LEVEL_VERBOSE, BTHX_PDO, “IOCTL_INTERNAL_USB_GET_PORT_STATUS”);
(*(PULONG)(pCurIoStack->Parameters.Others.Argument1)) = USBD_PORT_ENABLED | USBD_PORT_CONNECTED;
break;
default:
BthxTrace(TRACE_LEVEL_VERBOSE, BTHX_PDO, “The internal control code is 0x%x”, IoControlCode);
break;
}</ioctl_internal_usb_submit_urb></urb_function_bulk_or_interrupt_transfer></urb_function_get_descriptor_from_device>