usb_windows.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. /*
  2. * Copyright (C) 2008 The Android Open Source Project
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in
  12. * the documentation and/or other materials provided with the
  13. * distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  16. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  17. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  18. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  19. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  20. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  21. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  22. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  23. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  24. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  25. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  26. * SUCH DAMAGE.
  27. */
  28. #include <windows.h>
  29. #include <winerror.h>
  30. #include <errno.h>
  31. #include <usb100.h>
  32. #include <adb_api.h>
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #include <memory>
  36. #include <string>
  37. #include "usb.h"
  38. //#define TRACE_USB 1
  39. #if TRACE_USB
  40. #define DBG(x...) fprintf(stderr, x)
  41. #else
  42. #define DBG(x...)
  43. #endif
  44. #define MAX_USBFS_BULK_SIZE (1024 * 1024)
  45. /** Structure usb_handle describes our connection to the usb device via
  46. AdbWinApi.dll. This structure is returned from usb_open() routine and
  47. is expected in each subsequent call that is accessing the device.
  48. */
  49. struct usb_handle {
  50. /// Handle to USB interface
  51. ADBAPIHANDLE adb_interface;
  52. /// Handle to USB read pipe (endpoint)
  53. ADBAPIHANDLE adb_read_pipe;
  54. /// Handle to USB write pipe (endpoint)
  55. ADBAPIHANDLE adb_write_pipe;
  56. /// Interface name
  57. std::string interface_name;
  58. };
  59. class WindowsUsbTransport : public UsbTransport {
  60. public:
  61. WindowsUsbTransport(std::unique_ptr<usb_handle> handle) : handle_(std::move(handle)) {}
  62. ~WindowsUsbTransport() override;
  63. ssize_t Read(void* data, size_t len) override;
  64. ssize_t Write(const void* data, size_t len) override;
  65. int Close() override;
  66. int Reset() override;
  67. private:
  68. std::unique_ptr<usb_handle> handle_;
  69. DISALLOW_COPY_AND_ASSIGN(WindowsUsbTransport);
  70. };
  71. /// Class ID assigned to the device by androidusb.sys
  72. static const GUID usb_class_id = ANDROID_USB_CLASS_ID;
  73. /// Checks if interface (device) matches certain criteria
  74. int recognized_device(usb_handle* handle, ifc_match_func callback);
  75. /// Opens usb interface (device) by interface (device) name.
  76. std::unique_ptr<usb_handle> do_usb_open(const wchar_t* interface_name);
  77. /// Cleans up opened usb handle
  78. void usb_cleanup_handle(usb_handle* handle);
  79. /// Cleans up (but don't close) opened usb handle
  80. void usb_kick(usb_handle* handle);
  81. std::unique_ptr<usb_handle> do_usb_open(const wchar_t* interface_name) {
  82. // Allocate our handle
  83. std::unique_ptr<usb_handle> ret(new usb_handle);
  84. // Create interface.
  85. ret->adb_interface = AdbCreateInterfaceByName(interface_name);
  86. if (nullptr == ret->adb_interface) {
  87. errno = GetLastError();
  88. DBG("failed to open interface %S\n", interface_name);
  89. return nullptr;
  90. }
  91. // Open read pipe (endpoint)
  92. ret->adb_read_pipe =
  93. AdbOpenDefaultBulkReadEndpoint(ret->adb_interface,
  94. AdbOpenAccessTypeReadWrite,
  95. AdbOpenSharingModeReadWrite);
  96. if (nullptr != ret->adb_read_pipe) {
  97. // Open write pipe (endpoint)
  98. ret->adb_write_pipe =
  99. AdbOpenDefaultBulkWriteEndpoint(ret->adb_interface,
  100. AdbOpenAccessTypeReadWrite,
  101. AdbOpenSharingModeReadWrite);
  102. if (nullptr != ret->adb_write_pipe) {
  103. // Save interface name
  104. unsigned long name_len = 0;
  105. // First get expected name length
  106. AdbGetInterfaceName(ret->adb_interface,
  107. nullptr,
  108. &name_len,
  109. true);
  110. if (0 != name_len) {
  111. // Now save the name
  112. ret->interface_name.resize(name_len);
  113. if (AdbGetInterfaceName(ret->adb_interface,
  114. &ret->interface_name[0],
  115. &name_len,
  116. true)) {
  117. // We're done at this point
  118. return ret;
  119. }
  120. }
  121. }
  122. }
  123. // Something went wrong.
  124. errno = GetLastError();
  125. usb_cleanup_handle(ret.get());
  126. SetLastError(errno);
  127. return nullptr;
  128. }
  129. ssize_t WindowsUsbTransport::Write(const void* data, size_t len) {
  130. unsigned long time_out = 5000;
  131. unsigned long written = 0;
  132. unsigned count = 0;
  133. int ret;
  134. DBG("usb_write %zu\n", len);
  135. if (nullptr != handle_) {
  136. // Perform write
  137. while(len > 0) {
  138. int xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
  139. ret = AdbWriteEndpointSync(handle_->adb_write_pipe, const_cast<void*>(data), xfer,
  140. &written, time_out);
  141. errno = GetLastError();
  142. DBG("AdbWriteEndpointSync returned %d, errno: %d\n", ret, errno);
  143. if (ret == 0) {
  144. // assume ERROR_INVALID_HANDLE indicates we are disconnected
  145. if (errno == ERROR_INVALID_HANDLE)
  146. usb_kick(handle_.get());
  147. return -1;
  148. }
  149. count += written;
  150. len -= written;
  151. data = (const char *)data + written;
  152. if (len == 0)
  153. return count;
  154. }
  155. } else {
  156. DBG("usb_write NULL handle\n");
  157. SetLastError(ERROR_INVALID_HANDLE);
  158. }
  159. DBG("usb_write failed: %d\n", errno);
  160. return -1;
  161. }
  162. ssize_t WindowsUsbTransport::Read(void* data, size_t len) {
  163. unsigned long time_out = 0;
  164. unsigned long read = 0;
  165. int ret;
  166. DBG("usb_read %zu\n", len);
  167. if (nullptr != handle_) {
  168. while (1) {
  169. int xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
  170. ret = AdbReadEndpointSync(handle_->adb_read_pipe, data, xfer, &read, time_out);
  171. errno = GetLastError();
  172. DBG("usb_read got: %ld, expected: %d, errno: %d\n", read, xfer, errno);
  173. if (ret) {
  174. return read;
  175. } else {
  176. // assume ERROR_INVALID_HANDLE indicates we are disconnected
  177. if (errno == ERROR_INVALID_HANDLE)
  178. usb_kick(handle_.get());
  179. break;
  180. }
  181. // else we timed out - try again
  182. }
  183. } else {
  184. DBG("usb_read NULL handle\n");
  185. SetLastError(ERROR_INVALID_HANDLE);
  186. }
  187. DBG("usb_read failed: %d\n", errno);
  188. return -1;
  189. }
  190. void usb_cleanup_handle(usb_handle* handle) {
  191. if (NULL != handle) {
  192. if (NULL != handle->adb_write_pipe)
  193. AdbCloseHandle(handle->adb_write_pipe);
  194. if (NULL != handle->adb_read_pipe)
  195. AdbCloseHandle(handle->adb_read_pipe);
  196. if (NULL != handle->adb_interface)
  197. AdbCloseHandle(handle->adb_interface);
  198. handle->interface_name.clear();
  199. handle->adb_write_pipe = NULL;
  200. handle->adb_read_pipe = NULL;
  201. handle->adb_interface = NULL;
  202. }
  203. }
  204. void usb_kick(usb_handle* handle) {
  205. if (NULL != handle) {
  206. usb_cleanup_handle(handle);
  207. } else {
  208. SetLastError(ERROR_INVALID_HANDLE);
  209. errno = ERROR_INVALID_HANDLE;
  210. }
  211. }
  212. WindowsUsbTransport::~WindowsUsbTransport() {
  213. Close();
  214. }
  215. int WindowsUsbTransport::Close() {
  216. DBG("usb_close\n");
  217. if (nullptr != handle_) {
  218. // Cleanup handle
  219. usb_cleanup_handle(handle_.get());
  220. handle_.reset();
  221. }
  222. return 0;
  223. }
  224. int WindowsUsbTransport::Reset() {
  225. DBG("usb_reset currently unsupported\n\n");
  226. // TODO, this is a bit complicated since it is using ADB
  227. return -1;
  228. }
  229. int recognized_device(usb_handle* handle, ifc_match_func callback) {
  230. struct usb_ifc_info info;
  231. USB_DEVICE_DESCRIPTOR device_desc;
  232. USB_INTERFACE_DESCRIPTOR interf_desc;
  233. if (NULL == handle)
  234. return 0;
  235. // Check vendor and product id first
  236. if (!AdbGetUsbDeviceDescriptor(handle->adb_interface, &device_desc)) {
  237. DBG("skipping device %x:%x\n", device_desc.idVendor, device_desc.idProduct);
  238. return 0;
  239. }
  240. // Then check interface properties
  241. if (!AdbGetUsbInterfaceDescriptor(handle->adb_interface, &interf_desc)) {
  242. DBG("skipping device %x:%x, failed to find interface\n", device_desc.idVendor,
  243. device_desc.idProduct);
  244. return 0;
  245. }
  246. // Must have two endpoints
  247. if (2 != interf_desc.bNumEndpoints) {
  248. DBG("skipping device %x:%x, incorrect number of endpoints\n", device_desc.idVendor,
  249. device_desc.idProduct);
  250. return 0;
  251. }
  252. info.dev_vendor = device_desc.idVendor;
  253. info.dev_product = device_desc.idProduct;
  254. info.dev_class = device_desc.bDeviceClass;
  255. info.dev_subclass = device_desc.bDeviceSubClass;
  256. info.dev_protocol = device_desc.bDeviceProtocol;
  257. info.ifc_class = interf_desc.bInterfaceClass;
  258. info.ifc_subclass = interf_desc.bInterfaceSubClass;
  259. info.ifc_protocol = interf_desc.bInterfaceProtocol;
  260. info.writable = 1;
  261. // read serial number (if there is one)
  262. unsigned long serial_number_len = sizeof(info.serial_number);
  263. if (!AdbGetSerialNumber(handle->adb_interface, info.serial_number,
  264. &serial_number_len, true)) {
  265. info.serial_number[0] = 0;
  266. }
  267. info.device_path[0] = 0;
  268. if (callback(&info) == 0) {
  269. DBG("skipping device %x:%x, not selected by callback\n", device_desc.idVendor,
  270. device_desc.idProduct);
  271. return 1;
  272. }
  273. DBG("found device %x:%x (%s)\n", device_desc.idVendor, device_desc.idProduct,
  274. info.serial_number);
  275. return 0;
  276. }
  277. static std::unique_ptr<usb_handle> find_usb_device(ifc_match_func callback) {
  278. std::unique_ptr<usb_handle> handle;
  279. char entry_buffer[2048];
  280. char interf_name[2048];
  281. AdbInterfaceInfo* next_interface = (AdbInterfaceInfo*)(&entry_buffer[0]);
  282. unsigned long entry_buffer_size = sizeof(entry_buffer);
  283. char* copy_name;
  284. // Enumerate all present and active interfaces.
  285. ADBAPIHANDLE enum_handle =
  286. AdbEnumInterfaces(usb_class_id, true, true, true);
  287. if (NULL == enum_handle)
  288. return NULL;
  289. while (AdbNextInterface(enum_handle, next_interface, &entry_buffer_size)) {
  290. // TODO(vchtchetkine): FIXME - temp hack converting wchar_t into char.
  291. // It would be better to change AdbNextInterface so it will return
  292. // interface name as single char string.
  293. const wchar_t* wchar_name = next_interface->device_name;
  294. for(copy_name = interf_name;
  295. L'\0' != *wchar_name;
  296. wchar_name++, copy_name++) {
  297. *copy_name = (char)(*wchar_name);
  298. }
  299. *copy_name = '\0';
  300. DBG("attempting to open interface %S\n", next_interface->device_name);
  301. handle = do_usb_open(next_interface->device_name);
  302. if (NULL != handle) {
  303. // Lets see if this interface (device) belongs to us
  304. if (recognized_device(handle.get(), callback)) {
  305. // found it!
  306. break;
  307. } else {
  308. usb_cleanup_handle(handle.get());
  309. handle.reset();
  310. }
  311. }
  312. entry_buffer_size = sizeof(entry_buffer);
  313. }
  314. AdbCloseHandle(enum_handle);
  315. return handle;
  316. }
  317. UsbTransport* usb_open(ifc_match_func callback, uint32_t) {
  318. std::unique_ptr<usb_handle> handle = find_usb_device(callback);
  319. return handle ? new WindowsUsbTransport(std::move(handle)) : nullptr;
  320. }