Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds workarounds for wireless quirks of various controller models #364

Merged
merged 7 commits into from
May 25, 2024
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
3 changes: 3 additions & 0 deletions dshidmini.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=giphidgamepaddescriptor/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Guids/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=HIDAPI/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=HRESULT/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=jittering/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=libfmt/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=MSHIDUMDF/@EntryIndexedValue">True</s:Boolean>
Expand All @@ -27,12 +28,14 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=OTEL/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=otlp/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=ourself/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=PDEVICE/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=PXINPUT/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=SCPLIB/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=sdklogs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=sdkresource/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=sdktrace/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Sixaxis/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=VHIDMINI/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=WINERROR/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=XBONE/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=XBOX/@EntryIndexedValue">True</s:Boolean>
Expand Down
41 changes: 34 additions & 7 deletions sys/Device.c
Original file line number Diff line number Diff line change
Expand Up @@ -495,33 +495,60 @@ DsDevice_InitContext(
//
DS3_BTH_SET_LED(outReportBuffer, DS3_LED_OFF);

//
// Output Report Delay
//
#pragma region StartupDelay

WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
attributes.ParentObject = Device;

WDF_TIMER_CONFIG_INIT(
&timerCfg,
DsBth_EvtControlWriteTimerFunc
DsBth_EvtStartupDelayTimerFunc
);

if (!NT_SUCCESS(status = WdfTimerCreate(
&timerCfg,
&attributes,
&pDevCtx->Connection.Bth.Timers.HidOutputReport
&pDevCtx->Connection.Bth.Timers.StartupDelay
)))
{
TraceError(
TRACE_DSBTH,
"WdfTimerCreate (HidOutputReport) failed with status %!STATUS!",
"WdfTimerCreate (StartupDelay) failed with status %!STATUS!",
status
);
EventWriteFailedWithNTStatus(__FUNCTION__, L"WdfTimerCreate", status);
EventWriteFailedWithNTStatus(__FUNCTION__, L"WdfTimerCreate (StartupDelay)", status);
break;
}

#pragma endregion

#pragma region PostStartupTasks

WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
attributes.ParentObject = Device;

WDF_TIMER_CONFIG_INIT(
&timerCfg,
DsBth_EvtPostStartupTimerFunc
);

if (!NT_SUCCESS(status = WdfTimerCreate(
&timerCfg,
&attributes,
&pDevCtx->Connection.Bth.Timers.PostStartupTasks
)))
{
TraceError(
TRACE_DSBTH,
"WdfTimerCreate (PostStartupTasks) failed with status %!STATUS!",
status
);
EventWriteFailedWithNTStatus(__FUNCTION__, L"WdfTimerCreate (PostStartupTasks)", status);
break;
}

#pragma endregion

break;
}

Expand Down
11 changes: 8 additions & 3 deletions sys/Device.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,15 @@ struct BTH_DEVICE_CONTEXT
struct
{
//
// Delayed Output Report Timer
// Delayed startup timer
//
WDFTIMER HidOutputReport;

WDFTIMER StartupDelay;

//
// Post-delayed start timer
//
WDFTIMER PostStartupTasks;

} Timers;

//
Expand Down
6 changes: 3 additions & 3 deletions sys/Ds3.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ NTSTATUS DsUsb_Ds3Init(PDEVICE_CONTEXT Context)
// "Magic packet"
//
UCHAR hidCommandEnable[] = {
0x42, 0x0C, 0x00, 0x00
DS3_USB_COMMON_ENABLE
};

status = USB_SendControlRequest(
Expand Down Expand Up @@ -488,15 +488,15 @@ NTSTATUS DsUsb_Ds3PairToNewHost(WDFDEVICE Device)
//
// Send magic packet over BTH
//
NTSTATUS DsBth_Ds3Init(PDEVICE_CONTEXT Context)
NTSTATUS DsBth_Ds3SixaxisInit(PDEVICE_CONTEXT Context)
{
FuncEntry(TRACE_DS3);

//
// "Magic packet"
//
BYTE hidCommandEnable[] = {
0x53, 0xF4, 0x42, 0x03, 0x00, 0x00
DS3_BTH_SIXAXIS_ENABLE
};

NTSTATUS status;
Expand Down
5 changes: 4 additions & 1 deletion sys/Ds3.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ extern const UCHAR G_Ds3BthHidOutputReport[];
#define DS3_BTH_SET_SMALL_RUMBLE_STRENGTH(_buf_, _str_) ((_buf_)[4] = (_str_) > 0 ? 0x01 : 0x00)
#define DS3_BTH_SET_LARGE_RUMBLE_STRENGTH(_buf_, _str_) ((_buf_)[6] = (_str_))

#define DS3_USB_COMMON_ENABLE 0x42, 0x0C, 0x00, 0x00
#define DS3_BTH_SIXAXIS_ENABLE 0x53, 0xF4, 0x42, 0x03, 0x00, 0x00


VOID DS3_SET_LED_DURATION(
PDEVICE_CONTEXT Context,
Expand Down Expand Up @@ -149,6 +152,6 @@ NTSTATUS DS3_GetActiveRadioAddress(BD_ADDR* Address);

NTSTATUS DsUsb_Ds3PairToNewHost(WDFDEVICE Device);

NTSTATUS DsBth_Ds3Init(PDEVICE_CONTEXT Context);
NTSTATUS DsBth_Ds3SixaxisInit(PDEVICE_CONTEXT Context);

NTSTATUS DsUsb_Ds3RequestHostAddress(WDFDEVICE Device);
132 changes: 132 additions & 0 deletions sys/DsBth.Timers.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#include "Driver.h"
#include "DsBth.Timers.tmh"

//
// Called once delayed after power-up
//
_Use_decl_annotations_
VOID
DsBth_EvtStartupDelayTimerFunc(
WDFTIMER Timer
)
{
NTSTATUS status;

FuncEntry(TRACE_DSBTH);

const PDEVICE_CONTEXT pDevCtx = DeviceGetContext(WdfTimerGetParentObject(Timer));

//
// We have not yet received an input report from the remote device
//
if (pDevCtx->BatteryStatus == DsBatteryStatusNone)
{
DS3_SET_LED_FLAGS(pDevCtx, DS3_LED_OFF);
}
else
{
switch (pDevCtx->BatteryStatus)
{
case DsBatteryStatusCharged:
case DsBatteryStatusFull:
DS3_SET_LED_FLAGS(pDevCtx, DS3_LED_4);
break;
case DsBatteryStatusHigh:
DS3_SET_LED_FLAGS(pDevCtx, DS3_LED_3);
break;
case DsBatteryStatusMedium:
DS3_SET_LED_FLAGS(pDevCtx, DS3_LED_2);
break;
case DsBatteryStatusLow:
case DsBatteryStatusDying:
DS3_SET_LED_FLAGS(pDevCtx, DS3_LED_1);
DS3_SET_LED_DURATION(pDevCtx, 0, 0xFF, 15, 127, 127);
break;
default:
break;
}
}

DS3_SET_SMALL_RUMBLE_DURATION(pDevCtx, 0xFE);
DS3_SET_LARGE_RUMBLE_DURATION(pDevCtx, 0xFE);
DS3_SET_BOTH_RUMBLE_STRENGTH(pDevCtx, 0x00, 0x00);

if (!NT_SUCCESS(status = Ds_SendOutputReport(pDevCtx, Ds3OutputReportSourceDriverHighPriority)))
{
TraceError(
TRACE_DSBTH,
"Ds_SendOutputReport failed with status %!STATUS!",
status
);
EventWriteFailedWithNTStatus(__FUNCTION__, L"Ds_SendOutputReport", status);
}

//
// Start consuming input packets
//
if (!NT_SUCCESS(status = DMF_DefaultTarget_StreamStart(pDevCtx->Connection.Bth.HidInterrupt.InputStreamerModule)))
{
TraceError(
TRACE_DSBTH,
"DMF_DefaultTarget_StreamStart failed with status %!STATUS!",
status
);
EventWriteFailedWithNTStatus(__FUNCTION__, L"DMF_DefaultTarget_StreamStart", status);
}

//
// Send delayed initialization packets
// Required for compatibility with some SIXAXIS models
//
WdfTimerStart(
pDevCtx->Connection.Bth.Timers.PostStartupTasks,
WDF_REL_TIMEOUT_IN_SEC(1)
);

FuncExitNoReturn(TRACE_DSBTH);
}

//
// Invoked after startup delay to apply workarounds
//
_Use_decl_annotations_
VOID
DsBth_EvtPostStartupTimerFunc(
WDFTIMER Timer
)
{
NTSTATUS status;

FuncEntry(TRACE_DSBTH);

const PDEVICE_CONTEXT pDevCtx = DeviceGetContext(WdfTimerGetParentObject(Timer));

//
// We have not yet received an input report from the remote device
//
if (pDevCtx->BatteryStatus == DsBatteryStatusNone)
{
TraceWarning(
TRACE_DSBTH,
"Battery status still unknown, applying workarounds"
);
EventWriteApplyingWirelessWorkarounds();

//
// Send magic packet, starts input report sending
// NOTE: this is only required on certain models like the OG SIXAXIS
// It must not be issued on e.g. the Defender BTH or it disconnects
//
if (!NT_SUCCESS(status = DsBth_Ds3SixaxisInit(pDevCtx)))
{
TraceError(
TRACE_DSBTH,
"DsBth_Ds3Init failed with status %!STATUS!",
status
);
EventWriteFailedWithNTStatus(__FUNCTION__, L"DsBth_Ds3Init", status);
}
}

FuncExitNoReturn(TRACE_DSBTH);
}
Loading