Fixed interactions with the Linux Wiimote driver
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
diff --git a/src/joystick/hidapi/SDL_hidapi_wii.c b/src/joystick/hidapi/SDL_hidapi_wii.c
index 446ece2..37a69f7 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;
}
}