1217 lines
45 KiB
C++
1217 lines
45 KiB
C++
/*
|
|
* 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()
|