OSDN Git Service

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