Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion src/windows/wdfserial/QCMAIN.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ typedef struct _DEVICE_CONTEXT
ULONG DebugLevel;
UCHAR UsbDeviceType;
USHORT InterfaceIndex;
UCHAR InterfaceProtocol;
DEVICE_TYPE FdoDeviceType;

KEVENT TimeoutEvent;
Expand All @@ -258,7 +259,6 @@ typedef struct _DEVICE_CONTEXT
#endif // QCUSB_MUX_PROTOCOL

//QCPNP_RetrieveServiceConfig
BOOLEAN InServiceSelectiveSuspension;
ULONG SelectiveSuspendIdleTime;
BOOLEAN SelectiveSuspendInMiliSeconds;
WDF_POWER_POLICY_S0_IDLE_CAPABILITIES AssignedIdleCaps;
Expand Down Expand Up @@ -361,6 +361,20 @@ WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(REQUEST_CONTEXT, QCReqGetContext)
#define QCUSB_DEV_FUNC_VI 0x04
#define QCUSB_DEV_FUNC_UNDEF 0xFFFFFFFF

// USB interface bInterfaceProtocol values used by Qualcomm devices.
#define DEV_PROTOCOL_UNKNOWN 0x00
#define DEV_PROTOCOL_SAHARA 0x10
#define DEV_PROTOCOL_FIREHOSE 0x20
#define DEV_PROTOCOL_DIAG 0x30
#define DEV_PROTOCOL_DUN 0x40

// Helpers that classify a bInterfaceProtocol value by its high-nibble protocol family.
#define DEV_PROTOCOL_GROUP(p) ((UCHAR)((p) & 0xF0))
#define IS_DEV_PROTOCOL_SAHARA(p) (DEV_PROTOCOL_GROUP(p) == DEV_PROTOCOL_SAHARA)
#define IS_DEV_PROTOCOL_FIREHOSE(p) (DEV_PROTOCOL_GROUP(p) == DEV_PROTOCOL_FIREHOSE)
#define IS_DEV_PROTOCOL_DIAG(p) (DEV_PROTOCOL_GROUP(p) == DEV_PROTOCOL_DIAG)
#define IS_DEV_PROTOCOL_DUN(p) (DEV_PROTOCOL_GROUP(p) == DEV_PROTOCOL_DUN)

// Debug levels
#define QCSER_DBG_LEVEL_FORCE 0x0
#define QCSER_DBG_LEVEL_CRITICAL 0x1
Expand Down
165 changes: 46 additions & 119 deletions src/windows/wdfserial/QCPNP.c
Original file line number Diff line number Diff line change
Expand Up @@ -1603,7 +1603,8 @@ NTSTATUS QCPNP_EvtDevicePrepareHardware
usbInterfaceDesc.bInterfaceClass << 8 |
usbInterfaceDesc.bAlternateSetting << 16 |
usbInterfaceDesc.bInterfaceNumber << 24;
pDevContext->InterfaceIndex = usbInterfaceDesc.bInterfaceNumber;
pDevContext->InterfaceIndex = usbInterfaceDesc.bInterfaceNumber;
pDevContext->InterfaceProtocol = usbInterfaceDesc.bInterfaceProtocol;
status = QCMAIN_SetDriverRegistryDword(VEN_DEV_PROTOC, ifProtocol, pDevContext);

QCPNP_SetFunctionProtocol(pDevContext, ifProtocol);
Expand All @@ -1612,7 +1613,7 @@ NTSTATUS QCPNP_EvtDevicePrepareHardware
(
QCSER_DBG_MASK_READ,
QCSER_DBG_LEVEL_DETAIL,
("<%ws> QCPNP_EvtDevicePrepareHardware set interface protocol: %lu, status: 0x%x\n", pDevContext->PortName, ifProtocol, status)
("<%ws> QCPNP_EvtDevicePrepareHardware set interface protocol: 0x%x, status: 0x%x\n", pDevContext->PortName, usbInterfaceDesc.bInterfaceProtocol, status)
);
} // End update registry settings

Expand Down Expand Up @@ -1673,6 +1674,21 @@ NTSTATUS QCPNP_EvtDevicePrepareHardware
goto exit;
}

// For SAHARA or FIREHOSE devices, selective suspend is disabled by default
if (IS_DEV_PROTOCOL_SAHARA(pDevContext->InterfaceProtocol) ||
IS_DEV_PROTOCOL_FIREHOSE(pDevContext->InterfaceProtocol) ||
(pDevContext->DeviceFunction == QCUSB_DEV_FUNC_LPC))
{
QCSER_DbgPrint
(
QCSER_DBG_MASK_POWER,
QCSER_DBG_LEVEL_TRACE,
("<%ws> QCPNP_EvtDevicePrepareHardware selective suspend disabled for SAHARA/FIREHOSE and LPC devices\n",
pDevContext->PortName)
);
pDevContext->PowerManagementEnabled = FALSE;
}

// Setup usb selective suspend
status = QCPNP_EnableSelectiveSuspend(Device);
if (!NT_SUCCESS(status))
Expand Down Expand Up @@ -2071,64 +2087,46 @@ NTSTATUS QCPNP_EnableSelectiveSuspend
("<%ws> QCPNP_EnableSelectiveSuspend\n", pDevContext->PortName)
);

#ifdef QCUSB_MUX_PROTOCOL
if (pDevContext->DeviceFunction == QCUSB_DEV_FUNC_LPC)
idleSettings.IdleTimeout = pDevContext->SelectiveSuspendIdleTime;
#ifdef POFX_SUPPORT
idleSettings.IdleTimeoutType = SystemManagedIdleTimeoutWithHint;
#endif
if (idleSettings.IdleTimeout == 0)
{
QCSER_DbgPrint
(
QCSER_DBG_MASK_POWER,
QCSER_DBG_LEVEL_TRACE,
("<%ws> QCPNP_EnableSelectiveSuspend LPC deivce found, selective suspend disabled\n", pDevContext->PortName)
);

// prevent sending further control packets
// registry not set, ss is disabled
idleSettings.Enabled = WdfFalse;
idleSettings.IdleCaps = IdleCannotWakeFromS0;
idleSettings.UserControlOfIdleSettings = IdleDoNotAllowUserControl;
status = WdfDeviceAssignS0IdleSettings(Device, &idleSettings);
}
else
#endif
{
idleSettings.UserControlOfIdleSettings = IdleAllowUserControl;
idleSettings.IdleTimeout = pDevContext->SelectiveSuspendIdleTime;
#ifdef POFX_SUPPORT
idleSettings.IdleTimeoutType = SystemManagedIdleTimeoutWithHint;
#endif
if (idleSettings.IdleTimeout == 0)
if (pDevContext->SelectiveSuspendInMiliSeconds == FALSE)
{
// registry not set, ss is disabled
idleSettings.Enabled = WdfFalse;
idleSettings.IdleCaps = IdleCannotWakeFromS0;
status = WdfDeviceAssignS0IdleSettings(Device, &idleSettings);
idleSettings.IdleTimeout *= 1000;
}
else
idleSettings.Enabled = pDevContext->PowerManagementEnabled ? WdfTrue : WdfFalse;
status = WdfDeviceAssignS0IdleSettings(Device, &idleSettings);
if (status == STATUS_POWER_STATE_INVALID)
{
if (pDevContext->SelectiveSuspendInMiliSeconds == FALSE)
{
idleSettings.IdleTimeout *= 1000;
}
idleSettings.Enabled = WdfTrue; // explicitly enable SS (overrides any user/registry disable)
// bus driver reports the device cannot wakeup itself
QCSER_DbgPrint
(
QCSER_DBG_MASK_POWER,
QCSER_DBG_LEVEL_TRACE,
("<%ws> QCPNP_EnableSelectiveSuspend device reported cannot wake from idle\n", pDevContext->PortName)
);
idleSettings.IdleCaps = IdleCannotWakeFromS0;
status = WdfDeviceAssignS0IdleSettings(Device, &idleSettings);
if (status == STATUS_POWER_STATE_INVALID)
{
// bus driver reports the device cannot wakeup itself
QCSER_DbgPrint
(
QCSER_DBG_MASK_POWER,
QCSER_DBG_LEVEL_TRACE,
("<%ws> QCPNP_EnableSelectiveSuspend device reported cannot wake from idle\n", pDevContext->PortName)
);
idleSettings.IdleCaps = IdleCannotWakeFromS0;
status = WdfDeviceAssignS0IdleSettings(Device, &idleSettings);
}
}
QCSER_DbgPrint
(
QCSER_DBG_MASK_POWER,
QCSER_DBG_LEVEL_DETAIL,
("<%ws> QCPNP_EnableSelectiveSuspend timeout: %lu, status: 0x%x\n", pDevContext->PortName, idleSettings.IdleTimeout, status)
);
}
QCSER_DbgPrint
(
QCSER_DBG_MASK_POWER,
QCSER_DBG_LEVEL_DETAIL,
("<%ws> QCPNP_EnableSelectiveSuspend timeout: %lu, status: 0x%x\n", pDevContext->PortName, idleSettings.IdleTimeout, status)
);

pDevContext->AssignedIdleCaps = idleSettings.IdleCaps;

Expand Down Expand Up @@ -3849,15 +3847,6 @@ VOID QCPNP_RetrieveServiceConfig(PDEVICE_CONTEXT pDevContext)

if (status == STATUS_SUCCESS)
{
if (QCUTIL_IsHighSpeedDevice(pDevContext) == TRUE)
{
pDevContext->InServiceSelectiveSuspension = TRUE;
}
else
{
pDevContext->InServiceSelectiveSuspension = ((selectiveSuspendIdleTime >> 31) != 0);
}

selectiveSuspendInMili = selectiveSuspendIdleTime & 0x40000000;

selectiveSuspendIdleTime &= 0x00FFFFFF;
Expand Down Expand Up @@ -3895,13 +3884,10 @@ VOID QCPNP_RetrieveServiceConfig(PDEVICE_CONTEXT pDevContext)
(
QCSER_DBG_MASK_READ,
QCSER_DBG_LEVEL_ERROR,
("<%ws> QCPNP_RetrieveServiceConfig: new selective suspend idle time=%us(%u)\n",
pDevContext->PortName, selectiveSuspendIdleTime,
pDevContext->InServiceSelectiveSuspension)
("<%ws> QCPNP_RetrieveServiceConfig: new selective suspend idle time=%us\n",
pDevContext->PortName, selectiveSuspendIdleTime)
);
pDevContext->SelectiveSuspendIdleTime = selectiveSuspendIdleTime;
QCPWR_SyncUpWaitWake(pDevContext);
QCPWR_SetIdleTimer(pDevContext, 0, FALSE, 8);
}
}
else
Expand Down Expand Up @@ -3936,65 +3922,6 @@ VOID QCPNP_RetrieveServiceConfig(PDEVICE_CONTEXT pDevContext)
return;
} // QCPNP_RetrieveServiceConfig

/****************************************************************************
*
* function: QCUTIL_IsHighSpeedDevice
*
* purpose: Stub function. Returns FALSE to indicate the device is not a
* high-speed USB device in this implementation.
*
* arguments:pDevContext = pointer to the device context.
*
* returns: BOOLEAN (always FALSE)
*
****************************************************************************/
//Empty Functions to support QCPNP_RetrieveServiceConfig
BOOLEAN QCUTIL_IsHighSpeedDevice(PDEVICE_CONTEXT pDevContext)
{
UNREFERENCED_PARAMETER(pDevContext);
return 0;
} // QCUTIL_IsHighSpeedDevice

/****************************************************************************
*
* function: QCPWR_SyncUpWaitWake
*
* purpose: Stub function. Placeholder for synchronizing wait/wake power
* management state.
*
* arguments:pDevContext = pointer to the device context.
*
* returns: VOID
*
****************************************************************************/
VOID QCPWR_SyncUpWaitWake(PDEVICE_CONTEXT pDevContext)
{
UNREFERENCED_PARAMETER(pDevContext);
}

/****************************************************************************
*
* function: QCPWR_SetIdleTimer
*
* purpose: Stub function. Placeholder for setting the selective suspend
* idle timer.
*
* arguments:pDevContext = pointer to the device context.
* BusyMask = bitmask indicating busy state sources.
* NoReset = if TRUE, do not reset the timer.
* Cookie = caller identifier for debug purposes.
*
* returns: VOID
*
****************************************************************************/
VOID QCPWR_SetIdleTimer(PDEVICE_CONTEXT pDevContext, UCHAR BusyMask, BOOLEAN NoReset, UCHAR Cookie)
{
UNREFERENCED_PARAMETER(pDevContext);
UNREFERENCED_PARAMETER(BusyMask);
UNREFERENCED_PARAMETER(NoReset);
UNREFERENCED_PARAMETER(Cookie);
}

/****************************************************************************
*
* function: QCPNP_GetCID
Expand Down
11 changes: 0 additions & 11 deletions src/windows/wdfserial/QCPNP.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,17 +166,6 @@ NTSTATUS QCPNP_PostVendorRegistryProcess
PDEVICE_CONTEXT pDevContext
);

BOOLEAN QCUTIL_IsHighSpeedDevice
(
PDEVICE_CONTEXT pDevContext
);

//Empty Functions to support QCPNP_RetrieveServiceConfig
BOOLEAN QCUTIL_IsHighSpeedDevice
(
PDEVICE_CONTEXT pDevContext
);

VOID QCPWR_SyncUpWaitWake
(
PDEVICE_CONTEXT pDevContext
Expand Down
Loading