blob: 361cefd795ffd6c9cd39ad4eb886a62be0b1af4c [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
Ray Chiba3dc9b2022-03-01 21:57:03 +080036UsbGadget::UsbGadget() : mGadgetIrqPath("") {
Robin Pengc2b5ca92021-02-23 20:00:28 +080037 if (access(OS_DESC_PATH, R_OK) != 0) {
38 ALOGE("configfs setup not done yet");
39 abort();
40 }
41}
42
Ray Chiba3dc9b2022-03-01 21:57:03 +080043V1_0::Status UsbGadget::getUsbGadgetIrqPath() {
44 std::string irqs;
45 size_t read_pos = 0;
46 size_t found_pos = 0;
47
48 if (!ReadFileToString(kProcInterruptsPath, &irqs)) {
49 ALOGE("cannot read all interrupts");
50 return Status::ERROR;
51 }
52
53 while (true) {
54 found_pos = irqs.find_first_of("\n", read_pos);
55 if (found_pos == std::string::npos) {
56 ALOGI("the string of all interrupts is unexpected");
57 return Status::ERROR;
58 }
59
60 std::string single_irq = irqs.substr(read_pos, found_pos - read_pos);
61
62 if (single_irq.find("dwc3", 0) != std::string::npos) {
63 unsigned int dwc3_irq_number;
64 size_t dwc3_pos = single_irq.find_first_of(":");
65 if (!ParseUint(single_irq.substr(0, dwc3_pos), &dwc3_irq_number)) {
66 ALOGI("unknown IRQ strings");
67 return Status::ERROR;
68 }
69
70 mGadgetIrqPath = kProcIrqPath + single_irq.substr(0, dwc3_pos) + kSmpAffinityList;
71 break;
72 }
73
74 if (found_pos == irqs.npos) {
75 ALOGI("USB gadget doesn't start");
76 return Status::ERROR;
77 }
78
79 read_pos = found_pos + 1;
80 }
81
82 return Status::SUCCESS;
83}
84
Robin Pengc2b5ca92021-02-23 20:00:28 +080085void currentFunctionsAppliedCallback(bool functionsApplied, void *payload) {
86 UsbGadget *gadget = (UsbGadget *)payload;
87 gadget->mCurrentUsbFunctionsApplied = functionsApplied;
88}
89
90Return<void> UsbGadget::getCurrentUsbFunctions(const sp<V1_0::IUsbGadgetCallback> &callback) {
91 Return<void> ret = callback->getCurrentUsbFunctionsCb(
92 mCurrentUsbFunctions,
93 mCurrentUsbFunctionsApplied ? Status::FUNCTIONS_APPLIED : Status::FUNCTIONS_NOT_APPLIED);
94 if (!ret.isOk())
95 ALOGE("Call to getCurrentUsbFunctionsCb failed %s", ret.description().c_str());
96
97 return Void();
98}
99
100Return<void> UsbGadget::getUsbSpeed(const sp<V1_2::IUsbGadgetCallback> &callback) {
101 std::string current_speed;
102 if (ReadFileToString(SPEED_PATH, &current_speed)) {
103 current_speed = Trim(current_speed);
104 ALOGI("current USB speed is %s", current_speed.c_str());
105 if (current_speed == "low-speed")
106 mUsbSpeed = UsbSpeed::LOWSPEED;
107 else if (current_speed == "full-speed")
108 mUsbSpeed = UsbSpeed::FULLSPEED;
109 else if (current_speed == "high-speed")
110 mUsbSpeed = UsbSpeed::HIGHSPEED;
111 else if (current_speed == "super-speed")
112 mUsbSpeed = UsbSpeed::SUPERSPEED;
113 else if (current_speed == "super-speed-plus")
114 mUsbSpeed = UsbSpeed::SUPERSPEED_10Gb;
115 else if (current_speed == "UNKNOWN")
116 mUsbSpeed = UsbSpeed::UNKNOWN;
117 else
118 mUsbSpeed = UsbSpeed::RESERVED_SPEED;
119 } else {
120 ALOGE("Fail to read current speed");
121 mUsbSpeed = UsbSpeed::UNKNOWN;
122 }
123
124 if (callback) {
125 Return<void> ret = callback->getUsbSpeedCb(mUsbSpeed);
126
127 if (!ret.isOk())
128 ALOGE("Call to getUsbSpeedCb failed %s", ret.description().c_str());
129 }
130
131 return Void();
132}
133
134V1_0::Status UsbGadget::tearDownGadget() {
135 if (resetGadget() != Status::SUCCESS)
136 return Status::ERROR;
137
138 if (monitorFfs.isMonitorRunning()) {
139 monitorFfs.reset();
140 } else {
141 ALOGI("mMonitor not running");
142 }
143 return Status::SUCCESS;
144}
145
146static V1_0::Status validateAndSetVidPid(uint64_t functions) {
147 V1_0::Status ret = Status::SUCCESS;
148 std::string vendorFunctions = getVendorFunctions();
149
150 switch (functions) {
151 case static_cast<uint64_t>(GadgetFunction::MTP):
152 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
153 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
154 ret = Status::CONFIGURATION_NOT_SUPPORTED;
155 } else {
156 ret = setVidPid("0x18d1", "0x4ee1");
157 }
158 break;
159 case GadgetFunction::ADB | GadgetFunction::MTP:
160 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
161 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
162 ret = Status::CONFIGURATION_NOT_SUPPORTED;
163 } else {
164 ret = setVidPid("0x18d1", "0x4ee2");
165 }
166 break;
167 case static_cast<uint64_t>(GadgetFunction::RNDIS):
168 case GadgetFunction::RNDIS | GadgetFunction::NCM:
169 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
170 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
171 ret = Status::CONFIGURATION_NOT_SUPPORTED;
172 } else {
173 ret = setVidPid("0x18d1", "0x4ee3");
174 }
175 break;
176 case GadgetFunction::ADB | GadgetFunction::RNDIS:
177 case GadgetFunction::ADB | GadgetFunction::RNDIS | GadgetFunction::NCM:
178 if (vendorFunctions == "dm") {
179 ret = setVidPid("0x04e8", "0x6862");
180 } else {
181 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
182 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
183 ret = Status::CONFIGURATION_NOT_SUPPORTED;
184 } else {
185 ret = setVidPid("0x18d1", "0x4ee4");
186 }
187 }
188 break;
189 case static_cast<uint64_t>(GadgetFunction::PTP):
190 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
191 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
192 ret = Status::CONFIGURATION_NOT_SUPPORTED;
193 } else {
194 ret = setVidPid("0x18d1", "0x4ee5");
195 }
196 break;
197 case GadgetFunction::ADB | GadgetFunction::PTP:
198 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
199 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
200 ret = Status::CONFIGURATION_NOT_SUPPORTED;
201 } else {
202 ret = setVidPid("0x18d1", "0x4ee6");
203 }
204 break;
205 case static_cast<uint64_t>(GadgetFunction::ADB):
206 if (vendorFunctions == "dm") {
207 ret = setVidPid("0x04e8", "0x6862");
208 } else if (vendorFunctions == "etr_miu") {
209 ret = setVidPid("0x18d1", "0x4ee2");
Puma Hsufbcb7ad2021-08-19 19:36:51 +0800210 } else if (vendorFunctions == "uwb_acm"){
211 ret = setVidPid("0x18d1", "0x4ee2");
Robin Pengc2b5ca92021-02-23 20:00:28 +0800212 } else {
213 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
214 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
215 ret = Status::CONFIGURATION_NOT_SUPPORTED;
216 } else {
217 ret = setVidPid("0x18d1", "0x4ee7");
218 }
219 }
220 break;
221 case static_cast<uint64_t>(GadgetFunction::MIDI):
222 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
223 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
224 ret = Status::CONFIGURATION_NOT_SUPPORTED;
225 } else {
226 ret = setVidPid("0x18d1", "0x4ee8");
227 }
228 break;
229 case GadgetFunction::ADB | GadgetFunction::MIDI:
230 if (!(vendorFunctions == "user" || vendorFunctions == "")) {
231 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
232 ret = Status::CONFIGURATION_NOT_SUPPORTED;
233 } else {
234 ret = setVidPid("0x18d1", "0x4ee9");
235 }
236 break;
237 case static_cast<uint64_t>(GadgetFunction::ACCESSORY):
238 if (!(vendorFunctions == "user" || vendorFunctions == ""))
239 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
240 ret = setVidPid("0x18d1", "0x2d00");
241 break;
242 case GadgetFunction::ADB | GadgetFunction::ACCESSORY:
243 if (!(vendorFunctions == "user" || vendorFunctions == ""))
244 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
245 ret = setVidPid("0x18d1", "0x2d01");
246 break;
247 case static_cast<uint64_t>(GadgetFunction::AUDIO_SOURCE):
248 if (!(vendorFunctions == "user" || vendorFunctions == ""))
249 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
250 ret = setVidPid("0x18d1", "0x2d02");
251 break;
252 case GadgetFunction::ADB | GadgetFunction::AUDIO_SOURCE:
253 if (!(vendorFunctions == "user" || vendorFunctions == ""))
254 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
255 ret = setVidPid("0x18d1", "0x2d03");
256 break;
257 case GadgetFunction::ACCESSORY | GadgetFunction::AUDIO_SOURCE:
258 if (!(vendorFunctions == "user" || vendorFunctions == ""))
259 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
260 ret = setVidPid("0x18d1", "0x2d04");
261 break;
262 case GadgetFunction::ADB | GadgetFunction::ACCESSORY | GadgetFunction::AUDIO_SOURCE:
263 if (!(vendorFunctions == "user" || vendorFunctions == ""))
264 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
265 ret = setVidPid("0x18d1", "0x2d05");
266 break;
267 case static_cast<uint64_t>(GadgetFunction::NCM):
268 if (!(vendorFunctions == "user" || vendorFunctions == ""))
269 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
Maciej Żenczykowskie0ccd8f2020-12-27 19:58:32 -0800270 ret = setVidPid("0x18d1", "0x4eeb");
Robin Pengc2b5ca92021-02-23 20:00:28 +0800271 break;
272 case GadgetFunction::ADB | GadgetFunction::NCM:
Ricky Niu48b3e5d2021-11-24 17:26:38 +0800273 if (vendorFunctions == "dm") {
274 ret = setVidPid("0x04e8", "0x6862");
275 } else {
276 if (!(vendorFunctions == "user" || vendorFunctions == ""))
277 ALOGE("Invalid vendorFunctions set: %s", vendorFunctions.c_str());
278 ret = setVidPid("0x18d1", "0x4eec");
279 }
Robin Pengc2b5ca92021-02-23 20:00:28 +0800280 break;
281 default:
282 ALOGE("Combination not supported");
283 ret = Status::CONFIGURATION_NOT_SUPPORTED;
284 }
285 return ret;
286}
287
288Return<Status> UsbGadget::reset() {
289 ALOGI("USB Gadget reset");
290
291 if (!WriteStringToFile("none", PULLUP_PATH)) {
292 ALOGI("Gadget cannot be pulled down");
293 return Status::ERROR;
294 }
295
296 usleep(kDisconnectWaitUs);
297
298 if (!WriteStringToFile(kGadgetName, PULLUP_PATH)) {
299 ALOGI("Gadget cannot be pulled up");
300 return Status::ERROR;
301 }
302
303 return Status::SUCCESS;
304}
305
306V1_0::Status UsbGadget::setupFunctions(uint64_t functions,
307 const sp<V1_0::IUsbGadgetCallback> &callback,
308 uint64_t timeout) {
309 bool ffsEnabled = false;
310 int i = 0;
311
Maciej Żenczykowskie0ccd8f2020-12-27 19:58:32 -0800312 if (addGenericAndroidFunctions(&monitorFfs, functions, &ffsEnabled, &i) !=
Robin Pengc2b5ca92021-02-23 20:00:28 +0800313 Status::SUCCESS)
314 return Status::ERROR;
315
Robin Pengc2b5ca92021-02-23 20:00:28 +0800316 std::string vendorFunctions = getVendorFunctions();
317
318 if (vendorFunctions == "dm") {
319 ALOGI("enable usbradio debug functions");
Maciej Żenczykowskie0ccd8f2020-12-27 19:58:32 -0800320 if ((functions & GadgetFunction::RNDIS) != 0) {
Robin Pengc2b5ca92021-02-23 20:00:28 +0800321 if (linkFunction("acm.gs6", i++))
322 return Status::ERROR;
323 if (linkFunction("dm.gs7", i++))
324 return Status::ERROR;
325 } else {
326 if (linkFunction("dm.gs7", i++))
327 return Status::ERROR;
328 if (linkFunction("acm.gs6", i++))
329 return Status::ERROR;
330 }
331 } else if (vendorFunctions == "etr_miu") {
332 ALOGI("enable etr_miu functions");
333 if (linkFunction("etr_miu.gs11", i++))
334 return Status::ERROR;
Puma Hsufbcb7ad2021-08-19 19:36:51 +0800335 } else if (vendorFunctions == "uwb_acm") {
336 ALOGI("enable uwb acm function");
337 if (linkFunction("acm.uwb0", i++))
338 return Status::ERROR;
Robin Pengc2b5ca92021-02-23 20:00:28 +0800339 }
340
Maciej Żenczykowskie0ccd8f2020-12-27 19:58:32 -0800341 if ((functions & GadgetFunction::ADB) != 0) {
Robin Pengc2b5ca92021-02-23 20:00:28 +0800342 ffsEnabled = true;
343 if (addAdb(&monitorFfs, &i) != Status::SUCCESS)
344 return Status::ERROR;
345 }
346
Maciej Żenczykowskie0ccd8f2020-12-27 19:58:32 -0800347 if ((functions & GadgetFunction::NCM) != 0) {
348 ALOGI("setCurrentUsbFunctions ncm");
349 if (linkFunction("ncm.gs9", i++))
Robin Pengc2b5ca92021-02-23 20:00:28 +0800350 return Status::ERROR;
351 }
352
353 // Pull up the gadget right away when there are no ffs functions.
354 if (!ffsEnabled) {
355 if (!WriteStringToFile(kGadgetName, PULLUP_PATH))
356 return Status::ERROR;
357 mCurrentUsbFunctionsApplied = true;
358 if (callback)
359 callback->setCurrentUsbFunctionsCb(functions, Status::SUCCESS);
360 return Status::SUCCESS;
361 }
362
363 monitorFfs.registerFunctionsAppliedCallback(&currentFunctionsAppliedCallback, this);
364 // Monitors the ffs paths to pull up the gadget when descriptors are written.
365 // Also takes of the pulling up the gadget again if the userspace process
366 // dies and restarts.
367 monitorFfs.startMonitor();
368
369 if (kDebug)
370 ALOGI("Mainthread in Cv");
371
372 if (callback) {
373 bool pullup = monitorFfs.waitForPullUp(timeout);
374 Return<void> ret = callback->setCurrentUsbFunctionsCb(
375 functions, pullup ? Status::SUCCESS : Status::ERROR);
376 if (!ret.isOk())
377 ALOGE("setCurrentUsbFunctionsCb error %s", ret.description().c_str());
378 }
379
380 return Status::SUCCESS;
381}
382
383Return<void> UsbGadget::setCurrentUsbFunctions(uint64_t functions,
384 const sp<V1_0::IUsbGadgetCallback> &callback,
385 uint64_t timeout) {
386 std::unique_lock<std::mutex> lk(mLockSetCurrentFunction);
387
388 mCurrentUsbFunctions = functions;
389 mCurrentUsbFunctionsApplied = false;
390
Ray Chiba3dc9b2022-03-01 21:57:03 +0800391 // Get the gadget IRQ number before tearDownGadget()
392 if (mGadgetIrqPath.empty())
393 getUsbGadgetIrqPath();
394
Robin Pengc2b5ca92021-02-23 20:00:28 +0800395 // Unlink the gadget and stop the monitor if running.
396 V1_0::Status status = tearDownGadget();
397 if (status != Status::SUCCESS) {
398 goto error;
399 }
400
401 ALOGI("Returned from tearDown gadget");
402
403 // Leave the gadget pulled down to give time for the host to sense disconnect.
404 usleep(kDisconnectWaitUs);
405
406 if (functions == static_cast<uint64_t>(GadgetFunction::NONE)) {
407 if (callback == NULL)
408 return Void();
409 Return<void> ret = callback->setCurrentUsbFunctionsCb(functions, Status::SUCCESS);
410 if (!ret.isOk())
411 ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.description().c_str());
412 return Void();
413 }
414
415 status = validateAndSetVidPid(functions);
416
417 if (status != Status::SUCCESS) {
418 goto error;
419 }
420
421 status = setupFunctions(functions, callback, timeout);
422 if (status != Status::SUCCESS) {
423 goto error;
424 }
425
Maciej Żenczykowskia24469c2021-06-25 11:42:01 -0700426 if (functions & GadgetFunction::NCM) {
Ray Chiba3dc9b2022-03-01 21:57:03 +0800427 if (!mGadgetIrqPath.empty()) {
428 if (!WriteStringToFile(BIG_CORE, mGadgetIrqPath))
429 ALOGI("Cannot move gadget IRQ to big core, path:%s", mGadgetIrqPath.c_str());
430 }
Maciej Żenczykowskia24469c2021-06-25 11:42:01 -0700431 } else {
Ray Chiba3dc9b2022-03-01 21:57:03 +0800432 if (!mGadgetIrqPath.empty()) {
433 if (!WriteStringToFile(MEDIUM_CORE, mGadgetIrqPath))
434 ALOGI("Cannot move gadget IRQ to medium core, path:%s", mGadgetIrqPath.c_str());
435 }
Maciej Żenczykowskia24469c2021-06-25 11:42:01 -0700436 }
437
Robin Pengc2b5ca92021-02-23 20:00:28 +0800438 ALOGI("Usb Gadget setcurrent functions called successfully");
439 return Void();
440
441error:
442 ALOGI("Usb Gadget setcurrent functions failed");
443 if (callback == NULL)
444 return Void();
445 Return<void> ret = callback->setCurrentUsbFunctionsCb(functions, status);
446 if (!ret.isOk())
447 ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.description().c_str());
448 return Void();
449}
450} // namespace implementation
451} // namespace V1_2
452} // namespace gadget
453} // namespace usb
454} // namespace hardware
455} // namespace android