blob: b6d1dd393e8f64a14d452f3bae274b1c3b7e3d7f [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
17#define LOG_TAG "android.hardware.usb.gadget@1.2-service.gs101"
18
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
29namespace android {
30namespace hardware {
31namespace usb {
32namespace gadget {
33namespace V1_2 {
34namespace implementation {
35
Ricky Niuebd7fca2022-05-09 10:14:20 +080036string enabledPath;
37constexpr char kHsi2cPath[] = "/sys/devices/platform/10d50000.hsi2c";
38constexpr char kI2CPath[] = "/sys/devices/platform/10d50000.hsi2c/i2c-";
39constexpr char kAccessoryLimitCurrent[] = "i2c-max77759tcpc/usb_limit_accessory_current";
40constexpr char kAccessoryLimitCurrentEnable[] = "i2c-max77759tcpc/usb_limit_accessory_enable";
41
Ray Chiba3dc9b2022-03-01 21:57:03 +080042UsbGadget::UsbGadget() : mGadgetIrqPath("") {
Robin Pengc2b5ca92021-02-23 20:00:28 +080043 if (access(OS_DESC_PATH, R_OK) != 0) {
44 ALOGE("configfs setup not done yet");
45 abort();
46 }
47}
48
Ray Chiba3dc9b2022-03-01 21:57:03 +080049V1_0::Status UsbGadget::getUsbGadgetIrqPath() {
50 std::string irqs;
51 size_t read_pos = 0;
52 size_t found_pos = 0;
53
54 if (!ReadFileToString(kProcInterruptsPath, &irqs)) {
55 ALOGE("cannot read all interrupts");
56 return Status::ERROR;
57 }
58
59 while (true) {
60 found_pos = irqs.find_first_of("\n", read_pos);
61 if (found_pos == std::string::npos) {
62 ALOGI("the string of all interrupts is unexpected");
63 return Status::ERROR;
64 }
65
66 std::string single_irq = irqs.substr(read_pos, found_pos - read_pos);
67
68 if (single_irq.find("dwc3", 0) != std::string::npos) {
69 unsigned int dwc3_irq_number;
70 size_t dwc3_pos = single_irq.find_first_of(":");
71 if (!ParseUint(single_irq.substr(0, dwc3_pos), &dwc3_irq_number)) {
72 ALOGI("unknown IRQ strings");
73 return Status::ERROR;
74 }
75
76 mGadgetIrqPath = kProcIrqPath + single_irq.substr(0, dwc3_pos) + kSmpAffinityList;
77 break;
78 }
79
80 if (found_pos == irqs.npos) {
81 ALOGI("USB gadget doesn't start");
82 return Status::ERROR;
83 }
84
85 read_pos = found_pos + 1;
86 }
87
88 return Status::SUCCESS;
89}
90
Robin Pengc2b5ca92021-02-23 20:00:28 +080091void currentFunctionsAppliedCallback(bool functionsApplied, void *payload) {
92 UsbGadget *gadget = (UsbGadget *)payload;
93 gadget->mCurrentUsbFunctionsApplied = functionsApplied;
94}
95
96Return<void> UsbGadget::getCurrentUsbFunctions(const sp<V1_0::IUsbGadgetCallback> &callback) {
97 Return<void> ret = callback->getCurrentUsbFunctionsCb(
98 mCurrentUsbFunctions,
99 mCurrentUsbFunctionsApplied ? Status::FUNCTIONS_APPLIED : Status::FUNCTIONS_NOT_APPLIED);
100 if (!ret.isOk())
101 ALOGE("Call to getCurrentUsbFunctionsCb failed %s", ret.description().c_str());
102
103 return Void();
104}
105
106Return<void> UsbGadget::getUsbSpeed(const sp<V1_2::IUsbGadgetCallback> &callback) {
107 std::string current_speed;
108 if (ReadFileToString(SPEED_PATH, &current_speed)) {
109 current_speed = Trim(current_speed);
110 ALOGI("current USB speed is %s", current_speed.c_str());
111 if (current_speed == "low-speed")
112 mUsbSpeed = UsbSpeed::LOWSPEED;
113 else if (current_speed == "full-speed")
114 mUsbSpeed = UsbSpeed::FULLSPEED;
115 else if (current_speed == "high-speed")
116 mUsbSpeed = UsbSpeed::HIGHSPEED;
117 else if (current_speed == "super-speed")
118 mUsbSpeed = UsbSpeed::SUPERSPEED;
119 else if (current_speed == "super-speed-plus")
120 mUsbSpeed = UsbSpeed::SUPERSPEED_10Gb;
121 else if (current_speed == "UNKNOWN")
122 mUsbSpeed = UsbSpeed::UNKNOWN;
123 else
124 mUsbSpeed = UsbSpeed::RESERVED_SPEED;
125 } else {
126 ALOGE("Fail to read current speed");
127 mUsbSpeed = UsbSpeed::UNKNOWN;
128 }
129
130 if (callback) {
131 Return<void> ret = callback->getUsbSpeedCb(mUsbSpeed);
132
133 if (!ret.isOk())
134 ALOGE("Call to getUsbSpeedCb failed %s", ret.description().c_str());
135 }
136
137 return Void();
138}
139
140V1_0::Status UsbGadget::tearDownGadget() {
141 if (resetGadget() != Status::SUCCESS)
142 return Status::ERROR;
143
144 if (monitorFfs.isMonitorRunning()) {
145 monitorFfs.reset();
146 } else {
147 ALOGI("mMonitor not running");
148 }
149 return Status::SUCCESS;
150}
151
152static V1_0::Status validateAndSetVidPid(uint64_t functions) {
153 V1_0::Status ret = Status::SUCCESS;
154 std::string vendorFunctions = getVendorFunctions();
155
156 switch (functions) {
157 case static_cast<uint64_t>(GadgetFunction::MTP):
158 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
159 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
160 ret = Status::CONFIGURATION_NOT_SUPPORTED;
161 } else {
162 ret = setVidPid("0x18d1", "0x4ee1");
163 }
164 break;
165 case GadgetFunction::ADB | GadgetFunction::MTP:
166 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
167 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
168 ret = Status::CONFIGURATION_NOT_SUPPORTED;
169 } else {
170 ret = setVidPid("0x18d1", "0x4ee2");
171 }
172 break;
173 case static_cast<uint64_t>(GadgetFunction::RNDIS):
174 case GadgetFunction::RNDIS | GadgetFunction::NCM:
175 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
176 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
177 ret = Status::CONFIGURATION_NOT_SUPPORTED;
178 } else {
179 ret = setVidPid("0x18d1", "0x4ee3");
180 }
181 break;
182 case GadgetFunction::ADB | GadgetFunction::RNDIS:
183 case GadgetFunction::ADB | GadgetFunction::RNDIS | GadgetFunction::NCM:
184 if (vendorFunctions == "dm") {
185 ret = setVidPid("0x04e8", "0x6862");
186 } else {
187 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
188 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
189 ret = Status::CONFIGURATION_NOT_SUPPORTED;
190 } else {
191 ret = setVidPid("0x18d1", "0x4ee4");
192 }
193 }
194 break;
195 case static_cast<uint64_t>(GadgetFunction::PTP):
196 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
197 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
198 ret = Status::CONFIGURATION_NOT_SUPPORTED;
199 } else {
200 ret = setVidPid("0x18d1", "0x4ee5");
201 }
202 break;
203 case GadgetFunction::ADB | GadgetFunction::PTP:
204 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
205 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
206 ret = Status::CONFIGURATION_NOT_SUPPORTED;
207 } else {
208 ret = setVidPid("0x18d1", "0x4ee6");
209 }
210 break;
211 case static_cast<uint64_t>(GadgetFunction::ADB):
212 if (vendorFunctions == "dm") {
213 ret = setVidPid("0x04e8", "0x6862");
214 } else if (vendorFunctions == "etr_miu") {
215 ret = setVidPid("0x18d1", "0x4ee2");
Puma Hsufbcb7ad2021-08-19 19:36:51 +0800216 } else if (vendorFunctions == "uwb_acm"){
217 ret = setVidPid("0x18d1", "0x4ee2");
Robin Pengc2b5ca92021-02-23 20:00:28 +0800218 } else {
219 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
220 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
221 ret = Status::CONFIGURATION_NOT_SUPPORTED;
222 } else {
223 ret = setVidPid("0x18d1", "0x4ee7");
224 }
225 }
226 break;
227 case static_cast<uint64_t>(GadgetFunction::MIDI):
228 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
229 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
230 ret = Status::CONFIGURATION_NOT_SUPPORTED;
231 } else {
232 ret = setVidPid("0x18d1", "0x4ee8");
233 }
234 break;
235 case GadgetFunction::ADB | GadgetFunction::MIDI:
236 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
237 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
238 ret = Status::CONFIGURATION_NOT_SUPPORTED;
239 } else {
240 ret = setVidPid("0x18d1", "0x4ee9");
241 }
242 break;
243 case static_cast<uint64_t>(GadgetFunction::ACCESSORY):
244 if (!(vendorFunctions == "user" || vendorFunctions == ""))
245 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
246 ret = setVidPid("0x18d1", "0x2d00");
247 break;
248 case GadgetFunction::ADB | GadgetFunction::ACCESSORY:
249 if (!(vendorFunctions == "user" || vendorFunctions == ""))
250 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
251 ret = setVidPid("0x18d1", "0x2d01");
252 break;
253 case static_cast<uint64_t>(GadgetFunction::AUDIO_SOURCE):
254 if (!(vendorFunctions == "user" || vendorFunctions == ""))
255 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
256 ret = setVidPid("0x18d1", "0x2d02");
257 break;
258 case GadgetFunction::ADB | GadgetFunction::AUDIO_SOURCE:
259 if (!(vendorFunctions == "user" || vendorFunctions == ""))
260 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
261 ret = setVidPid("0x18d1", "0x2d03");
262 break;
263 case GadgetFunction::ACCESSORY | GadgetFunction::AUDIO_SOURCE:
264 if (!(vendorFunctions == "user" || vendorFunctions == ""))
265 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
266 ret = setVidPid("0x18d1", "0x2d04");
267 break;
268 case GadgetFunction::ADB | GadgetFunction::ACCESSORY | GadgetFunction::AUDIO_SOURCE:
269 if (!(vendorFunctions == "user" || vendorFunctions == ""))
270 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
271 ret = setVidPid("0x18d1", "0x2d05");
272 break;
273 case static_cast<uint64_t>(GadgetFunction::NCM):
274 if (!(vendorFunctions == "user" || vendorFunctions == ""))
275 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
Maciej Żenczykowskie0ccd8f2020-12-27 19:58:32 -0800276 ret = setVidPid("0x18d1", "0x4eeb");
Robin Pengc2b5ca92021-02-23 20:00:28 +0800277 break;
278 case GadgetFunction::ADB | GadgetFunction::NCM:
Ricky Niu48b3e5d2021-11-24 17:26:38 +0800279 if (vendorFunctions == "dm") {
280 ret = setVidPid("0x04e8", "0x6862");
281 } else {
282 if (!(vendorFunctions == "user" || vendorFunctions == ""))
283 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
284 ret = setVidPid("0x18d1", "0x4eec");
285 }
Robin Pengc2b5ca92021-02-23 20:00:28 +0800286 break;
287 default:
288 ALOGE("Combination not supported");
289 ret = Status::CONFIGURATION_NOT_SUPPORTED;
290 }
291 return ret;
292}
293
294Return<Status> UsbGadget::reset() {
295 ALOGI("USB Gadget reset");
296
297 if (!WriteStringToFile("none", PULLUP_PATH)) {
298 ALOGI("Gadget cannot be pulled down");
299 return Status::ERROR;
300 }
301
302 usleep(kDisconnectWaitUs);
303
304 if (!WriteStringToFile(kGadgetName, PULLUP_PATH)) {
305 ALOGI("Gadget cannot be pulled up");
306 return Status::ERROR;
307 }
308
309 return Status::SUCCESS;
310}
311
312V1_0::Status UsbGadget::setupFunctions(uint64_t functions,
313 const sp<V1_0::IUsbGadgetCallback> &callback,
314 uint64_t timeout) {
315 bool ffsEnabled = false;
316 int i = 0;
317
Maciej Żenczykowskie0ccd8f2020-12-27 19:58:32 -0800318 if (addGenericAndroidFunctions(&monitorFfs, functions, &ffsEnabled, &i) !=
Robin Pengc2b5ca92021-02-23 20:00:28 +0800319 Status::SUCCESS)
320 return Status::ERROR;
321
Robin Pengc2b5ca92021-02-23 20:00:28 +0800322 std::string vendorFunctions = getVendorFunctions();
323
324 if (vendorFunctions == "dm") {
325 ALOGI("enable usbradio debug functions");
Maciej Żenczykowskie0ccd8f2020-12-27 19:58:32 -0800326 if ((functions & GadgetFunction::RNDIS) != 0) {
Robin Pengc2b5ca92021-02-23 20:00:28 +0800327 if (linkFunction("acm.gs6", i++))
328 return Status::ERROR;
329 if (linkFunction("dm.gs7", i++))
330 return Status::ERROR;
331 } else {
332 if (linkFunction("dm.gs7", i++))
333 return Status::ERROR;
334 if (linkFunction("acm.gs6", i++))
335 return Status::ERROR;
336 }
337 } else if (vendorFunctions == "etr_miu") {
338 ALOGI("enable etr_miu functions");
339 if (linkFunction("etr_miu.gs11", i++))
340 return Status::ERROR;
Puma Hsufbcb7ad2021-08-19 19:36:51 +0800341 } else if (vendorFunctions == "uwb_acm") {
342 ALOGI("enable uwb acm function");
343 if (linkFunction("acm.uwb0", i++))
344 return Status::ERROR;
Robin Pengc2b5ca92021-02-23 20:00:28 +0800345 }
346
Maciej Żenczykowskie0ccd8f2020-12-27 19:58:32 -0800347 if ((functions & GadgetFunction::ADB) != 0) {
Robin Pengc2b5ca92021-02-23 20:00:28 +0800348 ffsEnabled = true;
349 if (addAdb(&monitorFfs, &i) != Status::SUCCESS)
350 return Status::ERROR;
351 }
352
Maciej Żenczykowskie0ccd8f2020-12-27 19:58:32 -0800353 if ((functions & GadgetFunction::NCM) != 0) {
354 ALOGI("setCurrentUsbFunctions ncm");
355 if (linkFunction("ncm.gs9", i++))
Robin Pengc2b5ca92021-02-23 20:00:28 +0800356 return Status::ERROR;
357 }
358
359 // Pull up the gadget right away when there are no ffs functions.
360 if (!ffsEnabled) {
361 if (!WriteStringToFile(kGadgetName, PULLUP_PATH))
362 return Status::ERROR;
363 mCurrentUsbFunctionsApplied = true;
364 if (callback)
365 callback->setCurrentUsbFunctionsCb(functions, Status::SUCCESS);
366 return Status::SUCCESS;
367 }
368
369 monitorFfs.registerFunctionsAppliedCallback(&currentFunctionsAppliedCallback, this);
370 // Monitors the ffs paths to pull up the gadget when descriptors are written.
371 // Also takes of the pulling up the gadget again if the userspace process
372 // dies and restarts.
373 monitorFfs.startMonitor();
374
375 if (kDebug)
376 ALOGI("Mainthread in Cv");
377
378 if (callback) {
379 bool pullup = monitorFfs.waitForPullUp(timeout);
380 Return<void> ret = callback->setCurrentUsbFunctionsCb(
381 functions, pullup ? Status::SUCCESS : Status::ERROR);
382 if (!ret.isOk())
383 ALOGE("setCurrentUsbFunctionsCb error %s", ret.description().c_str());
384 }
385
386 return Status::SUCCESS;
387}
388
Ricky Niuebd7fca2022-05-09 10:14:20 +0800389Status getI2cBusHelper(string *name) {
390 DIR *dp;
391
392 dp = opendir(kHsi2cPath);
393 if (dp != NULL) {
394 struct dirent *ep;
395
396 while ((ep = readdir(dp))) {
397 if (ep->d_type == DT_DIR) {
398 if (string::npos != string(ep->d_name).find("i2c-")) {
399 std::strtok(ep->d_name, "-");
400 *name = std::strtok(NULL, "-");
401 }
402 }
403 }
404 closedir(dp);
405 return Status::SUCCESS;
406 }
407
408 ALOGE("Failed to open %s", kHsi2cPath);
409 return Status::ERROR;
410}
411
Robin Pengc2b5ca92021-02-23 20:00:28 +0800412Return<void> UsbGadget::setCurrentUsbFunctions(uint64_t functions,
413 const sp<V1_0::IUsbGadgetCallback> &callback,
414 uint64_t timeout) {
415 std::unique_lock<std::mutex> lk(mLockSetCurrentFunction);
Ricky Niuebd7fca2022-05-09 10:14:20 +0800416 std::string current_usb_power_operation_mode, current_usb_type;
417 std::string usb_limit_sink_enable;
418
419 string accessoryCurrentLimitEnablePath, accessoryCurrentLimitPath, path;
Robin Pengc2b5ca92021-02-23 20:00:28 +0800420
421 mCurrentUsbFunctions = functions;
422 mCurrentUsbFunctionsApplied = false;
423
Ricky Niuebd7fca2022-05-09 10:14:20 +0800424 getI2cBusHelper(&path);
425 accessoryCurrentLimitPath = kI2CPath + path + "/" + kAccessoryLimitCurrent;
426 accessoryCurrentLimitEnablePath = kI2CPath + path + "/" + kAccessoryLimitCurrentEnable;
427
Ray Chiba3dc9b2022-03-01 21:57:03 +0800428 // Get the gadget IRQ number before tearDownGadget()
429 if (mGadgetIrqPath.empty())
430 getUsbGadgetIrqPath();
431
Robin Pengc2b5ca92021-02-23 20:00:28 +0800432 // Unlink the gadget and stop the monitor if running.
433 V1_0::Status status = tearDownGadget();
434 if (status != Status::SUCCESS) {
435 goto error;
436 }
437
438 ALOGI("Returned from tearDown gadget");
439
440 // Leave the gadget pulled down to give time for the host to sense disconnect.
441 usleep(kDisconnectWaitUs);
442
443 if (functions == static_cast<uint64_t>(GadgetFunction::NONE)) {
444 if (callback == NULL)
445 return Void();
446 Return<void> ret = callback->setCurrentUsbFunctionsCb(functions, Status::SUCCESS);
447 if (!ret.isOk())
448 ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.description().c_str());
449 return Void();
450 }
451
452 status = validateAndSetVidPid(functions);
453
454 if (status != Status::SUCCESS) {
455 goto error;
456 }
457
458 status = setupFunctions(functions, callback, timeout);
459 if (status != Status::SUCCESS) {
460 goto error;
461 }
462
Maciej Żenczykowskia24469c2021-06-25 11:42:01 -0700463 if (functions & GadgetFunction::NCM) {
Ray Chiba3dc9b2022-03-01 21:57:03 +0800464 if (!mGadgetIrqPath.empty()) {
465 if (!WriteStringToFile(BIG_CORE, mGadgetIrqPath))
466 ALOGI("Cannot move gadget IRQ to big core, path:%s", mGadgetIrqPath.c_str());
467 }
Maciej Żenczykowskia24469c2021-06-25 11:42:01 -0700468 } else {
Ray Chiba3dc9b2022-03-01 21:57:03 +0800469 if (!mGadgetIrqPath.empty()) {
470 if (!WriteStringToFile(MEDIUM_CORE, mGadgetIrqPath))
471 ALOGI("Cannot move gadget IRQ to medium core, path:%s", mGadgetIrqPath.c_str());
472 }
Maciej Żenczykowskia24469c2021-06-25 11:42:01 -0700473 }
474
Ricky Niuebd7fca2022-05-09 10:14:20 +0800475 if (ReadFileToString(CURRENT_USB_TYPE_PATH, &current_usb_type))
476 current_usb_type = Trim(current_usb_type);
477
478 if (ReadFileToString(CURRENT_USB_POWER_OPERATION_MODE_PATH, &current_usb_power_operation_mode))
479 current_usb_power_operation_mode = Trim(current_usb_power_operation_mode);
480
481 if (functions & GadgetFunction::ACCESSORY &&
482 current_usb_type == "Unknown SDP [CDP] DCP" &&
483 (current_usb_power_operation_mode == "default" ||
484 current_usb_power_operation_mode == "1.5A")) {
485 if (!WriteStringToFile("1300000", accessoryCurrentLimitPath)) {
486 ALOGI("Write 1.3A to limit current fail");
487 } else {
488 if (!WriteStringToFile("1", accessoryCurrentLimitEnablePath)) {
489 ALOGI("Enable limit current fail");
490 }
491 }
492 } else {
493 if (!WriteStringToFile("0", accessoryCurrentLimitEnablePath))
494 ALOGI("unvote accessory limit current failed");
495 }
496
Robin Pengc2b5ca92021-02-23 20:00:28 +0800497 ALOGI("Usb Gadget setcurrent functions called successfully");
498 return Void();
499
500error:
501 ALOGI("Usb Gadget setcurrent functions failed");
502 if (callback == NULL)
503 return Void();
504 Return<void> ret = callback->setCurrentUsbFunctionsCb(functions, status);
505 if (!ret.isOk())
506 ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.description().c_str());
507 return Void();
508}
509} // namespace implementation
510} // namespace V1_2
511} // namespace gadget
512} // namespace usb
513} // namespace hardware
514} // namespace android