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 AdbLegacyEndpointObject that
19  encapsulates a handle opened to an endpoint on our device controlled by
20  a custom (legacy) USB driver.
21*/
22
23#include "stdafx.h"
24#include "adb_api_legacy.h"
25#include "adb_legacy_endpoint_object.h"
26#include "adb_legacy_io_completion.h"
27#include "adb_helper_routines.h"
28
29AdbLegacyEndpointObject::AdbLegacyEndpointObject(
30    AdbLegacyInterfaceObject* parent_interf,
31    UCHAR endpoint_id,
32    UCHAR endpoint_index)
33    : AdbEndpointObject(parent_interf, endpoint_id, endpoint_index),
34      usb_handle_(INVALID_HANDLE_VALUE) {
35}
36
37AdbLegacyEndpointObject::~AdbLegacyEndpointObject() {
38  if (INVALID_HANDLE_VALUE != usb_handle_) {
39    ::CloseHandle(usb_handle_);
40  }
41}
42
43ADBAPIHANDLE AdbLegacyEndpointObject::CommonAsyncReadWrite(
44    bool is_read,
45    void* buffer,
46    ULONG bytes_to_transfer,
47    ULONG* bytes_transferred,
48    HANDLE event_handle,
49    ULONG time_out) {
50  if (NULL != bytes_transferred) {
51    *bytes_transferred = 0;
52  }
53
54  if (!IsOpened()) {
55    SetLastError(ERROR_INVALID_HANDLE);
56    return false;
57  }
58
59  bool is_ioctl_write = is_read ? false : (0 != time_out);
60
61  // Create completion i/o object
62  AdbLegacyIOCompletion* adb_io_completion = NULL;
63
64  try {
65    adb_io_completion = new AdbLegacyIOCompletion(this,
66                                                  bytes_to_transfer,
67                                                  event_handle,
68                                                  is_ioctl_write);
69  } catch (... ) {
70    // We don't expect exceptions other than OOM thrown here.
71    SetLastError(ERROR_OUTOFMEMORY);
72    return NULL;
73  }
74
75  // Create a handle for it
76  ADBAPIHANDLE ret = adb_io_completion->CreateHandle();
77  ULONG transferred = 0;
78  if (NULL != ret) {
79    BOOL res = TRUE;
80    if (0 == time_out) {
81      // Go the read / write file way
82      res = is_read ? ReadFile(usb_handle(),
83                               buffer,
84                               bytes_to_transfer,
85                               &transferred,
86                               adb_io_completion->overlapped()) :
87                      WriteFile(usb_handle(),
88                                buffer,
89                                bytes_to_transfer,
90                                &transferred,
91                                adb_io_completion->overlapped());
92    } else {
93      // Go IOCTL way
94      AdbBulkTransfer transfer_param;
95      transfer_param.time_out = time_out;
96      transfer_param.transfer_size = is_read ? 0 : bytes_to_transfer;
97      transfer_param.SetWriteBuffer(is_read ? NULL : buffer);
98
99      res = DeviceIoControl(usb_handle(),
100        is_read ? ADB_IOCTL_BULK_READ : ADB_IOCTL_BULK_WRITE,
101        &transfer_param, sizeof(transfer_param),
102        is_read ? buffer : adb_io_completion->transferred_bytes_ptr(),
103        is_read ? bytes_to_transfer : sizeof(ULONG),
104        &transferred,
105        adb_io_completion->overlapped());
106    }
107
108    if (NULL != bytes_transferred) {
109      *bytes_transferred = transferred;
110    }
111
112    ULONG error = GetLastError();
113    if (!res && (ERROR_IO_PENDING != error)) {
114      // I/O failed immediatelly. We need to close i/o completion object
115      // before we return NULL to the caller.
116      adb_io_completion->CloseHandle();
117      ret = NULL;
118      SetLastError(error);
119    }
120  }
121
122  // Offseting 'new'
123  adb_io_completion->Release();
124
125  return ret;
126}
127
128bool AdbLegacyEndpointObject::CommonSyncReadWrite(bool is_read,
129                                                  void* buffer,
130                                                  ULONG bytes_to_transfer,
131                                                  ULONG* bytes_transferred,
132                                                  ULONG time_out) {
133  if (NULL != bytes_transferred) {
134    *bytes_transferred = 0;
135  }
136
137  if (!IsOpened()) {
138    SetLastError(ERROR_INVALID_HANDLE);
139    return false;
140  }
141
142  bool is_ioctl_write = is_read ? false : (0 != time_out);
143
144  // This is synchronous I/O. Since we always open I/O items for
145  // overlapped I/O we're obligated to always provide OVERLAPPED
146  // structure to read / write routines. Prepare it now.
147  OVERLAPPED overlapped;
148  ZeroMemory(&overlapped, sizeof(overlapped));
149
150  BOOL ret = TRUE;
151  ULONG ioctl_write_transferred = 0;
152  if (0 == time_out) {
153    // Go the read / write file way
154    ret = is_read ?
155      ReadFile(usb_handle(), buffer, bytes_to_transfer, bytes_transferred, &overlapped) :
156      WriteFile(usb_handle(), buffer, bytes_to_transfer, bytes_transferred, &overlapped);
157  } else {
158    // Go IOCTL way
159    AdbBulkTransfer transfer_param;
160    transfer_param.time_out = time_out;
161    transfer_param.transfer_size = is_read ? 0 : bytes_to_transfer;
162    transfer_param.SetWriteBuffer(is_read ? NULL : buffer);
163
164    ULONG tmp;
165    ret = DeviceIoControl(usb_handle(),
166      is_read ? ADB_IOCTL_BULK_READ : ADB_IOCTL_BULK_WRITE,
167      &transfer_param, sizeof(transfer_param),
168      is_read ? buffer : &ioctl_write_transferred,
169      is_read ? bytes_to_transfer : sizeof(ULONG),
170      &tmp,
171      &overlapped);
172  }
173
174  // Lets see the result
175  if (!ret && (ERROR_IO_PENDING != GetLastError())) {
176    // I/O failed.
177    return false;
178  }
179
180  // Lets wait till I/O completes
181  ULONG transferred = 0;
182  ret = GetOverlappedResult(usb_handle(), &overlapped, &transferred, TRUE);
183  if (ret && (NULL != bytes_transferred)) {
184    *bytes_transferred = is_ioctl_write ? ioctl_write_transferred :
185                                          transferred;
186  }
187
188  return ret ? true : false;
189}
190
191ADBAPIHANDLE AdbLegacyEndpointObject::CreateHandle(
192    const wchar_t* item_path,
193    AdbOpenAccessType access_type,
194    AdbOpenSharingMode share_mode) {
195  // Convert access / share parameters into CreateFile - compatible
196  ULONG desired_access;
197  ULONG desired_sharing;
198
199  if (!GetSDKComplientParam(access_type, share_mode,
200                            &desired_access, &desired_sharing)) {
201    return NULL;
202  }
203
204  // Open USB handle
205  usb_handle_ = CreateFile(item_path,
206                           desired_access,
207                           share_mode,
208                           NULL,
209                           OPEN_EXISTING,
210                           FILE_FLAG_OVERLAPPED,  // Always overlapped!
211                           NULL);
212  if (INVALID_HANDLE_VALUE == usb_handle_) {
213    return NULL;
214  }
215
216  // Create ADB handle
217  ADBAPIHANDLE ret = AdbObjectHandle::CreateHandle();
218
219  if (NULL == ret) {
220    // If creation of ADB handle failed we have to close USB handle too.
221    ULONG error = GetLastError();
222    ::CloseHandle(usb_handle());
223    usb_handle_ = INVALID_HANDLE_VALUE;
224    SetLastError(error);
225  }
226
227  return ret;
228}
229
230bool AdbLegacyEndpointObject::CloseHandle() {
231  if (INVALID_HANDLE_VALUE != usb_handle_) {
232    ::CloseHandle(usb_handle_);
233    usb_handle_ = INVALID_HANDLE_VALUE;
234  }
235
236  return AdbEndpointObject::CloseHandle();
237}
238