Browse Source

Cleanup 8BitDo HIDAPI support for SF30 Pro and SN30 Pro

This sets the correct number of buttons for older controllers, and adds parsing for older firmware USB reports
Sam Lantinga 3 months ago
parent
commit
5bee85408c

+ 20 - 6
src/joystick/SDL_gamepad.c

@@ -779,6 +779,20 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid)
             }
             }
             break;
             break;
         }
         }
+    } else if (vendor == USB_VENDOR_8BITDO &&
+               (product == USB_PRODUCT_8BITDO_SN30_PRO ||
+                product == USB_PRODUCT_8BITDO_SN30_PRO_BT ||
+                product == USB_PRODUCT_8BITDO_PRO_2 ||
+                product == USB_PRODUCT_8BITDO_PRO_2_BT)) {
+            SDL_strlcat(mapping_string, "a:b1,b:b0,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", sizeof(mapping_string));
+            if (product == USB_PRODUCT_8BITDO_PRO_2 || product == USB_PRODUCT_8BITDO_PRO_2_BT) {
+                SDL_strlcat(mapping_string, "paddle1:b14,paddle2:b13,", sizeof(mapping_string));
+            }
+    } else if (vendor == USB_VENDOR_8BITDO &&
+               (product == USB_PRODUCT_8BITDO_SF30_PRO ||
+                product == USB_PRODUCT_8BITDO_SF30_PRO_BT)) {
+            // This controller has no guide button
+            SDL_strlcat(mapping_string, "a:b1,b:b0,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", sizeof(mapping_string));
     } else {
     } else {
         // All other gamepads have the standard set of 19 buttons and 6 axes
         // All other gamepads have the standard set of 19 buttons and 6 axes
         if (SDL_IsJoystickGameCube(vendor, product)) {
         if (SDL_IsJoystickGameCube(vendor, product)) {
@@ -802,20 +816,20 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid)
             SDL_strlcat(mapping_string, "misc1:b11,", sizeof(mapping_string));
             SDL_strlcat(mapping_string, "misc1:b11,", sizeof(mapping_string));
         } else if (SDL_IsJoystickGoogleStadiaController(vendor, product)) {
         } else if (SDL_IsJoystickGoogleStadiaController(vendor, product)) {
             // The Google Stadia controller has a share button and a Google Assistant button
             // The Google Stadia controller has a share button and a Google Assistant button
-            SDL_strlcat(mapping_string, "misc1:b11,misc2:b12", sizeof(mapping_string));
+            SDL_strlcat(mapping_string, "misc1:b11,misc2:b12,", sizeof(mapping_string));
         } else if (SDL_IsJoystickNVIDIASHIELDController(vendor, product)) {
         } else if (SDL_IsJoystickNVIDIASHIELDController(vendor, product)) {
             // The NVIDIA SHIELD controller has a share button between back and start buttons
             // The NVIDIA SHIELD controller has a share button between back and start buttons
             SDL_strlcat(mapping_string, "misc1:b11,", sizeof(mapping_string));
             SDL_strlcat(mapping_string, "misc1:b11,", sizeof(mapping_string));
 
 
             if (product == USB_PRODUCT_NVIDIA_SHIELD_CONTROLLER_V103) {
             if (product == USB_PRODUCT_NVIDIA_SHIELD_CONTROLLER_V103) {
                 // The original SHIELD controller has a touchpad and plus/minus buttons as well
                 // The original SHIELD controller has a touchpad and plus/minus buttons as well
-                SDL_strlcat(mapping_string, "touchpad:b12,misc2:b13,misc3:b14", sizeof(mapping_string));
+                SDL_strlcat(mapping_string, "touchpad:b12,misc2:b13,misc3:b14,", sizeof(mapping_string));
             }
             }
         } else if (SDL_IsJoystickHoriSteamController(vendor, product)) {
         } else if (SDL_IsJoystickHoriSteamController(vendor, product)) {
             /* The Wireless HORIPad for Steam has QAM, Steam, Capsense L/R Sticks, 2 rear buttons, and 2 misc buttons */
             /* The Wireless HORIPad for Steam has QAM, Steam, Capsense L/R Sticks, 2 rear buttons, and 2 misc buttons */
-            SDL_strlcat(mapping_string, "paddle1:b13,paddle2:b12,paddle3:b15,paddle4:b14,misc2:b11,misc3:b16,misc4:b17", sizeof(mapping_string));
-        } else if (SDL_IsJoystick8BitDoController(vendor, product)) {
-            SDL_strlcat(mapping_string, "paddle1:b12,paddle2:b11,paddle3:b14,paddle4:b13", sizeof(mapping_string));
+            SDL_strlcat(mapping_string, "paddle1:b13,paddle2:b12,paddle3:b15,paddle4:b14,misc2:b11,misc3:b16,misc4:b17,", sizeof(mapping_string));
+        } else if (vendor == USB_VENDOR_8BITDO && product == USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS) {
+            SDL_strlcat(mapping_string, "paddle1:b12,paddle2:b11,paddle3:b14,paddle4:b13,", sizeof(mapping_string));
         } else {
         } else {
             switch (SDL_GetGamepadTypeFromGUID(guid, NULL)) {
             switch (SDL_GetGamepadTypeFromGUID(guid, NULL)) {
             case SDL_GAMEPAD_TYPE_PS4:
             case SDL_GAMEPAD_TYPE_PS4:
@@ -1295,7 +1309,7 @@ static bool SDL_PrivateParseGamepadElement(SDL_Gamepad *gamepad, const char *szG
 static bool SDL_PrivateParseGamepadConfigString(SDL_Gamepad *gamepad, const char *pchString)
 static bool SDL_PrivateParseGamepadConfigString(SDL_Gamepad *gamepad, const char *pchString)
 {
 {
     char szGameButton[20];
     char szGameButton[20];
-    char szJoystickButton[20];
+    char szJoystickButton[128];
     bool bGameButton = true;
     bool bGameButton = true;
     int i = 0;
     int i = 0;
     const char *pchPos = pchString;
     const char *pchPos = pchString;

+ 0 - 18
src/joystick/SDL_joystick.c

@@ -3175,24 +3175,6 @@ bool SDL_IsJoystickHoriSteamController(Uint16 vendor_id, Uint16 product_id)
     return vendor_id == USB_VENDOR_HORI && (product_id == USB_PRODUCT_HORI_STEAM_CONTROLLER || product_id == USB_PRODUCT_HORI_STEAM_CONTROLLER_BT);
     return vendor_id == USB_VENDOR_HORI && (product_id == USB_PRODUCT_HORI_STEAM_CONTROLLER || product_id == USB_PRODUCT_HORI_STEAM_CONTROLLER_BT);
 }
 }
 
 
-bool SDL_IsJoystick8BitDoController(Uint16 vendor_id, Uint16 product_id)
-{
-    if (vendor_id == USB_VENDOR_8BITDO) {
-        switch (product_id) {
-        case USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS:
-        case USB_PRODUCT_8BITDO_SN30_PRO:
-        case USB_PRODUCT_8BITDO_SN30_PRO_BT:
-        case USB_PRODUCT_8BITDO_SF30_PRO:
-        case USB_PRODUCT_8BITDO_PRO_2:
-        case USB_PRODUCT_8BITDO_PRO_2_BT:
-            return true;
-        default:
-            break;
-        }
-    }
-    return false;
-}
-
 bool SDL_IsJoystickSteamDeck(Uint16 vendor_id, Uint16 product_id)
 bool SDL_IsJoystickSteamDeck(Uint16 vendor_id, Uint16 product_id)
 {
 {
     EControllerType eType = GuessControllerType(vendor_id, product_id);
     EControllerType eType = GuessControllerType(vendor_id, product_id);

+ 0 - 3
src/joystick/SDL_joystick_c.h

@@ -135,9 +135,6 @@ extern bool SDL_IsJoystickSteamController(Uint16 vendor_id, Uint16 product_id);
 // Function to return whether a joystick is a HORI Steam controller
 // Function to return whether a joystick is a HORI Steam controller
 extern bool SDL_IsJoystickHoriSteamController(Uint16 vendor_id, Uint16 product_id);
 extern bool SDL_IsJoystickHoriSteamController(Uint16 vendor_id, Uint16 product_id);
 
 
-// Function to return whether a joystick is a 8BitDo controller
-extern bool SDL_IsJoystick8BitDoController(Uint16 vendor_id, Uint16 product_id);
-
 // Function to return whether a joystick is a Steam Deck
 // Function to return whether a joystick is a Steam Deck
 extern bool SDL_IsJoystickSteamDeck(Uint16 vendor_id, Uint16 product_id);
 extern bool SDL_IsJoystickSteamDeck(Uint16 vendor_id, Uint16 product_id);
 
 

+ 124 - 13
src/joystick/hidapi/SDL_hidapi_8bitdo.c

@@ -126,7 +126,21 @@ static int ReadFeatureReport(SDL_hid_device *dev, Uint8 report_id, Uint8 *report
 
 
 static bool HIDAPI_Driver8BitDo_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name, SDL_GamepadType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
 static bool HIDAPI_Driver8BitDo_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name, SDL_GamepadType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
 {
 {
-    return SDL_IsJoystick8BitDoController(vendor_id, product_id);
+    if (vendor_id == USB_VENDOR_8BITDO) {
+        switch (product_id) {
+        case USB_PRODUCT_8BITDO_SF30_PRO:
+        case USB_PRODUCT_8BITDO_SF30_PRO_BT:
+        case USB_PRODUCT_8BITDO_SN30_PRO:
+        case USB_PRODUCT_8BITDO_SN30_PRO_BT:
+        case USB_PRODUCT_8BITDO_PRO_2:
+        case USB_PRODUCT_8BITDO_PRO_2_BT:
+        case USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS:
+            return true;
+        default:
+            break;
+        }
+    }
+    return false;
 }
 }
 
 
 static bool HIDAPI_Driver8BitDo_InitDevice(SDL_HIDAPI_Device *device)
 static bool HIDAPI_Driver8BitDo_InitDevice(SDL_HIDAPI_Device *device)
@@ -147,21 +161,24 @@ static bool HIDAPI_Driver8BitDo_InitDevice(SDL_HIDAPI_Device *device)
             ctx->rumble_supported = true;
             ctx->rumble_supported = true;
             ctx->powerstate_supported = true;
             ctx->powerstate_supported = true;
         }
         }
-    } else if (device->product_id == USB_PRODUCT_8BITDO_SN30_PRO || device->product_id == USB_PRODUCT_8BITDO_SN30_PRO_BT ||
-               device->product_id == USB_PRODUCT_8BITDO_SF30_PRO  || device->product_id == USB_PRODUCT_8BITDO_PRO_2 ||
-                device->product_id == USB_PRODUCT_8BITDO_PRO_2_BT) {
+    } else {
         Uint8 data[USB_PACKET_LENGTH];
         Uint8 data[USB_PACKET_LENGTH];
         int size = ReadFeatureReport(device->dev, SDL_8BITDO_FEATURE_REPORTID_ENABLE_SDL_REPORTID, data, sizeof(data));
         int size = ReadFeatureReport(device->dev, SDL_8BITDO_FEATURE_REPORTID_ENABLE_SDL_REPORTID, data, sizeof(data));
         if (size > 0) {
         if (size > 0) {
             ctx->sensors_supported = true;
             ctx->sensors_supported = true;
             ctx->rumble_supported = true;
             ctx->rumble_supported = true;
             ctx->powerstate_supported = true;
             ctx->powerstate_supported = true;
-        } else {
-            SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
-                         "HIDAPI_Driver8BitDo_InitDevice(): Couldn't read feature report 0x06");
         }
         }
     }
     }
 
 
+    if (device->product_id == USB_PRODUCT_8BITDO_SF30_PRO || device->product_id == USB_PRODUCT_8BITDO_SF30_PRO_BT) {
+        HIDAPI_SetDeviceName(device, "8BitDo SF30 Pro");
+    } else if (device->product_id == USB_PRODUCT_8BITDO_SN30_PRO || device->product_id == USB_PRODUCT_8BITDO_SN30_PRO_BT) {
+        HIDAPI_SetDeviceName(device, "8BitDo SN30 Pro");
+    } else if (device->product_id == USB_PRODUCT_8BITDO_PRO_2 || device->product_id == USB_PRODUCT_8BITDO_PRO_2_BT) {
+        HIDAPI_SetDeviceName(device, "8BitDo Pro 2");
+    }
+
     return HIDAPI_JoystickConnected(device, NULL);
     return HIDAPI_JoystickConnected(device, NULL);
 }
 }
 
 
@@ -187,7 +204,14 @@ static bool HIDAPI_Driver8BitDo_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joys
     SDL_zeroa(ctx->last_state);
     SDL_zeroa(ctx->last_state);
 
 
     // Initialize the joystick capabilities
     // Initialize the joystick capabilities
-    joystick->nbuttons = SDL_GAMEPAD_NUM_8BITDO_BUTTONS;
+    if (device->product_id == USB_PRODUCT_8BITDO_PRO_2 ||
+        device->product_id == USB_PRODUCT_8BITDO_PRO_2_BT ||
+        device->product_id == USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS) {
+        // This controller has additional buttons
+        joystick->nbuttons = SDL_GAMEPAD_NUM_8BITDO_BUTTONS;
+    } else {
+        joystick->nbuttons = 11;
+    }
     joystick->naxes = SDL_GAMEPAD_AXIS_COUNT;
     joystick->naxes = SDL_GAMEPAD_AXIS_COUNT;
     joystick->nhats = 1;
     joystick->nhats = 1;
 
 
@@ -257,12 +281,95 @@ static bool HIDAPI_Driver8BitDo_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *dev
     }
     }
     return SDL_Unsupported();
     return SDL_Unsupported();
 }
 }
+
+static void HIDAPI_Driver8BitDo_HandleOldStatePacket(SDL_Joystick *joystick, SDL_Driver8BitDo_Context *ctx, Uint8 *data, int size)
+{
+    Sint16 axis;
+    Uint64 timestamp = SDL_GetTicksNS();
+
+    if (ctx->last_state[2] != data[2]) {
+        Uint8 hat;
+
+        switch (data[2]) {
+        case 0:
+            hat = SDL_HAT_UP;
+            break;
+        case 1:
+            hat = SDL_HAT_RIGHTUP;
+            break;
+        case 2:
+            hat = SDL_HAT_RIGHT;
+            break;
+        case 3:
+            hat = SDL_HAT_RIGHTDOWN;
+            break;
+        case 4:
+            hat = SDL_HAT_DOWN;
+            break;
+        case 5:
+            hat = SDL_HAT_LEFTDOWN;
+            break;
+        case 6:
+            hat = SDL_HAT_LEFT;
+            break;
+        case 7:
+            hat = SDL_HAT_LEFTUP;
+            break;
+        default:
+            hat = SDL_HAT_CENTERED;
+            break;
+        }
+        SDL_SendJoystickHat(timestamp, joystick, 0, hat);
+    }
+
+    if (ctx->last_state[0] != data[0]) {
+        SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[0] & 0x01) != 0));
+        SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[0] & 0x02) != 0));
+        SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[0] & 0x08) != 0));
+        SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[0] & 0x10) != 0));
+        SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data[0] & 0x40) != 0));
+        SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data[0] & 0x80) != 0));
+    }
+
+    if (ctx->last_state[1] != data[1]) {
+        SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[1] & 0x10) != 0));
+        SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, ((data[1] & 0x04) != 0));
+        SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[1] & 0x08) != 0));
+        SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[1] & 0x20) != 0));
+        SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[1] & 0x40) != 0));
+
+        SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, (data[1] & 0x01) ? SDL_MAX_SINT16 : SDL_MIN_SINT16);
+        SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, (data[1] & 0x02) ? SDL_MAX_SINT16 : SDL_MIN_SINT16);
+    }
+
+#define READ_STICK_AXIS(offset) \
+    (data[offset] == 0x7f ? 0 : (Sint16)HIDAPI_RemapVal((float)((int)data[offset] - 0x7f), -0x7f, 0xff - 0x7f, SDL_MIN_SINT16, SDL_MAX_SINT16))
+    {
+        axis = READ_STICK_AXIS(3);
+        SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis);
+        axis = READ_STICK_AXIS(4);
+        SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis);
+        axis = READ_STICK_AXIS(5);
+        SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis);
+        axis = READ_STICK_AXIS(6);
+        SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis);
+    }
+#undef READ_STICK_AXIS
+
+    SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
+}
+
 static void HIDAPI_Driver8BitDo_HandleStatePacket(SDL_Joystick *joystick, SDL_Driver8BitDo_Context *ctx, Uint8 *data, int size)
 static void HIDAPI_Driver8BitDo_HandleStatePacket(SDL_Joystick *joystick, SDL_Driver8BitDo_Context *ctx, Uint8 *data, int size)
 {
 {
     Sint16 axis;
     Sint16 axis;
     Uint64 timestamp = SDL_GetTicksNS();
     Uint64 timestamp = SDL_GetTicksNS();
-    if (data[0] != SDL_8BITDO_REPORTID_SDL_REPORTID && data[0] != SDL_8BITDO_REPORTID_NOT_SUPPORTED_SDL_REPORTID &&
-        data[0] != SDL_8BITDO_BT_REPORTID_SDL_REPORTID) {
+
+    switch (data[0]) {
+    case SDL_8BITDO_REPORTID_NOT_SUPPORTED_SDL_REPORTID:    // Firmware without enhanced mode
+    case SDL_8BITDO_REPORTID_SDL_REPORTID:                  // Enhanced mode USB report
+    case SDL_8BITDO_BT_REPORTID_SDL_REPORTID:               // Enhanced mode Bluetooth report
+        break;
+    default:
         // We don't know how to handle this report
         // We don't know how to handle this report
         return;
         return;
     }
     }
@@ -323,7 +430,7 @@ static void HIDAPI_Driver8BitDo_HandleStatePacket(SDL_Joystick *joystick, SDL_Dr
         SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[9] & 0x40) != 0));
         SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[9] & 0x40) != 0));
     }
     }
 
 
-    if (ctx->last_state[10] != data[10]) {
+    if (size > 10 && ctx->last_state[10] != data[10]) {
         SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_8BITDO_L4, ((data[10] & 0x01) != 0));
         SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_8BITDO_L4, ((data[10] & 0x01) != 0));
         SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_8BITDO_R4, ((data[10] & 0x02) != 0));
         SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_8BITDO_R4, ((data[10] & 0x02) != 0));
     }
     }
@@ -381,7 +488,6 @@ static void HIDAPI_Driver8BitDo_HandleStatePacket(SDL_Joystick *joystick, SDL_Dr
         SDL_SendJoystickPowerInfo(joystick, state, percent);
         SDL_SendJoystickPowerInfo(joystick, state, percent);
     }
     }
 
 
-
     if (ctx->sensors_enabled) {
     if (ctx->sensors_enabled) {
         Uint64 sensor_timestamp;
         Uint64 sensor_timestamp;
         float values[3];
         float values[3];
@@ -440,7 +546,12 @@ static bool HIDAPI_Driver8BitDo_UpdateDevice(SDL_HIDAPI_Device *device)
             continue;
             continue;
         }
         }
 
 
-        HIDAPI_Driver8BitDo_HandleStatePacket(joystick, ctx, data, size);
+        if (size == 9) {
+            // Old firmware USB report for the SF30 Pro and SN30 Pro controllers
+            HIDAPI_Driver8BitDo_HandleOldStatePacket(joystick, ctx, data, size);
+        } else {
+            HIDAPI_Driver8BitDo_HandleStatePacket(joystick, ctx, data, size);
+        }
     }
     }
 
 
     if (size < 0) {
     if (size < 0) {

+ 2 - 1
src/joystick/usb_ids.h

@@ -60,9 +60,10 @@
 #define USB_VENDOR_ZEROPLUS     0x0c12
 #define USB_VENDOR_ZEROPLUS     0x0c12
 
 
 #define USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS             0x6012
 #define USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS             0x6012
+#define USB_PRODUCT_8BITDO_SF30_PRO                       0x6000    // B + START
+#define USB_PRODUCT_8BITDO_SF30_PRO_BT                    0x6100    // B + START
 #define USB_PRODUCT_8BITDO_SN30_PRO                       0x6001    // B + START
 #define USB_PRODUCT_8BITDO_SN30_PRO                       0x6001    // B + START
 #define USB_PRODUCT_8BITDO_SN30_PRO_BT                    0x6101    // B + START
 #define USB_PRODUCT_8BITDO_SN30_PRO_BT                    0x6101    // B + START
-#define USB_PRODUCT_8BITDO_SF30_PRO                       0x6000    // B + START
 #define USB_PRODUCT_8BITDO_PRO_2                          0x6003    // mode switch to D 
 #define USB_PRODUCT_8BITDO_PRO_2                          0x6003    // mode switch to D 
 #define USB_PRODUCT_8BITDO_PRO_2_BT                       0x6006    // mode switch to D 
 #define USB_PRODUCT_8BITDO_PRO_2_BT                       0x6006    // mode switch to D 
 #define USB_PRODUCT_AMAZON_LUNA_CONTROLLER                0x0419
 #define USB_PRODUCT_AMAZON_LUNA_CONTROLLER                0x0419