/* * Copyright (C) 2009 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 AdbLegacyEndpointObject that encapsulates a handle opened to an endpoint on our device controlled by a custom (legacy) USB driver. */ #include "stdafx.h" #include "adb_api_legacy.h" #include "adb_legacy_endpoint_object.h" #include "adb_legacy_io_completion.h" #include "adb_helper_routines.h" AdbLegacyEndpointObject::AdbLegacyEndpointObject( AdbLegacyInterfaceObject* parent_interf, UCHAR endpoint_id, UCHAR endpoint_index) : AdbEndpointObject(parent_interf, endpoint_id, endpoint_index), usb_handle_(INVALID_HANDLE_VALUE) { } AdbLegacyEndpointObject::~AdbLegacyEndpointObject() { if (INVALID_HANDLE_VALUE != usb_handle_) { ::CloseHandle(usb_handle_); } } ADBAPIHANDLE AdbLegacyEndpointObject::CommonAsyncReadWrite( bool is_read, void* buffer, ULONG bytes_to_transfer, ULONG* bytes_transferred, HANDLE event_handle, ULONG time_out) { if (NULL != bytes_transferred) { *bytes_transferred = 0; } if (!IsOpened()) { SetLastError(ERROR_INVALID_HANDLE); return false; } bool is_ioctl_write = is_read ? false : (0 != time_out); // Create completion i/o object AdbLegacyIOCompletion* adb_io_completion = NULL; try { adb_io_completion = new AdbLegacyIOCompletion(this, bytes_to_transfer, event_handle, is_ioctl_write); } catch (... ) { // We don't expect exceptions other than OOM thrown here. SetLastError(ERROR_OUTOFMEMORY); return NULL; } // Create a handle for it ADBAPIHANDLE ret = adb_io_completion->CreateHandle(); ULONG transferred = 0; if (NULL != ret) { BOOL res = TRUE; if (0 == time_out) { // Go the read / write file way res = is_read ? ReadFile(usb_handle(), buffer, bytes_to_transfer, &transferred, adb_io_completion->overlapped()) : WriteFile(usb_handle(), buffer, bytes_to_transfer, &transferred, adb_io_completion->overlapped()); } else { // Go IOCTL way AdbBulkTransfer transfer_param; transfer_param.time_out = time_out; transfer_param.transfer_size = is_read ? 0 : bytes_to_transfer; transfer_param.SetWriteBuffer(is_read ? NULL : buffer); res = DeviceIoControl(usb_handle(), is_read ? ADB_IOCTL_BULK_READ : ADB_IOCTL_BULK_WRITE, &transfer_param, sizeof(transfer_param), is_read ? buffer : adb_io_completion->transferred_bytes_ptr(), is_read ? bytes_to_transfer : sizeof(ULONG), &transferred, adb_io_completion->overlapped()); } if (NULL != bytes_transferred) { *bytes_transferred = transferred; } ULONG error = GetLastError(); if (!res && (ERROR_IO_PENDING != error)) { // I/O failed immediatelly. We need to close i/o completion object // before we return NULL to the caller. adb_io_completion->CloseHandle(); ret = NULL; SetLastError(error); } } // Offseting 'new' adb_io_completion->Release(); return ret; } bool AdbLegacyEndpointObject::CommonSyncReadWrite(bool is_read, void* buffer, ULONG bytes_to_transfer, ULONG* bytes_transferred, ULONG time_out) { if (NULL != bytes_transferred) { *bytes_transferred = 0; } if (!IsOpened()) { SetLastError(ERROR_INVALID_HANDLE); return false; } bool is_ioctl_write = is_read ? false : (0 != time_out); // This is synchronous I/O. Since we always open I/O items for // overlapped I/O we're obligated to always provide OVERLAPPED // structure to read / write routines. Prepare it now. OVERLAPPED overlapped; ZeroMemory(&overlapped, sizeof(overlapped)); BOOL ret = TRUE; ULONG ioctl_write_transferred = 0; if (0 == time_out) { // Go the read / write file way ret = is_read ? ReadFile(usb_handle(), buffer, bytes_to_transfer, bytes_transferred, &overlapped) : WriteFile(usb_handle(), buffer, bytes_to_transfer, bytes_transferred, &overlapped); } else { // Go IOCTL way AdbBulkTransfer transfer_param; transfer_param.time_out = time_out; transfer_param.transfer_size = is_read ? 0 : bytes_to_transfer; transfer_param.SetWriteBuffer(is_read ? NULL : buffer); ULONG tmp; ret = DeviceIoControl(usb_handle(), is_read ? ADB_IOCTL_BULK_READ : ADB_IOCTL_BULK_WRITE, &transfer_param, sizeof(transfer_param), is_read ? buffer : &ioctl_write_transferred, is_read ? bytes_to_transfer : sizeof(ULONG), &tmp, &overlapped); } // Lets see the result if (!ret && (ERROR_IO_PENDING != GetLastError())) { // I/O failed. return false; } // Lets wait till I/O completes ULONG transferred = 0; ret = GetOverlappedResult(usb_handle(), &overlapped, &transferred, TRUE); if (ret && (NULL != bytes_transferred)) { *bytes_transferred = is_ioctl_write ? ioctl_write_transferred : transferred; } return ret ? true : false; } ADBAPIHANDLE AdbLegacyEndpointObject::CreateHandle( const wchar_t* item_path, AdbOpenAccessType access_type, AdbOpenSharingMode share_mode) { // Convert access / share parameters into CreateFile - compatible ULONG desired_access; ULONG desired_sharing; if (!GetSDKComplientParam(access_type, share_mode, &desired_access, &desired_sharing)) { return NULL; } // Open USB handle usb_handle_ = CreateFile(item_path, desired_access, share_mode, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, // Always overlapped! NULL); if (INVALID_HANDLE_VALUE == usb_handle_) { return NULL; } // Create ADB handle ADBAPIHANDLE ret = AdbObjectHandle::CreateHandle(); if (NULL == ret) { // If creation of ADB handle failed we have to close USB handle too. ULONG error = GetLastError(); ::CloseHandle(usb_handle()); usb_handle_ = INVALID_HANDLE_VALUE; SetLastError(error); } return ret; } bool AdbLegacyEndpointObject::CloseHandle() { if (INVALID_HANDLE_VALUE != usb_handle_) { ::CloseHandle(usb_handle_); usb_handle_ = INVALID_HANDLE_VALUE; } return AdbEndpointObject::CloseHandle(); }