blob: 64fd17b0c807b436b9ce5f6b7c513d578769f382 [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";
Will McVickerb54d8f92023-09-20 16:15:13 -070041constexpr char kMax77759TcpcDevName[] = "i2c-max77759tcpc";
42constexpr unsigned int kMax77759TcpcClientId = 0x25;
43constexpr char kAccessoryLimitCurrent[] = "usb_limit_accessory_current";
44constexpr char kAccessoryLimitCurrentEnable[] = "usb_limit_accessory_enable";
45constexpr char kUpdateSdpEnumTimeout[] = "update_sdp_enum_timeout";
Ricky Niuebd7fca2022-05-09 10:14:20 +080046
Avichal Rakesheafdae62023-01-06 02:47:19 -080047using ::android::base::GetBoolProperty;
48using ::android::hardware::google::pixel::usb::kUvcEnabled;
49
Will McVickerb54d8f92023-09-20 16:15:13 -070050UsbGadget::UsbGadget() : mGadgetIrqPath(""),
51 mI2cBusNumber(-1),
52 mI2cClientPath("") {
Robin Pengc2b5ca92021-02-23 20:00:28 +080053 if (access(OS_DESC_PATH, R_OK) != 0) {
54 ALOGE("configfs setup not done yet");
55 abort();
56 }
57}
58
Ricky Niud6d0b7d2022-07-06 20:57:02 +080059Status UsbGadget::getUsbGadgetIrqPath() {
Ray Chiba3dc9b2022-03-01 21:57:03 +080060 std::string irqs;
61 size_t read_pos = 0;
62 size_t found_pos = 0;
63
64 if (!ReadFileToString(kProcInterruptsPath, &irqs)) {
65 ALOGE("cannot read all interrupts");
66 return Status::ERROR;
67 }
68
69 while (true) {
70 found_pos = irqs.find_first_of("\n", read_pos);
71 if (found_pos == std::string::npos) {
72 ALOGI("the string of all interrupts is unexpected");
73 return Status::ERROR;
74 }
75
76 std::string single_irq = irqs.substr(read_pos, found_pos - read_pos);
77
78 if (single_irq.find("dwc3", 0) != std::string::npos) {
79 unsigned int dwc3_irq_number;
80 size_t dwc3_pos = single_irq.find_first_of(":");
81 if (!ParseUint(single_irq.substr(0, dwc3_pos), &dwc3_irq_number)) {
82 ALOGI("unknown IRQ strings");
83 return Status::ERROR;
84 }
85
86 mGadgetIrqPath = kProcIrqPath + single_irq.substr(0, dwc3_pos) + kSmpAffinityList;
87 break;
88 }
89
90 if (found_pos == irqs.npos) {
91 ALOGI("USB gadget doesn't start");
92 return Status::ERROR;
93 }
94
95 read_pos = found_pos + 1;
96 }
97
98 return Status::SUCCESS;
99}
100
Robin Pengc2b5ca92021-02-23 20:00:28 +0800101void currentFunctionsAppliedCallback(bool functionsApplied, void *payload) {
102 UsbGadget *gadget = (UsbGadget *)payload;
103 gadget->mCurrentUsbFunctionsApplied = functionsApplied;
Amit Sunil Dhamneed622852023-09-12 17:53:45 -0700104 gadget->updateSdpEnumTimeout();
Robin Pengc2b5ca92021-02-23 20:00:28 +0800105}
106
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800107ScopedAStatus UsbGadget::getCurrentUsbFunctions(const shared_ptr<IUsbGadgetCallback> &callback,
108 int64_t in_transactionId) {
109 ScopedAStatus ret = callback->getCurrentUsbFunctionsCb(
Robin Pengc2b5ca92021-02-23 20:00:28 +0800110 mCurrentUsbFunctions,
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800111 mCurrentUsbFunctionsApplied ? Status::FUNCTIONS_APPLIED : Status::FUNCTIONS_NOT_APPLIED,
112 in_transactionId);
Robin Pengc2b5ca92021-02-23 20:00:28 +0800113 if (!ret.isOk())
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800114 ALOGE("Call to getCurrentUsbFunctionsCb failed %s", ret.getDescription().c_str());
Robin Pengc2b5ca92021-02-23 20:00:28 +0800115
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800116 return ScopedAStatus::ok();
Robin Pengc2b5ca92021-02-23 20:00:28 +0800117}
118
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800119ScopedAStatus UsbGadget::getUsbSpeed(const shared_ptr<IUsbGadgetCallback> &callback,
120 int64_t in_transactionId) {
Robin Pengc2b5ca92021-02-23 20:00:28 +0800121 std::string current_speed;
122 if (ReadFileToString(SPEED_PATH, &current_speed)) {
123 current_speed = Trim(current_speed);
124 ALOGI("current USB speed is %s", current_speed.c_str());
125 if (current_speed == "low-speed")
126 mUsbSpeed = UsbSpeed::LOWSPEED;
127 else if (current_speed == "full-speed")
128 mUsbSpeed = UsbSpeed::FULLSPEED;
129 else if (current_speed == "high-speed")
130 mUsbSpeed = UsbSpeed::HIGHSPEED;
131 else if (current_speed == "super-speed")
132 mUsbSpeed = UsbSpeed::SUPERSPEED;
133 else if (current_speed == "super-speed-plus")
134 mUsbSpeed = UsbSpeed::SUPERSPEED_10Gb;
135 else if (current_speed == "UNKNOWN")
136 mUsbSpeed = UsbSpeed::UNKNOWN;
137 else
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800138 mUsbSpeed = UsbSpeed::UNKNOWN;
Robin Pengc2b5ca92021-02-23 20:00:28 +0800139 } else {
140 ALOGE("Fail to read current speed");
141 mUsbSpeed = UsbSpeed::UNKNOWN;
142 }
143
144 if (callback) {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800145 ScopedAStatus ret = callback->getUsbSpeedCb(mUsbSpeed, in_transactionId);
Robin Pengc2b5ca92021-02-23 20:00:28 +0800146
147 if (!ret.isOk())
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800148 ALOGE("Call to getUsbSpeedCb failed %s", ret.getDescription().c_str());
Robin Pengc2b5ca92021-02-23 20:00:28 +0800149 }
150
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800151 return ScopedAStatus::ok();
Robin Pengc2b5ca92021-02-23 20:00:28 +0800152}
153
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800154Status UsbGadget::tearDownGadget() {
155 if (Status(resetGadget()) != Status::SUCCESS){
Robin Pengc2b5ca92021-02-23 20:00:28 +0800156 return Status::ERROR;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800157 }
Robin Pengc2b5ca92021-02-23 20:00:28 +0800158
159 if (monitorFfs.isMonitorRunning()) {
160 monitorFfs.reset();
161 } else {
162 ALOGI("mMonitor not running");
163 }
164 return Status::SUCCESS;
165}
166
Avichal Rakesheafdae62023-01-06 02:47:19 -0800167static Status validateAndSetVidPid(int64_t functions) {
168 Status ret;
Robin Pengc2b5ca92021-02-23 20:00:28 +0800169 std::string vendorFunctions = getVendorFunctions();
170
171 switch (functions) {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800172 case GadgetFunction::MTP:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800173 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
174 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
175 ret = Status::CONFIGURATION_NOT_SUPPORTED;
176 } else {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800177 ret = Status(setVidPid("0x18d1", "0x4ee1"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800178 }
179 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800180 case GadgetFunction::ADB |
181 GadgetFunction::MTP:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800182 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
183 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
184 ret = Status::CONFIGURATION_NOT_SUPPORTED;
185 } else {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800186 ret = Status(setVidPid("0x18d1", "0x4ee2"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800187 }
188 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800189 case GadgetFunction::RNDIS:
190 case GadgetFunction::RNDIS |
191 GadgetFunction::NCM:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800192 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
193 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
194 ret = Status::CONFIGURATION_NOT_SUPPORTED;
195 } else {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800196 ret = Status(setVidPid("0x18d1", "0x4ee3"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800197 }
198 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800199 case GadgetFunction::ADB |
200 GadgetFunction::RNDIS:
201 case GadgetFunction::ADB |
202 GadgetFunction::RNDIS |
203 GadgetFunction::NCM:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800204 if (vendorFunctions == "dm") {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800205 ret = Status(setVidPid("0x04e8", "0x6862"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800206 } else {
207 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
208 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
209 ret = Status::CONFIGURATION_NOT_SUPPORTED;
210 } else {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800211 ret = Status(setVidPid("0x18d1", "0x4ee4"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800212 }
213 }
214 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800215 case GadgetFunction::PTP:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800216 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
217 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
218 ret = Status::CONFIGURATION_NOT_SUPPORTED;
219 } else {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800220 ret = Status(setVidPid("0x18d1", "0x4ee5"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800221 }
222 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800223 case GadgetFunction::ADB |
224 GadgetFunction::PTP:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800225 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
226 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
227 ret = Status::CONFIGURATION_NOT_SUPPORTED;
228 } else {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800229 ret = Status(setVidPid("0x18d1", "0x4ee6"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800230 }
231 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800232 case GadgetFunction::ADB:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800233 if (vendorFunctions == "dm") {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800234 ret = Status(setVidPid("0x04e8", "0x6862"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800235 } else if (vendorFunctions == "etr_miu") {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800236 ret = Status(setVidPid("0x18d1", "0x4ee2"));
Puma Hsufbcb7ad2021-08-19 19:36:51 +0800237 } else if (vendorFunctions == "uwb_acm"){
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800238 ret = Status(setVidPid("0x18d1", "0x4ee2"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800239 } else {
240 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
241 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
242 ret = Status::CONFIGURATION_NOT_SUPPORTED;
243 } else {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800244 ret = Status(setVidPid("0x18d1", "0x4ee7"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800245 }
246 }
247 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800248 case GadgetFunction::MIDI:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800249 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
250 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
251 ret = Status::CONFIGURATION_NOT_SUPPORTED;
252 } else {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800253 ret = Status(setVidPid("0x18d1", "0x4ee8"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800254 }
255 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800256 case GadgetFunction::ADB |
257 GadgetFunction::MIDI:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800258 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
259 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
260 ret = Status::CONFIGURATION_NOT_SUPPORTED;
261 } else {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800262 ret = Status(setVidPid("0x18d1", "0x4ee9"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800263 }
264 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800265 case GadgetFunction::ACCESSORY:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800266 if (!(vendorFunctions == "user" || vendorFunctions == ""))
267 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800268 ret = Status(setVidPid("0x18d1", "0x2d00"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800269 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800270 case GadgetFunction::ADB |
271 GadgetFunction::ACCESSORY:
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", "0x2d01"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800275 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800276 case GadgetFunction::AUDIO_SOURCE:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800277 if (!(vendorFunctions == "user" || vendorFunctions == ""))
278 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800279 ret = Status(setVidPid("0x18d1", "0x2d02"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800280 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800281 case GadgetFunction::ADB |
282 GadgetFunction::AUDIO_SOURCE:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800283 if (!(vendorFunctions == "user" || vendorFunctions == ""))
284 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800285 ret = Status(setVidPid("0x18d1", "0x2d03"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800286 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800287 case GadgetFunction::ACCESSORY |
288 GadgetFunction::AUDIO_SOURCE:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800289 if (!(vendorFunctions == "user" || vendorFunctions == ""))
290 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800291 ret = Status(setVidPid("0x18d1", "0x2d04"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800292 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800293 case GadgetFunction::ADB |
294 GadgetFunction::ACCESSORY |
295 GadgetFunction::AUDIO_SOURCE:
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", "0x2d05"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800299 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800300 case GadgetFunction::NCM:
Robin Pengc2b5ca92021-02-23 20:00:28 +0800301 if (!(vendorFunctions == "user" || vendorFunctions == ""))
302 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800303 ret = Status(setVidPid("0x18d1", "0x4eeb"));
Robin Pengc2b5ca92021-02-23 20:00:28 +0800304 break;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800305 case GadgetFunction::ADB |
306 GadgetFunction::NCM:
Ricky Niu48b3e5d2021-11-24 17:26:38 +0800307 if (vendorFunctions == "dm") {
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800308 ret = Status(setVidPid("0x04e8", "0x6862"));
Ricky Niu48b3e5d2021-11-24 17:26:38 +0800309 } else {
310 if (!(vendorFunctions == "user" || vendorFunctions == ""))
311 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800312 ret = Status(setVidPid("0x18d1", "0x4eec"));
Ricky Niu48b3e5d2021-11-24 17:26:38 +0800313 }
Robin Pengc2b5ca92021-02-23 20:00:28 +0800314 break;
Avichal Rakesheafdae62023-01-06 02:47:19 -0800315 case GadgetFunction::UVC:
316 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
317 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
318 ret = Status::CONFIGURATION_NOT_SUPPORTED;
319 } else if (!GetBoolProperty(kUvcEnabled, false)) {
320 ALOGE("UVC function not enabled by config");
321 ret = Status::CONFIGURATION_NOT_SUPPORTED;
322 } else {
323 ret = Status(setVidPid("0x18d1", "0x4eed"));
324 }
325 break;
326 case GadgetFunction::ADB | GadgetFunction::UVC:
327 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
328 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
329 ret = Status::CONFIGURATION_NOT_SUPPORTED;
330 } else if (!GetBoolProperty(kUvcEnabled, false)) {
331 ALOGE("UVC function not enabled by config");
332 ret = Status::CONFIGURATION_NOT_SUPPORTED;
333 } else {
334 ret = Status(setVidPid("0x18d1", "0x4eee"));
335 }
336 break;
Robin Pengc2b5ca92021-02-23 20:00:28 +0800337 default:
338 ALOGE("Combination not supported");
339 ret = Status::CONFIGURATION_NOT_SUPPORTED;
340 }
341 return ret;
342}
343
Ricky Niu744f2142023-01-31 18:01:06 +0800344ScopedAStatus UsbGadget::reset(const shared_ptr<IUsbGadgetCallback> &callback,
345 int64_t in_transactionId) {
Robin Pengc2b5ca92021-02-23 20:00:28 +0800346 ALOGI("USB Gadget reset");
347
348 if (!WriteStringToFile("none", PULLUP_PATH)) {
349 ALOGI("Gadget cannot be pulled down");
Ricky Niu744f2142023-01-31 18:01:06 +0800350 if (callback)
351 callback->resetCb(Status::ERROR, in_transactionId);
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800352 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
353 -1, "Gadget cannot be pulled down");
Robin Pengc2b5ca92021-02-23 20:00:28 +0800354 }
355
356 usleep(kDisconnectWaitUs);
357
358 if (!WriteStringToFile(kGadgetName, PULLUP_PATH)) {
359 ALOGI("Gadget cannot be pulled up");
Ricky Niu744f2142023-01-31 18:01:06 +0800360 if (callback)
361 callback->resetCb(Status::ERROR, in_transactionId);
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800362 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
363 -1, "Gadget cannot be pulled up");
Robin Pengc2b5ca92021-02-23 20:00:28 +0800364 }
Ricky Niu744f2142023-01-31 18:01:06 +0800365 if (callback)
366 callback->resetCb(Status::SUCCESS, in_transactionId);
Robin Pengc2b5ca92021-02-23 20:00:28 +0800367
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800368 return ScopedAStatus::ok();
Robin Pengc2b5ca92021-02-23 20:00:28 +0800369}
370
Amit Sunil Dhamneed622852023-09-12 17:53:45 -0700371void UsbGadget::updateSdpEnumTimeout() {
Will McVickerb54d8f92023-09-20 16:15:13 -0700372 string update_sdp_enum_timeout_path;
373 std::string_view i2cPath;
Amit Sunil Dhamneed622852023-09-12 17:53:45 -0700374
Will McVickerb54d8f92023-09-20 16:15:13 -0700375 i2cPath = getI2cClientPath();
376 if (i2cPath.empty()) {
Amit Sunil Dhamneed622852023-09-12 17:53:45 -0700377 ALOGE("%s: Unable to locate i2c bus node", __func__);
Will McVickerb54d8f92023-09-20 16:15:13 -0700378 return;
Amit Sunil Dhamneed622852023-09-12 17:53:45 -0700379 }
380
Will McVickerb54d8f92023-09-20 16:15:13 -0700381 update_sdp_enum_timeout_path = std::string{i2cPath} + "/" + kUpdateSdpEnumTimeout;
Amit Sunil Dhamneed622852023-09-12 17:53:45 -0700382 if (!WriteStringToFile("1", update_sdp_enum_timeout_path)) {
383 ALOGE("%s: Unable to write to %s.", __func__, update_sdp_enum_timeout_path.c_str());
384 } else {
385 ALOGI("%s: Updated SDP enumeration timeout value.", __func__);
386 }
387}
388
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800389Status UsbGadget::setupFunctions(long functions,
390 const shared_ptr<IUsbGadgetCallback> &callback, uint64_t timeout,
391 int64_t in_transactionId) {
Robin Pengc2b5ca92021-02-23 20:00:28 +0800392 bool ffsEnabled = false;
393 int i = 0;
394
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800395 if (Status(addGenericAndroidFunctions(&monitorFfs, functions, &ffsEnabled, &i)) !=
Robin Pengc2b5ca92021-02-23 20:00:28 +0800396 Status::SUCCESS)
397 return Status::ERROR;
398
Robin Pengc2b5ca92021-02-23 20:00:28 +0800399 std::string vendorFunctions = getVendorFunctions();
400
401 if (vendorFunctions == "dm") {
402 ALOGI("enable usbradio debug functions");
Maciej Żenczykowskie0ccd8f2020-12-27 19:58:32 -0800403 if ((functions & GadgetFunction::RNDIS) != 0) {
Robin Pengc2b5ca92021-02-23 20:00:28 +0800404 if (linkFunction("acm.gs6", i++))
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800405 return Status::ERROR;
Robin Pengc2b5ca92021-02-23 20:00:28 +0800406 if (linkFunction("dm.gs7", i++))
407 return Status::ERROR;
408 } else {
409 if (linkFunction("dm.gs7", i++))
410 return Status::ERROR;
411 if (linkFunction("acm.gs6", i++))
412 return Status::ERROR;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800413 }
Robin Pengc2b5ca92021-02-23 20:00:28 +0800414 } else if (vendorFunctions == "etr_miu") {
415 ALOGI("enable etr_miu functions");
416 if (linkFunction("etr_miu.gs11", i++))
417 return Status::ERROR;
Puma Hsufbcb7ad2021-08-19 19:36:51 +0800418 } else if (vendorFunctions == "uwb_acm") {
419 ALOGI("enable uwb acm function");
420 if (linkFunction("acm.uwb0", i++))
421 return Status::ERROR;
Robin Pengc2b5ca92021-02-23 20:00:28 +0800422 }
423
Maciej Żenczykowskie0ccd8f2020-12-27 19:58:32 -0800424 if ((functions & GadgetFunction::ADB) != 0) {
Robin Pengc2b5ca92021-02-23 20:00:28 +0800425 ffsEnabled = true;
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800426 if (Status(addAdb(&monitorFfs, &i)) != Status::SUCCESS)
Robin Pengc2b5ca92021-02-23 20:00:28 +0800427 return Status::ERROR;
428 }
429
Maciej Żenczykowskie0ccd8f2020-12-27 19:58:32 -0800430 if ((functions & GadgetFunction::NCM) != 0) {
431 ALOGI("setCurrentUsbFunctions ncm");
432 if (linkFunction("ncm.gs9", i++))
Robin Pengc2b5ca92021-02-23 20:00:28 +0800433 return Status::ERROR;
434 }
435
436 // Pull up the gadget right away when there are no ffs functions.
437 if (!ffsEnabled) {
438 if (!WriteStringToFile(kGadgetName, PULLUP_PATH))
439 return Status::ERROR;
440 mCurrentUsbFunctionsApplied = true;
441 if (callback)
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800442 callback->setCurrentUsbFunctionsCb(functions, Status::SUCCESS, in_transactionId);
Amit Sunil Dhamneed622852023-09-12 17:53:45 -0700443 updateSdpEnumTimeout();
Robin Pengc2b5ca92021-02-23 20:00:28 +0800444 return Status::SUCCESS;
445 }
446
447 monitorFfs.registerFunctionsAppliedCallback(&currentFunctionsAppliedCallback, this);
448 // Monitors the ffs paths to pull up the gadget when descriptors are written.
449 // Also takes of the pulling up the gadget again if the userspace process
450 // dies and restarts.
451 monitorFfs.startMonitor();
452
453 if (kDebug)
454 ALOGI("Mainthread in Cv");
455
456 if (callback) {
457 bool pullup = monitorFfs.waitForPullUp(timeout);
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800458 ScopedAStatus ret = callback->setCurrentUsbFunctionsCb(
459 functions, pullup ? Status::SUCCESS : Status::ERROR, in_transactionId);
460 if (!ret.isOk()) {
461 ALOGE("setCurrentUsbFunctionsCb error %s", ret.getDescription().c_str());
462 return Status::ERROR;
463 }
Robin Pengc2b5ca92021-02-23 20:00:28 +0800464 }
Robin Pengc2b5ca92021-02-23 20:00:28 +0800465 return Status::SUCCESS;
466}
467
Will McVickerb54d8f92023-09-20 16:15:13 -0700468int UsbGadget::getI2cBusNumber() {
469 DIR *dp;
470 unsigned int busNumber;
471
472 // Since the i2c bus number doesn't change after boot, we only need to get
473 // it once.
474 if (mI2cBusNumber >= 0) {
475 return mI2cBusNumber;
476 }
477
478 dp = opendir(kHsi2cPath);
479 if (dp != NULL) {
480 struct dirent *ep;
481
482 while ((ep = readdir(dp))) {
483 if (ep->d_type == DT_DIR) {
484 if (sscanf(ep->d_name, "i2c-%u", &busNumber) == 1) {
485 mI2cBusNumber = busNumber;
486 break;
487 }
488 }
489 }
490 closedir(dp);
491 }
492
493 if (mI2cBusNumber < 0) {
494 ALOGE("Failed to open %s", kHsi2cPath);
495 }
496 return mI2cBusNumber;
497}
498
499std::string_view UsbGadget::getI2cClientPath() {
500 DIR *dp;
501 char i2cClientPathLabeled[PATH_MAX];
502 char i2cClientPathUnLabeled[PATH_MAX];
503
504 // Since the I2C client path doesn't change after boot, we only need to get
505 // it once.
506 if (!mI2cClientPath.empty()) {
507 return mI2cClientPath;
508 }
509
510 if (getI2cBusNumber() < 0) {
511 return std::string_view{""};
512 }
513
514 snprintf(i2cClientPathLabeled, sizeof(i2cClientPathLabeled),
515 "%s/i2c-%d/%s", kHsi2cPath, mI2cBusNumber, kMax77759TcpcDevName);
516 snprintf(i2cClientPathUnLabeled, sizeof(i2cClientPathUnLabeled),
517 "%s/i2c-%d/%d-%04x", kHsi2cPath, mI2cBusNumber, mI2cBusNumber,
518 kMax77759TcpcClientId);
519
520 dp = opendir(i2cClientPathLabeled);
521 if (dp != NULL) {
522 mI2cClientPath.assign(i2cClientPathLabeled);
523 closedir(dp);
524 return mI2cClientPath;
525 }
526
527 dp = opendir(i2cClientPathUnLabeled);
528 if (dp != NULL) {
529 mI2cClientPath.assign(i2cClientPathUnLabeled);
530 closedir(dp);
531 return mI2cClientPath;
532 }
533
534 ALOGE("Failed to find the i2c client path under %s", kHsi2cPath);
535 return std::string_view{""};
536}
Ricky Niuebd7fca2022-05-09 10:14:20 +0800537
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800538ScopedAStatus UsbGadget::setCurrentUsbFunctions(long functions,
539 const shared_ptr<IUsbGadgetCallback> &callback,
540 int64_t timeout,
541 int64_t in_transactionId) {
Robin Pengc2b5ca92021-02-23 20:00:28 +0800542 std::unique_lock<std::mutex> lk(mLockSetCurrentFunction);
Ricky Niuebd7fca2022-05-09 10:14:20 +0800543 std::string current_usb_power_operation_mode, current_usb_type;
544 std::string usb_limit_sink_enable;
545
Will McVickerb54d8f92023-09-20 16:15:13 -0700546 string accessoryCurrentLimitEnablePath, accessoryCurrentLimitPath;
547 std::string_view i2cPath;
Robin Pengc2b5ca92021-02-23 20:00:28 +0800548
549 mCurrentUsbFunctions = functions;
550 mCurrentUsbFunctionsApplied = false;
551
Will McVickerb54d8f92023-09-20 16:15:13 -0700552 i2cPath = getI2cClientPath();
553 if (!i2cPath.empty()) {
554 accessoryCurrentLimitPath = std::string{i2cPath} + "/" + kAccessoryLimitCurrent;
555 accessoryCurrentLimitEnablePath = std::string{i2cPath} + "/" + kAccessoryLimitCurrentEnable;
556 } else {
557 ALOGE("%s: Unable to locate i2c bus node", __func__);
558 }
Ricky Niuebd7fca2022-05-09 10:14:20 +0800559
Ray Chiba3dc9b2022-03-01 21:57:03 +0800560 // Get the gadget IRQ number before tearDownGadget()
561 if (mGadgetIrqPath.empty())
562 getUsbGadgetIrqPath();
563
Robin Pengc2b5ca92021-02-23 20:00:28 +0800564 // Unlink the gadget and stop the monitor if running.
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800565 Status status = tearDownGadget();
Robin Pengc2b5ca92021-02-23 20:00:28 +0800566 if (status != Status::SUCCESS) {
567 goto error;
568 }
569
570 ALOGI("Returned from tearDown gadget");
571
572 // Leave the gadget pulled down to give time for the host to sense disconnect.
573 usleep(kDisconnectWaitUs);
574
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800575 if (functions == GadgetFunction::NONE) {
Robin Pengc2b5ca92021-02-23 20:00:28 +0800576 if (callback == NULL)
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800577 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
578 -1, "callback == NULL");
579 ScopedAStatus ret = callback->setCurrentUsbFunctionsCb(functions, Status::SUCCESS, in_transactionId);
Robin Pengc2b5ca92021-02-23 20:00:28 +0800580 if (!ret.isOk())
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800581 ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.getDescription().c_str());
582 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
583 -1, "Error while calling setCurrentUsbFunctionsCb");
Robin Pengc2b5ca92021-02-23 20:00:28 +0800584 }
585
586 status = validateAndSetVidPid(functions);
587
588 if (status != Status::SUCCESS) {
589 goto error;
590 }
591
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800592 status = setupFunctions(functions, callback, timeout, in_transactionId);
Robin Pengc2b5ca92021-02-23 20:00:28 +0800593 if (status != Status::SUCCESS) {
594 goto error;
595 }
596
Maciej Żenczykowskia24469c2021-06-25 11:42:01 -0700597 if (functions & GadgetFunction::NCM) {
Ray Chiba3dc9b2022-03-01 21:57:03 +0800598 if (!mGadgetIrqPath.empty()) {
599 if (!WriteStringToFile(BIG_CORE, mGadgetIrqPath))
600 ALOGI("Cannot move gadget IRQ to big core, path:%s", mGadgetIrqPath.c_str());
601 }
Maciej Żenczykowskia24469c2021-06-25 11:42:01 -0700602 } else {
Ray Chiba3dc9b2022-03-01 21:57:03 +0800603 if (!mGadgetIrqPath.empty()) {
604 if (!WriteStringToFile(MEDIUM_CORE, mGadgetIrqPath))
605 ALOGI("Cannot move gadget IRQ to medium core, path:%s", mGadgetIrqPath.c_str());
606 }
Maciej Żenczykowskia24469c2021-06-25 11:42:01 -0700607 }
608
Ricky Niuebd7fca2022-05-09 10:14:20 +0800609 if (ReadFileToString(CURRENT_USB_TYPE_PATH, &current_usb_type))
610 current_usb_type = Trim(current_usb_type);
611
612 if (ReadFileToString(CURRENT_USB_POWER_OPERATION_MODE_PATH, &current_usb_power_operation_mode))
613 current_usb_power_operation_mode = Trim(current_usb_power_operation_mode);
614
615 if (functions & GadgetFunction::ACCESSORY &&
616 current_usb_type == "Unknown SDP [CDP] DCP" &&
617 (current_usb_power_operation_mode == "default" ||
618 current_usb_power_operation_mode == "1.5A")) {
Will McVickerb54d8f92023-09-20 16:15:13 -0700619 if (accessoryCurrentLimitPath.empty() || !WriteStringToFile("1300000", accessoryCurrentLimitPath)) {
Ricky Niuebd7fca2022-05-09 10:14:20 +0800620 ALOGI("Write 1.3A to limit current fail");
621 } else {
Will McVickerb54d8f92023-09-20 16:15:13 -0700622 if (accessoryCurrentLimitEnablePath.empty() ||
623 !WriteStringToFile("1", accessoryCurrentLimitEnablePath)) {
Ricky Niuebd7fca2022-05-09 10:14:20 +0800624 ALOGI("Enable limit current fail");
625 }
626 }
627 } else {
Will McVickerb54d8f92023-09-20 16:15:13 -0700628 if (accessoryCurrentLimitEnablePath.empty() ||
629 !WriteStringToFile("0", accessoryCurrentLimitEnablePath))
Ricky Niuebd7fca2022-05-09 10:14:20 +0800630 ALOGI("unvote accessory limit current failed");
631 }
632
Robin Pengc2b5ca92021-02-23 20:00:28 +0800633 ALOGI("Usb Gadget setcurrent functions called successfully");
Ricky Niub77191c2023-02-01 19:40:22 +0800634 return ScopedAStatus::ok();
Robin Pengc2b5ca92021-02-23 20:00:28 +0800635
636error:
637 ALOGI("Usb Gadget setcurrent functions failed");
638 if (callback == NULL)
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800639 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
640 -1, "Usb Gadget setcurrent functions failed");
641 ScopedAStatus ret = callback->setCurrentUsbFunctionsCb(functions, status, in_transactionId);
Robin Pengc2b5ca92021-02-23 20:00:28 +0800642 if (!ret.isOk())
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800643 ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.getDescription().c_str());
644 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
645 -1, "Error while calling setCurrentUsbFunctionsCb");
Robin Pengc2b5ca92021-02-23 20:00:28 +0800646}
Robin Pengc2b5ca92021-02-23 20:00:28 +0800647} // namespace gadget
648} // namespace usb
649} // namespace hardware
650} // namespace android
Ricky Niud6d0b7d2022-07-06 20:57:02 +0800651} // aidl