Re: [PATCH v4 6/9] usb: misc: qcom_eud: add host mode coordination
From: Elson Serrao
Date: Tue Jul 14 2026 - 20:40:20 EST
On 7/5/2026 11:46 PM, Peter Chen wrote:
> On 26-05-01 10:06:32, Elson Serrao wrote:
>> EUD functions by presenting itself as a USB device to the host PC for
>> debugging, making it incompatible with USB host mode configurations.
>> Enabling EUD while in host mode can also cause the USB controller to
>> misbehave, as the EUD hub supports only a single upstream-facing port.
>>
>> Handle the following scenarios to prevent these conflicts:
>> 1. Prevent the user from enabling EUD via sysfs when the USB port is in
>> host mode.
>> 2. Automatically disable EUD when the USB port switches to host mode,
>> and re-enable it when exiting host mode.
>>
>> This ensures consistent state management without creating conflicts
>> between the EUD debug hub and the USB controller.
>>
>> Signed-off-by: Elson Serrao <elson.serrao@xxxxxxxxxxxxxxxx>
>> ---
>> drivers/usb/misc/qcom_eud.c | 65 ++++++++++++++++++++++++++++++++++++-
>> 1 file changed, 64 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/usb/misc/qcom_eud.c b/drivers/usb/misc/qcom_eud.c
>> index f656ffc8818a..4734b6307a85 100644
>> --- a/drivers/usb/misc/qcom_eud.c
>> +++ b/drivers/usb/misc/qcom_eud.c
>> @@ -55,12 +55,15 @@ struct eud_chip {
>> struct device *dev;
>> void __iomem *base;
>> struct eud_path *paths[EUD_MAX_PORTS];
>> + /* serializes EUD control operations */
>> + struct mutex state_lock;
>> phys_addr_t mode_mgr;
>> unsigned int int_status;
>> int irq;
>> bool enabled;
>> bool usb_attached;
>> bool phy_enabled;
>> + bool eud_disabled_for_host;
>
> Could just use below two conditions for EUD enable/disable judgement:
>
> Enable:
> (path->curr_role == USB_ROLE_DEVICE) && (chip->enabled == true)
>
> Disable:
> (path->curr_role != USB_ROLE_DEVICE) || (chip->enabled == false)
>
This could work, and we may be able to drop the additional flag.
The only behavioral difference I can see is that EUD would no
longer be re-enabled as part of exiting host mode. Instead, it
would remain disabled until an explicit switch to DEVICE role.
I think this should be fine, since EUD is only usable once a
cable is plugged in and we switch to DEVICE mode anyway. So the
user remains unaware that EUD is hardware-disabled until the
cable is plugged back in.
Let me try this out and make sure there aren't any other corner
cases.
Thanks,
Elson
>
>> u8 port_idx;
>> };
>>
>> @@ -156,17 +159,43 @@ static ssize_t enable_store(struct device *dev,
>> const char *buf, size_t count)
>> {
>> struct eud_chip *chip = dev_get_drvdata(dev);
>> + struct eud_path *path;
>> bool enable;
>> int ret;
>>
>> if (kstrtobool(buf, &enable))
>> return -EINVAL;
>>
>> + guard(mutex)(&chip->state_lock);
>> +
>> /* Skip operation if already in desired state */
>> if (chip->enabled == enable)
>> return count;
>>
>> + /*
>> + * Handle double-disable scenario: User is disabling EUD that was already
>> + * disabled due to host mode. Since the hardware is already disabled, we
>> + * only need to clear the host-disabled flag to prevent unwanted re-enabling
>> + * when exiting host mode. This respects the user's explicit disable request.
>> + */
>> + if (!enable && chip->eud_disabled_for_host) {
>> + chip->eud_disabled_for_host = false;
>> + chip->enabled = false;
>> + return count;
>> + }
>> +
>> if (enable) {
>> + /*
>> + * EUD functions by presenting itself as a USB device to the host PC for
>> + * debugging, making it incompatible with USB host mode configuration.
>> + * Prevent enabling EUD in this configuration to avoid hardware conflicts.
>> + */
>> + path = chip->paths[chip->port_idx];
>> + if (path->curr_role == USB_ROLE_HOST) {
>> + dev_err(chip->dev, "cannot enable EUD: USB port is in host mode\n");
>> + return -EBUSY;
>> + }
>> +
>> ret = enable_eud(chip);
>> if (ret) {
>> dev_err(chip->dev, "failed to enable eud\n");
>> @@ -308,9 +337,41 @@ static irqreturn_t handle_eud_irq_thread(int irq, void *data)
>> static int eud_role_switch_set(struct usb_role_switch *sw, enum usb_role role)
>> {
>> struct eud_path *path = usb_role_switch_get_drvdata(sw);
>> + struct eud_chip *chip = path->chip;
>> int ret;
>>
>> - /* Forward the role request to the USB controller */
>> + guard(mutex)(&chip->state_lock);
>> +
>> + /*
>> + * EUD must be disabled when USB operates in host mode. EUD functions by
>> + * presenting itself as a USB device to the host PC for debugging, making
>> + * it incompatible with host mode configuration.
>> + *
>> + * chip->enabled preserves user's sysfs configuration and is not modified
>> + * during host mode transitions to maintain user intent.
>> + */
>> +
>> + /* Only act if EUD is enabled and this is the active path */
>> + if (chip->enabled && path->num == chip->port_idx) {
>> + if (role == USB_ROLE_HOST && !chip->eud_disabled_for_host) {
>> + ret = disable_eud(chip);
>> + if (ret) {
>> + dev_err(chip->dev, "failed to disable EUD for host mode: %d\n",
>> + ret);
>> + return ret;
>> + }
>> + chip->eud_disabled_for_host = true;
>> + } else if (role != USB_ROLE_HOST && chip->eud_disabled_for_host) {
>> + ret = enable_eud(chip);
>> + if (ret) {
>> + dev_err(chip->dev, "failed to re-enable EUD after host mode: %d\n",
>> + ret);
>> + return ret;
>> + }
>> + chip->eud_disabled_for_host = false;
>> + }
>> + }
>> +
>> ret = usb_role_switch_set_role(path->controller_sw, role);
>> if (ret) {
>> dev_err(path->chip->dev, "failed to set role %s for port %u: %d\n",
>> @@ -424,6 +485,8 @@ static int eud_probe(struct platform_device *pdev)
>>
>> chip->dev = &pdev->dev;
>>
>> + mutex_init(&chip->state_lock);
>> +
>> for_each_child_of_node_scoped(np, child) {
>> ret = eud_init_path(chip, child);
>> if (ret)
>> --
>> 2.34.1
>>
>>
>