summaryrefslogtreecommitdiffstats
path: root/host
diff options
context:
space:
mode:
authorvchtchetkine <vchtchetkine@google.com>2009-07-29 16:25:34 -0700
committervchtchetkine <vchtchetkine@google.com>2009-07-29 16:25:34 -0700
commit1db55021599137f7bcec830d298f6062b495cd35 (patch)
tree3c3d7c1b1bff9dd5b7341998d422a98014974a2c /host
parenteee1675aa40d9fcaae3765370f5331e4002d8dd6 (diff)
downloadandroid_development-1db55021599137f7bcec830d298f6062b495cd35.tar.gz
android_development-1db55021599137f7bcec830d298f6062b495cd35.tar.bz2
android_development-1db55021599137f7bcec830d298f6062b495cd35.zip
Copy legacy driver source code as a sample for custom USB drivers
The primary usage for this code is to provide vendors / customers who for some reasons are not satisfied with WinUsb, with a sample custom driver code that is compliant with our AdbWinApi.dll. So vendors / customers can build their own custom USB driver that can be recognized by AdbWinApi, and can be accessible from adb.exe
Diffstat (limited to 'host')
-rwxr-xr-xhost/windows/usb/legacy/driver/android_usb.inf130
-rwxr-xr-xhost/windows/usb/legacy/driver/android_usb.rc39
-rwxr-xr-xhost/windows/usb/legacy/driver/android_usb_bulk_file_object.cpp52
-rwxr-xr-xhost/windows/usb/legacy/driver/android_usb_bulk_file_object.h50
-rwxr-xr-xhost/windows/usb/legacy/driver/android_usb_device_file_object.cpp83
-rwxr-xr-xhost/windows/usb/legacy/driver/android_usb_device_file_object.h73
-rwxr-xr-xhost/windows/usb/legacy/driver/android_usb_device_object.cpp1216
-rwxr-xr-xhost/windows/usb/legacy/driver/android_usb_device_object.h603
-rwxr-xr-xhost/windows/usb/legacy/driver/android_usb_driver_defines.h171
-rwxr-xr-xhost/windows/usb/legacy/driver/android_usb_driver_object.cpp186
-rwxr-xr-xhost/windows/usb/legacy/driver/android_usb_driver_object.h152
-rwxr-xr-xhost/windows/usb/legacy/driver/android_usb_file_object.cpp100
-rwxr-xr-xhost/windows/usb/legacy/driver/android_usb_file_object.h184
-rwxr-xr-xhost/windows/usb/legacy/driver/android_usb_inl.h88
-rwxr-xr-xhost/windows/usb/legacy/driver/android_usb_interrupt_file_object.cpp53
-rwxr-xr-xhost/windows/usb/legacy/driver/android_usb_interrupt_file_object.h50
-rwxr-xr-xhost/windows/usb/legacy/driver/android_usb_new_delete.h154
-rwxr-xr-xhost/windows/usb/legacy/driver/android_usb_pipe_file_object.cpp738
-rwxr-xr-xhost/windows/usb/legacy/driver/android_usb_pipe_file_object.h305
-rwxr-xr-xhost/windows/usb/legacy/driver/android_usb_pool_tags.h51
-rwxr-xr-xhost/windows/usb/legacy/driver/android_usb_wdf_object.cpp153
-rwxr-xr-xhost/windows/usb/legacy/driver/android_usb_wdf_object.h188
-rwxr-xr-xhost/windows/usb/legacy/driver/makefile36
-rwxr-xr-xhost/windows/usb/legacy/driver/makefile.inc7
-rwxr-xr-xhost/windows/usb/legacy/driver/precomp.h42
-rwxr-xr-xhost/windows/usb/legacy/driver/sources32
-rwxr-xr-xhost/windows/usb/legacy/driver/sources.inc84
27 files changed, 5020 insertions, 0 deletions
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 <windows.h>
+
+// 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<PWSTR>(bulk_read_pipe_str)
+};
+
+/// Buffer for bulk write pipe name
+const WCHAR bulk_write_pipe_str[] = L"\\" DEVICE_BULK_WRITE_PIPE_NAME;
+
+/// Unicode string for bulk write pipe name
+UNICODE_STRING bulk_write_pipe_name = {
+ sizeof(bulk_write_pipe_str) - sizeof(WCHAR),
+ sizeof(bulk_write_pipe_str) - sizeof(WCHAR),
+ const_cast<PWSTR>(bulk_write_pipe_str)
+};
+
+/// Buffer for an index-based pipe name prefix
+const WCHAR index_pipe_prefix_str[] = L"\\" DEVICE_PIPE_NAME_PREFIX;
+
+/// Unicode string for index-based pipe name prefix
+UNICODE_STRING index_pipe_prefix = {
+ sizeof(index_pipe_prefix_str) - sizeof(WCHAR),
+ sizeof(index_pipe_prefix_str) - sizeof(WCHAR),
+ const_cast<PWSTR>(index_pipe_prefix_str)
+};
+
+/// GUID that sets class ID for our device
+const GUID android_guid = ANDROID_USB_CLASS_ID;
+
+#pragma code_seg("PAGE")
+
+AndroidUsbDeviceObject::AndroidUsbDeviceObject()
+ : AndroidUsbWdfObject(AndroidUsbWdfObjectTypeDevice),
+ wdf_target_device_(NULL),
+ wdf_usb_interface_(NULL),
+ serial_number_handle_(NULL),
+ serial_number_char_len_(0),
+ configured_pipes_num_(0),
+ bulk_read_pipe_index_(INVALID_UCHAR),
+ bulk_write_pipe_index_(INVALID_UCHAR),
+ configuration_descriptor_(NULL) {
+ ASSERT_IRQL_PASSIVE();
+}
+
+#pragma code_seg()
+
+AndroidUsbDeviceObject::~AndroidUsbDeviceObject() {
+ ASSERT_IRQL_LOW_OR_DISPATCH();
+ if (NULL != serial_number_handle_)
+ WdfObjectDelete(serial_number_handle_);
+}
+
+#pragma code_seg("PAGE")
+
+NTSTATUS AndroidUsbDeviceObject::CreateFDODevice(PWDFDEVICE_INIT device_init) {
+ ASSERT_IRQL_PASSIVE();
+
+ ASSERT(!IsTaretDeviceCreated());
+ if (IsTaretDeviceCreated())
+ return STATUS_INTERNAL_ERROR;
+
+ // Initialize our object attributes first
+ WDF_OBJECT_ATTRIBUTES device_attr;
+ NTSTATUS status = InitObjectAttributes(&device_attr, NULL);
+ ASSERT(NT_SUCCESS(status));
+ if (!NT_SUCCESS(status))
+ return status;
+
+ // Initialize the pnp_power_callbacks structure. Callback events for PnP
+ // and Power are specified here. If we don't supply any callbacks, the
+ // KMDF will take appropriate default actions for an FDO device object.
+ // EvtDevicePrepareHardware and EvtDeviceReleaseHardware are major entry
+ // points for initializing / cleaning up our device. Probably, we can leave
+ // the rest to the framework.
+ WDF_PNPPOWER_EVENT_CALLBACKS pnp_power_callbacks;
+ WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnp_power_callbacks);
+ pnp_power_callbacks.EvtDevicePrepareHardware =
+ EvtDevicePrepareHardwareEntry;
+ pnp_power_callbacks.EvtDeviceReleaseHardware =
+ EvtDeviceReleaseHardwareEntry;
+ WdfDeviceInitSetPnpPowerEventCallbacks(device_init, &pnp_power_callbacks);
+
+ // Initialize the request attributes to specify the context size and type
+ // for every request created by framework for this device.
+ WDF_OBJECT_ATTRIBUTES request_attr;
+ WDF_OBJECT_ATTRIBUTES_INIT(&request_attr);
+ WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&request_attr, AndroidUsbWdfRequestContext);
+ WdfDeviceInitSetRequestAttributes(device_init, &request_attr);
+
+ // Initialize WDF_FILEOBJECT_CONFIG_INIT struct to tell the KMDF that we are
+ // interested in handling Create requests that get genereated when an
+ // application or another kernel component opens a handle through the device.
+ // We are not interested in receiving cleanup / close IRPs at this point.
+ WDF_FILEOBJECT_CONFIG file_config;
+ WDF_OBJECT_ATTRIBUTES file_attr;
+ WDF_FILEOBJECT_CONFIG_INIT(&file_config,
+ EvtDeviceFileCreateEntry,
+ WDF_NO_EVENT_CALLBACK,
+ WDF_NO_EVENT_CALLBACK);
+ WDF_OBJECT_ATTRIBUTES_INIT(&file_attr);
+ WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&file_attr,
+ AndroidUsbWdfObjectContext);
+ file_attr.EvtCleanupCallback = AndroidUsbWdfObject::EvtCleanupCallbackEntry;
+ file_attr.EvtDestroyCallback = AndroidUsbWdfObject::EvtDestroyCallbackEntry;
+ // We will provide our own synchronization for file access
+ file_attr.SynchronizationScope = WdfSynchronizationScopeNone;
+ WdfDeviceInitSetFileObjectConfig(device_init, &file_config, &file_attr);
+
+ // I/O type is buffered by default. It could be very inefficient if we have
+ // large reads / writes through our device.
+ WdfDeviceInitSetIoType(device_init, WdfDeviceIoDirect);
+
+ // DeviceInit is completely initialized. So call the framework
+ // to create the device and attach it to the lower stack.
+ WDFDEVICE wdf_dev = NULL;
+ status = WdfDeviceCreate(&device_init, &device_attr, &wdf_dev);
+ ASSERT(NT_SUCCESS(status) && (NULL != wdf_dev));
+ if (!NT_SUCCESS(status))
+ return status;
+
+ // Save handle to the created device
+ set_wdf_object(wdf_dev);
+
+ // Tell the framework to set the SurpriseRemovalOK in the DeviceCaps so
+ // that we don't get the popup in usermode (on Win2K) when we surprise
+ // remove the device.
+ WDF_DEVICE_PNP_CAPABILITIES pnp_caps;
+ WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnp_caps);
+ pnp_caps.SurpriseRemovalOK = WdfTrue;
+ WdfDeviceSetPnpCapabilities(wdf_device(), &pnp_caps);
+
+ // Create our default queue object for this device to start receiving I/O
+ status = CreateDefaultQueue();
+ ASSERT(NT_SUCCESS(status));
+ if (!NT_SUCCESS(status))
+ return status;
+
+ // Register a device interface so that app can find our device and talk to it.
+ status = WdfDeviceCreateDeviceInterface(wdf_device(), &android_guid, NULL);
+ ASSERT(NT_SUCCESS(status));
+ if (!NT_SUCCESS(status))
+ return status;
+
+ // Initialize our extension to that device. We will do this at the very end
+ // so we know that we successfully passed entire device create chain when
+ // we are called with other callbacks to that device.
+ status = InitializeContext();
+ ASSERT(NT_SUCCESS(status));
+ if (!NT_SUCCESS(status))
+ return status;
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS AndroidUsbDeviceObject::ResetDevice() {
+ ASSERT_IRQL_PASSIVE();
+
+ if (!IsTaretDeviceCreated())
+ return STATUS_SUCCESS;
+
+ // Reset the device
+ NTSTATUS status =
+ status = WdfUsbTargetDeviceResetPortSynchronously(wdf_target_device());
+
+ // !!!!! Note that after the call to WdfUsbTargetDeviceResetPortSynchronously
+ // this object may be no longer valid !!!!!
+
+ if (!NT_SUCCESS(status))
+ GoogleDbgPrint("\n!!!!! AndroidUsbDeviceObject::ResetDevice failed %X", status);
+
+ return status;
+}
+
+NTSTATUS AndroidUsbDeviceObject::OnEvtDevicePrepareHardware(
+ WDFCMRESLIST resources_raw,
+ WDFCMRESLIST resources_translated) {
+ ASSERT_IRQL_PASSIVE();
+
+ // Create a USB device handle so that we can communicate with the underlying
+ // USB stack. The wdf_target_device_ handle is used to query, configure, and
+ // manage all aspects of the USB device. These aspects include device
+ // properties, bus properties, and I/O creation and synchronization. This
+ // call gets the device and configuration descriptors and stores them in
+ // wdf_target_device_ object.
+ NTSTATUS status = WdfUsbTargetDeviceCreate(wdf_device(),
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &wdf_target_device_);
+ ASSERT(NT_SUCCESS(status) && (NULL != wdf_target_device_));
+ if (!NT_SUCCESS(status))
+ return status;
+
+ // Retrieve USBD version information, port driver capabilites and device
+ // capabilites such as speed, power, etc.
+ WDF_USB_DEVICE_INFORMATION_INIT(&usb_device_info_);
+ status = WdfUsbTargetDeviceRetrieveInformation(wdf_target_device(),
+ &usb_device_info_);
+ ASSERT(NT_SUCCESS(status));
+ if (!NT_SUCCESS(status))
+ return status;
+
+ WdfUsbTargetDeviceGetDeviceDescriptor(wdf_target_device(),
+ &usb_device_descriptor_);
+#if DBG
+ PrintUsbTargedDeviceInformation(usb_device_info());
+ PrintUsbDeviceDescriptor(&usb_device_descriptor_);
+#endif // DBG
+
+ // Save device serial number
+ status =
+ WdfUsbTargetDeviceAllocAndQueryString(wdf_target_device(),
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &serial_number_handle_,
+ &serial_number_char_len_,
+ usb_device_descriptor_.iSerialNumber,
+ 0x0409); // English (US)
+ if (!NT_SUCCESS(status))
+ return status;
+
+#if DBG
+ UNICODE_STRING ser_num;
+ ser_num.Length = serial_number_byte_len();
+ ser_num.MaximumLength = ser_num.Length;
+ ser_num.Buffer = const_cast<WCHAR*>
+ (serial_number());
+ GoogleDbgPrint("\n*** Device serial number %wZ", &ser_num);
+#endif // DBG
+
+ // Configure our device now
+ status = ConfigureDevice();
+ ASSERT(NT_SUCCESS(status));
+ if (!NT_SUCCESS(status))
+ return status;
+
+ // Select device interfaces
+ status = SelectInterfaces();
+ if (!NT_SUCCESS(status))
+ return status;
+
+ return status;
+}
+
+NTSTATUS AndroidUsbDeviceObject::OnEvtDeviceReleaseHardware(
+ WDFCMRESLIST resources_translated) {
+ ASSERT_IRQL_PASSIVE();
+
+ // It's possible that Preparehardware failed half way thru. So make
+ // sure the target device exists.
+ if (!IsTaretDeviceCreated())
+ return STATUS_SUCCESS;
+
+ // Cancel all the currently queued I/O. This is better than sending an
+ // explicit USB abort request down because release hardware gets
+ // called even when the device surprise-removed.
+ WdfIoTargetStop(WdfUsbTargetDeviceGetIoTarget(wdf_target_device()),
+ WdfIoTargetCancelSentIo);
+
+ // Unselect all selected configurations
+ WDF_USB_DEVICE_SELECT_CONFIG_PARAMS config_params;
+ WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_DECONFIG(&config_params);
+
+ NTSTATUS status = WdfUsbTargetDeviceSelectConfig(wdf_target_device(),
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &config_params);
+ ASSERT(NT_SUCCESS(status) || (STATUS_DEVICE_NOT_CONNECTED == status));
+ return status;
+}
+
+void AndroidUsbDeviceObject::OnEvtDeviceFileCreate(WDFREQUEST request,
+ WDFFILEOBJECT wdf_fo) {
+ ASSERT_IRQL_PASSIVE();
+ ASSERT(IsInterfaceSelected());
+ if (!IsInterfaceSelected()) {
+ WdfRequestComplete(request, STATUS_INVALID_DEVICE_STATE);
+ return;
+ }
+
+ PUNICODE_STRING file_name = WdfFileObjectGetFileName(wdf_fo);
+ ASSERT(NULL != file_name);
+ if (NULL == file_name) {
+ WdfRequestComplete(request, STATUS_OBJECT_NAME_INVALID);
+ return;
+ }
+
+ WDFUSBPIPE wdf_pipe_obj = NULL;
+ WDF_USB_PIPE_INFORMATION pipe_info;
+
+ // TODO: Share / access check here?
+
+ // Lets see if this is a device open
+ if (0 != file_name->Length) {
+ // This is a pipe open. Lets retrieve pipe index from the name
+ UCHAR pipe_index = GetPipeIndexFromFileName(file_name);
+ if (INVALID_UCHAR == pipe_index) {
+ GoogleDbgPrint("\n!!!!! There is no pipe index for file %wZ", file_name);
+ WdfRequestComplete(request, STATUS_OBJECT_NAME_INVALID);
+ return;
+ }
+
+ // Make sure that pipe index doesn't exceed number of pipes
+ if (pipe_index >= configured_pipes_num()) {
+ WdfRequestComplete(request, STATUS_OBJECT_NAME_NOT_FOUND);
+ return;
+ }
+
+ // Retrieve the pipe along with the pipe info
+ WDF_USB_PIPE_INFORMATION_INIT(&pipe_info);
+ wdf_pipe_obj = WdfUsbInterfaceGetConfiguredPipe(wdf_usb_interface(),
+ pipe_index,
+ &pipe_info);
+ if (NULL == wdf_pipe_obj) {
+ GoogleDbgPrint("\n!!!!! There is no pipe for index %u for file %wZ",
+ pipe_index, file_name);
+ WdfRequestComplete(request, STATUS_OBJECT_NAME_NOT_FOUND);
+ return;
+ }
+ }
+
+ // If we're here this must be either device open or pipe open
+ ASSERT((NULL != wdf_pipe_obj) || (0 == file_name->Length));
+
+ // Create our file object extension for this file
+ AndroidUsbFileObject* wdf_file_ext = NULL;
+ NTSTATUS status;
+
+ if (0 == file_name->Length) {
+ // This is a device FO. Create wrapper for device FO
+ ASSERT(NULL == wdf_pipe_obj);
+ wdf_file_ext = new(NonPagedPool, GANDR_POOL_TAG_DEVICE_FO)
+ AndroidUsbDeviceFileObject(this, wdf_fo);
+ ASSERT(NULL != wdf_file_ext);
+ if (NULL == wdf_file_ext) {
+ WdfRequestComplete(request, STATUS_INSUFFICIENT_RESOURCES);
+ return;
+ }
+
+ // Initialize extension
+ status = wdf_file_ext->Initialize();
+ if (!NT_SUCCESS(status)) {
+ delete wdf_file_ext;
+ WdfRequestComplete(request, status);
+ return;
+ }
+ } else {
+ // This is a pipe file. Create and initialize appropriate extension for it.
+ status =
+ CreatePipeFileObjectExt(wdf_fo, wdf_pipe_obj, &pipe_info, &wdf_file_ext);
+ ASSERT((NULL != wdf_file_ext) || !NT_SUCCESS(status));
+ if (!NT_SUCCESS(status)) {
+ WdfRequestComplete(request, status);
+ return;
+ }
+ }
+ ASSERT(GetAndroidUsbFileObjectFromHandle(wdf_fo) == wdf_file_ext);
+ WdfRequestComplete(request, STATUS_SUCCESS);
+}
+
+NTSTATUS AndroidUsbDeviceObject::EvtDevicePrepareHardwareEntry(
+ WDFDEVICE wdf_dev,
+ WDFCMRESLIST resources_raw,
+ WDFCMRESLIST resources_translated) {
+ ASSERT_IRQL_PASSIVE();
+
+ // Get our wrapper for the device and redirect event to its handler
+ AndroidUsbDeviceObject* wdf_device_ext =
+ GetAndroidUsbDeviceObjectFromHandle(wdf_dev);
+ ASSERT(NULL != wdf_device_ext);
+ return (NULL != wdf_device_ext) ?
+ wdf_device_ext->OnEvtDevicePrepareHardware(resources_raw,
+ resources_translated) :
+ STATUS_INVALID_DEVICE_REQUEST;
+}
+
+NTSTATUS AndroidUsbDeviceObject::EvtDeviceReleaseHardwareEntry(
+ WDFDEVICE wdf_dev,
+ WDFCMRESLIST resources_translated) {
+ ASSERT_IRQL_PASSIVE();
+
+ // Get our wrapper for the device and redirect event to its handler
+ AndroidUsbDeviceObject* wdf_device_ext =
+ GetAndroidUsbDeviceObjectFromHandle(wdf_dev);
+ ASSERT(NULL != wdf_device_ext);
+ return (NULL != wdf_device_ext) ?
+ wdf_device_ext->OnEvtDeviceReleaseHardware(resources_translated) :
+ STATUS_INVALID_DEVICE_REQUEST;
+}
+
+void AndroidUsbDeviceObject::EvtDeviceFileCreateEntry(
+ WDFDEVICE wdf_dev,
+ WDFREQUEST request,
+ WDFFILEOBJECT wdf_fo) {
+ ASSERT_IRQL_PASSIVE();
+
+ ASSERT(NULL != wdf_fo);
+ if (NULL == wdf_fo) {
+ WdfRequestComplete(request, STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ // Get our wrapper for the device and redirect event to its handler
+ AndroidUsbDeviceObject* wdf_device_ext =
+ GetAndroidUsbDeviceObjectFromHandle(wdf_dev);
+ ASSERT(NULL != wdf_device_ext);
+ if (NULL != wdf_device_ext) {
+ wdf_device_ext->OnEvtDeviceFileCreate(request, wdf_fo);
+ } else {
+ WdfRequestComplete(request, STATUS_INVALID_DEVICE_REQUEST);
+ }
+}
+
+#pragma code_seg()
+
+void AndroidUsbDeviceObject::OnEvtIoRead(WDFREQUEST request,
+ size_t length) {
+ ASSERT_IRQL_LOW_OR_DISPATCH();
+ ASSERT(IsInterfaceSelected());
+ if (!IsInterfaceSelected()) {
+ WdfRequestComplete(request, STATUS_INVALID_DEVICE_STATE);
+ return;
+ }
+
+ // Get our file extension and dispatch this event to its handler
+ AndroidUsbFileObject* wdf_file_ext =
+ GetAndroidUsbFileObjectForRequest(request);
+ ASSERT(NULL != wdf_file_ext);
+ if (NULL != wdf_file_ext) {
+ wdf_file_ext->OnEvtIoRead(request, length);
+ } else {
+ WdfRequestComplete(request, STATUS_INVALID_DEVICE_REQUEST);
+ }
+}
+
+void AndroidUsbDeviceObject::OnEvtIoWrite(WDFREQUEST request,
+ size_t length) {
+ ASSERT_IRQL_LOW_OR_DISPATCH();
+ ASSERT(IsInterfaceSelected());
+ if (!IsInterfaceSelected()) {
+ WdfRequestComplete(request, STATUS_INVALID_DEVICE_STATE);
+ return;
+ }
+
+ // Get our file extension and dispatch this event to its handler
+ AndroidUsbFileObject* wdf_file_ext =
+ GetAndroidUsbFileObjectForRequest(request);
+ ASSERT(NULL != wdf_file_ext);
+ if (NULL != wdf_file_ext) {
+ wdf_file_ext->OnEvtIoWrite(request, length);
+ } else {
+ WdfRequestComplete(request, STATUS_INVALID_DEVICE_REQUEST);
+ }
+}
+
+void AndroidUsbDeviceObject::OnEvtIoDeviceControl(WDFREQUEST request,
+ size_t output_buf_len,
+ size_t input_buf_len,
+ ULONG ioctl_code) {
+ ASSERT_IRQL_LOW_OR_DISPATCH();
+ ASSERT(IsInterfaceSelected());
+ if (!IsInterfaceSelected()) {
+ WdfRequestComplete(request, STATUS_INVALID_DEVICE_STATE);
+ return;
+ }
+
+ // Get our file extension and dispatch this event to its handler
+ AndroidUsbFileObject* wdf_file_ext =
+ GetAndroidUsbFileObjectForRequest(request);
+ ASSERT(NULL != wdf_file_ext);
+ if (NULL != wdf_file_ext) {
+ wdf_file_ext->OnEvtIoDeviceControl(request,
+ output_buf_len,
+ input_buf_len,
+ ioctl_code);
+ } else {
+ WdfRequestComplete(request, STATUS_INVALID_DEVICE_REQUEST);
+ }
+}
+
+void AndroidUsbDeviceObject::EvtIoReadEntry(WDFQUEUE queue,
+ WDFREQUEST request,
+ size_t length) {
+ ASSERT_IRQL_LOW_OR_DISPATCH();
+
+ // Get our file extension and dispatch this event to the appropriate handler
+ // inside our device extension.
+ AndroidUsbFileObject* wdf_file_ext =
+ GetAndroidUsbFileObjectForRequest(request);
+ ASSERT(NULL != wdf_file_ext);
+ if (NULL != wdf_file_ext) {
+ wdf_file_ext->device_object()->OnEvtIoRead(request, length);
+ } else {
+ WdfRequestComplete(request, STATUS_INVALID_DEVICE_REQUEST);
+ }
+}
+
+void AndroidUsbDeviceObject::EvtIoWriteEntry(WDFQUEUE queue,
+ WDFREQUEST request,
+ size_t length) {
+ ASSERT_IRQL_LOW_OR_DISPATCH();
+
+ // Get our file extension and dispatch this event to the appropriate handler
+ // inside our device extension.
+ AndroidUsbFileObject* wdf_file_ext =
+ GetAndroidUsbFileObjectForRequest(request);
+ ASSERT(NULL != wdf_file_ext);
+ if (NULL != wdf_file_ext) {
+ wdf_file_ext->device_object()->OnEvtIoWrite(request, length);
+ } else {
+ WdfRequestComplete(request, STATUS_INVALID_DEVICE_REQUEST);
+ }
+}
+
+void AndroidUsbDeviceObject::EvtIoDeviceControlEntry(WDFQUEUE queue,
+ WDFREQUEST request,
+ size_t output_buf_len,
+ size_t input_buf_len,
+ ULONG ioctl_code) {
+ ASSERT_IRQL_LOW_OR_DISPATCH();
+
+ // Get our file extension and dispatch this event to the appropriate handler
+ // inside our device extension.
+ AndroidUsbFileObject* wdf_file_ext =
+ GetAndroidUsbFileObjectForRequest(request);
+ ASSERT(NULL != wdf_file_ext);
+ if (NULL != wdf_file_ext) {
+ wdf_file_ext->device_object()->OnEvtIoDeviceControl(request,
+ output_buf_len,
+ input_buf_len,
+ ioctl_code);
+ } else {
+ WdfRequestComplete(request, STATUS_INVALID_DEVICE_REQUEST);
+ }
+}
+
+void AndroidUsbDeviceObject::OnGetUsbDeviceDescriptorCtl(WDFREQUEST request,
+ size_t output_buf_len) {
+ ASSERT_IRQL_LOW_OR_DISPATCH();
+
+ // Check the buffer first
+ if (output_buf_len >= sizeof(USB_DEVICE_DESCRIPTOR)) {
+ // Get the output buffer
+ NTSTATUS status;
+ void* ret_info = OutAddress(request, &status);
+ ASSERT(NT_SUCCESS(status) && (NULL != ret_info));
+ if (NT_SUCCESS(status)) {
+ // Copy requested info into output buffer and complete request
+ RtlCopyMemory(ret_info,
+ usb_device_descriptor(),
+ sizeof(USB_DEVICE_DESCRIPTOR));
+
+ WdfRequestCompleteWithInformation(request,
+ STATUS_SUCCESS,
+ sizeof(USB_DEVICE_DESCRIPTOR));
+ } else {
+ WdfRequestComplete(request, status);
+ }
+ } else {
+ WdfRequestCompleteWithInformation(request,
+ STATUS_BUFFER_TOO_SMALL,
+ sizeof(USB_DEVICE_DESCRIPTOR));
+ }
+}
+
+void AndroidUsbDeviceObject::OnGetUsbConfigDescriptorCtl(WDFREQUEST request,
+ size_t output_buf_len) {
+ ASSERT_IRQL_LOW_OR_DISPATCH();
+
+ if (NULL != configuration_descriptor()) {
+ // Check the buffer first
+ if (output_buf_len >= sizeof(USB_CONFIGURATION_DESCRIPTOR)) {
+ // Get the output buffer
+ NTSTATUS status;
+ void* ret_info = OutAddress(request, &status);
+ ASSERT(NT_SUCCESS(status) && (NULL != ret_info));
+ if (NT_SUCCESS(status)) {
+ // Copy requested info into output buffer and complete request
+ RtlCopyMemory(ret_info,
+ configuration_descriptor(),
+ sizeof(USB_CONFIGURATION_DESCRIPTOR));
+
+ WdfRequestCompleteWithInformation(request,
+ STATUS_SUCCESS,
+ sizeof(USB_CONFIGURATION_DESCRIPTOR));
+ } else {
+ WdfRequestComplete(request, status);
+ }
+ } else {
+ WdfRequestCompleteWithInformation(request,
+ STATUS_BUFFER_TOO_SMALL,
+ sizeof(USB_CONFIGURATION_DESCRIPTOR));
+ }
+ } else {
+ WdfRequestComplete(request, STATUS_INVALID_DEVICE_REQUEST);
+ }
+}
+
+void AndroidUsbDeviceObject::OnGetUsbInterfaceDescriptorCtl(WDFREQUEST request,
+ size_t output_buf_len) {
+ ASSERT_IRQL_LOW_OR_DISPATCH();
+
+ // Check the buffer first
+ if (output_buf_len >= sizeof(USB_INTERFACE_DESCRIPTOR)) {
+ // Get the output buffer
+ NTSTATUS status;
+ void* ret_info = OutAddress(request, &status);
+ ASSERT(NT_SUCCESS(status) && (NULL != ret_info));
+ if (NT_SUCCESS(status)) {
+ // Copy requested info into output buffer and complete request
+ RtlCopyMemory(ret_info,
+ interface_descriptor(),
+ sizeof(USB_INTERFACE_DESCRIPTOR));
+
+ WdfRequestCompleteWithInformation(request,
+ STATUS_SUCCESS,
+ sizeof(USB_INTERFACE_DESCRIPTOR));
+ } else {
+ WdfRequestComplete(request, status);
+ }
+ } else {
+ WdfRequestCompleteWithInformation(request,
+ STATUS_BUFFER_TOO_SMALL,
+ sizeof(USB_INTERFACE_DESCRIPTOR));
+ }
+}
+
+void AndroidUsbDeviceObject::OnGetEndpointInformationCtl(
+ WDFREQUEST request,
+ size_t input_buf_len,
+ size_t output_buf_len) {
+ ASSERT_IRQL_LOW_OR_DISPATCH();
+
+ // Check the buffers first
+ if (input_buf_len < sizeof(AdbQueryEndpointInformation)) {
+ WdfRequestComplete(request, STATUS_INVALID_BUFFER_SIZE);
+ return;
+ }
+
+ if (output_buf_len < sizeof(AdbEndpointInformation)) {
+ WdfRequestCompleteWithInformation(request,
+ STATUS_BUFFER_TOO_SMALL,
+ sizeof(AdbEndpointInformation));
+ return;
+ }
+
+ // Get the output buffer
+ NTSTATUS status;
+ AdbEndpointInformation* ret_info = reinterpret_cast<AdbEndpointInformation*>
+ (OutAddress(request, &status));
+ ASSERT(NT_SUCCESS(status) && (NULL != ret_info));
+ if (!NT_SUCCESS(status)) {
+ WdfRequestComplete(request, status);
+ return;
+ }
+
+ // Get the input buffer
+ AdbQueryEndpointInformation* in = reinterpret_cast<AdbQueryEndpointInformation*>
+ (InAddress(request, &status));
+ ASSERT(NT_SUCCESS(status) && (NULL != in));
+ if (!NT_SUCCESS(status)) {
+ WdfRequestComplete(request, status);
+ return;
+ }
+
+ // Lets see what exactly is queried
+ UCHAR endpoint_index = in->endpoint_index;
+ if (ADB_QUERY_BULK_WRITE_ENDPOINT_INDEX == endpoint_index)
+ endpoint_index = bulk_write_pipe_index();
+ else if (ADB_QUERY_BULK_READ_ENDPOINT_INDEX == endpoint_index)
+ endpoint_index = bulk_read_pipe_index();
+
+ // Make sure index is valid and within interface range
+ if ((INVALID_UCHAR == endpoint_index) ||
+ (endpoint_index >= configured_pipes_num())) {
+ WdfRequestComplete(request, STATUS_NOT_FOUND);
+ return;
+ }
+
+ // Get endpoint information
+ WDF_USB_PIPE_INFORMATION pipe_info;
+ WDF_USB_PIPE_INFORMATION_INIT(&pipe_info);
+ WDFUSBPIPE wdf_pipe_obj =
+ WdfUsbInterfaceGetConfiguredPipe(wdf_usb_interface(), endpoint_index, &pipe_info);
+ if (NULL == wdf_pipe_obj) {
+ WdfRequestComplete(request, STATUS_NOT_FOUND);
+ return;
+ }
+
+ // Copy endpoint info to the output
+ ret_info->max_packet_size = pipe_info.MaximumPacketSize;
+ ret_info->endpoint_address = pipe_info.EndpointAddress;
+ ret_info->polling_interval = pipe_info.Interval;
+ ret_info->setting_index = pipe_info.SettingIndex;
+ ret_info->endpoint_type = static_cast<AdbEndpointType>(pipe_info.PipeType);
+ ret_info->max_transfer_size = pipe_info.MaximumTransferSize;
+
+ WdfRequestCompleteWithInformation(request,
+ STATUS_SUCCESS,
+ sizeof(AdbEndpointInformation));
+}
+
+void AndroidUsbDeviceObject::OnGetSerialNumberCtl(WDFREQUEST request,
+ size_t output_buf_len) {
+ ASSERT_IRQL_LOW();
+
+ if (NULL == serial_number()) {
+ // There is no serial number saved for this device!
+ WdfRequestComplete(request, STATUS_INTERNAL_ERROR);
+ return;
+ }
+
+ size_t expected_len = serial_number_byte_len() + sizeof(WCHAR);
+
+ // Check the buffer first
+ if (output_buf_len >= expected_len) {
+ // Get the output buffer
+ NTSTATUS status;
+ WCHAR* ret_info = reinterpret_cast<WCHAR*>(OutAddress(request, &status));
+ ASSERT(NT_SUCCESS(status) && (NULL != ret_info));
+ if (NT_SUCCESS(status)) {
+ // Copy serial number
+ RtlCopyMemory(ret_info, serial_number(), serial_number_byte_len());
+ ret_info[serial_number_char_len()] = L'\0';
+ WdfRequestCompleteWithInformation(request, STATUS_SUCCESS, expected_len);
+ } else {
+ WdfRequestComplete(request, status);
+ }
+ } else {
+ WdfRequestCompleteWithInformation(request,
+ STATUS_BUFFER_TOO_SMALL,
+ sizeof(expected_len));
+ }
+}
+
+#pragma code_seg("PAGE")
+
+NTSTATUS AndroidUsbDeviceObject::CreateDefaultQueue() {
+ ASSERT_IRQL_PASSIVE();
+
+ // Register I/O callbacks to tell the framework that we are interested
+ // in handling WdfRequestTypeRead, WdfRequestTypeWrite, and
+ // WdfRequestTypeDeviceControl requests. WdfIoQueueDispatchParallel means
+ // that we are capable of handling all the I/O request simultaneously and we
+ // are responsible for protecting data that could be accessed by these
+ // callbacks simultaneously. This queue will be, by default, automanaged by
+ // the framework with respect to PnP and Power events. That is, framework
+ // will take care of queuing, failing, dispatching incoming requests based
+ // on the current PnP / Power state of the device. We also need to register
+ // a EvtIoStop handler so that we can acknowledge requests that are pending
+ // at the target driver.
+ WDF_IO_QUEUE_CONFIG io_queue_config;
+ WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&io_queue_config,
+ WdfIoQueueDispatchParallel);
+
+ io_queue_config.EvtIoDeviceControl = EvtIoDeviceControlEntry;
+ io_queue_config.EvtIoRead = EvtIoReadEntry;
+ io_queue_config.EvtIoWrite = EvtIoWriteEntry;
+ io_queue_config.AllowZeroLengthRequests = TRUE;
+ // By default KMDF will take care of the power management of this queue
+ io_queue_config.PowerManaged = WdfUseDefault;
+
+ // Create queue object
+ WDFQUEUE wdf_queue_obj = NULL;
+ NTSTATUS status = WdfIoQueueCreate(wdf_device(),
+ &io_queue_config,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &wdf_queue_obj);
+ ASSERT(NT_SUCCESS(status) && (NULL != wdf_queue_obj));
+ if (!NT_SUCCESS(status))
+ return status;
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS AndroidUsbDeviceObject::ConfigureDevice() {
+ ASSERT_IRQL_PASSIVE();
+
+ ASSERT(IsTaretDeviceCreated());
+ if (!IsTaretDeviceCreated())
+ return STATUS_INTERNAL_ERROR;
+
+ // In order to get the configuration descriptor we must first query for its
+ // size (by supplying NULL for the descriptor's address), allocate enough
+ // memory and then retrieve the descriptor.
+ USHORT size = 0;
+
+ // Query descriptor size first
+ NTSTATUS status =
+ WdfUsbTargetDeviceRetrieveConfigDescriptor(wdf_target_device(),
+ WDF_NO_HANDLE,
+ &size);
+ ASSERT((status == STATUS_BUFFER_TOO_SMALL) || !NT_SUCCESS(status));
+ if (status != STATUS_BUFFER_TOO_SMALL)
+ return status;
+
+ // Create a memory object and specify our device as the parent so that
+ // it will be freed automatically along with our device.
+ WDFMEMORY memory = NULL;
+ WDF_OBJECT_ATTRIBUTES attributes;
+ WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
+ attributes.ParentObject = wdf_device();
+ status = WdfMemoryCreate(&attributes,
+ NonPagedPool,
+ GANDR_POOL_TAG_DEV_CFG_DESC,
+ size,
+ &memory,
+ reinterpret_cast<PVOID*>(&configuration_descriptor_));
+ ASSERT(NT_SUCCESS(status));
+ if (!NT_SUCCESS(status))
+ return status;
+
+ // Now retrieve configuration descriptor
+ status =
+ WdfUsbTargetDeviceRetrieveConfigDescriptor(wdf_target_device(),
+ configuration_descriptor_,
+ &size);
+ ASSERT(NT_SUCCESS(status) && (NULL != configuration_descriptor_));
+ if (!NT_SUCCESS(status))
+ return status;
+
+#if DBG
+ PrintConfigDescriptor(configuration_descriptor(), size);
+#endif // DBG
+
+ return status;
+}
+
+NTSTATUS AndroidUsbDeviceObject::SelectInterfaces() {
+ ASSERT_IRQL_PASSIVE();
+
+ ASSERT(IsDeviceConfigured());
+ if (!IsDeviceConfigured())
+ return STATUS_INTERNAL_ERROR;
+
+ WDF_USB_DEVICE_SELECT_CONFIG_PARAMS config_params;
+ PWDF_USB_INTERFACE_SETTING_PAIR pairs = NULL;
+ // TODO: We need to find a way (possibly by looking at each
+ // interface descriptor) to get index of the ADB interface in multiinterface
+ // configuration.
+ UCHAR adb_interface_index = 0;
+
+ if (IsSingleInterfaceDevice()) {
+ // Our device has only one interface, so we don't have to bother with
+ // multiple interfaces at all.
+ GoogleDbgPrint("\n********** Device reports single interface");
+ // Select single interface configuration
+ WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE(&config_params);
+ } else {
+ // Configure multiple interfaces
+ ULONG num_interf = GetInterfaceCount();
+ GoogleDbgPrint("\n********** Device reports %u interfaces",
+ num_interf);
+
+ // Allocate pairs for each interface
+ pairs = new(PagedPool, GANDR_POOL_TAG_INTERF_PAIRS)
+ WDF_USB_INTERFACE_SETTING_PAIR[num_interf];
+ ASSERT(NULL != pairs);
+ if (NULL == pairs)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ adb_interface_index = 1;
+ // Initialize each interface pair
+ for (UCHAR pair = 0; pair < num_interf; pair++) {
+ pairs[pair].SettingIndex = 0;
+ pairs[pair].UsbInterface =
+ WdfUsbTargetDeviceGetInterface(wdf_target_device(), pair);
+ ASSERT(NULL != pairs[pair].UsbInterface);
+ if (NULL == pairs[pair].UsbInterface) {
+ delete[] pairs;
+ return STATUS_INTERNAL_ERROR;
+ }
+ }
+
+ // Select multiinterface configuration
+ WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_MULTIPLE_INTERFACES(&config_params,
+ (UCHAR)num_interf,
+ pairs);
+ }
+
+ NTSTATUS status =
+ WdfUsbTargetDeviceSelectConfig(wdf_target_device(),
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &config_params);
+ if (NULL != pairs)
+ delete[] pairs;
+
+ // ASSERT(NT_SUCCESS(status));
+ if (!NT_SUCCESS(status))
+ return status;
+
+#if DBG
+ PrintSelectedConfig(&config_params);
+#endif // DBG
+
+ wdf_usb_interface_ =
+ WdfUsbTargetDeviceGetInterface(wdf_target_device(), adb_interface_index);
+ ASSERT(NULL != wdf_usb_interface_);
+ if (NULL == wdf_usb_interface_)
+ return STATUS_INTERNAL_ERROR;
+
+ configured_pipes_num_ = WdfUsbInterfaceGetNumEndpoints(wdf_usb_interface(), 0);
+ ASSERT(0 != configured_pipes_num_);
+
+ // Cache selected interface descriptor
+ BYTE setting_index =
+ WdfUsbInterfaceGetConfiguredSettingIndex(wdf_usb_interface());
+
+ WdfUsbInterfaceGetDescriptor(wdf_usb_interface(),
+ setting_index,
+ &interface_descriptor_);
+
+#if DBG
+ PrintInterfaceDescriptor(interface_descriptor());
+#endif // DBG
+
+ // Iterate over pipes, decoding and saving info about bulk r/w pipes for
+ // easier and faster addressing later on when they get opened
+ for (UCHAR pipe = 0; pipe < configured_pipes_num(); pipe++) {
+ WDF_USB_PIPE_INFORMATION pipe_info;
+ WDF_USB_PIPE_INFORMATION_INIT(&pipe_info);
+ WDFUSBPIPE wdf_pipe_obj =
+ WdfUsbInterfaceGetConfiguredPipe(wdf_usb_interface(), pipe, &pipe_info);
+ ASSERT(NULL != wdf_pipe_obj);
+ if (NULL != wdf_pipe_obj) {
+ if ((WdfUsbPipeTypeBulk == pipe_info.PipeType) &&
+ WDF_USB_PIPE_DIRECTION_IN(pipe_info.EndpointAddress)) {
+ // This is a bulk read pipe
+ ASSERT(!IsBulkReadPipeKnown());
+ bulk_read_pipe_index_ = pipe;
+ } else {
+ ASSERT(!IsBulkWritePipeKnown());
+ bulk_write_pipe_index_ = pipe;
+ }
+ }
+#if DBG
+ PrintPipeInformation(&pipe_info, pipe);
+#endif // DBG
+ }
+
+ // At the end we must have calculated indexes for both,
+ // bulk read and write pipes
+ ASSERT(!NT_SUCCESS(status) || (IsBulkReadPipeKnown() &&
+ IsBulkWritePipeKnown()));
+
+ return status;
+}
+
+UCHAR AndroidUsbDeviceObject::GetPipeIndexFromFileName(
+ PUNICODE_STRING file_path) {
+ ASSERT_IRQL_PASSIVE();
+ ASSERT((NULL != file_path) && (0 != file_path->Length) && (NULL != file_path->Buffer));
+ if ((NULL == file_path) ||
+ (0 == file_path->Length) ||
+ (NULL == file_path->Buffer)) {
+ return INVALID_UCHAR;
+ }
+
+ // Lets check for explicit r/w pipe names
+ if (0 == RtlCompareUnicodeString(file_path, &bulk_read_pipe_name, TRUE))
+ return bulk_read_pipe_index();
+ if (0 == RtlCompareUnicodeString(file_path, &bulk_write_pipe_name, TRUE))
+ return bulk_write_pipe_index();
+
+ // Lets check path format
+ if (file_path->Length <= index_pipe_prefix.Length) {
+ GoogleDbgPrint("\n!!!!! Bad format for pipe name: %wZ", file_path);
+ return INVALID_UCHAR;
+ }
+
+ // Now when whe know that file_path->Length is sufficient lets match this
+ // path with the prefix
+ UNICODE_STRING prefix_match = *file_path;
+ prefix_match.Length = index_pipe_prefix.Length;
+ prefix_match.MaximumLength = prefix_match.Length;
+
+ if (0 != RtlCompareUnicodeString(&prefix_match, &index_pipe_prefix, TRUE)) {
+ GoogleDbgPrint("\n!!!!! Bad format for pipe name: %wZ", file_path);
+ return INVALID_UCHAR;
+ }
+
+ // Prefix matches. Make sure that remaining chars are all decimal digits.
+ // Pipe index begins right after the prefix ends.
+ const ULONG index_begins_at = WcharLen(index_pipe_prefix.Length);
+ const ULONG name_len = WcharLen(file_path->Length);
+ for (ULONG index = index_begins_at; index < name_len; index++) {
+ if ((file_path->Buffer[index] > L'9') ||
+ (file_path->Buffer[index] < L'0')) {
+ GoogleDbgPrint("\n!!!!! Bad format for pipe name: %wZ", file_path);
+ return INVALID_UCHAR;
+ }
+ }
+
+ // Parse the pipe#
+ ULONG uval = 0;
+ ULONG umultiplier = 1;
+
+ // traversing least to most significant digits.
+ for (ULONG index = name_len - 1; index >= index_begins_at; index--) {
+ uval += (umultiplier * static_cast<ULONG>(file_path->Buffer[index] - L'0'));
+ umultiplier *= 10;
+ }
+
+ return static_cast<UCHAR>(uval);
+}
+
+NTSTATUS AndroidUsbDeviceObject::CreatePipeFileObjectExt(
+ WDFFILEOBJECT wdf_fo,
+ WDFUSBPIPE wdf_pipe_obj,
+ const WDF_USB_PIPE_INFORMATION* pipe_info,
+ AndroidUsbFileObject** wdf_file_ext) {
+ ASSERT_IRQL_PASSIVE();
+ ASSERT((NULL != wdf_fo) && (NULL != wdf_pipe_obj) && (NULL != pipe_info) && (NULL != wdf_file_ext));
+ if ((NULL == wdf_fo) || (NULL == wdf_pipe_obj) || (NULL == pipe_info) || (NULL == wdf_file_ext)) {
+ return STATUS_INTERNAL_ERROR;
+ }
+ *wdf_file_ext = NULL;
+
+ AndroidUsbPipeFileObject* wdf_pipe_file_ext = NULL;
+
+ // We support only WdfUsbPipeTypeBulk and WdfUsbPipeTypeInterrupt files
+ // at this point.
+ switch (pipe_info->PipeType) {
+ case WdfUsbPipeTypeBulk:
+ wdf_pipe_file_ext = new(NonPagedPool, GANDR_POOL_TAG_BULK_FILE)
+ AndroidUsbBulkPipeFileObject(this, wdf_fo, wdf_pipe_obj);
+ break;
+
+ case WdfUsbPipeTypeInterrupt:
+ wdf_pipe_file_ext = new(NonPagedPool, GANDR_POOL_TAG_INTERRUPT_FILE)
+ AndroidUsbInterruptPipeFileObject(this, wdf_fo, wdf_pipe_obj);
+ break;;
+
+ case WdfUsbPipeTypeIsochronous:
+ case WdfUsbPipeTypeControl:
+ case WdfUsbPipeTypeInvalid:
+ default:
+ return STATUS_OBJECT_TYPE_MISMATCH;
+ }
+
+ // If we reached here instance of a file wrapper must be created.
+ ASSERT(NULL != wdf_pipe_file_ext);
+ if (NULL == wdf_pipe_file_ext)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ // Initialize the wrapper.
+ NTSTATUS status = wdf_pipe_file_ext->InitializePipe(pipe_info);
+ ASSERT(NT_SUCCESS(status));
+ if (NT_SUCCESS(status)) {
+ *wdf_file_ext = wdf_pipe_file_ext;
+ } else {
+ delete wdf_pipe_file_ext;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+#if DBG
+#pragma code_seg()
+
+void AndroidUsbDeviceObject::PrintUsbDeviceDescriptor(
+ const USB_DEVICE_DESCRIPTOR* desc) {
+ GoogleDbgPrint("\n***** USB_DEVICE_DESCRIPTOR %p for device %p", desc, this);
+ GoogleDbgPrint("\n bDescriptorType = %u", desc->bDescriptorType);
+ GoogleDbgPrint("\n bcdUSB = x%02X", desc->bcdUSB);
+ GoogleDbgPrint("\n bDeviceClass = x%02X", desc->bDeviceClass);
+ GoogleDbgPrint("\n bDeviceSubClass = x%02X", desc->bDeviceSubClass);
+ GoogleDbgPrint("\n bDeviceProtocol = x%02X", desc->bDeviceProtocol);
+ GoogleDbgPrint("\n bMaxPacketSize = %u", desc->bMaxPacketSize0);
+ GoogleDbgPrint("\n idVendor = x%04X", desc->idVendor);
+ GoogleDbgPrint("\n idProduct = x%04X", desc->idProduct);
+ GoogleDbgPrint("\n bcdDevice = x%02X", desc->bcdDevice);
+ GoogleDbgPrint("\n iManufacturer = %u", desc->iManufacturer);
+ GoogleDbgPrint("\n iProduct = %u", desc->iProduct);
+ GoogleDbgPrint("\n iSerialNumber = %u", desc->iSerialNumber);
+ GoogleDbgPrint("\n bNumConfigurations = %u", desc->bNumConfigurations);
+}
+
+void AndroidUsbDeviceObject::PrintUsbTargedDeviceInformation(
+ const WDF_USB_DEVICE_INFORMATION* info) {
+ GoogleDbgPrint("\n***** WDF_USB_DEVICE_INFORMATION %p for device %p", info, this);
+ GoogleDbgPrint("\n HcdPortCapabilities = x%08X", info->HcdPortCapabilities);
+ GoogleDbgPrint("\n Traits = x%08X", info->Traits);
+ GoogleDbgPrint("\n VersionInfo.USBDI_Version = x%08X",
+ info->UsbdVersionInformation.USBDI_Version);
+ GoogleDbgPrint("\n VersionInfo.Supported_USB_Version = x%08X",
+ info->UsbdVersionInformation.Supported_USB_Version);
+}
+
+void AndroidUsbDeviceObject::PrintConfigDescriptor(
+ const USB_CONFIGURATION_DESCRIPTOR* desc,
+ ULONG size) {
+ GoogleDbgPrint("\n***** USB_CONFIGURATION_DESCRIPTOR %p for device %p size %u",
+ desc, this, size);
+ GoogleDbgPrint("\n bDescriptorType = %u", desc->bDescriptorType);
+ GoogleDbgPrint("\n wTotalLength = %u", desc->wTotalLength);
+ GoogleDbgPrint("\n bNumInterfaces = %u", desc->bNumInterfaces);
+ GoogleDbgPrint("\n bConfigurationValue = %u", desc->bConfigurationValue);
+ GoogleDbgPrint("\n iConfiguration = %u", desc->iConfiguration);
+ GoogleDbgPrint("\n bmAttributes = %u", desc->bmAttributes);
+ GoogleDbgPrint("\n MaxPower = %u", desc->MaxPower);
+}
+
+void AndroidUsbDeviceObject::PrintSelectedConfig(
+ const WDF_USB_DEVICE_SELECT_CONFIG_PARAMS* config) {
+ GoogleDbgPrint("\n***** WDF_USB_DEVICE_SELECT_CONFIG_PARAMS %p for device %p", config, this);
+ GoogleDbgPrint("\n Type = %u", config->Type);
+ switch (config->Type) {
+ case WdfUsbTargetDeviceSelectConfigTypeSingleInterface:
+ GoogleDbgPrint("\n SingleInterface:");
+ GoogleDbgPrint("\n NumberConfiguredPipes = %u",
+ config->Types.SingleInterface.NumberConfiguredPipes);
+ GoogleDbgPrint("\n ConfiguredUsbInterface = %p",
+ config->Types.SingleInterface.ConfiguredUsbInterface);
+ break;
+
+ case WdfUsbTargetDeviceSelectConfigTypeMultiInterface:
+ GoogleDbgPrint("\n MultiInterface:");
+ GoogleDbgPrint("\n NumberInterfaces = %u",
+ config->Types.MultiInterface.NumberInterfaces);
+ GoogleDbgPrint("\n NumberOfConfiguredInterfaces = %u",
+ config->Types.MultiInterface.NumberOfConfiguredInterfaces);
+ GoogleDbgPrint("\n Pairs = %p",
+ config->Types.MultiInterface.Pairs);
+ break;
+
+ case WdfUsbTargetDeviceSelectConfigTypeInterfacesDescriptor:
+ GoogleDbgPrint("\n Descriptor:");
+ GoogleDbgPrint("\n NumInterfaceDescriptors = %u",
+ config->Types.Descriptor.NumInterfaceDescriptors);
+ GoogleDbgPrint("\n ConfigurationDescriptor = %p",
+ config->Types.Descriptor.ConfigurationDescriptor);
+ GoogleDbgPrint("\n InterfaceDescriptors = %p",
+ config->Types.Descriptor.InterfaceDescriptors);
+ break;
+
+ case WdfUsbTargetDeviceSelectConfigTypeUrb:
+ GoogleDbgPrint("\n Urb:");
+ GoogleDbgPrint("\n Urb = %p",
+ config->Types.Urb.Urb);
+ break;
+
+ case WdfUsbTargetDeviceSelectConfigTypeInterfacesPairs:
+ case WdfUsbTargetDeviceSelectConfigTypeInvalid:
+ case WdfUsbTargetDeviceSelectConfigTypeDeconfig:
+ default:
+ GoogleDbgPrint("\n Config type is unknown or invalid or not printable.");
+ break;
+ }
+}
+
+void AndroidUsbDeviceObject::PrintInterfaceDescriptor(
+ const USB_INTERFACE_DESCRIPTOR* desc) {
+ GoogleDbgPrint("\n***** USB_INTERFACE_DESCRIPTOR %p for device %p",
+ desc, this);
+ GoogleDbgPrint("\n bLength = %u", desc->bLength);
+ GoogleDbgPrint("\n bDescriptorType = %u", desc->bDescriptorType);
+ GoogleDbgPrint("\n bInterfaceNumber = %u", desc->bInterfaceNumber);
+ GoogleDbgPrint("\n bAlternateSetting = %u", desc->bAlternateSetting);
+ GoogleDbgPrint("\n bNumEndpoints = %u", desc->bNumEndpoints);
+ GoogleDbgPrint("\n bInterfaceClass = x%02X", desc->bInterfaceClass);
+ GoogleDbgPrint("\n bInterfaceSubClass = x%02X", desc->bInterfaceSubClass);
+ GoogleDbgPrint("\n bInterfaceProtocol = x%02X", desc->bInterfaceProtocol);
+ GoogleDbgPrint("\n iInterface = %u", desc->iInterface);
+}
+
+void AndroidUsbDeviceObject::PrintPipeInformation(
+ const WDF_USB_PIPE_INFORMATION* info,
+ UCHAR pipe_index) {
+ GoogleDbgPrint("\n***** WDF_USB_PIPE_INFORMATION[%u] %p for device %p",
+ pipe_index, info, this);
+ GoogleDbgPrint("\n Size = %u", info->Size);
+ GoogleDbgPrint("\n MaximumPacketSize = %u", info->MaximumPacketSize);
+ GoogleDbgPrint("\n EndpointAddress = x%02X", info->EndpointAddress);
+ GoogleDbgPrint("\n Interval = %u", info->Interval);
+ GoogleDbgPrint("\n SettingIndex = %u", info->SettingIndex);
+ GoogleDbgPrint("\n PipeType = %u", info->PipeType);
+ GoogleDbgPrint("\n MaximumTransferSize = %u", info->MaximumTransferSize);
+}
+
+#endif // DBG
+
+#pragma data_seg()
+#pragma code_seg()
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<WDFDEVICE>(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<const WCHAR*>
+ (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<AndroidUsbDeviceObject*>(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<UCHAR>(0xFF))
+
+/// Invalid ULONG value
+#define INVALID_ULONG (static_cast<ULONG>(-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<WDFFILEOBJECT>(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<AndroidUsbFileObject*>(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<USHORT>(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<USHORT>(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<ULONG>(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<ULONG>(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<ULONG>(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<ULONG>(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<ULONG>(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<AdbEndpointInformation*>(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<AdbEndpointType>(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<AdbBulkTransfer*>(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<ULONG>(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<AdbBulkTransfer*>(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<ULONG*>(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<PVOID*>(&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<PURB>(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<ULONG*>(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<char*>(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<AndroidUsbPipeFileObject*>(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 <initguid.h>
+#include <ntddk.h>
+#include <ntintsafe.h>
+#include <ntstrsafe.h>
+#include "usbdi.h"
+#include "usbdlib.h"
+#include <wdf.h>
+#include <wdfusb.h>
+} // 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
+