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, &current_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(&currentFunctionsAppliedCallback, 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