vchtchetkine | 8267511 | 2009-07-24 11:30:41 -0700 | [diff] [blame] | 1 | /*
|
| 2 | * Copyright (C) 2009 The Android Open Source Project
|
| 3 | *
|
| 4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 | * you may not use this file except in compliance with the License.
|
| 6 | * You may obtain a copy of the License at
|
| 7 | *
|
| 8 | * http://www.apache.org/licenses/LICENSE-2.0
|
| 9 | *
|
| 10 | * Unless required by applicable law or agreed to in writing, software
|
| 11 | * distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 | * See the License for the specific language governing permissions and
|
| 14 | * limitations under the License.
|
| 15 | */
|
| 16 |
|
| 17 | /** \file
|
| 18 | This file consists of implementation of class AdbWinUsbInterfaceObject
|
| 19 | that encapsulates an interface on our USB device that is accessible
|
| 20 | via WinUsb API.
|
| 21 | */
|
| 22 |
|
| 23 | #include "stdafx.h"
|
| 24 | #include "adb_winusb_interface.h"
|
| 25 | #include "adb_winusb_endpoint_object.h"
|
| 26 |
|
| 27 | AdbWinUsbInterfaceObject::AdbWinUsbInterfaceObject(const wchar_t* interf_name)
|
| 28 | : AdbInterfaceObject(interf_name),
|
| 29 | usb_device_handle_(INVALID_HANDLE_VALUE),
|
| 30 | winusb_handle_(NULL),
|
| 31 | interface_number_(0xFF),
|
| 32 | def_read_endpoint_(0xFF),
|
| 33 | read_endpoint_id_(0xFF),
|
| 34 | def_write_endpoint_(0xFF),
|
| 35 | write_endpoint_id_(0xFF) {
|
| 36 | }
|
| 37 |
|
| 38 | AdbWinUsbInterfaceObject::~AdbWinUsbInterfaceObject() {
|
| 39 | ATLASSERT(NULL == winusb_handle_);
|
| 40 | ATLASSERT(INVALID_HANDLE_VALUE == usb_device_handle_);
|
| 41 | }
|
| 42 |
|
vchtchetkine | f855c4e | 2009-08-05 16:57:18 -0700 | [diff] [blame^] | 43 | LONG AdbWinUsbInterfaceObject::Release() {
|
| 44 | ATLASSERT(ref_count_ > 0);
|
| 45 | LONG ret = InterlockedDecrement(&ref_count_);
|
| 46 | ATLASSERT(ret >= 0);
|
| 47 | if (0 == ret) {
|
| 48 | LastReferenceReleased();
|
| 49 | delete this;
|
| 50 | }
|
| 51 | return ret;
|
| 52 | }
|
| 53 |
|
vchtchetkine | 8267511 | 2009-07-24 11:30:41 -0700 | [diff] [blame] | 54 | ADBAPIHANDLE AdbWinUsbInterfaceObject::CreateHandle() {
|
| 55 | // Open USB device for this inteface Note that WinUsb API
|
| 56 | // requires the handle to be opened for overlapped I/O.
|
| 57 | usb_device_handle_ = CreateFile(interface_name().c_str(),
|
| 58 | GENERIC_READ | GENERIC_WRITE,
|
| 59 | FILE_SHARE_READ | FILE_SHARE_WRITE,
|
| 60 | NULL, OPEN_EXISTING,
|
| 61 | FILE_FLAG_OVERLAPPED, NULL);
|
| 62 | if (INVALID_HANDLE_VALUE == usb_device_handle_)
|
| 63 | return NULL;
|
| 64 |
|
| 65 | // Initialize WinUSB API for this interface
|
| 66 | if (!WinUsb_Initialize(usb_device_handle_, &winusb_handle_))
|
| 67 | return NULL;
|
| 68 |
|
| 69 | // Cache current interface number that will be used in
|
| 70 | // WinUsb_Xxx calls performed on this interface.
|
| 71 | if (!WinUsb_GetCurrentAlternateSetting(winusb_handle(), &interface_number_))
|
| 72 | return false;
|
| 73 |
|
| 74 | // Cache interface properties
|
| 75 | unsigned long bytes_written;
|
| 76 |
|
| 77 | // Cache USB device descriptor
|
| 78 | if (!WinUsb_GetDescriptor(winusb_handle(), USB_DEVICE_DESCRIPTOR_TYPE, 0, 0,
|
| 79 | reinterpret_cast<PUCHAR>(&usb_device_descriptor_),
|
| 80 | sizeof(usb_device_descriptor_), &bytes_written)) {
|
| 81 | return false;
|
| 82 | }
|
| 83 |
|
| 84 | // Cache USB configuration descriptor
|
| 85 | if (!WinUsb_GetDescriptor(winusb_handle(), USB_CONFIGURATION_DESCRIPTOR_TYPE,
|
| 86 | 0, 0,
|
| 87 | reinterpret_cast<PUCHAR>(&usb_config_descriptor_),
|
| 88 | sizeof(usb_config_descriptor_), &bytes_written)) {
|
| 89 | return false;
|
| 90 | }
|
| 91 |
|
| 92 | // Cache USB interface descriptor
|
| 93 | if (!WinUsb_QueryInterfaceSettings(winusb_handle(), interface_number(),
|
| 94 | &usb_interface_descriptor_)) {
|
| 95 | return false;
|
| 96 | }
|
| 97 |
|
| 98 | // Save indexes and IDs for bulk read / write endpoints. We will use them to
|
| 99 | // convert ADB_QUERY_BULK_WRITE_ENDPOINT_INDEX and
|
| 100 | // ADB_QUERY_BULK_READ_ENDPOINT_INDEX into actual endpoint indexes and IDs.
|
| 101 | for (UCHAR endpoint = 0; endpoint < usb_interface_descriptor_.bNumEndpoints;
|
| 102 | endpoint++) {
|
| 103 | // Get endpoint information
|
| 104 | WINUSB_PIPE_INFORMATION pipe_info;
|
| 105 | if (!WinUsb_QueryPipe(winusb_handle(), interface_number(), endpoint,
|
| 106 | &pipe_info)) {
|
| 107 | return false;
|
| 108 | }
|
| 109 |
|
| 110 | if (UsbdPipeTypeBulk == pipe_info.PipeType) {
|
| 111 | // This is a bulk endpoint. Cache its index and ID.
|
| 112 | if (0 != (pipe_info.PipeId & USB_ENDPOINT_DIRECTION_MASK)) {
|
| 113 | // Use this endpoint as default bulk read endpoint
|
| 114 | ATLASSERT(0xFF == def_read_endpoint_);
|
| 115 | def_read_endpoint_ = endpoint;
|
| 116 | read_endpoint_id_ = pipe_info.PipeId;
|
| 117 | } else {
|
| 118 | // Use this endpoint as default bulk write endpoint
|
| 119 | ATLASSERT(0xFF == def_write_endpoint_);
|
| 120 | def_write_endpoint_ = endpoint;
|
| 121 | write_endpoint_id_ = pipe_info.PipeId;
|
| 122 | }
|
| 123 | }
|
| 124 | }
|
| 125 |
|
| 126 | return AdbInterfaceObject::CreateHandle();
|
| 127 | }
|
| 128 |
|
| 129 | bool AdbWinUsbInterfaceObject::CloseHandle() {
|
| 130 | if (NULL != winusb_handle_) {
|
| 131 | WinUsb_Free(winusb_handle_);
|
| 132 | winusb_handle_ = NULL;
|
| 133 | }
|
| 134 | if (INVALID_HANDLE_VALUE != usb_device_handle_) {
|
| 135 | ::CloseHandle(usb_device_handle_);
|
| 136 | usb_device_handle_ = INVALID_HANDLE_VALUE;
|
| 137 | }
|
| 138 |
|
| 139 | return AdbInterfaceObject::CloseHandle();
|
| 140 | }
|
| 141 |
|
| 142 | bool AdbWinUsbInterfaceObject::GetSerialNumber(void* buffer,
|
| 143 | unsigned long* buffer_char_size,
|
| 144 | bool ansi) {
|
| 145 | if (!IsOpened()) {
|
| 146 | SetLastError(ERROR_INVALID_HANDLE);
|
| 147 | return false;
|
| 148 | }
|
| 149 |
|
| 150 | if (NULL == buffer_char_size) {
|
| 151 | SetLastError(ERROR_INVALID_PARAMETER);
|
| 152 | return false;
|
| 153 | }
|
| 154 |
|
| 155 | // Calculate serial number string size. Note that WinUsb_GetDescriptor
|
| 156 | // API will not return number of bytes needed to store serial number
|
| 157 | // string. So we will have to start with a reasonably large preallocated
|
| 158 | // buffer and then loop through WinUsb_GetDescriptor calls, doubling up
|
| 159 | // string buffer size every time ERROR_INSUFFICIENT_BUFFER is returned.
|
| 160 | union {
|
| 161 | // Preallocate reasonably sized buffer on the stack.
|
| 162 | char small_buffer[64];
|
| 163 | USB_STRING_DESCRIPTOR initial_ser_num;
|
| 164 | };
|
| 165 | USB_STRING_DESCRIPTOR* ser_num = &initial_ser_num;
|
| 166 | // Buffer byte size
|
| 167 | unsigned long ser_num_size = sizeof(small_buffer);
|
| 168 | // After successful call to WinUsb_GetDescriptor will contain serial
|
| 169 | // number descriptor size.
|
| 170 | unsigned long bytes_written;
|
| 171 | while (!WinUsb_GetDescriptor(winusb_handle(), USB_STRING_DESCRIPTOR_TYPE,
|
| 172 | usb_device_descriptor_.iSerialNumber,
|
| 173 | 0x0409, // English (US)
|
| 174 | reinterpret_cast<PUCHAR>(ser_num),
|
| 175 | ser_num_size, &bytes_written)) {
|
| 176 | // Any error other than ERROR_INSUFFICIENT_BUFFER is terminal here.
|
| 177 | if (ERROR_INSUFFICIENT_BUFFER != GetLastError()) {
|
| 178 | if (ser_num != &initial_ser_num)
|
| 179 | delete[] reinterpret_cast<char*>(ser_num);
|
| 180 | return false;
|
| 181 | }
|
| 182 |
|
| 183 | // Double up buffer size and reallocate string buffer
|
| 184 | ser_num_size *= 2;
|
| 185 | if (ser_num != &initial_ser_num)
|
| 186 | delete[] reinterpret_cast<char*>(ser_num);
|
| 187 | try {
|
| 188 | ser_num =
|
| 189 | reinterpret_cast<USB_STRING_DESCRIPTOR*>(new char[ser_num_size]);
|
| 190 | } catch (...) {
|
| 191 | SetLastError(ERROR_OUTOFMEMORY);
|
| 192 | return false;
|
| 193 | }
|
| 194 | }
|
| 195 |
|
| 196 | // Serial number string length
|
| 197 | unsigned long str_len = (ser_num->bLength -
|
| 198 | FIELD_OFFSET(USB_STRING_DESCRIPTOR, bString)) /
|
| 199 | sizeof(wchar_t);
|
| 200 |
|
| 201 | // Lets see if requested buffer is big enough to fit the string
|
| 202 | if ((NULL == buffer) || (*buffer_char_size < (str_len + 1))) {
|
| 203 | // Requested buffer is too small.
|
| 204 | if (ser_num != &initial_ser_num)
|
| 205 | delete[] reinterpret_cast<char*>(ser_num);
|
| 206 | *buffer_char_size = str_len + 1;
|
| 207 | SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
| 208 | return false;
|
| 209 | }
|
| 210 |
|
| 211 | bool ret = true;
|
| 212 | if (ansi) {
|
| 213 | // We need to convert name from wide char to ansi string
|
| 214 | if (0 != WideCharToMultiByte(CP_ACP, 0, ser_num->bString,
|
| 215 | static_cast<int>(str_len),
|
| 216 | reinterpret_cast<PSTR>(buffer),
|
| 217 | static_cast<int>(*buffer_char_size),
|
| 218 | NULL, NULL)) {
|
| 219 | // Zero-terminate output string.
|
| 220 | reinterpret_cast<char*>(buffer)[str_len] = '\0';
|
| 221 | } else {
|
| 222 | ret = false;
|
| 223 | }
|
| 224 | } else {
|
| 225 | // For wide char output just copy string buffer,
|
| 226 | // and zero-terminate output string.
|
| 227 | CopyMemory(buffer, ser_num->bString, bytes_written);
|
| 228 | reinterpret_cast<wchar_t*>(buffer)[str_len] = L'\0';
|
| 229 | }
|
| 230 |
|
| 231 | if (ser_num != &initial_ser_num)
|
| 232 | delete[] reinterpret_cast<char*>(ser_num);
|
| 233 |
|
| 234 | return ret;
|
| 235 | }
|
| 236 |
|
| 237 | bool AdbWinUsbInterfaceObject::GetEndpointInformation(
|
| 238 | UCHAR endpoint_index,
|
| 239 | AdbEndpointInformation* info) {
|
| 240 | if (!IsOpened()) {
|
| 241 | SetLastError(ERROR_INVALID_HANDLE);
|
| 242 | return false;
|
| 243 | }
|
| 244 |
|
| 245 | if (NULL == info) {
|
| 246 | SetLastError(ERROR_INVALID_PARAMETER);
|
| 247 | return false;
|
| 248 | }
|
| 249 |
|
| 250 | // Get actual endpoint index for predefined read / write endpoints.
|
| 251 | if (ADB_QUERY_BULK_READ_ENDPOINT_INDEX == endpoint_index) {
|
| 252 | endpoint_index = def_read_endpoint_;
|
| 253 | } else if (ADB_QUERY_BULK_WRITE_ENDPOINT_INDEX == endpoint_index) {
|
| 254 | endpoint_index = def_write_endpoint_;
|
| 255 | }
|
| 256 |
|
| 257 | // Query endpoint information
|
| 258 | WINUSB_PIPE_INFORMATION pipe_info;
|
| 259 | if (!WinUsb_QueryPipe(winusb_handle(), interface_number(), endpoint_index,
|
| 260 | &pipe_info)) {
|
| 261 | return false;
|
| 262 | }
|
| 263 |
|
| 264 | // Save endpoint information into output.
|
| 265 | info->max_packet_size = pipe_info.MaximumPacketSize;
|
| 266 | info->max_transfer_size = 0xFFFFFFFF;
|
| 267 | info->endpoint_address = pipe_info.PipeId;
|
| 268 | info->polling_interval = pipe_info.Interval;
|
| 269 | info->setting_index = interface_number();
|
| 270 | switch (pipe_info.PipeType) {
|
| 271 | case UsbdPipeTypeControl:
|
| 272 | info->endpoint_type = AdbEndpointTypeControl;
|
| 273 | break;
|
| 274 |
|
| 275 | case UsbdPipeTypeIsochronous:
|
| 276 | info->endpoint_type = AdbEndpointTypeIsochronous;
|
| 277 | break;
|
| 278 |
|
| 279 | case UsbdPipeTypeBulk:
|
| 280 | info->endpoint_type = AdbEndpointTypeBulk;
|
| 281 | break;
|
| 282 |
|
| 283 | case UsbdPipeTypeInterrupt:
|
| 284 | info->endpoint_type = AdbEndpointTypeInterrupt;
|
| 285 | break;
|
| 286 |
|
| 287 | default:
|
| 288 | info->endpoint_type = AdbEndpointTypeInvalid;
|
| 289 | break;
|
| 290 | }
|
| 291 |
|
| 292 | return true;
|
| 293 | }
|
| 294 |
|
| 295 | ADBAPIHANDLE AdbWinUsbInterfaceObject::OpenEndpoint(
|
| 296 | UCHAR endpoint_index,
|
| 297 | AdbOpenAccessType access_type,
|
| 298 | AdbOpenSharingMode sharing_mode) {
|
| 299 | // Convert index into id
|
| 300 | UCHAR endpoint_id;
|
| 301 |
|
| 302 | if ((ADB_QUERY_BULK_READ_ENDPOINT_INDEX == endpoint_index) ||
|
| 303 | (def_read_endpoint_ == endpoint_index)) {
|
| 304 | endpoint_id = read_endpoint_id_;
|
| 305 | endpoint_index = def_read_endpoint_;
|
| 306 | } else if ((ADB_QUERY_BULK_WRITE_ENDPOINT_INDEX == endpoint_index) ||
|
| 307 | (def_write_endpoint_ == endpoint_index)) {
|
| 308 | endpoint_id = write_endpoint_id_;
|
| 309 | endpoint_index = def_write_endpoint_;
|
| 310 | } else {
|
| 311 | SetLastError(ERROR_INVALID_PARAMETER);
|
| 312 | return false;
|
| 313 | }
|
| 314 |
|
| 315 | return OpenEndpoint(endpoint_id, endpoint_index);
|
| 316 | }
|
| 317 |
|
| 318 | ADBAPIHANDLE AdbWinUsbInterfaceObject::OpenEndpoint(UCHAR endpoint_id,
|
vchtchetkine | 3916484 | 2009-07-28 12:45:33 -0700 | [diff] [blame] | 319 | UCHAR endpoint_index) {
|
vchtchetkine | 8267511 | 2009-07-24 11:30:41 -0700 | [diff] [blame] | 320 | if (!IsOpened()) {
|
| 321 | SetLastError(ERROR_INVALID_HANDLE);
|
| 322 | return false;
|
| 323 | }
|
| 324 |
|
| 325 | AdbEndpointObject* adb_endpoint = NULL;
|
| 326 |
|
| 327 | try {
|
| 328 | adb_endpoint =
|
| 329 | new AdbWinUsbEndpointObject(this, endpoint_id, endpoint_index);
|
| 330 | } catch (...) {
|
| 331 | SetLastError(ERROR_OUTOFMEMORY);
|
| 332 | return NULL;
|
| 333 | }
|
| 334 |
|
| 335 | ADBAPIHANDLE ret = adb_endpoint->CreateHandle();
|
| 336 |
|
| 337 | adb_endpoint->Release();
|
| 338 |
|
| 339 | return ret;
|
| 340 | }
|