diff --git a/host/windows/usb/legacy/driver/android_usb.inf b/host/windows/usb/legacy/driver/android_usb.inf new file mode 100755 index 000000000..f8bbf9a79 --- /dev/null +++ b/host/windows/usb/legacy/driver/android_usb.inf @@ -0,0 +1,130 @@ +;/*++ +; +;Abstract: +; Installation inf for the Android USB Bulk device +; +;--*/ + +[Version] +Signature="$WINDOWS NT$" +Class=USB +ClassGuid={F72FE0D4-CBCB-407d-8814-9ED673D0DD6B} +Provider=%GOOG% +DriverVer=06/25/2009,1.0.0010.00001 +CatalogFile.NTx86=androidusb86.cat +CatalogFile.NTamd64=androidusba64.cat + +; ================= Class section ===================== + +[ClassInstall32] +Addreg=AndroidUsbClassReg + +[AndroidUsbClassReg] +HKR,,,0,%ClassName% +HKR,,Icon,,-5 + +[DestinationDirs] +DefaultDestDir = 12 + +; ================= Device section ===================== + +[Manufacturer] +%MfgName%=Google,NTx86,NTamd64 + +; For Win2K +[Google] +; For loopback testing +%USB\VID_18D1&PID_DDDD.DeviceDescTest%=androidusb.Dev, USB\VID_18D1&PID_DDDD +; HTC Dream +%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01 +%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01 +%USB\VID_0BB4&PID_0C03&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C03&MI_01 +%USB\VID_0BB4&PID_0FFF.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0FFF + +; For XP and later +[Google.NTx86] +; For loopback testing +%USB\VID_18D1&PID_DDDD.DeviceDescTest%=androidusb.Dev, USB\VID_18D1&PID_DDDD +; HTC Dream +%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01 +%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01 +%USB\VID_0BB4&PID_0C03&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C03&MI_01 +%USB\VID_0BB4&PID_0FFF.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0FFF + +; For AMD64 and later +[Google.NTamd64] +; For loopback testing +%USB\VID_18D1&PID_DDDD.DeviceDescTest%=androidusb.Dev, USB\VID_18D1&PID_DDDD +; HTC Dream +%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01 +%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01 +%USB\VID_0BB4&PID_0C03&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C03&MI_01 +%USB\VID_0BB4&PID_0FFF.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0FFF + +[androidusb.Dev.NT] +CopyFiles=androidusb.Files.Ext + +[androidusb.Dev.NT.Services] +Addservice = androidusb, 0x00000002, androidusb.AddService + +[androidusb.AddService] +DisplayName = %androidusb.SvcDesc% +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 1 ; SERVICE_ERROR_NORMAL +ServiceBinary = %10%\System32\Drivers\androidusb.sys +AddReg = androidusb.AddReg +LoadOrderGroup = Base + +[androidusb.AddReg] +HKR,"Parameters","MaximumTransferSize",0x10001,4096 +HKR,"Parameters","DebugLevel",0x10001,2 +HKR, Parameters\Wdf, VerboseOn, 0x00010001, 1 +HKR, Parameters\Wdf, VerifierOn, 0x00010001, 1 +HKR, Parameters\Wdf, DbgBreakOnError, 0x00010001, 1 + +[androidusb.Files.Ext] +androidusb.sys + +[SourceDisksNames] +1=%Disk_Description%,,, + +[SourceDisksFiles] +androidusb.sys = 1 + +;-------------- WDF Coinstaller installation +[DestinationDirs] +CoInstaller_CopyFiles = 11 + +[androidusb.Dev.NT.CoInstallers] +AddReg=CoInstaller_AddReg +CopyFiles=CoInstaller_CopyFiles + +[CoInstaller_CopyFiles] +wdfcoinstaller01005.dll + +[SourceDisksFiles] +wdfcoinstaller01005.dll=1 ; make sure the number matches with SourceDisksNames + +[CoInstaller_AddReg] +HKR,,CoInstallers32,0x00010000, "wdfcoinstaller01005.dll,WdfCoInstaller" + +[androidusb.Dev.NT.Wdf] +KmdfService = androidusb, androidusb_wdfsect + +[androidusb_wdfsect] +KmdfLibraryVersion = 1.5 + +;---------------------------------------------------------------; + +[Strings] +GOOG = "Google, Inc" +MfgName = "Google, Inc" +Disk_Description= "ADB Interface Installation Disk" +androidusb.SvcDesc = "ADB Interface Driver" +ClassName = "ADB Interface" +USB\VID_18D1&PID_DDDD.DeviceDescTest="ADB Testing Interface" +USB\VID_0BB4&PID_0C01.DeviceDescRelease="HTC Dream" +USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease="HTC Dream Composite ADB Interface" +USB\VID_0BB4&PID_0C03&MI_01.DeviceDescRelease="HTC Magic Composite ADB Interface" +USB\VID_0BB4&PID_0FFF.DeviceDescRelease="HTC Bootloader" diff --git a/host/windows/usb/legacy/driver/android_usb.rc b/host/windows/usb/legacy/driver/android_usb.rc new file mode 100755 index 000000000..0e7571ea7 --- /dev/null +++ b/host/windows/usb/legacy/driver/android_usb.rc @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2008 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. + */ + +#include + +// Don't let the resource editor in here +#ifdef APSTUDIO_INVOKED + #error this file is not editable by Visual C++ +#endif //APSTUDIO_INVOKED + + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "ADB Interface" +#define VER_INTERNALNAME_STR "androidusb.sys" +#define VER_ORIGINALFILENAME_STR "androidusb.sys" +#define VER_FILEOS VOS_NT +#define VER_FILEFLAGSMASK (VS_FF_DEBUG | VS_FF_PRERELEASE) + +#if DBG + #define VER_FILEFLAGS VS_FF_DEBUG | VS_FF_PRERELEASE +#else // DBG + #define VER_FILEFLAGS VS_FF_PRERELEASE +#endif // DBG + +#include "common.ver" diff --git a/host/windows/usb/legacy/driver/android_usb_bulk_file_object.cpp b/host/windows/usb/legacy/driver/android_usb_bulk_file_object.cpp new file mode 100755 index 000000000..9f8ac6b29 --- /dev/null +++ b/host/windows/usb/legacy/driver/android_usb_bulk_file_object.cpp @@ -0,0 +1,52 @@ +/* + * 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 AndroidUsbBulkPipeFileObject + that encapsulates extension to a bulk pipe file objects. +*/ +#pragma data_seg() +#pragma code_seg() + +#include "precomp.h" +#include "android_usb_bulk_file_object.h" + +#pragma data_seg() +#pragma code_seg("PAGE") + +AndroidUsbBulkPipeFileObject::AndroidUsbBulkPipeFileObject( + AndroidUsbDeviceObject* dev_obj, + WDFFILEOBJECT wdf_fo, + WDFUSBPIPE wdf_pipe_obj) + : AndroidUsbPipeFileObject(dev_obj, wdf_fo, wdf_pipe_obj) { + ASSERT_IRQL_PASSIVE(); + +#if DBG + WDF_USB_PIPE_INFORMATION pipe_info; + WDF_USB_PIPE_INFORMATION_INIT(&pipe_info); + WdfUsbTargetPipeGetInformation(wdf_pipe_obj, &pipe_info); + ASSERT(WdfUsbPipeTypeBulk == pipe_info.PipeType); +#endif // DBG +} + +#pragma code_seg() + +AndroidUsbBulkPipeFileObject::~AndroidUsbBulkPipeFileObject() { + ASSERT_IRQL_LOW_OR_DISPATCH(); +} + +#pragma data_seg() +#pragma code_seg() diff --git a/host/windows/usb/legacy/driver/android_usb_bulk_file_object.h b/host/windows/usb/legacy/driver/android_usb_bulk_file_object.h new file mode 100755 index 000000000..f563daa35 --- /dev/null +++ b/host/windows/usb/legacy/driver/android_usb_bulk_file_object.h @@ -0,0 +1,50 @@ +/* + * 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. + */ + +#ifndef ANDROID_USB_BULK_PIPE_FILE_OBJECT_H__ +#define ANDROID_USB_BULK_PIPE_FILE_OBJECT_H__ +/** \file + This file consists of declaration of class AndroidUsbBulkPipeFileObject + that encapsulates extension to a bulk pipe file objects. +*/ + +#include "android_usb_pipe_file_object.h" + +/** AndroidUsbBulkPipeFileObject class encapsulates extension to a KMDF file + object that represent opened bulk pipe. Instances of this class must be + allocated from NonPagedPool. +*/ +class AndroidUsbBulkPipeFileObject : public AndroidUsbPipeFileObject { + public: + /** \brief Constructs the object. + + This method must be called at low IRQL. + @param dev_obj[in] Our device object for which this file has been created + @param wdf_fo[in] KMDF file object this extension wraps + @param wdf_pipe_obj[in] KMDF pipe for this file + */ + AndroidUsbBulkPipeFileObject(AndroidUsbDeviceObject* dev_obj, + WDFFILEOBJECT wdf_fo, + WDFUSBPIPE wdf_pipe_obj); + + /** \brief Destructs the object. + + This method can be called at any IRQL. + */ + virtual ~AndroidUsbBulkPipeFileObject(); +}; + +#endif // ANDROID_USB_BULK_PIPE_FILE_OBJECT_H__ diff --git a/host/windows/usb/legacy/driver/android_usb_device_file_object.cpp b/host/windows/usb/legacy/driver/android_usb_device_file_object.cpp new file mode 100755 index 000000000..a5e764ef7 --- /dev/null +++ b/host/windows/usb/legacy/driver/android_usb_device_file_object.cpp @@ -0,0 +1,83 @@ +/* + * 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 AndroidUsbDeviceFileObject + that encapsulates an extension for a KMDF file object that represent + opened device. +*/ +#pragma data_seg() +#pragma code_seg() + +#include "precomp.h" +#include "android_usb_device_file_object.h" + +#pragma data_seg() +#pragma code_seg("PAGE") + +AndroidUsbDeviceFileObject::AndroidUsbDeviceFileObject( + AndroidUsbDeviceObject* dev_obj, + WDFFILEOBJECT wdf_fo) + : AndroidUsbFileObject(AndroidUsbFileObjectTypeDevice, dev_obj, wdf_fo) { + ASSERT_IRQL_PASSIVE(); +} + +#pragma code_seg() + +AndroidUsbDeviceFileObject::~AndroidUsbDeviceFileObject() { + ASSERT_IRQL_LOW_OR_DISPATCH(); +} + +void AndroidUsbDeviceFileObject::OnEvtIoDeviceControl(WDFREQUEST request, + size_t output_buf_len, + size_t input_buf_len, + ULONG ioctl_code) { + ASSERT_IRQL_LOW_OR_DISPATCH(); + + switch (ioctl_code) { + case ADB_IOCTL_GET_USB_DEVICE_DESCRIPTOR: + device_object()->OnGetUsbDeviceDescriptorCtl(request, output_buf_len); + break; + + case ADB_IOCTL_GET_USB_CONFIGURATION_DESCRIPTOR: + device_object()->OnGetUsbConfigDescriptorCtl(request, output_buf_len); + break; + + case ADB_IOCTL_GET_USB_INTERFACE_DESCRIPTOR: + device_object()->OnGetUsbInterfaceDescriptorCtl(request, output_buf_len); + break; + + case ADB_IOCTL_GET_ENDPOINT_INFORMATION: + device_object()->OnGetEndpointInformationCtl(request, + input_buf_len, + output_buf_len); + break; + + case ADB_IOCTL_GET_SERIAL_NUMBER: + device_object()->OnGetSerialNumberCtl(request, output_buf_len); + break; + + default: + AndroidUsbFileObject::OnEvtIoDeviceControl(request, + output_buf_len, + input_buf_len, + ioctl_code); + break; + } +} + +#pragma data_seg() +#pragma code_seg() diff --git a/host/windows/usb/legacy/driver/android_usb_device_file_object.h b/host/windows/usb/legacy/driver/android_usb_device_file_object.h new file mode 100755 index 000000000..6deed6c74 --- /dev/null +++ b/host/windows/usb/legacy/driver/android_usb_device_file_object.h @@ -0,0 +1,73 @@ +/* + * 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. + */ + +#ifndef ANDROID_USB_DEVICE_FILE_OBJECT_H__ +#define ANDROID_USB_DEVICE_FILE_OBJECT_H__ +/** \file + This file consists of declaration of class AndroidUsbDeviceFileObject that + encapsulates an extension for a KMDF file object that represent opened + device. +*/ + +#include "android_usb_file_object.h" + +/** AndroidUsbDeviceFileObject class encapsulates an extension for a KMDF + file object that represent opened device. Instances of this class must be + allocated from NonPagedPool. +*/ +class AndroidUsbDeviceFileObject : public AndroidUsbFileObject { + public: + /** \brief Constructs the object. + + This method must be called at low IRQL. + @param dev_obj[in] Our device object for which this file has been created + @param wdf_fo[in] KMDF file object this extension wraps + */ + AndroidUsbDeviceFileObject(AndroidUsbDeviceObject* dev_obj, + WDFFILEOBJECT wdf_fo); + + /** \brief Destructs the object. + + This method can be called at any IRQL. + */ + virtual ~AndroidUsbDeviceFileObject(); + + /** \brief IOCTL event handler + + This method is called when a device control request comes to the file + object this extension wraps. We override this method to handle the + following IOCTL requests: + 1. ADB_CTL_GET_USB_DEVICE_DESCRIPTOR + 2. ADB_CTL_GET_USB_CONFIGURATION_DESCRIPTOR + 3. ADB_CTL_GET_USB_INTERFACE_DESCRIPTOR + 4. ADB_CTL_GET_ENDPOINT_INFORMATION + This callback can be called IRQL <= DISPATCH_LEVEL. + @param request[in] A handle to a framework request object. + @param output_buf_len[in] The length, in bytes, of the request's output + buffer, if an output buffer is available. + @param input_buf_len[in] The length, in bytes, of the request's input + buffer, if an input buffer is available. + @param ioctl_code[in] The driver-defined or system-defined I/O control code + that is associated with the request. + @return Successful status or an appropriate error code + */ + virtual void OnEvtIoDeviceControl(WDFREQUEST request, + size_t output_buf_len, + size_t input_buf_len, + ULONG ioctl_code); +}; + +#endif // ANDROID_USB_DEVICE_FILE_OBJECT_H__ diff --git a/host/windows/usb/legacy/driver/android_usb_device_object.cpp b/host/windows/usb/legacy/driver/android_usb_device_object.cpp new file mode 100755 index 000000000..1e7101f31 --- /dev/null +++ b/host/windows/usb/legacy/driver/android_usb_device_object.cpp @@ -0,0 +1,1216 @@ +/* + * 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(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(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(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 + (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 + (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 + (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(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(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(&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(file_path->Buffer[index] - L'0')); + umultiplier *= 10; + } + + return static_cast(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() diff --git a/host/windows/usb/legacy/driver/android_usb_device_object.h b/host/windows/usb/legacy/driver/android_usb_device_object.h new file mode 100755 index 000000000..698dc87e7 --- /dev/null +++ b/host/windows/usb/legacy/driver/android_usb_device_object.h @@ -0,0 +1,603 @@ +/* + * 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. + */ + +#ifndef ANDROID_USB_DEVICE_OBJECT_H__ +#define ANDROID_USB_DEVICE_OBJECT_H__ +/** \file + This file consists of declaration of class AndroidUsbDeviceObject that + encapsulates an extension for KMDF device (FDO) object. +*/ + +#include "android_usb_wdf_object.h" + +// Forward declaration for file object extension +class AndroidUsbFileObject; + +/** AndroidUsbDeviceObject class encapsulates an extension for KMDF FDO device + object. Instances of this class must be allocated from NonPagedPool. +*/ +class AndroidUsbDeviceObject : public AndroidUsbWdfObject { + public: + /** \brief Constructs the object. + + This method must be called at low IRQL. + */ + AndroidUsbDeviceObject(); + + /** \brief Destructs the object. + + This method can be called at any IRQL. + */ + ~AndroidUsbDeviceObject(); + + public: + /** \brief Creates and initializes FDO device object extension + + This method is called from driver's OnAddDevice method in response to + AddDevice call from the PnP manager + @param device_init[in] A pointer to a framework-allocated WDFDEVICE_INIT + structure. + @return If the routine succeeds, it returns STATUS_SUCCESS. Otherwise, + it returns one of the error status values defined in ntstatus.h. + */ + NTSTATUS CreateFDODevice(PWDFDEVICE_INIT device_init); + + /** \brief Resets target device + + When executing this method instance of this class may be deleted! + This method must be called at PASSIVE IRQL. + @return STATUS_SUCCESS or an appropriate error code + */ + NTSTATUS ResetDevice(); + + private: + /** \name Device event handlers and callbacks + */ + ///@{ + + /** \brief Handler for PnP prepare hardware event + + This method performs any operations that are needed to make a device + accessible to the driver. The framework calls this callback after the PnP + manager has assigned hardware resources to the device and after the device + has entered its uninitialized D0 state. This callback is called before + calling the driver's EvtDeviceD0Entry callback function. + This method is called at PASSIVE IRQL. + @param resources_raw[in] A handle to a framework resource-list object that + identifies the raw hardware resources that the PnP manager has + assigned to the device. + @param resources_translated[in] A handle to a framework resource-list + object that identifies the translated hardware resources that the + PnP manager has assigned to the device. + @return Successful status or an appropriate error code + */ + NTSTATUS OnEvtDevicePrepareHardware(WDFCMRESLIST resources_raw, + WDFCMRESLIST resources_translated); + + /** \brief Handler for PnP release hardware event + + This method performs operations that that are needed when a device is no + longer accessible. Framework calls the callback function if the device is + being removed, or if the PnP manager is attempting to redistribute hardware + resources. The framework calls the EvtDeviceReleaseHardware callback + function after the driver's device has been shut off, the PnP manager has + reclaimed the hardware resources that it assigned to the device, and the + device is no longer accessible. (The PCI configuration state is still + accessible.) Typically, a EvtDeviceReleaseHardware callback function unmaps + memory that the driver's EvtDevicePrepareHardware callback function mapped. + Usually, all other hardware shutdown operations should take place in the + driver's EvtDeviceD0Exit callback function. + This method is called at PASSIVE IRQL. + @param wdf_device[in] A handle to a framework device object. + @param resources_translated[in] A handle to a framework resource-list + object that identifies the translated hardware resources that the + PnP manager has assigned to the device. + @return Successful status or an appropriate error code + */ + NTSTATUS OnEvtDeviceReleaseHardware(WDFCMRESLIST resources_translated); + + /** \brief Handler for create file event (request) + + This method performs operations that are needed when an application + requests access to an item within this device path (including device + itself). This method is called synchronously, in the context of the + user thread that opens the item. + This method is called at PASSIVE IRQL. + @param request[in] A handle to a framework request object that represents + a file creation request. + @param wdf_fo[in] A handle to a framework file object that describes a + file that is being created with this request. + @return Successful status or an appropriate error code + */ + void OnEvtDeviceFileCreate(WDFREQUEST request, WDFFILEOBJECT wdf_fo); + + /** \brief Entry point for PnP prepare hardware event + + This callback performs any operations that are needed to make a device + accessible to the driver. The framework calls this callback after the PnP + manager has assigned hardware resources to the device and after the device + has entered its uninitialized D0 state. This callback is called before + calling the driver's EvtDeviceD0Entry callback function. + This callback is called at PASSIVE IRQL. + @param wdf_dev[in] A handle to a framework device object. + @param resources_raw[in] A handle to a framework resource-list object that + identifies the raw hardware resources that the PnP manager has + assigned to the device. + @param resources_translated[in] A handle to a framework resource-list + object that identifies the translated hardware resources that the + PnP manager has assigned to the device. + @return Successful status or an appropriate error code + */ + static NTSTATUS EvtDevicePrepareHardwareEntry(WDFDEVICE wdf_dev, + WDFCMRESLIST resources_raw, + WDFCMRESLIST resources_translated); + + /** \brief Entry point for PnP release hardware event + + This callback performs operations that that are needed when a device is no + longer accessible. Framework calls the callback function if the device is + being removed, or if the PnP manager is attempting to redistribute hardware + resources. The framework calls the EvtDeviceReleaseHardware callback + function after the driver's device has been shut off, the PnP manager has + reclaimed the hardware resources that it assigned to the device, and the + device is no longer accessible. (The PCI configuration state is still + accessible.) Typically, a EvtDeviceReleaseHardware callback function unmaps + memory that the driver's EvtDevicePrepareHardware callback function mapped. + Usually, all other hardware shutdown operations should take place in the + driver's EvtDeviceD0Exit callback function. + This callback is called at PASSIVE IRQL. + @param wdf_dev[in] A handle to a framework device object. + @param resources_translated[in] A handle to a framework resource-list + object that identifies the translated hardware resources that the + PnP manager has assigned to the device. + @return Successful status or an appropriate error code + */ + static NTSTATUS EvtDeviceReleaseHardwareEntry(WDFDEVICE wdf_dev, + WDFCMRESLIST resources_translated); + + /** \brief Entry point for create file event (request) + + This callback performs operations that that are needed when an application + requests access to a device. The framework calls a driver's + EvtDeviceFileCreate callback function when a user application or another + driver opens the device (or file on this device) to perform an I/O + operation, such as reading or writing a file. This callback function is + called synchronously, in the context of the user thread that opens the + device. + This callback is called at PASSIVE IRQL. + @param wdf_dev[in] A handle to a framework device object. + @param request[in] A handle to a framework request object that represents + a file creation request. + @param wdf_fo[in] A handle to a framework file object that describes a + file that is being created with this request. + @return Successful status or an appropriate error code + */ + static void EvtDeviceFileCreateEntry(WDFDEVICE wdf_dev, + WDFREQUEST request, + WDFFILEOBJECT wdf_fo); + + ///@} + + private: + /** \name I/O request event handlers and callbacks + */ + ///@{ + + /** \brief Read event handler + + This method is called when a read request comes to a file object opened + on this device. + This method can be called IRQL <= DISPATCH_LEVEL. + @param request[in] A handle to a framework request object. + @param length[in] The number of bytes to be read. + */ + void OnEvtIoRead(WDFREQUEST request, size_t length); + + /** \brief Write event handler + + This method is called when a write request comes to a file object opened + on this device. + This method can be called IRQL <= DISPATCH_LEVEL. + @param request[in] A handle to a framework request object. + @param length[in] The number of bytes to be written. + */ + void OnEvtIoWrite(WDFREQUEST request, size_t length); + + /** \brief IOCTL event handler + + This method is called when a device control request comes to a file object + opened on this device. + This method can be called IRQL <= DISPATCH_LEVEL. + @param request[in] A handle to a framework request object. + @param output_buf_len[in] The length, in bytes, of the request's output + buffer, if an output buffer is available. + @param input_buf_len[in] The length, in bytes, of the request's input + buffer, if an input buffer is available. + @param ioctl_code[in] The driver-defined or system-defined I/O control code + that is associated with the request. + */ + void OnEvtIoDeviceControl(WDFREQUEST request, + size_t output_buf_len, + size_t input_buf_len, + ULONG ioctl_code); + + /** \brief Entry point for read event + + This callback is called when a read request comes to a file object opened + on this device. + This callback can be called IRQL <= DISPATCH_LEVEL. + @param queue[in] A handle to the framework queue object that is associated + with the I/O request. + @param request[in] A handle to a framework request object. + @param length[in] The number of bytes to be read. + */ + static void EvtIoReadEntry(WDFQUEUE queue, + WDFREQUEST request, + size_t length); + + /** \brief Entry point for write event + + This callback is called when a write request comes to a file object opened + on this device. + This callback can be called IRQL <= DISPATCH_LEVEL. + @param queue[in] A handle to the framework queue object that is associated + with the I/O request. + @param request[in] A handle to a framework request object. + @param length[in] The number of bytes to be written. + */ + static void EvtIoWriteEntry(WDFQUEUE queue, + WDFREQUEST request, + size_t length); + + /** \brief Entry point for device IOCTL event + + This callback is called when a device control request comes to a file + object opened on this device. + This callback can be called IRQL <= DISPATCH_LEVEL. + @param queue[in] A handle to the framework queue object that is associated + with the I/O request. + @param request[in] A handle to a framework request object. + @param output_buf_len[in] The length, in bytes, of the request's output + buffer, if an output buffer is available. + @param input_buf_len[in] The length, in bytes, of the request's input + buffer, if an input buffer is available. + @param ioctl_code[in] The driver-defined or system-defined I/O control code + that is associated with the request. + */ + static void EvtIoDeviceControlEntry(WDFQUEUE queue, + WDFREQUEST request, + size_t output_buf_len, + size_t input_buf_len, + ULONG ioctl_code); + + ///@} + + public: + /** \name Device level I/O request handlers + */ + ///@{ + + /** \brief Gets USB device descriptor + + This method can be called at IRQL <= DISPATCH_LEVEL + @param request[in] A handle to a framework request object for this IOCTL. + @param output_buf_len[in] The length, in bytes, of the request's output + buffer, if an output buffer is available. + */ + void OnGetUsbDeviceDescriptorCtl(WDFREQUEST request, size_t output_buf_len); + + /** \brief Gets USB configuration descriptor for the selected configuration. + + This method can be called at IRQL <= DISPATCH_LEVEL + @param request[in] A handle to a framework request object for this IOCTL. + @param output_buf_len[in] The length, in bytes, of the request's output + buffer, if an output buffer is available. + */ + void OnGetUsbConfigDescriptorCtl(WDFREQUEST request, size_t output_buf_len); + + /** \brief Gets USB configuration descriptor for the selected interface. + + This method can be called at IRQL <= DISPATCH_LEVEL + @param request[in] A handle to a framework request object for this IOCTL. + @param output_buf_len[in] The length, in bytes, of the request's output + buffer, if an output buffer is available. + */ + void OnGetUsbInterfaceDescriptorCtl(WDFREQUEST request, size_t output_buf_len); + + /** \brief Gets information about an endpoint. + + This method can be called at IRQL <= DISPATCH_LEVEL + @param request[in] A handle to a framework request object for this IOCTL. + @param input_buf_len[in] The length, in bytes, of the request's input + buffer, if an input buffer is available. + @param output_buf_len[in] The length, in bytes, of the request's output + buffer, if an output buffer is available. + */ + void OnGetEndpointInformationCtl(WDFREQUEST request, + size_t input_buf_len, + size_t output_buf_len); + + /** \brief Gets device serial number. + + Serial number is returned in form of zero-terminated string that in the + output buffer. This method must be called at low IRQL. + @param request[in] A handle to a framework request object for this IOCTL. + @param output_buf_len[in] The length, in bytes, of the request's output + buffer, if an output buffer is available. + */ + void OnGetSerialNumberCtl(WDFREQUEST request, size_t output_buf_len); + + ///@} + + private: + /** \name Internal methods + */ + ///@{ + + /** \brief Creates default request queue for this device. + + In KMDF all I/O requests are coming through the queue object. So, in order + to enable our device to receive I/O requests we must create a queue for it. + This method is called at PASSIVE IRQL. + @return STATUS_SUCCESS or an appropriate error code. + */ + NTSTATUS CreateDefaultQueue(); + + /** \brief Configures our device. + + This method is called from the prepare hardware handler after underlying + FDO device has been created. + This method is called at PASSSIVE IRQL. + @return STATUS_SUCCESS or an appropriate error code. + */ + NTSTATUS ConfigureDevice(); + + /** \brief Selects interfaces on our device. + + This method is called from the prepare hardware handler after underlying + FDO device has been created and configured. + This method is called at PASSSIVE IRQL. + @return STATUS_SUCCESS or an appropriate error code. + */ + NTSTATUS SelectInterfaces(); + + /** \brief Gets pipe index from a file name + + This method is called from OnEvtDeviceFileCreate to determine index of + the pipe this file is addressing. + This method is called at PASSIVE IRQL. + @param file_path[in] Path to the file that being opened. + @return Pipe index or INVALID_UCHAR if index cannot be calculated. + */ + UCHAR GetPipeIndexFromFileName(PUNICODE_STRING file_path); + + /** \brief Creates file object extension for a pipe + + This method is called from OnEvtDeviceFileCreate to create an appropriate + file object extension for a particular pipe type. + This method is called at PASSIVE IRQL. + @param wdf_fo[in] KMDF file to extend. + @param wdf_pipe_obj[in] KMDF pipe for this extension + @param pipe_info[in] Pipe information + @param wdf_file_ext[out] Upon successfull completion will receive instance + of the extension. + @return STATUS_SUCCESS or an appropriate error code + */ + NTSTATUS CreatePipeFileObjectExt(WDFFILEOBJECT wdf_fo, + WDFUSBPIPE wdf_pipe_obj, + const WDF_USB_PIPE_INFORMATION* pipe_info, + AndroidUsbFileObject** wdf_file_ext); + + ///@} + + private: + /** \name Debugging support + */ + ///@{ + +#if DBG + /// Prints USB_DEVICE_DESCRIPTOR to debug output + void PrintUsbDeviceDescriptor(const USB_DEVICE_DESCRIPTOR* desc); + + /// Prints WDF_USB_DEVICE_INFORMATION to debug output + void PrintUsbTargedDeviceInformation(const WDF_USB_DEVICE_INFORMATION* info); + + /// Prints USB_CONFIGURATION_DESCRIPTOR to debug output + void PrintConfigDescriptor(const USB_CONFIGURATION_DESCRIPTOR* desc, + ULONG size); + + /// Prints WDF_USB_DEVICE_SELECT_CONFIG_PARAMS to debug output + void PrintSelectedConfig(const WDF_USB_DEVICE_SELECT_CONFIG_PARAMS* config); + + /// Prints USB_INTERFACE_DESCRIPTOR to debug output + void PrintInterfaceDescriptor(const USB_INTERFACE_DESCRIPTOR* desc); + + /// Prints WDF_USB_PIPE_INFORMATION to debug output + void PrintPipeInformation(const WDF_USB_PIPE_INFORMATION* info, + UCHAR pipe_index); + +#endif // DBG + + ///@} + + public: + /// Gets WDF device handle for this device + __forceinline WDFDEVICE wdf_device() const { + return reinterpret_cast(wdf_object()); + } + + /// Gets target USB device descriptor + __forceinline const USB_DEVICE_DESCRIPTOR* usb_device_descriptor() const { + return &usb_device_descriptor_; + } + + /// Gets target USB device information + __forceinline const WDF_USB_DEVICE_INFORMATION* usb_device_info() const { + return &usb_device_info_; + } + + /// Gets selected interface descriptor + __forceinline const USB_INTERFACE_DESCRIPTOR* interface_descriptor() const { + return &interface_descriptor_; + } + + /// Gets target (PDO) device handle + __forceinline WDFUSBDEVICE wdf_target_device() const { + return wdf_target_device_; + } + + /// Checks if target device has been created + __forceinline bool IsTaretDeviceCreated() const { + return (NULL != wdf_target_device()); + } + + /// Gets USB configuration descriptor + __forceinline const USB_CONFIGURATION_DESCRIPTOR* configuration_descriptor() const { + return configuration_descriptor_; + } + + /// Checks if device has been configured + __forceinline bool IsDeviceConfigured() const { + return (NULL != configuration_descriptor()); + } + + /// Gets number of interfaces for this device + __forceinline UCHAR GetInterfaceCount() const { + ASSERT(IsDeviceConfigured()); + return IsDeviceConfigured() ? configuration_descriptor()->bNumInterfaces : 0; + } + + /// Checks if this is "single interface" device + __forceinline bool IsSingleInterfaceDevice() const { + return (1 == GetInterfaceCount()); + } + + /// Gets USB interface selected on this device + __forceinline WDFUSBINTERFACE wdf_usb_interface() const { + return wdf_usb_interface_; + } + + /// Checks if an interface has been selected on this device + __forceinline bool IsInterfaceSelected() const { + return (NULL != wdf_usb_interface()); + } + + /// Gets number of pipes configured on this device + __forceinline UCHAR configured_pipes_num() const { + return configured_pipes_num_; + } + + /// Gets index of the bulk read pipe + __forceinline UCHAR bulk_read_pipe_index() const { + return bulk_read_pipe_index_; + } + + /// Gets index of the bulk write pipe + __forceinline UCHAR bulk_write_pipe_index() const { + return bulk_write_pipe_index_; + } + + /// Checks if this is a high speed device + __forceinline bool IsHighSpeed() const { + return (0 != (usb_device_info()->Traits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED)); + } + + /// Checks if bulk read pipe index is known + __forceinline bool IsBulkReadPipeKnown() const { + return (INVALID_UCHAR != bulk_read_pipe_index()); + } + + /// Checks if bulk write pipe index is known + __forceinline bool IsBulkWritePipeKnown() const { + return (INVALID_UCHAR != bulk_write_pipe_index()); + } + + /// Gets device serial number string. Note that string may be + /// not zero-terminated. Use serial_number_len() to get actual + /// length of this string. + __forceinline const WCHAR* serial_number() const { + ASSERT(NULL != serial_number_handle_); + return (NULL != serial_number_handle_) ? + reinterpret_cast + (WdfMemoryGetBuffer(serial_number_handle_, NULL)) : + NULL; + } + + /// Gets length (in bytes) of device serial number string + __forceinline USHORT serial_number_char_len() const { + return serial_number_char_len_; + } + + /// Gets length (in bytes) of device serial number string + __forceinline USHORT serial_number_byte_len() const { + return serial_number_char_len() * sizeof(WCHAR); + } + + protected: + /// Target USB device descriptor + USB_DEVICE_DESCRIPTOR usb_device_descriptor_; + + /// Target USB device information + WDF_USB_DEVICE_INFORMATION usb_device_info_; + + /// Selected interface descriptor + USB_INTERFACE_DESCRIPTOR interface_descriptor_; + + /// USB configuration descriptor + PUSB_CONFIGURATION_DESCRIPTOR configuration_descriptor_; + + /// Target (PDO?) device handle + WDFUSBDEVICE wdf_target_device_; + + /// USB interface selected on this device + WDFUSBINTERFACE wdf_usb_interface_; + + /// Device serial number + WDFMEMORY serial_number_handle_; + + /// Device serial number string length + USHORT serial_number_char_len_; + + /// Number of pipes configured on this device + UCHAR configured_pipes_num_; + + /// Index of the bulk read pipe + UCHAR bulk_read_pipe_index_; + + /// Index of the bulk write pipe + UCHAR bulk_write_pipe_index_; +}; + +/** \brief Gets device KMDF object extension for the given KMDF object + + @param wdf_dev[in] KMDF handle describing device object + @return Instance of AndroidUsbDeviceObject associated with KMDF object or + NULL if association is not found. +*/ +__forceinline AndroidUsbDeviceObject* GetAndroidUsbDeviceObjectFromHandle( + WDFDEVICE wdf_dev) { + AndroidUsbWdfObject* wdf_object_ext = + GetAndroidUsbWdfObjectFromHandle(wdf_dev); + ASSERT((NULL != wdf_object_ext) && + wdf_object_ext->Is(AndroidUsbWdfObjectTypeDevice)); + if ((NULL != wdf_object_ext) && + wdf_object_ext->Is(AndroidUsbWdfObjectTypeDevice)) { + return reinterpret_cast(wdf_object_ext); + } + return NULL; +} + +#endif // ANDROID_USB_DEVICE_OBJECT_H__ diff --git a/host/windows/usb/legacy/driver/android_usb_driver_defines.h b/host/windows/usb/legacy/driver/android_usb_driver_defines.h new file mode 100755 index 000000000..da976e56f --- /dev/null +++ b/host/windows/usb/legacy/driver/android_usb_driver_defines.h @@ -0,0 +1,171 @@ +/* + * 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. + */ + +#ifndef ANDROID_USB_DRIVER_DEFINES_H__ +#define ANDROID_USB_DRIVER_DEFINES_H__ +/** \file + This file consists of constants, types and macros used (and useful) in driver + development. +*/ + +/** \name IRQL assertions + These assertions help to verify that code is running at expected IRQL +*/ +///@{ + +/// Asserts that current IRQL is less than provided level +#define ASSERT_IRQL_LESS(irql_level) ASSERT(KeGetCurrentIrql() < irql_level) +/// Asserts that current IRQL is less or equal than provided level +#define ASSERT_IRQL_LESS_OR_EQUAL(irql_level) ASSERT(KeGetCurrentIrql() <= irql_level) +/// Asserts that current IRQL is the same as provided level +#define ASSERT_IRQL_IS(irql_level) ASSERT(irql_level == KeGetCurrentIrql()) +/// Asserts that current IRQL is less than DISPATCH_LEVEL +#define ASSERT_IRQL_LOW() ASSERT_IRQL_LESS(DISPATCH_LEVEL) +/// Asserts that current IRQL is above APC_LEVEL +#define ASSERT_IRQL_HIGH() ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL) +/// Asserts that current IRQL is at PASSIVE_LEVEL +#define ASSERT_IRQL_PASSIVE() ASSERT_IRQL_IS(PASSIVE_LEVEL) +/// Asserts that current IRQL is at APC_LEVEL +#define ASSERT_IRQL_APC() ASSERT_IRQL_IS(APC_LEVEL) +/// Asserts that current IRQL is at DISPATCH_LEVEL +#define ASSERT_IRQL_DISPATCH() ASSERT_IRQL_IS(DISPATCH_LEVEL) +/// Asserts that current IRQL is at APC or DISPATCH_LEVEL +#define ASSERT_IRQL_APC_OR_DISPATCH() \ + ASSERT((KeGetCurrentIrql() == APC_LEVEL) || (KeGetCurrentIrql() == DISPATCH_LEVEL)) +/// Asserts that current IRQL is less or equal DISPATCH_LEVEL +#define ASSERT_IRQL_LOW_OR_DISPATCH() \ + ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL) + +///@} + +#if DBG +/** \brief Overrides DbgPrint to make sure that nothing gets printed + to debug output in release build. +*/ +ULONG __cdecl GoogleDbgPrint(char* format, ...); +#else +#define GoogleDbgPrint(Arg) NOTHING +#endif + +/// Invalid UCHAR value +#define INVALID_UCHAR (static_cast(0xFF)) + +/// Invalid ULONG value +#define INVALID_ULONG (static_cast(-1)) + +/** Enum AndroidUsbWdfObjectType enumerates types of KMDF objects that + we extend in our driver. +*/ +enum AndroidUsbWdfObjectType { + // We start enum with 1 insetead of 0 to protect orselves from a dangling + // or uninitialized context structures because KMDF will zero our extension + // when it gets created. + + /// Device object context + AndroidUsbWdfObjectTypeDevice = 1, + + /// File object context + AndroidUsbWdfObjectTypeFile, + + /// Request object context + AndroidUsbWdfObjectTypeRequest, + + /// Workitem object context + AndroidUsbWdfObjectTypeWorkitem, + + /// Illegal (maximum) context id + AndroidUsbWdfObjectTypeMax +}; + +/** Structure AndroidUsbWdfObjectContext represents our context that extends + every KMDF object (device, file, pipe, etc). +*/ +typedef struct TagAndroidUsbWdfObjectContext { + /// KMDF object type that is extended with this context + AndroidUsbWdfObjectType object_type; + + /// Instance of the class that extends KMDF object with this context + class AndroidUsbWdfObject* wdf_object_ext; +} AndroidUsbWdfObjectContext; + +// KMDF woodoo to register our extension and implement accessor method +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(AndroidUsbWdfObjectContext, + GetAndroidUsbWdfObjectContext) + +/** Structure AndroidUsbWdfRequestContext represents our context that is + associated with every request recevied by the driver. +*/ +typedef struct TagAndroidUsbWdfRequestContext { + /// KMDF object type that is extended with this context + /// (must be AndroidUsbWdfObjectTypeRequest) + AndroidUsbWdfObjectType object_type; + + /// System time request has been first scheduled + // (time of the first WdfRequestSend is called for it) + LARGE_INTEGER sent_at; + + /// KMDF descriptor for the memory allocated for URB + WDFMEMORY urb_mem; + + /// MDL describing the transfer buffer + PMDL transfer_mdl; + + /// Private MDL that we build in order to perform the transfer + PMDL mdl; + + // Virtual address for the current segment of transfer. + void* virtual_address; + + /// Number of bytes remaining to transfer + ULONG length; + + /// Number of bytes requested to transfer + ULONG transfer_size; + + /// Accummulated number of bytes transferred + ULONG num_xfer; + + /// Initial timeout (in millisec) set for this request + ULONG initial_time_out; + + // Read / Write selector + bool is_read; + + // IOCTL selector + bool is_ioctl; +} AndroidUsbWdfRequestContext; + +// KMDF woodoo to register our extension and implement accessor method +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(AndroidUsbWdfRequestContext, + GetAndroidUsbWdfRequestContext) + +/** Structure AndroidUsbWorkitemContext represents our context that is + associated with workitems created by our driver. +*/ +typedef struct TagAndroidUsbWorkitemContext { + /// KMDF object type that is extended with this context + /// (must be AndroidUsbWdfObjectTypeWorkitem) + AndroidUsbWdfObjectType object_type; + + /// Pipe file object extension that enqueued this work item + class AndroidUsbPipeFileObject* pipe_file_ext; +} AndroidUsbWorkitemContext; + +// KMDF woodoo to register our extension and implement accessor method +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(AndroidUsbWorkitemContext, + GetAndroidUsbWorkitemContext) + +#endif // ANDROID_USB_DRIVER_DEFINES_H__ diff --git a/host/windows/usb/legacy/driver/android_usb_driver_object.cpp b/host/windows/usb/legacy/driver/android_usb_driver_object.cpp new file mode 100755 index 000000000..770a13aa8 --- /dev/null +++ b/host/windows/usb/legacy/driver/android_usb_driver_object.cpp @@ -0,0 +1,186 @@ +/* + * 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 AndroidUsbDriverObject that + encapsulates our driver object +*/ +#pragma data_seg() +#pragma code_seg() + +#include "precomp.h" +#include "android_usb_device_object.h" +#include "android_usb_driver_object.h" + +#pragma data_seg() + +/** Globally accessible instance of the AndroidUsbDriverObject. + NT OS design allows us using of a global pointer to our driver object + instance since it can't be created or destroyed concurently and its value + is not going to change between creation and destruction. +*/ +AndroidUsbDriverObject* global_driver_object = NULL; + +#pragma code_seg("INIT") + +extern "C" { + +/// Main entry point to the driver +NTSTATUS DriverEntry(PDRIVER_OBJECT drv_object, PUNICODE_STRING reg_path) { + // Just pass it down inside the class + return AndroidUsbDriverObject::DriverEntry(drv_object, reg_path); +} + +} // extern "C" + +NTSTATUS AndroidUsbDriverObject::DriverEntry(PDRIVER_OBJECT drv_object, + PUNICODE_STRING reg_path) { + ASSERT_IRQL_PASSIVE(); + ASSERT(NULL != drv_object); + ASSERT((NULL != reg_path) && + (NULL != reg_path->Buffer) && + (0 != reg_path->Length)); + + // Instantiate driver object + global_driver_object = new(NonPagedPool, GANDR_POOL_TAG_DRIVER_OBJECT) + AndroidUsbDriverObject(drv_object, reg_path); + ASSERT(NULL != global_driver_object); + if (NULL == global_driver_object) + return STATUS_INSUFFICIENT_RESOURCES; + + // Initialize driver object + NTSTATUS status = global_driver_object->OnDriverEntry(drv_object, reg_path); + + if (!NT_SUCCESS(status)) { + // Something went wrong. Delete our driver object and get out of here. + delete global_driver_object; + } + + return status; +} + +AndroidUsbDriverObject::AndroidUsbDriverObject(PDRIVER_OBJECT drv_object, + PUNICODE_STRING reg_path) + : driver_object_(drv_object), + wdf_driver_(NULL) { + ASSERT_IRQL_PASSIVE(); + ASSERT(NULL != driver_object()); +} + +NTSTATUS AndroidUsbDriverObject::OnDriverEntry(PDRIVER_OBJECT drv_object, + PUNICODE_STRING reg_path) { + ASSERT_IRQL_PASSIVE(); + ASSERT(driver_object() == drv_object); + + // Initiialize driver config, specifying our unload callback and default + // pool tag for memory allocations that KMDF does on our behalf. + WDF_DRIVER_CONFIG config; + WDF_DRIVER_CONFIG_INIT(&config, EvtDeviceAddEntry); + config.EvtDriverUnload = EvtDriverUnloadEntry; + config.DriverPoolTag = GANDR_POOL_TAG_DEFAULT; + + // Create a framework driver object to represent our driver. + NTSTATUS status = WdfDriverCreate(drv_object, + reg_path, + WDF_NO_OBJECT_ATTRIBUTES, + &config, + &wdf_driver_); + ASSERT(NT_SUCCESS(status)); + if (!NT_SUCCESS(status)) + return status; + + GoogleDbgPrint("\n>>>>>>>>>> Android USB driver has started >>>>>>>>>>"); + + return STATUS_SUCCESS; +} + +#pragma code_seg("PAGE") + +AndroidUsbDriverObject::~AndroidUsbDriverObject() { + ASSERT_IRQL_PASSIVE(); +} + +NTSTATUS AndroidUsbDriverObject::OnAddDevice(PWDFDEVICE_INIT device_init) { + ASSERT_IRQL_PASSIVE(); + GoogleDbgPrint("\n++++++++++ AndroidUsbDriverObject::OnAddDevice ++++++++++"); + // Instantiate our device object extension for this device + AndroidUsbDeviceObject* wdf_device_ext = + new(NonPagedPool, GANDR_POOL_TAG_KMDF_DEVICE) AndroidUsbDeviceObject(); + ASSERT(NULL != wdf_device_ext); + if (NULL == wdf_device_ext) + return STATUS_INSUFFICIENT_RESOURCES; + + // Create and initialize FDO device + NTSTATUS status = wdf_device_ext->CreateFDODevice(device_init); + ASSERT(NT_SUCCESS(status)); + if (!NT_SUCCESS(status)) + delete wdf_device_ext; + + return status; +} + +void AndroidUsbDriverObject::OnDriverUnload() { + ASSERT_IRQL_PASSIVE(); + GoogleDbgPrint("\n<<<<<<<<<< Android USB driver is unloaded <<<<<<<<<<"); +} + +NTSTATUS AndroidUsbDriverObject::EvtDeviceAddEntry( + WDFDRIVER wdf_drv, + PWDFDEVICE_INIT device_init) { + ASSERT_IRQL_PASSIVE(); + ASSERT((NULL != global_driver_object) && (global_driver_object->wdf_driver() == wdf_drv)); + + // Pass it down to our driver object + if ((NULL == global_driver_object) || + (global_driver_object->wdf_driver() != wdf_drv)) { + return STATUS_INTERNAL_ERROR; + } + + return global_driver_object->OnAddDevice(device_init); +} + +VOID AndroidUsbDriverObject::EvtDriverUnloadEntry(WDFDRIVER wdf_drv) { + ASSERT_IRQL_PASSIVE(); + ASSERT((NULL != global_driver_object) && + (global_driver_object->wdf_driver() == wdf_drv)); + + // Pass it down to our driver object + if ((NULL != global_driver_object) && + (global_driver_object->wdf_driver() == wdf_drv)) { + global_driver_object->OnDriverUnload(); + // Now we can (and have to) delete our driver object + delete global_driver_object; + } +} + +#if DBG + +#pragma code_seg() + +ULONG __cdecl GoogleDbgPrint(char* format, ...) { + va_list arg_list; + va_start(arg_list, format); + ULONG ret = + vDbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, format, arg_list); + va_end(arg_list); + + return ret; +} + +#endif // DBG + +#pragma data_seg() +#pragma code_seg() diff --git a/host/windows/usb/legacy/driver/android_usb_driver_object.h b/host/windows/usb/legacy/driver/android_usb_driver_object.h new file mode 100755 index 000000000..568b97733 --- /dev/null +++ b/host/windows/usb/legacy/driver/android_usb_driver_object.h @@ -0,0 +1,152 @@ +/* + * 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. + */ + +#ifndef ANDROID_USB_DRIVER_OBJECT_H__ +#define ANDROID_USB_DRIVER_OBJECT_H__ +/** \file + This file consists of declaration of class AndroidUsbDriverObject that + encapsulates our driver object. +*/ + +/// Globally accessible pointer to the driver object +extern class AndroidUsbDriverObject* global_driver_object; + +/** AndroidUsbDriverObject class encapsulates driver object and provides + overall initialization / cleanup as well as management of globally used + resources. We use KMDF framework for this driver because it takes care of + most of the USB related "things" (like PnP, power management and other + stuff) so we can concentrate more on real functionality. This driver is + based on KMDF's usbsamp driver sample available at DDK's src\kmdf\usbsamp + directory. Instance of this class (always one) must be allocated from + NonPagedPool. +*/ +class AndroidUsbDriverObject { + + public: + /** \brief Driver initialization entry point. + + This method is a "gate" to our driver class from main DriverEntry routine. + Since this method is called from within DriverEntry only it is placed in + "INIT" code segment. + This method is called at IRQL PASSIVE_LEVEL. + @param drv_object[in] Driver object passed to DriverEntry routine + @param reg_path[in] Path to the driver's Registry passed to DriverEntry + routine + @returns STATUS_SUCCESS on success or an appropriate error code. + */ + static NTSTATUS DriverEntry(PDRIVER_OBJECT drv_object, + PUNICODE_STRING reg_path); + + private: + /** \brief Constructs driver object. + + Constructor for driver class must be as light as possible. All + initialization that may fail must be deferred to OnDriverEntry method. + Since this method is called from within DriverEntry only it is placed in + "INIT" code segment. + This method is called at IRQL PASSIVE_LEVEL. + @param drv_object[in] Driver object passed to DriverEntry routine + @param reg_path[in] Path to the driver's Registry passed to DriverEntry + routine + */ + AndroidUsbDriverObject(PDRIVER_OBJECT drv_object, PUNICODE_STRING reg_path); + + /** \brief Destructs driver object. + + Destructor for driver class must be as light as possible. All + uninitialization must be done in OnDriverUnload method. + This method must be called at PASSIVE IRQL. + */ + ~AndroidUsbDriverObject(); + + /** \brief Initializes instance of the driver object. + + This method is called immediatelly after driver object has been + instantiated to perform actual initialization of the driver. Since this + method is called from within DriverEntry only it is placed in + "INIT" code segment. + This method is called at IRQL PASSIVE_LEVEL. + @param drv_object[in] Driver object passed to DriverEntry routine + @param reg_path[in] Path to the driver's Registry passed to DriverEntry + routine + @returns STATUS_SUCCESS on success or an appropriate error code. + */ + NTSTATUS OnDriverEntry(PDRIVER_OBJECT drv_object, PUNICODE_STRING reg_path); + + /** \brief Actual handler for KMDF's AddDevice event + + This method is called by the framework in response to AddDevice call from + the PnP manager. We create and initialize a device object to represent a + new instance of the device. + This method is called at IRQL PASSIVE_LEVEL. + @param device_init[in] A pointer to a framework-allocated WDFDEVICE_INIT + structure. + @return If the routine succeeds, it returns STATUS_SUCCESS. Otherwise, + it returns one of the error status values defined in ntstatus.h. + */ + NTSTATUS OnAddDevice(PWDFDEVICE_INIT device_init); + + /** \brief Actual driver unload event handler. + + This method is called when driver is being unloaded. + This method is called at IRQL PASSIVE_LEVEL. + */ + void OnDriverUnload(); + + /** \brief KMDF's DeviceAdd event entry point + + This callback is called by the framework in response to AddDevice call from + the PnP manager. We create and initialize a device object to represent a + new instance of the device. All the software resources should be allocated + in this callback. + This method is called at IRQL PASSIVE_LEVEL. + @param wdf_drv[in] WDF driver handle. + @param device_init[in] A pointer to a framework-allocated WDFDEVICE_INIT + structure. + @return If the routine succeeds, it returns STATUS_SUCCESS. Otherwise, + it returns one of the error status values defined in ntstatus.h. + */ + static NTSTATUS EvtDeviceAddEntry(WDFDRIVER wdf_drv, + PWDFDEVICE_INIT device_init); + + /** \brief Driver unload event entry point. + + Framework calls this callback when driver is being unloaded. + This method is called at IRQL PASSIVE_LEVEL. + */ + static VOID EvtDriverUnloadEntry(WDFDRIVER wdf_drv); + + public: + + /// Gets this driver's DRIVER_OBJECT + __forceinline PDRIVER_OBJECT driver_object() const { + return driver_object_; + } + + /// Gets KMDF driver handle + __forceinline WDFDRIVER wdf_driver() const { + return wdf_driver_; + } + + private: + /// This driver's driver object + PDRIVER_OBJECT driver_object_; + + /// KMDF driver handle + WDFDRIVER wdf_driver_; +}; + +#endif // ANDROID_USB_DRIVER_OBJECT_H__ diff --git a/host/windows/usb/legacy/driver/android_usb_file_object.cpp b/host/windows/usb/legacy/driver/android_usb_file_object.cpp new file mode 100755 index 000000000..196faec9f --- /dev/null +++ b/host/windows/usb/legacy/driver/android_usb_file_object.cpp @@ -0,0 +1,100 @@ +/* + * 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 AndroidUsbFileObject that + encapsulates a common extension for all KMDF file object types. +*/ +#pragma data_seg() +#pragma code_seg() + +#include "precomp.h" +#include "android_usb_file_object.h" + +#pragma data_seg() +#pragma code_seg("PAGE") + +AndroidUsbFileObject::AndroidUsbFileObject(AndroidUsbFileObjectType fo_type, + AndroidUsbDeviceObject* dev_obj, + WDFFILEOBJECT wdf_fo) + : AndroidUsbWdfObject(AndroidUsbWdfObjectTypeFile), + file_type_(fo_type), + device_object_(dev_obj) { + ASSERT_IRQL_PASSIVE(); + ASSERT(NULL != dev_obj); + ASSERT(fo_type < AndroidUsbFileObjectTypeMax); + ASSERT(NULL != wdf_fo); + set_wdf_object(wdf_fo); +} + +#pragma code_seg() + +AndroidUsbFileObject::~AndroidUsbFileObject() { + ASSERT_IRQL_LOW_OR_DISPATCH(); +} + +#pragma code_seg("PAGE") + +NTSTATUS AndroidUsbFileObject::Initialize() { + ASSERT_IRQL_LOW(); + ASSERT(NULL != wdf_file()); + if (NULL == wdf_file()) + return STATUS_INTERNAL_ERROR; + + // Register context for this file object + return InitializeContext(); +} + +#pragma code_seg() + +void AndroidUsbFileObject::OnEvtIoRead(WDFREQUEST request, + size_t length) { + ASSERT_IRQL_LOW_OR_DISPATCH(); + ASSERT(WdfRequestGetFileObject(request) == wdf_file()); + // Complete zero reads with success + if (0 == length) { + WdfRequestCompleteWithInformation(request, STATUS_SUCCESS, 0); + return; + } + + WdfRequestComplete(request, STATUS_INVALID_DEVICE_REQUEST); +} + +void AndroidUsbFileObject::OnEvtIoWrite(WDFREQUEST request, + size_t length) { + ASSERT_IRQL_LOW_OR_DISPATCH(); + ASSERT(WdfRequestGetFileObject(request) == wdf_file()); + // Complete zero writes with success + if (0 == length) { + WdfRequestCompleteWithInformation(request, STATUS_SUCCESS, 0); + return; + } + + WdfRequestComplete(request, STATUS_INVALID_DEVICE_REQUEST); +} + +void AndroidUsbFileObject::OnEvtIoDeviceControl(WDFREQUEST request, + size_t output_buf_len, + size_t input_buf_len, + ULONG ioctl_code) { + ASSERT_IRQL_LOW_OR_DISPATCH(); + ASSERT(WdfRequestGetFileObject(request) == wdf_file()); + + WdfRequestComplete(request, STATUS_INVALID_DEVICE_REQUEST); +} + +#pragma data_seg() +#pragma code_seg() diff --git a/host/windows/usb/legacy/driver/android_usb_file_object.h b/host/windows/usb/legacy/driver/android_usb_file_object.h new file mode 100755 index 000000000..f84547828 --- /dev/null +++ b/host/windows/usb/legacy/driver/android_usb_file_object.h @@ -0,0 +1,184 @@ +/* + * 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. + */ + +#ifndef ANDROID_USB_FILE_OBJECT_H__ +#define ANDROID_USB_FILE_OBJECT_H__ +/** \file + This file consists of declaration of class AndroidUsbFileObject that + encapsulates a common extension for all KMDF file object types. +*/ + +#include "android_usb_wdf_object.h" +#include "android_usb_device_object.h" + +/** Enumerator AndroidUsbFileObjectType defines possible types for our file + object extension. +*/ +enum AndroidUsbFileObjectType { + /// File extends device FO + AndroidUsbFileObjectTypeDevice, + + // File extends a pipe FO + AndroidUsbFileObjectTypePipe, + + AndroidUsbFileObjectTypeMax, +}; + +/** AndroidUsbFileObject class encapsulates a common extension for all KMDF + file object types. Instances of this class must be allocated from + NonPagedPool. +*/ +class AndroidUsbFileObject : public AndroidUsbWdfObject { + public: + /** \brief Constructs the object. + + This method must be called at low IRQL. + @param fo_type[in] Type of the file object that this object extends + @param dev_obj[in] Our device object for which this file has been created + @param wdf_fo[in] KMDF file object for this extension + */ + AndroidUsbFileObject(AndroidUsbFileObjectType fo_type, + AndroidUsbDeviceObject* dev_obj, + WDFFILEOBJECT wdf_fo); + + /** \brief Destructs the object. + + This method can be called at any IRQL. + */ + virtual ~AndroidUsbFileObject(); + + /** \brief Initializes the object + + This method verifies that instance has been created and calls base class's + InitializeContext method to register itself with the wrapped FO. All + derived classes must call this method when initializing. + This method must be called at low IRQL. + @return STATUS_SUCCESS on success or an appropriate error code + */ + virtual NTSTATUS Initialize(); + + /** \brief Read event handler + + This method is called when a read request comes to the file object this + class extends. + This method can be called IRQL <= DISPATCH_LEVEL. + @param request[in] A handle to a framework request object. + @param length[in] The number of bytes to be read. + @return Successful status or an appropriate error code + */ + virtual void OnEvtIoRead(WDFREQUEST request, size_t length); + + /** \brief Write event handler + + This method is called when a write request comes to the file object this + class extends. + This callback can be called IRQL <= DISPATCH_LEVEL. + @param request[in] A handle to a framework request object. + @param length[in] The number of bytes to be written. + @return Successful status or an appropriate error code + */ + virtual void OnEvtIoWrite(WDFREQUEST request, size_t length); + + /** \brief IOCTL event handler + + This method is called when a device control request comes to the file + object this class extends. + This callback can be called IRQL <= DISPATCH_LEVEL. + @param request[in] A handle to a framework request object. + @param output_buf_len[in] The length, in bytes, of the request's output + buffer, if an output buffer is available. + @param input_buf_len[in] The length, in bytes, of the request's input + buffer, if an input buffer is available. + @param ioctl_code[in] The driver-defined or system-defined I/O control code + that is associated with the request. + @return Successful status or an appropriate error code + */ + virtual void OnEvtIoDeviceControl(WDFREQUEST request, + size_t output_buf_len, + size_t input_buf_len, + ULONG ioctl_code); + + public: + /// Gets KMDF file handle for this extension + __forceinline WDFFILEOBJECT wdf_file() const { + return reinterpret_cast(wdf_object()); + } + + /// Gets device object that owns this file + __forceinline AndroidUsbDeviceObject* device_object() const { + return device_object_; + } + + /// Gets type of the file object that this extension wraps + __forceinline AndroidUsbFileObjectType file_type() const { + return file_type_; + } + + /// Gets WDF device handle for device that owns this file + __forceinline WDFDEVICE wdf_device() const { + ASSERT(NULL != device_object()); + return (NULL != device_object()) ? device_object()->wdf_device() : + NULL; + } + + /// Gets target (PDO) device handle for the device that owns this file + __forceinline WDFUSBDEVICE wdf_target_device() const { + ASSERT(NULL != device_object()); + return (NULL != device_object()) ? device_object()->wdf_target_device() : + NULL; + } + + protected: + /// Device object that owns this file + AndroidUsbDeviceObject* device_object_; + + /// Type of the file object that this extension wraps + AndroidUsbFileObjectType file_type_; +}; + +/** \brief Gets file KMDF object extension for the given KMDF file object + + This method can be called at any IRQL + @param wdf_fo[in] KMDF file handle describing file object + @return Instance of AndroidUsbFileObject associated with this object or NULL + if association is not found. +*/ +__forceinline AndroidUsbFileObject* GetAndroidUsbFileObjectFromHandle( + WDFFILEOBJECT wdf_fo) { + AndroidUsbWdfObject* wdf_object_ext = + GetAndroidUsbWdfObjectFromHandle(wdf_fo); + ASSERT(NULL != wdf_object_ext); + if (NULL != wdf_object_ext) { + ASSERT(wdf_object_ext->Is(AndroidUsbWdfObjectTypeFile)); + if (wdf_object_ext->Is(AndroidUsbWdfObjectTypeFile)) + return reinterpret_cast(wdf_object_ext); + } + return NULL; +} + +/** \brief Gets file KMDF file object extension for the given request + + This method can be called at any IRQL + @param request[in] KMDF request object + @return Instance of AndroidUsbFileObject associated with this request or NULL + if association is not found. +*/ +__forceinline AndroidUsbFileObject* GetAndroidUsbFileObjectForRequest( + WDFREQUEST request) { + return GetAndroidUsbFileObjectFromHandle(WdfRequestGetFileObject(request)); +} + +#endif // ANDROID_USB_FILE_OBJECT_H__ diff --git a/host/windows/usb/legacy/driver/android_usb_inl.h b/host/windows/usb/legacy/driver/android_usb_inl.h new file mode 100755 index 000000000..d08ed182f --- /dev/null +++ b/host/windows/usb/legacy/driver/android_usb_inl.h @@ -0,0 +1,88 @@ +/* + * 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. + */ + +#ifndef ANDROID_USB_INL_H__ +#define ANDROID_USB_INL_H__ +/** \file + This file consists of inline routines for the driver. +*/ + +/// Gets control code out of the entire IOCTL code packet +__forceinline ULONG GetCtlCode(ULONG ioctl_code) { + return (ioctl_code >> 2) & 0x0FFF; +} + +/** \brief + Converts string length from number of wide characters into number of bytes. +*/ +__forceinline USHORT ByteLen(USHORT wchar_len) { + return static_cast(wchar_len * sizeof(WCHAR)); +} + +/** \brief Gets byte length of a zero-terminated string not including + zero terminator. Must be called at low IRQL. +*/ +__forceinline USHORT ByteLen(const WCHAR* str) { + ASSERT_IRQL_LOW(); + return (NULL != str) ? ByteLen(static_cast(wcslen(str))) : 0; +} + +/** \brief + Converts string length from number of bytes into number of wide characters. + Can be called at any IRQL. +*/ +__forceinline USHORT WcharLen(USHORT byte_len) { + return byte_len / sizeof(WCHAR); +} + +/** \brief Retrieves pointer out of the WDFMEMORY handle +*/ +__forceinline void* GetAddress(WDFMEMORY wdf_mem) { + ASSERT(NULL != wdf_mem); + return (NULL != wdf_mem) ? WdfMemoryGetBuffer(wdf_mem, NULL) : NULL; +} + +/** \brief Retrieves output memory address for WDFREQUEST + + @param request[in] A handle to KMDF request object + @param status[out] Receives status of the call. Can be NULL. +*/ +__forceinline void* OutAddress(WDFREQUEST request, NTSTATUS* status) { + ASSERT(NULL != request); + WDFMEMORY wdf_mem = NULL; + NTSTATUS stat = WdfRequestRetrieveOutputMemory(request, &wdf_mem); + ASSERT((NULL != wdf_mem) || (!NT_SUCCESS(stat))); + if (NULL != status) + *status = stat; + return NT_SUCCESS(stat) ? GetAddress(wdf_mem) : NULL; +} + +/** \brief Retrieves input memory address for WDFREQUEST + + @param request[in] A handle to KMDF request object + @param status[out] Receives status of the call. Can be NULL. +*/ +__forceinline void* InAddress(WDFREQUEST request, NTSTATUS* status) { + ASSERT(NULL != request); + WDFMEMORY wdf_mem = NULL; + NTSTATUS stat = WdfRequestRetrieveInputMemory(request, &wdf_mem); + ASSERT((NULL != wdf_mem) || (!NT_SUCCESS(stat))); + if (NULL != status) + *status = stat; + return NT_SUCCESS(stat) ? GetAddress(wdf_mem) : NULL; +} + +#endif // ANDROID_USB_INL_H__ diff --git a/host/windows/usb/legacy/driver/android_usb_interrupt_file_object.cpp b/host/windows/usb/legacy/driver/android_usb_interrupt_file_object.cpp new file mode 100755 index 000000000..32c88caf9 --- /dev/null +++ b/host/windows/usb/legacy/driver/android_usb_interrupt_file_object.cpp @@ -0,0 +1,53 @@ +/* + * 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 AndroidUsbInterruptPipeFileObject + that encapsulates extension to an interrupt pipe file objects. +*/ +#pragma data_seg() +#pragma code_seg() + +#include "precomp.h" +#include "android_usb_interrupt_file_object.h" + +#pragma data_seg() +#pragma code_seg("PAGE") + +AndroidUsbInterruptPipeFileObject::AndroidUsbInterruptPipeFileObject( + AndroidUsbDeviceObject* dev_obj, + WDFFILEOBJECT wdf_fo, + WDFUSBPIPE wdf_pipe_obj) + : AndroidUsbPipeFileObject(dev_obj, wdf_fo, wdf_pipe_obj) { + ASSERT_IRQL_PASSIVE(); + +#if DBG + WDF_USB_PIPE_INFORMATION pipe_info; + WDF_USB_PIPE_INFORMATION_INIT(&pipe_info); + WdfUsbTargetPipeGetInformation(wdf_pipe_obj, &pipe_info); + ASSERT(WdfUsbPipeTypeInterrupt == pipe_info.PipeType); +#endif // DBG + +} + +#pragma code_seg() + +AndroidUsbInterruptPipeFileObject::~AndroidUsbInterruptPipeFileObject() { + ASSERT_IRQL_LOW_OR_DISPATCH(); +} + +#pragma data_seg() +#pragma code_seg() diff --git a/host/windows/usb/legacy/driver/android_usb_interrupt_file_object.h b/host/windows/usb/legacy/driver/android_usb_interrupt_file_object.h new file mode 100755 index 000000000..7b2396903 --- /dev/null +++ b/host/windows/usb/legacy/driver/android_usb_interrupt_file_object.h @@ -0,0 +1,50 @@ +/* + * 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. + */ + +#ifndef ANDROID_USB_INTERRUPT_PIPE_FILE_OBJECT_H__ +#define ANDROID_USB_INTERRUPT_PIPE_FILE_OBJECT_H__ +/** \file + This file consists of declaration of class AndroidUsbInterruptPipeFileObject + that encapsulates extension to an interrupt pipe file objects. +*/ + +#include "android_usb_pipe_file_object.h" + +/** AndroidUsbInterruptPipeFileObject class encapsulates extension for a KMDF + file object that represent opened interrupt pipe. Instances of this class + must be allocated from NonPagedPool. +*/ +class AndroidUsbInterruptPipeFileObject : public AndroidUsbPipeFileObject { + public: + /** \brief Constructs the object. + + This method must be called at low IRQL. + @param dev_obj[in] Our device object for which this file has been created + @param wdf_fo[in] KMDF file object this extension wraps + @param wdf_pipe_obj[in] KMDF pipe for this file + */ + AndroidUsbInterruptPipeFileObject(AndroidUsbDeviceObject* dev_obj, + WDFFILEOBJECT wdf_fo, + WDFUSBPIPE wdf_pipe_obj); + + /** \brief Destructs the object. + + This method can be called at any IRQL. + */ + virtual ~AndroidUsbInterruptPipeFileObject(); +}; + +#endif // ANDROID_USB_INTERRUPT_PIPE_FILE_OBJECT_H__ diff --git a/host/windows/usb/legacy/driver/android_usb_new_delete.h b/host/windows/usb/legacy/driver/android_usb_new_delete.h new file mode 100755 index 000000000..d1ca03b53 --- /dev/null +++ b/host/windows/usb/legacy/driver/android_usb_new_delete.h @@ -0,0 +1,154 @@ +/* + * 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. + */ + +#ifndef ANDROID_USB_NEW_DELETE_H__ +#define ANDROID_USB_NEW_DELETE_H__ +/** \file + This file consists implementations of our 'new' and 'delete' operators +*/ + +#include "android_usb_pool_tags.h" + +/** \brief Checks if given pool type is one of NonPaged pool kinds. + + All numeric values for all NonPaged pool types are even numbers while all + numeric values for all PagedPool types are odd numbers (see definition of + POOL_TYPE enum). So this routine utilizes this to see whether given pool + type is one of NonPaged pool kinds. This routine can be called at any IRQL. + @param pool_type[in] Pool type + @return True if pool type is one of NonPaged pool types, false otherwise +*/ +__forceinline bool IsPoolNonPaged(POOL_TYPE pool_type) { + return (0 == (pool_type & 0x1)); +} + +/** @name Operators new and delete + + In Kernel Mode development each memory allocation must specify type of the + pool from which memory should be allocated, usualy PagedPool or NonPagedPool. + Because of that "traditional" operator 'new' that takes only one parameter + (memory size) is not good so we modify that operator by adding two more + parameters: pool type and memory tag (last one is optional but highly + encouraged). To prevent from mistakes, traditional operator 'new' is also + defined. It will allocate requested number of bytes from NonPagedPool with + default memory tag but it will always assert on checked (debug) builds. + Since there is no infrastructure for C++ exceptions in Kernel Mode we are + not using them to report memory allocation error. So, on failure operators + 'new' are returning NULL instead of throwing an exception. +*/ +///@{ + +/** \brief Main operator new + + This is the main operator new that allocates specified number of bytes from + the specified pool and assigns a custom tag to the allocated memory. + Inherits IRQL restrictions for ExAllocatePoolWithTag (see the DDK doc). + @param size[in] Number of bytes to allocate. + @param pool_type[in] Type of the pool to allocate from. + @param pool_tag[in] A tag to attach to the allocated memory. Since utilities + that display tags use their ASCII representations it's advisable to + use tag values that are ASCII symbols, f.i. 'ATag'. Note that due to + inversion of bytes in stored ULONG value, to read 'ATag' in the tag + displaying utility, the actual value passed to operator 'new' must be + 'gaTA' + @return Pointer to allocated memory on success, NULL on error. +*/ +__forceinline void* __cdecl operator new(size_t size, + POOL_TYPE pool_type, + ULONG pool_tag) { + ASSERT((pool_type < MaxPoolType) && (0 != size)); + // Enforce IRQL restriction check. + ASSERT(IsPoolNonPaged(pool_type) || (KeGetCurrentIrql() < DISPATCH_LEVEL)); + return size ? ExAllocatePoolWithTag(pool_type, + static_cast(size), + pool_tag) : + NULL; +} + +/** \brief + Short operator new that attaches a default tag to the allocated memory. + + This version of operator new allocates specified number of bytes from the + specified pool and assigns a default tag (GANDR_POOL_TAG_DEFAULT) to the + allocated memory. Inherits IRQL restrictions for ExAllocatePoolWithTag. + @param size[in] Number of bytes to allocate. + @param pool_type[in] Type of the pool to allocate from. + @return Pointer to allocated memory on success, NULL on error. +*/ +__forceinline void* __cdecl operator new(size_t size, POOL_TYPE pool_type) { + ASSERT((pool_type < MaxPoolType) && (0 != size)); + // Enforce IRQL restriction check. + ASSERT(IsPoolNonPaged(pool_type) || (KeGetCurrentIrql() < DISPATCH_LEVEL)); + return size ? ExAllocatePoolWithTag(pool_type, + static_cast(size), + GANDR_POOL_TAG_DEFAULT) : + NULL; +} + +/** \brief Traditional operator new that should never be used. + + Using of this version of operator 'new' is prohibited in Kernel Mode + development. For the sake of safety it is implemented though to allocate + requested number of bytes from the NonPagedPool and attach default tag + to the allocated memory. It will assert on checked (debug) builds. + Inherits IRQL restrictions for ExAllocatePoolWithTag. + @param size[in] Number of bytes to allocate. + @return Pointer to memory allocated from NonPagedPool on success or NULL on + error. +*/ +__forceinline void* __cdecl operator new(size_t size) { + ASSERTMSG("\n!!! Using of operator new(size_t size) is detected!\n" + "This is illegal in our driver C++ development environment to use " + "this version of operator 'new'. Please switch to\n" + "new(size_t size, POOL_TYPE pool_type) or " + "new(size_t size, POOL_TYPE pool_type, ULONG pool_tag) ASAP!!!\n", + false); + ASSERT(0 != size); + return size ? ExAllocatePoolWithTag(NonPagedPool, + static_cast(size), + GANDR_POOL_TAG_DEFAULT) : + NULL; +} + +/** \brief Operator delete. + + Frees memory allocated by 'new' operator. + @param pointer[in] Memory to free. If this parameter is NULL operator does + nothing but asserts on checked build. Inherits IRQL restrictions + for ExFreePool. +*/ +__forceinline void __cdecl operator delete(void* pointer) { + ASSERT(NULL != pointer); + if (NULL != pointer) + ExFreePool(pointer); +} + +/** \brief Operator delete for arrays. + + Frees memory allocated by 'new' operator. + @param pointer[in] Memory to free. If this parameter is NULL operator does + nothing but asserts on checked build. Inherits IRQL restrictions + for ExFreePool. +*/ +__forceinline void __cdecl operator delete[](void* pointer) { + ASSERT(NULL != pointer); + if (NULL != pointer) + ExFreePool(pointer); +} + +///@} + +#endif // ANDROID_USB_NEW_DELETE_H__ diff --git a/host/windows/usb/legacy/driver/android_usb_pipe_file_object.cpp b/host/windows/usb/legacy/driver/android_usb_pipe_file_object.cpp new file mode 100755 index 000000000..e696b37dd --- /dev/null +++ b/host/windows/usb/legacy/driver/android_usb_pipe_file_object.cpp @@ -0,0 +1,738 @@ +/* + * 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 AndroidUsbPipeFileObject that + encapsulates a common extension for pipe file objects. +*/ +#pragma data_seg() +#pragma code_seg() + +#include "precomp.h" +#include "android_usb_pipe_file_object.h" + +#pragma data_seg() +#pragma code_seg("PAGE") + +AndroidUsbPipeFileObject::AndroidUsbPipeFileObject( + AndroidUsbDeviceObject* dev_obj, + WDFFILEOBJECT wdf_fo, + WDFUSBPIPE wdf_pipe_obj) + : AndroidUsbFileObject(AndroidUsbFileObjectTypePipe, dev_obj, wdf_fo), + wdf_pipe_(wdf_pipe_obj) { + ASSERT_IRQL_PASSIVE(); + ASSERT(NULL != wdf_pipe_obj); +} + +#pragma code_seg() + +AndroidUsbPipeFileObject::~AndroidUsbPipeFileObject() { + ASSERT_IRQL_LOW_OR_DISPATCH(); +} + +#pragma code_seg("PAGE") + +NTSTATUS AndroidUsbPipeFileObject::InitializePipe( + const WDF_USB_PIPE_INFORMATION* pipe_info) { + ASSERT_IRQL_LOW(); + ASSERT(IsPipeAttached()); + if (!IsPipeAttached()) + return STATUS_INTERNAL_ERROR; + + // Initialize base class + NTSTATUS status = AndroidUsbFileObject::Initialize(); + ASSERT(NT_SUCCESS(status)); + if (!NT_SUCCESS(status)) + return status; + + // Save pipe information + pipe_information_ = *pipe_info; + + // We will provide size check ourselves (less surprizes always better) + WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(wdf_pipe()); + + GoogleDbgPrint("\n===== File %p for %s pipe. max_transfer_size = %X, max_packet_size = %X", + this, is_input_pipe() ? "read" : "write", + max_transfer_size(), max_packet_size()); + return STATUS_SUCCESS; +} + +#pragma code_seg() + +void AndroidUsbPipeFileObject::OnEvtIoRead(WDFREQUEST request, + size_t length) { + ASSERT_IRQL_LOW_OR_DISPATCH(); + + // Make sure that this is an input pipe + if (is_output_pipe()) { + GoogleDbgPrint("\n!!!! Attempt to read from output pipe %p", this); + WdfRequestComplete(request, STATUS_ACCESS_DENIED); + return; + } + + // Make sure zero length I/O doesn't go through + if (0 == length) { + WdfRequestCompleteWithInformation(request, STATUS_SUCCESS, 0); + return; + } + + // Get MDL for this request. + PMDL request_mdl = NULL; + NTSTATUS status = WdfRequestRetrieveOutputWdmMdl(request, &request_mdl); + ASSERT(NT_SUCCESS(status) && (NULL != request_mdl)); + if (NT_SUCCESS(status)) { + CommonBulkReadWrite(request, + request_mdl, + static_cast(length), + true, + 0, + false); + } else { + WdfRequestComplete(request, status); + } +} + +void AndroidUsbPipeFileObject::OnEvtIoWrite(WDFREQUEST request, + size_t length) { + + // Make sure that this is an output pipe + if (is_input_pipe()) { + GoogleDbgPrint("\n!!!! Attempt to write to input pipe %p", this); + WdfRequestComplete(request, STATUS_ACCESS_DENIED); + return; + } + + // Make sure zero length I/O doesn't go through + if (0 == length) { + WdfRequestCompleteWithInformation(request, STATUS_SUCCESS, 0); + return; + } + + // Get MDL for this request. + PMDL request_mdl = NULL; + NTSTATUS status = WdfRequestRetrieveInputWdmMdl(request, &request_mdl); + ASSERT(NT_SUCCESS(status) && (NULL != request_mdl)); + if (NT_SUCCESS(status)) { + CommonBulkReadWrite(request, + request_mdl, + static_cast(length), + false, + 0, + false); + } else { + WdfRequestComplete(request, status); + } +} + +void AndroidUsbPipeFileObject::OnEvtIoDeviceControl(WDFREQUEST request, + size_t output_buf_len, + size_t input_buf_len, + ULONG ioctl_code) { + ASSERT_IRQL_LOW_OR_DISPATCH(); + + switch (ioctl_code) { + case ADB_IOCTL_GET_ENDPOINT_INFORMATION: + OnCtlGetEndpointInformation(request, output_buf_len); + break; + + case ADB_IOCTL_BULK_READ: + OnCtlBulkRead(request, output_buf_len, input_buf_len); + break; + + case ADB_IOCTL_BULK_WRITE: + OnCtlBulkWrite(request, output_buf_len, input_buf_len); + break; + + default: + AndroidUsbFileObject::OnEvtIoDeviceControl(request, + output_buf_len, + input_buf_len, + ioctl_code); + break; + } +} + +void AndroidUsbPipeFileObject::OnCtlGetEndpointInformation( + WDFREQUEST request, + size_t output_buf_len) { + ASSERT_IRQL_LOW_OR_DISPATCH(); + + // Verify output buffer + 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(OutAddress(request, &status)); + ASSERT(NT_SUCCESS(status) && (NULL != ret_info)); + if (!NT_SUCCESS(status)) { + WdfRequestComplete(request, status); + return; + } + + // Copy endpoint info to the output + ret_info->max_packet_size = pipe_information_.MaximumPacketSize; + ret_info->endpoint_address = pipe_information_.EndpointAddress; + ret_info->polling_interval = pipe_information_.Interval; + ret_info->setting_index = pipe_information_.SettingIndex; + ret_info->endpoint_type = + static_cast(pipe_information_.PipeType); + ret_info->max_transfer_size = pipe_information_.MaximumTransferSize; + + WdfRequestCompleteWithInformation(request, + STATUS_SUCCESS, + sizeof(AdbEndpointInformation)); +} + +void AndroidUsbPipeFileObject::OnCtlBulkRead(WDFREQUEST request, + size_t output_buf_len, + size_t input_buf_len) { + ASSERT_IRQL_LOW_OR_DISPATCH(); + + // Make sure that this is an input pipe + if (is_output_pipe()) { + GoogleDbgPrint("\n!!!! Attempt to IOCTL read from output pipe %p", this); + WdfRequestComplete(request, STATUS_ACCESS_DENIED); + return; + } + + // Make sure zero length I/O doesn't go through + if (0 == output_buf_len) { + WdfRequestCompleteWithInformation(request, STATUS_SUCCESS, 0); + return; + } + + // Verify buffers + ASSERT(input_buf_len >= sizeof(AdbBulkTransfer)); + if (input_buf_len < sizeof(AdbBulkTransfer)) { + WdfRequestComplete(request, STATUS_INVALID_BUFFER_SIZE); + return; + } + + // Get the input buffer + NTSTATUS status; + AdbBulkTransfer* transfer_param = + reinterpret_cast(InAddress(request, &status)); + ASSERT(NT_SUCCESS(status) && (NULL != transfer_param)); + if (!NT_SUCCESS(status)) { + WdfRequestComplete(request, status); + return; + } + + // Get MDL for this request. + PMDL request_mdl = NULL; + status = WdfRequestRetrieveOutputWdmMdl(request, &request_mdl); + ASSERT(NT_SUCCESS(status) && (NULL != request_mdl)); + if (NT_SUCCESS(status)) { + // Perform the read + CommonBulkReadWrite(request, + request_mdl, + static_cast(output_buf_len), + true, + transfer_param->time_out, + true); + } else { + WdfRequestComplete(request, status); + } +} + +void AndroidUsbPipeFileObject::OnCtlBulkWrite(WDFREQUEST request, + size_t output_buf_len, + size_t input_buf_len) { + ASSERT_IRQL_LOW_OR_DISPATCH(); + + // Make sure that this is an output pipe + if (is_input_pipe()) { + GoogleDbgPrint("\n!!!! Attempt to IOCTL write to input pipe %p", this); + WdfRequestComplete(request, STATUS_ACCESS_DENIED); + return; + } + + // Verify buffers + ASSERT(input_buf_len >= sizeof(AdbBulkTransfer)); + // Output buffer points to ULONG that receives number of transferred bytes + ASSERT(output_buf_len >= sizeof(ULONG)); + if ((input_buf_len < sizeof(AdbBulkTransfer)) || + (output_buf_len < sizeof(ULONG))) { + WdfRequestComplete(request, STATUS_INVALID_BUFFER_SIZE); + return; + } + + // Get the input buffer + NTSTATUS status = STATUS_SUCCESS; + AdbBulkTransfer* transfer_param = + reinterpret_cast(InAddress(request, &status)); + ASSERT(NT_SUCCESS(status) && (NULL != transfer_param)); + if (!NT_SUCCESS(status)) { + WdfRequestComplete(request, status); + return; + } + + // Get the output buffer + ULONG* ret_transfer = + reinterpret_cast(OutAddress(request, &status)); + ASSERT(NT_SUCCESS(status) && (NULL != ret_transfer)); + if (!NT_SUCCESS(status)) { + WdfRequestComplete(request, status); + return; + } + + // Cache these param to prevent us from sudden change after we've chacked it. + // This is common practice in protecting ourselves from malicious code: + // 1. Never trust anything that comes from the User Mode. + // 2. Never assume that anything that User Mode buffer has will remain + // unchanged. + void* transfer_buffer = transfer_param->GetWriteBuffer(); + ULONG transfer_size = transfer_param->transfer_size; + + // Make sure zero length I/O doesn't go through + if (0 == transfer_size) { + *ret_transfer = 0; + WdfRequestCompleteWithInformation(request, STATUS_SUCCESS, sizeof(ULONG)); + return; + } + + // Make sure that buffer is not NULL + ASSERT(NULL != transfer_buffer); + if (NULL == transfer_buffer) { + WdfRequestComplete(request, STATUS_INVALID_PARAMETER); + return; + } + + // At this point we are ready to build MDL for the user buffer. + PMDL write_mdl = + IoAllocateMdl(transfer_buffer, transfer_size, FALSE, FALSE, NULL); + ASSERT(NULL != write_mdl); + if (NULL == write_mdl) { + WdfRequestComplete(request, STATUS_INSUFFICIENT_RESOURCES); + return; + } + + // Now we need to probe/lock this mdl + __try { + MmProbeAndLockPages(write_mdl, + WdfRequestGetRequestorMode(request), + IoReadAccess); + status = STATUS_SUCCESS; + } __except (EXCEPTION_EXECUTE_HANDLER) { + status = GetExceptionCode(); + ASSERTMSG("\n!!!!! AndroidUsbPipeFileObject::OnCtlBulkWrite exception", + false); + } + + if (!NT_SUCCESS(status)) { + IoFreeMdl(write_mdl); + WdfRequestComplete(request, status); + return; + } + + // Perform the write + status = CommonBulkReadWrite(request, + write_mdl, + transfer_size, + false, + transfer_param->time_out, + true); + if (!NT_SUCCESS(status)) { + // If CommonBulkReadWrite failed we need to unlock and free MDL here + MmUnlockPages(write_mdl); + IoFreeMdl(write_mdl); + } +} + +NTSTATUS AndroidUsbPipeFileObject::CommonBulkReadWrite( + WDFREQUEST request, + PMDL transfer_mdl, + ULONG length, + bool is_read, + ULONG time_out, + bool is_ioctl) { + ASSERT_IRQL_LOW_OR_DISPATCH(); + + ASSERT(IsPipeAttached()); + if (!IsPipeAttached()) { + WdfRequestComplete(request, STATUS_INVALID_DEVICE_STATE); + return STATUS_INVALID_DEVICE_STATE; + } + + // Quick access check. Might be redundant though... + ASSERT((is_read && is_input_pipe()) || (!is_read && is_output_pipe())); + if ((is_read && is_output_pipe()) || (!is_read && is_input_pipe())) { + WdfRequestComplete(request, STATUS_ACCESS_DENIED); + return STATUS_ACCESS_DENIED; + } + + // Set URB flags + ULONG urb_flags = USBD_SHORT_TRANSFER_OK | (is_read ? + USBD_TRANSFER_DIRECTION_IN : + USBD_TRANSFER_DIRECTION_OUT); + + // Calculate transfer length for this stage. + ULONG stage_len = + (length > GetTransferGranularity()) ? GetTransferGranularity() : length; + + // Get virtual address that we're gonna use in the transfer. + // We rely here on the fact that we're in the context of the calling thread. + void* virtual_address = MmGetMdlVirtualAddress(transfer_mdl); + + // Allocate our private MDL for this address which we will use for the transfer + PMDL new_mdl = IoAllocateMdl(virtual_address, length, FALSE, FALSE, NULL); + ASSERT(NULL != new_mdl); + if (NULL == new_mdl) { + WdfRequestComplete(request, STATUS_INSUFFICIENT_RESOURCES); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // Map the portion of user buffer that we're going to transfer at this stage + // to our mdl. + IoBuildPartialMdl(transfer_mdl, new_mdl, virtual_address, stage_len); + + // Allocate memory for URB and associate it with this request + WDF_OBJECT_ATTRIBUTES mem_attrib; + WDF_OBJECT_ATTRIBUTES_INIT(&mem_attrib); + mem_attrib.ParentObject = request; + + WDFMEMORY urb_mem = NULL; + PURB urb = NULL; + NTSTATUS status = + WdfMemoryCreate(&mem_attrib, + NonPagedPool, + GANDR_POOL_TAG_BULKRW_URB, + sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), + &urb_mem, + reinterpret_cast(&urb)); + ASSERT(NT_SUCCESS(status) && (NULL != urb)); + if (!NT_SUCCESS(status)) { + IoFreeMdl(new_mdl); + WdfRequestComplete(request, STATUS_INSUFFICIENT_RESOURCES); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // Get USB pipe handle for our pipe and initialize transfer request for it + USBD_PIPE_HANDLE usbd_pipe_hndl = usbd_pipe(); + ASSERT(NULL != usbd_pipe_hndl); + if (NULL == usbd_pipe_hndl) { + IoFreeMdl(new_mdl); + WdfRequestComplete(request, STATUS_INTERNAL_ERROR); + return STATUS_INTERNAL_ERROR; + } + + // Initialize URB with request information + UsbBuildInterruptOrBulkTransferRequest( + urb, + sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), + usbd_pipe_hndl, + NULL, + new_mdl, + stage_len, + urb_flags, + NULL); + + // Build transfer request + status = WdfUsbTargetPipeFormatRequestForUrb(wdf_pipe(), + request, + urb_mem, + NULL); + ASSERT(NT_SUCCESS(status)); + if (!NT_SUCCESS(status)) { + IoFreeMdl(new_mdl); + WdfRequestComplete(request, status); + return status; + } + + // Initialize our request context. + AndroidUsbWdfRequestContext* context = + GetAndroidUsbWdfRequestContext(request); + ASSERT(NULL != context); + if (NULL == context) { + IoFreeMdl(new_mdl); + WdfRequestComplete(request, STATUS_INTERNAL_ERROR); + return STATUS_INTERNAL_ERROR; + } + + context->object_type = AndroidUsbWdfObjectTypeRequest; + context->urb_mem = urb_mem; + context->transfer_mdl = transfer_mdl; + context->mdl = new_mdl; + context->length = length; + context->transfer_size = stage_len; + context->num_xfer = 0; + context->virtual_address = virtual_address; + context->is_read = is_read; + context->initial_time_out = time_out; + context->is_ioctl = is_ioctl; + + // Set our completion routine + WdfRequestSetCompletionRoutine(request, + CommonReadWriteCompletionEntry, + this); + + // Init send options (our timeout goes here) + WDF_REQUEST_SEND_OPTIONS send_options; + if (0 != time_out) { + WDF_REQUEST_SEND_OPTIONS_INIT(&send_options, WDF_REQUEST_SEND_OPTION_TIMEOUT); + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&send_options, WDF_REL_TIMEOUT_IN_MS(time_out)); + } + + // Timestamp first WdfRequestSend + KeQuerySystemTime(&context->sent_at); + + // Send request asynchronously. + if (WdfRequestSend(request, wdf_pipe_io_target(), + (0 == time_out) ? WDF_NO_SEND_OPTIONS : &send_options)) { + return STATUS_SUCCESS; + } + + // Something went wrong here + status = WdfRequestGetStatus(request); + ASSERT(!NT_SUCCESS(status)); + GoogleDbgPrint("\n!!!!! CommonBulkReadWrite: WdfRequestGetStatus (is_read = %u) failed: %08X", + is_read, status); + WdfRequestCompleteWithInformation(request, status, 0); + + return status; +} + +void AndroidUsbPipeFileObject::OnCommonReadWriteCompletion( + WDFREQUEST request, + PWDF_REQUEST_COMPLETION_PARAMS completion_params, + AndroidUsbWdfRequestContext* context) { + ASSERT_IRQL_LOW_OR_DISPATCH(); + + NTSTATUS status = completion_params->IoStatus.Status; + if (!NT_SUCCESS(status)){ + GoogleDbgPrint("\n========== Request completed with failure: %X", status); + IoFreeMdl(context->mdl); + // If this was IOCTL-originated write we must unlock and free + // our transfer MDL. + if (context->is_ioctl && !context->is_read) { + MmUnlockPages(context->transfer_mdl); + IoFreeMdl(context->transfer_mdl); + } + WdfRequestComplete(request, status); + return; + } + + // Get our URB buffer + PURB urb + = reinterpret_cast(WdfMemoryGetBuffer(context->urb_mem, NULL)); + ASSERT(NULL != urb); + + // Lets see how much has been transfered and update our counters accordingly + ULONG bytes_transfered = + urb->UrbBulkOrInterruptTransfer.TransferBufferLength; + // We expect writes to transfer entire packet + ASSERT((bytes_transfered == context->transfer_size) || context->is_read); + context->num_xfer += bytes_transfered; + context->length -= bytes_transfered; + + // Is there anything left to transfer? Now, by the protocol we should + // successfuly complete partial reads, instead of waiting on full set + // of requested bytes being accumulated in the read buffer. + if ((0 == context->length) || context->is_read) { + status = STATUS_SUCCESS; + + // This was the last transfer + if (context->is_ioctl && !context->is_read) { + // For IOCTL-originated writes we have to return transfer size through + // the IOCTL's output buffer. + ULONG* ret_transfer = + reinterpret_cast(OutAddress(request, NULL)); + ASSERT(NULL != ret_transfer); + if (NULL != ret_transfer) + *ret_transfer = context->num_xfer; + WdfRequestSetInformation(request, sizeof(ULONG)); + + // We also must unlock / free transfer MDL + MmUnlockPages(context->transfer_mdl); + IoFreeMdl(context->transfer_mdl); + } else { + // For other requests we report transfer size through the request I/O + // completion status. + WdfRequestSetInformation(request, context->num_xfer); + } + IoFreeMdl(context->mdl); + WdfRequestComplete(request, status); + return; + } + + // There are something left for the transfer. Prepare for it. + // Required to free any mapping made on the partial MDL and + // reset internal MDL state. + MmPrepareMdlForReuse(context->mdl); + + // Update our virtual address + context->virtual_address = + reinterpret_cast(context->virtual_address) + bytes_transfered; + + // Calculate size of this transfer + ULONG stage_len = + (context->length > GetTransferGranularity()) ? GetTransferGranularity() : + context->length; + + IoBuildPartialMdl(context->transfer_mdl, + context->mdl, + context->virtual_address, + stage_len); + + // Reinitialize the urb and context + urb->UrbBulkOrInterruptTransfer.TransferBufferLength = stage_len; + context->transfer_size = stage_len; + + // Format the request to send a URB to a USB pipe. + status = WdfUsbTargetPipeFormatRequestForUrb(wdf_pipe(), + request, + context->urb_mem, + NULL); + ASSERT(NT_SUCCESS(status)); + if (!NT_SUCCESS(status)) { + if (context->is_ioctl && !context->is_read) { + MmUnlockPages(context->transfer_mdl); + IoFreeMdl(context->transfer_mdl); + } + IoFreeMdl(context->mdl); + WdfRequestComplete(request, status); + return; + } + + // Reset the completion routine + WdfRequestSetCompletionRoutine(request, + CommonReadWriteCompletionEntry, + this); + + // Send the request asynchronously. + if (!WdfRequestSend(request, wdf_pipe_io_target(), WDF_NO_SEND_OPTIONS)) { + if (context->is_ioctl && !context->is_read) { + MmUnlockPages(context->transfer_mdl); + IoFreeMdl(context->transfer_mdl); + } + status = WdfRequestGetStatus(request); + IoFreeMdl(context->mdl); + WdfRequestComplete(request, status); + } +} + +NTSTATUS AndroidUsbPipeFileObject::ResetPipe() { + ASSERT_IRQL_PASSIVE(); + + // This routine synchronously submits a URB_FUNCTION_RESET_PIPE + // request down the stack. + NTSTATUS status = WdfUsbTargetPipeAbortSynchronously(wdf_pipe(), + WDF_NO_HANDLE, + NULL); + if (NT_SUCCESS(status)) { + status = WdfUsbTargetPipeResetSynchronously(wdf_pipe(), + WDF_NO_HANDLE, + NULL); + if (!NT_SUCCESS(status)) + GoogleDbgPrint("\n!!!!! AndroidUsbPipeFileObject::ResetPipe failed %X", status); + } else { + GoogleDbgPrint("\n!!!!! WdfUsbTargetPipeAbortSynchronously failed %X", status); + } + + return status; +} + +NTSTATUS AndroidUsbPipeFileObject::QueueResetPipePassiveCallback() { + ASSERT_IRQL_LOW_OR_DISPATCH(); + + // Initialize workitem + WDF_OBJECT_ATTRIBUTES attr; + WDF_OBJECT_ATTRIBUTES_INIT(&attr); + WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&attr, AndroidUsbWorkitemContext); + attr.ParentObject = wdf_device(); + + WDFWORKITEM wdf_work_item = NULL; + WDF_WORKITEM_CONFIG workitem_config; + WDF_WORKITEM_CONFIG_INIT(&workitem_config, ResetPipePassiveCallbackEntry); + NTSTATUS status = WdfWorkItemCreate(&workitem_config, + &attr, + &wdf_work_item); + ASSERT(NT_SUCCESS(status) && (NULL != wdf_work_item)); + if (!NT_SUCCESS(status)) + return status; + + // Initialize our extension to work item + AndroidUsbWorkitemContext* context = + GetAndroidUsbWorkitemContext(wdf_work_item); + ASSERT(NULL != context); + if (NULL == context) { + WdfObjectDelete(wdf_work_item); + return STATUS_INTERNAL_ERROR; + } + + context->object_type = AndroidUsbWdfObjectTypeWorkitem; + context->pipe_file_ext = this; + + // Enqueue this work item. + WdfWorkItemEnqueue(wdf_work_item); + + return STATUS_SUCCESS; +} + +void AndroidUsbPipeFileObject::CommonReadWriteCompletionEntry( + WDFREQUEST request, + WDFIOTARGET wdf_target, + PWDF_REQUEST_COMPLETION_PARAMS completion_params, + WDFCONTEXT completion_context) { + ASSERT_IRQL_LOW_OR_DISPATCH(); + + AndroidUsbWdfRequestContext* + context = GetAndroidUsbWdfRequestContext(request); + ASSERT((NULL != context) && (AndroidUsbWdfObjectTypeRequest == context->object_type)); + + AndroidUsbPipeFileObject* pipe_file_ext = + reinterpret_cast(completion_context); + ASSERT((NULL != pipe_file_ext) && + (pipe_file_ext->wdf_pipe() == (WDFUSBPIPE)wdf_target)); + + pipe_file_ext->OnCommonReadWriteCompletion(request, + completion_params, + context); +} + +void AndroidUsbPipeFileObject::ResetPipePassiveCallbackEntry( + WDFWORKITEM wdf_work_item) { + ASSERT_IRQL_PASSIVE(); + + AndroidUsbWorkitemContext* context = + GetAndroidUsbWorkitemContext(wdf_work_item); + ASSERT((NULL != context) && + (AndroidUsbWdfObjectTypeWorkitem == context->object_type)); + if ((NULL == context) || + (AndroidUsbWdfObjectTypeWorkitem != context->object_type)) { + WdfObjectDelete(wdf_work_item); + return; + } + + // In the sample they reset the device if pipe reset failed + AndroidUsbDeviceObject* wdf_device_ext = + context->pipe_file_ext->device_object(); + + NTSTATUS status = context->pipe_file_ext->ResetPipe(); + if (!NT_SUCCESS(status)) + status = wdf_device_ext->ResetDevice(); + + WdfObjectDelete(wdf_work_item); +} + +#pragma data_seg() +#pragma code_seg() diff --git a/host/windows/usb/legacy/driver/android_usb_pipe_file_object.h b/host/windows/usb/legacy/driver/android_usb_pipe_file_object.h new file mode 100755 index 000000000..ce02d2518 --- /dev/null +++ b/host/windows/usb/legacy/driver/android_usb_pipe_file_object.h @@ -0,0 +1,305 @@ +/* + * 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. + */ + +#ifndef ANDROID_USB_PIPE_FILE_OBJECT_H__ +#define ANDROID_USB_PIPE_FILE_OBJECT_H__ +/** \file + This file consists of declaration of class AndroidUsbPipeFileObject that + encapsulates a common extension for pipe file objects. +*/ + +#include "android_usb_file_object.h" + +/** AndroidUsbPipeFileObject class encapsulates extension for a KMDF file + object that represents opened pipe. Instances of this class must be + allocated from NonPagedPool. +*/ +class AndroidUsbPipeFileObject : public AndroidUsbFileObject { + public: + /** \brief Constructs the object. + + This method must be called at low IRQL. + @param dev_obj[in] Our device object for which this file has been created + @param wdf_fo[in] KMDF file object this extension wraps + @param wdf_pipe_obj[in] KMDF pipe for this file + */ + AndroidUsbPipeFileObject(AndroidUsbDeviceObject* dev_obj, + WDFFILEOBJECT wdf_fo, + WDFUSBPIPE wdf_pipe_obj); + + /** \brief Destructs the object. + + This method can be called at any IRQL. + */ + virtual ~AndroidUsbPipeFileObject(); + + /** \brief Initializes the pipe file object extension + + This method internally calls AndroidUsbFileObject::Initialize() + This method must be called at low IRQL + @param pipe_info[in] Pipe information + @return STATUS_SUCCESS or an appropriate error code + */ + virtual NTSTATUS InitializePipe(const WDF_USB_PIPE_INFORMATION* pipe_info); + + /** \brief Read event handler + + This method is called when a read request comes to the file object this + extension wraps. This method is an override. + This method can be called IRQL <= DISPATCH_LEVEL. + @param request[in] A handle to a framework request object. + @param length[in] The number of bytes to be read. + @return Successful status or an appropriate error code + */ + virtual void OnEvtIoRead(WDFREQUEST request, size_t length); + + /** \brief Write event handler + + This method is called when a write request comes to the file object this + extension wraps. This method is an override. + This method can be called IRQL <= DISPATCH_LEVEL. + @param request[in] A handle to a framework request object. + @param length[in] The number of bytes to be written. + @return Successful status or an appropriate error code + */ + virtual void OnEvtIoWrite(WDFREQUEST request, size_t length); + + /** \brief IOCTL event handler + + This method is called when a device control request comes to the file + object this extension wraps. We hanlde the following IOCTLs here: + 1. ADB_CTL_GET_ENDPOINT_INFORMATION + 2. ADB_CTL_BULK_READ + 3. ADB_CTL_BULK_WRITE + This method can be called IRQL <= DISPATCH_LEVEL. + @param request[in] A handle to a framework request object. + @param output_buf_len[in] The length, in bytes, of the request's output + buffer, if an output buffer is available. + @param input_buf_len[in] The length, in bytes, of the request's input + buffer, if an input buffer is available. + @param ioctl_code[in] The driver-defined or system-defined I/O control code + that is associated with the request. + @return Successful status or an appropriate error code + */ + virtual void OnEvtIoDeviceControl(WDFREQUEST request, + size_t output_buf_len, + size_t input_buf_len, + ULONG ioctl_code); + + protected: + /** \brief Handler for ADB_CTL_GET_ENDPOINT_INFORMATION IOCTL request + + @param request[in] A handle to a framework request object. + @param output_buf_len[in] The length, in bytes, of the request's output + buffer, if an output buffer is available. + */ + virtual void OnCtlGetEndpointInformation(WDFREQUEST request, + size_t output_buf_len); + + /** \brief Handler for ADB_CTL_BULK_READ IOCTL request + + @param request[in] A handle to a framework request object. + @param output_buf_len[in] The length, in bytes, of the request's output + buffer, if an output buffer is available. + @param input_buf_len[in] The length, in bytes, of the request's input + buffer, if an input buffer is available. + */ + virtual void OnCtlBulkRead(WDFREQUEST request, + size_t output_buf_len, + size_t input_buf_len); + + /** \brief Handler for ADB_CTL_BULK_WRITE IOCTL request + + @param request[in] A handle to a framework request object. + @param output_buf_len[in] The length, in bytes, of the request's output + buffer, if an output buffer is available. + @param input_buf_len[in] The length, in bytes, of the request's input + buffer, if an input buffer is available. + */ + virtual void OnCtlBulkWrite(WDFREQUEST request, + size_t output_buf_len, + size_t input_buf_len); + + /** \brief Performs common bulk read / write on the pipe + + This method is called from bulk and interrupt pipe file extensions to + perform read to / write from the pipe this file represents. Typicaly, + this method is called from OnEvtIoRead / OnEvtIoWrite / + OnEvtIoDeviceControl methods. One very special case for this method is + IOCTL-originated write request. If this is IOCTL-originated write request + we can't report transfer size through the request's status block. Instead, + for IOCTL-originated writes, the output buffer must a) exist and b) point + to an ULONG that will receive size of the transfer. Besides, for this type + of writes we create / lock write buffer MDL ourselves so we need to unlock + and free it in the completion routine. + This method can be called at IRQL <= DISPATCH_LEVEL. + @param request[in] A handle to a framework request object. + @param transfer_mdl[in] MDL for the transferring buffer. The MDL must be + locked prior to this call. + @param length[in] The number of bytes to be read / written. If this method + is actually IOCTL originated write request this parameter must be + taken from AdbBulkTransfer.transfer_size by the caller of this + method. AdbBulkTransfer is available at the beginning of the input + buffer for bulk read / write IOCTLs. + @param is_read[in] If true this is a read operation, otherwise it's write + operation. + @param time_out[in] Number of milliseconds for this request to complete. + If this parameter is zero there will be no timeout associated with + the request. Otherwise, if request doesn't complete within the given + timeframe it will be cancelled. + @param is_ioctl[in] If 'true' this method has been called from IOCTL + handler. Otherwise it has been called from read / write handler. If + this is IOCTL-originated write request we need to report bytes + transferred through the IOCTL's output buffer. + This method can be called IRQL <= DISPATCH_LEVEL. + @return STATUS_SUCCESS or an appropriate error code + */ + virtual NTSTATUS CommonBulkReadWrite(WDFREQUEST request, + PMDL transfer_mdl, + ULONG length, + bool is_read, + ULONG time_out, + bool is_ioctl); + + /** \brief Handles request completion for CommonBulkReadWrite + + This method is called from CommonReadWriteCompletionEntry. + This method can be called at IRQL <= DISPATCH_LEVEL. + @param request[in] A handle to a framework request object that is being + completed. + @param params[in] A pointer to a WDF_REQUEST_COMPLETION_PARAMS structure + that contains information about the completed request. + @param context[in] Context associated with this request in + CommonBulkReadWrite + This method can be called IRQL <= DISPATCH_LEVEL. + */ + virtual void OnCommonReadWriteCompletion(WDFREQUEST request, + PWDF_REQUEST_COMPLETION_PARAMS completion_params, + AndroidUsbWdfRequestContext* context); + + /** \brief Resets pipe associated with this file + + After reseting the pipe this object might be destroyed. + This method must be called at PASSIVE IRQL. + @param read_device_on_failure[in] If true and reset pipe has failed this + method will attempt to reset the device. + @return STATUS_SUCCESS on success or an appropriate error code + */ + virtual NTSTATUS ResetPipe(); + + /** \brief Queues a workitem to launch pipe reset at PASSIVE IRQL + + This method can be called at IRQL <= DISPATCH_LEVEL. + @return STATUS_SUCCESS or an appropriate error code. + */ + virtual NTSTATUS QueueResetPipePassiveCallback(); + + private: + /** \brief Request completion routine for CommonBulkReadWrite + + This method can be called at IRQL <= DISPATCH_LEVEL. + @param request[in] A handle to a framework request object that is being + completed. + @param wdf_target[in] A handle to an I/O target object that represents the + I/O target that completed the request. In this case this is a pipe. + @param params[in] A pointer to a WDF_REQUEST_COMPLETION_PARAMS structure + that contains information about the completed request. + @param completion_context[in] A handle to driver-supplied context + information, which the driver specified in a previous call to + WdfRequestSetCompletionRoutine. In our case this is a pointer + to this class instance that issued the request. + This method can be called IRQL <= DISPATCH_LEVEL. + */ + static void CommonReadWriteCompletionEntry(WDFREQUEST request, + WDFIOTARGET wdf_target, + PWDF_REQUEST_COMPLETION_PARAMS params, + WDFCONTEXT completion_context); + + /** \brief Entry point for pipe reset workitem callback + + This method is called at PASSIVE IRQL + @param wdf_work_item[in] A handle to a framework work item object. + */ + static void ResetPipePassiveCallbackEntry(WDFWORKITEM wdf_work_item); + + public: + /// Gets KMDF pipe handle for this file + __forceinline WDFUSBPIPE wdf_pipe() const { + return wdf_pipe_; + } + + /// Gets maximum transfer size for this pipe + __forceinline ULONG max_transfer_size() const { + ASSERT(0 != pipe_information_.MaximumTransferSize); + return pipe_information_.MaximumTransferSize; + } + + /// Gets maximum packet size this pipe is capable of + __forceinline ULONG max_packet_size() const { + ASSERT(0 != pipe_information_.MaximumPacketSize); + return pipe_information_.MaximumPacketSize; + } + + /// Gets transfer granularity + // TODO: It looks like device USB is capable of handling + // packets with size greater than pipe_information_.MaximumPacketSize! + // So, looks like we are not bound by this parameter in this driver. + __forceinline ULONG GetTransferGranularity() const { + return max_transfer_size(); + } + + /// Checks if this is an input pipe + __forceinline bool is_input_pipe() const { + return WDF_USB_PIPE_DIRECTION_IN(pipe_information_.EndpointAddress) ? + true : false; + } + + /// Checks if this is an output pipe + __forceinline bool is_output_pipe() const { + return WDF_USB_PIPE_DIRECTION_OUT(pipe_information_.EndpointAddress) ? + true : false; + } + + /// Checks if pipe is attached to this file + __forceinline bool IsPipeAttached() const { + return (NULL != wdf_pipe()); + } + + /// Gets USBD pipe handle + // TODO: Can we cache this? + __forceinline USBD_PIPE_HANDLE usbd_pipe() const { + ASSERT(IsPipeAttached()); + return (IsPipeAttached()) ? WdfUsbTargetPipeWdmGetPipeHandle(wdf_pipe()) : + NULL; + } + + /// Gets I/O target handle for this pipe + // TODO: Can we cache this? + __forceinline WDFIOTARGET wdf_pipe_io_target() const { + ASSERT(IsPipeAttached()); + return (IsPipeAttached()) ? WdfUsbTargetPipeGetIoTarget(wdf_pipe()) : + NULL; + } + + protected: + /// Cached pipe information + WDF_USB_PIPE_INFORMATION pipe_information_; + + /// KMDF pipe handle for this file + WDFUSBPIPE wdf_pipe_; +}; + +#endif // ANDROID_USB_PIPE_FILE_OBJECT_H__ diff --git a/host/windows/usb/legacy/driver/android_usb_pool_tags.h b/host/windows/usb/legacy/driver/android_usb_pool_tags.h new file mode 100755 index 000000000..7e52e843d --- /dev/null +++ b/host/windows/usb/legacy/driver/android_usb_pool_tags.h @@ -0,0 +1,51 @@ +/* + * 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. + */ + +#ifndef ANDROID_USB_POOL_TAGS_H__ +#define ANDROID_USB_POOL_TAGS_H__ +/** \file + This file consists definitions for pool tags used in memory allocations for + the driver. +*/ + +/// Default pool tag for memory allocations (GAND) +#define GANDR_POOL_TAG_DEFAULT 'DNAG' + +/// Pool tag for the driver object (GADR) +#define GANDR_POOL_TAG_DRIVER_OBJECT 'RDAG' + +/// Pool tag for KMDF device object extension (GADx) +#define GANDR_POOL_TAG_KMDF_DEVICE 'xDAG' + +/// Pool tag for target device configuration descriptor (GACD) +#define GANDR_POOL_TAG_DEV_CFG_DESC 'DCAG' + +/// Pool tag for device file object extension (GADf) +#define GANDR_POOL_TAG_DEVICE_FO 'fDAG' + +/// Pool tag for a bulk file object extension (GABx) +#define GANDR_POOL_TAG_BULK_FILE 'xBAG' + +/// Pool tag for an interrupt file object extension (GAIx) +#define GANDR_POOL_TAG_INTERRUPT_FILE 'xIAG' + +/// Pool tag for URB allocated in bulk read / write (GAbu) +#define GANDR_POOL_TAG_BULKRW_URB 'ubAG' + +/// Pool tag for interface pairs (GAip) +#define GANDR_POOL_TAG_INTERF_PAIRS 'piAG' + +#endif // ANDROID_USB_POOL_TAGS_H__ diff --git a/host/windows/usb/legacy/driver/android_usb_wdf_object.cpp b/host/windows/usb/legacy/driver/android_usb_wdf_object.cpp new file mode 100755 index 000000000..7210be65d --- /dev/null +++ b/host/windows/usb/legacy/driver/android_usb_wdf_object.cpp @@ -0,0 +1,153 @@ +/* + * 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 a class AndroidUsbWdfObject that + encapsulates a basic extension to all KMDF objects. Currently, device and + file object extensions ared derived from it. +*/ +#pragma data_seg() +#pragma code_seg() + +#include "precomp.h" +#include "android_usb_wdf_object.h" + +#pragma data_seg() +#pragma code_seg("PAGE") + +AndroidUsbWdfObject::AndroidUsbWdfObject(AndroidUsbWdfObjectType obj_type) + : wdf_object_(NULL), + object_type_(obj_type) { + ASSERT_IRQL_LOW(); + ASSERT(obj_type < AndroidUsbWdfObjectTypeMax); +} + +#pragma code_seg() + +AndroidUsbWdfObject::~AndroidUsbWdfObject() { + ASSERT_IRQL_LOW_OR_DISPATCH(); +} + +#pragma code_seg("PAGE") + +NTSTATUS AndroidUsbWdfObject::InitObjectAttributes( + PWDF_OBJECT_ATTRIBUTES wdf_obj_attr, + WDFOBJECT parent) { + ASSERT_IRQL_LOW(); + + // Enforce file object extension exception. + ASSERT(!Is(AndroidUsbWdfObjectTypeFile)); + if (Is(AndroidUsbWdfObjectTypeFile)) + return STATUS_INTERNAL_ERROR; + + // Initialize attributes and set cleanup and destroy callbacks + WDF_OBJECT_ATTRIBUTES_INIT(wdf_obj_attr); + WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(wdf_obj_attr, + AndroidUsbWdfObjectContext); + wdf_obj_attr->EvtCleanupCallback = EvtCleanupCallbackEntry; + wdf_obj_attr->EvtDestroyCallback = EvtDestroyCallbackEntry; + wdf_obj_attr->ParentObject = parent; + wdf_obj_attr->SynchronizationScope = GetWdfSynchronizationScope(); + + return STATUS_SUCCESS; +} + +NTSTATUS AndroidUsbWdfObject::InitializeContext() { + ASSERT_IRQL_LOW(); + ASSERT(IsAttached()); + if (!IsAttached()) + return STATUS_INTERNAL_ERROR; + + // Initialize our extension to that object + AndroidUsbWdfObjectContext* context = + GetAndroidUsbWdfObjectContext(wdf_object()); + ASSERT(NULL != context); + if (NULL == context) + return STATUS_INTERNAL_ERROR; + + // Make sure that extension has not been initialized + ASSERT((0 == context->object_type) && (NULL == context->wdf_object_ext)); + if ((0 != context->object_type) || (NULL != context->wdf_object_ext)) + return STATUS_INTERNAL_ERROR; + + context->object_type = object_type(); + context->wdf_object_ext = this; + ASSERT(this == GetAndroidUsbWdfObjectFromHandle(wdf_object())); + + return STATUS_SUCCESS; +} + +#pragma code_seg() + +WDF_SYNCHRONIZATION_SCOPE AndroidUsbWdfObject::GetWdfSynchronizationScope() { + ASSERT_IRQL_LOW_OR_DISPATCH(); + + // By default we don't want KMDF to synchronize access to our objects + return WdfSynchronizationScopeNone; +} + +void AndroidUsbWdfObject::OnEvtCleanupCallback() { + ASSERT_IRQL_LOW_OR_DISPATCH(); + GoogleDbgPrint("\n----- Object %p of type %u is cleaned up", + this, object_type()); +} + +void AndroidUsbWdfObject::OnEvtDestroyCallback() { + ASSERT_IRQL_LOW_OR_DISPATCH(); + GoogleDbgPrint("\n----- Object %p of type %u is destroyed", + this, object_type()); +} + +void AndroidUsbWdfObject::EvtCleanupCallbackEntry(WDFOBJECT wdf_obj) { + ASSERT_IRQL_LOW_OR_DISPATCH(); + + AndroidUsbWdfObjectContext* context = GetAndroidUsbWdfObjectContext(wdf_obj); + ASSERT(NULL != context); + if (NULL != context) { + // For file objects we will be always called here even though we didn't + // create any extension for them. In this case the context must not be + // initialized. + ASSERT(((0 == context->object_type) && (NULL == context->wdf_object_ext)) || + ((0 != context->object_type) && (NULL != context->wdf_object_ext))); + if (NULL != context->wdf_object_ext) { + ASSERT(context->wdf_object_ext->Is(context->object_type)); + context->wdf_object_ext->OnEvtCleanupCallback(); + } + } +} + +void AndroidUsbWdfObject::EvtDestroyCallbackEntry(WDFOBJECT wdf_obj) { + ASSERT_IRQL_LOW_OR_DISPATCH(); + + AndroidUsbWdfObjectContext* context = + GetAndroidUsbWdfObjectContext(wdf_obj); + ASSERT(NULL != context); + if (NULL != context) { + // For file objects we will be always called here even though we didn't + // create any extension for them. In this case the context must not be + // initialized. + ASSERT(((0 == context->object_type) && (NULL == context->wdf_object_ext)) || + ((0 != context->object_type) && (NULL != context->wdf_object_ext))); + if (NULL != context->wdf_object_ext) { + ASSERT(context->wdf_object_ext->Is(context->object_type)); + context->wdf_object_ext->OnEvtDestroyCallback(); + delete context->wdf_object_ext; + } + } +} + +#pragma data_seg() +#pragma code_seg() diff --git a/host/windows/usb/legacy/driver/android_usb_wdf_object.h b/host/windows/usb/legacy/driver/android_usb_wdf_object.h new file mode 100755 index 000000000..d5e814cc6 --- /dev/null +++ b/host/windows/usb/legacy/driver/android_usb_wdf_object.h @@ -0,0 +1,188 @@ +/* + * 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. + */ + +#ifndef ANDROID_USB_WDF_OBJECT_H__ +#define ANDROID_USB_WDF_OBJECT_H__ +/** \file + This file consists of declaration of a class AndroidUsbWdfObject that + encapsulates a basic extension to all KMDF objects. Currently, device and + file object extensions ared derived from it. +*/ + +/** AndroidUsbWdfObject class encapsulates a basic extension to all KMDF + objects. Currently, device and file object extensions ared derived from it. + Instances of this and derived classes must be allocated from NonPagedPool. +*/ +class AndroidUsbWdfObject { + public: + /** \brief Constructs the object. + + @param obj_type[in] Type of the object that this wrapper represents. + This method must be called at low IRQL. + */ + AndroidUsbWdfObject(AndroidUsbWdfObjectType obj_type); + + /** \brief Destructs the object. + + This method can be called at any IRQL. + */ + virtual ~AndroidUsbWdfObject(); + + /** \brief Initializes object attributes for new KMDF object. + + Each KMDF extension object must perform attribute initializations in order + to register an extension with KMDF framework. Since all our extensions are + derived from the base AndroidUsbWdfObject we use a single WDF object + extension context for all KMDF objects that we extend. So we can initialize + and register our context extension structure here. Note that object + attributes for file object wrappers are initialized globaly, when device + object is created. So file object extensions must not call this method. + This method must be called at low IRQL. + @param wdf_obj_attr[out] Object attributes to initialize. + @param parent[in] Parent object for this object. Can be NULL. + @return STATUS_SUCCESS on success or an appropriate error code. + */ + virtual NTSTATUS InitObjectAttributes(PWDF_OBJECT_ATTRIBUTES wdf_obj_attr, + WDFOBJECT parent); + + /** \brief Initializes context for this extension + + This method initializes AndroidUsbWdfObjectContext structure that KMDF + allocated for the object that is being extended with this class. + InitObjectAttributes method must be called prior to the call to this + method. Besides, before calling this method, instance of this class must + be already attached to the KMDF object it represents. Otherwise this + method will fail with STATUS_INTERNAL_ERROR. + This method must be called at low IRQL. + @return STATUS_SUCCESS on success or an appropriate error code + */ + virtual NTSTATUS InitializeContext(); + + + protected: + /** \brief Returns syncronisation scope for this extension type. + + This method is called from InitObjectAttributes method to specify what + type of synchronization is required for instances of this type. By + default we return WdfSynchronizationScopeNone which makes KMDF not + to synchronize access to this type of object. + This method can be called at IRQL <= DISPATCH_LEVEL. + */ + virtual WDF_SYNCHRONIZATION_SCOPE GetWdfSynchronizationScope(); + + /** \brief Handler for cleanup event fired for associated KMDF object. + + The framework calls this callback function when either the framework or a + driver attempts to delete the object. + This method can be called at IRQL <= DISPATCH_LEVEL. + */ + virtual void OnEvtCleanupCallback(); + + /** \brief Handler for destroy callback + + The framework calls the EvtDestroyCallback callback function after the + object's reference count has been decremented to zero. The framework + deletes the object immediately after the EvtDestroyCallback callback + function returns. + This callback can be called at IRQL <= DISPATCH_LEVEL. + */ + virtual void OnEvtDestroyCallback(); + + /** \brief Removes driver's references on an object so it can be deleted. + + The framework calls the callback function when either the framework or a + driver attempts to delete the object. + This callback can be called at IRQL <= DISPATCH_LEVEL. + @param wdf_obj[in] A handle to a framework object this class wraps. + */ + static void EvtCleanupCallbackEntry(WDFOBJECT wdf_obj); + + /** \brief Called when framework object is being deleted + + The framework calls the EvtDestroyCallback callback function after the + object's reference count has been decremented to zero. The framework + deletes the object immediately after the EvtDestroyCallback callback + function returns. + This callback can be called at IRQL <= DISPATCH_LEVEL. + @param wdf_obj[in] A handle to a framework object this class wraps. + */ + static void EvtDestroyCallbackEntry(WDFOBJECT wdf_obj); + + public: + + /// Gets KMDF object extended with this instance + __forceinline WDFOBJECT wdf_object() const { + return wdf_object_; + } + + /// Sets KMDF object associated with this extension + __forceinline void set_wdf_object(WDFOBJECT wdf_obj) { + ASSERT(NULL == wdf_object_); + wdf_object_ = wdf_obj; + } + + /// Gets KMDF object type for this extension + __forceinline AndroidUsbWdfObjectType object_type() const { + return object_type_; + } + + /** \brief Checks if this extension represends KMDF object of the given type + + @param obj_type[in] Object type to check + @return true if this wrapper represents object of that type and + false otherwise. + */ + __forceinline Is(AndroidUsbWdfObjectType obj_type) const { + return (obj_type == object_type()); + } + + /// Checks if extension is attached to a KMDF object + __forceinline bool IsAttached() const { + return (NULL != wdf_object()); + } + + protected: + /// KMDF object that is extended with this instance + WDFOBJECT wdf_object_; + + /// KMDF object type for this extension + AndroidUsbWdfObjectType object_type_; +}; + +/** \brief Gets our extension for the given KMDF object + + This method can be called at any IRQL + @param wdf_obj[in] KMDF handle describing an object + @return Instance of AndroidUsbWdfObject associated with this object or NULL + if association is not found. +*/ +__forceinline AndroidUsbWdfObject* GetAndroidUsbWdfObjectFromHandle( + WDFOBJECT wdf_obj) { + ASSERT(NULL != wdf_obj); + if (NULL != wdf_obj) { + AndroidUsbWdfObjectContext* context = + GetAndroidUsbWdfObjectContext(wdf_obj); + ASSERT((NULL != context) && (NULL != context->wdf_object_ext) && + (context->wdf_object_ext->Is(context->object_type))); + if ((NULL != context) && (NULL != context->wdf_object_ext) && + context->wdf_object_ext->Is(context->object_type)) { + return context->wdf_object_ext; + } + } + return NULL; +} + +#endif // ANDROID_USB_WDF_OBJECT_H__ diff --git a/host/windows/usb/legacy/driver/makefile b/host/windows/usb/legacy/driver/makefile new file mode 100755 index 000000000..54a4d7bf5 --- /dev/null +++ b/host/windows/usb/legacy/driver/makefile @@ -0,0 +1,36 @@ +!IF 0 + +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. + +Module Name: + + makefile. + +Notes: + + DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source + file to this component. This file merely indirects to the real make file + that is shared by all the components of Windows NT (DDK) + +!ENDIF + +!if "$(DDK_TARGET_OS)"=="Win2K" +!message This driver is not intended to target the Windows 2000 platform. +!elseif "$(DDK_TARGET_OS)"=="WinNET" +!INCLUDE $(NTMAKEENV)\makefile.def +!else +!INCLUDE $(NTMAKEENV)\makefile.def +!endif + diff --git a/host/windows/usb/legacy/driver/makefile.inc b/host/windows/usb/legacy/driver/makefile.inc new file mode 100755 index 000000000..ca0dbd3d9 --- /dev/null +++ b/host/windows/usb/legacy/driver/makefile.inc @@ -0,0 +1,7 @@ +_LNG=$(LANGUAGE) +_INX=. +STAMP=stampinf -f $@ -a $(_BUILDARCH) + +$(OBJ_PATH)\$(O)\$(INF_NAME).inf: $(_INX)\$(INF_NAME).inx + copy $(_INX)\$(@B).inx $@ + $(STAMP) diff --git a/host/windows/usb/legacy/driver/precomp.h b/host/windows/usb/legacy/driver/precomp.h new file mode 100755 index 000000000..fecee1d7f --- /dev/null +++ b/host/windows/usb/legacy/driver/precomp.h @@ -0,0 +1,42 @@ +/* + * 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 + Standard precompile file +*/ +#pragma warning(disable:4200) +#pragma warning(disable:4201) // nameless struct/union +#pragma warning(disable:4214) // bit field types other than int +extern "C" { +#include +#include +#include +#include +#include "usbdi.h" +#include "usbdlib.h" +#include +#include +} // extern "C" +#pragma warning(default:4200) +#pragma warning(default:4201) +#pragma warning(default:4214) + +#include "adb_api_extra.h" +#include "android_usb_common_defines.h" +#include "android_usb_pool_tags.h" +#include "android_usb_driver_defines.h" +#include "android_usb_new_delete.h" +#include "android_usb_inl.h" diff --git a/host/windows/usb/legacy/driver/sources b/host/windows/usb/legacy/driver/sources new file mode 100755 index 000000000..20dcc18c2 --- /dev/null +++ b/host/windows/usb/legacy/driver/sources @@ -0,0 +1,32 @@ +!IF 0 + +Copyright (C) 2007 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. + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + +!ENDIF + +!include sources.inc + +SOURCES= $(MOST_SOURCES) android_usb.rc diff --git a/host/windows/usb/legacy/driver/sources.inc b/host/windows/usb/legacy/driver/sources.inc new file mode 100755 index 000000000..20dbe7acf --- /dev/null +++ b/host/windows/usb/legacy/driver/sources.inc @@ -0,0 +1,84 @@ +!IF 0 + +Copyright (C) 2007 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. + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that driver. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + +!ENDIF + +TARGETNAME=androidusb +!IF "$(DDKBUILDENV)"=="chk" +TARGETPATH=..\build\Debug +!ELSE +TARGETPATH=..\build\Release +!ENDIF +TARGETTYPE=DRIVER +KMDF_VERSION=1 +USECXX_FLAG=/TP +USER_C_FLAGS=$(USER_C_FLAGS) /wd4100 /wd4002 /wd4509 /wd4390 /TP + +INCLUDES=$(INCLUDES); \ + $(IFSKIT_INC_PATH); \ + ..\common; \ + ..\api; + +TARGETLIBS=$(DDK_LIB_PATH)\usbd.lib + +MSC_WARNING_LEVEL=/W4 /WX /Wp64 +MSC_OPTIMIZATION = /Oi /Ob1 +C_DEFINES=$(C_DEFINES) -DEXPLODE_POOLTAGS -DRTL_USE_AVL_TABLES + +RCOPTIONS=$(RCOPTIONS) /dVER_COMPANYNAME_STR="\"Google Inc\"" +RCOPTIONS=$(RCOPTIONS) /dVER_LEGALCOPYRIGHT_YEARS="\"2007\"" +RCOPTIONS=$(RCOPTIONS) /dVER_LEGALCOPYRIGHT_STR="\"\251 Google Inc. All rights reserved.\"" +RCOPTIONS=$(RCOPTIONS) /dVER_PRODUCTNAME_STR="\"Google Android USB Driver\"" +RCOPTIONS=$(RCOPTIONS) /dVER_PRODUCTVERSION="1,00,01,001" +RCOPTIONS=$(RCOPTIONS) /dVER_PRODUCTVERSION_STR="\"1.00\"" + +!IF 0 + +By overriding .rsrc section properties (!D removes Discardable attribute) +we make sure that all our vtables will be placed properly into non-discardable +data segment. Because of the nature of this driver we don't need to have +vtables in NonPaged data sections because all our objects can be paged. +Otherwise we may want to add /SECTION:.rsrc,X option that locks section in memory + +!ENDIF + +LINKER_FLAGS=$(LINKER_FLAGS) /MAP /MAPINFO:LINES /SECTION:.rsrc,!D + +MOST_SOURCES= \ + android_usb_driver_object.cpp \ + android_usb_wdf_object.cpp \ + android_usb_device_object.cpp \ + android_usb_file_object.cpp \ + android_usb_device_file_object.cpp \ + android_usb_pipe_file_object.cpp \ + android_usb_bulk_file_object.cpp \ + android_usb_interrupt_file_object.cpp + +PRECOMPILED_INCLUDE=precomp.h +PRECOMPILED_PCH=precomp.pch +PRECOMPILED_OBJ=precomp.obj +