usb_windows.c revision 0eabf64ce0c649e4ef691ae1b70cb20d599dd429
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
29#include <windows.h>
30#include <winerror.h>
31#include <errno.h>
32#include <usb100.h>
33#include <adb_api.h>
34#include <stdio.h>
35#include <stdlib.h>
36
37#include "usb.h"
38
39//#define TRACE_USB 1
40#if TRACE_USB
41#define DBG(x...) fprintf(stderr, x)
42#else
43#define DBG(x...)
44#endif
45
46#define MAX_USBFS_BULK_SIZE (1024 * 1024)
47
48/** Structure usb_handle describes our connection to the usb device via
49  AdbWinApi.dll. This structure is returned from usb_open() routine and
50  is expected in each subsequent call that is accessing the device.
51*/
52struct usb_handle {
53    /// Handle to USB interface
54    ADBAPIHANDLE  adb_interface;
55
56    /// Handle to USB read pipe (endpoint)
57    ADBAPIHANDLE  adb_read_pipe;
58
59    /// Handle to USB write pipe (endpoint)
60    ADBAPIHANDLE  adb_write_pipe;
61
62    /// Interface name
63    char*         interface_name;
64};
65
66/// Class ID assigned to the device by androidusb.sys
67static const GUID usb_class_id = ANDROID_USB_CLASS_ID;
68
69
70/// Checks if interface (device) matches certain criteria
71int recognized_device(usb_handle* handle, ifc_match_func callback);
72
73/// Opens usb interface (device) by interface (device) name.
74usb_handle* do_usb_open(const wchar_t* interface_name);
75
76/// Writes data to the opened usb handle
77int usb_write(usb_handle* handle, const void* data, int len);
78
79/// Reads data using the opened usb handle
80int usb_read(usb_handle *handle, void* data, int len);
81
82/// Cleans up opened usb handle
83void usb_cleanup_handle(usb_handle* handle);
84
85/// Cleans up (but don't close) opened usb handle
86void usb_kick(usb_handle* handle);
87
88/// Closes opened usb handle
89int usb_close(usb_handle* handle);
90
91
92usb_handle* do_usb_open(const wchar_t* interface_name) {
93    // Allocate our handle
94    usb_handle* ret = (usb_handle*)malloc(sizeof(usb_handle));
95    if (NULL == ret)
96        return NULL;
97
98    // Create interface.
99    ret->adb_interface = AdbCreateInterfaceByName(interface_name);
100
101    if (NULL == ret->adb_interface) {
102        free(ret);
103        errno = GetLastError();
104        return NULL;
105    }
106
107    // Open read pipe (endpoint)
108    ret->adb_read_pipe =
109        AdbOpenDefaultBulkReadEndpoint(ret->adb_interface,
110                                   AdbOpenAccessTypeReadWrite,
111                                   AdbOpenSharingModeReadWrite);
112    if (NULL != ret->adb_read_pipe) {
113        // Open write pipe (endpoint)
114        ret->adb_write_pipe =
115            AdbOpenDefaultBulkWriteEndpoint(ret->adb_interface,
116                                      AdbOpenAccessTypeReadWrite,
117                                      AdbOpenSharingModeReadWrite);
118        if (NULL != ret->adb_write_pipe) {
119            // Save interface name
120            unsigned long name_len = 0;
121
122            // First get expected name length
123            AdbGetInterfaceName(ret->adb_interface,
124                          NULL,
125                          &name_len,
126                          true);
127            if (0 != name_len) {
128                ret->interface_name = (char*)malloc(name_len);
129
130                if (NULL != ret->interface_name) {
131                    // Now save the name
132                    if (AdbGetInterfaceName(ret->adb_interface,
133                                  ret->interface_name,
134                                  &name_len,
135                                  true)) {
136                        // We're done at this point
137                        return ret;
138                    }
139                } else {
140                    SetLastError(ERROR_OUTOFMEMORY);
141                }
142            }
143        }
144    }
145
146    // Something went wrong.
147    errno = GetLastError();
148    usb_cleanup_handle(ret);
149    free(ret);
150    SetLastError(errno);
151
152    return NULL;
153}
154
155int usb_write(usb_handle* handle, const void* data, int len) {
156    unsigned long time_out = 5000;
157    unsigned long written = 0;
158    unsigned count = 0;
159    int ret;
160
161    DBG("usb_write %d\n", len);
162    if (NULL != handle) {
163        // Perform write
164        while(len > 0) {
165            int xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
166            ret = AdbWriteEndpointSync(handle->adb_write_pipe,
167                                   (void*)data,
168                                   (unsigned long)xfer,
169                                   &written,
170                                   time_out);
171            errno = GetLastError();
172            DBG("AdbWriteEndpointSync returned %d, errno: %d\n", ret, errno);
173            if (ret == 0) {
174                // assume ERROR_INVALID_HANDLE indicates we are disconnected
175                if (errno == ERROR_INVALID_HANDLE)
176                usb_kick(handle);
177                return -1;
178            }
179
180            count += written;
181            len -= written;
182            data = (const char *)data + written;
183
184            if (len == 0)
185                return count;
186        }
187    } else {
188        DBG("usb_write NULL handle\n");
189        SetLastError(ERROR_INVALID_HANDLE);
190    }
191
192    DBG("usb_write failed: %d\n", errno);
193
194    return -1;
195}
196
197int usb_read(usb_handle *handle, void* data, int len) {
198    unsigned long time_out = 0;
199    unsigned long read = 0;
200    int ret;
201
202    DBG("usb_read %d\n", len);
203    if (NULL != handle) {
204        while (1) {
205            int xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
206
207	        ret = AdbReadEndpointSync(handle->adb_read_pipe,
208	                              (void*)data,
209	                              (unsigned long)xfer,
210	                              &read,
211	                              time_out);
212            errno = GetLastError();
213            DBG("usb_read got: %ld, expected: %d, errno: %d\n", read, xfer, errno);
214            if (ret) {
215                return read;
216            } else {
217                // assume ERROR_INVALID_HANDLE indicates we are disconnected
218                if (errno == ERROR_INVALID_HANDLE)
219                    usb_kick(handle);
220                break;
221            }
222            // else we timed out - try again
223        }
224    } else {
225        DBG("usb_read NULL handle\n");
226        SetLastError(ERROR_INVALID_HANDLE);
227    }
228
229    DBG("usb_read failed: %d\n", errno);
230
231    return -1;
232}
233
234void usb_cleanup_handle(usb_handle* handle) {
235    if (NULL != handle) {
236        if (NULL != handle->interface_name)
237            free(handle->interface_name);
238        if (NULL != handle->adb_write_pipe)
239            AdbCloseHandle(handle->adb_write_pipe);
240        if (NULL != handle->adb_read_pipe)
241            AdbCloseHandle(handle->adb_read_pipe);
242        if (NULL != handle->adb_interface)
243            AdbCloseHandle(handle->adb_interface);
244
245        handle->interface_name = NULL;
246        handle->adb_write_pipe = NULL;
247        handle->adb_read_pipe = NULL;
248        handle->adb_interface = NULL;
249    }
250}
251
252void usb_kick(usb_handle* handle) {
253    if (NULL != handle) {
254        usb_cleanup_handle(handle);
255    } else {
256        SetLastError(ERROR_INVALID_HANDLE);
257        errno = ERROR_INVALID_HANDLE;
258    }
259}
260
261int usb_close(usb_handle* handle) {
262    DBG("usb_close\n");
263
264    if (NULL != handle) {
265        // Cleanup handle
266        usb_cleanup_handle(handle);
267        free(handle);
268    }
269
270    return 0;
271}
272
273int usb_wait_for_disconnect(usb_handle *usb) {
274    /* TODO: Punt for now */
275    return 0;
276}
277
278int recognized_device(usb_handle* handle, ifc_match_func callback) {
279    struct usb_ifc_info info;
280    USB_DEVICE_DESCRIPTOR device_desc;
281    USB_INTERFACE_DESCRIPTOR interf_desc;
282
283    if (NULL == handle)
284        return 0;
285
286    // Check vendor and product id first
287    if (!AdbGetUsbDeviceDescriptor(handle->adb_interface,
288                                 &device_desc)) {
289        return 0;
290    }
291
292    // Then check interface properties
293    if (!AdbGetUsbInterfaceDescriptor(handle->adb_interface,
294                                    &interf_desc)) {
295        return 0;
296    }
297
298    // Must have two endpoints
299    if (2 != interf_desc.bNumEndpoints) {
300        return 0;
301    }
302
303    info.dev_vendor = device_desc.idVendor;
304    info.dev_product = device_desc.idProduct;
305    info.dev_class = device_desc.bDeviceClass;
306    info.dev_subclass = device_desc.bDeviceSubClass;
307    info.dev_protocol = device_desc.bDeviceProtocol;
308    info.ifc_class = interf_desc.bInterfaceClass;
309    info.ifc_subclass = interf_desc.bInterfaceSubClass;
310    info.ifc_protocol = interf_desc.bInterfaceProtocol;
311    info.writable = 1;
312
313    // read serial number (if there is one)
314    unsigned long serial_number_len = sizeof(info.serial_number);
315    if (!AdbGetSerialNumber(handle->adb_interface, info.serial_number,
316                    &serial_number_len, true)) {
317        info.serial_number[0] = 0;
318    }
319
320    info.device_path[0] = 0;
321
322    if (callback(&info) == 0) {
323        return 1;
324    }
325
326    return 0;
327}
328
329static usb_handle *find_usb_device(ifc_match_func callback) {
330	usb_handle* handle = NULL;
331    char entry_buffer[2048];
332    char interf_name[2048];
333    AdbInterfaceInfo* next_interface = (AdbInterfaceInfo*)(&entry_buffer[0]);
334    unsigned long entry_buffer_size = sizeof(entry_buffer);
335    char* copy_name;
336
337    // Enumerate all present and active interfaces.
338    ADBAPIHANDLE enum_handle =
339        AdbEnumInterfaces(usb_class_id, true, true, true);
340
341    if (NULL == enum_handle)
342        return NULL;
343
344    while (AdbNextInterface(enum_handle, next_interface, &entry_buffer_size)) {
345        // TODO(vchtchetkine): FIXME - temp hack converting wchar_t into char.
346        // It would be better to change AdbNextInterface so it will return
347        // interface name as single char string.
348        const wchar_t* wchar_name = next_interface->device_name;
349        for(copy_name = interf_name;
350                L'\0' != *wchar_name;
351                wchar_name++, copy_name++) {
352            *copy_name = (char)(*wchar_name);
353        }
354        *copy_name = '\0';
355
356        handle = do_usb_open(next_interface->device_name);
357        if (NULL != handle) {
358            // Lets see if this interface (device) belongs to us
359            if (recognized_device(handle, callback)) {
360                // found it!
361                break;
362            } else {
363                usb_cleanup_handle(handle);
364                free(handle);
365                handle = NULL;
366            }
367        }
368
369        entry_buffer_size = sizeof(entry_buffer);
370    }
371
372    AdbCloseHandle(enum_handle);
373    return handle;
374}
375
376usb_handle *usb_open(ifc_match_func callback)
377{
378    return find_usb_device(callback);
379}
380
381// called from fastboot.c
382void sleep(int seconds)
383{
384    Sleep(seconds * 1000);
385}
386