1*4d7e907cSAndroid Build Coastguard Worker /*
2*4d7e907cSAndroid Build Coastguard Worker * Copyright (C) 2021 The Android Open Source Project
3*4d7e907cSAndroid Build Coastguard Worker *
4*4d7e907cSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*4d7e907cSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*4d7e907cSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*4d7e907cSAndroid Build Coastguard Worker *
8*4d7e907cSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*4d7e907cSAndroid Build Coastguard Worker *
10*4d7e907cSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*4d7e907cSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*4d7e907cSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*4d7e907cSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*4d7e907cSAndroid Build Coastguard Worker * limitations under the License.
15*4d7e907cSAndroid Build Coastguard Worker */
16*4d7e907cSAndroid Build Coastguard Worker
17*4d7e907cSAndroid Build Coastguard Worker #define LOG_TAG "android.hardware.usb.aidl-service"
18*4d7e907cSAndroid Build Coastguard Worker
19*4d7e907cSAndroid Build Coastguard Worker #include <aidl/android/hardware/usb/PortRole.h>
20*4d7e907cSAndroid Build Coastguard Worker #include <android-base/logging.h>
21*4d7e907cSAndroid Build Coastguard Worker #include <android-base/properties.h>
22*4d7e907cSAndroid Build Coastguard Worker #include <android-base/strings.h>
23*4d7e907cSAndroid Build Coastguard Worker #include <assert.h>
24*4d7e907cSAndroid Build Coastguard Worker #include <dirent.h>
25*4d7e907cSAndroid Build Coastguard Worker #include <pthread.h>
26*4d7e907cSAndroid Build Coastguard Worker #include <stdio.h>
27*4d7e907cSAndroid Build Coastguard Worker #include <sys/types.h>
28*4d7e907cSAndroid Build Coastguard Worker #include <unistd.h>
29*4d7e907cSAndroid Build Coastguard Worker #include <chrono>
30*4d7e907cSAndroid Build Coastguard Worker #include <regex>
31*4d7e907cSAndroid Build Coastguard Worker #include <thread>
32*4d7e907cSAndroid Build Coastguard Worker #include <unordered_map>
33*4d7e907cSAndroid Build Coastguard Worker
34*4d7e907cSAndroid Build Coastguard Worker #include <cutils/uevent.h>
35*4d7e907cSAndroid Build Coastguard Worker #include <sys/epoll.h>
36*4d7e907cSAndroid Build Coastguard Worker #include <utils/Errors.h>
37*4d7e907cSAndroid Build Coastguard Worker #include <utils/StrongPointer.h>
38*4d7e907cSAndroid Build Coastguard Worker
39*4d7e907cSAndroid Build Coastguard Worker #include "Usb.h"
40*4d7e907cSAndroid Build Coastguard Worker
41*4d7e907cSAndroid Build Coastguard Worker using android::base::GetProperty;
42*4d7e907cSAndroid Build Coastguard Worker using android::base::Trim;
43*4d7e907cSAndroid Build Coastguard Worker
44*4d7e907cSAndroid Build Coastguard Worker namespace aidl {
45*4d7e907cSAndroid Build Coastguard Worker namespace android {
46*4d7e907cSAndroid Build Coastguard Worker namespace hardware {
47*4d7e907cSAndroid Build Coastguard Worker namespace usb {
48*4d7e907cSAndroid Build Coastguard Worker
49*4d7e907cSAndroid Build Coastguard Worker constexpr char kTypecPath[] = "/sys/class/typec/";
50*4d7e907cSAndroid Build Coastguard Worker constexpr char kDataRoleNode[] = "/data_role";
51*4d7e907cSAndroid Build Coastguard Worker constexpr char kPowerRoleNode[] = "/power_role";
52*4d7e907cSAndroid Build Coastguard Worker
53*4d7e907cSAndroid Build Coastguard Worker // Set by the signal handler to destroy the thread
54*4d7e907cSAndroid Build Coastguard Worker volatile bool destroyThread;
55*4d7e907cSAndroid Build Coastguard Worker
56*4d7e907cSAndroid Build Coastguard Worker void queryVersionHelper(android::hardware::usb::Usb *usb,
57*4d7e907cSAndroid Build Coastguard Worker std::vector<PortStatus> *currentPortStatus);
58*4d7e907cSAndroid Build Coastguard Worker
enableUsbData(const string & in_portName,bool in_enable,int64_t in_transactionId)59*4d7e907cSAndroid Build Coastguard Worker ScopedAStatus Usb::enableUsbData(const string& in_portName, bool in_enable, int64_t in_transactionId) {
60*4d7e907cSAndroid Build Coastguard Worker std::vector<PortStatus> currentPortStatus;
61*4d7e907cSAndroid Build Coastguard Worker
62*4d7e907cSAndroid Build Coastguard Worker pthread_mutex_lock(&mLock);
63*4d7e907cSAndroid Build Coastguard Worker if (mCallback != NULL) {
64*4d7e907cSAndroid Build Coastguard Worker ScopedAStatus ret = mCallback->notifyEnableUsbDataStatus(
65*4d7e907cSAndroid Build Coastguard Worker in_portName, true, in_enable ? Status::SUCCESS : Status::ERROR, in_transactionId);
66*4d7e907cSAndroid Build Coastguard Worker if (!ret.isOk())
67*4d7e907cSAndroid Build Coastguard Worker ALOGE("notifyEnableUsbDataStatus error %s", ret.getDescription().c_str());
68*4d7e907cSAndroid Build Coastguard Worker } else {
69*4d7e907cSAndroid Build Coastguard Worker ALOGE("Not notifying the userspace. Callback is not set");
70*4d7e907cSAndroid Build Coastguard Worker }
71*4d7e907cSAndroid Build Coastguard Worker pthread_mutex_unlock(&mLock);
72*4d7e907cSAndroid Build Coastguard Worker queryVersionHelper(this, ¤tPortStatus);
73*4d7e907cSAndroid Build Coastguard Worker
74*4d7e907cSAndroid Build Coastguard Worker return ScopedAStatus::ok();
75*4d7e907cSAndroid Build Coastguard Worker }
76*4d7e907cSAndroid Build Coastguard Worker
enableUsbDataWhileDocked(const string & in_portName,int64_t in_transactionId)77*4d7e907cSAndroid Build Coastguard Worker ScopedAStatus Usb::enableUsbDataWhileDocked(const string& in_portName, int64_t in_transactionId) {
78*4d7e907cSAndroid Build Coastguard Worker
79*4d7e907cSAndroid Build Coastguard Worker pthread_mutex_lock(&mLock);
80*4d7e907cSAndroid Build Coastguard Worker if (mCallback != NULL) {
81*4d7e907cSAndroid Build Coastguard Worker ScopedAStatus ret = mCallback->notifyEnableUsbDataWhileDockedStatus(
82*4d7e907cSAndroid Build Coastguard Worker in_portName, Status::NOT_SUPPORTED, in_transactionId);
83*4d7e907cSAndroid Build Coastguard Worker if (!ret.isOk())
84*4d7e907cSAndroid Build Coastguard Worker ALOGE("notifyEnableUsbDataWhileDockedStatus error %s", ret.getDescription().c_str());
85*4d7e907cSAndroid Build Coastguard Worker } else {
86*4d7e907cSAndroid Build Coastguard Worker ALOGE("Not notifying the userspace. Callback is not set");
87*4d7e907cSAndroid Build Coastguard Worker }
88*4d7e907cSAndroid Build Coastguard Worker pthread_mutex_unlock(&mLock);
89*4d7e907cSAndroid Build Coastguard Worker
90*4d7e907cSAndroid Build Coastguard Worker return ScopedAStatus::ok();
91*4d7e907cSAndroid Build Coastguard Worker }
92*4d7e907cSAndroid Build Coastguard Worker
resetUsbPort(const string & in_portName,int64_t in_transactionId)93*4d7e907cSAndroid Build Coastguard Worker ScopedAStatus Usb::resetUsbPort(const string& in_portName, int64_t in_transactionId) {
94*4d7e907cSAndroid Build Coastguard Worker
95*4d7e907cSAndroid Build Coastguard Worker pthread_mutex_lock(&mLock);
96*4d7e907cSAndroid Build Coastguard Worker if (mCallback != NULL) {
97*4d7e907cSAndroid Build Coastguard Worker ScopedAStatus ret = mCallback->notifyResetUsbPortStatus(
98*4d7e907cSAndroid Build Coastguard Worker in_portName, Status::NOT_SUPPORTED, in_transactionId);
99*4d7e907cSAndroid Build Coastguard Worker if (!ret.isOk())
100*4d7e907cSAndroid Build Coastguard Worker ALOGE("notifyResetUsbPortStatus error %s", ret.getDescription().c_str());
101*4d7e907cSAndroid Build Coastguard Worker } else {
102*4d7e907cSAndroid Build Coastguard Worker ALOGE("Not notifying the userspace. Callback is not set");
103*4d7e907cSAndroid Build Coastguard Worker }
104*4d7e907cSAndroid Build Coastguard Worker pthread_mutex_unlock(&mLock);
105*4d7e907cSAndroid Build Coastguard Worker
106*4d7e907cSAndroid Build Coastguard Worker return ScopedAStatus::ok();
107*4d7e907cSAndroid Build Coastguard Worker }
108*4d7e907cSAndroid Build Coastguard Worker
queryMoistureDetectionStatus(std::vector<PortStatus> * currentPortStatus)109*4d7e907cSAndroid Build Coastguard Worker Status queryMoistureDetectionStatus(std::vector<PortStatus> *currentPortStatus) {
110*4d7e907cSAndroid Build Coastguard Worker string enabled, status, path, DetectedPath;
111*4d7e907cSAndroid Build Coastguard Worker
112*4d7e907cSAndroid Build Coastguard Worker for (int i = 0; i < currentPortStatus->size(); i++) {
113*4d7e907cSAndroid Build Coastguard Worker (*currentPortStatus)[i].supportedContaminantProtectionModes
114*4d7e907cSAndroid Build Coastguard Worker .push_back(ContaminantProtectionMode::NONE);
115*4d7e907cSAndroid Build Coastguard Worker (*currentPortStatus)[i].contaminantProtectionStatus
116*4d7e907cSAndroid Build Coastguard Worker = ContaminantProtectionStatus::NONE;
117*4d7e907cSAndroid Build Coastguard Worker (*currentPortStatus)[i].contaminantDetectionStatus
118*4d7e907cSAndroid Build Coastguard Worker = ContaminantDetectionStatus::NOT_SUPPORTED;
119*4d7e907cSAndroid Build Coastguard Worker (*currentPortStatus)[i].supportsEnableContaminantPresenceDetection = false;
120*4d7e907cSAndroid Build Coastguard Worker (*currentPortStatus)[i].supportsEnableContaminantPresenceProtection = false;
121*4d7e907cSAndroid Build Coastguard Worker }
122*4d7e907cSAndroid Build Coastguard Worker
123*4d7e907cSAndroid Build Coastguard Worker return Status::SUCCESS;
124*4d7e907cSAndroid Build Coastguard Worker }
125*4d7e907cSAndroid Build Coastguard Worker
queryNonCompliantChargerStatus(std::vector<PortStatus> * currentPortStatus)126*4d7e907cSAndroid Build Coastguard Worker Status queryNonCompliantChargerStatus(std::vector<PortStatus> *currentPortStatus) {
127*4d7e907cSAndroid Build Coastguard Worker string reasons, path;
128*4d7e907cSAndroid Build Coastguard Worker
129*4d7e907cSAndroid Build Coastguard Worker for (int i = 0; i < currentPortStatus->size(); i++) {
130*4d7e907cSAndroid Build Coastguard Worker (*currentPortStatus)[i].supportsComplianceWarnings = false;
131*4d7e907cSAndroid Build Coastguard Worker }
132*4d7e907cSAndroid Build Coastguard Worker return Status::SUCCESS;
133*4d7e907cSAndroid Build Coastguard Worker }
134*4d7e907cSAndroid Build Coastguard Worker
appendRoleNodeHelper(const string & portName,PortRole::Tag tag)135*4d7e907cSAndroid Build Coastguard Worker string appendRoleNodeHelper(const string &portName, PortRole::Tag tag) {
136*4d7e907cSAndroid Build Coastguard Worker string node(kTypecPath + portName);
137*4d7e907cSAndroid Build Coastguard Worker
138*4d7e907cSAndroid Build Coastguard Worker switch (tag) {
139*4d7e907cSAndroid Build Coastguard Worker case PortRole::dataRole:
140*4d7e907cSAndroid Build Coastguard Worker return node + kDataRoleNode;
141*4d7e907cSAndroid Build Coastguard Worker case PortRole::powerRole:
142*4d7e907cSAndroid Build Coastguard Worker return node + kPowerRoleNode;
143*4d7e907cSAndroid Build Coastguard Worker case PortRole::mode:
144*4d7e907cSAndroid Build Coastguard Worker return node + "/port_type";
145*4d7e907cSAndroid Build Coastguard Worker default:
146*4d7e907cSAndroid Build Coastguard Worker return "";
147*4d7e907cSAndroid Build Coastguard Worker }
148*4d7e907cSAndroid Build Coastguard Worker }
149*4d7e907cSAndroid Build Coastguard Worker
convertRoletoString(PortRole role)150*4d7e907cSAndroid Build Coastguard Worker string convertRoletoString(PortRole role) {
151*4d7e907cSAndroid Build Coastguard Worker if (role.getTag() == PortRole::powerRole) {
152*4d7e907cSAndroid Build Coastguard Worker if (role.get<PortRole::powerRole>() == PortPowerRole::SOURCE)
153*4d7e907cSAndroid Build Coastguard Worker return "source";
154*4d7e907cSAndroid Build Coastguard Worker else if (role.get<PortRole::powerRole>() == PortPowerRole::SINK)
155*4d7e907cSAndroid Build Coastguard Worker return "sink";
156*4d7e907cSAndroid Build Coastguard Worker } else if (role.getTag() == PortRole::dataRole) {
157*4d7e907cSAndroid Build Coastguard Worker if (role.get<PortRole::dataRole>() == PortDataRole::HOST)
158*4d7e907cSAndroid Build Coastguard Worker return "host";
159*4d7e907cSAndroid Build Coastguard Worker if (role.get<PortRole::dataRole>() == PortDataRole::DEVICE)
160*4d7e907cSAndroid Build Coastguard Worker return "device";
161*4d7e907cSAndroid Build Coastguard Worker } else if (role.getTag() == PortRole::mode) {
162*4d7e907cSAndroid Build Coastguard Worker if (role.get<PortRole::mode>() == PortMode::UFP)
163*4d7e907cSAndroid Build Coastguard Worker return "sink";
164*4d7e907cSAndroid Build Coastguard Worker if (role.get<PortRole::mode>() == PortMode::DFP)
165*4d7e907cSAndroid Build Coastguard Worker return "source";
166*4d7e907cSAndroid Build Coastguard Worker }
167*4d7e907cSAndroid Build Coastguard Worker return "none";
168*4d7e907cSAndroid Build Coastguard Worker }
169*4d7e907cSAndroid Build Coastguard Worker
extractRole(string * roleName)170*4d7e907cSAndroid Build Coastguard Worker void extractRole(string *roleName) {
171*4d7e907cSAndroid Build Coastguard Worker std::size_t first, last;
172*4d7e907cSAndroid Build Coastguard Worker
173*4d7e907cSAndroid Build Coastguard Worker first = roleName->find("[");
174*4d7e907cSAndroid Build Coastguard Worker last = roleName->find("]");
175*4d7e907cSAndroid Build Coastguard Worker
176*4d7e907cSAndroid Build Coastguard Worker if (first != string::npos && last != string::npos) {
177*4d7e907cSAndroid Build Coastguard Worker *roleName = roleName->substr(first + 1, last - first - 1);
178*4d7e907cSAndroid Build Coastguard Worker }
179*4d7e907cSAndroid Build Coastguard Worker }
180*4d7e907cSAndroid Build Coastguard Worker
switchToDrp(const string & portName)181*4d7e907cSAndroid Build Coastguard Worker void switchToDrp(const string &portName) {
182*4d7e907cSAndroid Build Coastguard Worker string filename = appendRoleNodeHelper(string(portName.c_str()), PortRole::mode);
183*4d7e907cSAndroid Build Coastguard Worker FILE *fp;
184*4d7e907cSAndroid Build Coastguard Worker
185*4d7e907cSAndroid Build Coastguard Worker if (filename != "") {
186*4d7e907cSAndroid Build Coastguard Worker fp = fopen(filename.c_str(), "w");
187*4d7e907cSAndroid Build Coastguard Worker if (fp != NULL) {
188*4d7e907cSAndroid Build Coastguard Worker int ret = fputs("dual", fp);
189*4d7e907cSAndroid Build Coastguard Worker fclose(fp);
190*4d7e907cSAndroid Build Coastguard Worker if (ret == EOF)
191*4d7e907cSAndroid Build Coastguard Worker ALOGE("Fatal: Error while switching back to drp");
192*4d7e907cSAndroid Build Coastguard Worker } else {
193*4d7e907cSAndroid Build Coastguard Worker ALOGE("Fatal: Cannot open file to switch back to drp");
194*4d7e907cSAndroid Build Coastguard Worker }
195*4d7e907cSAndroid Build Coastguard Worker } else {
196*4d7e907cSAndroid Build Coastguard Worker ALOGE("Fatal: invalid node type");
197*4d7e907cSAndroid Build Coastguard Worker }
198*4d7e907cSAndroid Build Coastguard Worker }
199*4d7e907cSAndroid Build Coastguard Worker
switchMode(const string & portName,const PortRole & in_role,struct Usb * usb)200*4d7e907cSAndroid Build Coastguard Worker bool switchMode(const string &portName, const PortRole &in_role, struct Usb *usb) {
201*4d7e907cSAndroid Build Coastguard Worker string filename = appendRoleNodeHelper(string(portName.c_str()), in_role.getTag());
202*4d7e907cSAndroid Build Coastguard Worker string written;
203*4d7e907cSAndroid Build Coastguard Worker FILE *fp;
204*4d7e907cSAndroid Build Coastguard Worker bool roleSwitch = false;
205*4d7e907cSAndroid Build Coastguard Worker
206*4d7e907cSAndroid Build Coastguard Worker if (filename == "") {
207*4d7e907cSAndroid Build Coastguard Worker ALOGE("Fatal: invalid node type");
208*4d7e907cSAndroid Build Coastguard Worker return false;
209*4d7e907cSAndroid Build Coastguard Worker }
210*4d7e907cSAndroid Build Coastguard Worker
211*4d7e907cSAndroid Build Coastguard Worker fp = fopen(filename.c_str(), "w");
212*4d7e907cSAndroid Build Coastguard Worker if (fp != NULL) {
213*4d7e907cSAndroid Build Coastguard Worker // Hold the lock here to prevent loosing connected signals
214*4d7e907cSAndroid Build Coastguard Worker // as once the file is written the partner added signal
215*4d7e907cSAndroid Build Coastguard Worker // can arrive anytime.
216*4d7e907cSAndroid Build Coastguard Worker pthread_mutex_lock(&usb->mPartnerLock);
217*4d7e907cSAndroid Build Coastguard Worker usb->mPartnerUp = false;
218*4d7e907cSAndroid Build Coastguard Worker int ret = fputs(convertRoletoString(in_role).c_str(), fp);
219*4d7e907cSAndroid Build Coastguard Worker fclose(fp);
220*4d7e907cSAndroid Build Coastguard Worker
221*4d7e907cSAndroid Build Coastguard Worker if (ret != EOF) {
222*4d7e907cSAndroid Build Coastguard Worker struct timespec to;
223*4d7e907cSAndroid Build Coastguard Worker struct timespec now;
224*4d7e907cSAndroid Build Coastguard Worker
225*4d7e907cSAndroid Build Coastguard Worker wait_again:
226*4d7e907cSAndroid Build Coastguard Worker clock_gettime(CLOCK_MONOTONIC, &now);
227*4d7e907cSAndroid Build Coastguard Worker to.tv_sec = now.tv_sec + PORT_TYPE_TIMEOUT;
228*4d7e907cSAndroid Build Coastguard Worker to.tv_nsec = now.tv_nsec;
229*4d7e907cSAndroid Build Coastguard Worker
230*4d7e907cSAndroid Build Coastguard Worker int err = pthread_cond_timedwait(&usb->mPartnerCV, &usb->mPartnerLock, &to);
231*4d7e907cSAndroid Build Coastguard Worker // There are no uevent signals which implies role swap timed out.
232*4d7e907cSAndroid Build Coastguard Worker if (err == ETIMEDOUT) {
233*4d7e907cSAndroid Build Coastguard Worker ALOGI("uevents wait timedout");
234*4d7e907cSAndroid Build Coastguard Worker // Validity check.
235*4d7e907cSAndroid Build Coastguard Worker } else if (!usb->mPartnerUp) {
236*4d7e907cSAndroid Build Coastguard Worker goto wait_again;
237*4d7e907cSAndroid Build Coastguard Worker // Role switch succeeded since usb->mPartnerUp is true.
238*4d7e907cSAndroid Build Coastguard Worker } else {
239*4d7e907cSAndroid Build Coastguard Worker roleSwitch = true;
240*4d7e907cSAndroid Build Coastguard Worker }
241*4d7e907cSAndroid Build Coastguard Worker } else {
242*4d7e907cSAndroid Build Coastguard Worker ALOGI("Role switch failed while wrting to file");
243*4d7e907cSAndroid Build Coastguard Worker }
244*4d7e907cSAndroid Build Coastguard Worker pthread_mutex_unlock(&usb->mPartnerLock);
245*4d7e907cSAndroid Build Coastguard Worker }
246*4d7e907cSAndroid Build Coastguard Worker
247*4d7e907cSAndroid Build Coastguard Worker if (!roleSwitch)
248*4d7e907cSAndroid Build Coastguard Worker switchToDrp(string(portName.c_str()));
249*4d7e907cSAndroid Build Coastguard Worker
250*4d7e907cSAndroid Build Coastguard Worker return roleSwitch;
251*4d7e907cSAndroid Build Coastguard Worker }
252*4d7e907cSAndroid Build Coastguard Worker
Usb()253*4d7e907cSAndroid Build Coastguard Worker Usb::Usb()
254*4d7e907cSAndroid Build Coastguard Worker : mLock(PTHREAD_MUTEX_INITIALIZER),
255*4d7e907cSAndroid Build Coastguard Worker mRoleSwitchLock(PTHREAD_MUTEX_INITIALIZER),
256*4d7e907cSAndroid Build Coastguard Worker mPartnerLock(PTHREAD_MUTEX_INITIALIZER),
257*4d7e907cSAndroid Build Coastguard Worker mPartnerUp(false)
258*4d7e907cSAndroid Build Coastguard Worker {
259*4d7e907cSAndroid Build Coastguard Worker pthread_condattr_t attr;
260*4d7e907cSAndroid Build Coastguard Worker if (pthread_condattr_init(&attr)) {
261*4d7e907cSAndroid Build Coastguard Worker ALOGE("pthread_condattr_init failed: %s", strerror(errno));
262*4d7e907cSAndroid Build Coastguard Worker abort();
263*4d7e907cSAndroid Build Coastguard Worker }
264*4d7e907cSAndroid Build Coastguard Worker if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)) {
265*4d7e907cSAndroid Build Coastguard Worker ALOGE("pthread_condattr_setclock failed: %s", strerror(errno));
266*4d7e907cSAndroid Build Coastguard Worker abort();
267*4d7e907cSAndroid Build Coastguard Worker }
268*4d7e907cSAndroid Build Coastguard Worker if (pthread_cond_init(&mPartnerCV, &attr)) {
269*4d7e907cSAndroid Build Coastguard Worker ALOGE("pthread_cond_init failed: %s", strerror(errno));
270*4d7e907cSAndroid Build Coastguard Worker abort();
271*4d7e907cSAndroid Build Coastguard Worker }
272*4d7e907cSAndroid Build Coastguard Worker if (pthread_condattr_destroy(&attr)) {
273*4d7e907cSAndroid Build Coastguard Worker ALOGE("pthread_condattr_destroy failed: %s", strerror(errno));
274*4d7e907cSAndroid Build Coastguard Worker abort();
275*4d7e907cSAndroid Build Coastguard Worker }
276*4d7e907cSAndroid Build Coastguard Worker }
277*4d7e907cSAndroid Build Coastguard Worker
switchRole(const string & in_portName,const PortRole & in_role,int64_t in_transactionId)278*4d7e907cSAndroid Build Coastguard Worker ScopedAStatus Usb::switchRole(const string& in_portName,
279*4d7e907cSAndroid Build Coastguard Worker const PortRole& in_role, int64_t in_transactionId) {
280*4d7e907cSAndroid Build Coastguard Worker string filename = appendRoleNodeHelper(string(in_portName.c_str()), in_role.getTag());
281*4d7e907cSAndroid Build Coastguard Worker string written;
282*4d7e907cSAndroid Build Coastguard Worker FILE *fp;
283*4d7e907cSAndroid Build Coastguard Worker bool roleSwitch = false;
284*4d7e907cSAndroid Build Coastguard Worker
285*4d7e907cSAndroid Build Coastguard Worker if (filename == "") {
286*4d7e907cSAndroid Build Coastguard Worker ALOGE("Fatal: invalid node type");
287*4d7e907cSAndroid Build Coastguard Worker return ScopedAStatus::ok();
288*4d7e907cSAndroid Build Coastguard Worker }
289*4d7e907cSAndroid Build Coastguard Worker
290*4d7e907cSAndroid Build Coastguard Worker pthread_mutex_lock(&mRoleSwitchLock);
291*4d7e907cSAndroid Build Coastguard Worker
292*4d7e907cSAndroid Build Coastguard Worker ALOGI("filename write: %s role:%s", filename.c_str(), convertRoletoString(in_role).c_str());
293*4d7e907cSAndroid Build Coastguard Worker
294*4d7e907cSAndroid Build Coastguard Worker if (in_role.getTag() == PortRole::mode) {
295*4d7e907cSAndroid Build Coastguard Worker roleSwitch = switchMode(in_portName, in_role, this);
296*4d7e907cSAndroid Build Coastguard Worker } else {
297*4d7e907cSAndroid Build Coastguard Worker fp = fopen(filename.c_str(), "w");
298*4d7e907cSAndroid Build Coastguard Worker if (fp != NULL) {
299*4d7e907cSAndroid Build Coastguard Worker int ret = fputs(convertRoletoString(in_role).c_str(), fp);
300*4d7e907cSAndroid Build Coastguard Worker fclose(fp);
301*4d7e907cSAndroid Build Coastguard Worker if ((ret != EOF) && ReadFileToString(filename, &written)) {
302*4d7e907cSAndroid Build Coastguard Worker written = Trim(written);
303*4d7e907cSAndroid Build Coastguard Worker extractRole(&written);
304*4d7e907cSAndroid Build Coastguard Worker ALOGI("written: %s", written.c_str());
305*4d7e907cSAndroid Build Coastguard Worker if (written == convertRoletoString(in_role)) {
306*4d7e907cSAndroid Build Coastguard Worker roleSwitch = true;
307*4d7e907cSAndroid Build Coastguard Worker } else {
308*4d7e907cSAndroid Build Coastguard Worker ALOGE("Role switch failed");
309*4d7e907cSAndroid Build Coastguard Worker }
310*4d7e907cSAndroid Build Coastguard Worker } else {
311*4d7e907cSAndroid Build Coastguard Worker ALOGE("failed to update the new role");
312*4d7e907cSAndroid Build Coastguard Worker }
313*4d7e907cSAndroid Build Coastguard Worker } else {
314*4d7e907cSAndroid Build Coastguard Worker ALOGE("fopen failed");
315*4d7e907cSAndroid Build Coastguard Worker }
316*4d7e907cSAndroid Build Coastguard Worker }
317*4d7e907cSAndroid Build Coastguard Worker
318*4d7e907cSAndroid Build Coastguard Worker pthread_mutex_lock(&mLock);
319*4d7e907cSAndroid Build Coastguard Worker if (mCallback != NULL) {
320*4d7e907cSAndroid Build Coastguard Worker ScopedAStatus ret = mCallback->notifyRoleSwitchStatus(
321*4d7e907cSAndroid Build Coastguard Worker in_portName, in_role, roleSwitch ? Status::SUCCESS : Status::ERROR, in_transactionId);
322*4d7e907cSAndroid Build Coastguard Worker if (!ret.isOk())
323*4d7e907cSAndroid Build Coastguard Worker ALOGE("RoleSwitchStatus error %s", ret.getDescription().c_str());
324*4d7e907cSAndroid Build Coastguard Worker } else {
325*4d7e907cSAndroid Build Coastguard Worker ALOGE("Not notifying the userspace. Callback is not set");
326*4d7e907cSAndroid Build Coastguard Worker }
327*4d7e907cSAndroid Build Coastguard Worker pthread_mutex_unlock(&mLock);
328*4d7e907cSAndroid Build Coastguard Worker pthread_mutex_unlock(&mRoleSwitchLock);
329*4d7e907cSAndroid Build Coastguard Worker
330*4d7e907cSAndroid Build Coastguard Worker return ScopedAStatus::ok();
331*4d7e907cSAndroid Build Coastguard Worker }
332*4d7e907cSAndroid Build Coastguard Worker
limitPowerTransfer(const string & in_portName,bool,int64_t in_transactionId)333*4d7e907cSAndroid Build Coastguard Worker ScopedAStatus Usb::limitPowerTransfer(const string& in_portName, bool /*in_limit*/,
334*4d7e907cSAndroid Build Coastguard Worker int64_t in_transactionId) {
335*4d7e907cSAndroid Build Coastguard Worker std::vector<PortStatus> currentPortStatus;
336*4d7e907cSAndroid Build Coastguard Worker
337*4d7e907cSAndroid Build Coastguard Worker pthread_mutex_lock(&mLock);
338*4d7e907cSAndroid Build Coastguard Worker if (mCallback != NULL && in_transactionId >= 0) {
339*4d7e907cSAndroid Build Coastguard Worker ScopedAStatus ret = mCallback->notifyLimitPowerTransferStatus(
340*4d7e907cSAndroid Build Coastguard Worker in_portName, false, Status::NOT_SUPPORTED, in_transactionId);
341*4d7e907cSAndroid Build Coastguard Worker if (!ret.isOk())
342*4d7e907cSAndroid Build Coastguard Worker ALOGE("limitPowerTransfer error %s", ret.getDescription().c_str());
343*4d7e907cSAndroid Build Coastguard Worker } else {
344*4d7e907cSAndroid Build Coastguard Worker ALOGE("Not notifying the userspace. Callback is not set");
345*4d7e907cSAndroid Build Coastguard Worker }
346*4d7e907cSAndroid Build Coastguard Worker pthread_mutex_unlock(&mLock);
347*4d7e907cSAndroid Build Coastguard Worker
348*4d7e907cSAndroid Build Coastguard Worker return ScopedAStatus::ok();
349*4d7e907cSAndroid Build Coastguard Worker }
350*4d7e907cSAndroid Build Coastguard Worker
getAccessoryConnected(const string & portName,string * accessory)351*4d7e907cSAndroid Build Coastguard Worker Status getAccessoryConnected(const string &portName, string *accessory) {
352*4d7e907cSAndroid Build Coastguard Worker string filename = kTypecPath + portName + "-partner/accessory_mode";
353*4d7e907cSAndroid Build Coastguard Worker
354*4d7e907cSAndroid Build Coastguard Worker if (!ReadFileToString(filename, accessory)) {
355*4d7e907cSAndroid Build Coastguard Worker ALOGE("getAccessoryConnected: Failed to open filesystem node: %s", filename.c_str());
356*4d7e907cSAndroid Build Coastguard Worker return Status::ERROR;
357*4d7e907cSAndroid Build Coastguard Worker }
358*4d7e907cSAndroid Build Coastguard Worker *accessory = Trim(*accessory);
359*4d7e907cSAndroid Build Coastguard Worker
360*4d7e907cSAndroid Build Coastguard Worker return Status::SUCCESS;
361*4d7e907cSAndroid Build Coastguard Worker }
362*4d7e907cSAndroid Build Coastguard Worker
getCurrentRoleHelper(const string & portName,bool connected,PortRole * currentRole)363*4d7e907cSAndroid Build Coastguard Worker Status getCurrentRoleHelper(const string &portName, bool connected, PortRole *currentRole) {
364*4d7e907cSAndroid Build Coastguard Worker string filename;
365*4d7e907cSAndroid Build Coastguard Worker string roleName;
366*4d7e907cSAndroid Build Coastguard Worker string accessory;
367*4d7e907cSAndroid Build Coastguard Worker
368*4d7e907cSAndroid Build Coastguard Worker // Mode
369*4d7e907cSAndroid Build Coastguard Worker
370*4d7e907cSAndroid Build Coastguard Worker if (currentRole->getTag() == PortRole::powerRole) {
371*4d7e907cSAndroid Build Coastguard Worker filename = kTypecPath + portName + kPowerRoleNode;
372*4d7e907cSAndroid Build Coastguard Worker currentRole->set<PortRole::powerRole>(PortPowerRole::NONE);
373*4d7e907cSAndroid Build Coastguard Worker } else if (currentRole->getTag() == PortRole::dataRole) {
374*4d7e907cSAndroid Build Coastguard Worker filename = kTypecPath + portName + kDataRoleNode;
375*4d7e907cSAndroid Build Coastguard Worker currentRole->set<PortRole::dataRole>(PortDataRole::NONE);
376*4d7e907cSAndroid Build Coastguard Worker } else if (currentRole->getTag() == PortRole::mode) {
377*4d7e907cSAndroid Build Coastguard Worker filename = kTypecPath + portName + kDataRoleNode;
378*4d7e907cSAndroid Build Coastguard Worker currentRole->set<PortRole::mode>(PortMode::NONE);
379*4d7e907cSAndroid Build Coastguard Worker } else {
380*4d7e907cSAndroid Build Coastguard Worker return Status::ERROR;
381*4d7e907cSAndroid Build Coastguard Worker }
382*4d7e907cSAndroid Build Coastguard Worker
383*4d7e907cSAndroid Build Coastguard Worker if (!connected)
384*4d7e907cSAndroid Build Coastguard Worker return Status::SUCCESS;
385*4d7e907cSAndroid Build Coastguard Worker
386*4d7e907cSAndroid Build Coastguard Worker if (currentRole->getTag() == PortRole::mode) {
387*4d7e907cSAndroid Build Coastguard Worker if (getAccessoryConnected(portName, &accessory) != Status::SUCCESS) {
388*4d7e907cSAndroid Build Coastguard Worker return Status::ERROR;
389*4d7e907cSAndroid Build Coastguard Worker }
390*4d7e907cSAndroid Build Coastguard Worker if (accessory == "analog_audio") {
391*4d7e907cSAndroid Build Coastguard Worker currentRole->set<PortRole::mode>(PortMode::AUDIO_ACCESSORY);
392*4d7e907cSAndroid Build Coastguard Worker return Status::SUCCESS;
393*4d7e907cSAndroid Build Coastguard Worker } else if (accessory == "debug") {
394*4d7e907cSAndroid Build Coastguard Worker currentRole->set<PortRole::mode>(PortMode::DEBUG_ACCESSORY);
395*4d7e907cSAndroid Build Coastguard Worker return Status::SUCCESS;
396*4d7e907cSAndroid Build Coastguard Worker }
397*4d7e907cSAndroid Build Coastguard Worker }
398*4d7e907cSAndroid Build Coastguard Worker
399*4d7e907cSAndroid Build Coastguard Worker if (!ReadFileToString(filename, &roleName)) {
400*4d7e907cSAndroid Build Coastguard Worker ALOGE("getCurrentRole: Failed to open filesystem node: %s", filename.c_str());
401*4d7e907cSAndroid Build Coastguard Worker return Status::ERROR;
402*4d7e907cSAndroid Build Coastguard Worker }
403*4d7e907cSAndroid Build Coastguard Worker
404*4d7e907cSAndroid Build Coastguard Worker roleName = Trim(roleName);
405*4d7e907cSAndroid Build Coastguard Worker extractRole(&roleName);
406*4d7e907cSAndroid Build Coastguard Worker
407*4d7e907cSAndroid Build Coastguard Worker if (roleName == "source") {
408*4d7e907cSAndroid Build Coastguard Worker currentRole->set<PortRole::powerRole>(PortPowerRole::SOURCE);
409*4d7e907cSAndroid Build Coastguard Worker } else if (roleName == "sink") {
410*4d7e907cSAndroid Build Coastguard Worker currentRole->set<PortRole::powerRole>(PortPowerRole::SINK);
411*4d7e907cSAndroid Build Coastguard Worker } else if (roleName == "host") {
412*4d7e907cSAndroid Build Coastguard Worker if (currentRole->getTag() == PortRole::dataRole)
413*4d7e907cSAndroid Build Coastguard Worker currentRole->set<PortRole::dataRole>(PortDataRole::HOST);
414*4d7e907cSAndroid Build Coastguard Worker else
415*4d7e907cSAndroid Build Coastguard Worker currentRole->set<PortRole::mode>(PortMode::DFP);
416*4d7e907cSAndroid Build Coastguard Worker } else if (roleName == "device") {
417*4d7e907cSAndroid Build Coastguard Worker if (currentRole->getTag() == PortRole::dataRole)
418*4d7e907cSAndroid Build Coastguard Worker currentRole->set<PortRole::dataRole>(PortDataRole::DEVICE);
419*4d7e907cSAndroid Build Coastguard Worker else
420*4d7e907cSAndroid Build Coastguard Worker currentRole->set<PortRole::mode>(PortMode::UFP);
421*4d7e907cSAndroid Build Coastguard Worker } else if (roleName != "none") {
422*4d7e907cSAndroid Build Coastguard Worker /* case for none has already been addressed.
423*4d7e907cSAndroid Build Coastguard Worker * so we check if the role isn't none.
424*4d7e907cSAndroid Build Coastguard Worker */
425*4d7e907cSAndroid Build Coastguard Worker return Status::UNRECOGNIZED_ROLE;
426*4d7e907cSAndroid Build Coastguard Worker }
427*4d7e907cSAndroid Build Coastguard Worker
428*4d7e907cSAndroid Build Coastguard Worker return Status::SUCCESS;
429*4d7e907cSAndroid Build Coastguard Worker }
430*4d7e907cSAndroid Build Coastguard Worker
getTypeCPortNamesHelper(std::unordered_map<string,bool> * names)431*4d7e907cSAndroid Build Coastguard Worker Status getTypeCPortNamesHelper(std::unordered_map<string, bool> *names) {
432*4d7e907cSAndroid Build Coastguard Worker DIR *dp;
433*4d7e907cSAndroid Build Coastguard Worker
434*4d7e907cSAndroid Build Coastguard Worker dp = opendir(kTypecPath);
435*4d7e907cSAndroid Build Coastguard Worker if (dp != NULL) {
436*4d7e907cSAndroid Build Coastguard Worker struct dirent *ep;
437*4d7e907cSAndroid Build Coastguard Worker
438*4d7e907cSAndroid Build Coastguard Worker while ((ep = readdir(dp))) {
439*4d7e907cSAndroid Build Coastguard Worker if (ep->d_type == DT_LNK) {
440*4d7e907cSAndroid Build Coastguard Worker if (string::npos == string(ep->d_name).find("-partner")) {
441*4d7e907cSAndroid Build Coastguard Worker std::unordered_map<string, bool>::const_iterator portName =
442*4d7e907cSAndroid Build Coastguard Worker names->find(ep->d_name);
443*4d7e907cSAndroid Build Coastguard Worker if (portName == names->end()) {
444*4d7e907cSAndroid Build Coastguard Worker names->insert({ep->d_name, false});
445*4d7e907cSAndroid Build Coastguard Worker }
446*4d7e907cSAndroid Build Coastguard Worker } else {
447*4d7e907cSAndroid Build Coastguard Worker (*names)[std::strtok(ep->d_name, "-")] = true;
448*4d7e907cSAndroid Build Coastguard Worker }
449*4d7e907cSAndroid Build Coastguard Worker }
450*4d7e907cSAndroid Build Coastguard Worker }
451*4d7e907cSAndroid Build Coastguard Worker closedir(dp);
452*4d7e907cSAndroid Build Coastguard Worker return Status::SUCCESS;
453*4d7e907cSAndroid Build Coastguard Worker }
454*4d7e907cSAndroid Build Coastguard Worker
455*4d7e907cSAndroid Build Coastguard Worker ALOGE("Failed to open /sys/class/typec");
456*4d7e907cSAndroid Build Coastguard Worker return Status::ERROR;
457*4d7e907cSAndroid Build Coastguard Worker }
458*4d7e907cSAndroid Build Coastguard Worker
canSwitchRoleHelper(const string & portName)459*4d7e907cSAndroid Build Coastguard Worker bool canSwitchRoleHelper(const string &portName) {
460*4d7e907cSAndroid Build Coastguard Worker string filename = kTypecPath + portName + "-partner/supports_usb_power_delivery";
461*4d7e907cSAndroid Build Coastguard Worker string supportsPD;
462*4d7e907cSAndroid Build Coastguard Worker
463*4d7e907cSAndroid Build Coastguard Worker if (ReadFileToString(filename, &supportsPD)) {
464*4d7e907cSAndroid Build Coastguard Worker supportsPD = Trim(supportsPD);
465*4d7e907cSAndroid Build Coastguard Worker if (supportsPD == "yes") {
466*4d7e907cSAndroid Build Coastguard Worker return true;
467*4d7e907cSAndroid Build Coastguard Worker }
468*4d7e907cSAndroid Build Coastguard Worker }
469*4d7e907cSAndroid Build Coastguard Worker
470*4d7e907cSAndroid Build Coastguard Worker return false;
471*4d7e907cSAndroid Build Coastguard Worker }
472*4d7e907cSAndroid Build Coastguard Worker
getPortStatusHelper(std::vector<PortStatus> * currentPortStatus)473*4d7e907cSAndroid Build Coastguard Worker Status getPortStatusHelper(std::vector<PortStatus> *currentPortStatus) {
474*4d7e907cSAndroid Build Coastguard Worker std::unordered_map<string, bool> names;
475*4d7e907cSAndroid Build Coastguard Worker Status result = getTypeCPortNamesHelper(&names);
476*4d7e907cSAndroid Build Coastguard Worker int i = -1;
477*4d7e907cSAndroid Build Coastguard Worker
478*4d7e907cSAndroid Build Coastguard Worker if (result == Status::SUCCESS) {
479*4d7e907cSAndroid Build Coastguard Worker currentPortStatus->resize(names.size());
480*4d7e907cSAndroid Build Coastguard Worker for (std::pair<string, bool> port : names) {
481*4d7e907cSAndroid Build Coastguard Worker i++;
482*4d7e907cSAndroid Build Coastguard Worker ALOGI("%s", port.first.c_str());
483*4d7e907cSAndroid Build Coastguard Worker (*currentPortStatus)[i].portName = port.first;
484*4d7e907cSAndroid Build Coastguard Worker
485*4d7e907cSAndroid Build Coastguard Worker PortRole currentRole;
486*4d7e907cSAndroid Build Coastguard Worker currentRole.set<PortRole::powerRole>(PortPowerRole::NONE);
487*4d7e907cSAndroid Build Coastguard Worker if (getCurrentRoleHelper(port.first, port.second, ¤tRole) == Status::SUCCESS){
488*4d7e907cSAndroid Build Coastguard Worker (*currentPortStatus)[i].currentPowerRole = currentRole.get<PortRole::powerRole>();
489*4d7e907cSAndroid Build Coastguard Worker } else {
490*4d7e907cSAndroid Build Coastguard Worker ALOGE("Error while retrieving portNames");
491*4d7e907cSAndroid Build Coastguard Worker goto done;
492*4d7e907cSAndroid Build Coastguard Worker }
493*4d7e907cSAndroid Build Coastguard Worker
494*4d7e907cSAndroid Build Coastguard Worker currentRole.set<PortRole::dataRole>(PortDataRole::NONE);
495*4d7e907cSAndroid Build Coastguard Worker if (getCurrentRoleHelper(port.first, port.second, ¤tRole) == Status::SUCCESS) {
496*4d7e907cSAndroid Build Coastguard Worker (*currentPortStatus)[i].currentDataRole = currentRole.get<PortRole::dataRole>();
497*4d7e907cSAndroid Build Coastguard Worker } else {
498*4d7e907cSAndroid Build Coastguard Worker ALOGE("Error while retrieving current port role");
499*4d7e907cSAndroid Build Coastguard Worker goto done;
500*4d7e907cSAndroid Build Coastguard Worker }
501*4d7e907cSAndroid Build Coastguard Worker
502*4d7e907cSAndroid Build Coastguard Worker currentRole.set<PortRole::mode>(PortMode::NONE);
503*4d7e907cSAndroid Build Coastguard Worker if (getCurrentRoleHelper(port.first, port.second, ¤tRole) == Status::SUCCESS) {
504*4d7e907cSAndroid Build Coastguard Worker (*currentPortStatus)[i].currentMode = currentRole.get<PortRole::mode>();
505*4d7e907cSAndroid Build Coastguard Worker } else {
506*4d7e907cSAndroid Build Coastguard Worker ALOGE("Error while retrieving current data role");
507*4d7e907cSAndroid Build Coastguard Worker goto done;
508*4d7e907cSAndroid Build Coastguard Worker }
509*4d7e907cSAndroid Build Coastguard Worker
510*4d7e907cSAndroid Build Coastguard Worker (*currentPortStatus)[i].canChangeMode = true;
511*4d7e907cSAndroid Build Coastguard Worker (*currentPortStatus)[i].canChangeDataRole =
512*4d7e907cSAndroid Build Coastguard Worker port.second ? canSwitchRoleHelper(port.first) : false;
513*4d7e907cSAndroid Build Coastguard Worker (*currentPortStatus)[i].canChangePowerRole =
514*4d7e907cSAndroid Build Coastguard Worker port.second ? canSwitchRoleHelper(port.first) : false;
515*4d7e907cSAndroid Build Coastguard Worker
516*4d7e907cSAndroid Build Coastguard Worker (*currentPortStatus)[i].supportedModes.push_back(PortMode::DRP);
517*4d7e907cSAndroid Build Coastguard Worker (*currentPortStatus)[i].usbDataStatus.push_back(UsbDataStatus::ENABLED);
518*4d7e907cSAndroid Build Coastguard Worker
519*4d7e907cSAndroid Build Coastguard Worker ALOGI("%d:%s connected:%d canChangeMode:%d canChagedata:%d canChangePower:%d "
520*4d7e907cSAndroid Build Coastguard Worker "usbDataEnabled:%d plugOrientation:%d",
521*4d7e907cSAndroid Build Coastguard Worker i, port.first.c_str(), port.second, (*currentPortStatus)[i].canChangeMode,
522*4d7e907cSAndroid Build Coastguard Worker (*currentPortStatus)[i].canChangeDataRole,
523*4d7e907cSAndroid Build Coastguard Worker (*currentPortStatus)[i].canChangePowerRole, 0,
524*4d7e907cSAndroid Build Coastguard Worker (*currentPortStatus)[i].plugOrientation);
525*4d7e907cSAndroid Build Coastguard Worker }
526*4d7e907cSAndroid Build Coastguard Worker
527*4d7e907cSAndroid Build Coastguard Worker return Status::SUCCESS;
528*4d7e907cSAndroid Build Coastguard Worker }
529*4d7e907cSAndroid Build Coastguard Worker done:
530*4d7e907cSAndroid Build Coastguard Worker return Status::ERROR;
531*4d7e907cSAndroid Build Coastguard Worker }
532*4d7e907cSAndroid Build Coastguard Worker
queryVersionHelper(android::hardware::usb::Usb * usb,std::vector<PortStatus> * currentPortStatus)533*4d7e907cSAndroid Build Coastguard Worker void queryVersionHelper(android::hardware::usb::Usb *usb,
534*4d7e907cSAndroid Build Coastguard Worker std::vector<PortStatus> *currentPortStatus) {
535*4d7e907cSAndroid Build Coastguard Worker Status status;
536*4d7e907cSAndroid Build Coastguard Worker pthread_mutex_lock(&usb->mLock);
537*4d7e907cSAndroid Build Coastguard Worker status = getPortStatusHelper(currentPortStatus);
538*4d7e907cSAndroid Build Coastguard Worker queryMoistureDetectionStatus(currentPortStatus);
539*4d7e907cSAndroid Build Coastguard Worker queryNonCompliantChargerStatus(currentPortStatus);
540*4d7e907cSAndroid Build Coastguard Worker if (usb->mCallback != NULL) {
541*4d7e907cSAndroid Build Coastguard Worker ScopedAStatus ret = usb->mCallback->notifyPortStatusChange(*currentPortStatus,
542*4d7e907cSAndroid Build Coastguard Worker status);
543*4d7e907cSAndroid Build Coastguard Worker if (!ret.isOk())
544*4d7e907cSAndroid Build Coastguard Worker ALOGE("queryPortStatus error %s", ret.getDescription().c_str());
545*4d7e907cSAndroid Build Coastguard Worker } else {
546*4d7e907cSAndroid Build Coastguard Worker ALOGI("Notifying userspace skipped. Callback is NULL");
547*4d7e907cSAndroid Build Coastguard Worker }
548*4d7e907cSAndroid Build Coastguard Worker pthread_mutex_unlock(&usb->mLock);
549*4d7e907cSAndroid Build Coastguard Worker }
550*4d7e907cSAndroid Build Coastguard Worker
queryPortStatus(int64_t in_transactionId)551*4d7e907cSAndroid Build Coastguard Worker ScopedAStatus Usb::queryPortStatus(int64_t in_transactionId) {
552*4d7e907cSAndroid Build Coastguard Worker std::vector<PortStatus> currentPortStatus;
553*4d7e907cSAndroid Build Coastguard Worker
554*4d7e907cSAndroid Build Coastguard Worker queryVersionHelper(this, ¤tPortStatus);
555*4d7e907cSAndroid Build Coastguard Worker pthread_mutex_lock(&mLock);
556*4d7e907cSAndroid Build Coastguard Worker if (mCallback != NULL) {
557*4d7e907cSAndroid Build Coastguard Worker ScopedAStatus ret = mCallback->notifyQueryPortStatus(
558*4d7e907cSAndroid Build Coastguard Worker "all", Status::SUCCESS, in_transactionId);
559*4d7e907cSAndroid Build Coastguard Worker if (!ret.isOk())
560*4d7e907cSAndroid Build Coastguard Worker ALOGE("notifyQueryPortStatus error %s", ret.getDescription().c_str());
561*4d7e907cSAndroid Build Coastguard Worker } else {
562*4d7e907cSAndroid Build Coastguard Worker ALOGE("Not notifying the userspace. Callback is not set");
563*4d7e907cSAndroid Build Coastguard Worker }
564*4d7e907cSAndroid Build Coastguard Worker pthread_mutex_unlock(&mLock);
565*4d7e907cSAndroid Build Coastguard Worker
566*4d7e907cSAndroid Build Coastguard Worker return ScopedAStatus::ok();
567*4d7e907cSAndroid Build Coastguard Worker }
568*4d7e907cSAndroid Build Coastguard Worker
enableContaminantPresenceDetection(const string & in_portName,bool,int64_t in_transactionId)569*4d7e907cSAndroid Build Coastguard Worker ScopedAStatus Usb::enableContaminantPresenceDetection(const string& in_portName,
570*4d7e907cSAndroid Build Coastguard Worker bool /*in_enable*/, int64_t in_transactionId) {
571*4d7e907cSAndroid Build Coastguard Worker std::vector<PortStatus> currentPortStatus;
572*4d7e907cSAndroid Build Coastguard Worker
573*4d7e907cSAndroid Build Coastguard Worker pthread_mutex_lock(&mLock);
574*4d7e907cSAndroid Build Coastguard Worker if (mCallback != NULL) {
575*4d7e907cSAndroid Build Coastguard Worker ScopedAStatus ret = mCallback->notifyContaminantEnabledStatus(
576*4d7e907cSAndroid Build Coastguard Worker in_portName, false, Status::ERROR, in_transactionId);
577*4d7e907cSAndroid Build Coastguard Worker if (!ret.isOk())
578*4d7e907cSAndroid Build Coastguard Worker ALOGE("enableContaminantPresenceDetection error %s", ret.getDescription().c_str());
579*4d7e907cSAndroid Build Coastguard Worker } else {
580*4d7e907cSAndroid Build Coastguard Worker ALOGE("Not notifying the userspace. Callback is not set");
581*4d7e907cSAndroid Build Coastguard Worker }
582*4d7e907cSAndroid Build Coastguard Worker pthread_mutex_unlock(&mLock);
583*4d7e907cSAndroid Build Coastguard Worker
584*4d7e907cSAndroid Build Coastguard Worker queryVersionHelper(this, ¤tPortStatus);
585*4d7e907cSAndroid Build Coastguard Worker return ScopedAStatus::ok();
586*4d7e907cSAndroid Build Coastguard Worker }
587*4d7e907cSAndroid Build Coastguard Worker
588*4d7e907cSAndroid Build Coastguard Worker
589*4d7e907cSAndroid Build Coastguard Worker struct data {
590*4d7e907cSAndroid Build Coastguard Worker int uevent_fd;
591*4d7e907cSAndroid Build Coastguard Worker ::aidl::android::hardware::usb::Usb *usb;
592*4d7e907cSAndroid Build Coastguard Worker };
593*4d7e907cSAndroid Build Coastguard Worker
uevent_event(uint32_t,struct data * payload)594*4d7e907cSAndroid Build Coastguard Worker static void uevent_event(uint32_t /*epevents*/, struct data *payload) {
595*4d7e907cSAndroid Build Coastguard Worker char msg[UEVENT_MSG_LEN + 2];
596*4d7e907cSAndroid Build Coastguard Worker char *cp;
597*4d7e907cSAndroid Build Coastguard Worker int n;
598*4d7e907cSAndroid Build Coastguard Worker
599*4d7e907cSAndroid Build Coastguard Worker n = uevent_kernel_multicast_recv(payload->uevent_fd, msg, UEVENT_MSG_LEN);
600*4d7e907cSAndroid Build Coastguard Worker if (n <= 0)
601*4d7e907cSAndroid Build Coastguard Worker return;
602*4d7e907cSAndroid Build Coastguard Worker if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
603*4d7e907cSAndroid Build Coastguard Worker return;
604*4d7e907cSAndroid Build Coastguard Worker
605*4d7e907cSAndroid Build Coastguard Worker msg[n] = '\0';
606*4d7e907cSAndroid Build Coastguard Worker msg[n + 1] = '\0';
607*4d7e907cSAndroid Build Coastguard Worker cp = msg;
608*4d7e907cSAndroid Build Coastguard Worker
609*4d7e907cSAndroid Build Coastguard Worker while (*cp) {
610*4d7e907cSAndroid Build Coastguard Worker if (std::regex_match(cp, std::regex("(add)(.*)(-partner)"))) {
611*4d7e907cSAndroid Build Coastguard Worker ALOGI("partner added");
612*4d7e907cSAndroid Build Coastguard Worker pthread_mutex_lock(&payload->usb->mPartnerLock);
613*4d7e907cSAndroid Build Coastguard Worker payload->usb->mPartnerUp = true;
614*4d7e907cSAndroid Build Coastguard Worker pthread_cond_signal(&payload->usb->mPartnerCV);
615*4d7e907cSAndroid Build Coastguard Worker pthread_mutex_unlock(&payload->usb->mPartnerLock);
616*4d7e907cSAndroid Build Coastguard Worker } else if (!strncmp(cp, "DEVTYPE=typec_", strlen("DEVTYPE=typec_"))) {
617*4d7e907cSAndroid Build Coastguard Worker std::vector<PortStatus> currentPortStatus;
618*4d7e907cSAndroid Build Coastguard Worker queryVersionHelper(payload->usb, ¤tPortStatus);
619*4d7e907cSAndroid Build Coastguard Worker
620*4d7e907cSAndroid Build Coastguard Worker // Role switch is not in progress and port is in disconnected state
621*4d7e907cSAndroid Build Coastguard Worker if (!pthread_mutex_trylock(&payload->usb->mRoleSwitchLock)) {
622*4d7e907cSAndroid Build Coastguard Worker for (unsigned long i = 0; i < currentPortStatus.size(); i++) {
623*4d7e907cSAndroid Build Coastguard Worker DIR *dp =
624*4d7e907cSAndroid Build Coastguard Worker opendir(string(kTypecPath +
625*4d7e907cSAndroid Build Coastguard Worker string(currentPortStatus[i].portName.c_str()) +
626*4d7e907cSAndroid Build Coastguard Worker "-partner").c_str());
627*4d7e907cSAndroid Build Coastguard Worker if (dp == NULL) {
628*4d7e907cSAndroid Build Coastguard Worker switchToDrp(currentPortStatus[i].portName);
629*4d7e907cSAndroid Build Coastguard Worker } else {
630*4d7e907cSAndroid Build Coastguard Worker closedir(dp);
631*4d7e907cSAndroid Build Coastguard Worker }
632*4d7e907cSAndroid Build Coastguard Worker }
633*4d7e907cSAndroid Build Coastguard Worker pthread_mutex_unlock(&payload->usb->mRoleSwitchLock);
634*4d7e907cSAndroid Build Coastguard Worker }
635*4d7e907cSAndroid Build Coastguard Worker break;
636*4d7e907cSAndroid Build Coastguard Worker } /* advance to after the next \0 */
637*4d7e907cSAndroid Build Coastguard Worker while (*cp++) {
638*4d7e907cSAndroid Build Coastguard Worker }
639*4d7e907cSAndroid Build Coastguard Worker }
640*4d7e907cSAndroid Build Coastguard Worker }
641*4d7e907cSAndroid Build Coastguard Worker
work(void * param)642*4d7e907cSAndroid Build Coastguard Worker void *work(void *param) {
643*4d7e907cSAndroid Build Coastguard Worker int epoll_fd, uevent_fd;
644*4d7e907cSAndroid Build Coastguard Worker struct epoll_event ev;
645*4d7e907cSAndroid Build Coastguard Worker int nevents = 0;
646*4d7e907cSAndroid Build Coastguard Worker struct data payload;
647*4d7e907cSAndroid Build Coastguard Worker
648*4d7e907cSAndroid Build Coastguard Worker uevent_fd = uevent_open_socket(UEVENT_MAX_EVENTS * UEVENT_MSG_LEN, true);
649*4d7e907cSAndroid Build Coastguard Worker
650*4d7e907cSAndroid Build Coastguard Worker if (uevent_fd < 0) {
651*4d7e907cSAndroid Build Coastguard Worker ALOGE("uevent_init: uevent_open_socket failed\n");
652*4d7e907cSAndroid Build Coastguard Worker return NULL;
653*4d7e907cSAndroid Build Coastguard Worker }
654*4d7e907cSAndroid Build Coastguard Worker
655*4d7e907cSAndroid Build Coastguard Worker payload.uevent_fd = uevent_fd;
656*4d7e907cSAndroid Build Coastguard Worker payload.usb = (::aidl::android::hardware::usb::Usb *)param;
657*4d7e907cSAndroid Build Coastguard Worker
658*4d7e907cSAndroid Build Coastguard Worker fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
659*4d7e907cSAndroid Build Coastguard Worker
660*4d7e907cSAndroid Build Coastguard Worker ev.events = EPOLLIN;
661*4d7e907cSAndroid Build Coastguard Worker ev.data.ptr = (void *)uevent_event;
662*4d7e907cSAndroid Build Coastguard Worker
663*4d7e907cSAndroid Build Coastguard Worker epoll_fd = epoll_create(UEVENT_MAX_EVENTS);
664*4d7e907cSAndroid Build Coastguard Worker if (epoll_fd == -1) {
665*4d7e907cSAndroid Build Coastguard Worker ALOGE("epoll_create failed; errno=%d", errno);
666*4d7e907cSAndroid Build Coastguard Worker goto error;
667*4d7e907cSAndroid Build Coastguard Worker }
668*4d7e907cSAndroid Build Coastguard Worker
669*4d7e907cSAndroid Build Coastguard Worker if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1) {
670*4d7e907cSAndroid Build Coastguard Worker ALOGE("epoll_ctl failed; errno=%d", errno);
671*4d7e907cSAndroid Build Coastguard Worker goto error;
672*4d7e907cSAndroid Build Coastguard Worker }
673*4d7e907cSAndroid Build Coastguard Worker
674*4d7e907cSAndroid Build Coastguard Worker while (!destroyThread) {
675*4d7e907cSAndroid Build Coastguard Worker struct epoll_event events[UEVENT_MAX_EVENTS];
676*4d7e907cSAndroid Build Coastguard Worker
677*4d7e907cSAndroid Build Coastguard Worker nevents = epoll_wait(epoll_fd, events, UEVENT_MAX_EVENTS, -1);
678*4d7e907cSAndroid Build Coastguard Worker if (nevents == -1) {
679*4d7e907cSAndroid Build Coastguard Worker if (errno == EINTR)
680*4d7e907cSAndroid Build Coastguard Worker continue;
681*4d7e907cSAndroid Build Coastguard Worker ALOGE("usb epoll_wait failed; errno=%d", errno);
682*4d7e907cSAndroid Build Coastguard Worker break;
683*4d7e907cSAndroid Build Coastguard Worker }
684*4d7e907cSAndroid Build Coastguard Worker
685*4d7e907cSAndroid Build Coastguard Worker for (int n = 0; n < nevents; ++n) {
686*4d7e907cSAndroid Build Coastguard Worker if (events[n].data.ptr)
687*4d7e907cSAndroid Build Coastguard Worker (*(void (*)(int, struct data *payload))events[n].data.ptr)(events[n].events,
688*4d7e907cSAndroid Build Coastguard Worker &payload);
689*4d7e907cSAndroid Build Coastguard Worker }
690*4d7e907cSAndroid Build Coastguard Worker }
691*4d7e907cSAndroid Build Coastguard Worker
692*4d7e907cSAndroid Build Coastguard Worker ALOGI("exiting worker thread");
693*4d7e907cSAndroid Build Coastguard Worker error:
694*4d7e907cSAndroid Build Coastguard Worker close(uevent_fd);
695*4d7e907cSAndroid Build Coastguard Worker
696*4d7e907cSAndroid Build Coastguard Worker if (epoll_fd >= 0)
697*4d7e907cSAndroid Build Coastguard Worker close(epoll_fd);
698*4d7e907cSAndroid Build Coastguard Worker
699*4d7e907cSAndroid Build Coastguard Worker return NULL;
700*4d7e907cSAndroid Build Coastguard Worker }
701*4d7e907cSAndroid Build Coastguard Worker
sighandler(int sig)702*4d7e907cSAndroid Build Coastguard Worker void sighandler(int sig) {
703*4d7e907cSAndroid Build Coastguard Worker if (sig == SIGUSR1) {
704*4d7e907cSAndroid Build Coastguard Worker destroyThread = true;
705*4d7e907cSAndroid Build Coastguard Worker ALOGI("destroy set");
706*4d7e907cSAndroid Build Coastguard Worker return;
707*4d7e907cSAndroid Build Coastguard Worker }
708*4d7e907cSAndroid Build Coastguard Worker signal(SIGUSR1, sighandler);
709*4d7e907cSAndroid Build Coastguard Worker }
710*4d7e907cSAndroid Build Coastguard Worker
setCallback(const shared_ptr<IUsbCallback> & in_callback)711*4d7e907cSAndroid Build Coastguard Worker ScopedAStatus Usb::setCallback(
712*4d7e907cSAndroid Build Coastguard Worker const shared_ptr<IUsbCallback>& in_callback) {
713*4d7e907cSAndroid Build Coastguard Worker
714*4d7e907cSAndroid Build Coastguard Worker pthread_mutex_lock(&mLock);
715*4d7e907cSAndroid Build Coastguard Worker if ((mCallback == NULL && in_callback == NULL) ||
716*4d7e907cSAndroid Build Coastguard Worker (mCallback != NULL && in_callback != NULL)) {
717*4d7e907cSAndroid Build Coastguard Worker mCallback = in_callback;
718*4d7e907cSAndroid Build Coastguard Worker pthread_mutex_unlock(&mLock);
719*4d7e907cSAndroid Build Coastguard Worker return ScopedAStatus::ok();
720*4d7e907cSAndroid Build Coastguard Worker }
721*4d7e907cSAndroid Build Coastguard Worker
722*4d7e907cSAndroid Build Coastguard Worker mCallback = in_callback;
723*4d7e907cSAndroid Build Coastguard Worker ALOGI("registering callback");
724*4d7e907cSAndroid Build Coastguard Worker
725*4d7e907cSAndroid Build Coastguard Worker if (mCallback == NULL) {
726*4d7e907cSAndroid Build Coastguard Worker if (!pthread_kill(mPoll, SIGUSR1)) {
727*4d7e907cSAndroid Build Coastguard Worker pthread_join(mPoll, NULL);
728*4d7e907cSAndroid Build Coastguard Worker ALOGI("pthread destroyed");
729*4d7e907cSAndroid Build Coastguard Worker }
730*4d7e907cSAndroid Build Coastguard Worker pthread_mutex_unlock(&mLock);
731*4d7e907cSAndroid Build Coastguard Worker return ScopedAStatus::ok();
732*4d7e907cSAndroid Build Coastguard Worker }
733*4d7e907cSAndroid Build Coastguard Worker
734*4d7e907cSAndroid Build Coastguard Worker destroyThread = false;
735*4d7e907cSAndroid Build Coastguard Worker signal(SIGUSR1, sighandler);
736*4d7e907cSAndroid Build Coastguard Worker
737*4d7e907cSAndroid Build Coastguard Worker /*
738*4d7e907cSAndroid Build Coastguard Worker * Create a background thread if the old callback value is NULL
739*4d7e907cSAndroid Build Coastguard Worker * and being updated with a new value.
740*4d7e907cSAndroid Build Coastguard Worker */
741*4d7e907cSAndroid Build Coastguard Worker if (pthread_create(&mPoll, NULL, work, this)) {
742*4d7e907cSAndroid Build Coastguard Worker ALOGE("pthread creation failed %d", errno);
743*4d7e907cSAndroid Build Coastguard Worker mCallback = NULL;
744*4d7e907cSAndroid Build Coastguard Worker }
745*4d7e907cSAndroid Build Coastguard Worker
746*4d7e907cSAndroid Build Coastguard Worker pthread_mutex_unlock(&mLock);
747*4d7e907cSAndroid Build Coastguard Worker return ScopedAStatus::ok();
748*4d7e907cSAndroid Build Coastguard Worker }
749*4d7e907cSAndroid Build Coastguard Worker
750*4d7e907cSAndroid Build Coastguard Worker } // namespace usb
751*4d7e907cSAndroid Build Coastguard Worker } // namespace hardware
752*4d7e907cSAndroid Build Coastguard Worker } // namespace android
753*4d7e907cSAndroid Build Coastguard Worker } // aidl
754