blob: 17e1da72d3d519b266d997ee675a6f14d9097a33 [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;
149 ALOGI("functions: %ld, timeout: %ld", functions, timeout);
150
151 if ((functions & GadgetFunction::ADB) != 0) {
152 ffsEnabled = true;
153 }
154
155 if ((functions & GadgetFunction::NCM) != 0) {
156 ALOGI("setCurrentUsbFunctions ncm");
157 }
158
159 // Pull up the gadget right away when there are no ffs functions.
160 if (!ffsEnabled) {
161 mCurrentUsbFunctionsApplied = true;
162 if (callback)
163 callback->setCurrentUsbFunctionsCb(functions, Status::SUCCESS, in_transactionId);
164 return Status::SUCCESS;
165 }
166
167 return Status::SUCCESS;
168}
169
170Status getI2cBusHelper(string* name) {
171 DIR* dp;
172
173 dp = opendir(kHsi2cPath);
174 if (dp != NULL) {
175 struct dirent* ep;
176
177 while ((ep = readdir(dp))) {
178 if (ep->d_type == DT_DIR) {
179 if (string::npos != string(ep->d_name).find("i2c-")) {
180 std::strtok(ep->d_name, "-");
181 *name = std::strtok(NULL, "-");
182 }
183 }
184 }
185 closedir(dp);
186 return Status::SUCCESS;
187 }
188
189 ALOGE("Failed to open %s", kHsi2cPath);
190 return Status::ERROR;
191}
192
193ScopedAStatus UsbGadget::setCurrentUsbFunctions(long functions,
194 const shared_ptr<IUsbGadgetCallback>& callback,
195 int64_t timeout, int64_t in_transactionId) {
196 std::unique_lock<std::mutex> lk(mLockSetCurrentFunction);
197 std::string current_usb_power_operation_mode, current_usb_type;
198 std::string usb_limit_sink_enable;
199
200 string accessoryCurrentLimitEnablePath, accessoryCurrentLimitPath, path;
201
202 ALOGI("enter setCurrentUsbFunctions, in_transactionId=%ld , %ld", in_transactionId, timeout);
203 mCurrentUsbFunctions = functions;
204 mCurrentUsbFunctionsApplied = false;
205
206 getI2cBusHelper(&path);
207 accessoryCurrentLimitPath = kI2CPath + path + "/" + kAccessoryLimitCurrent;
208 accessoryCurrentLimitEnablePath = kI2CPath + path + "/" + kAccessoryLimitCurrentEnable;
209
210 // Get the gadget IRQ number before tearDownGadget()
211 if (mGadgetIrqPath.empty()) getUsbGadgetIrqPath();
212
213 // Unlink the gadget and stop the monitor if running.
214 Status status = tearDownGadget();
215 if (status != Status::SUCCESS) {
216 goto error;
217 }
218
219 ALOGI("Returned from tearDown gadget");
220
221 // Leave the gadget pulled down to give time for the host to sense disconnect.
222 // usleep(kDisconnectWaitUs);
223
224 if (functions == GadgetFunction::NONE) {
225 if (callback == NULL)
226 return ScopedAStatus::fromServiceSpecificErrorWithMessage(-1, "callback == NULL");
227 ScopedAStatus ret =
228 callback->setCurrentUsbFunctionsCb(functions, Status::SUCCESS, in_transactionId);
229 if (!ret.isOk())
230 ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.getDescription().c_str());
231 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
232 -1, "Error while calling setCurrentUsbFunctionsCb");
233 }
234
235 status = setupFunctions(functions, callback, timeout, in_transactionId);
236 if (status != Status::SUCCESS) {
237 goto error;
238 }
239
240 if (functions & GadgetFunction::NCM) {
241 if (!mGadgetIrqPath.empty()) {
242 if (!WriteStringToFile(BIG_CORE, mGadgetIrqPath))
243 ALOGI("Cannot move gadget IRQ to big core, path:%s", mGadgetIrqPath.c_str());
244 }
245 } else {
246 if (!mGadgetIrqPath.empty()) {
247 if (!WriteStringToFile(MEDIUM_CORE, mGadgetIrqPath))
248 ALOGI("Cannot move gadget IRQ to medium core, path:%s", mGadgetIrqPath.c_str());
249 }
250 }
251
252 if (ReadFileToString(CURRENT_USB_TYPE_PATH, &current_usb_type))
253 current_usb_type = Trim(current_usb_type);
254
255 if (ReadFileToString(CURRENT_USB_POWER_OPERATION_MODE_PATH, &current_usb_power_operation_mode))
256 current_usb_power_operation_mode = Trim(current_usb_power_operation_mode);
257
258 if (functions & GadgetFunction::ACCESSORY && current_usb_type == "Unknown SDP [CDP] DCP" &&
259 (current_usb_power_operation_mode == "default" ||
260 current_usb_power_operation_mode == "1.5A")) {
261 if (!WriteStringToFile("1300000", accessoryCurrentLimitPath)) {
262 ALOGI("Write 1.3A to limit current fail");
263 } else {
264 if (!WriteStringToFile("1", accessoryCurrentLimitEnablePath)) {
265 ALOGI("Enable limit current fail");
266 }
267 }
268 } else {
269 if (!WriteStringToFile("0", accessoryCurrentLimitEnablePath))
270 ALOGI("unvote accessory limit current failed");
271 }
272
273 ALOGI("Usb Gadget setcurrent functions called successfully");
274 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
275 -1, "Usb Gadget setcurrent functions called successfully");
276
277error:
278 ALOGI("Usb Gadget setcurrent functions failed");
279 if (callback == NULL)
280 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
281 -1, "Usb Gadget setcurrent functions failed");
282 ScopedAStatus ret = callback->setCurrentUsbFunctionsCb(functions, status, in_transactionId);
283 if (!ret.isOk())
284 ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.getDescription().c_str());
285 return ScopedAStatus::fromServiceSpecificErrorWithMessage(
286 -1, "Error while calling setCurrentUsbFunctionsCb");
287}
288} // namespace gadget
289} // namespace usb
290} // namespace hardware
291} // namespace android
292} // namespace aidl