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