mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-09-07 11:58:12 +00:00
hidapi: Add support for Steam controllers connected via USB
This commit is contained in:

committed by
Sam Lantinga

parent
e67ae274a5
commit
1a311bc638
@@ -211,10 +211,9 @@ static void ResetSteamControllerPacketAssembler(SteamControllerPacketAssembler *
|
|||||||
pAssembler->nExpectedSegmentNumber = 0;
|
pAssembler->nExpectedSegmentNumber = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void InitializeSteamControllerPacketAssembler(SteamControllerPacketAssembler *pAssembler)
|
static void InitializeSteamControllerPacketAssembler(SteamControllerPacketAssembler *pAssembler, bool bIsBle)
|
||||||
{
|
{
|
||||||
// We only support BLE devices right now
|
pAssembler->bIsBle = bIsBle;
|
||||||
pAssembler->bIsBle = true;
|
|
||||||
ResetSteamControllerPacketAssembler(pAssembler);
|
ResetSteamControllerPacketAssembler(pAssembler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,14 +282,13 @@ static int WriteSegmentToSteamControllerPacketAssembler(SteamControllerPacketAss
|
|||||||
|
|
||||||
#define BLE_MAX_READ_RETRIES 8
|
#define BLE_MAX_READ_RETRIES 8
|
||||||
|
|
||||||
static int SetFeatureReport(SDL_hid_device *dev, unsigned char uBuffer[65], int nActualDataLen)
|
static int SetFeatureReport(SDL_HIDAPI_Device *dev, unsigned char uBuffer[65], int nActualDataLen)
|
||||||
{
|
{
|
||||||
int nRet = -1;
|
int nRet = -1;
|
||||||
bool bBle = true; // only wireless/BLE for now, though macOS could do wired in the future
|
|
||||||
|
|
||||||
DPRINTF("SetFeatureReport %p %p %d\n", dev, uBuffer, nActualDataLen);
|
DPRINTF("SetFeatureReport %p %p %d\n", dev, uBuffer, nActualDataLen);
|
||||||
|
|
||||||
if (bBle) {
|
if (dev->is_bluetooth) {
|
||||||
int nSegmentNumber = 0;
|
int nSegmentNumber = 0;
|
||||||
uint8_t uPacketBuffer[MAX_REPORT_SEGMENT_SIZE];
|
uint8_t uPacketBuffer[MAX_REPORT_SEGMENT_SIZE];
|
||||||
unsigned char *pBufferPtr = uBuffer + 1;
|
unsigned char *pBufferPtr = uBuffer + 1;
|
||||||
@@ -316,29 +314,31 @@ static int SetFeatureReport(SDL_hid_device *dev, unsigned char uBuffer[65], int
|
|||||||
pBufferPtr += nBytesInPacket;
|
pBufferPtr += nBytesInPacket;
|
||||||
nSegmentNumber++;
|
nSegmentNumber++;
|
||||||
|
|
||||||
nRet = SDL_hid_send_feature_report(dev, uPacketBuffer, sizeof(uPacketBuffer));
|
nRet = SDL_hid_send_feature_report(dev->dev, uPacketBuffer, sizeof(uPacketBuffer));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nRet = SDL_hid_send_feature_report(dev->dev, uBuffer, 65);
|
||||||
|
}
|
||||||
|
|
||||||
DPRINTF("SetFeatureReport() ret = %d\n", nRet);
|
DPRINTF("SetFeatureReport() ret = %d\n", nRet);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nRet;
|
return nRet;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int GetFeatureReport(SDL_hid_device *dev, unsigned char uBuffer[65])
|
static int GetFeatureReport(SDL_HIDAPI_Device *dev, unsigned char uBuffer[65])
|
||||||
{
|
{
|
||||||
int nRet = -1;
|
int nRet = -1;
|
||||||
bool bBle = true;
|
|
||||||
|
|
||||||
DPRINTF("GetFeatureReport( %p %p )\n", dev, uBuffer);
|
DPRINTF("GetFeatureReport( %p %p )\n", dev, uBuffer);
|
||||||
|
|
||||||
if (bBle) {
|
if (dev->is_bluetooth) {
|
||||||
int nRetries = 0;
|
int nRetries = 0;
|
||||||
uint8_t uSegmentBuffer[MAX_REPORT_SEGMENT_SIZE + 1];
|
uint8_t uSegmentBuffer[MAX_REPORT_SEGMENT_SIZE + 1];
|
||||||
uint8_t ucBytesToRead = MAX_REPORT_SEGMENT_SIZE;
|
uint8_t ucBytesToRead = MAX_REPORT_SEGMENT_SIZE;
|
||||||
uint8_t ucDataStartOffset = 0;
|
uint8_t ucDataStartOffset = 0;
|
||||||
|
|
||||||
SteamControllerPacketAssembler assembler;
|
SteamControllerPacketAssembler assembler;
|
||||||
InitializeSteamControllerPacketAssembler(&assembler);
|
InitializeSteamControllerPacketAssembler(&assembler, dev->is_bluetooth);
|
||||||
|
|
||||||
// On Windows and macOS, BLE devices get 2 copies of the feature report ID, one that is removed by ReadFeatureReport,
|
// On Windows and macOS, BLE devices get 2 copies of the feature report ID, one that is removed by ReadFeatureReport,
|
||||||
// and one that's included in the buffer we receive. We pad the bytes to read and skip over the report ID
|
// and one that's included in the buffer we receive. We pad the bytes to read and skip over the report ID
|
||||||
@@ -351,7 +351,7 @@ static int GetFeatureReport(SDL_hid_device *dev, unsigned char uBuffer[65])
|
|||||||
while (nRetries < BLE_MAX_READ_RETRIES) {
|
while (nRetries < BLE_MAX_READ_RETRIES) {
|
||||||
SDL_memset(uSegmentBuffer, 0, sizeof(uSegmentBuffer));
|
SDL_memset(uSegmentBuffer, 0, sizeof(uSegmentBuffer));
|
||||||
uSegmentBuffer[0] = BLE_REPORT_NUMBER;
|
uSegmentBuffer[0] = BLE_REPORT_NUMBER;
|
||||||
nRet = SDL_hid_get_feature_report(dev, uSegmentBuffer, ucBytesToRead);
|
nRet = SDL_hid_get_feature_report(dev->dev, uSegmentBuffer, ucBytesToRead);
|
||||||
|
|
||||||
DPRINTF("GetFeatureReport ble ret=%d\n", nRet);
|
DPRINTF("GetFeatureReport ble ret=%d\n", nRet);
|
||||||
HEXDUMP(uSegmentBuffer, nRet);
|
HEXDUMP(uSegmentBuffer, nRet);
|
||||||
@@ -378,12 +378,18 @@ static int GetFeatureReport(SDL_hid_device *dev, unsigned char uBuffer[65])
|
|||||||
}
|
}
|
||||||
printf("Could not get a full ble packet after %d retries\n", nRetries);
|
printf("Could not get a full ble packet after %d retries\n", nRetries);
|
||||||
return -1;
|
return -1;
|
||||||
|
} else {
|
||||||
|
SDL_memset(uBuffer, 0, 65);
|
||||||
|
nRet = SDL_hid_get_feature_report(dev->dev, uBuffer, 65);
|
||||||
|
|
||||||
|
DPRINTF("GetFeatureReport USB ret=%d\n", nRet);
|
||||||
|
HEXDUMP(uBuffer, nRet);
|
||||||
}
|
}
|
||||||
|
|
||||||
return nRet;
|
return nRet;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ReadResponse(SDL_hid_device *dev, uint8_t uBuffer[65], int nExpectedResponse)
|
static int ReadResponse(SDL_HIDAPI_Device *dev, uint8_t uBuffer[65], int nExpectedResponse)
|
||||||
{
|
{
|
||||||
int nRet = GetFeatureReport(dev, uBuffer);
|
int nRet = GetFeatureReport(dev, uBuffer);
|
||||||
|
|
||||||
@@ -406,7 +412,7 @@ static int ReadResponse(SDL_hid_device *dev, uint8_t uBuffer[65], int nExpectedR
|
|||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// Reset steam controller (unmap buttons and pads) and re-fetch capability bits
|
// Reset steam controller (unmap buttons and pads) and re-fetch capability bits
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
static bool ResetSteamController(SDL_hid_device *dev, bool bSuppressErrorSpew, uint32_t *punUpdateRateUS)
|
static bool ResetSteamController(SDL_HIDAPI_Device *dev, bool bSuppressErrorSpew, uint32_t *punUpdateRateUS)
|
||||||
{
|
{
|
||||||
// Firmware quirk: Set Feature and Get Feature requests always require a 65-byte buffer.
|
// Firmware quirk: Set Feature and Get Feature requests always require a 65-byte buffer.
|
||||||
unsigned char buf[65];
|
unsigned char buf[65];
|
||||||
@@ -593,7 +599,7 @@ static int ReadSteamController(SDL_hid_device *dev, uint8_t *pData, int nDataSiz
|
|||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// Close a Steam Controller
|
// Close a Steam Controller
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
static void CloseSteamController(SDL_hid_device *dev)
|
static void CloseSteamController(SDL_HIDAPI_Device *dev)
|
||||||
{
|
{
|
||||||
// Switch the Steam Controller back to lizard mode so it works with the OS
|
// Switch the Steam Controller back to lizard mode so it works with the OS
|
||||||
unsigned char buf[65];
|
unsigned char buf[65];
|
||||||
@@ -1010,7 +1016,7 @@ static bool HIDAPI_DriverSteam_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joyst
|
|||||||
SDL_zero(ctx->m_state);
|
SDL_zero(ctx->m_state);
|
||||||
SDL_zero(ctx->m_last_state);
|
SDL_zero(ctx->m_last_state);
|
||||||
|
|
||||||
if (!ResetSteamController(device->dev, false, &ctx->update_rate_in_us)) {
|
if (!ResetSteamController(device, false, &ctx->update_rate_in_us)) {
|
||||||
SDL_SetError("Couldn't reset controller");
|
SDL_SetError("Couldn't reset controller");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1018,7 +1024,7 @@ static bool HIDAPI_DriverSteam_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joyst
|
|||||||
update_rate_in_hz = 1000000.0f / ctx->update_rate_in_us;
|
update_rate_in_hz = 1000000.0f / ctx->update_rate_in_us;
|
||||||
}
|
}
|
||||||
|
|
||||||
InitializeSteamControllerPacketAssembler(&ctx->m_assembler);
|
InitializeSteamControllerPacketAssembler(&ctx->m_assembler, device->is_bluetooth);
|
||||||
|
|
||||||
// Initialize the joystick capabilities
|
// Initialize the joystick capabilities
|
||||||
joystick->nbuttons = SDL_GAMEPAD_NUM_STEAM_BUTTONS;
|
joystick->nbuttons = SDL_GAMEPAD_NUM_STEAM_BUTTONS;
|
||||||
@@ -1073,7 +1079,7 @@ static bool HIDAPI_DriverSteam_SetSensorsEnabled(SDL_HIDAPI_Device *device, SDL_
|
|||||||
ADD_SETTING(SETTING_IMU_MODE, SETTING_GYRO_MODE_OFF);
|
ADD_SETTING(SETTING_IMU_MODE, SETTING_GYRO_MODE_OFF);
|
||||||
}
|
}
|
||||||
buf[2] = (unsigned char)(nSettings * 3);
|
buf[2] = (unsigned char)(nSettings * 3);
|
||||||
if (SetFeatureReport(device->dev, buf, 3 + nSettings * 3) < 0) {
|
if (SetFeatureReport(device, buf, 3 + nSettings * 3) < 0) {
|
||||||
return SDL_SetError("Couldn't write feature report");
|
return SDL_SetError("Couldn't write feature report");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1210,7 +1216,7 @@ static bool HIDAPI_DriverSteam_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||||||
|
|
||||||
static void HIDAPI_DriverSteam_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
static void HIDAPI_DriverSteam_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||||
{
|
{
|
||||||
CloseSteamController(device->dev);
|
CloseSteamController(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HIDAPI_DriverSteam_FreeDevice(SDL_HIDAPI_Device *device)
|
static void HIDAPI_DriverSteam_FreeDevice(SDL_HIDAPI_Device *device)
|
||||||
|
Reference in New Issue
Block a user