NTSTATUS ConfigureUsbInterface(WDFDEVICE Device, PDEVICE_CONTEXT DeviceContext) { NTSTATUS status = STATUS_SUCCESS; WDF_USB_DEVICE_SELECT_CONFIG_PARAMS usbConfig; // Create USB Target Device Object for Device Context status = WdfUsbTargetDeviceCreate(Device, WDF_NO_OBJECT_ATTRIBUTES, &DeviceContext->UsbDevice); if(!NT_SUCCESS(status)) { KdPrint((__DRIVER_NAME "WdfUsbTargetDeviceCreate failed with status 0x%08x\n", status)); return status; } /*Initialize the parameters struct so that the device can initialize and use a single specified interface. this only works if the device has just 1 interface.*/ /*Chon duy nhat 1 interface cua USB Device */ WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE(&usbConfig); /*Chon duy nhat 1 interface cua USB Device */ status = WdfUsbTargetDeviceSelectConfig(DeviceContext->UsbDevice, WDF_NO_OBJECT_ATTRIBUTES, &usbConfig); if(!NT_SUCCESS(status)) { KdPrint((__DRIVER_NAME "WdfUsbTargetDeviceSelectConfig failed with status 0x%08x\n", status)); return status; } /*Put the USB interface in our device context so that we can use it in future calls to our driver.*/ DeviceContext->UsbInterface = usbConfig.Types.SingleInterface.ConfiguredUsbInterface; return status; }
static NTSTATUS UsbChief_ReadAndSelectDescriptors(IN WDFDEVICE Device) { PDEVICE_CONTEXT pDeviceContext; NTSTATUS Status; PAGED_CODE(); pDeviceContext = GetDeviceContext(Device); if (!pDeviceContext->WdfUsbTargetDevice) { Status = WdfUsbTargetDeviceCreate(Device, WDF_NO_OBJECT_ATTRIBUTES, &pDeviceContext->WdfUsbTargetDevice); if (!NT_SUCCESS(Status)) return Status; } WdfUsbTargetDeviceGetDeviceDescriptor(pDeviceContext->WdfUsbTargetDevice, &pDeviceContext->UsbDeviceDescriptor); return UsbChief_ConfigureDevice(Device); }
/*++ Routine Description: This routine configures the USB device. In this routines we get the device descriptor, the configuration descriptor and select the configuration. Arguments: Device - Handle to a framework device Return Value: NTSTATUS - NT status value. --*/ NTSTATUS ReadAndSelectDescriptors(IN WDFDEVICE Device) { NTSTATUS status; PDEVICE_CONTEXT pDeviceContext; PAGED_CODE(); // initialize variables pDeviceContext = GetDeviceContext(Device); // Create a USB device handle so that we can communicate with the // underlying USB stack. The WDFUSBDEVICE handle is used to query, // configure, and manage all aspects of the USB device. // These aspects include device properties, bus properties, // and I/O creation and synchronization. We only create device the first // the PrepareHardware is called. If the device is restarted by pnp manager // for resource re-balance, we will use the same device handle but then select // the interfaces again because the USB stack could reconfigure the device on // restart. if (pDeviceContext->WdfUsbTargetDevice == NULL) { status = WdfUsbTargetDeviceCreate(Device, WDF_NO_OBJECT_ATTRIBUTES, &pDeviceContext->WdfUsbTargetDevice); if (!NT_SUCCESS(status)) { PSDrv_DbgPrint(3, ("WdfUsbTargetDeviceCreate failed! (Status = %x)\n", status)); return status; } } WdfUsbTargetDeviceGetDeviceDescriptor(pDeviceContext->WdfUsbTargetDevice, &pDeviceContext->UsbDeviceDescriptor); ASSERT(pDeviceContext->UsbDeviceDescriptor.bNumConfigurations); status = ConfigureDevice(Device); return status; }
NTSTATUS FilterEvtDevicePrepareHardware( WDFDEVICE Device, WDFCMRESLIST ResourceList, WDFCMRESLIST ResourceListTranslated ) /*++ Routine Description: In this callback, the driver does whatever is necessary to make the hardware ready to use. In the case of a USB device, this involves reading and selecting descriptors. Arguments: Device - handle to a device Return Value: NT status value --*/ { NTSTATUS status = STATUS_SUCCESS; PFILTER_EXTENSION pFilterContext = NULL; UNREFERENCED_PARAMETER(ResourceList); UNREFERENCED_PARAMETER(ResourceListTranslated); PAGED_CODE(); KdPrint(("--> FilterEvtDevicePrepareHardware\n")); pFilterContext = FilterGetData(Device); // // Create a USB device handle so that we can communicate with the // underlying USB stack. The WDFUSBDEVICE handle is used to query, // configure, and manage all aspects of the USB device. // These aspects include device properties, bus properties, // and I/O creation and synchronization. We only create device the first // the PrepareHardware is called. If the device is restarted by pnp manager // for resource rebalance, we will use the same device handle but then select // the interfaces again because the USB stack could reconfigure the device on // restart. // // To make WdfUsbTargetDeviceCreate success, have to implement this filter as // a lowerfilter otherwise this call may fail due to the func driver - osrusbfx2 does // not pass internal IOCTLs (which is how it configure and query USB properties via // URBs) down the stack. if (pFilterContext->UsbDevice == NULL) { status = WdfUsbTargetDeviceCreate(Device, WDF_NO_OBJECT_ATTRIBUTES, &pFilterContext->UsbDevice); if (!NT_SUCCESS(status)) { KdPrint(("WdfUsbTargetDeviceCreate failed with Status code %x\n", status)); return status; } else { KdPrint(("WdfUsbTargetDeviceCreate success\n", status)); } } KdPrint(("<-- FilterEvtDevicePrepareHardware\n")); return status; }
NTSTATUS OsrFxEvtDevicePrepareHardware( WDFDEVICE Device, WDFCMRESLIST ResourceList, WDFCMRESLIST ResourceListTranslated ) /*++ Routine Description: In this callback, the driver does whatever is necessary to make the hardware ready to use. In the case of a USB device, this involves reading and selecting descriptors. Arguments: Device - handle to a device ResourceList - handle to a resource-list object that identifies the raw hardware resources that the PnP manager assigned to the device ResourceListTranslated - handle to a resource-list object that identifies the translated hardware resources that the PnP manager assigned to the device Return Value: NT status value --*/ { NTSTATUS status; PDEVICE_CONTEXT pDeviceContext; WDF_USB_DEVICE_INFORMATION deviceInfo; ULONG waitWakeEnable; UNREFERENCED_PARAMETER(ResourceList); UNREFERENCED_PARAMETER(ResourceListTranslated); waitWakeEnable = FALSE; PAGED_CODE(); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> EvtDevicePrepareHardware\n"); pDeviceContext = GetDeviceContext(Device); // // Create a USB device handle so that we can communicate with the // underlying USB stack. The WDFUSBDEVICE handle is used to query, // configure, and manage all aspects of the USB device. // These aspects include device properties, bus properties, // and I/O creation and synchronization. We only create device the first // the PrepareHardware is called. If the device is restarted by pnp manager // for resource rebalance, we will use the same device handle but then select // the interfaces again because the USB stack could reconfigure the device on // restart. // if (pDeviceContext->UsbDevice == NULL) { status = WdfUsbTargetDeviceCreate(Device, WDF_NO_OBJECT_ATTRIBUTES, &pDeviceContext->UsbDevice); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfUsbTargetDeviceCreate failed with Status code %!STATUS!\n", status); return status; } } // // Retrieve USBD version information, port driver capabilites and device // capabilites such as speed, power, etc. // WDF_USB_DEVICE_INFORMATION_INIT(&deviceInfo); status = WdfUsbTargetDeviceRetrieveInformation( pDeviceContext->UsbDevice, &deviceInfo); if (NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "IsDeviceHighSpeed: %s\n", (deviceInfo.Traits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED) ? "TRUE" : "FALSE"); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "IsDeviceSelfPowered: %s\n", (deviceInfo.Traits & WDF_USB_DEVICE_TRAIT_SELF_POWERED) ? "TRUE" : "FALSE"); waitWakeEnable = deviceInfo.Traits & WDF_USB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "IsDeviceRemoteWakeable: %s\n", waitWakeEnable ? "TRUE" : "FALSE"); // // Save these for use later. // pDeviceContext->UsbDeviceTraits = deviceInfo.Traits; } else { pDeviceContext->UsbDeviceTraits = 0; } status = SelectInterfaces(Device); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "SelectInterfaces failed 0x%x\n", status); return status; } // // Enable wait-wake and idle timeout if the device supports it // if (waitWakeEnable) { status = OsrFxSetPowerPolicy(Device); if (!NT_SUCCESS (status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "OsrFxSetPowerPolicy failed %!STATUS!\n", status); return status; } } status = OsrFxConfigContReaderForInterruptEndPoint(pDeviceContext); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- EvtDevicePrepareHardware\n"); return status; }
NTSTATUS HidFx2EvtDevicePrepareHardware( IN WDFDEVICE Device, IN WDFCMRESLIST ResourceList, IN WDFCMRESLIST ResourceListTranslated ) /*++ Routine Description: In this callback, the driver does whatever is necessary to make the hardware ready to use. In the case of a USB device, this involves reading and selecting descriptors. Arguments: Device - handle to a device ResourceList - A handle to a framework resource-list object that identifies the raw hardware resourcest ResourceListTranslated - A handle to a framework resource-list object that identifies the translated hardware resources Return Value: NT status value --*/ { NTSTATUS status = STATUS_SUCCESS; PDEVICE_EXTENSION devContext = NULL; WDF_USB_DEVICE_SELECT_CONFIG_PARAMS configParams; WDF_OBJECT_ATTRIBUTES attributes; PUSB_DEVICE_DESCRIPTOR usbDeviceDescriptor = NULL; UNREFERENCED_PARAMETER(ResourceList); UNREFERENCED_PARAMETER(ResourceListTranslated); PAGED_CODE (); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "HidFx2EvtDevicePrepareHardware Enter\n"); devContext = GetDeviceContext(Device); // // Create a WDFUSBDEVICE object. WdfUsbTargetDeviceCreate obtains the // USB device descriptor and the first USB configuration descriptor from // the device and stores them. It also creates a framework USB interface // object for each interface in the device's first configuration. // // The parent of each USB device object is the driver's framework driver // object. The driver cannot change this parent, and the ParentObject // member or the WDF_OBJECT_ATTRIBUTES structure must be NULL. // // We only create device the first time PrepareHardware is called. If // the device is restarted by pnp manager for resource rebalance, we // will use the same device handle but then select the interfaces again // because the USB stack could reconfigure the device on restart. // if (devContext->UsbDevice == NULL) { status = WdfUsbTargetDeviceCreate(Device, WDF_NO_OBJECT_ATTRIBUTES, &devContext->UsbDevice); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfUsbTargetDeviceCreate failed 0x%x\n", status); return status; } } // // Select a device configuration by using a // WDF_USB_DEVICE_SELECT_CONFIG_PARAMS structure to specify USB // descriptors, a URB, or handles to framework USB interface objects. // WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE( &configParams); status = WdfUsbTargetDeviceSelectConfig(devContext->UsbDevice, WDF_NO_OBJECT_ATTRIBUTES, &configParams); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfUsbTargetDeviceSelectConfig failed %!STATUS!\n", status); return status; } devContext->UsbInterface = configParams.Types.SingleInterface.ConfiguredUsbInterface; // // Get the device descriptor and store it in device context // WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ParentObject = Device; status = WdfMemoryCreate( &attributes, NonPagedPool, 0, sizeof(USB_DEVICE_DESCRIPTOR), &devContext->DeviceDescriptor, &usbDeviceDescriptor ); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfMemoryCreate for Device Descriptor failed %!STATUS!\n", status); return status; } WdfUsbTargetDeviceGetDeviceDescriptor( devContext->UsbDevice, usbDeviceDescriptor ); // // Get the Interrupt pipe. There are other endpoints but we are only // interested in interrupt endpoint since our HID data comes from that // endpoint. Another way to get the interrupt endpoint is by enumerating // through all the pipes in a loop and looking for pipe of Interrupt type. // devContext->InterruptPipe = WdfUsbInterfaceGetConfiguredPipe( devContext->UsbInterface, INTERRUPT_ENDPOINT_INDEX, NULL);// pipeInfo if (NULL == devContext->InterruptPipe) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "Failed to get interrupt pipe info\n"); status = STATUS_INVALID_DEVICE_STATE; return status; } // // Tell the framework that it's okay to read less than // MaximumPacketSize // WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(devContext->InterruptPipe); // //configure continuous reader // status = HidFx2ConfigContReaderForInterruptEndPoint(devContext); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "HidFx2EvtDevicePrepareHardware Exit, Status:0x%x\n", status); return status; }
/////////////////////////////////////////////////////////////////////////////// // // BasicUsbEvtDevicePrepareHardware // // This routine is called by the framework when a device of // the type we support is coming online. Our job will be to // create our WDFUSBDEVICE and configure it. // // INPUTS: // // Device - One of our WDFDEVICE objects // // ResourceList - We're a USB device, so not used // // ResourceListTranslated - We're a USB device, so not // used // // OUTPUTS: // // None. // // RETURNS: // // STATUS_SUCCESS, otherwise an error indicating why the driver could not // load. // // IRQL: // // This routine is called at IRQL == PASSIVE_LEVEL. // // NOTES: // // /////////////////////////////////////////////////////////////////////////////// NTSTATUS BasicUsbEvtDevicePrepareHardware( IN WDFDEVICE Device, IN WDFCMRESLIST ResourceList, IN WDFCMRESLIST ResourceListTranslated ) { NTSTATUS status; PBASICUSB_DEVICE_CONTEXT devContext; WDF_USB_DEVICE_SELECT_CONFIG_PARAMS selectConfigParams; WDFUSBINTERFACE configuredInterface; WDF_USB_PIPE_INFORMATION pipeInfo; UCHAR numPipes; UCHAR pipeIndex; WDFUSBPIPE configuredPipe; WDF_USB_CONTINUOUS_READER_CONFIG contReaderConfig; UNREFERENCED_PARAMETER(ResourceList); UNREFERENCED_PARAMETER(ResourceListTranslated); #if DBG DbgPrint("BasicUsbEvtDevicePrepareHardware\n"); #endif devContext = BasicUsbGetContextFromDevice(Device); // // First thing to do is create our WDFUSBDEVICE. This is the // special USB I/O target that we'll be using to configure our // device and to send control requests. // // Under very rare cirumstances (i.e. resource rebalance of the // host controller) it's possible to come through here multiple // times. We could handle this by having an // EvtDeviceReleaseHardware and cleaning up the USB device // target, but we'll just leave it around and avoid creating it // multiple times with this check. No race condition as our // Prepare and Release can't run in parallel for the same device // if (devContext->BasicUsbUsbDevice == NULL) { status = WdfUsbTargetDeviceCreate(Device, WDF_NO_OBJECT_ATTRIBUTES, &devContext->BasicUsbUsbDevice); if (!NT_SUCCESS(status)) { #if DBG DbgPrint("WdfUsbTargetDeviceCreate failed 0x%0x\n", status); #endif return status; } } // // Now that our WDFUSBDEVICE is created, it's time to select // our configuration and enable our interface. // // // The OSRFX2 device only has a single interface, so we'll // initialize our select configuration parameters structure // using the specially provided macro // WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE( &selectConfigParams); // // And actually select our configuration. // status = WdfUsbTargetDeviceSelectConfig(devContext->BasicUsbUsbDevice, WDF_NO_OBJECT_ATTRIBUTES, &selectConfigParams); if (!NT_SUCCESS(status)) { #if DBG DbgPrint("WdfUsbTargetDeviceSelectConfig failed 0x%0x\n", status); #endif return status; } // // Our single interface has been configured. Let's grab the // WDFUSBINTERFACE object so that we can get our pipes. // configuredInterface = selectConfigParams.Types.SingleInterface.ConfiguredUsbInterface; // // How many pipes were configure? // numPipes = selectConfigParams.Types.SingleInterface.NumberConfiguredPipes; // // For all the pipes that were configured.... // for(pipeIndex = 0; pipeIndex < numPipes; pipeIndex++) { // // We'll need to find out the type the pipe, which we'll do // by supplying a pipe information structure when calling // WdfUsbInterfaceGetConfiguredPipe // WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); // // Get the configured pipe. // configuredPipe = WdfUsbInterfaceGetConfiguredPipe(configuredInterface, pipeIndex, &pipeInfo); // // For this device, we're looking for three pipes: // // 1) A Bulk IN pipe // 2) A Bulk OUT pipe // 3) An Interrupt IN pipe // // // First, let's see what type of pipe it is... // switch (pipeInfo.PipeType) { case WdfUsbPipeTypeBulk: { // // Bulk pipe. Determine if it's an IN pipe or not. // if (WdfUsbTargetPipeIsInEndpoint(configuredPipe)) { // // Bulk IN pipe. Should only ever get one of these... // ASSERT(devContext->BulkInPipe == NULL); devContext->BulkInPipe = configuredPipe; } else { // // HAS to be an OUT... // ASSERT(WdfUsbTargetPipeIsOutEndpoint(configuredPipe)); // // Bulk OUT pipe. Should only ever get one of these... // ASSERT(devContext->BulkOutPipe == NULL); devContext->BulkOutPipe = configuredPipe; } break; } case WdfUsbPipeTypeInterrupt: { // // We're only expecting an IN interrupt pipe // ASSERT(WdfUsbTargetPipeIsInEndpoint(configuredPipe)); // // And we're only expected one of them // ASSERT(devContext->InterruptInPipe == NULL); devContext->InterruptInPipe = configuredPipe; break; } default: { // // Don't know what it is, don't care what it is... // #if DBG DbgPrint("Unexpected pipe type? 0x%x\n", pipeInfo.PipeType); #endif break; } } } // // We hopefully have found everything we need... // if (devContext->BulkInPipe == NULL || devContext->BulkOutPipe == NULL || devContext->InterruptInPipe == NULL) { #if DBG DbgPrint("Didn't find expected pipes. BIN=0x%p, BOUT=0x%p, IIN=0x%p\n", devContext->BulkInPipe, devContext->BulkOutPipe, devContext->InterruptInPipe); #endif return STATUS_DEVICE_CONFIGURATION_ERROR; } // // By default, KMDF will not allow any non-MaxPacketSize // aligned I/O to be done against IN pipes. This is to avoid // hitting "babble" conditions, which occur when the device // sends more data than what you've asked it for. // // Our device doesn't babble, so we don't need this check on // our IN pipes. // WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(devContext->BulkInPipe); WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(devContext->InterruptInPipe); // // For fun, we're going to hang a continuous reader out on the // interrupt endpoint. By doing so, we'll get called at // BasicUsbInterruptPipeReadComplete every time someone toggles // the switches on the switch pack. // // // Initialize the continuous reader config structure, specifying // our callback, our context, and the size of the transfers. // WDF_USB_CONTINUOUS_READER_CONFIG_INIT(&contReaderConfig, BasicUsbInterruptPipeReadComplete, devContext, sizeof(UCHAR)); // // And create the continuous reader. // // Note that the continuous reader is not started by default, so // we'll need to manually start it when we are called at // EvtD0Entry. // status = WdfUsbTargetPipeConfigContinuousReader(devContext->InterruptInPipe, &contReaderConfig); if (!NT_SUCCESS(status)) { #if DBG DbgPrint("WdfUsbTargetPipeConfigContinuousReader failed 0x%0x\n", status); #endif return status; } return STATUS_SUCCESS; }
NTSTATUS OsrFxEvtDevicePrepareHardware( IN WDFDEVICE Device, IN WDFCMRESLIST ResourceList, IN WDFCMRESLIST ResourceListTranslated ) /*++ Routine Description: In this callback, the driver does whatever is necessary to make the hardware ready to use. In the case of a USB device, this involves reading descriptors and selecting interfaces. Arguments: Device - handle to a device Return Value: NT status value --*/ { NTSTATUS status, tempStatus; PDEVICE_CONTEXT pDeviceContext; WDF_USB_DEVICE_SELECT_CONFIG_PARAMS configParams; UNREFERENCED_PARAMETER(ResourceList); UNREFERENCED_PARAMETER(ResourceListTranslated); PAGED_CODE(); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> EvtDevicePrepareHardware\n"); pDeviceContext = GetDeviceContext(Device); // // Create a USB device handle so that we can communicate with the // underlying USB stack. The WDFUSBDEVICE handle is used to query, // configure, and manage all aspects of the USB device. // These aspects include device properties, bus properties, // and I/O creation and synchronization. We only create device the first // the PrepareHardware is called. If the device is restarted by pnp manager // for resource rebalance, we will use the same device handle but then select // the interfaces again because the USB stack could reconfigure the device on // restart. // if (pDeviceContext->UsbDevice == NULL) { status = WdfUsbTargetDeviceCreate(Device, WDF_NO_OBJECT_ATTRIBUTES, &pDeviceContext->UsbDevice); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfUsbTargetDeviceCreate failed with Status code %!STATUS!\n", status); return status; } } WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE( &configParams); status = WdfUsbTargetDeviceSelectConfig(pDeviceContext->UsbDevice, WDF_NO_OBJECT_ATTRIBUTES, &configParams); if(!NT_SUCCESS(status)) { WDF_USB_DEVICE_INFORMATION deviceInfo; TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfUsbTargetDeviceSelectConfig failed %!STATUS! \n", status); // // detect if we are connected to a 1.1 USB port // WDF_USB_DEVICE_INFORMATION_INIT(&deviceInfo); tempStatus = WdfUsbTargetDeviceRetrieveInformation(pDeviceContext->UsbDevice, &deviceInfo); if (NT_SUCCESS(tempStatus)) { // // Since the Osr USB fx2 device is capable of working at high speed, the only reason // the device would not be working at high speed is if the port doesn't // support it. If the port doesn't support high speed it is a 1.1 port // if ((deviceInfo.Traits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED) == 0) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, " On a 1.1 USB port on Windows Vista" " this is expected as the OSR USB Fx2 board's Interrupt EndPoint descriptor" " doesn't conform to the USB specification. Windows Vista detects this and" " returns an error. \n" ); } } return status; } pDeviceContext->UsbInterface = configParams.Types.SingleInterface.ConfiguredUsbInterface; status = OsrFxConfigContReaderForInterruptEndPoint(pDeviceContext); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- EvtDevicePrepareHardware\n"); return status; }
// 设备配置 // 按照WDF框架,设备配置选项默认为1;如存在多个配置选项,需要切换选择的话,会比较麻烦。 // 一种办法是:使用初始化宏:WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_INTERFACES_DESCRIPTORS // 使用这个宏,需要首先获取配置描述符,和相关接口描述符。 // 另一种办法是:使用WDM方法,先构建一个配置选择的URB,然后要么自己调用IRP发送到总线驱动, // 要么使用WDF方法调用WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_URB初始化宏。 // NTSTATUS DrvClass::ConfigureUsbDevice() { WDF_USB_DEVICE_SELECT_CONFIG_PARAMS usbConfig; WDF_USB_INTERFACE_SELECT_SETTING_PARAMS interfaceSelectSetting; KDBG(DPFLTR_INFO_LEVEL, "[ConfigureUsbDevice]"); // 创建Usb设备对象。 // USB设备对象是我们进行USB操作的起点。大部分的USB接口函数,都是针对它进行的。 // USB设备对象被创建后,由驱动自己维护;框架本身不处理它,也不保持它。 NTSTATUS status = WdfUsbTargetDeviceCreate(m_hDevice, WDF_NO_OBJECT_ATTRIBUTES, &m_hUsbDevice); if(!NT_SUCCESS(status)) { KDBG(DPFLTR_INFO_LEVEL, "WdfUsbTargetDeviceCreate failed with status 0x%08x\n", status); return status; } // 接口配置 // WDF提供了多种接口配置的初始化宏,分别针对单一接口、多接口的USB设备, // 初始化宏还提供了在多个配置间进行切换的途径,正如上面所讲过的。 // 在选择默认配置的情况下,设备配置将无比简单,简单到令长期受折磨的内核程序员大跌眼镜; // 因为WDM上百行的代码逻辑,这里只要两三行就够了。 UCHAR numInterfaces = WdfUsbTargetDeviceGetNumInterfaces(m_hUsbDevice); if(1 == numInterfaces) { KDBG(DPFLTR_INFO_LEVEL, "There is one interface.", status); WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE(&usbConfig); } else// 多接口 { KDBG(DPFLTR_INFO_LEVEL, "There are %d interfaces.", numInterfaces); PWDF_USB_INTERFACE_SETTING_PAIR settingPairs = (WDF_USB_INTERFACE_SETTING_PAIR*) ExAllocatePoolWithTag(PagedPool, sizeof(WDF_USB_INTERFACE_SETTING_PAIR) * numInterfaces, POOLTAG); if (settingPairs == NULL) return STATUS_INSUFFICIENT_RESOURCES; int nNum = InitSettingPairs(m_hUsbDevice, settingPairs, numInterfaces); WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_MULTIPLE_INTERFACES(&usbConfig, nNum, settingPairs); } status = WdfUsbTargetDeviceSelectConfig(m_hUsbDevice, WDF_NO_OBJECT_ATTRIBUTES, &usbConfig); if(!NT_SUCCESS(status)) { KDBG(DPFLTR_INFO_LEVEL, "WdfUsbTargetDeviceSelectConfig failed with status 0x%08x\n", status); return status; } // 保存接口 if(1 == numInterfaces) { m_hUsbInterface = usbConfig.Types.SingleInterface.ConfiguredUsbInterface; // 使用SINGLE_INTERFACE接口配置宏,接口的AltSetting值默认为0。 // 下面两行代码演示了如何手动修改某接口的AltSetting值(此处为1). WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_INIT_SETTING(&interfaceSelectSetting, 1); status = WdfUsbInterfaceSelectSetting(m_hUsbInterface, WDF_NO_OBJECT_ATTRIBUTES, &interfaceSelectSetting); } else { int i; m_hUsbInterface = usbConfig.Types.MultiInterface.Pairs[0].UsbInterface; for(i = 0; i < numInterfaces; i++) m_hMulInterfaces[i] = usbConfig.Types.MultiInterface.Pairs[i].UsbInterface; } return status; }
// In this callback, the driver does whatever is necessary to make the hardware ready to use. // In the case of a USB device, this involves reading and selecting descriptors. NTSTATUS HidFx2EvtDevicePrepareHardware( _In_ WDFDEVICE hDevice, _In_ WDFCMRESLIST hResourceList, _In_ WDFCMRESLIST hResourceListTranslated ) { NTSTATUS status = STATUS_SUCCESS; PDEVICE_EXTENSION pDevContext = NULL; WDF_USB_DEVICE_SELECT_CONFIG_PARAMS configParams; WDF_OBJECT_ATTRIBUTES attributes; PUSB_DEVICE_DESCRIPTOR pUsbDeviceDescriptor = NULL; UNREFERENCED_PARAMETER(hResourceList); UNREFERENCED_PARAMETER(hResourceListTranslated); PAGED_CODE (); TraceVerbose(DBG_INIT, "(%!FUNC!) Enter\n"); pDevContext = GetDeviceContext(hDevice); // Create a WDFUSBDEVICE object. WdfUsbTargetDeviceCreate obtains the USB device descriptor and the first USB configuration //descriptor from the device and stores them. It also creates a framework USB interface object for each interface in the device's first configuration. // // The parent of each USB device object is the driver's framework driver object. The driver cannot change this parent, and the ParentObject // member or the WDF_OBJECT_ATTRIBUTES structure must be NULL. // // We only create device the first time PrepareHardware is called. If the device is restarted by pnp manager for resource rebalance, we // will use the same device handle but then select the interfaces again because the USB stack could reconfigure the device on restart. if (pDevContext->hUsbDevice == NULL) { status = WdfUsbTargetDeviceCreate(hDevice, WDF_NO_OBJECT_ATTRIBUTES, &pDevContext->hUsbDevice); if (!NT_SUCCESS(status)) { TraceErr(DBG_PNP, "(%!FUNC!) WdfUsbTargetDeviceCreate failed %!STATUS!\n", status); return status; } } // Select a device configuration by using a WDF_USB_DEVICE_SELECT_CONFIG_PARAMS WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE(&configParams); status = WdfUsbTargetDeviceSelectConfig(pDevContext->hUsbDevice, WDF_NO_OBJECT_ATTRIBUTES, &configParams); if (!NT_SUCCESS(status)) { TraceErr(DBG_PNP, "(%!FUNC!) WdfUsbTargetDeviceSelectConfig failed %!STATUS!\n", status); return status; } pDevContext->hUsbInterface = configParams.Types.SingleInterface.ConfiguredUsbInterface; // Get the device descriptor and store it in device context WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ParentObject = hDevice; status = WdfMemoryCreate(&attributes, NonPagedPool, 0, sizeof(USB_DEVICE_DESCRIPTOR), &pDevContext->hDeviceDescriptor, &pUsbDeviceDescriptor); if (!NT_SUCCESS(status)) { TraceErr(DBG_PNP, "(%!FUNC!) WdfMemoryCreate for Device Descriptor failed %!STATUS!\n", status); return status; } WdfUsbTargetDeviceGetDeviceDescriptor(pDevContext->hUsbDevice, pUsbDeviceDescriptor); // Get the Interrupt pipe. There are other endpoints but we are only interested in interrupt endpoint since our HID data comes from this pDevContext->hInterruptPipe = WdfUsbInterfaceGetConfiguredPipe(pDevContext->hUsbInterface, INTERRUPT_ENDPOINT_INDEX, NULL); if (NULL == pDevContext->hInterruptPipe) { TraceErr(DBG_PNP, "(%!FUNC!) Failed to get interrupt pipe info\n"); status = STATUS_INVALID_DEVICE_STATE; return status; } // Tell the framework that it's okay to read less than MaximumPacketSize WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(pDevContext->hInterruptPipe); //configure continuous reader status = HidFx2ConfigContReaderForInterruptEndPoint(pDevContext); TraceVerbose(DBG_INIT, "(%!FUNC!) Exit, Status: %!STATUS!\n", status); return status; }
NTSTATUS AndroidUsbDeviceObject::OnEvtDevicePrepareHardware( WDFCMRESLIST resources_raw, WDFCMRESLIST resources_translated) { ASSERT_IRQL_PASSIVE(); // Create a USB device handle so that we can communicate with the underlying // USB stack. The wdf_target_device_ handle is used to query, configure, and // manage all aspects of the USB device. These aspects include device // properties, bus properties, and I/O creation and synchronization. This // call gets the device and configuration descriptors and stores them in // wdf_target_device_ object. NTSTATUS status = WdfUsbTargetDeviceCreate(wdf_device(), WDF_NO_OBJECT_ATTRIBUTES, &wdf_target_device_); ASSERT(NT_SUCCESS(status) && (NULL != wdf_target_device_)); if (!NT_SUCCESS(status)) return status; // Retrieve USBD version information, port driver capabilites and device // capabilites such as speed, power, etc. WDF_USB_DEVICE_INFORMATION_INIT(&usb_device_info_); status = WdfUsbTargetDeviceRetrieveInformation(wdf_target_device(), &usb_device_info_); ASSERT(NT_SUCCESS(status)); if (!NT_SUCCESS(status)) return status; WdfUsbTargetDeviceGetDeviceDescriptor(wdf_target_device(), &usb_device_descriptor_); #if DBG PrintUsbTargedDeviceInformation(usb_device_info()); PrintUsbDeviceDescriptor(&usb_device_descriptor_); #endif // DBG // Save device serial number status = WdfUsbTargetDeviceAllocAndQueryString(wdf_target_device(), WDF_NO_OBJECT_ATTRIBUTES, &serial_number_handle_, &serial_number_char_len_, usb_device_descriptor_.iSerialNumber, 0x0409); // English (US) if (!NT_SUCCESS(status)) return status; #if DBG UNICODE_STRING ser_num; ser_num.Length = serial_number_byte_len(); ser_num.MaximumLength = ser_num.Length; ser_num.Buffer = const_cast<WCHAR*> (serial_number()); GoogleDbgPrint("\n*** Device serial number %wZ", &ser_num); #endif // DBG // Configure our device now status = ConfigureDevice(); ASSERT(NT_SUCCESS(status)); if (!NT_SUCCESS(status)) return status; // Select device interfaces status = SelectInterfaces(); if (!NT_SUCCESS(status)) return status; return status; }
NTSTATUS CyEvtDevicePrepareHardware ( IN WDFDEVICE Device, IN WDFCMRESLIST ResourcesRaw, IN WDFCMRESLIST ResourcesTranslated ) { NTSTATUS NTStatus; PDEVICE_CONTEXT pDeviceContext; WDF_USB_DEVICE_INFORMATION UsbDeviceInfo; ULONG ulWaitWakeEnable; UNICODE_STRING unicodeSCRIPTFILE; WDF_OBJECT_ATTRIBUTES attributes; WDFMEMORY hScriptFileNameBufMem; PVOID pScriptFNBuf=NULL; ULONG ScripFileNtBufferlen=0; UNREFERENCED_PARAMETER(ResourcesRaw); UNREFERENCED_PARAMETER(ResourcesTranslated); ulWaitWakeEnable = FALSE; PAGED_CODE(); CyTraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "Start CyEvtDevicePrepareHardware\n"); pDeviceContext = CyGetDeviceContext(Device); // // Create a USB device handle so that we can communicate with the // underlying USB stack. The WDFUSBDEVICE handle is used to query, // configure, and manage all aspects of the USB device. // These aspects include device properties, bus properties, // and I/O creation and synchronization. We only create device the first // the PrepareHardware is called. If the device is restarted by pnp manager // for resource rebalance, we will use the same device handle but then select // the interfaces again because the USB stack could reconfigure the device on // restart. // if (pDeviceContext->CyUsbDevice == NULL) { NTStatus = WdfUsbTargetDeviceCreate(Device, WDF_NO_OBJECT_ATTRIBUTES, &pDeviceContext->CyUsbDevice); if (!NT_SUCCESS(NTStatus)) { CyTraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfUsbTargetDeviceCreate failed with Status code %!STATUS!\n", NTStatus); return NTStatus; } } // // Retrieve USBD version information, port driver capabilites and device // capabilites such as speed, power, etc. // WDF_USB_DEVICE_INFORMATION_INIT(&UsbDeviceInfo); NTStatus = WdfUsbTargetDeviceRetrieveInformation( pDeviceContext->CyUsbDevice, &UsbDeviceInfo); if (NT_SUCCESS(NTStatus)) { CyTraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "IsDeviceHighSpeed: %s\n", (UsbDeviceInfo.Traits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED) ? "TRUE" : "FALSE"); CyTraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "IsDeviceSelfPowered: %s\n", (UsbDeviceInfo.Traits & WDF_USB_DEVICE_TRAIT_SELF_POWERED) ? "TRUE" : "FALSE"); ulWaitWakeEnable = UsbDeviceInfo.Traits & WDF_USB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE; CyTraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "IsDeviceRemoteWakeable: %s\n", ulWaitWakeEnable ? "TRUE" : "FALSE"); pDeviceContext->ulUSBDeviceTrait = UsbDeviceInfo.Traits; pDeviceContext->ulUSBDIVersion = UsbDeviceInfo.UsbdVersionInformation.USBDI_Version; pDeviceContext->ulWaitWakeEnable = ulWaitWakeEnable; } //Get device descriptor WdfUsbTargetDeviceGetDeviceDescriptor( pDeviceContext->CyUsbDevice, &pDeviceContext->UsbDeviceDescriptor ); NTStatus = CySelectInterfaces(Device); if (!NT_SUCCESS(NTStatus)) { CyTraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "SelectInterfaces failed 0x%x\n", NTStatus); return NTStatus; } if (ulWaitWakeEnable) { NTStatus = CySetPowerPolicy(Device); if (!NT_SUCCESS (NTStatus)) { CyTraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "Set power policy failed %!STATUS!\n", NTStatus); return NTStatus; } } // Check for the script file in the registry and execute if it is exist // Allocate buffer to get the registry key WDF_OBJECT_ATTRIBUTES_INIT(&attributes); NTStatus = WdfMemoryCreate( &attributes, NonPagedPool, 0, CYREGSCRIPT_BUFFER_SIZE, &hScriptFileNameBufMem, &pScriptFNBuf ); if (!NT_SUCCESS(NTStatus)) { CyTraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfMemoryCreate failed %!STATUS!\n",NTStatus); return FALSE; } if(GetRegistryKey(Device, NULL, REG_SZ, CYREG_SCRIPTFILE, pScriptFNBuf,&ScripFileNtBufferlen)) { CyExecuteScriptFile(Device, pScriptFNBuf); } CyTraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "End CyEvtDevicePrepareHardware\n"); //// CyTraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "End CyEvtDevicePrepareHardware\n"); return NTStatus; }