| /* |
| * Copyright (C) 2006 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /** \file |
| This file consists of implementation of class AndroidUsbDeviceObject that |
| encapsulates an extension for KMDF device (FDO) object. |
| */ |
| #pragma data_seg() |
| #pragma code_seg() |
| |
| #include "precomp.h" |
| #include "android_usb_device_object.h" |
| #include "android_usb_file_object.h" |
| #include "android_usb_device_file_object.h" |
| #include "android_usb_pipe_file_object.h" |
| #include "android_usb_bulk_file_object.h" |
| #include "android_usb_interrupt_file_object.h" |
| |
| #pragma data_seg() |
| |
| /// Buffer for bulk read pipe name |
| const WCHAR bulk_read_pipe_str[] = L"\\" DEVICE_BULK_READ_PIPE_NAME; |
| |
| /// Unicode string for bulk read pipe name |
| UNICODE_STRING bulk_read_pipe_name = { |
| sizeof(bulk_read_pipe_str) - sizeof(WCHAR), |
| sizeof(bulk_read_pipe_str) - sizeof(WCHAR), |
| const_cast<PWSTR>(bulk_read_pipe_str) |
| }; |
| |
| /// Buffer for bulk write pipe name |
| const WCHAR bulk_write_pipe_str[] = L"\\" DEVICE_BULK_WRITE_PIPE_NAME; |
| |
| /// Unicode string for bulk write pipe name |
| UNICODE_STRING bulk_write_pipe_name = { |
| sizeof(bulk_write_pipe_str) - sizeof(WCHAR), |
| sizeof(bulk_write_pipe_str) - sizeof(WCHAR), |
| const_cast<PWSTR>(bulk_write_pipe_str) |
| }; |
| |
| /// Buffer for an index-based pipe name prefix |
| const WCHAR index_pipe_prefix_str[] = L"\\" DEVICE_PIPE_NAME_PREFIX; |
| |
| /// Unicode string for index-based pipe name prefix |
| UNICODE_STRING index_pipe_prefix = { |
| sizeof(index_pipe_prefix_str) - sizeof(WCHAR), |
| sizeof(index_pipe_prefix_str) - sizeof(WCHAR), |
| const_cast<PWSTR>(index_pipe_prefix_str) |
| }; |
| |
| /// GUID that sets class ID for our device |
| const GUID android_guid = ANDROID_USB_CLASS_ID; |
| |
| #pragma code_seg("PAGE") |
| |
| AndroidUsbDeviceObject::AndroidUsbDeviceObject() |
| : AndroidUsbWdfObject(AndroidUsbWdfObjectTypeDevice), |
| wdf_target_device_(NULL), |
| wdf_usb_interface_(NULL), |
| serial_number_handle_(NULL), |
| serial_number_char_len_(0), |
| configured_pipes_num_(0), |
| bulk_read_pipe_index_(INVALID_UCHAR), |
| bulk_write_pipe_index_(INVALID_UCHAR), |
| configuration_descriptor_(NULL) { |
| ASSERT_IRQL_PASSIVE(); |
| } |
| |
| #pragma code_seg() |
| |
| AndroidUsbDeviceObject::~AndroidUsbDeviceObject() { |
| ASSERT_IRQL_LOW_OR_DISPATCH(); |
| if (NULL != serial_number_handle_) |
| WdfObjectDelete(serial_number_handle_); |
| } |
| |
| #pragma code_seg("PAGE") |
| |
| NTSTATUS AndroidUsbDeviceObject::CreateFDODevice(PWDFDEVICE_INIT device_init) { |
| ASSERT_IRQL_PASSIVE(); |
| |
| ASSERT(!IsTaretDeviceCreated()); |
| if (IsTaretDeviceCreated()) |
| return STATUS_INTERNAL_ERROR; |
| |
| // Initialize our object attributes first |
| WDF_OBJECT_ATTRIBUTES device_attr; |
| NTSTATUS status = InitObjectAttributes(&device_attr, NULL); |
| ASSERT(NT_SUCCESS(status)); |
| if (!NT_SUCCESS(status)) |
| return status; |
| |
| // Initialize the pnp_power_callbacks structure. Callback events for PnP |
| // and Power are specified here. If we don't supply any callbacks, the |
| // KMDF will take appropriate default actions for an FDO device object. |
| // EvtDevicePrepareHardware and EvtDeviceReleaseHardware are major entry |
| // points for initializing / cleaning up our device. Probably, we can leave |
| // the rest to the framework. |
| WDF_PNPPOWER_EVENT_CALLBACKS pnp_power_callbacks; |
| WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnp_power_callbacks); |
| pnp_power_callbacks.EvtDevicePrepareHardware = |
| EvtDevicePrepareHardwareEntry; |
| pnp_power_callbacks.EvtDeviceReleaseHardware = |
| EvtDeviceReleaseHardwareEntry; |
| WdfDeviceInitSetPnpPowerEventCallbacks(device_init, &pnp_power_callbacks); |
| |
| // Initialize the request attributes to specify the context size and type |
| // for every request created by framework for this device. |
| WDF_OBJECT_ATTRIBUTES request_attr; |
| WDF_OBJECT_ATTRIBUTES_INIT(&request_attr); |
| WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&request_attr, AndroidUsbWdfRequestContext); |
| WdfDeviceInitSetRequestAttributes(device_init, &request_attr); |
| |
| // Initialize WDF_FILEOBJECT_CONFIG_INIT struct to tell the KMDF that we are |
| // interested in handling Create requests that get genereated when an |
| // application or another kernel component opens a handle through the device. |
| // We are not interested in receiving cleanup / close IRPs at this point. |
| WDF_FILEOBJECT_CONFIG file_config; |
| WDF_OBJECT_ATTRIBUTES file_attr; |
| WDF_FILEOBJECT_CONFIG_INIT(&file_config, |
| EvtDeviceFileCreateEntry, |
| WDF_NO_EVENT_CALLBACK, |
| WDF_NO_EVENT_CALLBACK); |
| WDF_OBJECT_ATTRIBUTES_INIT(&file_attr); |
| WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&file_attr, |
| AndroidUsbWdfObjectContext); |
| file_attr.EvtCleanupCallback = AndroidUsbWdfObject::EvtCleanupCallbackEntry; |
| file_attr.EvtDestroyCallback = AndroidUsbWdfObject::EvtDestroyCallbackEntry; |
| // We will provide our own synchronization for file access |
| file_attr.SynchronizationScope = WdfSynchronizationScopeNone; |
| WdfDeviceInitSetFileObjectConfig(device_init, &file_config, &file_attr); |
| |
| // I/O type is buffered by default. It could be very inefficient if we have |
| // large reads / writes through our device. |
| WdfDeviceInitSetIoType(device_init, WdfDeviceIoDirect); |
| |
| // DeviceInit is completely initialized. So call the framework |
| // to create the device and attach it to the lower stack. |
| WDFDEVICE wdf_dev = NULL; |
| status = WdfDeviceCreate(&device_init, &device_attr, &wdf_dev); |
| ASSERT(NT_SUCCESS(status) && (NULL != wdf_dev)); |
| if (!NT_SUCCESS(status)) |
| return status; |
| |
| // Save handle to the created device |
| set_wdf_object(wdf_dev); |
| |
| // Tell the framework to set the SurpriseRemovalOK in the DeviceCaps so |
| // that we don't get the popup in usermode (on Win2K) when we surprise |
| // remove the device. |
| WDF_DEVICE_PNP_CAPABILITIES pnp_caps; |
| WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnp_caps); |
| pnp_caps.SurpriseRemovalOK = WdfTrue; |
| WdfDeviceSetPnpCapabilities(wdf_device(), &pnp_caps); |
| |
| // Create our default queue object for this device to start receiving I/O |
| status = CreateDefaultQueue(); |
| ASSERT(NT_SUCCESS(status)); |
| if (!NT_SUCCESS(status)) |
| return status; |
| |
| // Register a device interface so that app can find our device and talk to it. |
| status = WdfDeviceCreateDeviceInterface(wdf_device(), &android_guid, NULL); |
| ASSERT(NT_SUCCESS(status)); |
| if (!NT_SUCCESS(status)) |
| return status; |
| |
| // Initialize our extension to that device. We will do this at the very end |
| // so we know that we successfully passed entire device create chain when |
| // we are called with other callbacks to that device. |
| status = InitializeContext(); |
| ASSERT(NT_SUCCESS(status)); |
| if (!NT_SUCCESS(status)) |
| return status; |
| |
| return STATUS_SUCCESS; |
| } |
| |
| NTSTATUS AndroidUsbDeviceObject::ResetDevice() { |
| ASSERT_IRQL_PASSIVE(); |
| |
| if (!IsTaretDeviceCreated()) |
| return STATUS_SUCCESS; |
| |
| // Reset the device |
| NTSTATUS status = |
| status = WdfUsbTargetDeviceResetPortSynchronously(wdf_target_device()); |
| |
| // !!!!! Note that after the call to WdfUsbTargetDeviceResetPortSynchronously |
| // this object may be no longer valid !!!!! |
| |
| if (!NT_SUCCESS(status)) |
| GoogleDbgPrint("\n!!!!! AndroidUsbDeviceObject::ResetDevice failed %X", 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 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; |
| } |
| |
| void AndroidUsbDeviceObject::OnEvtDeviceFileCreate(WDFREQUEST request, |
| WDFFILEOBJECT wdf_fo) { |
| ASSERT_IRQL_PASSIVE(); |
| ASSERT(IsInterfaceSelected()); |
| if (!IsInterfaceSelected()) { |
| WdfRequestComplete(request, STATUS_INVALID_DEVICE_STATE); |
| return; |
| } |
| |
| PUNICODE_STRING file_name = WdfFileObjectGetFileName(wdf_fo); |
| ASSERT(NULL != file_name); |
| if (NULL == file_name) { |
| WdfRequestComplete(request, STATUS_OBJECT_NAME_INVALID); |
| return; |
| } |
| |
| WDFUSBPIPE wdf_pipe_obj = NULL; |
| WDF_USB_PIPE_INFORMATION pipe_info; |
| |
| // TODO: Share / access check here? |
| |
| // Lets see if this is a device open |
| if (0 != file_name->Length) { |
| // This is a pipe open. Lets retrieve pipe index from the name |
| UCHAR pipe_index = GetPipeIndexFromFileName(file_name); |
| if (INVALID_UCHAR == pipe_index) { |
| GoogleDbgPrint("\n!!!!! There is no pipe index for file %wZ", file_name); |
| WdfRequestComplete(request, STATUS_OBJECT_NAME_INVALID); |
| return; |
| } |
| |
| // Make sure that pipe index doesn't exceed number of pipes |
| if (pipe_index >= configured_pipes_num()) { |
| WdfRequestComplete(request, STATUS_OBJECT_NAME_NOT_FOUND); |
| return; |
| } |
| |
| // Retrieve the pipe along with the pipe info |
| WDF_USB_PIPE_INFORMATION_INIT(&pipe_info); |
| wdf_pipe_obj = WdfUsbInterfaceGetConfiguredPipe(wdf_usb_interface(), |
| pipe_index, |
| &pipe_info); |
| if (NULL == wdf_pipe_obj) { |
| GoogleDbgPrint("\n!!!!! There is no pipe for index %u for file %wZ", |
| pipe_index, file_name); |
| WdfRequestComplete(request, STATUS_OBJECT_NAME_NOT_FOUND); |
| return; |
| } |
| } |
| |
| // If we're here this must be either device open or pipe open |
| ASSERT((NULL != wdf_pipe_obj) || (0 == file_name->Length)); |
| |
| // Create our file object extension for this file |
| AndroidUsbFileObject* wdf_file_ext = NULL; |
| NTSTATUS status; |
| |
| if (0 == file_name->Length) { |
| // This is a device FO. Create wrapper for device FO |
| ASSERT(NULL == wdf_pipe_obj); |
| wdf_file_ext = new(NonPagedPool, GANDR_POOL_TAG_DEVICE_FO) |
| AndroidUsbDeviceFileObject(this, wdf_fo); |
| ASSERT(NULL != wdf_file_ext); |
| if (NULL == wdf_file_ext) { |
| WdfRequestComplete(request, STATUS_INSUFFICIENT_RESOURCES); |
| return; |
| } |
| |
| // Initialize extension |
| status = wdf_file_ext->Initialize(); |
| if (!NT_SUCCESS(status)) { |
| delete wdf_file_ext; |
| WdfRequestComplete(request, status); |
| return; |
| } |
| } else { |
| // This is a pipe file. Create and initialize appropriate extension for it. |
| status = |
| CreatePipeFileObjectExt(wdf_fo, wdf_pipe_obj, &pipe_info, &wdf_file_ext); |
| ASSERT((NULL != wdf_file_ext) || !NT_SUCCESS(status)); |
| if (!NT_SUCCESS(status)) { |
| WdfRequestComplete(request, status); |
| return; |
| } |
| } |
| ASSERT(GetAndroidUsbFileObjectFromHandle(wdf_fo) == wdf_file_ext); |
| WdfRequestComplete(request, STATUS_SUCCESS); |
| } |
| |
| NTSTATUS AndroidUsbDeviceObject::EvtDevicePrepareHardwareEntry( |
| WDFDEVICE wdf_dev, |
| WDFCMRESLIST resources_raw, |
| WDFCMRESLIST resources_translated) { |
| ASSERT_IRQL_PASSIVE(); |
| |
| // Get our wrapper for the device and redirect event to its handler |
| AndroidUsbDeviceObject* wdf_device_ext = |
| GetAndroidUsbDeviceObjectFromHandle(wdf_dev); |
| ASSERT(NULL != wdf_device_ext); |
| return (NULL != wdf_device_ext) ? |
| wdf_device_ext->OnEvtDevicePrepareHardware(resources_raw, |
| resources_translated) : |
| STATUS_INVALID_DEVICE_REQUEST; |
| } |
| |
| NTSTATUS AndroidUsbDeviceObject::EvtDeviceReleaseHardwareEntry( |
| WDFDEVICE wdf_dev, |
| WDFCMRESLIST resources_translated) { |
| ASSERT_IRQL_PASSIVE(); |
| |
| // Get our wrapper for the device and redirect event to its handler |
| AndroidUsbDeviceObject* wdf_device_ext = |
| GetAndroidUsbDeviceObjectFromHandle(wdf_dev); |
| ASSERT(NULL != wdf_device_ext); |
| return (NULL != wdf_device_ext) ? |
| wdf_device_ext->OnEvtDeviceReleaseHardware(resources_translated) : |
| STATUS_INVALID_DEVICE_REQUEST; |
| } |
| |
| void AndroidUsbDeviceObject::EvtDeviceFileCreateEntry( |
| WDFDEVICE wdf_dev, |
| WDFREQUEST request, |
| WDFFILEOBJECT wdf_fo) { |
| ASSERT_IRQL_PASSIVE(); |
| |
| ASSERT(NULL != wdf_fo); |
| if (NULL == wdf_fo) { |
| WdfRequestComplete(request, STATUS_INVALID_PARAMETER); |
| return; |
| } |
| |
| // Get our wrapper for the device and redirect event to its handler |
| AndroidUsbDeviceObject* wdf_device_ext = |
| GetAndroidUsbDeviceObjectFromHandle(wdf_dev); |
| ASSERT(NULL != wdf_device_ext); |
| if (NULL != wdf_device_ext) { |
| wdf_device_ext->OnEvtDeviceFileCreate(request, wdf_fo); |
| } else { |
| WdfRequestComplete(request, STATUS_INVALID_DEVICE_REQUEST); |
| } |
| } |
| |
| #pragma code_seg() |
| |
| void AndroidUsbDeviceObject::OnEvtIoRead(WDFREQUEST request, |
| size_t length) { |
| ASSERT_IRQL_LOW_OR_DISPATCH(); |
| ASSERT(IsInterfaceSelected()); |
| if (!IsInterfaceSelected()) { |
| WdfRequestComplete(request, STATUS_INVALID_DEVICE_STATE); |
| return; |
| } |
| |
| // Get our file extension and dispatch this event to its handler |
| AndroidUsbFileObject* wdf_file_ext = |
| GetAndroidUsbFileObjectForRequest(request); |
| ASSERT(NULL != wdf_file_ext); |
| if (NULL != wdf_file_ext) { |
| wdf_file_ext->OnEvtIoRead(request, length); |
| } else { |
| WdfRequestComplete(request, STATUS_INVALID_DEVICE_REQUEST); |
| } |
| } |
| |
| void AndroidUsbDeviceObject::OnEvtIoWrite(WDFREQUEST request, |
| size_t length) { |
| ASSERT_IRQL_LOW_OR_DISPATCH(); |
| ASSERT(IsInterfaceSelected()); |
| if (!IsInterfaceSelected()) { |
| WdfRequestComplete(request, STATUS_INVALID_DEVICE_STATE); |
| return; |
| } |
| |
| // Get our file extension and dispatch this event to its handler |
| AndroidUsbFileObject* wdf_file_ext = |
| GetAndroidUsbFileObjectForRequest(request); |
| ASSERT(NULL != wdf_file_ext); |
| if (NULL != wdf_file_ext) { |
| wdf_file_ext->OnEvtIoWrite(request, length); |
| } else { |
| WdfRequestComplete(request, STATUS_INVALID_DEVICE_REQUEST); |
| } |
| } |
| |
| void AndroidUsbDeviceObject::OnEvtIoDeviceControl(WDFREQUEST request, |
| size_t output_buf_len, |
| size_t input_buf_len, |
| ULONG ioctl_code) { |
| ASSERT_IRQL_LOW_OR_DISPATCH(); |
| ASSERT(IsInterfaceSelected()); |
| if (!IsInterfaceSelected()) { |
| WdfRequestComplete(request, STATUS_INVALID_DEVICE_STATE); |
| return; |
| } |
| |
| // Get our file extension and dispatch this event to its handler |
| AndroidUsbFileObject* wdf_file_ext = |
| GetAndroidUsbFileObjectForRequest(request); |
| ASSERT(NULL != wdf_file_ext); |
| if (NULL != wdf_file_ext) { |
| wdf_file_ext->OnEvtIoDeviceControl(request, |
| output_buf_len, |
| input_buf_len, |
| ioctl_code); |
| } else { |
| WdfRequestComplete(request, STATUS_INVALID_DEVICE_REQUEST); |
| } |
| } |
| |
| void AndroidUsbDeviceObject::EvtIoReadEntry(WDFQUEUE queue, |
| WDFREQUEST request, |
| size_t length) { |
| ASSERT_IRQL_LOW_OR_DISPATCH(); |
| |
| // Get our file extension and dispatch this event to the appropriate handler |
| // inside our device extension. |
| AndroidUsbFileObject* wdf_file_ext = |
| GetAndroidUsbFileObjectForRequest(request); |
| ASSERT(NULL != wdf_file_ext); |
| if (NULL != wdf_file_ext) { |
| wdf_file_ext->device_object()->OnEvtIoRead(request, length); |
| } else { |
| WdfRequestComplete(request, STATUS_INVALID_DEVICE_REQUEST); |
| } |
| } |
| |
| void AndroidUsbDeviceObject::EvtIoWriteEntry(WDFQUEUE queue, |
| WDFREQUEST request, |
| size_t length) { |
| ASSERT_IRQL_LOW_OR_DISPATCH(); |
| |
| // Get our file extension and dispatch this event to the appropriate handler |
| // inside our device extension. |
| AndroidUsbFileObject* wdf_file_ext = |
| GetAndroidUsbFileObjectForRequest(request); |
| ASSERT(NULL != wdf_file_ext); |
| if (NULL != wdf_file_ext) { |
| wdf_file_ext->device_object()->OnEvtIoWrite(request, length); |
| } else { |
| WdfRequestComplete(request, STATUS_INVALID_DEVICE_REQUEST); |
| } |
| } |
| |
| void AndroidUsbDeviceObject::EvtIoDeviceControlEntry(WDFQUEUE queue, |
| WDFREQUEST request, |
| size_t output_buf_len, |
| size_t input_buf_len, |
| ULONG ioctl_code) { |
| ASSERT_IRQL_LOW_OR_DISPATCH(); |
| |
| // Get our file extension and dispatch this event to the appropriate handler |
| // inside our device extension. |
| AndroidUsbFileObject* wdf_file_ext = |
| GetAndroidUsbFileObjectForRequest(request); |
| ASSERT(NULL != wdf_file_ext); |
| if (NULL != wdf_file_ext) { |
| wdf_file_ext->device_object()->OnEvtIoDeviceControl(request, |
| output_buf_len, |
| input_buf_len, |
| ioctl_code); |
| } else { |
| WdfRequestComplete(request, STATUS_INVALID_DEVICE_REQUEST); |
| } |
| } |
| |
| void AndroidUsbDeviceObject::OnGetUsbDeviceDescriptorCtl(WDFREQUEST request, |
| size_t output_buf_len) { |
| ASSERT_IRQL_LOW_OR_DISPATCH(); |
| |
| // Check the buffer first |
| if (output_buf_len >= sizeof(USB_DEVICE_DESCRIPTOR)) { |
| // Get the output buffer |
| NTSTATUS status; |
| void* ret_info = OutAddress(request, &status); |
| ASSERT(NT_SUCCESS(status) && (NULL != ret_info)); |
| if (NT_SUCCESS(status)) { |
| // Copy requested info into output buffer and complete request |
| RtlCopyMemory(ret_info, |
| usb_device_descriptor(), |
| sizeof(USB_DEVICE_DESCRIPTOR)); |
| |
| WdfRequestCompleteWithInformation(request, |
| STATUS_SUCCESS, |
| sizeof(USB_DEVICE_DESCRIPTOR)); |
| } else { |
| WdfRequestComplete(request, status); |
| } |
| } else { |
| WdfRequestCompleteWithInformation(request, |
| STATUS_BUFFER_TOO_SMALL, |
| sizeof(USB_DEVICE_DESCRIPTOR)); |
| } |
| } |
| |
| void AndroidUsbDeviceObject::OnGetUsbConfigDescriptorCtl(WDFREQUEST request, |
| size_t output_buf_len) { |
| ASSERT_IRQL_LOW_OR_DISPATCH(); |
| |
| if (NULL != configuration_descriptor()) { |
| // Check the buffer first |
| if (output_buf_len >= sizeof(USB_CONFIGURATION_DESCRIPTOR)) { |
| // Get the output buffer |
| NTSTATUS status; |
| void* ret_info = OutAddress(request, &status); |
| ASSERT(NT_SUCCESS(status) && (NULL != ret_info)); |
| if (NT_SUCCESS(status)) { |
| // Copy requested info into output buffer and complete request |
| RtlCopyMemory(ret_info, |
| configuration_descriptor(), |
| sizeof(USB_CONFIGURATION_DESCRIPTOR)); |
| |
| WdfRequestCompleteWithInformation(request, |
| STATUS_SUCCESS, |
| sizeof(USB_CONFIGURATION_DESCRIPTOR)); |
| } else { |
| WdfRequestComplete(request, status); |
| } |
| } else { |
| WdfRequestCompleteWithInformation(request, |
| STATUS_BUFFER_TOO_SMALL, |
| sizeof(USB_CONFIGURATION_DESCRIPTOR)); |
| } |
| } else { |
| WdfRequestComplete(request, STATUS_INVALID_DEVICE_REQUEST); |
| } |
| } |
| |
| void AndroidUsbDeviceObject::OnGetUsbInterfaceDescriptorCtl(WDFREQUEST request, |
| size_t output_buf_len) { |
| ASSERT_IRQL_LOW_OR_DISPATCH(); |
| |
| // Check the buffer first |
| if (output_buf_len >= sizeof(USB_INTERFACE_DESCRIPTOR)) { |
| // Get the output buffer |
| NTSTATUS status; |
| void* ret_info = OutAddress(request, &status); |
| ASSERT(NT_SUCCESS(status) && (NULL != ret_info)); |
| if (NT_SUCCESS(status)) { |
| // Copy requested info into output buffer and complete request |
| RtlCopyMemory(ret_info, |
| interface_descriptor(), |
| sizeof(USB_INTERFACE_DESCRIPTOR)); |
| |
| WdfRequestCompleteWithInformation(request, |
| STATUS_SUCCESS, |
| sizeof(USB_INTERFACE_DESCRIPTOR)); |
| } else { |
| WdfRequestComplete(request, status); |
| } |
| } else { |
| WdfRequestCompleteWithInformation(request, |
| STATUS_BUFFER_TOO_SMALL, |
| sizeof(USB_INTERFACE_DESCRIPTOR)); |
| } |
| } |
| |
| void AndroidUsbDeviceObject::OnGetEndpointInformationCtl( |
| WDFREQUEST request, |
| size_t input_buf_len, |
| size_t output_buf_len) { |
| ASSERT_IRQL_LOW_OR_DISPATCH(); |
| |
| // Check the buffers first |
| if (input_buf_len < sizeof(AdbQueryEndpointInformation)) { |
| WdfRequestComplete(request, STATUS_INVALID_BUFFER_SIZE); |
| return; |
| } |
| |
| if (output_buf_len < sizeof(AdbEndpointInformation)) { |
| WdfRequestCompleteWithInformation(request, |
| STATUS_BUFFER_TOO_SMALL, |
| sizeof(AdbEndpointInformation)); |
| return; |
| } |
| |
| // Get the output buffer |
| NTSTATUS status; |
| AdbEndpointInformation* ret_info = reinterpret_cast<AdbEndpointInformation*> |
| (OutAddress(request, &status)); |
| ASSERT(NT_SUCCESS(status) && (NULL != ret_info)); |
| if (!NT_SUCCESS(status)) { |
| WdfRequestComplete(request, status); |
| return; |
| } |
| |
| // Get the input buffer |
| AdbQueryEndpointInformation* in = reinterpret_cast<AdbQueryEndpointInformation*> |
| (InAddress(request, &status)); |
| ASSERT(NT_SUCCESS(status) && (NULL != in)); |
| if (!NT_SUCCESS(status)) { |
| WdfRequestComplete(request, status); |
| return; |
| } |
| |
| // Lets see what exactly is queried |
| UCHAR endpoint_index = in->endpoint_index; |
| if (ADB_QUERY_BULK_WRITE_ENDPOINT_INDEX == endpoint_index) |
| endpoint_index = bulk_write_pipe_index(); |
| else if (ADB_QUERY_BULK_READ_ENDPOINT_INDEX == endpoint_index) |
| endpoint_index = bulk_read_pipe_index(); |
| |
| // Make sure index is valid and within interface range |
| if ((INVALID_UCHAR == endpoint_index) || |
| (endpoint_index >= configured_pipes_num())) { |
| WdfRequestComplete(request, STATUS_NOT_FOUND); |
| return; |
| } |
| |
| // Get endpoint information |
| WDF_USB_PIPE_INFORMATION pipe_info; |
| WDF_USB_PIPE_INFORMATION_INIT(&pipe_info); |
| WDFUSBPIPE wdf_pipe_obj = |
| WdfUsbInterfaceGetConfiguredPipe(wdf_usb_interface(), endpoint_index, &pipe_info); |
| if (NULL == wdf_pipe_obj) { |
| WdfRequestComplete(request, STATUS_NOT_FOUND); |
| return; |
| } |
| |
| // Copy endpoint info to the output |
| ret_info->max_packet_size = pipe_info.MaximumPacketSize; |
| ret_info->endpoint_address = pipe_info.EndpointAddress; |
| ret_info->polling_interval = pipe_info.Interval; |
| ret_info->setting_index = pipe_info.SettingIndex; |
| ret_info->endpoint_type = static_cast<AdbEndpointType>(pipe_info.PipeType); |
| ret_info->max_transfer_size = pipe_info.MaximumTransferSize; |
| |
| WdfRequestCompleteWithInformation(request, |
| STATUS_SUCCESS, |
| sizeof(AdbEndpointInformation)); |
| } |
| |
| void AndroidUsbDeviceObject::OnGetSerialNumberCtl(WDFREQUEST request, |
| size_t output_buf_len) { |
| ASSERT_IRQL_LOW(); |
| |
| if (NULL == serial_number()) { |
| // There is no serial number saved for this device! |
| WdfRequestComplete(request, STATUS_INTERNAL_ERROR); |
| return; |
| } |
| |
| size_t expected_len = serial_number_byte_len() + sizeof(WCHAR); |
| |
| // Check the buffer first |
| if (output_buf_len >= expected_len) { |
| // Get the output buffer |
| NTSTATUS status; |
| WCHAR* ret_info = reinterpret_cast<WCHAR*>(OutAddress(request, &status)); |
| ASSERT(NT_SUCCESS(status) && (NULL != ret_info)); |
| if (NT_SUCCESS(status)) { |
| // Copy serial number |
| RtlCopyMemory(ret_info, serial_number(), serial_number_byte_len()); |
| ret_info[serial_number_char_len()] = L'\0'; |
| WdfRequestCompleteWithInformation(request, STATUS_SUCCESS, expected_len); |
| } else { |
| WdfRequestComplete(request, status); |
| } |
| } else { |
| WdfRequestCompleteWithInformation(request, |
| STATUS_BUFFER_TOO_SMALL, |
| sizeof(expected_len)); |
| } |
| } |
| |
| #pragma code_seg("PAGE") |
| |
| NTSTATUS AndroidUsbDeviceObject::CreateDefaultQueue() { |
| ASSERT_IRQL_PASSIVE(); |
| |
| // Register I/O callbacks to tell the framework that we are interested |
| // in handling WdfRequestTypeRead, WdfRequestTypeWrite, and |
| // WdfRequestTypeDeviceControl requests. WdfIoQueueDispatchParallel means |
| // that we are capable of handling all the I/O request simultaneously and we |
| // are responsible for protecting data that could be accessed by these |
| // callbacks simultaneously. This queue will be, by default, automanaged by |
| // the framework with respect to PnP and Power events. That is, framework |
| // will take care of queuing, failing, dispatching incoming requests based |
| // on the current PnP / Power state of the device. We also need to register |
| // a EvtIoStop handler so that we can acknowledge requests that are pending |
| // at the target driver. |
| WDF_IO_QUEUE_CONFIG io_queue_config; |
| WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&io_queue_config, |
| WdfIoQueueDispatchParallel); |
| |
| io_queue_config.EvtIoDeviceControl = EvtIoDeviceControlEntry; |
| io_queue_config.EvtIoRead = EvtIoReadEntry; |
| io_queue_config.EvtIoWrite = EvtIoWriteEntry; |
| io_queue_config.AllowZeroLengthRequests = TRUE; |
| // By default KMDF will take care of the power management of this queue |
| io_queue_config.PowerManaged = WdfUseDefault; |
| |
| // Create queue object |
| WDFQUEUE wdf_queue_obj = NULL; |
| NTSTATUS status = WdfIoQueueCreate(wdf_device(), |
| &io_queue_config, |
| WDF_NO_OBJECT_ATTRIBUTES, |
| &wdf_queue_obj); |
| ASSERT(NT_SUCCESS(status) && (NULL != wdf_queue_obj)); |
| if (!NT_SUCCESS(status)) |
| return status; |
| return STATUS_SUCCESS; |
| } |
| |
| NTSTATUS AndroidUsbDeviceObject::ConfigureDevice() { |
| ASSERT_IRQL_PASSIVE(); |
| |
| ASSERT(IsTaretDeviceCreated()); |
| if (!IsTaretDeviceCreated()) |
| return STATUS_INTERNAL_ERROR; |
| |
| // In order to get the configuration descriptor we must first query for its |
| // size (by supplying NULL for the descriptor's address), allocate enough |
| // memory and then retrieve the descriptor. |
| USHORT size = 0; |
| |
| // Query descriptor size first |
| NTSTATUS status = |
| WdfUsbTargetDeviceRetrieveConfigDescriptor(wdf_target_device(), |
| WDF_NO_HANDLE, |
| &size); |
| ASSERT((status == STATUS_BUFFER_TOO_SMALL) || !NT_SUCCESS(status)); |
| if (status != STATUS_BUFFER_TOO_SMALL) |
| return status; |
| |
| // Create a memory object and specify our device as the parent so that |
| // it will be freed automatically along with our device. |
| WDFMEMORY memory = NULL; |
| WDF_OBJECT_ATTRIBUTES attributes; |
| WDF_OBJECT_ATTRIBUTES_INIT(&attributes); |
| attributes.ParentObject = wdf_device(); |
| status = WdfMemoryCreate(&attributes, |
| NonPagedPool, |
| GANDR_POOL_TAG_DEV_CFG_DESC, |
| size, |
| &memory, |
| reinterpret_cast<PVOID*>(&configuration_descriptor_)); |
| ASSERT(NT_SUCCESS(status)); |
| if (!NT_SUCCESS(status)) |
| return status; |
| |
| // Now retrieve configuration descriptor |
| status = |
| WdfUsbTargetDeviceRetrieveConfigDescriptor(wdf_target_device(), |
| configuration_descriptor_, |
| &size); |
| ASSERT(NT_SUCCESS(status) && (NULL != configuration_descriptor_)); |
| if (!NT_SUCCESS(status)) |
| return status; |
| |
| #if DBG |
| PrintConfigDescriptor(configuration_descriptor(), size); |
| #endif // DBG |
| |
| 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; |
| } |
| |
| UCHAR AndroidUsbDeviceObject::GetPipeIndexFromFileName( |
| PUNICODE_STRING file_path) { |
| ASSERT_IRQL_PASSIVE(); |
| ASSERT((NULL != file_path) && (0 != file_path->Length) && (NULL != file_path->Buffer)); |
| if ((NULL == file_path) || |
| (0 == file_path->Length) || |
| (NULL == file_path->Buffer)) { |
| return INVALID_UCHAR; |
| } |
| |
| // Lets check for explicit r/w pipe names |
| if (0 == RtlCompareUnicodeString(file_path, &bulk_read_pipe_name, TRUE)) |
| return bulk_read_pipe_index(); |
| if (0 == RtlCompareUnicodeString(file_path, &bulk_write_pipe_name, TRUE)) |
| return bulk_write_pipe_index(); |
| |
| // Lets check path format |
| if (file_path->Length <= index_pipe_prefix.Length) { |
| GoogleDbgPrint("\n!!!!! Bad format for pipe name: %wZ", file_path); |
| return INVALID_UCHAR; |
| } |
| |
| // Now when whe know that file_path->Length is sufficient lets match this |
| // path with the prefix |
| UNICODE_STRING prefix_match = *file_path; |
| prefix_match.Length = index_pipe_prefix.Length; |
| prefix_match.MaximumLength = prefix_match.Length; |
| |
| if (0 != RtlCompareUnicodeString(&prefix_match, &index_pipe_prefix, TRUE)) { |
| GoogleDbgPrint("\n!!!!! Bad format for pipe name: %wZ", file_path); |
| return INVALID_UCHAR; |
| } |
| |
| // Prefix matches. Make sure that remaining chars are all decimal digits. |
| // Pipe index begins right after the prefix ends. |
| const ULONG index_begins_at = WcharLen(index_pipe_prefix.Length); |
| const ULONG name_len = WcharLen(file_path->Length); |
| for (ULONG index = index_begins_at; index < name_len; index++) { |
| if ((file_path->Buffer[index] > L'9') || |
| (file_path->Buffer[index] < L'0')) { |
| GoogleDbgPrint("\n!!!!! Bad format for pipe name: %wZ", file_path); |
| return INVALID_UCHAR; |
| } |
| } |
| |
| // Parse the pipe# |
| ULONG uval = 0; |
| ULONG umultiplier = 1; |
| |
| // traversing least to most significant digits. |
| for (ULONG index = name_len - 1; index >= index_begins_at; index--) { |
| uval += (umultiplier * static_cast<ULONG>(file_path->Buffer[index] - L'0')); |
| umultiplier *= 10; |
| } |
| |
| return static_cast<UCHAR>(uval); |
| } |
| |
| NTSTATUS AndroidUsbDeviceObject::CreatePipeFileObjectExt( |
| WDFFILEOBJECT wdf_fo, |
| WDFUSBPIPE wdf_pipe_obj, |
| const WDF_USB_PIPE_INFORMATION* pipe_info, |
| AndroidUsbFileObject** wdf_file_ext) { |
| ASSERT_IRQL_PASSIVE(); |
| ASSERT((NULL != wdf_fo) && (NULL != wdf_pipe_obj) && (NULL != pipe_info) && (NULL != wdf_file_ext)); |
| if ((NULL == wdf_fo) || (NULL == wdf_pipe_obj) || (NULL == pipe_info) || (NULL == wdf_file_ext)) { |
| return STATUS_INTERNAL_ERROR; |
| } |
| *wdf_file_ext = NULL; |
| |
| AndroidUsbPipeFileObject* wdf_pipe_file_ext = NULL; |
| |
| // We support only WdfUsbPipeTypeBulk and WdfUsbPipeTypeInterrupt files |
| // at this point. |
| switch (pipe_info->PipeType) { |
| case WdfUsbPipeTypeBulk: |
| wdf_pipe_file_ext = new(NonPagedPool, GANDR_POOL_TAG_BULK_FILE) |
| AndroidUsbBulkPipeFileObject(this, wdf_fo, wdf_pipe_obj); |
| break; |
| |
| case WdfUsbPipeTypeInterrupt: |
| wdf_pipe_file_ext = new(NonPagedPool, GANDR_POOL_TAG_INTERRUPT_FILE) |
| AndroidUsbInterruptPipeFileObject(this, wdf_fo, wdf_pipe_obj); |
| break;; |
| |
| case WdfUsbPipeTypeIsochronous: |
| case WdfUsbPipeTypeControl: |
| case WdfUsbPipeTypeInvalid: |
| default: |
| return STATUS_OBJECT_TYPE_MISMATCH; |
| } |
| |
| // If we reached here instance of a file wrapper must be created. |
| ASSERT(NULL != wdf_pipe_file_ext); |
| if (NULL == wdf_pipe_file_ext) |
| return STATUS_INSUFFICIENT_RESOURCES; |
| |
| // Initialize the wrapper. |
| NTSTATUS status = wdf_pipe_file_ext->InitializePipe(pipe_info); |
| ASSERT(NT_SUCCESS(status)); |
| if (NT_SUCCESS(status)) { |
| *wdf_file_ext = wdf_pipe_file_ext; |
| } else { |
| delete wdf_pipe_file_ext; |
| } |
| |
| return STATUS_SUCCESS; |
| } |
| |
| #if DBG |
| #pragma code_seg() |
| |
| void AndroidUsbDeviceObject::PrintUsbDeviceDescriptor( |
| const USB_DEVICE_DESCRIPTOR* desc) { |
| GoogleDbgPrint("\n***** USB_DEVICE_DESCRIPTOR %p for device %p", desc, this); |
| GoogleDbgPrint("\n bDescriptorType = %u", desc->bDescriptorType); |
| GoogleDbgPrint("\n bcdUSB = x%02X", desc->bcdUSB); |
| GoogleDbgPrint("\n bDeviceClass = x%02X", desc->bDeviceClass); |
| GoogleDbgPrint("\n bDeviceSubClass = x%02X", desc->bDeviceSubClass); |
| GoogleDbgPrint("\n bDeviceProtocol = x%02X", desc->bDeviceProtocol); |
| GoogleDbgPrint("\n bMaxPacketSize = %u", desc->bMaxPacketSize0); |
| GoogleDbgPrint("\n idVendor = x%04X", desc->idVendor); |
| GoogleDbgPrint("\n idProduct = x%04X", desc->idProduct); |
| GoogleDbgPrint("\n bcdDevice = x%02X", desc->bcdDevice); |
| GoogleDbgPrint("\n iManufacturer = %u", desc->iManufacturer); |
| GoogleDbgPrint("\n iProduct = %u", desc->iProduct); |
| GoogleDbgPrint("\n iSerialNumber = %u", desc->iSerialNumber); |
| GoogleDbgPrint("\n bNumConfigurations = %u", desc->bNumConfigurations); |
| } |
| |
| void AndroidUsbDeviceObject::PrintUsbTargedDeviceInformation( |
| const WDF_USB_DEVICE_INFORMATION* info) { |
| GoogleDbgPrint("\n***** WDF_USB_DEVICE_INFORMATION %p for device %p", info, this); |
| GoogleDbgPrint("\n HcdPortCapabilities = x%08X", info->HcdPortCapabilities); |
| GoogleDbgPrint("\n Traits = x%08X", info->Traits); |
| GoogleDbgPrint("\n VersionInfo.USBDI_Version = x%08X", |
| info->UsbdVersionInformation.USBDI_Version); |
| GoogleDbgPrint("\n VersionInfo.Supported_USB_Version = x%08X", |
| info->UsbdVersionInformation.Supported_USB_Version); |
| } |
| |
| void AndroidUsbDeviceObject::PrintConfigDescriptor( |
| const USB_CONFIGURATION_DESCRIPTOR* desc, |
| ULONG size) { |
| GoogleDbgPrint("\n***** USB_CONFIGURATION_DESCRIPTOR %p for device %p size %u", |
| desc, this, size); |
| GoogleDbgPrint("\n bDescriptorType = %u", desc->bDescriptorType); |
| GoogleDbgPrint("\n wTotalLength = %u", desc->wTotalLength); |
| GoogleDbgPrint("\n bNumInterfaces = %u", desc->bNumInterfaces); |
| GoogleDbgPrint("\n bConfigurationValue = %u", desc->bConfigurationValue); |
| GoogleDbgPrint("\n iConfiguration = %u", desc->iConfiguration); |
| GoogleDbgPrint("\n bmAttributes = %u", desc->bmAttributes); |
| GoogleDbgPrint("\n MaxPower = %u", desc->MaxPower); |
| } |
| |
| void AndroidUsbDeviceObject::PrintSelectedConfig( |
| const WDF_USB_DEVICE_SELECT_CONFIG_PARAMS* config) { |
| GoogleDbgPrint("\n***** WDF_USB_DEVICE_SELECT_CONFIG_PARAMS %p for device %p", config, this); |
| GoogleDbgPrint("\n Type = %u", config->Type); |
| switch (config->Type) { |
| case WdfUsbTargetDeviceSelectConfigTypeSingleInterface: |
| GoogleDbgPrint("\n SingleInterface:"); |
| GoogleDbgPrint("\n NumberConfiguredPipes = %u", |
| config->Types.SingleInterface.NumberConfiguredPipes); |
| GoogleDbgPrint("\n ConfiguredUsbInterface = %p", |
| config->Types.SingleInterface.ConfiguredUsbInterface); |
| break; |
| |
| case WdfUsbTargetDeviceSelectConfigTypeMultiInterface: |
| GoogleDbgPrint("\n MultiInterface:"); |
| GoogleDbgPrint("\n NumberInterfaces = %u", |
| config->Types.MultiInterface.NumberInterfaces); |
| GoogleDbgPrint("\n NumberOfConfiguredInterfaces = %u", |
| config->Types.MultiInterface.NumberOfConfiguredInterfaces); |
| GoogleDbgPrint("\n Pairs = %p", |
| config->Types.MultiInterface.Pairs); |
| break; |
| |
| case WdfUsbTargetDeviceSelectConfigTypeInterfacesDescriptor: |
| GoogleDbgPrint("\n Descriptor:"); |
| GoogleDbgPrint("\n NumInterfaceDescriptors = %u", |
| config->Types.Descriptor.NumInterfaceDescriptors); |
| GoogleDbgPrint("\n ConfigurationDescriptor = %p", |
| config->Types.Descriptor.ConfigurationDescriptor); |
| GoogleDbgPrint("\n InterfaceDescriptors = %p", |
| config->Types.Descriptor.InterfaceDescriptors); |
| break; |
| |
| case WdfUsbTargetDeviceSelectConfigTypeUrb: |
| GoogleDbgPrint("\n Urb:"); |
| GoogleDbgPrint("\n Urb = %p", |
| config->Types.Urb.Urb); |
| break; |
| |
| case WdfUsbTargetDeviceSelectConfigTypeInterfacesPairs: |
| case WdfUsbTargetDeviceSelectConfigTypeInvalid: |
| case WdfUsbTargetDeviceSelectConfigTypeDeconfig: |
| default: |
| GoogleDbgPrint("\n Config type is unknown or invalid or not printable."); |
| break; |
| } |
| } |
| |
| void AndroidUsbDeviceObject::PrintInterfaceDescriptor( |
| const USB_INTERFACE_DESCRIPTOR* desc) { |
| GoogleDbgPrint("\n***** USB_INTERFACE_DESCRIPTOR %p for device %p", |
| desc, this); |
| GoogleDbgPrint("\n bLength = %u", desc->bLength); |
| GoogleDbgPrint("\n bDescriptorType = %u", desc->bDescriptorType); |
| GoogleDbgPrint("\n bInterfaceNumber = %u", desc->bInterfaceNumber); |
| GoogleDbgPrint("\n bAlternateSetting = %u", desc->bAlternateSetting); |
| GoogleDbgPrint("\n bNumEndpoints = %u", desc->bNumEndpoints); |
| GoogleDbgPrint("\n bInterfaceClass = x%02X", desc->bInterfaceClass); |
| GoogleDbgPrint("\n bInterfaceSubClass = x%02X", desc->bInterfaceSubClass); |
| GoogleDbgPrint("\n bInterfaceProtocol = x%02X", desc->bInterfaceProtocol); |
| GoogleDbgPrint("\n iInterface = %u", desc->iInterface); |
| } |
| |
| void AndroidUsbDeviceObject::PrintPipeInformation( |
| const WDF_USB_PIPE_INFORMATION* info, |
| UCHAR pipe_index) { |
| GoogleDbgPrint("\n***** WDF_USB_PIPE_INFORMATION[%u] %p for device %p", |
| pipe_index, info, this); |
| GoogleDbgPrint("\n Size = %u", info->Size); |
| GoogleDbgPrint("\n MaximumPacketSize = %u", info->MaximumPacketSize); |
| GoogleDbgPrint("\n EndpointAddress = x%02X", info->EndpointAddress); |
| GoogleDbgPrint("\n Interval = %u", info->Interval); |
| GoogleDbgPrint("\n SettingIndex = %u", info->SettingIndex); |
| GoogleDbgPrint("\n PipeType = %u", info->PipeType); |
| GoogleDbgPrint("\n MaximumTransferSize = %u", info->MaximumTransferSize); |
| } |
| |
| #endif // DBG |
| |
| #pragma data_seg() |
| #pragma code_seg() |