blob: 8ccca8c99325ecf84b0b9c0632cceb59f3f359a9 [file] [log] [blame]
Ricky Niu73b76522022-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}
45
46Status UsbGadget::getUsbGadgetIrqPath() {
47 std::string irqs;
48 size_t read_pos = 0;
49 size_t found_pos = 0;
50
51 if (!ReadFileToString(kProcInterruptsPath, &irqs)) {
52 ALOGE("cannot read all interrupts");
53 return Status::ERROR;
54 }
55
56 while (true) {
57 found_pos = irqs.find_first_of("\n", read_pos);
58 if (found_pos == std::string::npos) {
59 ALOGI("the string of all interrupts is unexpected");
60 return Status::ERROR;
61 }
62
63 std::string single_irq = irqs.substr(read_pos, found_pos - read_pos);
64
65 if (single_irq.find("dwc3", 0) != std::string::npos) {
66 unsigned int dwc3_irq_number;
67 size_t dwc3_pos = single_irq.find_first_of(":");
68 if (!ParseUint(single_irq.substr(0, dwc3_pos), &dwc3_irq_number)) {
69 ALOGI("unknown IRQ strings");
70 return Status::ERROR;
71 }
72
73 mGadgetIrqPath = kProcIrqPath + single_irq.substr(0, dwc3_pos) + kSmpAffinityList;
74 break;
75 }
76
77 if (found_pos == irqs.npos) {
78 ALOGI("USB gadget doesn't start");
79 return Status::ERROR;
80 }
81
82 read_pos = found_pos + 1;
83 }
84
85 return Status::SUCCESS;
86}
87
88void currentFunctionsAppliedCallback(bool functionsApplied, void *payload) {
89 UsbGadget *gadget = (UsbGadget *)payload;
90 gadget->mCurrentUsbFunctionsApplied = functionsApplied;
91}
92
93ScopedAStatus UsbGadget::getCurrentUsbFunctions(const shared_ptr<IUsbGadgetCallback> &callback,
94 int64_t in_transactionId) {
95 ScopedAStatus ret = callback->getCurrentUsbFunctionsCb(
96 mCurrentUsbFunctions,
97 mCurrentUsbFunctionsApplied ? Status::FUNCTIONS_APPLIED : Status::FUNCTIONS_NOT_APPLIED,
98 in_transactionId);
99 if (!ret.isOk())
100 ALOGE("Call to getCurrentUsbFunctionsCb failed %s", ret.getDescription().c_str());
101
102 return ScopedAStatus::ok();
103}
104
105ScopedAStatus UsbGadget::getUsbSpeed(const shared_ptr<IUsbGadgetCallback> &callback,
106 int64_t in_transactionId) {
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::UNKNOWN;
125 } else {
126 ALOGE("Fail to read current speed");
127 mUsbSpeed = UsbSpeed::UNKNOWN;
128 }
129
130 if (callback) {
131 ScopedAStatus ret = callback->getUsbSpeedCb(mUsbSpeed, in_transactionId);
132
133 if (!ret.isOk())
134 ALOGE("Call to getUsbSpeedCb failed %s", ret.getDescription().c_str());
135 }
136
137 return ScopedAStatus::ok();
138}
139
140Status UsbGadget::tearDownGadget() {
141 return Status::SUCCESS;
142}
143
Ricky Niu44612032023-01-31 17:52:49 +0800144ScopedAStatus UsbGadget::reset(const shared_ptr<IUsbGadgetCallback> &callback,
145 int64_t in_transactionId) {
146 if (callback)
147 callback->resetCb(Status::SUCCESS, in_transactionId);
Ricky Niu73b76522022-02-10 14:52:12 +0800148 return ScopedAStatus::ok();
149}
150
151Status UsbGadget::setupFunctions(long functions,
152 const shared_ptr<IUsbGadgetCallback> &callback, uint64_t timeout,
153 int64_t in_transactionId) {
154 bool ffsEnabled = false;
Ricky Niu2bbf8ee2022-12-01 15:24:44 +0800155 if (timeout == 0) {
156 ALOGI("timeout not setup");
157 }
Ricky Niu73b76522022-02-10 14:52:12 +0800158
159 if ((functions & GadgetFunction::ADB) != 0) {
160 ffsEnabled = true;
161 }
162
163 if ((functions & GadgetFunction::NCM) != 0) {
164 ALOGI("setCurrentUsbFunctions ncm");
165 }
166
167 // Pull up the gadget right away when there are no ffs functions.
168 if (!ffsEnabled) {
169 mCurrentUsbFunctionsApplied = true;
170 if (callback)
171 callback->setCurrentUsbFunctionsCb(functions, Status::SUCCESS, in_transactionId);
172 return Status::SUCCESS;
173 }
174
175 return Status::SUCCESS;
176}
177
178Status getI2cBusHelper(string *name) {
179 DIR *dp;
180
181 dp = opendir(kHsi2cPath);
182 if (dp != NULL) {
183 struct dirent *ep;
184
185 while ((ep = readdir(dp))) {
186 if (ep->d_type == DT_DIR) {
187 if (string::npos != string(ep->d_name).find("i2c-")) {
188 std::strtok(ep->d_name, "-");
189 *name = std::strtok(NULL, "-");
190 }
191 }
192 }
193 closedir(dp);
194 return Status::SUCCESS;
195 }
196
197 ALOGE("Failed to open %s", kHsi2cPath);
198 return Status::ERROR;
199}
200
Ricky Niu2bbf8ee2022-12-01 15:24:44 +0800201ScopedAStatus UsbGadget::setCurrentUsbFunctions(int64_t functions,
Ricky Niu73b76522022-02-10 14:52:12 +0800202 const shared_ptr<IUsbGadgetCallback> &callback,
Ricky Niu2bbf8ee2022-12-01 15:24:44 +0800203 int64_t timeoutMs,
Ricky Niu73b76522022-02-10 14:52:12 +0800204 int64_t in_transactionId) {
205 std::unique_lock<std::mutex> lk(mLockSetCurrentFunction);
206 std::string current_usb_power_operation_mode, current_usb_type;
207 std::string usb_limit_sink_enable;
208
209 string accessoryCurrentLimitEnablePath, accessoryCurrentLimitPath, path;
210
Ricky Niu73b76522022-02-10 14:52:12 +0800211 mCurrentUsbFunctions = functions;
212 mCurrentUsbFunctionsApplied = false;
213
214 getI2cBusHelper(&path);
215 accessoryCurrentLimitPath = kI2CPath + path + "/" + kAccessoryLimitCurrent;
216 accessoryCurrentLimitEnablePath = kI2CPath + path + "/" + kAccessoryLimitCurrentEnable;
217
218 // Get the gadget IRQ number before tearDownGadget()
219 if (mGadgetIrqPath.empty())
220 getUsbGadgetIrqPath();
221
222 // Unlink the gadget and stop the monitor if running.
223 Status status = tearDownGadget();
224 if (status != Status::SUCCESS) {
225 goto error;
226 }
227
228 ALOGI("Returned from tearDown gadget");
229
230 // Leave the gadget pulled down to give time for the host to sense disconnect.
231 //usleep(kDisconnectWaitUs);
232
233 if (functions == GadgetFunction::NONE) {
234 if (callback == NULL)
235 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
236 -1, "callback == NULL");
237 ScopedAStatus ret = callback->setCurrentUsbFunctionsCb(functions, Status::SUCCESS, in_transactionId);
238 if (!ret.isOk())
239 ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.getDescription().c_str());
240 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
241 -1, "Error while calling setCurrentUsbFunctionsCb");
242 }
243
Ricky Niu2bbf8ee2022-12-01 15:24:44 +0800244 status = setupFunctions(functions, callback, timeoutMs, in_transactionId);
Ricky Niu73b76522022-02-10 14:52:12 +0800245 if (status != Status::SUCCESS) {
246 goto error;
247 }
248
249 if (functions & GadgetFunction::NCM) {
250 if (!mGadgetIrqPath.empty()) {
251 if (!WriteStringToFile(BIG_CORE, mGadgetIrqPath))
252 ALOGI("Cannot move gadget IRQ to big core, path:%s", mGadgetIrqPath.c_str());
253 }
254 } else {
255 if (!mGadgetIrqPath.empty()) {
256 if (!WriteStringToFile(MEDIUM_CORE, mGadgetIrqPath))
257 ALOGI("Cannot move gadget IRQ to medium core, path:%s", mGadgetIrqPath.c_str());
258 }
259 }
260
261 if (ReadFileToString(CURRENT_USB_TYPE_PATH, &current_usb_type))
262 current_usb_type = Trim(current_usb_type);
263
264 if (ReadFileToString(CURRENT_USB_POWER_OPERATION_MODE_PATH, &current_usb_power_operation_mode))
265 current_usb_power_operation_mode = Trim(current_usb_power_operation_mode);
266
267 if (functions & GadgetFunction::ACCESSORY &&
268 current_usb_type == "Unknown SDP [CDP] DCP" &&
269 (current_usb_power_operation_mode == "default" ||
270 current_usb_power_operation_mode == "1.5A")) {
271 if (!WriteStringToFile("1300000", accessoryCurrentLimitPath)) {
272 ALOGI("Write 1.3A to limit current fail");
273 } else {
274 if (!WriteStringToFile("1", accessoryCurrentLimitEnablePath)) {
275 ALOGI("Enable limit current fail");
276 }
277 }
278 } else {
279 if (!WriteStringToFile("0", accessoryCurrentLimitEnablePath))
280 ALOGI("unvote accessory limit current failed");
281 }
282
283 ALOGI("Usb Gadget setcurrent functions called successfully");
284 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
285 -1, "Usb Gadget setcurrent functions called successfully");
286
287
288error:
289 ALOGI("Usb Gadget setcurrent functions failed");
290 if (callback == NULL)
291 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
292 -1, "Usb Gadget setcurrent functions failed");
293 ScopedAStatus ret = callback->setCurrentUsbFunctionsCb(functions, status, in_transactionId);
294 if (!ret.isOk())
295 ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.getDescription().c_str());
296 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
297 -1, "Error while calling setCurrentUsbFunctionsCb");
298}
299} // namespace gadget
300} // namespace usb
301} // namespace hardware
302} // namespace android
303} // aidl