blob: 72cf681e5dac85d1153bc7c821adb38baf03c9ad [file] [log] [blame]
Ricky Niu1eaaea42022-02-10 14:52:12 +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.aidl-service"
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
29#include <aidl/android/frameworks/stats/IStats.h>
30
31namespace aidl {
32namespace android {
33namespace hardware {
34namespace usb {
35namespace gadget {
36
37string enabledPath;
38constexpr char kHsi2cPath[] = "/sys/devices/platform/10d50000.hsi2c";
39constexpr char kI2CPath[] = "/sys/devices/platform/10d50000.hsi2c/i2c-";
40constexpr char kAccessoryLimitCurrent[] = "i2c-max77759tcpc/usb_limit_accessory_current";
41constexpr char kAccessoryLimitCurrentEnable[] = "i2c-max77759tcpc/usb_limit_accessory_enable";
42
43UsbGadget::UsbGadget() : mGadgetIrqPath("") {}
44
45Status UsbGadget::getUsbGadgetIrqPath() {
46 std::string irqs;
47 size_t read_pos = 0;
48 size_t found_pos = 0;
49
50 if (!ReadFileToString(kProcInterruptsPath, &irqs)) {
51 ALOGE("cannot read all interrupts");
52 return Status::ERROR;
53 }
54
55 while (true) {
56 found_pos = irqs.find_first_of("\n", read_pos);
57 if (found_pos == std::string::npos) {
58 ALOGI("the string of all interrupts is unexpected");
59 return Status::ERROR;
60 }
61
62 std::string single_irq = irqs.substr(read_pos, found_pos - read_pos);
63
64 if (single_irq.find("dwc3", 0) != std::string::npos) {
65 unsigned int dwc3_irq_number;
66 size_t dwc3_pos = single_irq.find_first_of(":");
67 if (!ParseUint(single_irq.substr(0, dwc3_pos), &dwc3_irq_number)) {
68 ALOGI("unknown IRQ strings");
69 return Status::ERROR;
70 }
71
72 mGadgetIrqPath = kProcIrqPath + single_irq.substr(0, dwc3_pos) + kSmpAffinityList;
73 break;
74 }
75
76 if (found_pos == irqs.npos) {
77 ALOGI("USB gadget doesn't start");
78 return Status::ERROR;
79 }
80
81 read_pos = found_pos + 1;
82 }
83
84 return Status::SUCCESS;
85}
86
87void currentFunctionsAppliedCallback(bool functionsApplied, void* payload) {
88 UsbGadget* gadget = (UsbGadget*)payload;
89 gadget->mCurrentUsbFunctionsApplied = functionsApplied;
90}
91
92ScopedAStatus UsbGadget::getCurrentUsbFunctions(const shared_ptr<IUsbGadgetCallback>& callback,
93 int64_t in_transactionId) {
94 ScopedAStatus ret = callback->getCurrentUsbFunctionsCb(
95 mCurrentUsbFunctions,
96 mCurrentUsbFunctionsApplied ? Status::FUNCTIONS_APPLIED : Status::FUNCTIONS_NOT_APPLIED,
97 in_transactionId);
98 if (!ret.isOk())
99 ALOGE("Call to getCurrentUsbFunctionsCb failed %s", ret.getDescription().c_str());
100
101 return ScopedAStatus::ok();
102}
103
104ScopedAStatus UsbGadget::getUsbSpeed(const shared_ptr<IUsbGadgetCallback>& callback,
105 int64_t in_transactionId) {
106 std::string current_speed;
107 if (ReadFileToString(SPEED_PATH, &current_speed)) {
108 current_speed = Trim(current_speed);
109 ALOGI("current USB speed is %s", current_speed.c_str());
110 if (current_speed == "low-speed")
111 mUsbSpeed = UsbSpeed::LOWSPEED;
112 else if (current_speed == "full-speed")
113 mUsbSpeed = UsbSpeed::FULLSPEED;
114 else if (current_speed == "high-speed")
115 mUsbSpeed = UsbSpeed::HIGHSPEED;
116 else if (current_speed == "super-speed")
117 mUsbSpeed = UsbSpeed::SUPERSPEED;
118 else if (current_speed == "super-speed-plus")
119 mUsbSpeed = UsbSpeed::SUPERSPEED_10Gb;
120 else if (current_speed == "UNKNOWN")
121 mUsbSpeed = UsbSpeed::UNKNOWN;
122 else
123 mUsbSpeed = UsbSpeed::UNKNOWN;
124 } else {
125 ALOGE("Fail to read current speed");
126 mUsbSpeed = UsbSpeed::UNKNOWN;
127 }
128
129 if (callback) {
130 ScopedAStatus ret = callback->getUsbSpeedCb(mUsbSpeed, in_transactionId);
131
132 if (!ret.isOk()) ALOGE("Call to getUsbSpeedCb failed %s", ret.getDescription().c_str());
133 }
134
135 return ScopedAStatus::ok();
136}
137
138Status UsbGadget::tearDownGadget() {
139 return Status::SUCCESS;
140}
141
142ScopedAStatus UsbGadget::reset() {
143 return ScopedAStatus::ok();
144}
145
146Status UsbGadget::setupFunctions(long functions, const shared_ptr<IUsbGadgetCallback>& callback,
147 uint64_t timeout, int64_t in_transactionId) {
148 bool ffsEnabled = false;
Ricky Niucf684312023-01-12 14:48:53 +0800149 if (timeout == 0) {
150 ALOGI("timeout not setup");
151 }
Ricky Niu1eaaea42022-02-10 14:52:12 +0800152
153 if ((functions & GadgetFunction::ADB) != 0) {
154 ffsEnabled = true;
155 }
156
157 if ((functions & GadgetFunction::NCM) != 0) {
158 ALOGI("setCurrentUsbFunctions ncm");
159 }
160
161 // Pull up the gadget right away when there are no ffs functions.
162 if (!ffsEnabled) {
163 mCurrentUsbFunctionsApplied = true;
164 if (callback)
165 callback->setCurrentUsbFunctionsCb(functions, Status::SUCCESS, in_transactionId);
166 return Status::SUCCESS;
167 }
168
169 return Status::SUCCESS;
170}
171
172Status getI2cBusHelper(string* name) {
173 DIR* dp;
174
175 dp = opendir(kHsi2cPath);
176 if (dp != NULL) {
177 struct dirent* ep;
178
179 while ((ep = readdir(dp))) {
180 if (ep->d_type == DT_DIR) {
181 if (string::npos != string(ep->d_name).find("i2c-")) {
182 std::strtok(ep->d_name, "-");
183 *name = std::strtok(NULL, "-");
184 }
185 }
186 }
187 closedir(dp);
188 return Status::SUCCESS;
189 }
190
191 ALOGE("Failed to open %s", kHsi2cPath);
192 return Status::ERROR;
193}
194
Ricky Niucf684312023-01-12 14:48:53 +0800195ScopedAStatus UsbGadget::setCurrentUsbFunctions(int64_t functions,
Ricky Niu1eaaea42022-02-10 14:52:12 +0800196 const shared_ptr<IUsbGadgetCallback>& callback,
Ricky Niucf684312023-01-12 14:48:53 +0800197 int64_t timeoutMs, int64_t in_transactionId) {
Ricky Niu1eaaea42022-02-10 14:52:12 +0800198 std::unique_lock<std::mutex> lk(mLockSetCurrentFunction);
199 std::string current_usb_power_operation_mode, current_usb_type;
200 std::string usb_limit_sink_enable;
201
202 string accessoryCurrentLimitEnablePath, accessoryCurrentLimitPath, path;
203
Ricky Niu1eaaea42022-02-10 14:52:12 +0800204 mCurrentUsbFunctions = functions;
205 mCurrentUsbFunctionsApplied = false;
206
207 getI2cBusHelper(&path);
208 accessoryCurrentLimitPath = kI2CPath + path + "/" + kAccessoryLimitCurrent;
209 accessoryCurrentLimitEnablePath = kI2CPath + path + "/" + kAccessoryLimitCurrentEnable;
210
211 // Get the gadget IRQ number before tearDownGadget()
212 if (mGadgetIrqPath.empty()) getUsbGadgetIrqPath();
213
214 // Unlink the gadget and stop the monitor if running.
215 Status status = tearDownGadget();
216 if (status != Status::SUCCESS) {
217 goto error;
218 }
219
220 ALOGI("Returned from tearDown gadget");
221
222 // Leave the gadget pulled down to give time for the host to sense disconnect.
223 // usleep(kDisconnectWaitUs);
224
225 if (functions == GadgetFunction::NONE) {
226 if (callback == NULL)
227 return ScopedAStatus::fromServiceSpecificErrorWithMessage(-1, "callback == NULL");
228 ScopedAStatus ret =
229 callback->setCurrentUsbFunctionsCb(functions, Status::SUCCESS, in_transactionId);
230 if (!ret.isOk())
231 ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.getDescription().c_str());
232 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
233 -1, "Error while calling setCurrentUsbFunctionsCb");
234 }
235
Ricky Niucf684312023-01-12 14:48:53 +0800236 status = setupFunctions(functions, callback, timeoutMs, in_transactionId);
Ricky Niu1eaaea42022-02-10 14:52:12 +0800237 if (status != Status::SUCCESS) {
238 goto error;
239 }
240
241 if (functions & GadgetFunction::NCM) {
242 if (!mGadgetIrqPath.empty()) {
243 if (!WriteStringToFile(BIG_CORE, mGadgetIrqPath))
244 ALOGI("Cannot move gadget IRQ to big core, path:%s", mGadgetIrqPath.c_str());
245 }
246 } else {
247 if (!mGadgetIrqPath.empty()) {
248 if (!WriteStringToFile(MEDIUM_CORE, mGadgetIrqPath))
249 ALOGI("Cannot move gadget IRQ to medium core, path:%s", mGadgetIrqPath.c_str());
250 }
251 }
252
253 if (ReadFileToString(CURRENT_USB_TYPE_PATH, &current_usb_type))
254 current_usb_type = Trim(current_usb_type);
255
256 if (ReadFileToString(CURRENT_USB_POWER_OPERATION_MODE_PATH, &current_usb_power_operation_mode))
257 current_usb_power_operation_mode = Trim(current_usb_power_operation_mode);
258
259 if (functions & GadgetFunction::ACCESSORY && current_usb_type == "Unknown SDP [CDP] DCP" &&
260 (current_usb_power_operation_mode == "default" ||
261 current_usb_power_operation_mode == "1.5A")) {
262 if (!WriteStringToFile("1300000", accessoryCurrentLimitPath)) {
263 ALOGI("Write 1.3A to limit current fail");
264 } else {
265 if (!WriteStringToFile("1", accessoryCurrentLimitEnablePath)) {
266 ALOGI("Enable limit current fail");
267 }
268 }
269 } else {
270 if (!WriteStringToFile("0", accessoryCurrentLimitEnablePath))
271 ALOGI("unvote accessory limit current failed");
272 }
273
274 ALOGI("Usb Gadget setcurrent functions called successfully");
275 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
276 -1, "Usb Gadget setcurrent functions called successfully");
277
278error:
279 ALOGI("Usb Gadget setcurrent functions failed");
280 if (callback == NULL)
281 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
282 -1, "Usb Gadget setcurrent functions failed");
283 ScopedAStatus ret = callback->setCurrentUsbFunctionsCb(functions, status, in_transactionId);
284 if (!ret.isOk())
285 ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.getDescription().c_str());
286 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
287 -1, "Error while calling setCurrentUsbFunctionsCb");
288}
289} // namespace gadget
290} // namespace usb
291} // namespace hardware
292} // namespace android
293} // namespace aidl