blob: 51f7f5b8174fb4f31e73f4bdf4a8a05824677101 [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) {
Pawan Wagh9b130072023-02-01 23:38:37 +000094 if (callback == nullptr) {
95 return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
96 }
Ricky Niu1eaaea42022-02-10 14:52:12 +080097 ScopedAStatus ret = callback->getCurrentUsbFunctionsCb(
98 mCurrentUsbFunctions,
99 mCurrentUsbFunctionsApplied ? Status::FUNCTIONS_APPLIED : Status::FUNCTIONS_NOT_APPLIED,
100 in_transactionId);
101 if (!ret.isOk())
102 ALOGE("Call to getCurrentUsbFunctionsCb failed %s", ret.getDescription().c_str());
103
104 return ScopedAStatus::ok();
105}
106
107ScopedAStatus UsbGadget::getUsbSpeed(const shared_ptr<IUsbGadgetCallback>& callback,
108 int64_t in_transactionId) {
109 std::string current_speed;
110 if (ReadFileToString(SPEED_PATH, &current_speed)) {
111 current_speed = Trim(current_speed);
112 ALOGI("current USB speed is %s", current_speed.c_str());
113 if (current_speed == "low-speed")
114 mUsbSpeed = UsbSpeed::LOWSPEED;
115 else if (current_speed == "full-speed")
116 mUsbSpeed = UsbSpeed::FULLSPEED;
117 else if (current_speed == "high-speed")
118 mUsbSpeed = UsbSpeed::HIGHSPEED;
119 else if (current_speed == "super-speed")
120 mUsbSpeed = UsbSpeed::SUPERSPEED;
121 else if (current_speed == "super-speed-plus")
122 mUsbSpeed = UsbSpeed::SUPERSPEED_10Gb;
123 else if (current_speed == "UNKNOWN")
124 mUsbSpeed = UsbSpeed::UNKNOWN;
125 else
126 mUsbSpeed = UsbSpeed::UNKNOWN;
127 } else {
128 ALOGE("Fail to read current speed");
129 mUsbSpeed = UsbSpeed::UNKNOWN;
130 }
131
132 if (callback) {
133 ScopedAStatus ret = callback->getUsbSpeedCb(mUsbSpeed, in_transactionId);
134
135 if (!ret.isOk()) ALOGE("Call to getUsbSpeedCb failed %s", ret.getDescription().c_str());
136 }
137
138 return ScopedAStatus::ok();
139}
140
141Status UsbGadget::tearDownGadget() {
142 return Status::SUCCESS;
143}
144
145ScopedAStatus UsbGadget::reset() {
146 return ScopedAStatus::ok();
147}
148
149Status UsbGadget::setupFunctions(long functions, const shared_ptr<IUsbGadgetCallback>& callback,
150 uint64_t timeout, int64_t in_transactionId) {
151 bool ffsEnabled = false;
Ricky Niucf684312023-01-12 14:48:53 +0800152 if (timeout == 0) {
153 ALOGI("timeout not setup");
154 }
Ricky Niu1eaaea42022-02-10 14:52:12 +0800155
156 if ((functions & GadgetFunction::ADB) != 0) {
157 ffsEnabled = true;
158 }
159
160 if ((functions & GadgetFunction::NCM) != 0) {
161 ALOGI("setCurrentUsbFunctions ncm");
162 }
163
164 // Pull up the gadget right away when there are no ffs functions.
165 if (!ffsEnabled) {
166 mCurrentUsbFunctionsApplied = true;
167 if (callback)
168 callback->setCurrentUsbFunctionsCb(functions, Status::SUCCESS, in_transactionId);
169 return Status::SUCCESS;
170 }
171
172 return Status::SUCCESS;
173}
174
175Status getI2cBusHelper(string* name) {
176 DIR* dp;
177
178 dp = opendir(kHsi2cPath);
179 if (dp != NULL) {
180 struct dirent* ep;
181
182 while ((ep = readdir(dp))) {
183 if (ep->d_type == DT_DIR) {
184 if (string::npos != string(ep->d_name).find("i2c-")) {
185 std::strtok(ep->d_name, "-");
186 *name = std::strtok(NULL, "-");
187 }
188 }
189 }
190 closedir(dp);
191 return Status::SUCCESS;
192 }
193
194 ALOGE("Failed to open %s", kHsi2cPath);
195 return Status::ERROR;
196}
197
Ricky Niucf684312023-01-12 14:48:53 +0800198ScopedAStatus UsbGadget::setCurrentUsbFunctions(int64_t functions,
Ricky Niu1eaaea42022-02-10 14:52:12 +0800199 const shared_ptr<IUsbGadgetCallback>& callback,
Ricky Niucf684312023-01-12 14:48:53 +0800200 int64_t timeoutMs, int64_t in_transactionId) {
Ricky Niu1eaaea42022-02-10 14:52:12 +0800201 std::unique_lock<std::mutex> lk(mLockSetCurrentFunction);
202 std::string current_usb_power_operation_mode, current_usb_type;
203 std::string usb_limit_sink_enable;
204
205 string accessoryCurrentLimitEnablePath, accessoryCurrentLimitPath, path;
206
Ricky Niu1eaaea42022-02-10 14:52:12 +0800207 mCurrentUsbFunctions = functions;
208 mCurrentUsbFunctionsApplied = false;
209
210 getI2cBusHelper(&path);
211 accessoryCurrentLimitPath = kI2CPath + path + "/" + kAccessoryLimitCurrent;
212 accessoryCurrentLimitEnablePath = kI2CPath + path + "/" + kAccessoryLimitCurrentEnable;
213
214 // Get the gadget IRQ number before tearDownGadget()
215 if (mGadgetIrqPath.empty()) getUsbGadgetIrqPath();
216
217 // Unlink the gadget and stop the monitor if running.
218 Status status = tearDownGadget();
219 if (status != Status::SUCCESS) {
220 goto error;
221 }
222
223 ALOGI("Returned from tearDown gadget");
224
225 // Leave the gadget pulled down to give time for the host to sense disconnect.
226 // usleep(kDisconnectWaitUs);
227
228 if (functions == GadgetFunction::NONE) {
229 if (callback == NULL)
230 return ScopedAStatus::fromServiceSpecificErrorWithMessage(-1, "callback == NULL");
231 ScopedAStatus ret =
232 callback->setCurrentUsbFunctionsCb(functions, Status::SUCCESS, in_transactionId);
233 if (!ret.isOk())
234 ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.getDescription().c_str());
235 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
236 -1, "Error while calling setCurrentUsbFunctionsCb");
237 }
238
Ricky Niucf684312023-01-12 14:48:53 +0800239 status = setupFunctions(functions, callback, timeoutMs, in_transactionId);
Ricky Niu1eaaea42022-02-10 14:52:12 +0800240 if (status != Status::SUCCESS) {
241 goto error;
242 }
243
244 if (functions & GadgetFunction::NCM) {
245 if (!mGadgetIrqPath.empty()) {
246 if (!WriteStringToFile(BIG_CORE, mGadgetIrqPath))
247 ALOGI("Cannot move gadget IRQ to big core, path:%s", mGadgetIrqPath.c_str());
248 }
249 } else {
250 if (!mGadgetIrqPath.empty()) {
251 if (!WriteStringToFile(MEDIUM_CORE, mGadgetIrqPath))
252 ALOGI("Cannot move gadget IRQ to medium core, path:%s", mGadgetIrqPath.c_str());
253 }
254 }
255
256 if (ReadFileToString(CURRENT_USB_TYPE_PATH, &current_usb_type))
257 current_usb_type = Trim(current_usb_type);
258
259 if (ReadFileToString(CURRENT_USB_POWER_OPERATION_MODE_PATH, &current_usb_power_operation_mode))
260 current_usb_power_operation_mode = Trim(current_usb_power_operation_mode);
261
262 if (functions & GadgetFunction::ACCESSORY && current_usb_type == "Unknown SDP [CDP] DCP" &&
263 (current_usb_power_operation_mode == "default" ||
264 current_usb_power_operation_mode == "1.5A")) {
265 if (!WriteStringToFile("1300000", accessoryCurrentLimitPath)) {
266 ALOGI("Write 1.3A to limit current fail");
267 } else {
268 if (!WriteStringToFile("1", accessoryCurrentLimitEnablePath)) {
269 ALOGI("Enable limit current fail");
270 }
271 }
272 } else {
273 if (!WriteStringToFile("0", accessoryCurrentLimitEnablePath))
274 ALOGI("unvote accessory limit current failed");
275 }
276
277 ALOGI("Usb Gadget setcurrent functions called successfully");
278 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
279 -1, "Usb Gadget setcurrent functions called successfully");
280
281error:
282 ALOGI("Usb Gadget setcurrent functions failed");
283 if (callback == NULL)
284 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
285 -1, "Usb Gadget setcurrent functions failed");
286 ScopedAStatus ret = callback->setCurrentUsbFunctionsCb(functions, status, in_transactionId);
287 if (!ret.isOk())
288 ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.getDescription().c_str());
289 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
290 -1, "Error while calling setCurrentUsbFunctionsCb");
291}
292} // namespace gadget
293} // namespace usb
294} // namespace hardware
295} // namespace android
296} // namespace aidl