blob: 119c77e1dc478a6899c8540d5c411ce5d95794b2 [file] [log] [blame]
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -07001/*
2 * Copyright (C) 2017 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 */
Tomasz Wiszkowski9915c6c2017-08-03 14:20:43 -070016// #undef NDEBUG
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -070017
Tomasz Wiszkowski93ea8052017-09-21 10:02:45 -070018#include "guest/commands/usbforward/usb_server.h"
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -070019
20#include <string>
21#include <vector>
22#include <strings.h>
23#include <cutils/log.h>
24#include <libusb/libusb.h>
25#include "common/libs/fs/shared_select.h"
Greg Hartman6588a2d2017-09-29 16:36:52 -070026#include "common/libs/usbforward/protocol.h"
Tomasz Wiszkowski93ea8052017-09-21 10:02:45 -070027#include "guest/commands/usbforward/transport_request.h"
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -070028
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -070029namespace usb_forward {
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -070030namespace {
Tomasz Wiszkowski85521942017-07-31 12:42:41 -070031// USBServer exports device kExportedVendorID:kExportedProductID to the server.
32// We will not support exporting multiple USB devices as there's no practical
33// need for this.
34constexpr uint16_t kExportedVendorID = 0x18d1;
35constexpr uint16_t kExportedProductID = 0x4ee7;
36
37// Use default BUS and DEVICE IDs so that it's easier to attach over USB/IP.
38constexpr uint8_t kDefaultBusID = 1;
39constexpr uint8_t kDefaultDevID = 1;
40
Tomasz Wiszkowski482292e2017-08-04 16:33:00 -070041std::shared_ptr<libusb_device_handle> GetDevice() {
42 std::shared_ptr<libusb_device_handle> res(
Tomasz Wiszkowski85521942017-07-31 12:42:41 -070043 libusb_open_device_with_vid_pid(nullptr, kExportedVendorID,
44 kExportedProductID),
45 [](libusb_device_handle* h) {
Tomasz Wiszkowskia48e7452017-09-05 15:21:07 -070046 // Apparently, deleter is called even on an uninitialized shared_ptr.
47 if (h != nullptr) {
48 libusb_release_interface(h, 0);
49 libusb_close(h);
50 }
Tomasz Wiszkowski85521942017-07-31 12:42:41 -070051 });
52
53 if (res) libusb_claim_interface(res.get(), 0);
54
55 return res;
56}
57
Tomasz Wiszkowski8a40b252017-09-14 14:46:39 -070058} // anonymous namespace
59
60bool USBServer::GetDeviceInfo(
61 DeviceInfo* info, std::vector<InterfaceInfo>* ifaces) {
62 if (!handle_) return false;
Tomasz Wiszkowski85521942017-07-31 12:42:41 -070063
64 // This function does not modify the reference count of the returned device,
65 // so do not feel compelled to unreference it when you are done.
Tomasz Wiszkowski8a40b252017-09-14 14:46:39 -070066 libusb_device* dev = libusb_get_device(handle_.get());
Tomasz Wiszkowski85521942017-07-31 12:42:41 -070067
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -070068 libusb_device_descriptor desc;
69 libusb_config_descriptor* conf;
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -070070 memset(info, 0, sizeof(*info));
71
72 int res = libusb_get_device_descriptor(dev, &desc);
73 if (res < 0) {
74 // This shouldn't really happen.
75 ALOGE("libusb_get_device_descriptor failed %d", res);
Tomasz Wiszkowski85521942017-07-31 12:42:41 -070076 return false;
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -070077 }
78
79 res = libusb_get_active_config_descriptor(dev, &conf);
80 if (res < 0) {
81 // This shouldn't really happen.
82 ALOGE("libusb_get_active_config_descriptor failed %d", res);
83 libusb_free_config_descriptor(conf);
Tomasz Wiszkowski85521942017-07-31 12:42:41 -070084 return false;
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -070085 }
86
87 info->vendor_id = desc.idVendor;
88 info->product_id = desc.idProduct;
89 info->dev_version = desc.bcdDevice;
90 info->dev_class = desc.bDeviceClass;
91 info->dev_subclass = desc.bDeviceSubClass;
92 info->dev_protocol = desc.bDeviceProtocol;
93 info->speed = libusb_get_device_speed(dev);
94 info->num_configurations = desc.bNumConfigurations;
95 info->num_interfaces = conf->bNumInterfaces;
96 info->cur_configuration = conf->bConfigurationValue;
Tomasz Wiszkowski85521942017-07-31 12:42:41 -070097 info->bus_id = kDefaultBusID;
98 info->dev_id = kDefaultDevID;
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -070099
100 if (ifaces != nullptr) {
101 for (int ifidx = 0; ifidx < conf->bNumInterfaces; ++ifidx) {
102 const libusb_interface& iface = conf->interface[ifidx];
103 for (int altidx = 0; altidx < iface.num_altsetting; ++altidx) {
104 const libusb_interface_descriptor& alt = iface.altsetting[altidx];
105 ifaces->push_back(InterfaceInfo{alt.bInterfaceClass,
106 alt.bInterfaceSubClass,
107 alt.bInterfaceProtocol, 0});
108 }
109 }
110 }
111 libusb_free_config_descriptor(conf);
Tomasz Wiszkowski85521942017-07-31 12:42:41 -0700112 return true;
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -0700113}
Tomasz Wiszkowski9915c6c2017-08-03 14:20:43 -0700114
Greg Hartman153b1062017-11-11 12:09:21 -0800115USBServer::USBServer(const cvd::SharedFD& fd)
Tomasz Wiszkowski8a40b252017-09-14 14:46:39 -0700116 : fd_{fd},
Greg Hartman153b1062017-11-11 12:09:21 -0800117 device_event_fd_{cvd::SharedFD::Event(0, 0)},
118 thread_event_fd_{cvd::SharedFD::Event(0, 0)} {}
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700119
120void USBServer::HandleDeviceList(uint32_t tag) {
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -0700121 // Iterate all devices and send structure for every found device.
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -0700122 // Write header: number of devices.
Tomasz Wiszkowski85521942017-07-31 12:42:41 -0700123 DeviceInfo info;
124 std::vector<InterfaceInfo> ifaces;
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700125 bool found = GetDeviceInfo(&info, &ifaces);
126
Greg Hartman153b1062017-11-11 12:09:21 -0800127 cvd::LockGuard<cvd::Mutex> lock(write_mutex_);
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700128 ResponseHeader rsp{StatusSuccess, tag};
129 fd_->Write(&rsp, sizeof(rsp));
130 if (found) {
Tomasz Wiszkowski85521942017-07-31 12:42:41 -0700131 uint32_t cnt = 1;
132 fd_->Write(&cnt, sizeof(cnt));
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -0700133 fd_->Write(&info, sizeof(info));
134 fd_->Write(ifaces.data(), ifaces.size() * sizeof(InterfaceInfo));
Tomasz Wiszkowski85521942017-07-31 12:42:41 -0700135 } else {
136 // No devices.
137 uint32_t cnt = 0;
138 fd_->Write(&cnt, sizeof(cnt));
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -0700139 }
140}
141
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700142void USBServer::HandleAttach(uint32_t tag) {
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700143 // We read the request, but it no longer plays any significant role here.
144 AttachRequest req;
145 if (fd_->Read(&req, sizeof(req)) != sizeof(req)) return;
146
Greg Hartman153b1062017-11-11 12:09:21 -0800147 cvd::LockGuard<cvd::Mutex> lock(write_mutex_);
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700148 ResponseHeader rsp{handle_ ? StatusSuccess : StatusFailure, tag};
149 fd_->Write(&rsp, sizeof(rsp));
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -0700150}
151
Tomasz Wiszkowskicdf57482017-08-14 12:47:25 -0700152void USBServer::HandleHeartbeat(uint32_t tag) {
Greg Hartman153b1062017-11-11 12:09:21 -0800153 cvd::LockGuard<cvd::Mutex> lock(write_mutex_);
Tomasz Wiszkowski8a40b252017-09-14 14:46:39 -0700154 ResponseHeader rsp{handle_ ? StatusSuccess : StatusFailure, tag};
Tomasz Wiszkowskicdf57482017-08-14 12:47:25 -0700155 fd_->Write(&rsp, sizeof(rsp));
156}
157
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700158void USBServer::HandleControlTransfer(uint32_t tag) {
Tomasz Wiszkowski25530102017-07-28 09:33:07 -0700159 ControlTransfer req;
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -0700160 // If disconnected prematurely, don't send response.
161 if (fd_->Read(&req, sizeof(req)) != sizeof(req)) return;
162
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700163 // Technically speaking this isn't endpoint, but names, masks, values and
164 // meaning here is exactly same.
165 bool is_data_in =
166 ((req.type & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN);
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -0700167
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700168 std::unique_ptr<TransportRequest> treq(new TransportRequest(
Tomasz Wiszkowski482292e2017-08-04 16:33:00 -0700169 handle_,
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700170 [this, is_data_in, tag](bool is_success, const uint8_t* data,
171 int32_t length) {
172 OnTransferComplete(tag, is_data_in, is_success, data, length);
173 },
174 req));
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -0700175
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700176 if (!is_data_in && req.length) {
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -0700177 // If disconnected prematurely, don't send response.
Tomasz Wiszkowski9915c6c2017-08-03 14:20:43 -0700178 int32_t got = 0;
179 while (got < req.length) {
180 auto read = fd_->Read(&treq->Buffer()[got], req.length - got);
181 if (fd_->GetErrno() != 0) {
182 ALOGE("Failed to read from client: %s", fd_->StrError());
183 return;
184 } else if (read == 0) {
185 ALOGE("Failed to read from client: short read");
186 return;
187 }
188 got += read;
189 }
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -0700190 }
191
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700192 // At this point we store transport request internally until it completes.
193 TransportRequest* treq_ptr = treq.get();
194 {
Greg Hartman153b1062017-11-11 12:09:21 -0800195 cvd::LockGuard<cvd::Mutex> lock(requests_mutex_);
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700196 requests_in_flight_[tag] = std::move(treq);
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -0700197 }
198
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700199 if (!treq_ptr->Submit()) {
200 OnTransferComplete(tag, is_data_in, false, nullptr, 0);
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -0700201 }
202}
203
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700204void USBServer::HandleDataTransfer(uint32_t tag) {
Tomasz Wiszkowski25530102017-07-28 09:33:07 -0700205 DataTransfer req;
206 // If disconnected prematurely, don't send response.
207 if (fd_->Read(&req, sizeof(req)) != sizeof(req)) return;
208
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700209 bool is_data_in = !req.is_host_to_device;
Tomasz Wiszkowski25530102017-07-28 09:33:07 -0700210
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700211 std::unique_ptr<TransportRequest> treq(new TransportRequest(
Tomasz Wiszkowski482292e2017-08-04 16:33:00 -0700212 handle_,
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700213 [this, is_data_in, tag](bool is_success, const uint8_t* data,
214 int32_t length) {
215 OnTransferComplete(tag, is_data_in, is_success, data, length);
216 },
217 req));
218
219 if (!is_data_in && req.length) {
Tomasz Wiszkowski25530102017-07-28 09:33:07 -0700220 // If disconnected prematurely, don't send response.
Tomasz Wiszkowski9915c6c2017-08-03 14:20:43 -0700221 int32_t got = 0;
222 while (got < req.length) {
223 auto read = fd_->Read(&treq->Buffer()[got], req.length - got);
224 if (fd_->GetErrno() != 0) {
225 ALOGE("Failed to read from client: %s", fd_->StrError());
226 return;
227 } else if (read == 0) {
228 ALOGE("Failed to read from client: short read");
229 return;
230 }
231 got += read;
232 }
Tomasz Wiszkowski25530102017-07-28 09:33:07 -0700233 }
234
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700235 // At this point we store transport request internally until it completes.
236 TransportRequest* treq_ptr = treq.get();
237 {
Greg Hartman153b1062017-11-11 12:09:21 -0800238 cvd::LockGuard<cvd::Mutex> lock(requests_mutex_);
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700239 requests_in_flight_[tag] = std::move(treq);
Tomasz Wiszkowski25530102017-07-28 09:33:07 -0700240 }
241
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700242 if (!treq_ptr->Submit()) {
243 OnTransferComplete(tag, is_data_in, false, nullptr, 0);
244 }
245}
Tomasz Wiszkowski25530102017-07-28 09:33:07 -0700246
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700247void USBServer::OnTransferComplete(uint32_t tag, bool is_data_in,
248 bool is_success, const uint8_t* buffer,
249 int32_t actual_length) {
250 ResponseHeader rsp{is_success ? StatusSuccess : StatusFailure, tag};
251
Greg Hartman153b1062017-11-11 12:09:21 -0800252 cvd::LockGuard<cvd::Mutex> lock(write_mutex_);
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700253 fd_->Write(&rsp, sizeof(rsp));
254 if (is_success && is_data_in) {
255 fd_->Write(&actual_length, sizeof(actual_length));
256 if (actual_length > 0) {
257 // NOTE: don't use buffer_ here directly, as libusb uses first few bytes
258 // to store control data there.
Tomasz Wiszkowski9915c6c2017-08-03 14:20:43 -0700259 int32_t sent = 0;
260 while (sent < actual_length) {
261 int packet_size = fd_->Write(&buffer[sent], actual_length - sent);
262 sent += packet_size;
Greg Hartman41e939e2017-08-17 12:43:00 -0700263 ALOGV("Sending response, %d / %d bytes sent", sent, actual_length);
Tomasz Wiszkowski9915c6c2017-08-03 14:20:43 -0700264 if (fd_->GetErrno() != 0) {
265 ALOGE("Send failed: %s", fd_->StrError());
266 return;
267 }
268 }
Tomasz Wiszkowski25530102017-07-28 09:33:07 -0700269 }
270 }
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700271
272 {
Greg Hartman153b1062017-11-11 12:09:21 -0800273 cvd::LockGuard<cvd::Mutex> lock(requests_mutex_);
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700274 requests_in_flight_.erase(tag);
275 }
Tomasz Wiszkowski25530102017-07-28 09:33:07 -0700276}
277
Tomasz Wiszkowski482292e2017-08-04 16:33:00 -0700278int USBServer::HandleDeviceEvent(libusb_context*, libusb_device*,
279 libusb_hotplug_event event, void* self_raw) {
280 auto self = reinterpret_cast<USBServer*>(self_raw);
Tomasz Wiszkowski8a40b252017-09-14 14:46:39 -0700281 int64_t dummy = 1;
282 self->device_event_fd_->Write(&dummy, sizeof(dummy));
Tomasz Wiszkowski482292e2017-08-04 16:33:00 -0700283 return 0;
284}
285
Tomasz Wiszkowski8a40b252017-09-14 14:46:39 -0700286void* USBServer::ProcessLibUSBRequests(void* self_raw) {
287 USBServer* self = reinterpret_cast<USBServer*>(self_raw);
288 ALOGI("Starting hotplug thread.");
Tomasz Wiszkowski482292e2017-08-04 16:33:00 -0700289
Greg Hartman153b1062017-11-11 12:09:21 -0800290 cvd::SharedFDSet rset;
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -0700291 while (true) {
Tomasz Wiszkowski8a40b252017-09-14 14:46:39 -0700292 // Do not wait if there's no event.
293 timeval select_timeout{0, 0};
294 rset.Zero();
295 rset.Set(self->thread_event_fd_);
Greg Hartman153b1062017-11-11 12:09:21 -0800296 int ret = cvd::Select(&rset, nullptr, nullptr, &select_timeout);
Tomasz Wiszkowski8a40b252017-09-14 14:46:39 -0700297 if (ret > 0) break;
298
299 timeval libusb_timeout{1, 0};
300 libusb_handle_events_timeout_completed(nullptr, &libusb_timeout, nullptr);
301 }
302
303 int64_t dummy;
304 self->thread_event_fd_->Read(&dummy, sizeof(dummy));
305 ALOGI("Shutting down hotplug thread.");
306 return nullptr;
307}
308
309void USBServer::InitLibUSB() {
310 if (libusb_init(nullptr) != 0) return;
311 libusb_hotplug_register_callback(
312 nullptr,
313 libusb_hotplug_event(LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT),
314 libusb_hotplug_flag(0), kExportedVendorID, kExportedProductID,
315 LIBUSB_HOTPLUG_MATCH_ANY, &USBServer::HandleDeviceEvent, this,
316 &hotplug_handle_);
317 handle_ = GetDevice();
Greg Hartman153b1062017-11-11 12:09:21 -0800318 libusb_thread_.reset(new cvd::ScopedThread(&ProcessLibUSBRequests, this));
Tomasz Wiszkowski8a40b252017-09-14 14:46:39 -0700319}
320
321void USBServer::ExitLibUSB() {
322 if (!libusb_thread_) return;
323 libusb_hotplug_deregister_callback(nullptr, hotplug_handle_);
324 int64_t dummy = 1;
325 thread_event_fd_->Write(&dummy, sizeof(dummy));
326 libusb_thread_.reset();
327 handle_.reset();
328 libusb_exit(nullptr);
329}
330
331void USBServer::Serve() {
Greg Hartman153b1062017-11-11 12:09:21 -0800332 cvd::SharedFDSet rset;
Tomasz Wiszkowski8a40b252017-09-14 14:46:39 -0700333 while (true) {
334 timeval retry_timeout{1, 0};
335 timeval* select_timeout = nullptr;
336 if (!handle_) {
337 select_timeout = &retry_timeout;
338 }
339
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -0700340 rset.Zero();
341 rset.Set(fd_);
Tomasz Wiszkowski8a40b252017-09-14 14:46:39 -0700342 rset.Set(device_event_fd_);
Greg Hartman153b1062017-11-11 12:09:21 -0800343 int ret = cvd::Select(&rset, nullptr, nullptr, select_timeout);
Tomasz Wiszkowski8a40b252017-09-14 14:46:39 -0700344
345 // device_event_fd_ is reset each time libusb notices device has re-appeared
346 // or is gone. In both cases, the existing handle is no longer valid.
347 if (rset.IsSet(device_event_fd_)) {
348 int64_t dummy;
349 device_event_fd_->Read(&dummy, sizeof(dummy));
350 handle_.reset();
351 }
352
353 if (!handle_) {
354 ExitLibUSB();
355 InitLibUSB();
356 if (handle_) {
357 ALOGI("Device present.");
358 }
359 }
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -0700360
361 if (ret < 0) continue;
362
363 if (rset.IsSet(fd_)) {
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700364 RequestHeader req;
Tomasz Wiszkowski9915c6c2017-08-03 14:20:43 -0700365 if (fd_->Read(&req, sizeof(req)) != sizeof(req)) {
Tomasz Wiszkowski85521942017-07-31 12:42:41 -0700366 // There's nobody on the other side.
367 sleep(3);
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -0700368 continue;
369 }
370
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700371 switch (req.command) {
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -0700372 case CmdDeviceList:
Tomasz Wiszkowski9915c6c2017-08-03 14:20:43 -0700373 ALOGV("Processing DeviceList command, tag=%d", req.tag);
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700374 HandleDeviceList(req.tag);
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -0700375 break;
376
377 case CmdAttach:
Tomasz Wiszkowski9915c6c2017-08-03 14:20:43 -0700378 ALOGV("Processing Attach command, tag=%d", req.tag);
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700379 HandleAttach(req.tag);
Tomasz Wiszkowski9915c6c2017-08-03 14:20:43 -0700380 break;
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -0700381
Tomasz Wiszkowski25530102017-07-28 09:33:07 -0700382 case CmdControlTransfer:
Tomasz Wiszkowski9915c6c2017-08-03 14:20:43 -0700383 ALOGV("Processing ControlTransfer command, tag=%d", req.tag);
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700384 HandleControlTransfer(req.tag);
Tomasz Wiszkowski25530102017-07-28 09:33:07 -0700385 break;
386
387 case CmdDataTransfer:
Tomasz Wiszkowski9915c6c2017-08-03 14:20:43 -0700388 ALOGV("Processing DataTransfer command, tag=%d", req.tag);
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700389 HandleDataTransfer(req.tag);
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -0700390 break;
391
Tomasz Wiszkowskicdf57482017-08-14 12:47:25 -0700392 case CmdHeartbeat:
393 ALOGV("Processing Heartbeat command, tag=%d", req.tag);
394 HandleHeartbeat(req.tag);
395 break;
396
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -0700397 default:
Tomasz Wiszkowski9915c6c2017-08-03 14:20:43 -0700398 ALOGE("Discarding unknown command %08x, tag=%d", req.command,
399 req.tag);
Tomasz Wiszkowskiae4ff632017-07-20 14:56:16 -0700400 }
401 }
402 }
403}
Tomasz Wiszkowski9cbe5552017-08-01 16:11:05 -0700404
Tomasz Wiszkowskicdf57482017-08-14 12:47:25 -0700405} // namespace usb_forward