blob: 2000445dfcc19c40abbaabd088aaf84dea0ebe21 [file] [log] [blame]
Robin Pengc2b5ca92021-02-23 20:00:28 +08001/*
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
Ricky Niud6d0b7d2022-07-06 20:57:02 +080017#define LOG_TAG "android.hardware.usb.gadget.aidl-service"
Robin Pengc2b5ca92021-02-23 20:00:28 +080018
19#include "UsbGadget.h"
20#include <dirent.h>
21#include <fcntl.h>
22#include <stdio.h>
23#include <sys/inotify.h>
24#include <sys/mount.h>
25#include <sys/stat.h>
26#include <sys/types.h>
27#include <unistd.h>
28
Avichal Rakesheafdae62023-01-06 02:47:19 -080029#include <android-base/properties.h>
30
Ricky Niud6d0b7d2022-07-06 20:57:02 +080031#include <aidl/android/frameworks/stats/IStats.h>
32
33namespace aidl {
Robin Pengc2b5ca92021-02-23 20:00:28 +080034namespace android {
35namespace hardware {
36namespace usb {
37namespace gadget {
Robin Pengc2b5ca92021-02-23 20:00:28 +080038
Ricky Niuebd7fca2022-05-09 10:14:20 +080039string enabledPath;
40constexpr char kHsi2cPath[] = "/sys/devices/platform/10d50000.hsi2c";
41constexpr char kI2CPath[] = "/sys/devices/platform/10d50000.hsi2c/i2c-";
42constexpr char kAccessoryLimitCurrent[] = "i2c-max77759tcpc/usb_limit_accessory_current";
43constexpr char kAccessoryLimitCurrentEnable[] = "i2c-max77759tcpc/usb_limit_accessory_enable";
44
Avichal Rakesheafdae62023-01-06 02:47:19 -080045using ::android::base::GetBoolProperty;
46using ::android::hardware::google::pixel::usb::kUvcEnabled;
47
Ray Chiba3dc9b2022-03-01 21:57:03 +080048UsbGadget::UsbGadget() : mGadgetIrqPath("") {
Robin Pengc2b5ca92021-02-23 20:00:28 +080049 if (access(OS_DESC_PATH, R_OK) != 0) {
50 ALOGE("configfs setup not done yet");
51 abort();
52 }
53}
54
Ricky Niud6d0b7d2022-07-06 20:57:02 +080055Status UsbGadget::getUsbGadgetIrqPath() {
Ray Chiba3dc9b2022-03-01 21:57:03 +080056 std::string irqs;
57 size_t read_pos = 0;
58 size_t found_pos = 0;
59
60 if (!ReadFileToString(kProcInterruptsPath, &irqs)) {
61 ALOGE("cannot read all interrupts");
62 return Status::ERROR;
63 }
64
65 while (true) {
66 found_pos = irqs.find_first_of("\n", read_pos);
67 if (found_pos == std::string::npos) {
68 ALOGI("the string of all interrupts is unexpected");
69 return Status::ERROR;
70 }
71
72 std::string single_irq = irqs.substr(read_pos, found_pos - read_pos);
73
74 if (single_irq.find("dwc3", 0) != std::string::npos) {
75 unsigned int dwc3_irq_number;
76 size_t dwc3_pos = single_irq.find_first_of(":");
77 if (!ParseUint(single_irq.substr(0, dwc3_pos), &dwc3_irq_number)) {
78 ALOGI("unknown IRQ strings");
79 return Status::ERROR;
80 }
81
82 mGadgetIrqPath = kProcIrqPath + single_irq.substr(0, dwc3_pos) + kSmpAffinityList;
83 break;
84 }
85
86 if (found_pos == irqs.npos) {
87 ALOGI("USB gadget doesn't start");
88 return Status::ERROR;
89 }
90
91 read_pos = found_pos + 1;
92 }
93
94 return Status::SUCCESS;
95}
96
Robin Pengc2b5ca92021-02-23 20:00:28 +080097void currentFunctionsAppliedCallback(bool functionsApplied, void *payload) {
98 UsbGadget *gadget = (UsbGadget *)payload;
99 gadget->mCurrentUsbFunctionsApplied = functionsApplied;
100}
101
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800102ScopedAStatus UsbGadget::getCurrentUsbFunctions(const shared_ptr<IUsbGadgetCallback> &callback,
103 int64_t in_transactionId) {
104 ScopedAStatus ret = callback->getCurrentUsbFunctionsCb(
Robin Pengc2b5ca92021-02-23 20:00:28 +0800105 mCurrentUsbFunctions,
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800106 mCurrentUsbFunctionsApplied ? Status::FUNCTIONS_APPLIED : Status::FUNCTIONS_NOT_APPLIED,
107 in_transactionId);
Robin Pengc2b5ca92021-02-23 20:00:28 +0800108 if (!ret.isOk())
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800109 ALOGE("Call to getCurrentUsbFunctionsCb failed %s", ret.getDescription().c_str());
Robin Pengc2b5ca92021-02-23 20:00:28 +0800110
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800111 return ScopedAStatus::ok();
Robin Pengc2b5ca92021-02-23 20:00:28 +0800112}
113
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800114ScopedAStatus UsbGadget::getUsbSpeed(const shared_ptr<IUsbGadgetCallback> &callback,
115 int64_t in_transactionId) {
Robin Pengc2b5ca92021-02-23 20:00:28 +0800116 std::string current_speed;
117 if (ReadFileToString(SPEED_PATH, &current_speed)) {
118 current_speed = Trim(current_speed);
119 ALOGI("current USB speed is %s", current_speed.c_str());
120 if (current_speed == "low-speed")
121 mUsbSpeed = UsbSpeed::LOWSPEED;
122 else if (current_speed == "full-speed")
123 mUsbSpeed = UsbSpeed::FULLSPEED;
124 else if (current_speed == "high-speed")
125 mUsbSpeed = UsbSpeed::HIGHSPEED;
126 else if (current_speed == "super-speed")
127 mUsbSpeed = UsbSpeed::SUPERSPEED;
128 else if (current_speed == "super-speed-plus")
129 mUsbSpeed = UsbSpeed::SUPERSPEED_10Gb;
130 else if (current_speed == "UNKNOWN")
131 mUsbSpeed = UsbSpeed::UNKNOWN;
132 else
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800133 mUsbSpeed = UsbSpeed::UNKNOWN;
Robin Pengc2b5ca92021-02-23 20:00:28 +0800134 } else {
135 ALOGE("Fail to read current speed");
136 mUsbSpeed = UsbSpeed::UNKNOWN;
137 }
138
139 if (callback) {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800140 ScopedAStatus ret = callback->getUsbSpeedCb(mUsbSpeed, in_transactionId);
Robin Pengc2b5ca92021-02-23 20:00:28 +0800141
142 if (!ret.isOk())
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800143 ALOGE("Call to getUsbSpeedCb failed %s", ret.getDescription().c_str());
Robin Pengc2b5ca92021-02-23 20:00:28 +0800144 }
145
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800146 return ScopedAStatus::ok();
Robin Pengc2b5ca92021-02-23 20:00:28 +0800147}
148
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800149Status UsbGadget::tearDownGadget() {
150 if (Status(resetGadget()) != Status::SUCCESS){
Robin Pengc2b5ca92021-02-23 20:00:28 +0800151 return Status::ERROR;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800152 }
Robin Pengc2b5ca92021-02-23 20:00:28 +0800153
154 if (monitorFfs.isMonitorRunning()) {
155 monitorFfs.reset();
156 } else {
157 ALOGI("mMonitor not running");
158 }
159 return Status::SUCCESS;
160}
161
Avichal Rakesheafdae62023-01-06 02:47:19 -0800162static Status validateAndSetVidPid(int64_t functions) {
163 Status ret;
Robin Pengc2b5ca92021-02-23 20:00:28 +0800164 std::string vendorFunctions = getVendorFunctions();
165
166 switch (functions) {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800167 case GadgetFunction::MTP:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800168 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
169 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
170 ret = Status::CONFIGURATION_NOT_SUPPORTED;
171 } else {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800172 ret = Status(setVidPid("0x18d1", "0x4ee1"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800173 }
174 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800175 case GadgetFunction::ADB |
176 GadgetFunction::MTP:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800177 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
178 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
179 ret = Status::CONFIGURATION_NOT_SUPPORTED;
180 } else {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800181 ret = Status(setVidPid("0x18d1", "0x4ee2"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800182 }
183 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800184 case GadgetFunction::RNDIS:
185 case GadgetFunction::RNDIS |
186 GadgetFunction::NCM:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800187 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
188 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
189 ret = Status::CONFIGURATION_NOT_SUPPORTED;
190 } else {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800191 ret = Status(setVidPid("0x18d1", "0x4ee3"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800192 }
193 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800194 case GadgetFunction::ADB |
195 GadgetFunction::RNDIS:
196 case GadgetFunction::ADB |
197 GadgetFunction::RNDIS |
198 GadgetFunction::NCM:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800199 if (vendorFunctions == "dm") {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800200 ret = Status(setVidPid("0x04e8", "0x6862"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800201 } else {
202 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
203 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
204 ret = Status::CONFIGURATION_NOT_SUPPORTED;
205 } else {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800206 ret = Status(setVidPid("0x18d1", "0x4ee4"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800207 }
208 }
209 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800210 case GadgetFunction::PTP:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800211 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
212 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
213 ret = Status::CONFIGURATION_NOT_SUPPORTED;
214 } else {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800215 ret = Status(setVidPid("0x18d1", "0x4ee5"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800216 }
217 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800218 case GadgetFunction::ADB |
219 GadgetFunction::PTP:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800220 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
221 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
222 ret = Status::CONFIGURATION_NOT_SUPPORTED;
223 } else {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800224 ret = Status(setVidPid("0x18d1", "0x4ee6"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800225 }
226 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800227 case GadgetFunction::ADB:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800228 if (vendorFunctions == "dm") {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800229 ret = Status(setVidPid("0x04e8", "0x6862"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800230 } else if (vendorFunctions == "etr_miu") {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800231 ret = Status(setVidPid("0x18d1", "0x4ee2"));
Puma Hsufbcb7ad2021-08-19 19:36:51 +0800232 } else if (vendorFunctions == "uwb_acm"){
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800233 ret = Status(setVidPid("0x18d1", "0x4ee2"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800234 } else {
235 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
236 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
237 ret = Status::CONFIGURATION_NOT_SUPPORTED;
238 } else {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800239 ret = Status(setVidPid("0x18d1", "0x4ee7"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800240 }
241 }
242 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800243 case GadgetFunction::MIDI:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800244 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
245 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
246 ret = Status::CONFIGURATION_NOT_SUPPORTED;
247 } else {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800248 ret = Status(setVidPid("0x18d1", "0x4ee8"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800249 }
250 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800251 case GadgetFunction::ADB |
252 GadgetFunction::MIDI:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800253 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
254 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
255 ret = Status::CONFIGURATION_NOT_SUPPORTED;
256 } else {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800257 ret = Status(setVidPid("0x18d1", "0x4ee9"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800258 }
259 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800260 case GadgetFunction::ACCESSORY:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800261 if (!(vendorFunctions == "user" || vendorFunctions == ""))
262 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800263 ret = Status(setVidPid("0x18d1", "0x2d00"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800264 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800265 case GadgetFunction::ADB |
266 GadgetFunction::ACCESSORY:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800267 if (!(vendorFunctions == "user" || vendorFunctions == ""))
268 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800269 ret = Status(setVidPid("0x18d1", "0x2d01"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800270 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800271 case GadgetFunction::AUDIO_SOURCE:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800272 if (!(vendorFunctions == "user" || vendorFunctions == ""))
273 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800274 ret = Status(setVidPid("0x18d1", "0x2d02"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800275 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800276 case GadgetFunction::ADB |
277 GadgetFunction::AUDIO_SOURCE:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800278 if (!(vendorFunctions == "user" || vendorFunctions == ""))
279 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800280 ret = Status(setVidPid("0x18d1", "0x2d03"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800281 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800282 case GadgetFunction::ACCESSORY |
283 GadgetFunction::AUDIO_SOURCE:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800284 if (!(vendorFunctions == "user" || vendorFunctions == ""))
285 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800286 ret = Status(setVidPid("0x18d1", "0x2d04"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800287 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800288 case GadgetFunction::ADB |
289 GadgetFunction::ACCESSORY |
290 GadgetFunction::AUDIO_SOURCE:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800291 if (!(vendorFunctions == "user" || vendorFunctions == ""))
292 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800293 ret = Status(setVidPid("0x18d1", "0x2d05"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800294 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800295 case GadgetFunction::NCM:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800296 if (!(vendorFunctions == "user" || vendorFunctions == ""))
297 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800298 ret = Status(setVidPid("0x18d1", "0x4eeb"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800299 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800300 case GadgetFunction::ADB |
301 GadgetFunction::NCM:
Ricky Niu48b3e5d2021-11-24 17:26:38 +0800302 if (vendorFunctions == "dm") {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800303 ret = Status(setVidPid("0x04e8", "0x6862"));
Ricky Niu48b3e5d2021-11-24 17:26:38 +0800304 } else {
305 if (!(vendorFunctions == "user" || vendorFunctions == ""))
306 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800307 ret = Status(setVidPid("0x18d1", "0x4eec"));
Ricky Niu48b3e5d2021-11-24 17:26:38 +0800308 }
Robin Pengc2b5ca92021-02-23 20:00:28 +0800309 break;
Avichal Rakesheafdae62023-01-06 02:47:19 -0800310 case GadgetFunction::UVC:
311 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
312 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
313 ret = Status::CONFIGURATION_NOT_SUPPORTED;
314 } else if (!GetBoolProperty(kUvcEnabled, false)) {
315 ALOGE("UVC function not enabled by config");
316 ret = Status::CONFIGURATION_NOT_SUPPORTED;
317 } else {
318 ret = Status(setVidPid("0x18d1", "0x4eed"));
319 }
320 break;
321 case GadgetFunction::ADB | GadgetFunction::UVC:
322 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
323 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
324 ret = Status::CONFIGURATION_NOT_SUPPORTED;
325 } else if (!GetBoolProperty(kUvcEnabled, false)) {
326 ALOGE("UVC function not enabled by config");
327 ret = Status::CONFIGURATION_NOT_SUPPORTED;
328 } else {
329 ret = Status(setVidPid("0x18d1", "0x4eee"));
330 }
331 break;
Robin Pengc2b5ca92021-02-23 20:00:28 +0800332 default:
333 ALOGE("Combination not supported");
334 ret = Status::CONFIGURATION_NOT_SUPPORTED;
335 }
336 return ret;
337}
338
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800339ScopedAStatus UsbGadget::reset() {
Robin Pengc2b5ca92021-02-23 20:00:28 +0800340 ALOGI("USB Gadget reset");
341
342 if (!WriteStringToFile("none", PULLUP_PATH)) {
343 ALOGI("Gadget cannot be pulled down");
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800344 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
345 -1, "Gadget cannot be pulled down");
Robin Pengc2b5ca92021-02-23 20:00:28 +0800346 }
347
348 usleep(kDisconnectWaitUs);
349
350 if (!WriteStringToFile(kGadgetName, PULLUP_PATH)) {
351 ALOGI("Gadget cannot be pulled up");
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800352 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
353 -1, "Gadget cannot be pulled up");
Robin Pengc2b5ca92021-02-23 20:00:28 +0800354 }
355
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800356 return ScopedAStatus::ok();
Robin Pengc2b5ca92021-02-23 20:00:28 +0800357}
358
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800359Status UsbGadget::setupFunctions(long functions,
360 const shared_ptr<IUsbGadgetCallback> &callback, uint64_t timeout,
361 int64_t in_transactionId) {
Robin Pengc2b5ca92021-02-23 20:00:28 +0800362 bool ffsEnabled = false;
363 int i = 0;
364
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800365 if (Status(addGenericAndroidFunctions(&monitorFfs, functions, &ffsEnabled, &i)) !=
Robin Pengc2b5ca92021-02-23 20:00:28 +0800366 Status::SUCCESS)
367 return Status::ERROR;
368
Robin Pengc2b5ca92021-02-23 20:00:28 +0800369 std::string vendorFunctions = getVendorFunctions();
370
371 if (vendorFunctions == "dm") {
372 ALOGI("enable usbradio debug functions");
Maciej Żenczykowskie0ccd8f2020-12-27 19:58:32 -0800373 if ((functions & GadgetFunction::RNDIS) != 0) {
Robin Pengc2b5ca92021-02-23 20:00:28 +0800374 if (linkFunction("acm.gs6", i++))
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800375 return Status::ERROR;
Robin Pengc2b5ca92021-02-23 20:00:28 +0800376 if (linkFunction("dm.gs7", i++))
377 return Status::ERROR;
378 } else {
379 if (linkFunction("dm.gs7", i++))
380 return Status::ERROR;
381 if (linkFunction("acm.gs6", i++))
382 return Status::ERROR;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800383 }
Robin Pengc2b5ca92021-02-23 20:00:28 +0800384 } else if (vendorFunctions == "etr_miu") {
385 ALOGI("enable etr_miu functions");
386 if (linkFunction("etr_miu.gs11", i++))
387 return Status::ERROR;
Puma Hsufbcb7ad2021-08-19 19:36:51 +0800388 } else if (vendorFunctions == "uwb_acm") {
389 ALOGI("enable uwb acm function");
390 if (linkFunction("acm.uwb0", i++))
391 return Status::ERROR;
Robin Pengc2b5ca92021-02-23 20:00:28 +0800392 }
393
Maciej Żenczykowskie0ccd8f2020-12-27 19:58:32 -0800394 if ((functions & GadgetFunction::ADB) != 0) {
Robin Pengc2b5ca92021-02-23 20:00:28 +0800395 ffsEnabled = true;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800396 if (Status(addAdb(&monitorFfs, &i)) != Status::SUCCESS)
Robin Pengc2b5ca92021-02-23 20:00:28 +0800397 return Status::ERROR;
398 }
399
Maciej Żenczykowskie0ccd8f2020-12-27 19:58:32 -0800400 if ((functions & GadgetFunction::NCM) != 0) {
401 ALOGI("setCurrentUsbFunctions ncm");
402 if (linkFunction("ncm.gs9", i++))
Robin Pengc2b5ca92021-02-23 20:00:28 +0800403 return Status::ERROR;
404 }
405
406 // Pull up the gadget right away when there are no ffs functions.
407 if (!ffsEnabled) {
408 if (!WriteStringToFile(kGadgetName, PULLUP_PATH))
409 return Status::ERROR;
410 mCurrentUsbFunctionsApplied = true;
411 if (callback)
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800412 callback->setCurrentUsbFunctionsCb(functions, Status::SUCCESS, in_transactionId);
Robin Pengc2b5ca92021-02-23 20:00:28 +0800413 return Status::SUCCESS;
414 }
415
416 monitorFfs.registerFunctionsAppliedCallback(&currentFunctionsAppliedCallback, this);
417 // Monitors the ffs paths to pull up the gadget when descriptors are written.
418 // Also takes of the pulling up the gadget again if the userspace process
419 // dies and restarts.
420 monitorFfs.startMonitor();
421
422 if (kDebug)
423 ALOGI("Mainthread in Cv");
424
425 if (callback) {
426 bool pullup = monitorFfs.waitForPullUp(timeout);
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800427 ScopedAStatus ret = callback->setCurrentUsbFunctionsCb(
428 functions, pullup ? Status::SUCCESS : Status::ERROR, in_transactionId);
429 if (!ret.isOk()) {
430 ALOGE("setCurrentUsbFunctionsCb error %s", ret.getDescription().c_str());
431 return Status::ERROR;
432 }
Robin Pengc2b5ca92021-02-23 20:00:28 +0800433 }
Robin Pengc2b5ca92021-02-23 20:00:28 +0800434 return Status::SUCCESS;
435}
436
Ricky Niuebd7fca2022-05-09 10:14:20 +0800437Status getI2cBusHelper(string *name) {
438 DIR *dp;
439
440 dp = opendir(kHsi2cPath);
441 if (dp != NULL) {
442 struct dirent *ep;
443
444 while ((ep = readdir(dp))) {
445 if (ep->d_type == DT_DIR) {
446 if (string::npos != string(ep->d_name).find("i2c-")) {
447 std::strtok(ep->d_name, "-");
448 *name = std::strtok(NULL, "-");
449 }
450 }
451 }
452 closedir(dp);
453 return Status::SUCCESS;
454 }
455
456 ALOGE("Failed to open %s", kHsi2cPath);
457 return Status::ERROR;
458}
459
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800460ScopedAStatus UsbGadget::setCurrentUsbFunctions(long functions,
461 const shared_ptr<IUsbGadgetCallback> &callback,
462 int64_t timeout,
463 int64_t in_transactionId) {
Robin Pengc2b5ca92021-02-23 20:00:28 +0800464 std::unique_lock<std::mutex> lk(mLockSetCurrentFunction);
Ricky Niuebd7fca2022-05-09 10:14:20 +0800465 std::string current_usb_power_operation_mode, current_usb_type;
466 std::string usb_limit_sink_enable;
467
468 string accessoryCurrentLimitEnablePath, accessoryCurrentLimitPath, path;
Robin Pengc2b5ca92021-02-23 20:00:28 +0800469
470 mCurrentUsbFunctions = functions;
471 mCurrentUsbFunctionsApplied = false;
472
Ricky Niuebd7fca2022-05-09 10:14:20 +0800473 getI2cBusHelper(&path);
474 accessoryCurrentLimitPath = kI2CPath + path + "/" + kAccessoryLimitCurrent;
475 accessoryCurrentLimitEnablePath = kI2CPath + path + "/" + kAccessoryLimitCurrentEnable;
476
Ray Chiba3dc9b2022-03-01 21:57:03 +0800477 // Get the gadget IRQ number before tearDownGadget()
478 if (mGadgetIrqPath.empty())
479 getUsbGadgetIrqPath();
480
Robin Pengc2b5ca92021-02-23 20:00:28 +0800481 // Unlink the gadget and stop the monitor if running.
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800482 Status status = tearDownGadget();
Robin Pengc2b5ca92021-02-23 20:00:28 +0800483 if (status != Status::SUCCESS) {
484 goto error;
485 }
486
487 ALOGI("Returned from tearDown gadget");
488
489 // Leave the gadget pulled down to give time for the host to sense disconnect.
490 usleep(kDisconnectWaitUs);
491
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800492 if (functions == GadgetFunction::NONE) {
Robin Pengc2b5ca92021-02-23 20:00:28 +0800493 if (callback == NULL)
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800494 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
495 -1, "callback == NULL");
496 ScopedAStatus ret = callback->setCurrentUsbFunctionsCb(functions, Status::SUCCESS, in_transactionId);
Robin Pengc2b5ca92021-02-23 20:00:28 +0800497 if (!ret.isOk())
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800498 ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.getDescription().c_str());
499 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
500 -1, "Error while calling setCurrentUsbFunctionsCb");
Robin Pengc2b5ca92021-02-23 20:00:28 +0800501 }
502
503 status = validateAndSetVidPid(functions);
504
505 if (status != Status::SUCCESS) {
506 goto error;
507 }
508
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800509 status = setupFunctions(functions, callback, timeout, in_transactionId);
Robin Pengc2b5ca92021-02-23 20:00:28 +0800510 if (status != Status::SUCCESS) {
511 goto error;
512 }
513
Maciej Żenczykowskia24469c2021-06-25 11:42:01 -0700514 if (functions & GadgetFunction::NCM) {
Ray Chiba3dc9b2022-03-01 21:57:03 +0800515 if (!mGadgetIrqPath.empty()) {
516 if (!WriteStringToFile(BIG_CORE, mGadgetIrqPath))
517 ALOGI("Cannot move gadget IRQ to big core, path:%s", mGadgetIrqPath.c_str());
518 }
Maciej Żenczykowskia24469c2021-06-25 11:42:01 -0700519 } else {
Ray Chiba3dc9b2022-03-01 21:57:03 +0800520 if (!mGadgetIrqPath.empty()) {
521 if (!WriteStringToFile(MEDIUM_CORE, mGadgetIrqPath))
522 ALOGI("Cannot move gadget IRQ to medium core, path:%s", mGadgetIrqPath.c_str());
523 }
Maciej Żenczykowskia24469c2021-06-25 11:42:01 -0700524 }
525
Ricky Niuebd7fca2022-05-09 10:14:20 +0800526 if (ReadFileToString(CURRENT_USB_TYPE_PATH, &current_usb_type))
527 current_usb_type = Trim(current_usb_type);
528
529 if (ReadFileToString(CURRENT_USB_POWER_OPERATION_MODE_PATH, &current_usb_power_operation_mode))
530 current_usb_power_operation_mode = Trim(current_usb_power_operation_mode);
531
532 if (functions & GadgetFunction::ACCESSORY &&
533 current_usb_type == "Unknown SDP [CDP] DCP" &&
534 (current_usb_power_operation_mode == "default" ||
535 current_usb_power_operation_mode == "1.5A")) {
536 if (!WriteStringToFile("1300000", accessoryCurrentLimitPath)) {
537 ALOGI("Write 1.3A to limit current fail");
538 } else {
539 if (!WriteStringToFile("1", accessoryCurrentLimitEnablePath)) {
540 ALOGI("Enable limit current fail");
541 }
542 }
543 } else {
544 if (!WriteStringToFile("0", accessoryCurrentLimitEnablePath))
545 ALOGI("unvote accessory limit current failed");
546 }
547
Robin Pengc2b5ca92021-02-23 20:00:28 +0800548 ALOGI("Usb Gadget setcurrent functions called successfully");
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800549 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
550 -1, "Usb Gadget setcurrent functions called successfully");
551
Robin Pengc2b5ca92021-02-23 20:00:28 +0800552
553error:
554 ALOGI("Usb Gadget setcurrent functions failed");
555 if (callback == NULL)
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800556 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
557 -1, "Usb Gadget setcurrent functions failed");
558 ScopedAStatus ret = callback->setCurrentUsbFunctionsCb(functions, status, in_transactionId);
Robin Pengc2b5ca92021-02-23 20:00:28 +0800559 if (!ret.isOk())
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800560 ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.getDescription().c_str());
561 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
562 -1, "Error while calling setCurrentUsbFunctionsCb");
Robin Pengc2b5ca92021-02-23 20:00:28 +0800563}
Robin Pengc2b5ca92021-02-23 20:00:28 +0800564} // namespace gadget
565} // namespace usb
566} // namespace hardware
567} // namespace android
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800568} // aidl