NTSTATUS OsrFxEvtDeviceD0Exit( IN WDFDEVICE Device, IN WDF_POWER_DEVICE_STATE TargetState ) /*++ Routine Description: This routine undoes anything done in EvtDeviceD0Entry. It is called whenever the device leaves the D0 state, which happens when the device is stopped, when it is removed, and when it is powered off. The device is still in D0 when this callback is invoked, which means that the driver can still touch hardware in this routine. EvtDeviceD0Exit event callback must perform any operations that are necessary before the specified device is moved out of the D0 state. If the driver needs to save hardware state before the device is powered down, then that should be done here. This function runs at PASSIVE_LEVEL, though it is generally not paged. A driver can optionally make this function pageable if DO_POWER_PAGABLE is set. Even if DO_POWER_PAGABLE isn't set, this function still runs at PASSIVE_LEVEL. In this case, though, the function absolutely must not do anything that will cause a page fault. Arguments: Device - Handle to a framework device object. TargetState - Device power state which the device will be put in once this callback is complete. Return Value: Success implies that the device can be used. Failure will result in the device stack being torn down. --*/ { PDEVICE_CONTEXT pDeviceContext; PAGED_CODE(); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, "-->OsrFxEvtDeviceD0Exit - moving to %s\n", DbgDevicePowerString(TargetState)); pDeviceContext = GetDeviceContext(Device); WdfIoTargetStop(WdfUsbTargetDeviceGetIoTarget(pDeviceContext->UsbDevice), WdfIoTargetCancelSentIo); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, "<--OsrFxEvtDeviceD0Exit\n"); return STATUS_SUCCESS; }
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; }
NTSTATUS OsrFxEvtDeviceD0Entry( IN WDFDEVICE Device, IN WDF_POWER_DEVICE_STATE PreviousState ) /*++ Routine Description: EvtDeviceD0Entry event callback must perform any operations that are necessary before the specified device is used. It will be called every time the hardware needs to be (re-)initialized. This function is not marked pageable because this function is in the device power up path. When a function is marked pagable and the code section is paged out, it will generate a page fault which could impact the fast resume behavior because the client driver will have to wait until the system drivers can service this page fault. This function runs at PASSIVE_LEVEL, even though it is not paged. A driver can optionally make this function pageable if DO_POWER_PAGABLE is set. Even if DO_POWER_PAGABLE isn't set, this function still runs at PASSIVE_LEVEL. In this case, though, the function absolutely must not do anything that will cause a page fault. Arguments: Device - Handle to a framework device object. PreviousState - Device power state which the device was in most recently. If the device is being newly started, this will be PowerDeviceUnspecified. Return Value: NTSTATUS --*/ { PDEVICE_CONTEXT pDeviceContext; NTSTATUS status; pDeviceContext = GetDeviceContext(Device); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, "-->OsrFxEvtEvtDeviceD0Entry - coming from %s\n", DbgDevicePowerString(PreviousState)); status = WdfIoTargetStart(WdfUsbTargetDeviceGetIoTarget(pDeviceContext->UsbDevice)); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, "<--OsrFxEvtEvtDeviceD0Entry\n"); 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); }
VOID XferCtrl ( __in WDFQUEUE Queue, __in WDFREQUEST Request, __in size_t InputBufferLength, __in size_t OutputBufferLength) { NTSTATUS status; PDEVICE_CONTEXT deviceContext; PREQUEST_CONTEXT requestContext; WDFMEMORY transferMemory; PWDF_USB_CONTROL_SETUP_PACKET setupPacket; WDF_REQUEST_SEND_OPTIONS sendOptions; WDFMEMORY_OFFSET _transferOffset; PWDFMEMORY_OFFSET transferOffset = &_transferOffset; UNREFERENCED_PARAMETER(InputBufferLength); UNREFERENCED_PARAMETER(OutputBufferLength); deviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); requestContext = GetRequestContext(Request); setupPacket = (PWDF_USB_CONTROL_SETUP_PACKET)&requestContext->IoControlRequest.control; USBDBG("bmDir=%s bmType=%s bmRecipient=%s bmReserved=%03u bRequest=%u wIndex=%u wValue=%u wLength=%u\n", GetBmRequestDirString(setupPacket->Packet.bm.Request.Dir), GetBmRequestTypeString(setupPacket->Packet.bm.Request.Type), GetBmRequestRecipientString(setupPacket->Packet.bm.Request.Recipient), setupPacket->Packet.bm.Request.Reserved, setupPacket->Packet.bRequest, setupPacket->Packet.wIndex.Value, setupPacket->Packet.wValue.Value, setupPacket->Packet.wLength); // If the device and config descriptor requests are not handled they will be the "true" // descriptors directly from the device. i.e. if the device has two unassociated interfaces // the composite layer will split it into two but each virtual device interface would show // both interface deacriptors. // if (setupPacket->Packet.bm.Request.Dir == BMREQUEST_DEVICE_TO_HOST && setupPacket->Packet.bm.Request.Type == BMREQUEST_STANDARD && setupPacket->Packet.bRequest == USB_REQUEST_GET_DESCRIPTOR) { UCHAR descriptorType = setupPacket->Packet.wValue.Bytes.HiByte; // UCHAR descriptorIndex = setupPacket->Packet.wValue.Bytes.LowByte; ULONG descriptorSize = 0; PVOID descriptorIn = NULL; PVOID outputBuffer = NULL; size_t outputBufferLength = 0; if (requestContext->IoControlCode == LIBUSB_IOCTL_GET_DESCRIPTOR) { switch(descriptorType) { case USB_DESCRIPTOR_TYPE_DEVICE: descriptorSize = sizeof(deviceContext->UsbDeviceDescriptor); descriptorIn = &deviceContext->UsbDeviceDescriptor; break; case USB_DESCRIPTOR_TYPE_CONFIGURATION: if (setupPacket->Packet.wValue.Bytes.LowByte == 0) { descriptorSize = deviceContext->ConfigurationDescriptorSize; descriptorIn = deviceContext->UsbConfigurationDescriptor; } else { // we only support the one for now. ;) WdfRequestCompleteWithInformation(Request, STATUS_NO_MORE_ENTRIES, 0); return; } break; } if (descriptorIn && descriptorSize) { // handle (or fail) this standard request here. status = WdfRequestRetrieveOutputBuffer(Request, 2, &outputBuffer, &outputBufferLength); if (NT_SUCCESS(status)) { descriptorSize = (ULONG)min(descriptorSize, outputBufferLength); RtlCopyMemory(outputBuffer, descriptorIn, descriptorSize); WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, descriptorSize); return; } USBERR("WdfRequestRetrieveOutputBuffer failed. status=%Xh\n", status); WdfRequestCompleteWithInformation(Request, status, 0); return; } } } if (METHOD_FROM_CTL_CODE(requestContext->IoControlCode) == METHOD_BUFFERED && requestContext->RequestType == WdfRequestTypeWrite) { // support for some of the legacy LIBUSB_IOCTL codes which place the data input // buffer at the end of the libusb_request structure. status = WdfRequestRetrieveInputMemory(Request, &transferMemory); if (!NT_SUCCESS(status)) { USBERR("WdfRequestRetrieveInputMemory failed. status=%Xh\n", status); goto Exit; } if (requestContext->Length < sizeof(libusb_request)) { // this can never happen because the input buffer length is checked for // this by the default IoControl event. status = STATUS_BUFFER_TOO_SMALL; USBERR("input buffer length is less than sizeof(libusb_request) status=%Xh\n", status); goto Exit; } transferOffset->BufferOffset = sizeof(libusb_request); transferOffset->BufferLength = requestContext->Length - sizeof(libusb_request); if (transferOffset->BufferLength == 0) { // this is okay but no input data means transferOffset->BufferOffset is pointing // to invalid memory; because the length is also zero it is still most likely safe. transferOffset = NULL; transferMemory = NULL; } } else { // native control transfers are direct; data comes from/goes to the out buffer whether reading or writing. transferOffset = NULL; status = WdfRequestRetrieveOutputMemory(Request, &transferMemory); if (!NT_SUCCESS(status) && status != STATUS_BUFFER_TOO_SMALL) { USBERR("WdfRequestRetrieveOutputMemory failed. status=%Xh\n", status); goto Exit; } if (status == STATUS_BUFFER_TOO_SMALL) { // zero length transfer buffer, this is okay. transferMemory = NULL; USBMSG("zero-length transfer buffer\n"); } } status = WdfUsbTargetDeviceFormatRequestForControlTransfer( deviceContext->WdfUsbTargetDevice, Request, setupPacket, transferMemory, transferOffset); if (!NT_SUCCESS(status)) { USBERR("WdfUsbTargetDeviceFormatRequestForControlTransfer failed. status=%Xh\n", status); goto Exit; } WdfRequestSetCompletionRoutine(Request, XferCtrlComplete, NULL); WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions, 0); status = SetRequestTimeout(requestContext, Request, &sendOptions); if (!NT_SUCCESS(status)) { USBERR("SetRequestTimeout failed. status=%Xh\n", status); goto Exit; } if (!WdfRequestSend(Request, WdfUsbTargetDeviceGetIoTarget(deviceContext->WdfUsbTargetDevice), &sendOptions)) { status = WdfRequestGetStatus(Request); USBERR("WdfRequestSend failed. status=%Xh\n", status); } else { USBMSGN("[Ok] status=%Xh", status); return; } Exit: if (!NT_SUCCESS(status)) { WdfRequestCompleteWithInformation(Request, status, 0); } return; }