blob: c4986e8e18a7e219c036297c77656acc1e676e69 [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
144ScopedAStatus UsbGadget::reset() {
145 return ScopedAStatus::ok();
146}
147
148Status UsbGadget::setupFunctions(long functions,
149 const shared_ptr<IUsbGadgetCallback> &callback, uint64_t timeout,
150 int64_t in_transactionId) {
151 bool ffsEnabled = false;
Ricky Niu2bbf8ee2022-12-01 15:24:44 +0800152 if (timeout == 0) {
153 ALOGI("timeout not setup");
154 }
Ricky Niu73b76522022-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 Niu2bbf8ee2022-12-01 15:24:44 +0800198ScopedAStatus UsbGadget::setCurrentUsbFunctions(int64_t functions,
Ricky Niu73b76522022-02-10 14:52:12 +0800199 const shared_ptr<IUsbGadgetCallback> &callback,
Ricky Niu2bbf8ee2022-12-01 15:24:44 +0800200 int64_t timeoutMs,
Ricky Niu73b76522022-02-10 14:52:12 +0800201 int64_t in_transactionId) {
202 std::unique_lock<std::mutex> lk(mLockSetCurrentFunction);
203 std::string current_usb_power_operation_mode, current_usb_type;
204 std::string usb_limit_sink_enable;
205
206 string accessoryCurrentLimitEnablePath, accessoryCurrentLimitPath, path;
207
Ricky Niu73b76522022-02-10 14:52:12 +0800208 mCurrentUsbFunctions = functions;
209 mCurrentUsbFunctionsApplied = false;
210
211 getI2cBusHelper(&path);
212 accessoryCurrentLimitPath = kI2CPath + path + "/" + kAccessoryLimitCurrent;
213 accessoryCurrentLimitEnablePath = kI2CPath + path + "/" + kAccessoryLimitCurrentEnable;
214
215 // Get the gadget IRQ number before tearDownGadget()
216 if (mGadgetIrqPath.empty())
217 getUsbGadgetIrqPath();
218
219 // Unlink the gadget and stop the monitor if running.
220 Status status = tearDownGadget();
221 if (status != Status::SUCCESS) {
222 goto error;
223 }
224
225 ALOGI("Returned from tearDown gadget");
226
227 // Leave the gadget pulled down to give time for the host to sense disconnect.
228 //usleep(kDisconnectWaitUs);
229
230 if (functions == GadgetFunction::NONE) {
231 if (callback == NULL)
232 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
233 -1, "callback == NULL");
234 ScopedAStatus ret = callback->setCurrentUsbFunctionsCb(functions, Status::SUCCESS, in_transactionId);
235 if (!ret.isOk())
236 ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.getDescription().c_str());
237 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
238 -1, "Error while calling setCurrentUsbFunctionsCb");
239 }
240
Ricky Niu2bbf8ee2022-12-01 15:24:44 +0800241 status = setupFunctions(functions, callback, timeoutMs, in_transactionId);
Ricky Niu73b76522022-02-10 14:52:12 +0800242 if (status != Status::SUCCESS) {
243 goto error;
244 }
245
246 if (functions & GadgetFunction::NCM) {
247 if (!mGadgetIrqPath.empty()) {
248 if (!WriteStringToFile(BIG_CORE, mGadgetIrqPath))
249 ALOGI("Cannot move gadget IRQ to big core, path:%s", mGadgetIrqPath.c_str());
250 }
251 } else {
252 if (!mGadgetIrqPath.empty()) {
253 if (!WriteStringToFile(MEDIUM_CORE, mGadgetIrqPath))
254 ALOGI("Cannot move gadget IRQ to medium core, path:%s", mGadgetIrqPath.c_str());
255 }
256 }
257
258 if (ReadFileToString(CURRENT_USB_TYPE_PATH, &current_usb_type))
259 current_usb_type = Trim(current_usb_type);
260
261 if (ReadFileToString(CURRENT_USB_POWER_OPERATION_MODE_PATH, &current_usb_power_operation_mode))
262 current_usb_power_operation_mode = Trim(current_usb_power_operation_mode);
263
264 if (functions & GadgetFunction::ACCESSORY &&
265 current_usb_type == "Unknown SDP [CDP] DCP" &&
266 (current_usb_power_operation_mode == "default" ||
267 current_usb_power_operation_mode == "1.5A")) {
268 if (!WriteStringToFile("1300000", accessoryCurrentLimitPath)) {
269 ALOGI("Write 1.3A to limit current fail");
270 } else {
271 if (!WriteStringToFile("1", accessoryCurrentLimitEnablePath)) {
272 ALOGI("Enable limit current fail");
273 }
274 }
275 } else {
276 if (!WriteStringToFile("0", accessoryCurrentLimitEnablePath))
277 ALOGI("unvote accessory limit current failed");
278 }
279
280 ALOGI("Usb Gadget setcurrent functions called successfully");
281 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
282 -1, "Usb Gadget setcurrent functions called successfully");
283
284
285error:
286 ALOGI("Usb Gadget setcurrent functions failed");
287 if (callback == NULL)
288 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
289 -1, "Usb Gadget setcurrent functions failed");
290 ScopedAStatus ret = callback->setCurrentUsbFunctionsCb(functions, status, in_transactionId);
291 if (!ret.isOk())
292 ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.getDescription().c_str());
293 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
294 -1, "Error while calling setCurrentUsbFunctionsCb");
295}
296} // namespace gadget
297} // namespace usb
298} // namespace hardware
299} // namespace android
300} // aidl