Support GL852G USB hub JK level tuning

The JK level setting is configured to the hub via a vendor USB
command whenever the hub is enabled.
The shell command can be used to change the JK setting for testing
purpose, but the values take effect next time the hub is enumerated.

Bug: 261923350
Bug: 340665903
Test: adb shell cmd android.hardware.usb.IUsb/default hub-vendor-cmd
<hex wValue> <hex wIndex>
Test: verify on user/userdebug builds the vendor command is triggered
      in the following scenarios.
      1. boot with Kolan docked
      2. undock and dock Kolan
      3. kill android.hardware.usb.IUsb/default

Change-Id: I8873695c42f362138d99b45ffa2ef637c357202b
This commit is contained in:
Roy Luo 2023-03-17 00:44:01 +00:00
parent b058b0088f
commit fd704fdcfb
2 changed files with 88 additions and 80 deletions

View file

@ -126,6 +126,9 @@ AltModeData::DisplayPortAltModeData constructAltModeData(string hpd, string pin_
#define GL852G_PRODUCT_ID1 0x0608
#define GL852G_PRODUCT_ID2 0x0610
#define GL852G_VENDOR_CMD_REQ 0xe3
// GL852G port 1 and port 2 JK level default settings
#define GL852G_VENDOR_CMD_VALUE_DEFAULT 0x0008
#define GL852G_VENDOR_CMD_INDEX_DEFAULT 0x0404
ScopedAStatus Usb::enableUsbData(const string& in_portName, bool in_enable,
int64_t in_transactionId) {
@ -521,6 +524,61 @@ void updatePortStatus(android::hardware::usb::Usb *usb) {
queryVersionHelper(usb, &currentPortStatus);
}
static int usbDeviceRemoved(const char *devname, void* client_data) {
return 0;
}
static int usbDeviceAdded(const char *devname, void* client_data) {
uint16_t vendorId, productId;
struct usb_device *device;
::aidl::android::hardware::usb::Usb *usb;
int value, index;
device = usb_device_open(devname);
if (!device) {
ALOGE("usb_device_open failed\n");
return 0;
}
usb = (::aidl::android::hardware::usb::Usb *)client_data;
value = usb->mUsbHubVendorCmdValue;
index = usb->mUsbHubVendorCmdIndex;
// The vendor cmd only applies to USB Hubs of Genesys Logic, Inc.
// The request field of vendor cmd is fixed to 0xe3.
vendorId = usb_device_get_vendor_id(device);
productId = usb_device_get_product_id(device);
if (vendorId == GL852G_VENDOR_ID &&
(productId == GL852G_PRODUCT_ID1 || productId == GL852G_PRODUCT_ID2)) {
int ret = usb_device_control_transfer(device,
USB_DIR_OUT | USB_TYPE_VENDOR, GL852G_VENDOR_CMD_REQ, value, index,
NULL, 0, CTRL_TRANSFER_TIMEOUT_MSEC);
ALOGI("USB hub vendor cmd %s (wValue 0x%x, wIndex 0x%x, return %d)\n",
ret? "failed" : "succeeded", value, index, ret);
}
usb_device_close(device);
return 0;
}
void *usbHostWork(void *param) {
struct usb_host_context *ctx;
ALOGI("creating USB host thread\n");
ctx = usb_host_init();
if (!ctx) {
ALOGE("usb_host_init failed\n");
return NULL;
}
// This will never return, it will keep monitoring USB sysfs inotify events
usb_host_run(ctx, usbDeviceAdded, usbDeviceRemoved, NULL, param);
return NULL;
}
Usb::Usb()
: mLock(PTHREAD_MUTEX_INITIALIZER),
mRoleSwitchLock(PTHREAD_MUTEX_INITIALIZER),
@ -542,7 +600,9 @@ Usb::Usb()
mDisplayPortPollRunning(false),
mDisplayPortPollStarting(false),
mDisplayPortCVLock(PTHREAD_MUTEX_INITIALIZER),
mDisplayPortLock(PTHREAD_MUTEX_INITIALIZER) {
mDisplayPortLock(PTHREAD_MUTEX_INITIALIZER),
mUsbHubVendorCmdValue(GL852G_VENDOR_CMD_VALUE_DEFAULT),
mUsbHubVendorCmdIndex(GL852G_VENDOR_CMD_INDEX_DEFAULT) {
pthread_condattr_t attr;
if (pthread_condattr_init(&attr)) {
ALOGE("pthread_condattr_init failed: %s", strerror(errno));
@ -579,6 +639,10 @@ Usb::Usb()
ALOGE("mDisplayPortActivateTimer timerfd failed: %s", strerror(errno));
abort();
}
if (pthread_create(&mUsbHost, NULL, usbHostWork, this)) {
ALOGE("pthread creation failed %d\n", errno);
abort();
}
ALOGI("feature flag enable_usb_data_compliance_warning: %d",
usb_flags::enable_usb_data_compliance_warning());
@ -1950,82 +2014,6 @@ void Usb::shutdownDisplayPortPoll(bool force) {
}
}
struct hub_vendor_cmd {
// wValue filed of standard device request
int value;
// wIndex field of standard device request
int index;
// Output pipe to shell command
int out;
// Whether the hub is found
bool found;
};
static int usbDeviceAdded(const char *devname, void* client_data) {
struct hub_vendor_cmd *cmd = (struct hub_vendor_cmd *)client_data;
uint16_t vendorId, productId;
struct usb_device *device = usb_device_open(devname);
if (!device) {
dprintf(cmd->out, "usb_device_open failed\n");
return 0;
}
// The vendor cmd only applies to USB Hubs of Genesys Logic, Inc.
// The request field of vendor cmd is fixed to 0xe3.
vendorId = usb_device_get_vendor_id(device);
productId = usb_device_get_product_id(device);
if (vendorId == GL852G_VENDOR_ID &&
(productId == GL852G_PRODUCT_ID1 || productId == GL852G_PRODUCT_ID2)) {
int ret = usb_device_control_transfer(
device, USB_DIR_OUT | USB_TYPE_VENDOR,
GL852G_VENDOR_CMD_REQ, cmd->value, cmd->index, NULL, 0,
CTRL_TRANSFER_TIMEOUT_MSEC);
dprintf(cmd->out, "Vendor cmd %s (wValue %x, wIndex %x, return %d)\n",
ret? "failed" : "succeeded", cmd->value, cmd->index, ret);
// Stop iterating through usb devices once the hub is found.
cmd->found = true;
return 1;
}
return 0;
}
static int usbDiscoveryDone(void *client_data)
{
struct hub_vendor_cmd *cmd = (struct hub_vendor_cmd *)client_data;
dprintf(cmd->out, "Done USB discovery, hub %s found\n",
cmd->found ? "is" : "not");
return 1;
}
static status_t sendHubVendorCmd(int out, Vector<String8>& args) {
if (args.size() < 3) {
dprintf(out, "Incorrect number of argument supplied\n");
return ::android::UNKNOWN_ERROR;
}
struct hub_vendor_cmd cmd = {
.value = std::stoi(args[1].c_str(), NULL, 16),
.index = std::stoi(args[2].c_str(), NULL, 16),
.out = out,
.found = false
};
struct usb_host_context *ctx;
ctx = usb_host_init();
if (!ctx) {
dprintf(out, "usb_host_init failed\n");
return ::android::UNKNOWN_ERROR;
}
usb_host_run(ctx, usbDeviceAdded, NULL, usbDiscoveryDone, &cmd);
usb_host_cleanup(ctx);
return ::android::NO_ERROR;
}
status_t Usb::handleShellCommand(int in, int out, int err, const char** argv,
uint32_t argc) {
uid_t uid = AIBinder_getCallingUid();
@ -2041,13 +2029,28 @@ status_t Usb::handleShellCommand(int in, int out, int err, const char** argv,
if (argc >= 1) {
if (!utf8Args[0].compare(String8("hub-vendor-cmd"))) {
return sendHubVendorCmd(out, utf8Args);
if (utf8Args.size() < 3) {
dprintf(out, "Incorrect number of argument supplied\n");
return ::android::UNKNOWN_ERROR;
}
int value, index;
if (!::android::base::ParseInt(utf8Args[1].c_str(), &value) ||
!::android::base::ParseInt(utf8Args[2].c_str(), &index)) {
dprintf(out, "Fail to parse arguments\n");
return ::android::UNKNOWN_ERROR;
}
mUsbHubVendorCmdValue = value;
mUsbHubVendorCmdIndex = index;
ALOGI("USB hub vendor cmd update (wValue 0x%x, wIndex 0x%x)\n",
mUsbHubVendorCmdValue, mUsbHubVendorCmdIndex);
return ::android::NO_ERROR;
}
}
dprintf(out, "usage: adb shell cmd hub-vendor-cmd VALUE INDEX\n"
" VALUE wValue field in hex format, e.g. f321\n"
" INDEX wIndex field in hex format, e.g. f321\n");
" VALUE wValue field in hex format, e.g. 0xf321\n"
" INDEX wIndex field in hex format, e.g. 0xf321\n"
" The settings take effect next time the hub is enabled\n");
return ::android::NO_ERROR;
}

View file

@ -167,10 +167,15 @@ struct Usb : public BnUsb {
*/
bool mPartnerSupportsDisplayPort;
// Usb hub vendor command settings for JK level tuning
int mUsbHubVendorCmdValue;
int mUsbHubVendorCmdIndex;
private:
pthread_t mPoll;
pthread_t mDisplayPortPoll;
pthread_t mDisplayPortShutdownHelper;
pthread_t mUsbHost;
};
} // namespace usb