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
27AdbWinUsbInterfaceObject::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
38AdbWinUsbInterfaceObject::~AdbWinUsbInterfaceObject() {
39  ATLASSERT(NULL == winusb_handle_);
40  ATLASSERT(INVALID_HANDLE_VALUE == usb_device_handle_);
41}
42
43LONG 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
54ADBAPIHANDLE 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
129bool 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
142bool 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
237bool 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
295ADBAPIHANDLE 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
318ADBAPIHANDLE AdbWinUsbInterfaceObject::OpenEndpoint(UCHAR endpoint_id,
319                                                    UCHAR endpoint_index) {
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}
341