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