/* * 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 AdbWinUsbInterfaceObject that encapsulates an interface on our USB device that is accessible via WinUsb API. */ #include "stdafx.h" #include "adb_winusb_interface.h" #include "adb_winusb_endpoint_object.h" AdbWinUsbInterfaceObject::AdbWinUsbInterfaceObject(const wchar_t* interf_name) : AdbInterfaceObject(interf_name), usb_device_handle_(INVALID_HANDLE_VALUE), winusb_handle_(NULL), interface_number_(0xFF), def_read_endpoint_(0xFF), read_endpoint_id_(0xFF), def_write_endpoint_(0xFF), write_endpoint_id_(0xFF) { } AdbWinUsbInterfaceObject::~AdbWinUsbInterfaceObject() { ATLASSERT(NULL == winusb_handle_); ATLASSERT(INVALID_HANDLE_VALUE == usb_device_handle_); } LONG AdbWinUsbInterfaceObject::Release() { ATLASSERT(ref_count_ > 0); LONG ret = InterlockedDecrement(&ref_count_); ATLASSERT(ret >= 0); if (0 == ret) { LastReferenceReleased(); delete this; } return ret; } ADBAPIHANDLE AdbWinUsbInterfaceObject::CreateHandle() { // Open USB device for this inteface Note that WinUsb API // requires the handle to be opened for overlapped I/O. usb_device_handle_ = CreateFile(interface_name().c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (INVALID_HANDLE_VALUE == usb_device_handle_) return NULL; // Initialize WinUSB API for this interface if (!WinUsb_Initialize(usb_device_handle_, &winusb_handle_)) return NULL; // Cache current interface number that will be used in // WinUsb_Xxx calls performed on this interface. if (!WinUsb_GetCurrentAlternateSetting(winusb_handle(), &interface_number_)) return false; // Cache interface properties unsigned long bytes_written; // Cache USB device descriptor if (!WinUsb_GetDescriptor(winusb_handle(), USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, reinterpret_cast<PUCHAR>(&usb_device_descriptor_), sizeof(usb_device_descriptor_), &bytes_written)) { return false; } // Cache USB configuration descriptor if (!WinUsb_GetDescriptor(winusb_handle(), USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0, reinterpret_cast<PUCHAR>(&usb_config_descriptor_), sizeof(usb_config_descriptor_), &bytes_written)) { return false; } // Cache USB interface descriptor if (!WinUsb_QueryInterfaceSettings(winusb_handle(), interface_number(), &usb_interface_descriptor_)) { return false; } // Save indexes and IDs for bulk read / write endpoints. We will use them to // convert ADB_QUERY_BULK_WRITE_ENDPOINT_INDEX and // ADB_QUERY_BULK_READ_ENDPOINT_INDEX into actual endpoint indexes and IDs. for (UCHAR endpoint = 0; endpoint < usb_interface_descriptor_.bNumEndpoints; endpoint++) { // Get endpoint information WINUSB_PIPE_INFORMATION pipe_info; if (!WinUsb_QueryPipe(winusb_handle(), interface_number(), endpoint, &pipe_info)) { return false; } if (UsbdPipeTypeBulk == pipe_info.PipeType) { // This is a bulk endpoint. Cache its index and ID. if (0 != (pipe_info.PipeId & USB_ENDPOINT_DIRECTION_MASK)) { // Use this endpoint as default bulk read endpoint ATLASSERT(0xFF == def_read_endpoint_); def_read_endpoint_ = endpoint; read_endpoint_id_ = pipe_info.PipeId; } else { // Use this endpoint as default bulk write endpoint ATLASSERT(0xFF == def_write_endpoint_); def_write_endpoint_ = endpoint; write_endpoint_id_ = pipe_info.PipeId; } } } return AdbInterfaceObject::CreateHandle(); } bool AdbWinUsbInterfaceObject::CloseHandle() { if (NULL != winusb_handle_) { WinUsb_Free(winusb_handle_); winusb_handle_ = NULL; } if (INVALID_HANDLE_VALUE != usb_device_handle_) { ::CloseHandle(usb_device_handle_); usb_device_handle_ = INVALID_HANDLE_VALUE; } return AdbInterfaceObject::CloseHandle(); } bool AdbWinUsbInterfaceObject::GetSerialNumber(void* buffer, unsigned long* buffer_char_size, bool ansi) { if (!IsOpened()) { SetLastError(ERROR_INVALID_HANDLE); return false; } if (NULL == buffer_char_size) { SetLastError(ERROR_INVALID_PARAMETER); return false; } // Calculate serial number string size. Note that WinUsb_GetDescriptor // API will not return number of bytes needed to store serial number // string. So we will have to start with a reasonably large preallocated // buffer and then loop through WinUsb_GetDescriptor calls, doubling up // string buffer size every time ERROR_INSUFFICIENT_BUFFER is returned. union { // Preallocate reasonably sized buffer on the stack. char small_buffer[64]; USB_STRING_DESCRIPTOR initial_ser_num; }; USB_STRING_DESCRIPTOR* ser_num = &initial_ser_num; // Buffer byte size unsigned long ser_num_size = sizeof(small_buffer); // After successful call to WinUsb_GetDescriptor will contain serial // number descriptor size. unsigned long bytes_written; while (!WinUsb_GetDescriptor(winusb_handle(), USB_STRING_DESCRIPTOR_TYPE, usb_device_descriptor_.iSerialNumber, 0x0409, // English (US) reinterpret_cast<PUCHAR>(ser_num), ser_num_size, &bytes_written)) { // Any error other than ERROR_INSUFFICIENT_BUFFER is terminal here. if (ERROR_INSUFFICIENT_BUFFER != GetLastError()) { if (ser_num != &initial_ser_num) delete[] reinterpret_cast<char*>(ser_num); return false; } // Double up buffer size and reallocate string buffer ser_num_size *= 2; if (ser_num != &initial_ser_num) delete[] reinterpret_cast<char*>(ser_num); try { ser_num = reinterpret_cast<USB_STRING_DESCRIPTOR*>(new char[ser_num_size]); } catch (...) { SetLastError(ERROR_OUTOFMEMORY); return false; } } // Serial number string length unsigned long str_len = (ser_num->bLength - FIELD_OFFSET(USB_STRING_DESCRIPTOR, bString)) / sizeof(wchar_t); // Lets see if requested buffer is big enough to fit the string if ((NULL == buffer) || (*buffer_char_size < (str_len + 1))) { // Requested buffer is too small. if (ser_num != &initial_ser_num) delete[] reinterpret_cast<char*>(ser_num); *buffer_char_size = str_len + 1; SetLastError(ERROR_INSUFFICIENT_BUFFER); return false; } bool ret = true; if (ansi) { // We need to convert name from wide char to ansi string if (0 != WideCharToMultiByte(CP_ACP, 0, ser_num->bString, static_cast<int>(str_len), reinterpret_cast<PSTR>(buffer), static_cast<int>(*buffer_char_size), NULL, NULL)) { // Zero-terminate output string. reinterpret_cast<char*>(buffer)[str_len] = '\0'; } else { ret = false; } } else { // For wide char output just copy string buffer, // and zero-terminate output string. CopyMemory(buffer, ser_num->bString, bytes_written); reinterpret_cast<wchar_t*>(buffer)[str_len] = L'\0'; } if (ser_num != &initial_ser_num) delete[] reinterpret_cast<char*>(ser_num); return ret; } bool AdbWinUsbInterfaceObject::GetEndpointInformation( UCHAR endpoint_index, AdbEndpointInformation* info) { if (!IsOpened()) { SetLastError(ERROR_INVALID_HANDLE); return false; } if (NULL == info) { SetLastError(ERROR_INVALID_PARAMETER); return false; } // Get actual endpoint index for predefined read / write endpoints. if (ADB_QUERY_BULK_READ_ENDPOINT_INDEX == endpoint_index) { endpoint_index = def_read_endpoint_; } else if (ADB_QUERY_BULK_WRITE_ENDPOINT_INDEX == endpoint_index) { endpoint_index = def_write_endpoint_; } // Query endpoint information WINUSB_PIPE_INFORMATION pipe_info; if (!WinUsb_QueryPipe(winusb_handle(), interface_number(), endpoint_index, &pipe_info)) { return false; } // Save endpoint information into output. info->max_packet_size = pipe_info.MaximumPacketSize; info->max_transfer_size = 0xFFFFFFFF; info->endpoint_address = pipe_info.PipeId; info->polling_interval = pipe_info.Interval; info->setting_index = interface_number(); switch (pipe_info.PipeType) { case UsbdPipeTypeControl: info->endpoint_type = AdbEndpointTypeControl; break; case UsbdPipeTypeIsochronous: info->endpoint_type = AdbEndpointTypeIsochronous; break; case UsbdPipeTypeBulk: info->endpoint_type = AdbEndpointTypeBulk; break; case UsbdPipeTypeInterrupt: info->endpoint_type = AdbEndpointTypeInterrupt; break; default: info->endpoint_type = AdbEndpointTypeInvalid; break; } return true; } ADBAPIHANDLE AdbWinUsbInterfaceObject::OpenEndpoint( UCHAR endpoint_index, AdbOpenAccessType access_type, AdbOpenSharingMode sharing_mode) { // Convert index into id UCHAR endpoint_id; if ((ADB_QUERY_BULK_READ_ENDPOINT_INDEX == endpoint_index) || (def_read_endpoint_ == endpoint_index)) { endpoint_id = read_endpoint_id_; endpoint_index = def_read_endpoint_; } else if ((ADB_QUERY_BULK_WRITE_ENDPOINT_INDEX == endpoint_index) || (def_write_endpoint_ == endpoint_index)) { endpoint_id = write_endpoint_id_; endpoint_index = def_write_endpoint_; } else { SetLastError(ERROR_INVALID_PARAMETER); return false; } return OpenEndpoint(endpoint_id, endpoint_index); } ADBAPIHANDLE AdbWinUsbInterfaceObject::OpenEndpoint(UCHAR endpoint_id, UCHAR endpoint_index) { if (!IsOpened()) { SetLastError(ERROR_INVALID_HANDLE); return false; } AdbEndpointObject* adb_endpoint = NULL; try { adb_endpoint = new AdbWinUsbEndpointObject(this, endpoint_id, endpoint_index); } catch (...) { SetLastError(ERROR_OUTOFMEMORY); return NULL; } ADBAPIHANDLE ret = adb_endpoint->CreateHandle(); adb_endpoint->Release(); return ret; }