Fixed interactions with the Linux Wiimote driver

This commit is contained in:
Sam Lantinga 2022-09-02 11:21:51 -07:00
parent 0c984360d1
commit b6d23d21db
1 changed files with 50 additions and 21 deletions

View File

@ -174,24 +174,37 @@ HIDAPI_DriverWii_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 produc
static int ReadInput(SDL_DriverWii_Context *ctx) static int ReadInput(SDL_DriverWii_Context *ctx)
{ {
int size;
/* Make sure we don't try to read at the same time a write is happening */ /* Make sure we don't try to read at the same time a write is happening */
if (SDL_AtomicGet(&ctx->device->rumble_pending) > 0) { if (SDL_AtomicGet(&ctx->device->rumble_pending) > 0) {
return 0; return 0;
} }
return SDL_hid_read_timeout(ctx->device->dev, ctx->m_rgucReadBuffer, sizeof(ctx->m_rgucReadBuffer), 0); size = SDL_hid_read_timeout(ctx->device->dev, ctx->m_rgucReadBuffer, sizeof(ctx->m_rgucReadBuffer), 0);
#ifdef DEBUG_WII_PROTOCOL
if (size > 0) {
HIDAPI_DumpPacket("Wii packet: size = %d", ctx->m_rgucReadBuffer, size);
}
#endif
return size;
} }
static int WriteOutput(SDL_DriverWii_Context *ctx, const Uint8 *data, int size, SDL_bool sync) static SDL_bool WriteOutput(SDL_DriverWii_Context *ctx, const Uint8 *data, int size, SDL_bool sync)
{ {
#ifdef DEBUG_WII_PROTOCOL
if (size > 0) {
HIDAPI_DumpPacket("Wii write packet: size = %d", data, size);
}
#endif
if (sync) { if (sync) {
return SDL_hid_write(ctx->device->dev, data, size); return (SDL_hid_write(ctx->device->dev, data, size) >= 0);
} else { } else {
/* Use the rumble thread for general asynchronous writes */ /* Use the rumble thread for general asynchronous writes */
if (SDL_HIDAPI_LockRumble() < 0) { if (SDL_HIDAPI_LockRumble() < 0) {
return -1; return SDL_FALSE;
} }
return SDL_HIDAPI_SendRumbleAndUnlock(ctx->device, data, size); return (SDL_HIDAPI_SendRumbleAndUnlock(ctx->device, data, size) >= 0);
} }
} }
@ -226,6 +239,7 @@ static SDL_bool WriteRegister(SDL_DriverWii_Context *ctx, Uint32 address, const
{ {
Uint8 writeRequest[k_unWiiPacketDataLength]; Uint8 writeRequest[k_unWiiPacketDataLength];
SDL_zeroa(writeRequest);
writeRequest[0] = k_eWiiOutputReportIDs_WriteMemory; writeRequest[0] = k_eWiiOutputReportIDs_WriteMemory;
writeRequest[1] = 0x04 | ctx->m_bRumbleActive; writeRequest[1] = 0x04 | ctx->m_bRumbleActive;
writeRequest[2] = (address >> 16) & 0xff; writeRequest[2] = (address >> 16) & 0xff;
@ -512,19 +526,27 @@ ReadExtensionControllerType(SDL_HIDAPI_Device *device)
device->dev = SDL_hid_open_path(device->path, 0); device->dev = SDL_hid_open_path(device->path, 0);
if (device->dev) { if (device->dev) {
const Uint8 statusRequest[2] = { k_eWiiOutputReportIDs_StatusRequest, 0 }; const int MAX_ATTEMPTS = 20;
WriteOutput(ctx, statusRequest, sizeof(statusRequest), SDL_TRUE); int attempts = 0;
if (ReadInputSync(ctx, k_eWiiInputReportIDs_Status, NULL)) { for (attempts = 0; attempts < MAX_ATTEMPTS; ++attempts) {
SDL_bool hasExtension = (ctx->m_rgucReadBuffer[3] & 2) ? SDL_TRUE : SDL_FALSE; const Uint8 statusRequest[2] = { k_eWiiOutputReportIDs_StatusRequest, 0 };
if (hasExtension) { WriteOutput(ctx, statusRequest, sizeof(statusRequest), SDL_TRUE);
/* http://wiibrew.org/wiki/Wiimote/Extension_Controllers#The_New_Way */ if (ReadInputSync(ctx, k_eWiiInputReportIDs_Status, NULL)) {
if (SendExtensionIdentify1(ctx, SDL_TRUE) && SDL_bool hasExtension = (ctx->m_rgucReadBuffer[3] & 2) ? SDL_TRUE : SDL_FALSE;
SendExtensionIdentify2(ctx, SDL_TRUE) && if (hasExtension) {
SendExtensionIdentify3(ctx, SDL_TRUE)) { /* http://wiibrew.org/wiki/Wiimote/Extension_Controllers#The_New_Way */
ParseExtensionResponse(ctx, &eExtensionControllerType); if (SendExtensionIdentify1(ctx, SDL_TRUE) &&
SendExtensionIdentify2(ctx, SDL_TRUE) &&
SendExtensionIdentify3(ctx, SDL_TRUE)) {
ParseExtensionResponse(ctx, &eExtensionControllerType);
}
} else {
eExtensionControllerType = k_eWiiExtensionControllerType_None;
} }
} else { }
eExtensionControllerType = k_eWiiExtensionControllerType_None; if (eExtensionControllerType != k_eWiiExtensionControllerType_Unknown) {
/* Got it! */
break;
} }
} }
SDL_hid_close(device->dev); SDL_hid_close(device->dev);
@ -1048,6 +1070,7 @@ static void HandleResponse(SDL_DriverWii_Context *ctx, SDL_Joystick *joystick)
break; break;
} }
#if 0 /* This happens with the Linux Wiimote driver */
if (type == k_eWiiInputReportIDs_Acknowledge) { if (type == k_eWiiInputReportIDs_Acknowledge) {
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "HIDAPI WII: A mysterious ack has arrived! Type: %02x, Code: %d", SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "HIDAPI WII: A mysterious ack has arrived! Type: %02x, Code: %d",
ctx->m_rgucReadBuffer[3], ctx->m_rgucReadBuffer[4]); ctx->m_rgucReadBuffer[3], ctx->m_rgucReadBuffer[4]);
@ -1068,13 +1091,21 @@ static void HandleResponse(SDL_DriverWii_Context *ctx, SDL_Joystick *joystick)
ctx->m_rgucReadBuffer[3] & 0xF, ctx->m_rgucReadBuffer[3] & 0xF,
str); str);
} }
#endif /* 0 */
} }
static void HandleButtonPacket(SDL_DriverWii_Context *ctx, SDL_Joystick *joystick) static void HandleButtonPacket(SDL_DriverWii_Context *ctx, SDL_Joystick *joystick)
{ {
EWiiInputReportIDs eExpectedReport = GetButtonPacketType(ctx);
WiiButtonData data; WiiButtonData data;
SDL_zero(data);
if (eExpectedReport != ctx->m_rgucReadBuffer[0]) {
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "HIDAPI WII: Resetting report mode to %d\n", eExpectedReport);
RequestButtonPacketType(ctx, eExpectedReport);
}
/* IR camera data is not supported */ /* IR camera data is not supported */
SDL_zero(data);
switch (ctx->m_rgucReadBuffer[0]) { switch (ctx->m_rgucReadBuffer[0]) {
case k_eWiiInputReportIDs_ButtonData0: /* 30 BB BB */ case k_eWiiInputReportIDs_ButtonData0: /* 30 BB BB */
GetBaseButtons(&data, ctx->m_rgucReadBuffer + 1); GetBaseButtons(&data, ctx->m_rgucReadBuffer + 1);
@ -1149,9 +1180,6 @@ HIDAPI_DriverWii_UpdateDevice(SDL_HIDAPI_Device *device)
now = SDL_GetTicks(); now = SDL_GetTicks();
while ((size = ReadInput(ctx)) > 0) { while ((size = ReadInput(ctx)) > 0) {
#ifdef DEBUG_WII_PROTOCOL
HIDAPI_DumpPacket("Wii packet: size = %d", ctx->m_rgucReadBuffer, size);
#endif
HandleInput(ctx, joystick); HandleInput(ctx, joystick);
ctx->m_unLastInput = now; ctx->m_unLastInput = now;
@ -1178,6 +1206,7 @@ HIDAPI_DriverWii_UpdateDevice(SDL_HIDAPI_Device *device)
data[1] = ctx->m_bRumbleActive; data[1] = ctx->m_bRumbleActive;
WriteOutput(ctx, data, sizeof(data), SDL_FALSE); WriteOutput(ctx, data, sizeof(data), SDL_FALSE);
ctx->m_eCommState = k_eWiiCommunicationState_None;
ctx->m_unLastStatus = now; ctx->m_unLastStatus = now;
} }
} }