usb: reattempt to enter displayport alt mode if driver entry process fails
In the kernel, it is possible for the DisplayPort Alt Mode driver to queue an Enter Mode message to the tcpm and have that message be interupted by a Power Role or Vconn swap, which results in the Port Partner never entering Alt Mode. Add a debounce that checks to make sure that the port partner enters Alt Mode when DisplayPort Alt Mode is active on the port. On trigger, reattempt to send Enter Mode through the tcpm up to 2 times. Test: Manual test on device - put device into Preferred Source role, test to see if Alt Mode reentry triggers when original entry is interrupted by PR Swap from monitor. Bug: 308383356 Change-Id: I96563c9900a01e428850e4873371bcdb0225aa07 Signed-off-by: RD Babiera <rdbabiera@google.com>
This commit is contained in:
parent
78a70da442
commit
04d1e94d10
2 changed files with 74 additions and 3 deletions
|
@ -560,6 +560,11 @@ Usb::Usb()
|
||||||
ALOGE("mDisplayPortDebounceTimer timerfd failed: %s", strerror(errno));
|
ALOGE("mDisplayPortDebounceTimer timerfd failed: %s", strerror(errno));
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
mDisplayPortActivateTimer = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
|
||||||
|
if (mDisplayPortActivateTimer == -1) {
|
||||||
|
ALOGE("mDisplayPortActivateTimer 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,
|
||||||
|
@ -1721,6 +1726,10 @@ static int displayPortPollOpenFileHelper(const char *file, int flags) {
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* armTimerFdHelper - Sets timerfd (fd) to trigger after (ms) milliseconds.
|
||||||
|
* Setting ms to 0 disarms the timer.
|
||||||
|
*/
|
||||||
static int armTimerFdHelper(int fd, int ms) {
|
static int armTimerFdHelper(int fd, int ms) {
|
||||||
struct itimerspec ts;
|
struct itimerspec ts;
|
||||||
|
|
||||||
|
@ -1733,23 +1742,31 @@ static int armTimerFdHelper(int fd, int ms) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void *displayPortPollWork(void *param) {
|
void *displayPortPollWork(void *param) {
|
||||||
|
/* USB Payload */
|
||||||
|
::aidl::android::hardware::usb::Usb *usb = (::aidl::android::hardware::usb::Usb *)param;
|
||||||
|
/* Epoll fields */
|
||||||
int epoll_fd;
|
int epoll_fd;
|
||||||
struct epoll_event ev_hpd, ev_pin, ev_orientation, ev_eventfd, ev_link, ev_debounce;
|
struct epoll_event ev_hpd, ev_pin, ev_orientation, ev_eventfd, ev_link, ev_debounce;
|
||||||
|
struct epoll_event ev_activate;
|
||||||
int nevents = 0;
|
int nevents = 0;
|
||||||
int hpd_fd, pin_fd, orientation_fd, link_training_status_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;
|
||||||
|
/* DisplayPort link statuses */
|
||||||
bool orientationSet = false;
|
bool orientationSet = false;
|
||||||
bool pinSet = false;
|
bool pinSet = false;
|
||||||
|
int activateRetryCount = 0;
|
||||||
unsigned long res;
|
unsigned long res;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
/* File paths */
|
||||||
string displayPortUsbPath, irqHpdCountPath, hpdPath, pinAssignmentPath, orientationPath;
|
string displayPortUsbPath, irqHpdCountPath, hpdPath, pinAssignmentPath, orientationPath;
|
||||||
string tcpcI2cBus, linkPath;
|
string tcpcI2cBus, linkPath, partnerActivePath, portActivePath;
|
||||||
::aidl::android::hardware::usb::Usb *usb = (::aidl::android::hardware::usb::Usb *)param;
|
|
||||||
|
|
||||||
usb->mDisplayPortPollRunning = true;
|
usb->mDisplayPortPollRunning = true;
|
||||||
usb->mDisplayPortPollStarting = false;
|
usb->mDisplayPortPollStarting = false;
|
||||||
|
|
||||||
|
/*---------- Setup ----------*/
|
||||||
|
|
||||||
if (usb->getDisplayPortUsbPathHelper(&displayPortUsbPath) == Status::ERROR) {
|
if (usb->getDisplayPortUsbPathHelper(&displayPortUsbPath) == Status::ERROR) {
|
||||||
ALOGE("usbdp: worker: could not locate usb displayport directory");
|
ALOGE("usbdp: worker: could not locate usb displayport directory");
|
||||||
goto usb_path_error;
|
goto usb_path_error;
|
||||||
|
@ -1761,6 +1778,9 @@ void *displayPortPollWork(void *param) {
|
||||||
orientationPath = "/sys/class/typec/port0/orientation";
|
orientationPath = "/sys/class/typec/port0/orientation";
|
||||||
linkPath = string(kDisplayPortDrmPath) + "link_status";
|
linkPath = string(kDisplayPortDrmPath) + "link_status";
|
||||||
|
|
||||||
|
partnerActivePath = displayPortUsbPath + "../mode1/active";
|
||||||
|
portActivePath = "/sys/class/typec/port0/port0.0/mode1/active";
|
||||||
|
|
||||||
getI2cBusHelper(&tcpcI2cBus);
|
getI2cBusHelper(&tcpcI2cBus);
|
||||||
irqHpdCountPath = kI2CPath + tcpcI2cBus + "/" + tcpcI2cBus + kIrqHpdCounPath;
|
irqHpdCountPath = kI2CPath + tcpcI2cBus + "/" + tcpcI2cBus + kIrqHpdCounPath;
|
||||||
ALOGI("usbdp: worker: irqHpdCountPath:%s", irqHpdCountPath.c_str());
|
ALOGI("usbdp: worker: irqHpdCountPath:%s", irqHpdCountPath.c_str());
|
||||||
|
@ -1793,12 +1813,15 @@ void *displayPortPollWork(void *param) {
|
||||||
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_debounce.events = epoll_flags;
|
||||||
|
ev_activate.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_training_status_fd;
|
ev_link.data.fd = link_training_status_fd;
|
||||||
ev_debounce.data.fd = usb->mDisplayPortDebounceTimer;
|
ev_debounce.data.fd = usb->mDisplayPortDebounceTimer;
|
||||||
|
ev_activate.data.fd = usb->mDisplayPortActivateTimer;
|
||||||
|
|
||||||
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);
|
||||||
|
@ -1817,7 +1840,11 @@ void *displayPortPollWork(void *param) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, usb->mDisplayPortDebounceTimer, &ev_debounce) == -1) {
|
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);
|
ALOGE("usbdp: worker: epoll_ctl failed to add framework update debounce; errno=%d", errno);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, usb->mDisplayPortActivateTimer, &ev_activate) == -1) {
|
||||||
|
ALOGE("usbdp: worker: epoll_ctl failed to add activate debounce; errno=%d", errno);
|
||||||
goto error;
|
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) {
|
||||||
|
@ -1825,6 +1852,9 @@ void *displayPortPollWork(void *param) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Arm timer to see if DisplayPort Alt Mode Activates */
|
||||||
|
armTimerFdHelper(usb->mDisplayPortActivateTimer, DISPLAYPORT_ACTIVATE_DEBOUNCE_MS);
|
||||||
|
|
||||||
while (!destroyDisplayPortThread) {
|
while (!destroyDisplayPortThread) {
|
||||||
struct epoll_event events[64];
|
struct epoll_event events[64];
|
||||||
|
|
||||||
|
@ -1874,6 +1904,33 @@ void *displayPortPollWork(void *param) {
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
ALOGE("usbdp: debounce read errno:%d", errno);
|
ALOGE("usbdp: debounce read errno:%d", errno);
|
||||||
queryVersionHelper(usb, ¤tPortStatus);
|
queryVersionHelper(usb, ¤tPortStatus);
|
||||||
|
} else if (events[n].data.fd == usb->mDisplayPortActivateTimer) {
|
||||||
|
string activePartner, activePort;
|
||||||
|
|
||||||
|
if (ReadFileToString(partnerActivePath.c_str(), &activePartner) &&
|
||||||
|
ReadFileToString(portActivePath.c_str(), &activePort)) {
|
||||||
|
// Retry activate signal when DisplayPort Alt Mode is active on port but not
|
||||||
|
// partner.
|
||||||
|
if (!strncmp(activePartner.c_str(), "no", strlen("no")) &&
|
||||||
|
!strncmp(activePort.c_str(), "yes", strlen("yes")) &&
|
||||||
|
activateRetryCount < DISPLAYPORT_ACTIVATE_MAX_RETRIES) {
|
||||||
|
if (!WriteStringToFile("1", partnerActivePath)) {
|
||||||
|
ALOGE("usbdp: Failed to activate port partner Alt Mode");
|
||||||
|
} else {
|
||||||
|
ALOGI("usbdp: Attempting to activate port partner Alt Mode");
|
||||||
|
}
|
||||||
|
activateRetryCount++;
|
||||||
|
armTimerFdHelper(usb->mDisplayPortActivateTimer,
|
||||||
|
DISPLAYPORT_ACTIVATE_DEBOUNCE_MS);
|
||||||
|
} else {
|
||||||
|
ALOGI("usbdp: DisplayPort Alt Mode is active, or disabled on port");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
activateRetryCount++;
|
||||||
|
armTimerFdHelper(usb->mDisplayPortActivateTimer,
|
||||||
|
DISPLAYPORT_ACTIVATE_DEBOUNCE_MS);
|
||||||
|
ALOGE("usbdp: Failed to read active state from port or partner");
|
||||||
|
}
|
||||||
} 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))) {
|
||||||
|
@ -1895,6 +1952,8 @@ void *displayPortPollWork(void *param) {
|
||||||
}
|
}
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
/* Need to disarm so new threads don't get old event */
|
||||||
|
armTimerFdHelper(usb->mDisplayPortActivateTimer, 0);
|
||||||
close(link_training_status_fd);
|
close(link_training_status_fd);
|
||||||
link_training_status_fd_error:
|
link_training_status_fd_error:
|
||||||
close(orientation_fd);
|
close(orientation_fd);
|
||||||
|
@ -1904,6 +1963,7 @@ 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->mDisplayPortDebounceTimer, &ev_debounce);
|
||||||
|
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, usb->mDisplayPortActivateTimer, &ev_activate);
|
||||||
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:
|
||||||
|
|
|
@ -32,6 +32,13 @@
|
||||||
#define PORT_TYPE_TIMEOUT 8
|
#define PORT_TYPE_TIMEOUT 8
|
||||||
#define DISPLAYPORT_CAPABILITIES_RECEPTACLE_BIT 6
|
#define DISPLAYPORT_CAPABILITIES_RECEPTACLE_BIT 6
|
||||||
#define DISPLAYPORT_STATUS_DEBOUNCE_MS 2000
|
#define DISPLAYPORT_STATUS_DEBOUNCE_MS 2000
|
||||||
|
/*
|
||||||
|
* Type-C HAL should wait 2 seconds to reattempt DisplayPort Alt Mode entry to
|
||||||
|
* allow the port and port partner to settle Role Swaps.
|
||||||
|
*/
|
||||||
|
#define DISPLAYPORT_ACTIVATE_DEBOUNCE_MS 2000
|
||||||
|
// Number of times the HAL should reattempt to enter DisplayPort Alt Mode
|
||||||
|
#define DISPLAYPORT_ACTIVATE_MAX_RETRIES 2
|
||||||
|
|
||||||
namespace aidl {
|
namespace aidl {
|
||||||
namespace android {
|
namespace android {
|
||||||
|
@ -173,6 +180,10 @@ struct Usb : public BnUsb {
|
||||||
* sending notifications to the frameworks layer.
|
* sending notifications to the frameworks layer.
|
||||||
*/
|
*/
|
||||||
int mDisplayPortDebounceTimer;
|
int mDisplayPortDebounceTimer;
|
||||||
|
/*
|
||||||
|
* eventfd to monitor whether a connection results in DisplayPort Alt Mode activating.
|
||||||
|
*/
|
||||||
|
int mDisplayPortActivateTimer;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
pthread_t mPoll;
|
pthread_t mPoll;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue