NTSTATUS AndroidUsbDeviceObject::OnEvtDeviceReleaseHardware( WDFCMRESLIST resources_translated) { ASSERT_IRQL_PASSIVE(); // It's possible that Preparehardware failed half way thru. So make // sure the target device exists. if (!IsTaretDeviceCreated()) return STATUS_SUCCESS; // Cancel all the currently queued I/O. This is better than sending an // explicit USB abort request down because release hardware gets // called even when the device surprise-removed. WdfIoTargetStop(WdfUsbTargetDeviceGetIoTarget(wdf_target_device()), WdfIoTargetCancelSentIo); // Unselect all selected configurations WDF_USB_DEVICE_SELECT_CONFIG_PARAMS config_params; WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_DECONFIG(&config_params); NTSTATUS status = WdfUsbTargetDeviceSelectConfig(wdf_target_device(), WDF_NO_OBJECT_ATTRIBUTES, &config_params); ASSERT(NT_SUCCESS(status) || (STATUS_DEVICE_NOT_CONNECTED == status)); return status; }
static NTSTATUS UsbChief_SelectInterfaces(IN WDFDEVICE Device) { WDF_USB_DEVICE_SELECT_CONFIG_PARAMS configParams; NTSTATUS Status; PDEVICE_CONTEXT pDeviceContext; PAGED_CODE(); pDeviceContext = GetDeviceContext(Device); WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE( &configParams); Status = WdfUsbTargetDeviceSelectConfig(pDeviceContext->WdfUsbTargetDevice, WDF_NO_OBJECT_ATTRIBUTES, &configParams); if (NT_SUCCESS(Status) && WdfUsbTargetDeviceGetNumInterfaces(pDeviceContext->WdfUsbTargetDevice) > 0) { pDeviceContext->UsbInterface = configParams.Types.SingleInterface.ConfiguredUsbInterface; pDeviceContext->NumberConfiguredPipes = configParams.Types.SingleInterface.NumberConfiguredPipes; } return Status; }
NTSTATUS EvtDevicePrepareHardware( IN WDFDEVICE Device, IN WDFCMRESLIST ResourceList, IN WDFCMRESLIST ResourceListTranslated ) { NTSTATUS status; PDEVICE_CONTEXT pDeviceContext; WDF_USB_DEVICE_SELECT_CONFIG_PARAMS configParams; UNREFERENCED_PARAMETER(ResourceList); UNREFERENCED_PARAMETER(ResourceListTranslated); pDeviceContext = GetDeviceContext(Device); // // Create the USB device if it is not already created. // if (pDeviceContext->UsbDevice == NULL) { WDF_USB_DEVICE_CREATE_CONFIG config; WDF_USB_DEVICE_CREATE_CONFIG_INIT(&config, USBD_CLIENT_CONTRACT_VERSION_602); status = WdfUsbTargetDeviceCreateWithParameters(Device, &config, WDF_NO_OBJECT_ATTRIBUTES, &pDeviceContext->UsbDevice); if (!NT_SUCCESS(status)) { KdPrint(("WdfUsbTargetDeviceCreateWithParameters failed 0x%x\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)) { KdPrint(("WdfUsbTargetDeviceSelectConfig failed 0x%x\n", status)); return status; } pDeviceContext->UsbInterface = configParams.Types.SingleInterface.ConfiguredUsbInterface; return status; }
// 此函数类似于WDM中的PNP_MN_STOP_DEVICE函数,在设备移除时被调用。 // 当个函数被调用时候,设备仍处于工作状态。 NTSTATUS DrvClass::PnpReleaseHardware(IN WDFCMRESLIST ResourceListTranslated) { KDBG(DPFLTR_INFO_LEVEL, "[PnpReleaseHardware]"); // 如果PnpPrepareHardware调用失败,UsbDevice为空; // 这时候直接返回即可。 if (m_hUsbDevice == NULL) return STATUS_SUCCESS; // 取消USB设备的所有IO操作。它将连带取消所有Pipe的IO操作。 WdfIoTargetStop(WdfUsbTargetDeviceGetIoTarget(m_hUsbDevice), WdfIoTargetCancelSentIo); // Deconfiguration或者“反配置” WDF_USB_DEVICE_SELECT_CONFIG_PARAMS configParams; WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_DECONFIG(&configParams); return WdfUsbTargetDeviceSelectConfig(m_hUsbDevice, WDF_NO_OBJECT_ATTRIBUTES, &configParams); }
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; }
/*++ Routine Description: This helper routine selects the configuration, interface and creates a context for every pipe (end point) in that interface. Arguments: Device - Handle to a framework device Return Value: NT status value --*/ NTSTATUS SelectInterfaces(IN WDFDEVICE Device) { WDF_USB_DEVICE_SELECT_CONFIG_PARAMS configParams; NTSTATUS status; PDEVICE_CONTEXT pDeviceContext; UCHAR numInterfaces; PAGED_CODE(); pDeviceContext = GetDeviceContext(Device); numInterfaces = WdfUsbTargetDeviceGetNumInterfaces(pDeviceContext->WdfUsbTargetDevice); if (numInterfaces == 1) { // The device has only 1 interface. PSDrv_DbgPrint(3, ("Device has a single interface!\n")); WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE(&configParams); status = WdfUsbTargetDeviceSelectConfig(pDeviceContext->WdfUsbTargetDevice, WDF_NO_OBJECT_ATTRIBUTES, &configParams); if (NT_SUCCESS(status) && numInterfaces > 0) { pDeviceContext->UsbInterface = configParams.Types.SingleInterface.ConfiguredUsbInterface; pDeviceContext->NumberConfiguredPipes = configParams.Types.SingleInterface.NumberConfiguredPipes; } } else { // The device has more then one interface... PSDrv_DbgPrint(3, ("Device has multiple interfaces (%d) - this is not supported yet!\n", numInterfaces)); status = STATUS_NOT_SUPPORTED; } pDeviceContext->nCurrIf = 0; pDeviceContext->nCurrAltIf = 0; 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::SelectInterfaces() { ASSERT_IRQL_PASSIVE(); ASSERT(IsDeviceConfigured()); if (!IsDeviceConfigured()) return STATUS_INTERNAL_ERROR; WDF_USB_DEVICE_SELECT_CONFIG_PARAMS config_params; PWDF_USB_INTERFACE_SETTING_PAIR pairs = NULL; // TODO: We need to find a way (possibly by looking at each // interface descriptor) to get index of the ADB interface in multiinterface // configuration. UCHAR adb_interface_index = 0; if (IsSingleInterfaceDevice()) { // Our device has only one interface, so we don't have to bother with // multiple interfaces at all. GoogleDbgPrint("\n********** Device reports single interface"); // Select single interface configuration WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE(&config_params); } else { // Configure multiple interfaces ULONG num_interf = GetInterfaceCount(); GoogleDbgPrint("\n********** Device reports %u interfaces", num_interf); // Allocate pairs for each interface pairs = new(PagedPool, GANDR_POOL_TAG_INTERF_PAIRS) WDF_USB_INTERFACE_SETTING_PAIR[num_interf]; ASSERT(NULL != pairs); if (NULL == pairs) return STATUS_INSUFFICIENT_RESOURCES; adb_interface_index = 1; // Initialize each interface pair for (UCHAR pair = 0; pair < num_interf; pair++) { pairs[pair].SettingIndex = 0; pairs[pair].UsbInterface = WdfUsbTargetDeviceGetInterface(wdf_target_device(), pair); ASSERT(NULL != pairs[pair].UsbInterface); if (NULL == pairs[pair].UsbInterface) { delete[] pairs; return STATUS_INTERNAL_ERROR; } } // Select multiinterface configuration WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_MULTIPLE_INTERFACES(&config_params, (UCHAR)num_interf, pairs); } NTSTATUS status = WdfUsbTargetDeviceSelectConfig(wdf_target_device(), WDF_NO_OBJECT_ATTRIBUTES, &config_params); if (NULL != pairs) delete[] pairs; // ASSERT(NT_SUCCESS(status)); if (!NT_SUCCESS(status)) return status; #if DBG PrintSelectedConfig(&config_params); #endif // DBG wdf_usb_interface_ = WdfUsbTargetDeviceGetInterface(wdf_target_device(), adb_interface_index); ASSERT(NULL != wdf_usb_interface_); if (NULL == wdf_usb_interface_) return STATUS_INTERNAL_ERROR; configured_pipes_num_ = WdfUsbInterfaceGetNumEndpoints(wdf_usb_interface(), 0); ASSERT(0 != configured_pipes_num_); // Cache selected interface descriptor BYTE setting_index = WdfUsbInterfaceGetConfiguredSettingIndex(wdf_usb_interface()); WdfUsbInterfaceGetDescriptor(wdf_usb_interface(), setting_index, &interface_descriptor_); #if DBG PrintInterfaceDescriptor(interface_descriptor()); #endif // DBG // Iterate over pipes, decoding and saving info about bulk r/w pipes for // easier and faster addressing later on when they get opened for (UCHAR pipe = 0; pipe < configured_pipes_num(); pipe++) { WDF_USB_PIPE_INFORMATION pipe_info; WDF_USB_PIPE_INFORMATION_INIT(&pipe_info); WDFUSBPIPE wdf_pipe_obj = WdfUsbInterfaceGetConfiguredPipe(wdf_usb_interface(), pipe, &pipe_info); ASSERT(NULL != wdf_pipe_obj); if (NULL != wdf_pipe_obj) { if ((WdfUsbPipeTypeBulk == pipe_info.PipeType) && WDF_USB_PIPE_DIRECTION_IN(pipe_info.EndpointAddress)) { // This is a bulk read pipe ASSERT(!IsBulkReadPipeKnown()); bulk_read_pipe_index_ = pipe; } else { ASSERT(!IsBulkWritePipeKnown()); bulk_write_pipe_index_ = pipe; } } #if DBG PrintPipeInformation(&pipe_info, pipe); #endif // DBG } // At the end we must have calculated indexes for both, // bulk read and write pipes ASSERT(!NT_SUCCESS(status) || (IsBulkReadPipeKnown() && IsBulkWritePipeKnown())); return status; }
NTSTATUS TemperUsbDriverEvtDevicePrepareHardware( _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 Return Value: NT status value --*/ { NTSTATUS status; PDEVICE_CONTEXT pDeviceContext; WDF_USB_DEVICE_CREATE_CONFIG createParams; WDF_USB_DEVICE_SELECT_CONFIG_PARAMS configParams; UNREFERENCED_PARAMETER(ResourceList); UNREFERENCED_PARAMETER(ResourceListTranslated); TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry"); status = STATUS_SUCCESS; pDeviceContext = DeviceGetContext(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 the 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 (pDeviceContext->UsbDevice == NULL) { status = WdfUsbTargetDeviceCreateWithParameters(Device, &createParams, WDF_NO_OBJECT_ATTRIBUTES, &pDeviceContext->UsbDevice ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "WdfUsbTargetDeviceCreateWithParameters failed 0x%x", status); return status; } } // // Select the first configuration of the device, using the first alternate // setting of each interface // WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_MULTIPLE_INTERFACES(&configParams, 0, NULL ); status = WdfUsbTargetDeviceSelectConfig(pDeviceContext->UsbDevice, WDF_NO_OBJECT_ATTRIBUTES, &configParams ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE, "WdfUsbTargetDeviceSelectConfig failed 0x%x", status); return status; } TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit"); return status; }
NTSTATUS SelectInterfaces( __in WDFDEVICE Device ) /*++ Routine Description: This helper routine selects the configuration, interface and creates a context for every pipe (end point) in that interface. Arguments: Device - Handle to a framework device Return Value: NT status value --*/ { WDF_USB_DEVICE_SELECT_CONFIG_PARAMS configParams; NTSTATUS status; PDEVICE_CONTEXT pDeviceContext; WDFUSBPIPE pipe; WDF_USB_PIPE_INFORMATION pipeInfo; UCHAR index; UCHAR numberConfiguredPipes; PAGED_CODE(); pDeviceContext = GetDeviceContext(Device); WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE( &configParams); status = WdfUsbTargetDeviceSelectConfig(pDeviceContext->UsbDevice, WDF_NO_OBJECT_ATTRIBUTES, &configParams); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfUsbTargetDeviceSelectConfig failed %!STATUS! \n", status); // // 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 ((pDeviceContext->UsbDeviceTraits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED) == 0) { GUID activity = DeviceToActivityId(Device); 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" ); EventWriteSelectConfigFailure( &activity, pDeviceContext->DeviceName, pDeviceContext->Location, status ); } return status; } pDeviceContext->UsbInterface = configParams.Types.SingleInterface.ConfiguredUsbInterface; numberConfiguredPipes = configParams.Types.SingleInterface.NumberConfiguredPipes; // // Get pipe handles // for(index=0; index < numberConfiguredPipes; index++) { WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); pipe = WdfUsbInterfaceGetConfiguredPipe( pDeviceContext->UsbInterface, index, //PipeIndex, &pipeInfo ); // // Tell the framework that it's okay to read less than // MaximumPacketSize // WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(pipe); if(WdfUsbPipeTypeInterrupt == pipeInfo.PipeType) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "Interrupt Pipe is 0x%p\n", pipe); pDeviceContext->InterruptPipe = pipe; } if(WdfUsbPipeTypeBulk == pipeInfo.PipeType && WdfUsbTargetPipeIsInEndpoint(pipe)) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "BulkInput Pipe is 0x%p\n", pipe); pDeviceContext->BulkReadPipe = pipe; } if(WdfUsbPipeTypeBulk == pipeInfo.PipeType && WdfUsbTargetPipeIsOutEndpoint(pipe)) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "BulkOutput Pipe is 0x%p\n", pipe); pDeviceContext->BulkWritePipe = pipe; } } // // If we didn't find all the 3 pipes, fail the start. // if(!(pDeviceContext->BulkWritePipe && pDeviceContext->BulkReadPipe && pDeviceContext->InterruptPipe)) { status = STATUS_INVALID_DEVICE_STATE; TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "Device is not configured properly %!STATUS!\n", status); return status; } return status; }
NTSTATUS CySelectInterfaces( __in WDFDEVICE Device ) { NTSTATUS NTStatus; PDEVICE_CONTEXT pDeviceContext; BYTE altSettings; PAGED_CODE(); CyTraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,"Start CySelectInterfaces\n"); pDeviceContext = CyGetDeviceContext(Device); pDeviceContext->ucNumberOfInterface = WdfUsbTargetDeviceGetNumInterfaces(pDeviceContext->CyUsbDevice); /*if(pDeviceContext->ucNumberOfInterface == 1)*/ { CyTraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP," Single interface\n"); pDeviceContext->bIsMultiplInterface = FALSE; WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE(&pDeviceContext->UsbInterfaceConfig); } //else //{ // CyTraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,"Multiple interface :0x%x\n",pDeviceContext->ucNumberOfInterface); // pDeviceContext->bIsMultiplInterface = TRUE; // pDeviceContext->MultipleInterfacePair = ExAllocatePoolWithTag(PagedPool, // sizeof(WDF_USB_INTERFACE_SETTING_PAIR) * pDeviceContext->ucNumberOfInterface, // CYMEM_TAG // ); // if (pDeviceContext->MultipleInterfacePair == NULL) // { // CyTraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,"Insufficient resources\n"); // return STATUS_INSUFFICIENT_RESOURCES; // } // // // // Call driver-defined routine to populate the // // WDF_USB_INTERFACE_SETTING_PAIR structures // // that ExAllocatePoolWithTag allocated. // // // InitInterfacePair( // pDeviceContext->CyUsbDevice, // pDeviceContext->MultipleInterfacePair, // pDeviceContext->ucNumberOfInterface // ); // WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_MULTIPLE_INTERFACES( // &pDeviceContext->UsbInterfaceConfig, // pDeviceContext->ucNumberOfInterface, // pDeviceContext->MultipleInterfacePair // ); //} NTStatus = WdfUsbTargetDeviceSelectConfig(pDeviceContext->CyUsbDevice, WDF_NO_OBJECT_ATTRIBUTES, &pDeviceContext->UsbInterfaceConfig); if(!NT_SUCCESS(NTStatus)) { CyTraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, "WdfUsbTargetDeviceSelectConfig failed %!STATUS! \n", NTStatus); return NTStatus; } pDeviceContext->ucNumAltSettigns = WdfUsbInterfaceGetNumSettings(pDeviceContext->UsbInterfaceConfig.Types.SingleInterface.ConfiguredUsbInterface); pDeviceContext->ucActiveAltSettings = 0; /* First active alternat settings will be ZERO */ pDeviceContext->ucActiveConfigNum = 0; // This is the defaul configuration number if(!(pDeviceContext->bIsMultiplInterface)) {//single interface CyGetActiveAltInterfaceConfig(pDeviceContext); } else {// Multiple interface cyGetMultipleInterfaceConfig(pDeviceContext); } pDeviceContext->ucNumberOfInterfaceCompositUSB30Only = 0; // intialize // Check if device is USB3.0 then parse the device configuration and store SS EP information if(pDeviceContext->UsbDeviceDescriptor.bcdUSB == USB30MAJORVER) { /* RTL_OSVERSIONINFOW lpVersionInformation= {0}; //WORKAROUND : WIN 8 based xHCI does not provide USBDI version of xHCI driver stack, so adding this works around to differenciate OS // Get the OS version if it is WIN 8 then we do not need to parse the descriptor table to get the MaxBurst other paramter as it is being added to MaxPacketSize in Windows 9 if(RtlGetVersion(&lpVersionInformation)==STATUS_SUCCESS) { CyTraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,"Operting System Version information\n"); CyTraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,"dwMajorVersion:%x dwMinorVersion:%x dwBuildNumber:%x\n",lpVersionInformation.dwMajorVersion ,lpVersionInformation.dwMinorVersion ,lpVersionInformation.dwBuildNumber); } if(!((lpVersionInformation.dwMajorVersion==6) && (lpVersionInformation.dwMinorVersion ==2)))*/ CyGetAndParseUSB30DeviceConfiguration(pDeviceContext); } CyTraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,"End CySelectInterfaces\n"); return NTStatus; }