usb: populate USB aidl hal AltModeData

Populates AltModeData within PortStatus with DisplayPort
Alt Mode statuses for pin assignment, hpd, link training
status, and port partner capability.

Test: manual test on device
Bug: 297286558
Change-Id: I52a56f7090ed6dbef6211f19d6350cecac58e4fa
(cherry picked from commit c2c37bf3a81e4138bd2c0e82275d363dce2220ec)
Signed-off-by: RD Babiera <rdbabiera@google.com>
This commit is contained in:
RD Babiera 2023-02-28 18:44:07 +00:00
parent d14e37d77d
commit 2323e69cf4
2 changed files with 202 additions and 9 deletions

View file

@ -35,6 +35,7 @@
#include <cutils/uevent.h> #include <cutils/uevent.h>
#include <sys/epoll.h> #include <sys/epoll.h>
#include <sys/eventfd.h> #include <sys/eventfd.h>
#include <sys/timerfd.h>
#include <utils/Errors.h> #include <utils/Errors.h>
#include <utils/StrongPointer.h> #include <utils/StrongPointer.h>
@ -47,6 +48,7 @@
using aidl::android::frameworks::stats::IStats; using aidl::android::frameworks::stats::IStats;
using android::base::GetProperty; using android::base::GetProperty;
using android::base::Join; using android::base::Join;
using android::base::ParseUint;
using android::base::Tokenize; using android::base::Tokenize;
using android::base::Trim; using android::base::Trim;
using android::hardware::google::pixel::getStatsService; using android::hardware::google::pixel::getStatsService;
@ -86,6 +88,8 @@ constexpr char kIrqHpdCounPath[] = "-0025/irq_hpd_count";
constexpr int kSamplingIntervalSec = 5; constexpr int kSamplingIntervalSec = 5;
void queryVersionHelper(android::hardware::usb::Usb *usb, void queryVersionHelper(android::hardware::usb::Usb *usb,
std::vector<PortStatus> *currentPortStatus); std::vector<PortStatus> *currentPortStatus);
AltModeData::DisplayPortAltModeData constructAltModeData(string hpd, string pin_assignment,
string link_status, string vdo);
ScopedAStatus Usb::enableUsbData(const string& in_portName, bool in_enable, ScopedAStatus Usb::enableUsbData(const string& in_portName, bool in_enable,
int64_t in_transactionId) { int64_t in_transactionId) {
@ -434,6 +438,11 @@ Usb::Usb()
ALOGE("mDisplayPortEventPipe eventfd failed: %s", strerror(errno)); ALOGE("mDisplayPortEventPipe eventfd failed: %s", strerror(errno));
abort(); abort();
} }
mDisplayPortDebounceTimer = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
if (mDisplayPortDebounceTimer == -1) {
ALOGE("mDisplayPortDebounceTimer timerfd failed: %s", strerror(errno));
abort();
}
} }
ScopedAStatus Usb::switchRole(const string& in_portName, const PortRole& in_role, ScopedAStatus Usb::switchRole(const string& in_portName, const PortRole& in_role,
@ -773,6 +782,118 @@ done:
return Status::ERROR; return Status::ERROR;
} }
/* DisplayPort Helper Functions Start */
DisplayPortAltModePinAssignment parsePinAssignmentHelper(string pinAssignments) {
size_t pos = pinAssignments.find("[");
if (pos != string::npos) {
pinAssignments = pinAssignments.substr(pos+1, 1);
if (pinAssignments == "C") {
return DisplayPortAltModePinAssignment::C;
} else if (pinAssignments == "D") {
return DisplayPortAltModePinAssignment::D;
} else if (pinAssignments == "E") {
return DisplayPortAltModePinAssignment::E;
}
}
return DisplayPortAltModePinAssignment::NONE;
}
LinkTrainingStatus parseLinkTrainingStatusHelper(string linkTrainingStatus) {
linkTrainingStatus = Trim(linkTrainingStatus);
if (linkTrainingStatus == LINK_TRAINING_STATUS_SUCCESS) {
return LinkTrainingStatus::SUCCESS;
} else if (linkTrainingStatus == LINK_TRAINING_STATUS_FAILURE || \
linkTrainingStatus == LINK_TRAINING_STATUS_FAILURE_SINK) {
return LinkTrainingStatus::FAILURE;
}
return LinkTrainingStatus::UNKNOWN;
}
bool isDisplayPortPlugHelper(string vdoString) {
unsigned long vdo;
unsigned long receptacleFlag = 1 << DISPLAYPORT_CAPABILITIES_RECEPTACLE_BIT;
vdoString = Trim(vdoString);
if (ParseUint(vdoString.c_str(), &vdo)) {
/* We check to see if receptacleFlag is 0, meaning that the DP interface is presented on a
* USB-C plug.
*/
return !(vdo & receptacleFlag);
} else {
ALOGE("usbdp: isDisplayPortPlugHelper: errno:%d", errno);
}
return false;
}
AltModeData::DisplayPortAltModeData constructAltModeData(string hpd, string pin_assignment,
string link_status, string vdo) {
AltModeData::DisplayPortAltModeData dpData;
// vdo
if (isDisplayPortPlugHelper(vdo)) {
dpData.cableStatus = DisplayPortAltModeStatus::CAPABLE;
} else {
dpData.partnerSinkStatus = DisplayPortAltModeStatus::CAPABLE;
}
// hpd, status
if (!strncmp(hpd.c_str(), "1", strlen("1"))) {
dpData.hpd = true;
}
// pin
dpData.pinAssignment = parsePinAssignmentHelper(pin_assignment);
// link training
link_status = Trim(link_status);
dpData.linkTrainingStatus = parseLinkTrainingStatusHelper(link_status);
if (dpData.linkTrainingStatus == LinkTrainingStatus::SUCCESS) {
dpData.partnerSinkStatus = dpData.partnerSinkStatus == DisplayPortAltModeStatus::CAPABLE ? \
DisplayPortAltModeStatus::ENABLED : DisplayPortAltModeStatus::UNKNOWN;
dpData.cableStatus = dpData.cableStatus == DisplayPortAltModeStatus::CAPABLE ? \
DisplayPortAltModeStatus::ENABLED : DisplayPortAltModeStatus::UNKNOWN;
if (dpData.partnerSinkStatus == DisplayPortAltModeStatus::ENABLED) {
dpData.cableStatus = DisplayPortAltModeStatus::ENABLED;
}
} else if (dpData.linkTrainingStatus == LinkTrainingStatus::FAILURE &&
dpData.partnerSinkStatus == DisplayPortAltModeStatus::CAPABLE) {
// 2.0 cable that fails EDID reports not capable, other link training failures assume
// 3.0 cable that fails in all other cases.
dpData.cableStatus = (link_status == LINK_TRAINING_STATUS_FAILURE_SINK) ? \
DisplayPortAltModeStatus::NOT_CAPABLE : DisplayPortAltModeStatus::CAPABLE;
}
return dpData;
}
/* DisplayPort Helper Functions End */
// Only care about first port which must support DisplayPortAltMode
Status queryDisplayPortStatus(android::hardware::usb::Usb *usb,
std::vector<PortStatus> *currentPortStatus) {
string hpd, pinAssign, linkStatus, vdo;
string path;
AltModeData::DisplayPortAltModeData dpData;
if (usb->getDisplayPortUsbPathHelper(&path) == Status::ERROR) {
(*currentPortStatus)[0].supportedAltModes.push_back(dpData);
return Status::SUCCESS;
}
usb->readDisplayPortAttribute("hpd", path, &hpd);
usb->readDisplayPortAttribute("pin_assignment", path, &pinAssign);
usb->readDisplayPortAttribute("vdo", path, &vdo);
usb->readDisplayPortAttribute("link_status", path, &linkStatus);
// Set DisplayPortAltModeInfo
dpData = constructAltModeData(hpd, pinAssign, linkStatus, vdo);
(*currentPortStatus)[0].supportedAltModes.push_back(dpData);
return Status::SUCCESS;
}
void queryVersionHelper(android::hardware::usb::Usb *usb, void queryVersionHelper(android::hardware::usb::Usb *usb,
std::vector<PortStatus> *currentPortStatus) { std::vector<PortStatus> *currentPortStatus) {
Status status; Status status;
@ -790,7 +911,7 @@ void queryVersionHelper(android::hardware::usb::Usb *usb,
usb->setupDisplayPortPoll(); usb->setupDisplayPortPoll();
} }
pthread_mutex_unlock(&usb->mDisplayPortLock); pthread_mutex_unlock(&usb->mDisplayPortLock);
queryDisplayPortStatus(usb, currentPortStatus);
if (usb->mCallback != NULL) { if (usb->mCallback != NULL) {
ScopedAStatus ret = usb->mCallback->notifyPortStatusChange(*currentPortStatus, ScopedAStatus ret = usb->mCallback->notifyPortStatusChange(*currentPortStatus,
status); status);
@ -1109,6 +1230,30 @@ Status Usb::getDisplayPortUsbPathHelper(string *path) {
return result; return result;
} }
Status Usb::readDisplayPortAttribute(string attribute, string usb_path, string* value) {
string attrPath;
if (!strncmp(attribute.c_str(), "hpd", strlen("hpd")) ||
!strncmp(attribute.c_str(), "pin_assignment", strlen("pin_assignment"))) {
attrPath = usb_path + attribute;
} else if (!strncmp(attribute.c_str(), "link_status", strlen("link_status"))) {
attrPath = string(kDisplayPortDrmPath) + "link_status";
} else if (!strncmp(attribute.c_str(), "vdo", strlen("vdo"))) {
attrPath = usb_path + "/../vdo";
} else {
goto error;
}
// Read Attribute
if(ReadFileToString(attrPath.c_str(), value)) {
return Status::SUCCESS;
}
error:
ALOGE("usbdp: Failed to read Type-C attribute %s", attribute.c_str());
return Status::ERROR;
}
Status Usb::writeDisplayPortAttributeOverride(string attribute, string value) { Status Usb::writeDisplayPortAttributeOverride(string attribute, string value) {
string attrDrmPath; string attrDrmPath;
@ -1206,15 +1351,28 @@ static int displayPortPollOpenFileHelper(const char *file, int flags) {
return fd; return fd;
} }
static int armTimerFdHelper(int fd, int ms) {
struct itimerspec ts;
ts.it_interval.tv_sec = 0;
ts.it_interval.tv_nsec = 0;
ts.it_value.tv_sec = ms / 1000;
ts.it_value.tv_nsec = (ms % 1000) * 1000000;
return timerfd_settime(fd, 0, &ts, NULL);
}
void *displayPortPollWork(void *param) { void *displayPortPollWork(void *param) {
int epoll_fd; int epoll_fd;
struct epoll_event ev_hpd, ev_pin, ev_orientation, ev_eventfd, ev_link; struct epoll_event ev_hpd, ev_pin, ev_orientation, ev_eventfd, ev_link, ev_debounce;
int nevents = 0; int nevents = 0;
int hpd_fd, pin_fd, orientation_fd, link_fd; int hpd_fd, pin_fd, orientation_fd, link_training_status_fd;
int file_flags = O_RDONLY; int file_flags = O_RDONLY;
int epoll_flags; int epoll_flags;
bool orientationSet = false; bool orientationSet = false;
bool pinSet = false; bool pinSet = false;
unsigned long res;
int ret = 0;
string displayPortUsbPath, irqHpdCountPath, hpdPath, pinAssignmentPath, orientationPath; string displayPortUsbPath, irqHpdCountPath, hpdPath, pinAssignmentPath, orientationPath;
string tcpcI2cBus, linkPath; string tcpcI2cBus, linkPath;
::aidl::android::hardware::usb::Usb *usb = (::aidl::android::hardware::usb::Usb *)param; ::aidl::android::hardware::usb::Usb *usb = (::aidl::android::hardware::usb::Usb *)param;
@ -1253,8 +1411,8 @@ void *displayPortPollWork(void *param) {
== -1){ == -1){
goto orientation_fd_error; goto orientation_fd_error;
} }
if ((link_fd = displayPortPollOpenFileHelper(linkPath.c_str(), file_flags)) == -1){ if ((link_training_status_fd = displayPortPollOpenFileHelper(linkPath.c_str(), file_flags)) == -1){
goto link_fd_error; goto link_training_status_fd_error;
} }
// Set epoll_event events and flags // Set epoll_event events and flags
@ -1264,11 +1422,13 @@ void *displayPortPollWork(void *param) {
ev_orientation.events = epoll_flags; ev_orientation.events = epoll_flags;
ev_eventfd.events = epoll_flags; ev_eventfd.events = epoll_flags;
ev_link.events = epoll_flags; ev_link.events = epoll_flags;
ev_debounce.events = epoll_flags;
ev_hpd.data.fd = hpd_fd; ev_hpd.data.fd = hpd_fd;
ev_pin.data.fd = pin_fd; ev_pin.data.fd = pin_fd;
ev_orientation.data.fd = orientation_fd; ev_orientation.data.fd = orientation_fd;
ev_eventfd.data.fd = usb->mDisplayPortEventPipe; ev_eventfd.data.fd = usb->mDisplayPortEventPipe;
ev_link.data.fd = link_fd; ev_link.data.fd = link_training_status_fd;
ev_debounce.data.fd = usb->mDisplayPortDebounceTimer;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, hpd_fd, &ev_hpd) == -1) { if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, hpd_fd, &ev_hpd) == -1) {
ALOGE("usbdp: worker: epoll_ctl failed to add hpd; errno=%d", errno); ALOGE("usbdp: worker: epoll_ctl failed to add hpd; errno=%d", errno);
@ -1282,10 +1442,14 @@ void *displayPortPollWork(void *param) {
ALOGE("usbdp: worker: epoll_ctl failed to add orientation; errno=%d", errno); ALOGE("usbdp: worker: epoll_ctl failed to add orientation; errno=%d", errno);
goto error; goto error;
} }
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, link_fd, &ev_link) == -1) { if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, link_training_status_fd, &ev_link) == -1) {
ALOGE("usbdp: worker: epoll_ctl failed to add link status; errno=%d", errno); ALOGE("usbdp: worker: epoll_ctl failed to add link status; errno=%d", errno);
goto error; goto error;
} }
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, usb->mDisplayPortDebounceTimer, &ev_debounce) == -1) {
ALOGE("usbdp: worker: epoll_ctl failed to add debounce; errno=%d", errno);
goto error;
}
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, usb->mDisplayPortEventPipe, &ev_eventfd) == -1) { if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, usb->mDisplayPortEventPipe, &ev_eventfd) == -1) {
ALOGE("usbdp: worker: epoll_ctl failed to add orientation; errno=%d", errno); ALOGE("usbdp: worker: epoll_ctl failed to add orientation; errno=%d", errno);
goto error; goto error;
@ -1318,16 +1482,28 @@ void *displayPortPollWork(void *param) {
} }
} }
usb->writeDisplayPortAttribute("hpd", hpdPath); usb->writeDisplayPortAttribute("hpd", hpdPath);
armTimerFdHelper(usb->mDisplayPortDebounceTimer, DISPLAYPORT_STATUS_DEBOUNCE_MS);
} else if (events[n].data.fd == pin_fd) { } else if (events[n].data.fd == pin_fd) {
if (usb->writeDisplayPortAttribute("pin_assignment", pinAssignmentPath) == if (usb->writeDisplayPortAttribute("pin_assignment", pinAssignmentPath) ==
Status::SUCCESS) { Status::SUCCESS) {
pinSet = true; pinSet = true;
armTimerFdHelper(usb->mDisplayPortDebounceTimer, DISPLAYPORT_STATUS_DEBOUNCE_MS);
} }
} else if (events[n].data.fd == orientation_fd) { } else if (events[n].data.fd == orientation_fd) {
if (usb->writeDisplayPortAttribute("orientation", orientationPath) == if (usb->writeDisplayPortAttribute("orientation", orientationPath) ==
Status::SUCCESS) { Status::SUCCESS) {
orientationSet = true; orientationSet = true;
armTimerFdHelper(usb->mDisplayPortDebounceTimer, DISPLAYPORT_STATUS_DEBOUNCE_MS);
} }
} else if (events[n].data.fd == link_training_status_fd) {
armTimerFdHelper(usb->mDisplayPortDebounceTimer, DISPLAYPORT_STATUS_DEBOUNCE_MS);
} else if (events[n].data.fd == usb->mDisplayPortDebounceTimer) {
std::vector<PortStatus> currentPortStatus;
ret = read(usb->mDisplayPortDebounceTimer, &res, sizeof(res));
ALOGI("usbdp: dp debounce triggered, val:%lu ret:%d", res, ret);
if (ret < 0)
ALOGE("usbdp: debounce read errno:%d", errno);
queryVersionHelper(usb, &currentPortStatus);
} else if (events[n].data.fd == usb->mDisplayPortEventPipe) { } else if (events[n].data.fd == usb->mDisplayPortEventPipe) {
uint64_t flag = 0; uint64_t flag = 0;
if (!read(usb->mDisplayPortEventPipe, &flag, sizeof(flag))) { if (!read(usb->mDisplayPortEventPipe, &flag, sizeof(flag))) {
@ -1349,14 +1525,15 @@ void *displayPortPollWork(void *param) {
} }
error: error:
close(link_fd); close(link_training_status_fd);
link_fd_error: link_training_status_fd_error:
close(orientation_fd); close(orientation_fd);
orientation_fd_error: orientation_fd_error:
close(pin_fd); close(pin_fd);
pin_fd_error: pin_fd_error:
close(hpd_fd); close(hpd_fd);
hpd_fd_error: hpd_fd_error:
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, usb->mDisplayPortDebounceTimer, &ev_debounce);
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, usb->mDisplayPortEventPipe, &ev_eventfd); epoll_ctl(epoll_fd, EPOLL_CTL_DEL, usb->mDisplayPortEventPipe, &ev_eventfd);
close(epoll_fd); close(epoll_fd);
epoll_fd_error: epoll_fd_error:

View file

@ -29,6 +29,8 @@
// Having a margin of ~3 secs for the directory and other related bookeeping // Having a margin of ~3 secs for the directory and other related bookeeping
// structures created and uvent fired. // structures created and uvent fired.
#define PORT_TYPE_TIMEOUT 8 #define PORT_TYPE_TIMEOUT 8
#define DISPLAYPORT_CAPABILITIES_RECEPTACLE_BIT 6
#define DISPLAYPORT_STATUS_DEBOUNCE_MS 2000
namespace aidl { namespace aidl {
namespace android { namespace android {
@ -57,6 +59,11 @@ constexpr char kGadgetName[] = "11210000.dwc3";
#define VBUS_PATH NEW_UDC_PATH "dwc3_exynos_otg_b_sess" #define VBUS_PATH NEW_UDC_PATH "dwc3_exynos_otg_b_sess"
#define USB_DATA_PATH NEW_UDC_PATH "usb_data_enabled" #define USB_DATA_PATH NEW_UDC_PATH "usb_data_enabled"
#define LINK_TRAINING_STATUS_UNKNOWN "0"
#define LINK_TRAINING_STATUS_SUCCESS "1"
#define LINK_TRAINING_STATUS_FAILURE "2"
#define LINK_TRAINING_STATUS_FAILURE_SINK "3"
#define DISPLAYPORT_SHUTDOWN_CLEAR 0 #define DISPLAYPORT_SHUTDOWN_CLEAR 0
#define DISPLAYPORT_SHUTDOWN_SET 1 #define DISPLAYPORT_SHUTDOWN_SET 1
#define DISPLAYPORT_IRQ_HPD_COUNT_CHECK 3 #define DISPLAYPORT_IRQ_HPD_COUNT_CHECK 3
@ -81,6 +88,7 @@ struct Usb : public BnUsb {
ScopedAStatus resetUsbPort(const string& in_portName, int64_t in_transactionId) override; ScopedAStatus resetUsbPort(const string& in_portName, int64_t in_transactionId) override;
Status getDisplayPortUsbPathHelper(string *path); Status getDisplayPortUsbPathHelper(string *path);
Status readDisplayPortAttribute(string attribute, string usb_path, string* value);
Status writeDisplayPortAttributeOverride(string attribute, string value); Status writeDisplayPortAttributeOverride(string attribute, string value);
Status writeDisplayPortAttribute(string attribute, string usb_path); Status writeDisplayPortAttribute(string attribute, string usb_path);
bool determineDisplayPortRetry(string linkPath, string hpdPath); bool determineDisplayPortRetry(string linkPath, string hpdPath);
@ -121,6 +129,14 @@ struct Usb : public BnUsb {
pthread_mutex_t mDisplayPortLock; pthread_mutex_t mDisplayPortLock;
// eventfd to signal DisplayPort thread // eventfd to signal DisplayPort thread
int mDisplayPortEventPipe; int mDisplayPortEventPipe;
/*
* eventfd to set DisplayPort framework update debounce timer. Debounce timer is necessary for
* 1) allowing enough time for each sysfs node needed to set HPD high in the drm to populate
* 2) preventing multiple IRQs that trigger link training failures from continuously
* sending notifications to the frameworks layer.
*/
int mDisplayPortDebounceTimer;
private: private:
pthread_t mPoll; pthread_t mPoll;
pthread_t mDisplayPortPoll; pthread_t mDisplayPortPoll;