1 /*
2 * Copyright (C) 2020 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 #define LOG_TAG "android.hardware.usb.gadget.aidl-service"
18
19 #include "UsbGadget.h"
20 #include <fcntl.h>
21 #include <stdio.h>
22 #include <sys/inotify.h>
23 #include <sys/mount.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27
28 #include<android-base/properties.h>
29
30 #include <aidl/android/frameworks/stats/IStats.h>
31 #include <pixelusb/I2cHelper.h>
32
33 namespace aidl {
34 namespace android {
35 namespace hardware {
36 namespace usb {
37 namespace gadget {
38 #define NUM_HSI2C_PATHS 2
39
40 using ::android::hardware::google::pixel::usb::getI2cClientPath;
41
42 using ::android::base::GetBoolProperty;
43 using ::android::hardware::google::pixel::usb::kUvcEnabled;
44
45 string enabledPath;
46 constexpr char* kHsi2cPaths[] = { (char *) "/sys/devices/platform/108d0000.hsi2c",
47 (char *) "/sys/devices/platform/10cb0000.hsi2c" };
48 constexpr char kTcpcDevName[] = "i2c-max77759tcpc";
49 constexpr char kI2cClientId[] = "0025";
50 constexpr char kAccessoryLimitCurrent[] = "usb_limit_accessory_current";
51 constexpr char kAccessoryLimitCurrentEnable[] = "usb_limit_accessory_enable";
52
UsbGadget()53 UsbGadget::UsbGadget() : mGadgetIrqPath(""),
54 mI2cClientPath("") {
55 if (access(OS_DESC_PATH, R_OK) != 0) {
56 ALOGE("configfs setup not done yet");
57 abort();
58 }
59 }
60
getUsbGadgetIrqPath()61 Status UsbGadget::getUsbGadgetIrqPath() {
62 std::string irqs;
63 size_t read_pos = 0;
64 size_t found_pos = 0;
65
66 if (!ReadFileToString(kProcInterruptsPath, &irqs)) {
67 ALOGE("cannot read all interrupts");
68 return Status::ERROR;
69 }
70
71 while (true) {
72 found_pos = irqs.find_first_of("\n", read_pos);
73 if (found_pos == std::string::npos) {
74 ALOGI("the string of all interrupts is unexpected");
75 return Status::ERROR;
76 }
77
78 std::string single_irq = irqs.substr(read_pos, found_pos - read_pos);
79
80 if (single_irq.find("dwc3", 0) != std::string::npos) {
81 unsigned int dwc3_irq_number;
82 size_t dwc3_pos = single_irq.find_first_of(":");
83 if (!ParseUint(single_irq.substr(0, dwc3_pos), &dwc3_irq_number)) {
84 ALOGI("unknown IRQ strings");
85 return Status::ERROR;
86 }
87
88 mGadgetIrqPath = kProcIrqPath + single_irq.substr(0, dwc3_pos) + kSmpAffinityList;
89 break;
90 }
91
92 if (found_pos == irqs.npos) {
93 ALOGI("USB gadget doesn't start");
94 return Status::ERROR;
95 }
96
97 read_pos = found_pos + 1;
98 }
99
100 return Status::SUCCESS;
101 }
102
currentFunctionsAppliedCallback(bool functionsApplied,void * payload)103 void currentFunctionsAppliedCallback(bool functionsApplied, void *payload) {
104 UsbGadget *gadget = (UsbGadget *)payload;
105 gadget->mCurrentUsbFunctionsApplied = functionsApplied;
106 }
107
getCurrentUsbFunctions(const shared_ptr<IUsbGadgetCallback> & callback,int64_t in_transactionId)108 ScopedAStatus UsbGadget::getCurrentUsbFunctions(const shared_ptr<IUsbGadgetCallback> &callback,
109 int64_t in_transactionId) {
110 ScopedAStatus ret = callback->getCurrentUsbFunctionsCb(
111 mCurrentUsbFunctions,
112 mCurrentUsbFunctionsApplied ? Status::FUNCTIONS_APPLIED : Status::FUNCTIONS_NOT_APPLIED,
113 in_transactionId);
114 if (!ret.isOk())
115 ALOGE("Call to getCurrentUsbFunctionsCb failed %s", ret.getDescription().c_str());
116
117 return ScopedAStatus::ok();
118 }
119
getUsbSpeed(const shared_ptr<IUsbGadgetCallback> & callback,int64_t in_transactionId)120 ScopedAStatus UsbGadget::getUsbSpeed(const shared_ptr<IUsbGadgetCallback> &callback,
121 int64_t in_transactionId) {
122 std::string current_speed;
123 if (ReadFileToString(SPEED_PATH, ¤t_speed)) {
124 current_speed = Trim(current_speed);
125 ALOGI("current USB speed is %s", current_speed.c_str());
126 if (current_speed == "low-speed")
127 mUsbSpeed = UsbSpeed::LOWSPEED;
128 else if (current_speed == "full-speed")
129 mUsbSpeed = UsbSpeed::FULLSPEED;
130 else if (current_speed == "high-speed")
131 mUsbSpeed = UsbSpeed::HIGHSPEED;
132 else if (current_speed == "super-speed")
133 mUsbSpeed = UsbSpeed::SUPERSPEED;
134 else if (current_speed == "super-speed-plus")
135 mUsbSpeed = UsbSpeed::SUPERSPEED_10Gb;
136 else if (current_speed == "UNKNOWN")
137 mUsbSpeed = UsbSpeed::UNKNOWN;
138 else
139 mUsbSpeed = UsbSpeed::UNKNOWN;
140 } else {
141 ALOGE("Fail to read current speed");
142 mUsbSpeed = UsbSpeed::UNKNOWN;
143 }
144
145 if (callback) {
146 ScopedAStatus ret = callback->getUsbSpeedCb(mUsbSpeed, in_transactionId);
147
148 if (!ret.isOk())
149 ALOGE("Call to getUsbSpeedCb failed %s", ret.getDescription().c_str());
150 }
151
152 return ScopedAStatus::ok();
153 }
154
tearDownGadget()155 Status UsbGadget::tearDownGadget() {
156 if (Status(resetGadget()) != Status::SUCCESS){
157 return Status::ERROR;
158 }
159
160 if (monitorFfs.isMonitorRunning()) {
161 monitorFfs.reset();
162 } else {
163 ALOGI("mMonitor not running");
164 }
165 return Status::SUCCESS;
166 }
167
validateAndSetVidPid(uint64_t functions)168 static Status validateAndSetVidPid(uint64_t functions) {
169 Status ret = Status::SUCCESS;
170 std::string vendorFunctions = getVendorFunctions();
171
172 switch (functions) {
173 case GadgetFunction::MTP:
174 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
175 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
176 ret = Status::CONFIGURATION_NOT_SUPPORTED;
177 } else {
178 ret = Status(setVidPid("0x18d1", "0x4ee1"));
179 }
180 break;
181 case GadgetFunction::ADB |
182 GadgetFunction::MTP:
183 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
184 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
185 ret = Status::CONFIGURATION_NOT_SUPPORTED;
186 } else {
187 ret = Status(setVidPid("0x18d1", "0x4ee2"));
188 }
189 break;
190 case GadgetFunction::RNDIS:
191 case GadgetFunction::RNDIS |
192 GadgetFunction::NCM:
193 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
194 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
195 ret = Status::CONFIGURATION_NOT_SUPPORTED;
196 } else {
197 ret = Status(setVidPid("0x18d1", "0x4ee3"));
198 }
199 break;
200 case GadgetFunction::ADB |
201 GadgetFunction::RNDIS:
202 case GadgetFunction::ADB |
203 GadgetFunction::RNDIS |
204 GadgetFunction::NCM:
205 if (vendorFunctions == "dm") {
206 ret = Status(setVidPid("0x04e8", "0x6862"));
207 } else {
208 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
209 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
210 ret = Status::CONFIGURATION_NOT_SUPPORTED;
211 } else {
212 ret = Status(setVidPid("0x18d1", "0x4ee4"));
213 }
214 }
215 break;
216 case GadgetFunction::PTP:
217 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
218 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
219 ret = Status::CONFIGURATION_NOT_SUPPORTED;
220 } else {
221 ret = Status(setVidPid("0x18d1", "0x4ee5"));
222 }
223 break;
224 case GadgetFunction::ADB |
225 GadgetFunction::PTP:
226 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
227 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
228 ret = Status::CONFIGURATION_NOT_SUPPORTED;
229 } else {
230 ret = Status(setVidPid("0x18d1", "0x4ee6"));
231 }
232 break;
233 case GadgetFunction::ADB:
234 if (vendorFunctions == "dm") {
235 ret = Status(setVidPid("0x04e8", "0x6862"));
236 } else if (vendorFunctions == "etr_miu") {
237 ret = Status(setVidPid("0x18d1", "0x4ee2"));
238 } else if (vendorFunctions == "uwb_acm"){
239 ret = Status(setVidPid("0x18d1", "0x4ee2"));
240 } else {
241 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
242 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
243 ret = Status::CONFIGURATION_NOT_SUPPORTED;
244 } else {
245 ret = Status(setVidPid("0x18d1", "0x4ee7"));
246 }
247 }
248 break;
249 case GadgetFunction::MIDI:
250 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
251 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
252 ret = Status::CONFIGURATION_NOT_SUPPORTED;
253 } else {
254 ret = Status(setVidPid("0x18d1", "0x4ee8"));
255 }
256 break;
257 case GadgetFunction::ADB |
258 GadgetFunction::MIDI:
259 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
260 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
261 ret = Status::CONFIGURATION_NOT_SUPPORTED;
262 } else {
263 ret = Status(setVidPid("0x18d1", "0x4ee9"));
264 }
265 break;
266 case GadgetFunction::ACCESSORY:
267 if (!(vendorFunctions == "user" || vendorFunctions == ""))
268 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
269 ret = Status(setVidPid("0x18d1", "0x2d00"));
270 break;
271 case GadgetFunction::ADB |
272 GadgetFunction::ACCESSORY:
273 if (!(vendorFunctions == "user" || vendorFunctions == ""))
274 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
275 ret = Status(setVidPid("0x18d1", "0x2d01"));
276 break;
277 case GadgetFunction::AUDIO_SOURCE:
278 if (!(vendorFunctions == "user" || vendorFunctions == ""))
279 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
280 ret = Status(setVidPid("0x18d1", "0x2d02"));
281 break;
282 case GadgetFunction::ADB |
283 GadgetFunction::AUDIO_SOURCE:
284 if (!(vendorFunctions == "user" || vendorFunctions == ""))
285 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
286 ret = Status(setVidPid("0x18d1", "0x2d03"));
287 break;
288 case GadgetFunction::ACCESSORY |
289 GadgetFunction::AUDIO_SOURCE:
290 if (!(vendorFunctions == "user" || vendorFunctions == ""))
291 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
292 ret = Status(setVidPid("0x18d1", "0x2d04"));
293 break;
294 case GadgetFunction::ADB |
295 GadgetFunction::ACCESSORY |
296 GadgetFunction::AUDIO_SOURCE:
297 if (!(vendorFunctions == "user" || vendorFunctions == ""))
298 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
299 ret = Status(setVidPid("0x18d1", "0x2d05"));
300 break;
301 case GadgetFunction::NCM:
302 if (!(vendorFunctions == "user" || vendorFunctions == ""))
303 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
304 ret = Status(setVidPid("0x18d1", "0x4eeb"));
305 break;
306 case GadgetFunction::ADB |
307 GadgetFunction::NCM:
308 if (vendorFunctions == "dm") {
309 ret = Status(setVidPid("0x04e8", "0x6862"));
310 } else {
311 if (!(vendorFunctions == "user" || vendorFunctions == ""))
312 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
313 ret = Status(setVidPid("0x18d1", "0x4eec"));
314 }
315 break;
316 case GadgetFunction::UVC:
317 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
318 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
319 ret = Status::CONFIGURATION_NOT_SUPPORTED;
320 } else if (!GetBoolProperty(kUvcEnabled, false)) {
321 ALOGE("UVC function not enabled by config");
322 ret = Status::CONFIGURATION_NOT_SUPPORTED;
323 } else {
324 ret = Status(setVidPid("0x18d1", "0x4eed"));
325 }
326 break;
327 case GadgetFunction::ADB | GadgetFunction::UVC:
328 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
329 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
330 ret = Status::CONFIGURATION_NOT_SUPPORTED;
331 } else if (!GetBoolProperty(kUvcEnabled, false)) {
332 ALOGE("UVC function not enabled by config");
333 ret = Status::CONFIGURATION_NOT_SUPPORTED;
334 } else {
335 ret = Status(setVidPid("0x18d1", "0x4eee"));
336 }
337 break;
338 default:
339 ALOGE("Combination not supported");
340 ret = Status::CONFIGURATION_NOT_SUPPORTED;
341 }
342 return ret;
343 }
344
reset(const shared_ptr<IUsbGadgetCallback> & callback,int64_t in_transactionId)345 ScopedAStatus UsbGadget::reset(const shared_ptr<IUsbGadgetCallback> &callback,
346 int64_t in_transactionId) {
347 ALOGI("USB Gadget reset");
348
349 if (!WriteStringToFile("none", PULLUP_PATH)) {
350 ALOGI("Gadget cannot be pulled down");
351 if (callback)
352 callback->resetCb(Status::ERROR, in_transactionId);
353 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
354 -1, "Gadget cannot be pulled down");
355 }
356
357 usleep(kDisconnectWaitUs);
358
359 if (!WriteStringToFile(kGadgetName, PULLUP_PATH)) {
360 ALOGI("Gadget cannot be pulled up");
361 if (callback)
362 callback->resetCb(Status::ERROR, in_transactionId);
363 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
364 -1, "Gadget cannot be pulled up");
365 }
366 if (callback)
367 callback->resetCb(Status::SUCCESS, in_transactionId);
368
369 return ScopedAStatus::ok();
370 }
371
setupFunctions(long functions,const shared_ptr<IUsbGadgetCallback> & callback,uint64_t timeout,int64_t in_transactionId)372 Status UsbGadget::setupFunctions(long functions,
373 const shared_ptr<IUsbGadgetCallback> &callback, uint64_t timeout,
374 int64_t in_transactionId) {
375 bool ffsEnabled = false;
376 int i = 0;
377
378 if (Status(addGenericAndroidFunctions(&monitorFfs, functions, &ffsEnabled, &i)) !=
379 Status::SUCCESS)
380 return Status::ERROR;
381
382 std::string vendorFunctions = getVendorFunctions();
383
384 if (((functions & GadgetFunction::NCM) != 0) && (vendorFunctions != "dm")) {
385 if (linkFunction("ncm.gs9", i++))
386 return Status::ERROR;
387 }
388
389 if (vendorFunctions == "dm") {
390 ALOGI("enable usbradio debug functions");
391 if ((functions & GadgetFunction::RNDIS) != 0) {
392 if (linkFunction("acm.gs6", i++))
393 return Status::ERROR;
394 if (linkFunction("dm.gs7", i++))
395 return Status::ERROR;
396 } else {
397 if (linkFunction("dm.gs7", i++))
398 return Status::ERROR;
399 if (linkFunction("acm.gs6", i++))
400 return Status::ERROR;
401 }
402 } else if (vendorFunctions == "etr_miu") {
403 ALOGI("enable etr_miu functions");
404 if (linkFunction("etr_miu.gs11", i++))
405 return Status::ERROR;
406 } else if (vendorFunctions == "uwb_acm") {
407 ALOGI("enable uwb acm function");
408 if (linkFunction("acm.uwb0", i++))
409 return Status::ERROR;
410 }
411
412 if ((functions & GadgetFunction::ADB) != 0) {
413 ffsEnabled = true;
414 if (Status(addAdb(&monitorFfs, &i)) != Status::SUCCESS)
415 return Status::ERROR;
416 }
417
418 if (((functions & GadgetFunction::NCM) != 0) && (vendorFunctions == "dm")) {
419 if (linkFunction("ncm.gs9", i++))
420 return Status::ERROR;
421 }
422
423 // Pull up the gadget right away when there are no ffs functions.
424 if (!ffsEnabled) {
425 if (!WriteStringToFile(kGadgetName, PULLUP_PATH))
426 return Status::ERROR;
427 mCurrentUsbFunctionsApplied = true;
428 if (callback)
429 callback->setCurrentUsbFunctionsCb(functions, Status::SUCCESS, in_transactionId);
430 return Status::SUCCESS;
431 }
432
433 monitorFfs.registerFunctionsAppliedCallback(¤tFunctionsAppliedCallback, this);
434 // Monitors the ffs paths to pull up the gadget when descriptors are written.
435 // Also takes of the pulling up the gadget again if the userspace process
436 // dies and restarts.
437 monitorFfs.startMonitor();
438
439 if (kDebug)
440 ALOGI("Mainthread in Cv");
441
442 if (callback) {
443 bool pullup = monitorFfs.waitForPullUp(timeout);
444 ScopedAStatus ret = callback->setCurrentUsbFunctionsCb(
445 functions, pullup ? Status::SUCCESS : Status::ERROR, in_transactionId);
446 if (!ret.isOk()) {
447 ALOGE("setCurrentUsbFunctionsCb error %s", ret.getDescription().c_str());
448 return Status::ERROR;
449 }
450 }
451 return Status::SUCCESS;
452 }
453
setCurrentUsbFunctions(long functions,const shared_ptr<IUsbGadgetCallback> & callback,int64_t timeout,int64_t in_transactionId)454 ScopedAStatus UsbGadget::setCurrentUsbFunctions(long functions,
455 const shared_ptr<IUsbGadgetCallback> &callback,
456 int64_t timeout,
457 int64_t in_transactionId) {
458 std::unique_lock<std::mutex> lk(mLockSetCurrentFunction);
459 std::string current_usb_power_operation_mode, current_usb_type;
460 std::string usb_limit_sink_enable;
461 std::string accessoryCurrentLimitEnablePath, accessoryCurrentLimitPath;
462
463 mCurrentUsbFunctions = functions;
464 mCurrentUsbFunctionsApplied = false;
465
466 if (mI2cClientPath.empty()) {
467 for (int i = 0; i < NUM_HSI2C_PATHS; i++) {
468 mI2cClientPath = getI2cClientPath(kHsi2cPaths[i], kTcpcDevName, kI2cClientId);
469 if (mI2cClientPath.empty()) {
470 ALOGE("%s: Unable to locate i2c bus node", __func__);
471 } else {
472 break;
473 }
474 }
475 }
476 accessoryCurrentLimitPath = mI2cClientPath + kAccessoryLimitCurrent;
477 accessoryCurrentLimitEnablePath = mI2cClientPath + kAccessoryLimitCurrentEnable;
478
479 // Get the gadget IRQ number before tearDownGadget()
480 if (mGadgetIrqPath.empty())
481 getUsbGadgetIrqPath();
482
483 // Unlink the gadget and stop the monitor if running.
484 Status status = tearDownGadget();
485 if (status != Status::SUCCESS) {
486 goto error;
487 }
488
489 ALOGI("Returned from tearDown gadget");
490
491 // Leave the gadget pulled down to give time for the host to sense disconnect.
492 usleep(kDisconnectWaitUs);
493
494 if (functions == GadgetFunction::NONE) {
495 if (callback == NULL)
496 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
497 -1, "callback == NULL");
498 ScopedAStatus ret = callback->setCurrentUsbFunctionsCb(functions, Status::SUCCESS, in_transactionId);
499 if (!ret.isOk())
500 ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.getDescription().c_str());
501 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
502 -1, "Error while calling setCurrentUsbFunctionsCb");
503 }
504
505 status = validateAndSetVidPid(functions);
506
507 if (status != Status::SUCCESS) {
508 goto error;
509 }
510
511 status = setupFunctions(functions, callback, timeout, in_transactionId);
512 if (status != Status::SUCCESS) {
513 goto error;
514 }
515
516 if (functions & GadgetFunction::NCM) {
517 if (!mGadgetIrqPath.empty()) {
518 if (!WriteStringToFile(BIG_CORE, mGadgetIrqPath))
519 ALOGI("Cannot move gadget IRQ to big core, path:%s", mGadgetIrqPath.c_str());
520 }
521 } else {
522 if (!mGadgetIrqPath.empty()) {
523 if (!WriteStringToFile(MEDIUM_CORE, mGadgetIrqPath))
524 ALOGI("Cannot move gadget IRQ to medium core, path:%s", mGadgetIrqPath.c_str());
525 }
526 }
527
528 if (ReadFileToString(CURRENT_USB_TYPE_PATH, ¤t_usb_type))
529 current_usb_type = Trim(current_usb_type);
530
531 if (ReadFileToString(CURRENT_USB_POWER_OPERATION_MODE_PATH, ¤t_usb_power_operation_mode))
532 current_usb_power_operation_mode = Trim(current_usb_power_operation_mode);
533
534 if (functions & GadgetFunction::ACCESSORY &&
535 current_usb_type == "Unknown SDP [CDP] DCP" &&
536 (current_usb_power_operation_mode == "default" ||
537 current_usb_power_operation_mode == "1.5A")) {
538 if (!WriteStringToFile("1300000", accessoryCurrentLimitPath)) {
539 ALOGI("Write 1.3A to limit current fail");
540 } else {
541 if (!WriteStringToFile("1", accessoryCurrentLimitEnablePath)) {
542 ALOGI("Enable limit current fail");
543 }
544 }
545 } else {
546 if (!WriteStringToFile("0", accessoryCurrentLimitEnablePath))
547 ALOGI("unvote accessory limit current failed");
548 }
549
550 ALOGI("Usb Gadget setcurrent functions called successfully");
551 return ScopedAStatus::ok();
552
553 error:
554 ALOGI("Usb Gadget setcurrent functions failed");
555 if (callback == NULL)
556 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
557 -1, "Usb Gadget setcurrent functions failed");
558 ScopedAStatus ret = callback->setCurrentUsbFunctionsCb(functions, status, in_transactionId);
559 if (!ret.isOk())
560 ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.getDescription().c_str());
561 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
562 -1, "Error while calling setCurrentUsbFunctionsCb");
563 }
564 } // namespace gadget
565 } // namespace usb
566 } // namespace hardware
567 } // namespace android
568 } // aidl
569