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 "[email protected]"
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_1 {
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 
tearDownGadget()57 V1_0::Status UsbGadget::tearDownGadget() {
58     if (resetGadget() != V1_0::Status::SUCCESS) return V1_0::Status::ERROR;
59 
60     if (monitorFfs.isMonitorRunning()) {
61         monitorFfs.reset();
62     } else {
63         ALOGI("mMonitor not running");
64     }
65     return V1_0::Status::SUCCESS;
66 }
67 
reset()68 Return<Status> UsbGadget::reset() {
69     if (!WriteStringToFile("none", PULLUP_PATH)) {
70         ALOGI("Gadget cannot be pulled down");
71         return Status::ERROR;
72     }
73 
74     return Status::SUCCESS;
75 }
76 
validateAndSetVidPid(uint64_t functions)77 static V1_0::Status validateAndSetVidPid(uint64_t functions) {
78     V1_0::Status ret = V1_0::Status::SUCCESS;
79 
80     switch (functions) {
81         case static_cast<uint64_t>(V1_0::GadgetFunction::MTP):
82             ret = setVidPid("0x18d1", "0x4ee1");
83             break;
84         case V1_0::GadgetFunction::ADB | V1_0::GadgetFunction::MTP:
85             ret = setVidPid("0x18d1", "0x4ee2");
86             break;
87         case static_cast<uint64_t>(V1_0::GadgetFunction::RNDIS):
88             ret = setVidPid("0x18d1", "0x4ee3");
89             break;
90         case V1_0::GadgetFunction::ADB | V1_0::GadgetFunction::RNDIS:
91             ret = setVidPid("0x18d1", "0x4ee4");
92             break;
93         case static_cast<uint64_t>(V1_0::GadgetFunction::PTP):
94             ret = setVidPid("0x18d1", "0x4ee5");
95             break;
96         case V1_0::GadgetFunction::ADB | V1_0::GadgetFunction::PTP:
97             ret = setVidPid("0x18d1", "0x4ee6");
98             break;
99         case static_cast<uint64_t>(V1_0::GadgetFunction::ADB):
100             ret = setVidPid("0x18d1", "0x4ee7");
101             break;
102         case static_cast<uint64_t>(V1_0::GadgetFunction::MIDI):
103             ret = setVidPid("0x18d1", "0x4ee8");
104             break;
105         case V1_0::GadgetFunction::ADB | V1_0::GadgetFunction::MIDI:
106             ret = setVidPid("0x18d1", "0x4ee9");
107             break;
108         case static_cast<uint64_t>(V1_0::GadgetFunction::ACCESSORY):
109             ret = setVidPid("0x18d1", "0x2d00");
110             break;
111         case V1_0::GadgetFunction::ADB | V1_0::GadgetFunction::ACCESSORY:
112             ret = setVidPid("0x18d1", "0x2d01");
113             break;
114         case static_cast<uint64_t>(V1_0::GadgetFunction::AUDIO_SOURCE):
115             ret = setVidPid("0x18d1", "0x2d02");
116             break;
117         case V1_0::GadgetFunction::ADB | V1_0::GadgetFunction::AUDIO_SOURCE:
118             ret = setVidPid("0x18d1", "0x2d03");
119             break;
120         case V1_0::GadgetFunction::ACCESSORY | V1_0::GadgetFunction::AUDIO_SOURCE:
121             ret = setVidPid("0x18d1", "0x2d04");
122             break;
123         case V1_0::GadgetFunction::ADB | V1_0::GadgetFunction::ACCESSORY |
124                 V1_0::GadgetFunction::AUDIO_SOURCE:
125             ret = setVidPid("0x18d1", "0x2d05");
126             break;
127         default:
128             ALOGE("Combination not supported");
129             ret = V1_0::Status::CONFIGURATION_NOT_SUPPORTED;
130     }
131     return ret;
132 }
133 
setupFunctions(uint64_t functions,const sp<V1_0::IUsbGadgetCallback> & callback,uint64_t timeout)134 V1_0::Status UsbGadget::setupFunctions(uint64_t functions,
135                                        const sp<V1_0::IUsbGadgetCallback>& callback,
136                                        uint64_t timeout) {
137     bool ffsEnabled = false;
138     int i = 0;
139 
140     if (addGenericAndroidFunctions(&monitorFfs, functions, &ffsEnabled, &i) !=
141         V1_0::Status::SUCCESS)
142         return V1_0::Status::ERROR;
143 
144     if ((functions & V1_0::GadgetFunction::ADB) != 0) {
145         ffsEnabled = true;
146         if (addAdb(&monitorFfs, &i) != V1_0::Status::SUCCESS) return V1_0::Status::ERROR;
147     }
148 
149     // Pull up the gadget right away when there are no ffs functions.
150     if (!ffsEnabled) {
151         if (!WriteStringToFile(kGadgetName, PULLUP_PATH)) return V1_0::Status::ERROR;
152         mCurrentUsbFunctionsApplied = true;
153         if (callback) callback->setCurrentUsbFunctionsCb(functions, V1_0::Status::SUCCESS);
154         return V1_0::Status::SUCCESS;
155     }
156 
157     monitorFfs.registerFunctionsAppliedCallback(&currentFunctionsAppliedCallback, this);
158     // Monitors the ffs paths to pull up the gadget when descriptors are written.
159     // Also takes of the pulling up the gadget again if the userspace process
160     // dies and restarts.
161     monitorFfs.startMonitor();
162 
163     if (kDebug) ALOGI("Mainthread in Cv");
164 
165     if (callback) {
166         bool pullup = monitorFfs.waitForPullUp(timeout);
167         Return<void> ret = callback->setCurrentUsbFunctionsCb(
168                 functions, pullup ? V1_0::Status::SUCCESS : V1_0::Status::ERROR);
169         if (!ret.isOk()) ALOGE("setCurrentUsbFunctionsCb error %s", ret.description().c_str());
170     }
171 
172     return V1_0::Status::SUCCESS;
173 }
174 
setCurrentUsbFunctions(uint64_t functions,const sp<V1_0::IUsbGadgetCallback> & callback,uint64_t timeout)175 Return<void> UsbGadget::setCurrentUsbFunctions(uint64_t functions,
176                                                const sp<V1_0::IUsbGadgetCallback>& callback,
177                                                uint64_t timeout) {
178     std::unique_lock<std::mutex> lk(mLockSetCurrentFunction);
179 
180     mCurrentUsbFunctions = functions;
181     mCurrentUsbFunctionsApplied = false;
182 
183     // Unlink the gadget and stop the monitor if running.
184     V1_0::Status status = tearDownGadget();
185     if (status != V1_0::Status::SUCCESS) {
186         goto error;
187     }
188 
189     ALOGI("Returned from tearDown gadget");
190 
191     // Leave the gadget pulled down to give time for the host to sense disconnect.
192     usleep(kDisconnectWaitUs);
193 
194     if (functions == static_cast<uint64_t>(V1_0::GadgetFunction::NONE)) {
195         if (callback == NULL) return Void();
196         Return<void> ret = callback->setCurrentUsbFunctionsCb(functions, V1_0::Status::SUCCESS);
197         if (!ret.isOk())
198             ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.description().c_str());
199         return Void();
200     }
201 
202     status = validateAndSetVidPid(functions);
203 
204     if (status != V1_0::Status::SUCCESS) {
205         goto error;
206     }
207 
208     status = setupFunctions(functions, callback, timeout);
209     if (status != V1_0::Status::SUCCESS) {
210         goto error;
211     }
212 
213     ALOGI("Usb Gadget setcurrent functions called successfully");
214     return Void();
215 
216 error:
217     ALOGI("Usb Gadget setcurrent functions failed");
218     if (callback == NULL) return Void();
219     Return<void> ret = callback->setCurrentUsbFunctionsCb(functions, status);
220     if (!ret.isOk())
221         ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.description().c_str());
222     return Void();
223 }
224 }  // namespace implementation
225 }  // namespace V1_1
226 }  // namespace gadget
227 }  // namespace usb
228 }  // namespace hardware
229 }  // namespace android
230