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(¤tFunctionsAppliedCallback, 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