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