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 
AdbWinUsbInterfaceObject(const wchar_t * interf_name)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 
~AdbWinUsbInterfaceObject()38 AdbWinUsbInterfaceObject::~AdbWinUsbInterfaceObject() {
39   ATLASSERT(NULL == winusb_handle_);
40   ATLASSERT(INVALID_HANDLE_VALUE == usb_device_handle_);
41 }
42 
Release()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 
CreateHandle()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 
CloseHandle()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 
GetSerialNumber(void * buffer,unsigned long * buffer_char_size,bool ansi)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 
GetEndpointInformation(UCHAR endpoint_index,AdbEndpointInformation * info)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 
OpenEndpoint(UCHAR endpoint_index,AdbOpenAccessType access_type,AdbOpenSharingMode sharing_mode)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 
OpenEndpoint(UCHAR endpoint_id,UCHAR endpoint_index)318 ADBAPIHANDLE 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