From b6d23d21db888c119e669a966ddc4ee3f947bc28 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Fri, 2 Sep 2022 11:21:51 -0700 Subject: [PATCH] Fixed interactions with the Linux Wiimote driver --- src/joystick/hidapi/SDL_hidapi_wii.c | 71 ++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 21 deletions(-) diff --git a/src/joystick/hidapi/SDL_hidapi_wii.c b/src/joystick/hidapi/SDL_hidapi_wii.c index 446ece2bb..37a69f77b 100644 --- a/src/joystick/hidapi/SDL_hidapi_wii.c +++ b/src/joystick/hidapi/SDL_hidapi_wii.c @@ -174,24 +174,37 @@ HIDAPI_DriverWii_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 produc 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 */ if (SDL_AtomicGet(&ctx->device->rumble_pending) > 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) { - return SDL_hid_write(ctx->device->dev, data, size); + return (SDL_hid_write(ctx->device->dev, data, size) >= 0); } else { /* Use the rumble thread for general asynchronous writes */ 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]; + SDL_zeroa(writeRequest); writeRequest[0] = k_eWiiOutputReportIDs_WriteMemory; writeRequest[1] = 0x04 | ctx->m_bRumbleActive; writeRequest[2] = (address >> 16) & 0xff; @@ -512,19 +526,27 @@ ReadExtensionControllerType(SDL_HIDAPI_Device *device) device->dev = SDL_hid_open_path(device->path, 0); if (device->dev) { - const Uint8 statusRequest[2] = { k_eWiiOutputReportIDs_StatusRequest, 0 }; - WriteOutput(ctx, statusRequest, sizeof(statusRequest), SDL_TRUE); - if (ReadInputSync(ctx, k_eWiiInputReportIDs_Status, NULL)) { - SDL_bool hasExtension = (ctx->m_rgucReadBuffer[3] & 2) ? SDL_TRUE : SDL_FALSE; - if (hasExtension) { - /* http://wiibrew.org/wiki/Wiimote/Extension_Controllers#The_New_Way */ - if (SendExtensionIdentify1(ctx, SDL_TRUE) && - SendExtensionIdentify2(ctx, SDL_TRUE) && - SendExtensionIdentify3(ctx, SDL_TRUE)) { - ParseExtensionResponse(ctx, &eExtensionControllerType); + const int MAX_ATTEMPTS = 20; + int attempts = 0; + for (attempts = 0; attempts < MAX_ATTEMPTS; ++attempts) { + const Uint8 statusRequest[2] = { k_eWiiOutputReportIDs_StatusRequest, 0 }; + WriteOutput(ctx, statusRequest, sizeof(statusRequest), SDL_TRUE); + if (ReadInputSync(ctx, k_eWiiInputReportIDs_Status, NULL)) { + SDL_bool hasExtension = (ctx->m_rgucReadBuffer[3] & 2) ? SDL_TRUE : SDL_FALSE; + if (hasExtension) { + /* http://wiibrew.org/wiki/Wiimote/Extension_Controllers#The_New_Way */ + 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); @@ -1048,6 +1070,7 @@ static void HandleResponse(SDL_DriverWii_Context *ctx, SDL_Joystick *joystick) break; } +#if 0 /* This happens with the Linux Wiimote driver */ if (type == k_eWiiInputReportIDs_Acknowledge) { 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]); @@ -1068,13 +1091,21 @@ static void HandleResponse(SDL_DriverWii_Context *ctx, SDL_Joystick *joystick) ctx->m_rgucReadBuffer[3] & 0xF, str); } +#endif /* 0 */ } static void HandleButtonPacket(SDL_DriverWii_Context *ctx, SDL_Joystick *joystick) { + EWiiInputReportIDs eExpectedReport = GetButtonPacketType(ctx); 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 */ + SDL_zero(data); switch (ctx->m_rgucReadBuffer[0]) { case k_eWiiInputReportIDs_ButtonData0: /* 30 BB BB */ GetBaseButtons(&data, ctx->m_rgucReadBuffer + 1); @@ -1149,9 +1180,6 @@ HIDAPI_DriverWii_UpdateDevice(SDL_HIDAPI_Device *device) now = SDL_GetTicks(); while ((size = ReadInput(ctx)) > 0) { -#ifdef DEBUG_WII_PROTOCOL - HIDAPI_DumpPacket("Wii packet: size = %d", ctx->m_rgucReadBuffer, size); -#endif HandleInput(ctx, joystick); ctx->m_unLastInput = now; @@ -1178,6 +1206,7 @@ HIDAPI_DriverWii_UpdateDevice(SDL_HIDAPI_Device *device) data[1] = ctx->m_bRumbleActive; WriteOutput(ctx, data, sizeof(data), SDL_FALSE); + ctx->m_eCommState = k_eWiiCommunicationState_None; ctx->m_unLastStatus = now; } }