1 /*
2 * Copyright (C) 2021 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.aidl-service"
18
19 #include <android-base/logging.h>
20 #include <android-base/parseint.h>
21 #include <android-base/properties.h>
22 #include <android-base/strings.h>
23 #include <assert.h>
24 #include <cstring>
25 #include <dirent.h>
26 #include <pthread.h>
27 #include <stdio.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 #include <regex>
31 #include <thread>
32 #include <unordered_map>
33
34 #include <cutils/uevent.h>
35 #include <sys/epoll.h>
36 #include <sys/eventfd.h>
37 #include <sys/timerfd.h>
38 #include <utils/Errors.h>
39 #include <utils/StrongPointer.h>
40
41 #include "Usb.h"
42
43 #include <aidl/android/frameworks/stats/IStats.h>
44 #include <android_hardware_usb_flags.h>
45 #include <pixelusb/UsbGadgetAidlCommon.h>
46 #include <pixelstats/StatsHelper.h>
47
48 namespace usb_flags = android::hardware::usb::flags;
49
50 using aidl::android::frameworks::stats::IStats;
51 using android::base::GetProperty;
52 using android::base::Join;
53 using android::base::ParseUint;
54 using android::base::Tokenize;
55 using android::base::Trim;
56 using android::hardware::google::pixel::getStatsService;
57 using android::hardware::google::pixel::PixelAtoms::VendorUsbPortOverheat;
58 using android::hardware::google::pixel::reportUsbPortOverheat;
59
60 namespace aidl {
61 namespace android {
62 namespace hardware {
63 namespace usb {
64 // Set by the signal handler to destroy the thread
65 volatile bool destroyThread;
66 volatile bool destroyDisplayPortThread;
67
68 string enabledPath;
69 constexpr char kHsi2cPath[] = "/sys/devices/platform/10cb0000.hsi2c";
70 constexpr char kI2CPath[] = "/sys/devices/platform/10cb0000.hsi2c/i2c-";
71 constexpr char kContaminantDetectionPath[] = "-0025/contaminant_detection";
72 constexpr char kDisplayPortDrmPath[] = "/sys/devices/platform/110f0000.drmdp/drm-displayport/";
73 constexpr char kDisplayPortUsbPath[] = "/sys/class/typec/port0-partner/";
74 constexpr char kComplianceWarningsPath[] = "device/non_compliant_reasons";
75 constexpr char kComplianceWarningBC12[] = "bc12";
76 constexpr char kComplianceWarningDebugAccessory[] = "debug-accessory";
77 constexpr char kComplianceWarningMissingRp[] = "missing_rp";
78 constexpr char kComplianceWarningOther[] = "other";
79 constexpr char kComplianceWarningInputPowerLimited[] = "input_power_limited";
80 constexpr char kStatusPath[] = "-0025/contaminant_detection_status";
81 constexpr char kSinkLimitEnable[] = "-0025/usb_limit_sink_enable";
82 constexpr char kSourceLimitEnable[] = "-0025/usb_limit_source_enable";
83 constexpr char kSinkLimitCurrent[] = "-0025/usb_limit_sink_current";
84 constexpr char kTypecPath[] = "/sys/class/typec";
85 constexpr char kDisableContatminantDetection[] = "vendor.usb.contaminantdisable";
86 constexpr char kOverheatStatsPath[] = "/sys/devices/platform/google,usbc_port_cooling_dev/";
87 constexpr char kOverheatStatsDev[] = "DRIVER=google,usbc_port_cooling_dev";
88 constexpr char kThermalZoneForTrip[] = "VIRTUAL-USB-THROTTLING";
89 constexpr char kThermalZoneForTempReadPrimary[] = "usb_pwr_therm2";
90 constexpr char kThermalZoneForTempReadSecondary1[] = "usb_pwr_therm";
91 constexpr char kThermalZoneForTempReadSecondary2[] = "qi_therm";
92 constexpr char kPogoUsbActive[] = "/sys/devices/platform/google,pogo/pogo_usb_active";
93 constexpr char kPogoEnableUsb[] = "/sys/devices/platform/google,pogo/enable_usb";
94 constexpr char kPowerSupplyUsbType[] = "/sys/class/power_supply/usb/usb_type";
95 constexpr char kIrqHpdCounPath[] = "-0025/irq_hpd_count";
96 constexpr char kUdcUeventRegex[] =
97 "/devices/platform/11210000.usb/11210000.dwc3/udc/11210000.dwc3";
98 constexpr char kUdcStatePath[] =
99 "/sys/devices/platform/11210000.usb/11210000.dwc3/udc/11210000.dwc3/state";
100 constexpr char kHost1UeventRegex[] =
101 "/devices/platform/11210000.usb/11210000.dwc3/xhci-hcd-exynos.[0-9].auto/usb1/1-0:1.0";
102 constexpr char kHost1StatePath[] = "/sys/bus/usb/devices/usb1/1-0:1.0/usb1-port1/state";
103 constexpr char kHost2UeventRegex[] =
104 "/devices/platform/11210000.usb/11210000.dwc3/xhci-hcd-exynos.[0-9].auto/usb2/2-0:1.0";
105 constexpr char kHost2StatePath[] = "/sys/bus/usb/devices/usb2/2-0:1.0/usb2-port1/state";
106 constexpr char kDataRolePath[] = "/sys/devices/platform/11210000.usb/new_data_role";
107 constexpr int kSamplingIntervalSec = 5;
108 void queryVersionHelper(android::hardware::usb::Usb *usb,
109 std::vector<PortStatus> *currentPortStatus);
110 AltModeData::DisplayPortAltModeData constructAltModeData(string hpd, string pin_assignment,
111 string link_status, string vdo);
112
enableUsbData(const string & in_portName,bool in_enable,int64_t in_transactionId)113 ScopedAStatus Usb::enableUsbData(const string& in_portName, bool in_enable,
114 int64_t in_transactionId) {
115 bool result = true;
116 std::vector<PortStatus> currentPortStatus;
117 string displayPortPartnerPath;
118
119 ALOGI("Userspace turn %s USB data signaling. opID:%ld", in_enable ? "on" : "off",
120 in_transactionId);
121
122 if (in_enable) {
123 if (!mUsbDataEnabled) {
124 if (!WriteStringToFile("1", USB_DATA_PATH)) {
125 ALOGE("Not able to turn on usb connection notification");
126 result = false;
127 }
128
129 if (!WriteStringToFile(kGadgetName, PULLUP_PATH)) {
130 ALOGE("Gadget cannot be pulled up");
131 result = false;
132 }
133
134 if (!WriteStringToFile("1", DISPLAYPORT_ACTIVE_PATH)) {
135 ALOGE("Failed to enable DisplayPort Alt Mode on port");
136 } else {
137 ALOGI("Successfully enabled DisplayPort Alt Mode on port");
138 }
139
140 if (getDisplayPortUsbPathHelper(&displayPortPartnerPath) == Status::SUCCESS) {
141 size_t pos = displayPortPartnerPath.find("/displayport");
142 if (pos != string::npos) {
143 displayPortPartnerPath = displayPortPartnerPath.substr(0, pos) + "/mode1/active";
144 }
145 if (!WriteStringToFile("1", displayPortPartnerPath)) {
146 ALOGE("Failed to enable DisplayPort Alt Mode on partner at %s",
147 displayPortPartnerPath.c_str());
148 } else {
149 ALOGI("Successfully enabled DisplayPort Alt Mode on partner at %s",
150 displayPortPartnerPath.c_str());
151 setupDisplayPortPoll();
152 }
153 }
154 }
155 } else {
156 if (!WriteStringToFile("1", ID_PATH)) {
157 ALOGE("Not able to turn off host mode");
158 result = false;
159 }
160
161 if (!WriteStringToFile("0", VBUS_PATH)) {
162 ALOGE("Not able to set Vbus state");
163 result = false;
164 }
165
166 if (!WriteStringToFile("0", USB_DATA_PATH)) {
167 ALOGE("Not able to turn off usb connection notification");
168 result = false;
169 }
170
171 if (!WriteStringToFile("none", PULLUP_PATH)) {
172 ALOGE("Gadget cannot be pulled down");
173 result = false;
174 }
175
176 if (getDisplayPortUsbPathHelper(&displayPortPartnerPath) == Status::SUCCESS) {
177 size_t pos = displayPortPartnerPath.find("/displayport");
178 if (pos != string::npos) {
179 displayPortPartnerPath = displayPortPartnerPath.substr(0, pos) + "/mode1/active";
180 }
181 if (!WriteStringToFile("0", displayPortPartnerPath)) {
182 ALOGE("Failed to disable DisplayPort Alt Mode on partner at %s",
183 displayPortPartnerPath.c_str());
184 } else {
185 ALOGI("Successfully disabled DisplayPort Alt Mode on partner at %s",
186 displayPortPartnerPath.c_str());
187 shutdownDisplayPortPoll(true);
188 }
189 }
190
191 if (!WriteStringToFile("0", DISPLAYPORT_ACTIVE_PATH)) {
192 ALOGE("Failed to disable DisplayPort Alt Mode on port");
193 } else {
194 ALOGI("Successfully disabled DisplayPort Alt Mode on port");
195 }
196 }
197
198 if (result) {
199 mUsbDataEnabled = in_enable;
200 }
201 pthread_mutex_lock(&mLock);
202 if (mCallback != NULL) {
203 ScopedAStatus ret = mCallback->notifyEnableUsbDataStatus(
204 in_portName, in_enable, result ? Status::SUCCESS : Status::ERROR, in_transactionId);
205 if (!ret.isOk())
206 ALOGE("notifyEnableUsbDataStatus error %s", ret.getDescription().c_str());
207 } else {
208 ALOGE("Not notifying the userspace. Callback is not set");
209 }
210 pthread_mutex_unlock(&mLock);
211 queryVersionHelper(this, ¤tPortStatus);
212
213 return ScopedAStatus::ok();
214 }
215
enableUsbDataWhileDocked(const string & in_portName,int64_t in_transactionId)216 ScopedAStatus Usb::enableUsbDataWhileDocked(const string& in_portName,
217 int64_t in_transactionId) {
218 bool success = true;
219 bool notSupported = true;
220 std::vector<PortStatus> currentPortStatus;
221
222 ALOGI("Userspace enableUsbDataWhileDocked opID:%ld", in_transactionId);
223
224 int flags = O_RDONLY;
225 ::android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(kPogoEnableUsb, flags)));
226 if (fd != -1) {
227 notSupported = false;
228 success = WriteStringToFile("1", kPogoEnableUsb);
229 if (!success) {
230 ALOGE("Write to enable_usb failed");
231 }
232 }
233
234 pthread_mutex_lock(&mLock);
235 if (mCallback != NULL) {
236 ScopedAStatus ret = mCallback->notifyEnableUsbDataWhileDockedStatus(
237 in_portName, notSupported ? Status::NOT_SUPPORTED :
238 success ? Status::SUCCESS : Status::ERROR, in_transactionId);
239 if (!ret.isOk())
240 ALOGE("notifyEnableUsbDataStatus error %s", ret.getDescription().c_str());
241 } else {
242 ALOGE("Not notifying the userspace. Callback is not set");
243 }
244 pthread_mutex_unlock(&mLock);
245 queryVersionHelper(this, ¤tPortStatus);
246
247 return ScopedAStatus::ok();
248 }
249
resetUsbPort(const std::string & in_portName,int64_t in_transactionId)250 ScopedAStatus Usb::resetUsbPort(const std::string& in_portName, int64_t in_transactionId) {
251 bool result = true;
252 std::vector<PortStatus> currentPortStatus;
253
254 ALOGI("Userspace reset USB Port. opID:%ld", in_transactionId);
255
256 if (!WriteStringToFile("none", PULLUP_PATH)) {
257 ALOGI("Gadget cannot be pulled down");
258 result = false;
259 }
260
261 pthread_mutex_lock(&mLock);
262 if (mCallback != NULL) {
263 ::ndk::ScopedAStatus ret = mCallback->notifyResetUsbPortStatus(
264 in_portName, result ? Status::SUCCESS : Status::ERROR, in_transactionId);
265 if (!ret.isOk())
266 ALOGE("notifyTransactionStatus error %s", ret.getDescription().c_str());
267 } else {
268 ALOGE("Not notifying the userspace. Callback is not set");
269 }
270 pthread_mutex_unlock(&mLock);
271
272 return ::ndk::ScopedAStatus::ok();
273 }
274
getI2cBusHelper(string * name)275 Status getI2cBusHelper(string *name) {
276 DIR *dp;
277
278 dp = opendir(kHsi2cPath);
279 if (dp != NULL) {
280 struct dirent *ep;
281
282 while ((ep = readdir(dp))) {
283 if (ep->d_type == DT_DIR) {
284 if (string::npos != string(ep->d_name).find("i2c-")) {
285 std::strtok(ep->d_name, "-");
286 *name = std::strtok(NULL, "-");
287 }
288 }
289 }
290 closedir(dp);
291 return Status::SUCCESS;
292 }
293
294 ALOGE("Failed to open %s", kHsi2cPath);
295 return Status::ERROR;
296 }
297
queryMoistureDetectionStatus(std::vector<PortStatus> * currentPortStatus)298 Status queryMoistureDetectionStatus(std::vector<PortStatus> *currentPortStatus) {
299 string enabled, status, path, DetectedPath;
300
301 (*currentPortStatus)[0].supportedContaminantProtectionModes
302 .push_back(ContaminantProtectionMode::FORCE_DISABLE);
303 (*currentPortStatus)[0].contaminantProtectionStatus = ContaminantProtectionStatus::NONE;
304 (*currentPortStatus)[0].contaminantDetectionStatus = ContaminantDetectionStatus::DISABLED;
305 (*currentPortStatus)[0].supportsEnableContaminantPresenceDetection = true;
306 (*currentPortStatus)[0].supportsEnableContaminantPresenceProtection = false;
307
308 getI2cBusHelper(&path);
309 enabledPath = kI2CPath + path + "/" + path + kContaminantDetectionPath;
310 if (!ReadFileToString(enabledPath, &enabled)) {
311 ALOGE("Failed to open moisture_detection_enabled");
312 return Status::ERROR;
313 }
314
315 enabled = Trim(enabled);
316 if (enabled == "1") {
317 DetectedPath = kI2CPath + path + "/" + path + kStatusPath;
318 if (!ReadFileToString(DetectedPath, &status)) {
319 ALOGE("Failed to open moisture_detected");
320 return Status::ERROR;
321 }
322 status = Trim(status);
323 if (status == "1") {
324 (*currentPortStatus)[0].contaminantDetectionStatus =
325 ContaminantDetectionStatus::DETECTED;
326 (*currentPortStatus)[0].contaminantProtectionStatus =
327 ContaminantProtectionStatus::FORCE_DISABLE;
328 } else {
329 (*currentPortStatus)[0].contaminantDetectionStatus =
330 ContaminantDetectionStatus::NOT_DETECTED;
331 }
332 }
333
334 ALOGI("ContaminantDetectionStatus:%d ContaminantProtectionStatus:%d",
335 (*currentPortStatus)[0].contaminantDetectionStatus,
336 (*currentPortStatus)[0].contaminantProtectionStatus);
337
338 return Status::SUCCESS;
339 }
340
queryNonCompliantChargerStatus(std::vector<PortStatus> * currentPortStatus)341 Status queryNonCompliantChargerStatus(std::vector<PortStatus> *currentPortStatus) {
342 string reasons, path;
343
344 for (int i = 0; i < currentPortStatus->size(); i++) {
345 (*currentPortStatus)[i].supportsComplianceWarnings = true;
346 path = string(kTypecPath) + "/" + (*currentPortStatus)[i].portName + "/" +
347 string(kComplianceWarningsPath);
348 if (ReadFileToString(path.c_str(), &reasons)) {
349 std::vector<string> reasonsList = Tokenize(reasons.c_str(), "[], \n\0");
350 for (string reason : reasonsList) {
351 if (!strncmp(reason.c_str(), kComplianceWarningDebugAccessory,
352 strlen(kComplianceWarningDebugAccessory))) {
353 (*currentPortStatus)[i].complianceWarnings.push_back(ComplianceWarning::DEBUG_ACCESSORY);
354 continue;
355 }
356 if (!strncmp(reason.c_str(), kComplianceWarningBC12,
357 strlen(kComplianceWarningBC12))) {
358 (*currentPortStatus)[i].complianceWarnings.push_back(ComplianceWarning::BC_1_2);
359 continue;
360 }
361 if (!strncmp(reason.c_str(), kComplianceWarningMissingRp,
362 strlen(kComplianceWarningMissingRp))) {
363 (*currentPortStatus)[i].complianceWarnings.push_back(ComplianceWarning::MISSING_RP);
364 continue;
365 }
366 if (!strncmp(reason.c_str(), kComplianceWarningOther,
367 strlen(kComplianceWarningOther)) ||
368 !strncmp(reason.c_str(), kComplianceWarningInputPowerLimited,
369 strlen(kComplianceWarningInputPowerLimited))) {
370 if (usb_flags::enable_usb_data_compliance_warning() &&
371 usb_flags::enable_input_power_limited_warning()) {
372 ALOGI("Report through INPUT_POWER_LIMITED warning");
373 (*currentPortStatus)[i].complianceWarnings.push_back(
374 ComplianceWarning::INPUT_POWER_LIMITED);
375 continue;
376 } else {
377 (*currentPortStatus)[i].complianceWarnings.push_back(
378 ComplianceWarning::OTHER);
379 continue;
380 }
381 }
382 }
383 if ((*currentPortStatus)[i].complianceWarnings.size() > 0 &&
384 (*currentPortStatus)[i].currentPowerRole == PortPowerRole::NONE) {
385 (*currentPortStatus)[i].currentMode = PortMode::UFP;
386 (*currentPortStatus)[i].currentPowerRole = PortPowerRole::SINK;
387 (*currentPortStatus)[i].currentDataRole = PortDataRole::NONE;
388 (*currentPortStatus)[i].powerBrickStatus = PowerBrickStatus::CONNECTED;
389 }
390 }
391 }
392 return Status::SUCCESS;
393 }
394
appendRoleNodeHelper(const string & portName,PortRole::Tag tag)395 string appendRoleNodeHelper(const string &portName, PortRole::Tag tag) {
396 string node("/sys/class/typec/" + portName);
397
398 switch (tag) {
399 case PortRole::dataRole:
400 return node + "/data_role";
401 case PortRole::powerRole:
402 return node + "/power_role";
403 case PortRole::mode:
404 return node + "/port_type";
405 default:
406 return "";
407 }
408 }
409
convertRoletoString(PortRole role)410 string convertRoletoString(PortRole role) {
411 if (role.getTag() == PortRole::powerRole) {
412 if (role.get<PortRole::powerRole>() == PortPowerRole::SOURCE)
413 return "source";
414 else if (role.get<PortRole::powerRole>() == PortPowerRole::SINK)
415 return "sink";
416 } else if (role.getTag() == PortRole::dataRole) {
417 if (role.get<PortRole::dataRole>() == PortDataRole::HOST)
418 return "host";
419 if (role.get<PortRole::dataRole>() == PortDataRole::DEVICE)
420 return "device";
421 } else if (role.getTag() == PortRole::mode) {
422 if (role.get<PortRole::mode>() == PortMode::UFP)
423 return "sink";
424 if (role.get<PortRole::mode>() == PortMode::DFP)
425 return "source";
426 }
427 return "none";
428 }
429
extractRole(string * roleName)430 void extractRole(string *roleName) {
431 std::size_t first, last;
432
433 first = roleName->find("[");
434 last = roleName->find("]");
435
436 if (first != string::npos && last != string::npos) {
437 *roleName = roleName->substr(first + 1, last - first - 1);
438 }
439 }
440
switchToDrp(const string & portName)441 void switchToDrp(const string &portName) {
442 string filename = appendRoleNodeHelper(string(portName.c_str()), PortRole::mode);
443 FILE *fp;
444
445 if (filename != "") {
446 fp = fopen(filename.c_str(), "w");
447 if (fp != NULL) {
448 int ret = fputs("dual", fp);
449 fclose(fp);
450 if (ret == EOF)
451 ALOGE("Fatal: Error while switching back to drp");
452 } else {
453 ALOGE("Fatal: Cannot open file to switch back to drp");
454 }
455 } else {
456 ALOGE("Fatal: invalid node type");
457 }
458 }
459
switchMode(const string & portName,const PortRole & in_role,struct Usb * usb)460 bool switchMode(const string &portName, const PortRole &in_role, struct Usb *usb) {
461 string filename = appendRoleNodeHelper(string(portName.c_str()), in_role.getTag());
462 string written;
463 FILE *fp;
464 bool roleSwitch = false;
465
466 if (filename == "") {
467 ALOGE("Fatal: invalid node type");
468 return false;
469 }
470
471 fp = fopen(filename.c_str(), "w");
472 if (fp != NULL) {
473 // Hold the lock here to prevent loosing connected signals
474 // as once the file is written the partner added signal
475 // can arrive anytime.
476 pthread_mutex_lock(&usb->mPartnerLock);
477 usb->mPartnerUp = false;
478 int ret = fputs(convertRoletoString(in_role).c_str(), fp);
479 fclose(fp);
480
481 if (ret != EOF) {
482 struct timespec to;
483 struct timespec now;
484
485 wait_again:
486 clock_gettime(CLOCK_MONOTONIC, &now);
487 to.tv_sec = now.tv_sec + PORT_TYPE_TIMEOUT;
488 to.tv_nsec = now.tv_nsec;
489
490 int err = pthread_cond_timedwait(&usb->mPartnerCV, &usb->mPartnerLock, &to);
491 // There are no uevent signals which implies role swap timed out.
492 if (err == ETIMEDOUT) {
493 ALOGI("uevents wait timedout");
494 // Validity check.
495 } else if (!usb->mPartnerUp) {
496 goto wait_again;
497 // Role switch succeeded since usb->mPartnerUp is true.
498 } else {
499 roleSwitch = true;
500 }
501 } else {
502 ALOGI("Role switch failed while wrting to file");
503 }
504 pthread_mutex_unlock(&usb->mPartnerLock);
505 }
506
507 if (!roleSwitch)
508 switchToDrp(string(portName.c_str()));
509
510 return roleSwitch;
511 }
512
updatePortStatus(android::hardware::usb::Usb * usb)513 void updatePortStatus(android::hardware::usb::Usb *usb) {
514 std::vector<PortStatus> currentPortStatus;
515
516 queryVersionHelper(usb, ¤tPortStatus);
517 }
518
Usb()519 Usb::Usb()
520 : mLock(PTHREAD_MUTEX_INITIALIZER),
521 mRoleSwitchLock(PTHREAD_MUTEX_INITIALIZER),
522 mPartnerLock(PTHREAD_MUTEX_INITIALIZER),
523 mPartnerUp(false),
524 mUsbDataSessionMonitor(kUdcUeventRegex, kUdcStatePath, kHost1UeventRegex, kHost1StatePath,
525 kHost2UeventRegex, kHost2StatePath, kDataRolePath,
526 std::bind(&updatePortStatus, this)),
527 mOverheat(ZoneInfo(TemperatureType::USB_PORT, kThermalZoneForTrip,
528 ThrottlingSeverity::CRITICAL),
529 {ZoneInfo(TemperatureType::UNKNOWN, kThermalZoneForTempReadPrimary,
530 ThrottlingSeverity::NONE),
531 ZoneInfo(TemperatureType::UNKNOWN, kThermalZoneForTempReadSecondary1,
532 ThrottlingSeverity::NONE),
533 ZoneInfo(TemperatureType::UNKNOWN, kThermalZoneForTempReadSecondary2,
534 ThrottlingSeverity::NONE)}, kSamplingIntervalSec),
535 mUsbDataEnabled(true),
536 mDisplayPortPollRunning(false),
537 mDisplayPortPollStarting(false),
538 mDisplayPortCVLock(PTHREAD_MUTEX_INITIALIZER),
539 mDisplayPortLock(PTHREAD_MUTEX_INITIALIZER) {
540 pthread_condattr_t attr;
541 if (pthread_condattr_init(&attr)) {
542 ALOGE("pthread_condattr_init failed: %s", strerror(errno));
543 abort();
544 }
545 if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)) {
546 ALOGE("pthread_condattr_setclock failed: %s", strerror(errno));
547 abort();
548 }
549 if (pthread_cond_init(&mPartnerCV, &attr)) {
550 ALOGE("pthread_cond_init failed: %s", strerror(errno));
551 abort();
552 }
553 if (pthread_cond_init(&mDisplayPortCV, &attr)) {
554 ALOGE("usbdp: pthread_cond_init failed: %s", strerror(errno));
555 abort();
556 }
557 if (pthread_condattr_destroy(&attr)) {
558 ALOGE("pthread_condattr_destroy failed: %s", strerror(errno));
559 abort();
560 }
561 mDisplayPortEventPipe = eventfd(0, EFD_NONBLOCK);
562 if (mDisplayPortEventPipe == -1) {
563 ALOGE("mDisplayPortEventPipe eventfd failed: %s", strerror(errno));
564 abort();
565 }
566 mDisplayPortDebounceTimer = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
567 if (mDisplayPortDebounceTimer == -1) {
568 ALOGE("mDisplayPortDebounceTimer timerfd failed: %s", strerror(errno));
569 abort();
570 }
571 mDisplayPortActivateTimer = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
572 if (mDisplayPortActivateTimer == -1) {
573 ALOGE("mDisplayPortActivateTimer timerfd failed: %s", strerror(errno));
574 abort();
575 }
576
577 ALOGI("feature flag enable_usb_data_compliance_warning: %d",
578 usb_flags::enable_usb_data_compliance_warning());
579 ALOGI("feature flag enable_input_power_limited_warning: %d",
580 usb_flags::enable_input_power_limited_warning());
581 }
582
switchRole(const string & in_portName,const PortRole & in_role,int64_t in_transactionId)583 ScopedAStatus Usb::switchRole(const string& in_portName, const PortRole& in_role,
584 int64_t in_transactionId) {
585 string filename = appendRoleNodeHelper(string(in_portName.c_str()), in_role.getTag());
586 string written;
587 FILE *fp;
588 bool roleSwitch = false;
589
590 if (filename == "") {
591 ALOGE("Fatal: invalid node type");
592 return ScopedAStatus::ok();
593 }
594
595 pthread_mutex_lock(&mRoleSwitchLock);
596
597 ALOGI("filename write: %s role:%s", filename.c_str(), convertRoletoString(in_role).c_str());
598
599 if (in_role.getTag() == PortRole::mode) {
600 roleSwitch = switchMode(in_portName, in_role, this);
601 } else {
602 fp = fopen(filename.c_str(), "w");
603 if (fp != NULL) {
604 int ret = fputs(convertRoletoString(in_role).c_str(), fp);
605 if (ret == EAGAIN) {
606 ALOGI("role switch busy, retry in %d ms", ROLE_SWAP_RETRY_MS);
607 std::this_thread::sleep_for(std::chrono::milliseconds(ROLE_SWAP_RETRY_MS));
608 ret = fputs(convertRoletoString(in_role).c_str(), fp);
609 }
610 fclose(fp);
611 if ((ret != EOF) && ReadFileToString(filename, &written)) {
612 written = Trim(written);
613 extractRole(&written);
614 ALOGI("written: %s", written.c_str());
615 if (written == convertRoletoString(in_role)) {
616 roleSwitch = true;
617 } else {
618 ALOGE("Role switch failed");
619 }
620 } else {
621 ALOGE("failed to update the new role");
622 }
623 } else {
624 ALOGE("fopen failed");
625 }
626 }
627
628 pthread_mutex_lock(&mLock);
629 if (mCallback != NULL) {
630 ScopedAStatus ret = mCallback->notifyRoleSwitchStatus(
631 in_portName, in_role, roleSwitch ? Status::SUCCESS : Status::ERROR, in_transactionId);
632 if (!ret.isOk())
633 ALOGE("RoleSwitchStatus error %s", ret.getDescription().c_str());
634 } else {
635 ALOGE("Not notifying the userspace. Callback is not set");
636 }
637 pthread_mutex_unlock(&mLock);
638 pthread_mutex_unlock(&mRoleSwitchLock);
639
640 return ScopedAStatus::ok();
641 }
642
limitPowerTransfer(const string & in_portName,bool in_limit,int64_t in_transactionId)643 ScopedAStatus Usb::limitPowerTransfer(const string& in_portName, bool in_limit,
644 int64_t in_transactionId) {
645 bool sessionFail = false, success;
646 std::vector<PortStatus> currentPortStatus;
647 string path, sinkLimitEnablePath, currentLimitPath, sourceLimitEnablePath;
648
649 getI2cBusHelper(&path);
650 sinkLimitEnablePath = kI2CPath + path + "/" + path + kSinkLimitEnable;
651 currentLimitPath = kI2CPath + path + "/" + path + kSinkLimitCurrent;
652 sourceLimitEnablePath = kI2CPath + path + "/" + path + kSourceLimitEnable;
653
654 pthread_mutex_lock(&mLock);
655 if (in_limit) {
656 success = WriteStringToFile("0", currentLimitPath);
657 if (!success) {
658 ALOGE("Failed to set sink current limit");
659 sessionFail = true;
660 }
661 }
662 success = WriteStringToFile(in_limit ? "1" : "0", sinkLimitEnablePath);
663 if (!success) {
664 ALOGE("Failed to %s sink current limit: %s", in_limit ? "enable" : "disable",
665 sinkLimitEnablePath.c_str());
666 sessionFail = true;
667 }
668 success = WriteStringToFile(in_limit ? "1" : "0", sourceLimitEnablePath);
669 if (!success) {
670 ALOGE("Failed to %s source current limit: %s", in_limit ? "enable" : "disable",
671 sourceLimitEnablePath.c_str());
672 sessionFail = true;
673 }
674
675 ALOGI("limitPowerTransfer limit:%c opId:%ld", in_limit ? 'y' : 'n', in_transactionId);
676 if (mCallback != NULL && in_transactionId >= 0) {
677 ScopedAStatus ret = mCallback->notifyLimitPowerTransferStatus(
678 in_portName, in_limit, sessionFail ? Status::ERROR : Status::SUCCESS,
679 in_transactionId);
680 if (!ret.isOk())
681 ALOGE("limitPowerTransfer error %s", ret.getDescription().c_str());
682 } else {
683 ALOGE("Not notifying the userspace. Callback is not set");
684 }
685
686 pthread_mutex_unlock(&mLock);
687 queryVersionHelper(this, ¤tPortStatus);
688
689 return ScopedAStatus::ok();
690 }
691
queryPowerTransferStatus(std::vector<PortStatus> * currentPortStatus)692 Status queryPowerTransferStatus(std::vector<PortStatus> *currentPortStatus) {
693 string limitedPath, enabled, path;
694
695 getI2cBusHelper(&path);
696 limitedPath = kI2CPath + path + "/" + path + kSinkLimitEnable;
697 if (!ReadFileToString(limitedPath, &enabled)) {
698 ALOGE("Failed to open limit_sink_enable");
699 return Status::ERROR;
700 }
701
702 enabled = Trim(enabled);
703 (*currentPortStatus)[0].powerTransferLimited = enabled == "1";
704
705 ALOGI("powerTransferLimited:%d", (*currentPortStatus)[0].powerTransferLimited ? 1 : 0);
706 return Status::SUCCESS;
707 }
708
getAccessoryConnected(const string & portName,string * accessory)709 Status getAccessoryConnected(const string &portName, string *accessory) {
710 string filename = "/sys/class/typec/" + portName + "-partner/accessory_mode";
711
712 if (!ReadFileToString(filename, accessory)) {
713 ALOGE("getAccessoryConnected: Failed to open filesystem node: %s", filename.c_str());
714 return Status::ERROR;
715 }
716 *accessory = Trim(*accessory);
717
718 return Status::SUCCESS;
719 }
720
getCurrentRoleHelper(const string & portName,bool connected,PortRole * currentRole)721 Status getCurrentRoleHelper(const string &portName, bool connected, PortRole *currentRole) {
722 string filename;
723 string roleName;
724 string accessory;
725
726 // Mode
727
728 if (currentRole->getTag() == PortRole::powerRole) {
729 filename = "/sys/class/typec/" + portName + "/power_role";
730 currentRole->set<PortRole::powerRole>(PortPowerRole::NONE);
731 } else if (currentRole->getTag() == PortRole::dataRole) {
732 filename = "/sys/class/typec/" + portName + "/data_role";
733 currentRole->set<PortRole::dataRole>(PortDataRole::NONE);
734 } else if (currentRole->getTag() == PortRole::mode) {
735 filename = "/sys/class/typec/" + portName + "/data_role";
736 currentRole->set<PortRole::mode>(PortMode::NONE);
737 } else {
738 return Status::ERROR;
739 }
740
741 if (!connected)
742 return Status::SUCCESS;
743
744 if (currentRole->getTag() == PortRole::mode) {
745 if (getAccessoryConnected(portName, &accessory) != Status::SUCCESS) {
746 return Status::ERROR;
747 }
748 if (accessory == "analog_audio") {
749 currentRole->set<PortRole::mode>(PortMode::AUDIO_ACCESSORY);
750 return Status::SUCCESS;
751 } else if (accessory == "debug") {
752 currentRole->set<PortRole::mode>(PortMode::DEBUG_ACCESSORY);
753 return Status::SUCCESS;
754 }
755 }
756
757 if (!ReadFileToString(filename, &roleName)) {
758 ALOGE("getCurrentRole: Failed to open filesystem node: %s", filename.c_str());
759 return Status::ERROR;
760 }
761
762 roleName = Trim(roleName);
763 extractRole(&roleName);
764
765 if (roleName == "source") {
766 currentRole->set<PortRole::powerRole>(PortPowerRole::SOURCE);
767 } else if (roleName == "sink") {
768 currentRole->set<PortRole::powerRole>(PortPowerRole::SINK);
769 } else if (roleName == "host") {
770 if (currentRole->getTag() == PortRole::dataRole)
771 currentRole->set<PortRole::dataRole>(PortDataRole::HOST);
772 else
773 currentRole->set<PortRole::mode>(PortMode::DFP);
774 } else if (roleName == "device") {
775 if (currentRole->getTag() == PortRole::dataRole)
776 currentRole->set<PortRole::dataRole>(PortDataRole::DEVICE);
777 else
778 currentRole->set<PortRole::mode>(PortMode::UFP);
779 } else if (roleName != "none") {
780 /* case for none has already been addressed.
781 * so we check if the role isn't none.
782 */
783 return Status::UNRECOGNIZED_ROLE;
784 }
785 return Status::SUCCESS;
786 }
787
getTypeCPortNamesHelper(std::unordered_map<string,bool> * names)788 Status getTypeCPortNamesHelper(std::unordered_map<string, bool> *names) {
789 DIR *dp;
790
791 dp = opendir(kTypecPath);
792 if (dp != NULL) {
793 struct dirent *ep;
794
795 while ((ep = readdir(dp))) {
796 if (ep->d_type == DT_LNK) {
797 if (string::npos == string(ep->d_name).find("-partner")) {
798 std::unordered_map<string, bool>::const_iterator portName =
799 names->find(ep->d_name);
800 if (portName == names->end()) {
801 names->insert({ep->d_name, false});
802 }
803 } else {
804 (*names)[std::strtok(ep->d_name, "-")] = true;
805 }
806 }
807 }
808 closedir(dp);
809 return Status::SUCCESS;
810 }
811
812 ALOGE("Failed to open /sys/class/typec");
813 return Status::ERROR;
814 }
815
canSwitchRoleHelper(const string & portName)816 bool canSwitchRoleHelper(const string &portName) {
817 string filename = "/sys/class/typec/" + portName + "-partner/supports_usb_power_delivery";
818 string supportsPD;
819
820 if (ReadFileToString(filename, &supportsPD)) {
821 supportsPD = Trim(supportsPD);
822 if (supportsPD == "yes") {
823 return true;
824 }
825 }
826
827 return false;
828 }
829
getPortStatusHelper(android::hardware::usb::Usb * usb,std::vector<PortStatus> * currentPortStatus)830 Status getPortStatusHelper(android::hardware::usb::Usb *usb,
831 std::vector<PortStatus> *currentPortStatus) {
832 std::unordered_map<string, bool> names;
833 Status result = getTypeCPortNamesHelper(&names);
834 int i = -1;
835
836 if (result == Status::SUCCESS) {
837 currentPortStatus->resize(names.size());
838 for (std::pair<string, bool> port : names) {
839 i++;
840 ALOGI("%s", port.first.c_str());
841 (*currentPortStatus)[i].portName = port.first;
842
843 PortRole currentRole;
844 currentRole.set<PortRole::powerRole>(PortPowerRole::NONE);
845 if (getCurrentRoleHelper(port.first, port.second, ¤tRole) == Status::SUCCESS){
846 (*currentPortStatus)[i].currentPowerRole = currentRole.get<PortRole::powerRole>();
847 } else {
848 ALOGE("Error while retrieving portNames");
849 goto done;
850 }
851
852 currentRole.set<PortRole::dataRole>(PortDataRole::NONE);
853 if (getCurrentRoleHelper(port.first, port.second, ¤tRole) == Status::SUCCESS) {
854 (*currentPortStatus)[i].currentDataRole = currentRole.get<PortRole::dataRole>();
855 } else {
856 ALOGE("Error while retrieving current port role");
857 goto done;
858 }
859
860 currentRole.set<PortRole::mode>(PortMode::NONE);
861 if (getCurrentRoleHelper(port.first, port.second, ¤tRole) == Status::SUCCESS) {
862 (*currentPortStatus)[i].currentMode = currentRole.get<PortRole::mode>();
863 } else {
864 ALOGE("Error while retrieving current data role");
865 goto done;
866 }
867
868 (*currentPortStatus)[i].canChangeMode = true;
869 (*currentPortStatus)[i].canChangeDataRole =
870 port.second ? canSwitchRoleHelper(port.first) : false;
871 (*currentPortStatus)[i].canChangePowerRole =
872 port.second ? canSwitchRoleHelper(port.first) : false;
873
874 (*currentPortStatus)[i].supportedModes.push_back(PortMode::DRP);
875
876 bool dataEnabled = true;
877 string pogoUsbActive = "0";
878 if (ReadFileToString(string(kPogoUsbActive), &pogoUsbActive) &&
879 stoi(Trim(pogoUsbActive)) == 1) {
880 (*currentPortStatus)[i].usbDataStatus.push_back(UsbDataStatus::DISABLED_DOCK);
881 dataEnabled = false;
882 }
883 if (!usb->mUsbDataEnabled) {
884 (*currentPortStatus)[i].usbDataStatus.push_back(UsbDataStatus::DISABLED_FORCE);
885 dataEnabled = false;
886 }
887 if (dataEnabled) {
888 (*currentPortStatus)[i].usbDataStatus.push_back(UsbDataStatus::ENABLED);
889 }
890
891 // When connected return powerBrickStatus
892 if (port.second) {
893 string usbType;
894 if (ReadFileToString(string(kPowerSupplyUsbType), &usbType)) {
895 if (strstr(usbType.c_str(), "[D")) {
896 (*currentPortStatus)[i].powerBrickStatus = PowerBrickStatus::CONNECTED;
897 } else if (strstr(usbType.c_str(), "[U")) {
898 (*currentPortStatus)[i].powerBrickStatus = PowerBrickStatus::UNKNOWN;
899 } else {
900 (*currentPortStatus)[i].powerBrickStatus =
901 PowerBrickStatus::NOT_CONNECTED;
902 }
903 } else {
904 ALOGE("Error while reading usb_type");
905 }
906 } else {
907 (*currentPortStatus)[i].powerBrickStatus = PowerBrickStatus::NOT_CONNECTED;
908 }
909
910 ALOGI("%d:%s connected:%d canChangeMode:%d canChagedata:%d canChangePower:%d "
911 "usbDataEnabled:%d",
912 i, port.first.c_str(), port.second,
913 (*currentPortStatus)[i].canChangeMode,
914 (*currentPortStatus)[i].canChangeDataRole,
915 (*currentPortStatus)[i].canChangePowerRole,
916 dataEnabled ? 1 : 0);
917 }
918
919 return Status::SUCCESS;
920 }
921 done:
922 return Status::ERROR;
923 }
924
925 /* DisplayPort Helper Functions Start */
926
parsePinAssignmentHelper(string pinAssignments)927 DisplayPortAltModePinAssignment parsePinAssignmentHelper(string pinAssignments) {
928 size_t pos = pinAssignments.find("[");
929 if (pos != string::npos) {
930 pinAssignments = pinAssignments.substr(pos+1, 1);
931 if (pinAssignments == "C") {
932 return DisplayPortAltModePinAssignment::C;
933 } else if (pinAssignments == "D") {
934 return DisplayPortAltModePinAssignment::D;
935 } else if (pinAssignments == "E") {
936 return DisplayPortAltModePinAssignment::E;
937 }
938 }
939 return DisplayPortAltModePinAssignment::NONE;
940 }
941
parseLinkTrainingStatusHelper(string linkTrainingStatus)942 LinkTrainingStatus parseLinkTrainingStatusHelper(string linkTrainingStatus) {
943 linkTrainingStatus = Trim(linkTrainingStatus);
944 if (linkTrainingStatus == LINK_TRAINING_STATUS_SUCCESS) {
945 return LinkTrainingStatus::SUCCESS;
946 } else if (linkTrainingStatus == LINK_TRAINING_STATUS_FAILURE || \
947 linkTrainingStatus == LINK_TRAINING_STATUS_FAILURE_SINK) {
948 return LinkTrainingStatus::FAILURE;
949 }
950 return LinkTrainingStatus::UNKNOWN;
951 }
952
isDisplayPortPlugHelper(string vdoString)953 bool isDisplayPortPlugHelper(string vdoString) {
954 unsigned long vdo;
955 unsigned long receptacleFlag = 1 << DISPLAYPORT_CAPABILITIES_RECEPTACLE_BIT;
956
957 vdoString = Trim(vdoString);
958 if (ParseUint(vdoString.c_str(), &vdo)) {
959 /* We check to see if receptacleFlag is 0, meaning that the DP interface is presented on a
960 * USB-C plug.
961 */
962 return !(vdo & receptacleFlag);
963 } else {
964 ALOGE("usbdp: isDisplayPortPlugHelper: errno:%d", errno);
965 }
966
967 return false;
968 }
969
constructAltModeData(string hpd,string pin_assignment,string link_status,string vdo)970 AltModeData::DisplayPortAltModeData constructAltModeData(string hpd, string pin_assignment,
971 string link_status, string vdo) {
972 AltModeData::DisplayPortAltModeData dpData;
973
974 // vdo
975 if (isDisplayPortPlugHelper(vdo)) {
976 dpData.cableStatus = DisplayPortAltModeStatus::CAPABLE;
977 } else {
978 dpData.partnerSinkStatus = DisplayPortAltModeStatus::CAPABLE;
979 }
980
981 // hpd, status
982 if (!strncmp(hpd.c_str(), "1", strlen("1"))) {
983 dpData.hpd = true;
984 }
985
986 // pin
987 dpData.pinAssignment = parsePinAssignmentHelper(pin_assignment);
988
989 // link training
990 link_status = Trim(link_status);
991 dpData.linkTrainingStatus = parseLinkTrainingStatusHelper(link_status);
992 if (dpData.linkTrainingStatus == LinkTrainingStatus::SUCCESS) {
993 dpData.partnerSinkStatus = dpData.partnerSinkStatus == DisplayPortAltModeStatus::CAPABLE ? \
994 DisplayPortAltModeStatus::ENABLED : DisplayPortAltModeStatus::UNKNOWN;
995 dpData.cableStatus = dpData.cableStatus == DisplayPortAltModeStatus::CAPABLE ? \
996 DisplayPortAltModeStatus::ENABLED : DisplayPortAltModeStatus::UNKNOWN;
997 if (dpData.partnerSinkStatus == DisplayPortAltModeStatus::ENABLED) {
998 dpData.cableStatus = DisplayPortAltModeStatus::ENABLED;
999 }
1000 } else if (dpData.linkTrainingStatus == LinkTrainingStatus::FAILURE &&
1001 dpData.partnerSinkStatus == DisplayPortAltModeStatus::CAPABLE) {
1002 // 2.0 cable that fails EDID reports not capable, other link training failures assume
1003 // 3.0 cable that fails in all other cases.
1004 dpData.cableStatus = (link_status == LINK_TRAINING_STATUS_FAILURE_SINK) ? \
1005 DisplayPortAltModeStatus::NOT_CAPABLE : DisplayPortAltModeStatus::CAPABLE;
1006 }
1007
1008 return dpData;
1009 }
1010
queryPartnerSvids(std::vector<string> * svids)1011 Status queryPartnerSvids(std::vector<string> *svids) {
1012 DIR *dp;
1013
1014 dp = opendir(kDisplayPortUsbPath);
1015 if (dp != NULL) {
1016 struct dirent *ep;
1017 // Iterate through directories for Alt Mode SVIDs
1018 while ((ep = readdir(dp))) {
1019 if (ep->d_type == DT_DIR) {
1020 string svid;
1021 string portPartnerPath = string(kDisplayPortUsbPath) + string(ep->d_name) + "/svid";
1022 if (ReadFileToString(portPartnerPath, &svid)) {
1023 (*svids).push_back(Trim(svid));
1024 }
1025 }
1026 }
1027 closedir(dp);
1028 } else {
1029 return Status::ERROR;
1030 }
1031 return Status::SUCCESS;
1032 }
1033
1034 /* DisplayPort Helper Functions End */
1035
1036 // Only care about first port which must support DisplayPortAltMode
queryDisplayPortStatus(android::hardware::usb::Usb * usb,std::vector<PortStatus> * currentPortStatus)1037 Status queryDisplayPortStatus(android::hardware::usb::Usb *usb,
1038 std::vector<PortStatus> *currentPortStatus) {
1039 string hpd, pinAssign, linkStatus, vdo;
1040 string path;
1041 AltModeData::DisplayPortAltModeData dpData;
1042
1043 /*
1044 * We check if the DisplayPort Alt Mode sysfs nodes exist. If they don't, then it means that the
1045 * device has not entered Alt Mode with the port partner because of a source/sink role
1046 * incompatibility, pin assignment incompatibility, etc. So, we then check to see if the partner
1047 * supports Thunderbolt and DisplayPort SVIDs. If it supports DisplayPort, then we assume that
1048 * it must be a source device and Thunderbolt should operate similarly; we don't populate the
1049 * DisplayPortAltModeStatus. If it only supports Thunderbolt, then we cannot determine if it is
1050 * sink or source capable, and need to notify the user.
1051 */
1052 if (usb->getDisplayPortUsbPathHelper(&path) == Status::ERROR) {
1053 std::vector<string> svids;
1054 if (queryPartnerSvids(&svids) == Status::SUCCESS) {
1055 if (std::count(svids.begin(), svids.end(), SVID_THUNDERBOLT) &&
1056 !std::count(svids.begin(), svids.end(), SVID_DISPLAYPORT)) {
1057 dpData.cableStatus = DisplayPortAltModeStatus::NOT_CAPABLE;
1058 }
1059 }
1060 } else {
1061 usb->readDisplayPortAttribute("hpd", path, &hpd);
1062 usb->readDisplayPortAttribute("pin_assignment", path, &pinAssign);
1063 usb->readDisplayPortAttribute("vdo", path, &vdo);
1064 usb->readDisplayPortAttribute("link_status", path, &linkStatus);
1065
1066 dpData = constructAltModeData(hpd, pinAssign, linkStatus, vdo);
1067 }
1068
1069 (*currentPortStatus)[0].supportedAltModes.push_back(dpData);
1070
1071 return Status::SUCCESS;
1072 }
1073
queryUsbDataSession(android::hardware::usb::Usb * usb,std::vector<PortStatus> * currentPortStatus)1074 void queryUsbDataSession(android::hardware::usb::Usb *usb,
1075 std::vector<PortStatus> *currentPortStatus) {
1076 std::vector<ComplianceWarning> warnings;
1077
1078 usb->mUsbDataSessionMonitor.getComplianceWarnings(
1079 (*currentPortStatus)[0].currentDataRole, &warnings);
1080 (*currentPortStatus)[0].complianceWarnings.insert(
1081 (*currentPortStatus)[0].complianceWarnings.end(),
1082 warnings.begin(),
1083 warnings.end());
1084 }
1085
queryVersionHelper(android::hardware::usb::Usb * usb,std::vector<PortStatus> * currentPortStatus)1086 void queryVersionHelper(android::hardware::usb::Usb *usb,
1087 std::vector<PortStatus> *currentPortStatus) {
1088 Status status;
1089 string displayPortUsbPath;
1090
1091 pthread_mutex_lock(&usb->mLock);
1092 status = getPortStatusHelper(usb, currentPortStatus);
1093 queryMoistureDetectionStatus(currentPortStatus);
1094 queryPowerTransferStatus(currentPortStatus);
1095 queryNonCompliantChargerStatus(currentPortStatus);
1096 queryUsbDataSession(usb, currentPortStatus);
1097 pthread_mutex_lock(&usb->mDisplayPortLock);
1098 if (!usb->mDisplayPortFirstSetupDone &&
1099 usb->getDisplayPortUsbPathHelper(&displayPortUsbPath) == Status::SUCCESS) {
1100
1101 ALOGI("usbdp: boot with display connected or usb hal restarted");
1102 usb->setupDisplayPortPoll();
1103 }
1104 pthread_mutex_unlock(&usb->mDisplayPortLock);
1105 queryDisplayPortStatus(usb, currentPortStatus);
1106 if (usb->mCallback != NULL) {
1107 ScopedAStatus ret = usb->mCallback->notifyPortStatusChange(*currentPortStatus,
1108 status);
1109 if (!ret.isOk())
1110 ALOGE("queryPortStatus error %s", ret.getDescription().c_str());
1111 } else {
1112 ALOGI("Notifying userspace skipped. Callback is NULL");
1113 }
1114 pthread_mutex_unlock(&usb->mLock);
1115 }
1116
queryPortStatus(int64_t in_transactionId)1117 ScopedAStatus Usb::queryPortStatus(int64_t in_transactionId) {
1118 std::vector<PortStatus> currentPortStatus;
1119
1120 queryVersionHelper(this, ¤tPortStatus);
1121 pthread_mutex_lock(&mLock);
1122 if (mCallback != NULL) {
1123 ScopedAStatus ret = mCallback->notifyQueryPortStatus(
1124 "all", Status::SUCCESS, in_transactionId);
1125 if (!ret.isOk())
1126 ALOGE("notifyQueryPortStatus error %s", ret.getDescription().c_str());
1127 } else {
1128 ALOGE("Not notifying the userspace. Callback is not set");
1129 }
1130 pthread_mutex_unlock(&mLock);
1131
1132 return ScopedAStatus::ok();
1133 }
1134
enableContaminantPresenceDetection(const string & in_portName,bool in_enable,int64_t in_transactionId)1135 ScopedAStatus Usb::enableContaminantPresenceDetection(const string& in_portName,
1136 bool in_enable, int64_t in_transactionId) {
1137 string disable = GetProperty(kDisableContatminantDetection, "");
1138 std::vector<PortStatus> currentPortStatus;
1139 bool success = true;
1140
1141 if (disable != "true")
1142 success = WriteStringToFile(in_enable ? "1" : "0", enabledPath);
1143
1144 pthread_mutex_lock(&mLock);
1145 if (mCallback != NULL) {
1146 ScopedAStatus ret = mCallback->notifyContaminantEnabledStatus(
1147 in_portName, in_enable, success ? Status::SUCCESS : Status::ERROR, in_transactionId);
1148 if (!ret.isOk())
1149 ALOGE("notifyContaminantEnabledStatus error %s", ret.getDescription().c_str());
1150 } else {
1151 ALOGE("Not notifying the userspace. Callback is not set");
1152 }
1153 pthread_mutex_unlock(&mLock);
1154
1155 queryVersionHelper(this, ¤tPortStatus);
1156 return ScopedAStatus::ok();
1157 }
1158
report_overheat_event(android::hardware::usb::Usb * usb)1159 void report_overheat_event(android::hardware::usb::Usb *usb) {
1160 VendorUsbPortOverheat overheat_info;
1161 string contents;
1162
1163 overheat_info.set_plug_temperature_deci_c(usb->mPluggedTemperatureCelsius * 10);
1164 overheat_info.set_max_temperature_deci_c(usb->mOverheat.getMaxOverheatTemperature() * 10);
1165 if (ReadFileToString(string(kOverheatStatsPath) + "trip_time", &contents)) {
1166 overheat_info.set_time_to_overheat_secs(stoi(Trim(contents)));
1167 } else {
1168 ALOGE("Unable to read trip_time");
1169 return;
1170 }
1171 if (ReadFileToString(string(kOverheatStatsPath) + "hysteresis_time", &contents)) {
1172 overheat_info.set_time_to_hysteresis_secs(stoi(Trim(contents)));
1173 } else {
1174 ALOGE("Unable to read hysteresis_time");
1175 return;
1176 }
1177 if (ReadFileToString(string(kOverheatStatsPath) + "cleared_time", &contents)) {
1178 overheat_info.set_time_to_inactive_secs(stoi(Trim(contents)));
1179 } else {
1180 ALOGE("Unable to read cleared_time");
1181 return;
1182 }
1183
1184 const shared_ptr<IStats> stats_client = getStatsService();
1185 if (!stats_client) {
1186 ALOGE("Unable to get AIDL Stats service");
1187 } else {
1188 reportUsbPortOverheat(stats_client, overheat_info);
1189 }
1190 }
1191
1192 struct data {
1193 int uevent_fd;
1194 ::aidl::android::hardware::usb::Usb *usb;
1195 };
1196
1197 enum UeventType { UNKNOWN, BIND, CHANGE };
1198
matchUeventType(char * str)1199 enum UeventType matchUeventType(char* str) {
1200 if (!strncmp(str, "ACTION=bind", strlen("ACTION=bind"))) {
1201 return UeventType::BIND;
1202 } else if (!strncmp(str, "ACTION=change", strlen("ACTION=change"))) {
1203 return UeventType::CHANGE;
1204 }
1205 return UeventType::UNKNOWN;
1206 }
1207
uevent_event(uint32_t,struct data * payload)1208 static void uevent_event(uint32_t /*epevents*/, struct data *payload) {
1209 char msg[UEVENT_MSG_LEN + 2];
1210 char *cp;
1211 int n;
1212 enum UeventType uevent_type = UeventType::UNKNOWN;
1213
1214 n = uevent_kernel_multicast_recv(payload->uevent_fd, msg, UEVENT_MSG_LEN);
1215 if (n <= 0)
1216 return;
1217 if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
1218 return;
1219
1220 msg[n] = '\0';
1221 msg[n + 1] = '\0';
1222 cp = msg;
1223
1224 while (*cp) {
1225 if (std::regex_match(cp, std::regex("(add)(.*)(-partner)"))) {
1226 ALOGI("partner added");
1227 pthread_mutex_lock(&payload->usb->mPartnerLock);
1228 payload->usb->mPartnerUp = true;
1229 pthread_cond_signal(&payload->usb->mPartnerCV);
1230 pthread_mutex_unlock(&payload->usb->mPartnerLock);
1231 } else if (std::regex_match(cp, std::regex("(remove)(.*)(-partner)"))) {
1232 string drmDisconnectPath = string(kDisplayPortDrmPath) + "usbc_cable_disconnect";
1233
1234 if (payload->usb->mPartnerSupportsDisplayPort) {
1235 ALOGI("displayport partner removed");
1236 if (!WriteStringToFile("1", drmDisconnectPath)) {
1237 ALOGE("Failed to signal disconnect to drm");
1238 }
1239 payload->usb->mPartnerSupportsDisplayPort = false;
1240 }
1241 } else if (!strncmp(cp, "DEVTYPE=typec_", strlen("DEVTYPE=typec_")) ||
1242 !strncmp(cp, "DRIVER=max77759tcpc",
1243 strlen("DRIVER=max77759tcpc")) ||
1244 !strncmp(cp, "DRIVER=pogo-transport",
1245 strlen("DRIVER=pogo-transport")) ||
1246 !strncmp(cp, "POWER_SUPPLY_NAME=usb",
1247 strlen("POWER_SUPPLY_NAME=usb"))) {
1248 std::vector<PortStatus> currentPortStatus;
1249 queryVersionHelper(payload->usb, ¤tPortStatus);
1250
1251 // Role switch is not in progress and port is in disconnected state
1252 if (!pthread_mutex_trylock(&payload->usb->mRoleSwitchLock)) {
1253 for (unsigned long i = 0; i < currentPortStatus.size(); i++) {
1254 DIR *dp =
1255 opendir(string("/sys/class/typec/" +
1256 string(currentPortStatus[i].portName.c_str()) +
1257 "-partner").c_str());
1258 if (dp == NULL) {
1259 switchToDrp(currentPortStatus[i].portName);
1260 } else {
1261 closedir(dp);
1262 }
1263 }
1264 pthread_mutex_unlock(&payload->usb->mRoleSwitchLock);
1265 }
1266 if (!strncmp(cp, "DRIVER=max77759tcpc", strlen("DRIVER=max77759tcpc"))
1267 && payload->usb->mDisplayPortPollRunning) {
1268 uint64_t flag = DISPLAYPORT_IRQ_HPD_COUNT_CHECK;
1269
1270 ALOGI("usbdp: DISPLAYPORT_IRQ_HPD_COUNT_CHECK sent");
1271 write(payload->usb->mDisplayPortEventPipe, &flag, sizeof(flag));
1272 }
1273 /*if (!!strncmp(cp, "DEVTYPE=typec_alternate_mode", strlen("DEVTYPE=typec_alternate_mode"))) {
1274 break;
1275 }*/
1276 } else if (!strncmp(cp, kOverheatStatsDev, strlen(kOverheatStatsDev))) {
1277 ALOGV("Overheat Cooling device suez update");
1278 report_overheat_event(payload->usb);
1279 } else if (!(strncmp(cp, "ACTION=", strlen("ACTION=")))) {
1280 uevent_type = matchUeventType(cp);
1281 } else if (!strncmp(cp, "DRIVER=typec_displayport", strlen("DRIVER=typec_displayport"))) {
1282 if (uevent_type == UeventType::BIND) {
1283 pthread_mutex_lock(&payload->usb->mDisplayPortLock);
1284 payload->usb->setupDisplayPortPoll();
1285 pthread_mutex_unlock(&payload->usb->mDisplayPortLock);
1286 } else if (uevent_type == UeventType::CHANGE) {
1287 pthread_mutex_lock(&payload->usb->mDisplayPortLock);
1288 payload->usb->shutdownDisplayPortPoll(false);
1289 pthread_mutex_unlock(&payload->usb->mDisplayPortLock);
1290 }
1291 break;
1292 }
1293 /* advance to after the next \0 */
1294 while (*cp++) {
1295 }
1296 }
1297 }
1298
work(void * param)1299 void *work(void *param) {
1300 int epoll_fd, uevent_fd;
1301 struct epoll_event ev;
1302 int nevents = 0;
1303 struct data payload;
1304
1305 ALOGE("creating thread");
1306
1307 uevent_fd = uevent_open_socket(64 * 1024, true);
1308
1309 if (uevent_fd < 0) {
1310 ALOGE("uevent_init: uevent_open_socket failed\n");
1311 return NULL;
1312 }
1313
1314 payload.uevent_fd = uevent_fd;
1315 payload.usb = (::aidl::android::hardware::usb::Usb *)param;
1316
1317 fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
1318
1319 ev.events = EPOLLIN;
1320 ev.data.ptr = (void *)uevent_event;
1321
1322 epoll_fd = epoll_create(64);
1323 if (epoll_fd == -1) {
1324 ALOGE("epoll_create failed; errno=%d", errno);
1325 goto error;
1326 }
1327
1328 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1) {
1329 ALOGE("epoll_ctl failed; errno=%d", errno);
1330 goto error;
1331 }
1332
1333 while (!destroyThread) {
1334 struct epoll_event events[64];
1335
1336 nevents = epoll_wait(epoll_fd, events, 64, -1);
1337 if (nevents == -1) {
1338 if (errno == EINTR)
1339 continue;
1340 ALOGE("usb epoll_wait failed; errno=%d", errno);
1341 break;
1342 }
1343
1344 for (int n = 0; n < nevents; ++n) {
1345 if (events[n].data.ptr)
1346 (*(void (*)(int, struct data *payload))events[n].data.ptr)(events[n].events,
1347 &payload);
1348 }
1349 }
1350
1351 ALOGI("exiting worker thread");
1352 error:
1353 close(uevent_fd);
1354
1355 if (epoll_fd >= 0)
1356 close(epoll_fd);
1357
1358 return NULL;
1359 }
1360
sighandler(int sig)1361 void sighandler(int sig) {
1362 if (sig == SIGUSR1) {
1363 destroyThread = true;
1364 ALOGI("destroy set");
1365 return;
1366 }
1367 signal(SIGUSR1, sighandler);
1368 }
1369
setCallback(const shared_ptr<IUsbCallback> & in_callback)1370 ScopedAStatus Usb::setCallback(const shared_ptr<IUsbCallback>& in_callback) {
1371 pthread_mutex_lock(&mLock);
1372 if ((mCallback == NULL && in_callback == NULL) ||
1373 (mCallback != NULL && in_callback != NULL)) {
1374 mCallback = in_callback;
1375 pthread_mutex_unlock(&mLock);
1376 return ScopedAStatus::ok();
1377 }
1378
1379 mCallback = in_callback;
1380 ALOGI("registering callback");
1381
1382 if (mCallback == NULL) {
1383 if (!pthread_kill(mPoll, SIGUSR1)) {
1384 pthread_join(mPoll, NULL);
1385 ALOGI("pthread destroyed");
1386 }
1387 pthread_mutex_unlock(&mLock);
1388 return ScopedAStatus::ok();
1389 }
1390
1391 destroyThread = false;
1392 signal(SIGUSR1, sighandler);
1393
1394 /*
1395 * Create a background thread if the old callback value is NULL
1396 * and being updated with a new value.
1397 */
1398 if (pthread_create(&mPoll, NULL, work, this)) {
1399 ALOGE("pthread creation failed %d", errno);
1400 mCallback = NULL;
1401 }
1402
1403 pthread_mutex_unlock(&mLock);
1404 return ScopedAStatus::ok();
1405 }
1406
1407 /***** DisplayPort Alt Mode Helpers *****/
1408
getDisplayPortUsbPathHelper(string * path)1409 Status Usb::getDisplayPortUsbPathHelper(string *path) {
1410 DIR *dp;
1411 Status result = Status::ERROR;
1412
1413 dp = opendir(kDisplayPortUsbPath);
1414 if (dp != NULL) {
1415 struct dirent *ep;
1416 // Iterate through all alt mode directories to find displayport driver
1417 while ((ep = readdir(dp))) {
1418 if (ep->d_type == DT_DIR) {
1419 DIR *displayPortDp;
1420 string portPartnerPath = string(kDisplayPortUsbPath) + string(ep->d_name)
1421 + "/displayport/";
1422 displayPortDp = opendir(portPartnerPath.c_str());
1423 if (displayPortDp != NULL) {
1424 *path = portPartnerPath;
1425 closedir(displayPortDp);
1426 result = Status::SUCCESS;
1427 break;
1428 }
1429 }
1430 }
1431 closedir(dp);
1432 }
1433 return result;
1434 }
1435
readDisplayPortAttribute(string attribute,string usb_path,string * value)1436 Status Usb::readDisplayPortAttribute(string attribute, string usb_path, string* value) {
1437 string attrPath;
1438
1439 if (!strncmp(attribute.c_str(), "hpd", strlen("hpd")) ||
1440 !strncmp(attribute.c_str(), "pin_assignment", strlen("pin_assignment"))) {
1441 attrPath = usb_path + attribute;
1442 } else if (!strncmp(attribute.c_str(), "link_status", strlen("link_status"))) {
1443 attrPath = string(kDisplayPortDrmPath) + "link_status";
1444 } else if (!strncmp(attribute.c_str(), "vdo", strlen("vdo"))) {
1445 attrPath = usb_path + "/../vdo";
1446 } else {
1447 goto error;
1448 }
1449
1450 // Read Attribute
1451 if(ReadFileToString(attrPath.c_str(), value)) {
1452 return Status::SUCCESS;
1453 }
1454
1455 error:
1456 ALOGE("usbdp: Failed to read Type-C attribute %s", attribute.c_str());
1457 return Status::ERROR;
1458 }
1459
writeDisplayPortAttributeOverride(string attribute,string value)1460 Status Usb::writeDisplayPortAttributeOverride(string attribute, string value) {
1461 string attrDrmPath;
1462
1463 // Get Drm Path
1464 attrDrmPath = string(kDisplayPortDrmPath) + attribute;
1465
1466 // Write to drm
1467 if(!WriteStringToFile(value, attrDrmPath)) {
1468 ALOGE("usbdp: Failed to write attribute %s to drm: %s", attribute.c_str(), value.c_str());
1469 return Status::ERROR;
1470 }
1471 ALOGI("usbdp: Successfully wrote attribute %s: %s to drm.", attribute.c_str(), value.c_str());
1472 return Status::SUCCESS;
1473 }
1474
writeDisplayPortAttribute(string attribute,string usb_path)1475 Status Usb::writeDisplayPortAttribute(string attribute, string usb_path) {
1476 string attrUsb, attrDrm, attrDrmPath;
1477
1478 // Get Drm Path
1479 attrDrmPath = string(kDisplayPortDrmPath) + attribute;
1480
1481 // Read Attribute
1482 if(!ReadFileToString(usb_path, &attrUsb)) {
1483 ALOGE("usbdp: Failed to open or read Type-C attribute %s", attribute.c_str());
1484 return Status::ERROR;
1485 }
1486
1487 // Separate Logic for hpd and pin_assignment
1488 if (!strncmp(attribute.c_str(), "hpd", strlen("hpd"))) {
1489 if (!strncmp(attrUsb.c_str(), "0", strlen("0"))) {
1490 // Read DRM attribute to compare
1491 if(!ReadFileToString(attrDrmPath, &attrDrm)) {
1492 ALOGE("usbdp: Failed to open or read hpd from drm");
1493 return Status::ERROR;
1494 }
1495 if (!strncmp(attrDrm.c_str(), "0", strlen("0"))) {
1496 ALOGI("usbdp: Skipping hpd write when drm and usb both equal 0");
1497 return Status::SUCCESS;
1498 }
1499 }
1500 } else if (!strncmp(attribute.c_str(), "irq_hpd_count", strlen("irq_hpd_count"))) {
1501 uint32_t temp;
1502 if (!::android::base::ParseUint(Trim(attrUsb), &temp)) {
1503 ALOGE("usbdp: failed parsing irq_hpd_count:%s", attrUsb.c_str());
1504 return Status::ERROR;
1505 }
1506 // Used to cache the values read from tcpci's irq_hpd_count.
1507 // Update drm driver when cached value is not the same as the read value.
1508 ALOGI("usbdp: mIrqHpdCountCache:%u irq_hpd_count:%u", mIrqHpdCountCache, temp);
1509 if (mIrqHpdCountCache == temp) {
1510 return Status::SUCCESS;
1511 } else {
1512 mIrqHpdCountCache = temp;
1513 }
1514 attrDrmPath = string(kDisplayPortDrmPath) + "irq_hpd";
1515 } else if (!strncmp(attribute.c_str(), "pin_assignment", strlen("pin_assignment"))) {
1516 size_t pos = attrUsb.find("[");
1517 if (pos != string::npos) {
1518 ALOGI("usbdp: Modifying Pin Config from %s", attrUsb.c_str());
1519 attrUsb = attrUsb.substr(pos+1, 1);
1520 } else {
1521 // Don't write anything
1522 ALOGI("usbdp: Pin config not yet chosen, nothing written.");
1523 return Status::ERROR;
1524 }
1525 }
1526
1527 // Write to drm
1528 if(!WriteStringToFile(attrUsb, attrDrmPath)) {
1529 ALOGE("usbdp: Failed to write attribute %s to drm: %s", attribute.c_str(), attrUsb.c_str());
1530 return Status::ERROR;
1531 }
1532 ALOGI("usbdp: Successfully wrote attribute %s: %s to drm.", attribute.c_str(), attrUsb.c_str());
1533 return Status::SUCCESS;
1534 }
1535
determineDisplayPortRetry(string linkPath,string hpdPath)1536 bool Usb::determineDisplayPortRetry(string linkPath, string hpdPath) {
1537 string linkStatus, hpd;
1538
1539 if(ReadFileToString(linkPath, &linkStatus) && ReadFileToString(hpdPath, &hpd)) {
1540 if (!strncmp(linkStatus.c_str(), "2", strlen("2")) &&
1541 !strncmp(hpd.c_str(), "1", strlen("1"))) {
1542 return true;
1543 }
1544 }
1545
1546 return false;
1547 }
1548
displayPortPollOpenFileHelper(const char * file,int flags)1549 static int displayPortPollOpenFileHelper(const char *file, int flags) {
1550 int fd = open(file, flags);
1551 if (fd == -1) {
1552 ALOGE("usbdp: worker: open at %s failed; errno=%d", file, errno);
1553 }
1554 return fd;
1555 }
1556
1557 /*
1558 * armTimerFdHelper - Sets timerfd (fd) to trigger after (ms) milliseconds.
1559 * Setting ms to 0 disarms the timer.
1560 */
armTimerFdHelper(int fd,int ms)1561 static int armTimerFdHelper(int fd, int ms) {
1562 struct itimerspec ts;
1563
1564 ts.it_interval.tv_sec = 0;
1565 ts.it_interval.tv_nsec = 0;
1566 ts.it_value.tv_sec = ms / 1000;
1567 ts.it_value.tv_nsec = (ms % 1000) * 1000000;
1568
1569 return timerfd_settime(fd, 0, &ts, NULL);
1570 }
1571
displayPortPollWork(void * param)1572 void *displayPortPollWork(void *param) {
1573 /* USB Payload */
1574 ::aidl::android::hardware::usb::Usb *usb = (::aidl::android::hardware::usb::Usb *)param;
1575 /* Epoll fields */
1576 int epoll_fd;
1577 struct epoll_event ev_hpd, ev_pin, ev_orientation, ev_eventfd, ev_link, ev_debounce;
1578 struct epoll_event ev_activate;
1579 int nevents = 0;
1580 int hpd_fd, pin_fd, orientation_fd, link_training_status_fd;
1581 int file_flags = O_RDONLY;
1582 int epoll_flags;
1583 /* DisplayPort link statuses */
1584 bool orientationSet = false;
1585 bool pinSet = false;
1586 int activateRetryCount = 0;
1587 unsigned long res;
1588 int ret = 0;
1589 /* File paths */
1590 string displayPortUsbPath, irqHpdCountPath, hpdPath, pinAssignmentPath, orientationPath;
1591 string tcpcI2cBus, linkPath, partnerActivePath, portActivePath;
1592
1593 usb->mDisplayPortPollRunning = true;
1594 usb->mDisplayPortPollStarting = false;
1595
1596 /*---------- Setup ----------*/
1597
1598 if (usb->getDisplayPortUsbPathHelper(&displayPortUsbPath) == Status::ERROR) {
1599 ALOGE("usbdp: worker: could not locate usb displayport directory");
1600 goto usb_path_error;
1601 }
1602
1603 ALOGI("usbdp: worker: displayport usb path located at %s", displayPortUsbPath.c_str());
1604 hpdPath = displayPortUsbPath + "hpd";
1605 pinAssignmentPath = displayPortUsbPath + "pin_assignment";
1606 orientationPath = "/sys/class/typec/port0/orientation";
1607 linkPath = string(kDisplayPortDrmPath) + "link_status";
1608
1609 partnerActivePath = displayPortUsbPath + "../mode1/active";
1610 portActivePath = "/sys/class/typec/port0/port0.0/mode1/active";
1611
1612 getI2cBusHelper(&tcpcI2cBus);
1613 irqHpdCountPath = kI2CPath + tcpcI2cBus + "/" + tcpcI2cBus + kIrqHpdCounPath;
1614 ALOGI("usbdp: worker: irqHpdCountPath:%s", irqHpdCountPath.c_str());
1615
1616 epoll_fd = epoll_create(64);
1617 if (epoll_fd == -1) {
1618 ALOGE("usbdp: worker: epoll_create failed; errno=%d", errno);
1619 goto epoll_fd_error;
1620 }
1621
1622 if ((hpd_fd = displayPortPollOpenFileHelper(hpdPath.c_str(), file_flags)) == -1){
1623 goto hpd_fd_error;
1624 }
1625 if ((pin_fd = displayPortPollOpenFileHelper(pinAssignmentPath.c_str(), file_flags)) == -1){
1626 goto pin_fd_error;
1627 }
1628 if ((orientation_fd = displayPortPollOpenFileHelper(orientationPath.c_str(), file_flags))
1629 == -1){
1630 goto orientation_fd_error;
1631 }
1632 if ((link_training_status_fd = displayPortPollOpenFileHelper(linkPath.c_str(), file_flags)) == -1){
1633 goto link_training_status_fd_error;
1634 }
1635
1636 // Set epoll_event events and flags
1637 epoll_flags = EPOLLIN | EPOLLET;
1638 ev_hpd.events = epoll_flags;
1639 ev_pin.events = epoll_flags;
1640 ev_orientation.events = epoll_flags;
1641 ev_eventfd.events = epoll_flags;
1642 ev_link.events = epoll_flags;
1643 ev_debounce.events = epoll_flags;
1644 ev_activate.events = epoll_flags;
1645
1646 ev_hpd.data.fd = hpd_fd;
1647 ev_pin.data.fd = pin_fd;
1648 ev_orientation.data.fd = orientation_fd;
1649 ev_eventfd.data.fd = usb->mDisplayPortEventPipe;
1650 ev_link.data.fd = link_training_status_fd;
1651 ev_debounce.data.fd = usb->mDisplayPortDebounceTimer;
1652 ev_activate.data.fd = usb->mDisplayPortActivateTimer;
1653
1654 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, hpd_fd, &ev_hpd) == -1) {
1655 ALOGE("usbdp: worker: epoll_ctl failed to add hpd; errno=%d", errno);
1656 goto error;
1657 }
1658 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pin_fd, &ev_pin) == -1) {
1659 ALOGE("usbdp: worker: epoll_ctl failed to add pin; errno=%d", errno);
1660 goto error;
1661 }
1662 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, orientation_fd, &ev_orientation) == -1) {
1663 ALOGE("usbdp: worker: epoll_ctl failed to add orientation; errno=%d", errno);
1664 goto error;
1665 }
1666 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, link_training_status_fd, &ev_link) == -1) {
1667 ALOGE("usbdp: worker: epoll_ctl failed to add link status; errno=%d", errno);
1668 goto error;
1669 }
1670 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, usb->mDisplayPortDebounceTimer, &ev_debounce) == -1) {
1671 ALOGE("usbdp: worker: epoll_ctl failed to add framework update debounce; errno=%d", errno);
1672 goto error;
1673 }
1674 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, usb->mDisplayPortActivateTimer, &ev_activate) == -1) {
1675 ALOGE("usbdp: worker: epoll_ctl failed to add activate debounce; errno=%d", errno);
1676 goto error;
1677 }
1678 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, usb->mDisplayPortEventPipe, &ev_eventfd) == -1) {
1679 ALOGE("usbdp: worker: epoll_ctl failed to add orientation; errno=%d", errno);
1680 goto error;
1681 }
1682
1683 /* Arm timer to see if DisplayPort Alt Mode Activates */
1684 armTimerFdHelper(usb->mDisplayPortActivateTimer, DISPLAYPORT_ACTIVATE_DEBOUNCE_MS);
1685
1686 while (!destroyDisplayPortThread) {
1687 struct epoll_event events[64];
1688
1689 nevents = epoll_wait(epoll_fd, events, 64, -1);
1690 if (nevents == -1) {
1691 if (errno == EINTR)
1692 continue;
1693 ALOGE("usbdp: worker: epoll_wait failed; errno=%d", errno);
1694 break;
1695 }
1696
1697 for (int n = 0; n < nevents; n++) {
1698 if (events[n].data.fd == hpd_fd) {
1699 if (!pinSet || !orientationSet) {
1700 ALOGW("usbdp: worker: HPD may be set before pin_assignment and orientation");
1701 if (!pinSet &&
1702 usb->writeDisplayPortAttribute("pin_assignment", pinAssignmentPath) ==
1703 Status::SUCCESS) {
1704 pinSet = true;
1705 }
1706 if (!orientationSet &&
1707 usb->writeDisplayPortAttribute("orientation", orientationPath) ==
1708 Status::SUCCESS) {
1709 orientationSet = true;
1710 }
1711 }
1712 usb->writeDisplayPortAttribute("hpd", hpdPath);
1713 armTimerFdHelper(usb->mDisplayPortDebounceTimer, DISPLAYPORT_STATUS_DEBOUNCE_MS);
1714 } else if (events[n].data.fd == pin_fd) {
1715 if (usb->writeDisplayPortAttribute("pin_assignment", pinAssignmentPath) ==
1716 Status::SUCCESS) {
1717 pinSet = true;
1718 armTimerFdHelper(usb->mDisplayPortDebounceTimer, DISPLAYPORT_STATUS_DEBOUNCE_MS);
1719 }
1720 } else if (events[n].data.fd == orientation_fd) {
1721 if (usb->writeDisplayPortAttribute("orientation", orientationPath) ==
1722 Status::SUCCESS) {
1723 orientationSet = true;
1724 armTimerFdHelper(usb->mDisplayPortDebounceTimer, DISPLAYPORT_STATUS_DEBOUNCE_MS);
1725 }
1726 } else if (events[n].data.fd == link_training_status_fd) {
1727 armTimerFdHelper(usb->mDisplayPortDebounceTimer, DISPLAYPORT_STATUS_DEBOUNCE_MS);
1728 } else if (events[n].data.fd == usb->mDisplayPortDebounceTimer) {
1729 std::vector<PortStatus> currentPortStatus;
1730 ret = read(usb->mDisplayPortDebounceTimer, &res, sizeof(res));
1731 ALOGI("usbdp: dp debounce triggered, val:%lu ret:%d", res, ret);
1732 if (ret < 0) {
1733 ALOGW("usbdp: debounce read error:%d", errno);
1734 continue;
1735 }
1736 queryVersionHelper(usb, ¤tPortStatus);
1737 } else if (events[n].data.fd == usb->mDisplayPortActivateTimer) {
1738 string activePartner, activePort;
1739
1740 if (ReadFileToString(partnerActivePath.c_str(), &activePartner) &&
1741 ReadFileToString(portActivePath.c_str(), &activePort)) {
1742 // Retry activate signal when DisplayPort Alt Mode is active on port but not
1743 // partner.
1744 if (!strncmp(activePartner.c_str(), "no", strlen("no")) &&
1745 !strncmp(activePort.c_str(), "yes", strlen("yes")) &&
1746 activateRetryCount < DISPLAYPORT_ACTIVATE_MAX_RETRIES) {
1747 if (!WriteStringToFile("1", partnerActivePath)) {
1748 ALOGE("usbdp: Failed to activate port partner Alt Mode");
1749 } else {
1750 ALOGI("usbdp: Attempting to activate port partner Alt Mode");
1751 }
1752 activateRetryCount++;
1753 armTimerFdHelper(usb->mDisplayPortActivateTimer,
1754 DISPLAYPORT_ACTIVATE_DEBOUNCE_MS);
1755 } else {
1756 ALOGI("usbdp: DisplayPort Alt Mode is active, or disabled on port");
1757 }
1758 } else {
1759 activateRetryCount++;
1760 armTimerFdHelper(usb->mDisplayPortActivateTimer,
1761 DISPLAYPORT_ACTIVATE_DEBOUNCE_MS);
1762 ALOGE("usbdp: Failed to read active state from port or partner");
1763 }
1764 } else if (events[n].data.fd == usb->mDisplayPortEventPipe) {
1765 uint64_t flag = 0;
1766 if (!read(usb->mDisplayPortEventPipe, &flag, sizeof(flag))) {
1767 if (errno == EAGAIN)
1768 continue;
1769 ALOGI("usbdp: worker: Shutdown eventfd read error");
1770 goto error;
1771 }
1772 if (flag == DISPLAYPORT_SHUTDOWN_SET) {
1773 ALOGI("usbdp: worker: Shutdown eventfd triggered");
1774 destroyDisplayPortThread = true;
1775 break;
1776 } else if (flag == DISPLAYPORT_IRQ_HPD_COUNT_CHECK) {
1777 ALOGI("usbdp: worker: IRQ_HPD event through DISPLAYPORT_IRQ_HPD_COUNT_CHECK");
1778 usb->writeDisplayPortAttribute("irq_hpd_count", irqHpdCountPath);
1779 }
1780 }
1781 }
1782 }
1783
1784 error:
1785 /* Need to disarm so new threads don't get old event */
1786 armTimerFdHelper(usb->mDisplayPortDebounceTimer, 0);
1787 armTimerFdHelper(usb->mDisplayPortActivateTimer, 0);
1788 close(link_training_status_fd);
1789 link_training_status_fd_error:
1790 close(orientation_fd);
1791 orientation_fd_error:
1792 close(pin_fd);
1793 pin_fd_error:
1794 close(hpd_fd);
1795 hpd_fd_error:
1796 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, usb->mDisplayPortDebounceTimer, &ev_debounce);
1797 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, usb->mDisplayPortActivateTimer, &ev_activate);
1798 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, usb->mDisplayPortEventPipe, &ev_eventfd);
1799 close(epoll_fd);
1800 epoll_fd_error:
1801 usb_path_error:
1802 usb->mDisplayPortPollRunning = false;
1803 ALOGI("usbdp: worker: exiting worker thread");
1804 return NULL;
1805 }
1806
setTimespecTimer(int debounceMs)1807 static struct timespec setTimespecTimer(int debounceMs) {
1808 struct timespec to;
1809 struct timespec now;
1810
1811 clock_gettime(CLOCK_MONOTONIC, &now);
1812 to.tv_nsec = now.tv_nsec + ((debounceMs % 1000) * 1000000);
1813 to.tv_sec = now.tv_sec + (debounceMs / 1000);
1814 if (to.tv_nsec >= 1000000000) {
1815 to.tv_nsec -= 1000000000;
1816 to.tv_sec += 1;
1817 }
1818
1819 return to;
1820 }
1821
setupDisplayPortPoll()1822 void Usb::setupDisplayPortPoll() {
1823 uint64_t flag = DISPLAYPORT_SHUTDOWN_CLEAR;
1824 mDisplayPortFirstSetupDone = true;
1825 int ret;
1826
1827 ALOGI("usbdp: setup: beginning setup for displayport poll thread");
1828 mPartnerSupportsDisplayPort = true;
1829
1830 /*
1831 * If thread is currently starting, then it hasn't setup DisplayPort fd's, and we can abandon
1832 * this process.
1833 */
1834 if (mDisplayPortPollStarting) {
1835 ALOGI("usbdp: setup: abandoning poll thread because another startup is in progress");
1836 return;
1837 }
1838
1839 /*
1840 * Check to see if thread is currently running. If it is, then we assume that it must have
1841 * invalid DisplayPort fd's and the new thread takes over.
1842 */
1843 if (mDisplayPortPollRunning) {
1844 shutdownDisplayPortPoll(true);
1845 pthread_mutex_lock(&mDisplayPortCVLock);
1846 struct timespec to = setTimespecTimer(DISPLAYPORT_POLL_WAIT_MS);
1847 ret = pthread_cond_timedwait(&mDisplayPortCV, &mDisplayPortCVLock, &to);
1848 if (ret == ETIMEDOUT) {
1849 ALOGI("usbdp: setup: Wait for poll to shutdown timed out, starting new poll anyways.");
1850 }
1851 pthread_mutex_unlock(&mDisplayPortCVLock);
1852 }
1853
1854 // Indicate that startup procedure is initiated (mutex protects two threads running setup at
1855 // once)
1856 mDisplayPortPollStarting = true;
1857
1858 // Reset shutdown signals because shutdown() does not perform self clean-up
1859 write(mDisplayPortEventPipe, &flag, sizeof(flag));
1860 destroyDisplayPortThread = false;
1861
1862 /*
1863 * Create a background thread to poll DisplayPort system files
1864 */
1865 if (pthread_create(&mDisplayPortPoll, NULL, displayPortPollWork, this)) {
1866 ALOGE("usbdp: setup: failed to create displayport poll thread %d", errno);
1867 goto error;
1868 }
1869 ALOGI("usbdp: setup: successfully started displayport poll thread");
1870 return;
1871
1872 error:
1873 mDisplayPortPollStarting = false;
1874 return;
1875 }
1876
shutdownDisplayPortPollHelper()1877 void Usb::shutdownDisplayPortPollHelper() {
1878 uint64_t flag = DISPLAYPORT_SHUTDOWN_SET;
1879
1880 // Write shutdown signal to child thread.
1881 write(mDisplayPortEventPipe, &flag, sizeof(flag));
1882 pthread_join(mDisplayPortPoll, NULL);
1883 writeDisplayPortAttributeOverride("hpd", "0");
1884 pthread_mutex_lock(&mDisplayPortCVLock);
1885 pthread_cond_signal(&mDisplayPortCV);
1886 pthread_mutex_unlock(&mDisplayPortCVLock);
1887 }
1888
shutdownDisplayPortPollWork(void * param)1889 void *shutdownDisplayPortPollWork(void *param) {
1890 ::aidl::android::hardware::usb::Usb *usb = (::aidl::android::hardware::usb::Usb *)param;
1891
1892 usb->shutdownDisplayPortPollHelper();
1893 ALOGI("usbdp: shutdown: displayport thread shutdown complete.");
1894 return NULL;
1895 }
1896
shutdownDisplayPortPoll(bool force)1897 void Usb::shutdownDisplayPortPoll(bool force) {
1898 string displayPortUsbPath;
1899
1900 ALOGI("usbdp: shutdown: beginning shutdown for displayport poll thread");
1901
1902 /*
1903 * Determine if should shutdown thread
1904 *
1905 * getDisplayPortUsbPathHelper locates a DisplayPort directory, no need to double check
1906 * directory.
1907 *
1908 * Force is put in place to shutdown even when displayPortUsbPath is still present.
1909 * Happens when back to back BIND events are sent and fds are no longer current.
1910 */
1911 if (!mDisplayPortPollRunning ||
1912 (!force && getDisplayPortUsbPathHelper(&displayPortUsbPath) == Status::SUCCESS)) {
1913 return;
1914 }
1915
1916 // Shutdown is nonblocking to let other usb operations continue
1917 if (pthread_create(&mDisplayPortShutdownHelper, NULL, shutdownDisplayPortPollWork, this)) {
1918 ALOGE("usbdp: shutdown: shutdown worker pthread creation failed %d", errno);
1919 }
1920 }
1921
1922 } // namespace usb
1923 } // namespace hardware
1924 } // namespace android
1925 } // aidl
1926