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@1.2-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 namespace android {
30 namespace hardware {
31 namespace usb {
32 namespace gadget {
33 namespace V1_2 {
34 namespace implementation {
35
UsbGadget()36 UsbGadget::UsbGadget() {
37 if (access(OS_DESC_PATH, R_OK) != 0) {
38 ALOGE("configfs setup not done yet");
39 abort();
40 }
41 }
42
currentFunctionsAppliedCallback(bool functionsApplied,void * payload)43 void currentFunctionsAppliedCallback(bool functionsApplied, void* payload) {
44 UsbGadget* gadget = (UsbGadget*)payload;
45 gadget->mCurrentUsbFunctionsApplied = functionsApplied;
46 }
47
getCurrentUsbFunctions(const sp<V1_0::IUsbGadgetCallback> & callback)48 Return<void> UsbGadget::getCurrentUsbFunctions(const sp<V1_0::IUsbGadgetCallback>& callback) {
49 Return<void> ret = callback->getCurrentUsbFunctionsCb(
50 mCurrentUsbFunctions, mCurrentUsbFunctionsApplied ? Status::FUNCTIONS_APPLIED
51 : Status::FUNCTIONS_NOT_APPLIED);
52 if (!ret.isOk()) ALOGE("Call to getCurrentUsbFunctionsCb failed %s", ret.description().c_str());
53
54 return Void();
55 }
56
getUsbSpeed(const sp<V1_2::IUsbGadgetCallback> & callback)57 Return<void> UsbGadget::getUsbSpeed(const sp<V1_2::IUsbGadgetCallback>& callback) {
58 std::string current_speed;
59 if (ReadFileToString(SPEED_PATH, ¤t_speed)) {
60 current_speed = Trim(current_speed);
61 ALOGI("current USB speed is %s", current_speed.c_str());
62 if (current_speed == "low-speed")
63 mUsbSpeed = UsbSpeed::LOWSPEED;
64 else if (current_speed == "full-speed")
65 mUsbSpeed = UsbSpeed::FULLSPEED;
66 else if (current_speed == "high-speed")
67 mUsbSpeed = UsbSpeed::HIGHSPEED;
68 else if (current_speed == "super-speed")
69 mUsbSpeed = UsbSpeed::SUPERSPEED;
70 else if (current_speed == "super-speed-plus")
71 mUsbSpeed = UsbSpeed::SUPERSPEED_10Gb;
72 else if (current_speed == "UNKNOWN")
73 mUsbSpeed = UsbSpeed::UNKNOWN;
74 else {
75 /**
76 * This part is used for USB4 or reserved speed.
77 *
78 * If reserved speed is detected, it needs to convert to other speeds.
79 * For example:
80 * If the bandwidth of new speed is 7G, adding new if
81 * statement and set mUsbSpeed to SUPERSPEED.
82 * If the bandwidth of new speed is 80G, adding new if
83 * statement and set mUsbSpeed to USB4_GEN3_40Gb.
84 */
85 mUsbSpeed = UsbSpeed::RESERVED_SPEED;
86 }
87 } else {
88 ALOGE("Fail to read current speed");
89 mUsbSpeed = UsbSpeed::UNKNOWN;
90 }
91
92 if (callback) {
93 Return<void> ret = callback->getUsbSpeedCb(mUsbSpeed);
94
95 if (!ret.isOk()) ALOGE("Call to getUsbSpeedCb failed %s", ret.description().c_str());
96 }
97
98 return Void();
99 }
100
tearDownGadget()101 V1_0::Status UsbGadget::tearDownGadget() {
102 if (resetGadget() != V1_0::Status::SUCCESS) return V1_0::Status::ERROR;
103
104 if (monitorFfs.isMonitorRunning()) {
105 monitorFfs.reset();
106 } else {
107 ALOGI("mMonitor not running");
108 }
109 return V1_0::Status::SUCCESS;
110 }
111
reset()112 Return<Status> UsbGadget::reset() {
113 if (!WriteStringToFile("none", PULLUP_PATH)) {
114 ALOGI("Gadget cannot be pulled down");
115 return Status::ERROR;
116 }
117
118 usleep(kDisconnectWaitUs);
119
120 if (!WriteStringToFile(kGadgetName, PULLUP_PATH)) {
121 ALOGI("Gadget cannot be pulled up");
122 return Status::ERROR;
123 }
124
125 return Status::SUCCESS;
126 }
127
validateAndSetVidPid(uint64_t functions)128 static V1_0::Status validateAndSetVidPid(uint64_t functions) {
129 V1_0::Status ret = V1_0::Status::SUCCESS;
130
131 switch (functions) {
132 case static_cast<uint64_t>(V1_2::GadgetFunction::MTP):
133 ret = setVidPid("0x18d1", "0x4ee1");
134 break;
135 case V1_2::GadgetFunction::ADB | V1_2::GadgetFunction::MTP:
136 ret = setVidPid("0x18d1", "0x4ee2");
137 break;
138 case static_cast<uint64_t>(V1_2::GadgetFunction::RNDIS):
139 ret = setVidPid("0x18d1", "0x4ee3");
140 break;
141 case V1_2::GadgetFunction::ADB | V1_2::GadgetFunction::RNDIS:
142 ret = setVidPid("0x18d1", "0x4ee4");
143 break;
144 case static_cast<uint64_t>(V1_2::GadgetFunction::PTP):
145 ret = setVidPid("0x18d1", "0x4ee5");
146 break;
147 case V1_2::GadgetFunction::ADB | V1_2::GadgetFunction::PTP:
148 ret = setVidPid("0x18d1", "0x4ee6");
149 break;
150 case static_cast<uint64_t>(V1_2::GadgetFunction::ADB):
151 ret = setVidPid("0x18d1", "0x4ee7");
152 break;
153 case static_cast<uint64_t>(V1_2::GadgetFunction::MIDI):
154 ret = setVidPid("0x18d1", "0x4ee8");
155 break;
156 case V1_2::GadgetFunction::ADB | V1_2::GadgetFunction::MIDI:
157 ret = setVidPid("0x18d1", "0x4ee9");
158 break;
159 case static_cast<uint64_t>(V1_2::GadgetFunction::NCM):
160 ret = setVidPid("0x18d1", "0x4eeb");
161 break;
162 case V1_2::GadgetFunction::ADB | V1_2::GadgetFunction::NCM:
163 ret = setVidPid("0x18d1", "0x4eec");
164 break;
165 case static_cast<uint64_t>(V1_2::GadgetFunction::ACCESSORY):
166 ret = setVidPid("0x18d1", "0x2d00");
167 break;
168 case V1_2::GadgetFunction::ADB | V1_2::GadgetFunction::ACCESSORY:
169 ret = setVidPid("0x18d1", "0x2d01");
170 break;
171 case static_cast<uint64_t>(V1_2::GadgetFunction::AUDIO_SOURCE):
172 ret = setVidPid("0x18d1", "0x2d02");
173 break;
174 case V1_2::GadgetFunction::ADB | V1_2::GadgetFunction::AUDIO_SOURCE:
175 ret = setVidPid("0x18d1", "0x2d03");
176 break;
177 case V1_2::GadgetFunction::ACCESSORY | V1_2::GadgetFunction::AUDIO_SOURCE:
178 ret = setVidPid("0x18d1", "0x2d04");
179 break;
180 case V1_2::GadgetFunction::ADB | V1_2::GadgetFunction::ACCESSORY |
181 V1_2::GadgetFunction::AUDIO_SOURCE:
182 ret = setVidPid("0x18d1", "0x2d05");
183 break;
184 default:
185 ALOGE("Combination not supported");
186 ret = V1_0::Status::CONFIGURATION_NOT_SUPPORTED;
187 }
188 return ret;
189 }
190
setupFunctions(uint64_t functions,const sp<V1_0::IUsbGadgetCallback> & callback,uint64_t timeout)191 V1_0::Status UsbGadget::setupFunctions(uint64_t functions,
192 const sp<V1_0::IUsbGadgetCallback>& callback,
193 uint64_t timeout) {
194 bool ffsEnabled = false;
195 int i = 0;
196
197 if (addGenericAndroidFunctions(&monitorFfs, functions, &ffsEnabled, &i) !=
198 V1_0::Status::SUCCESS)
199 return V1_0::Status::ERROR;
200
201 if ((functions & V1_2::GadgetFunction::ADB) != 0) {
202 ffsEnabled = true;
203 if (addAdb(&monitorFfs, &i) != V1_0::Status::SUCCESS) return V1_0::Status::ERROR;
204 }
205
206 // Pull up the gadget right away when there are no ffs functions.
207 if (!ffsEnabled) {
208 if (!WriteStringToFile(kGadgetName, PULLUP_PATH)) return V1_0::Status::ERROR;
209 mCurrentUsbFunctionsApplied = true;
210 if (callback) callback->setCurrentUsbFunctionsCb(functions, V1_0::Status::SUCCESS);
211 return V1_0::Status::SUCCESS;
212 }
213
214 monitorFfs.registerFunctionsAppliedCallback(¤tFunctionsAppliedCallback, this);
215 // Monitors the ffs paths to pull up the gadget when descriptors are written.
216 // Also takes of the pulling up the gadget again if the userspace process
217 // dies and restarts.
218 monitorFfs.startMonitor();
219
220 if (kDebug) ALOGI("Mainthread in Cv");
221
222 if (callback) {
223 bool pullup = monitorFfs.waitForPullUp(timeout);
224 Return<void> ret = callback->setCurrentUsbFunctionsCb(
225 functions, pullup ? V1_0::Status::SUCCESS : V1_0::Status::ERROR);
226 if (!ret.isOk()) ALOGE("setCurrentUsbFunctionsCb error %s", ret.description().c_str());
227 }
228
229 return V1_0::Status::SUCCESS;
230 }
231
setCurrentUsbFunctions(uint64_t functions,const sp<V1_0::IUsbGadgetCallback> & callback,uint64_t timeout)232 Return<void> UsbGadget::setCurrentUsbFunctions(uint64_t functions,
233 const sp<V1_0::IUsbGadgetCallback>& callback,
234 uint64_t timeout) {
235 std::unique_lock<std::mutex> lk(mLockSetCurrentFunction);
236
237 mCurrentUsbFunctions = functions;
238 mCurrentUsbFunctionsApplied = false;
239
240 // Unlink the gadget and stop the monitor if running.
241 V1_0::Status status = tearDownGadget();
242 if (status != V1_0::Status::SUCCESS) {
243 goto error;
244 }
245
246 ALOGI("Returned from tearDown gadget");
247
248 // Leave the gadget pulled down to give time for the host to sense disconnect.
249 usleep(kDisconnectWaitUs);
250
251 if (functions == static_cast<uint64_t>(V1_2::GadgetFunction::NONE)) {
252 if (callback == NULL) return Void();
253 Return<void> ret = callback->setCurrentUsbFunctionsCb(functions, V1_0::Status::SUCCESS);
254 if (!ret.isOk())
255 ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.description().c_str());
256 return Void();
257 }
258
259 status = validateAndSetVidPid(functions);
260
261 if (status != V1_0::Status::SUCCESS) {
262 goto error;
263 }
264
265 status = setupFunctions(functions, callback, timeout);
266 if (status != V1_0::Status::SUCCESS) {
267 goto error;
268 }
269
270 ALOGI("Usb Gadget setcurrent functions called successfully");
271 return Void();
272
273 error:
274 ALOGI("Usb Gadget setcurrent functions failed");
275 if (callback == NULL) return Void();
276 Return<void> ret = callback->setCurrentUsbFunctionsCb(functions, status);
277 if (!ret.isOk())
278 ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.description().c_str());
279 return Void();
280 }
281 } // namespace implementation
282 } // namespace V1_2
283 } // namespace gadget
284 } // namespace usb
285 } // namespace hardware
286 } // namespace android
287