#pragma once #include #include #ifndef SWITCH_PICO_HID_INSTANCE_COUNT #define SWITCH_PICO_HID_INSTANCE_COUNT 1 #endif #if SWITCH_PICO_HID_INSTANCE_COUNT < 1 || SWITCH_PICO_HID_INSTANCE_COUNT > 4 #error "SWITCH_PICO_HID_INSTANCE_COUNT must be between 1 and 4" #endif namespace XInputFeasibility { constexpr uint16_t kPrototypeVendorId = 0xcafe; constexpr uint16_t kPrototypeProductId = 0x4010; constexpr uint16_t kPrototypeDeviceRevision = 0x0101; constexpr uint8_t kInterfaceDescriptorSize = 39; constexpr uint16_t kConfigurationDescriptorSize = 9 + SWITCH_PICO_HID_INSTANCE_COUNT * kInterfaceDescriptorSize; constexpr uint16_t kMsCompatIdDescriptorSize = 16 + SWITCH_PICO_HID_INSTANCE_COUNT * 24; constexpr uint8_t kMsVendorRequest = 0x20; constexpr uint16_t kMsCompatIdIndex = 0x0004; constexpr uint16_t kSwitchProbeVendorId = 0x057e; constexpr uint16_t kSwitchProbeProductId = 0x2009; // Windows caches Microsoft OS descriptor support by VID, PID, and bcdDevice. // Use a revision distinct from genuine Pro Controllers so their cached // "unsupported" result cannot suppress this probe's 0xEE request. constexpr uint16_t kSwitchProbeDeviceRevision = 0x0211; static const uint8_t kSwitchProbeDeviceDescriptor[] = { 0x12, 0x01, // Device descriptor 0x00, 0x02, // USB 2.0 0x00, 0x00, 0x00, // Class information comes from the interface descriptor 0x40, // Endpoint zero packet size static_cast(kSwitchProbeVendorId & 0xff), static_cast(kSwitchProbeVendorId >> 8), static_cast(kSwitchProbeProductId & 0xff), static_cast(kSwitchProbeProductId >> 8), static_cast(kSwitchProbeDeviceRevision & 0xff), static_cast(kSwitchProbeDeviceRevision >> 8), 0x01, 0x02, 0x03, // Manufacturer, product, serial strings 0x01, // One configuration }; static const uint8_t kDeviceDescriptor[] = { 0x12, 0x01, // Device descriptor 0x00, 0x02, // USB 2.0 0x00, 0x00, 0x00, // Composite device; each interface binds to the XUSB driver 0x40, // Endpoint zero packet size static_cast(kPrototypeVendorId & 0xff), static_cast(kPrototypeVendorId >> 8), static_cast(kPrototypeProductId & 0xff), static_cast(kPrototypeProductId >> 8), static_cast(kPrototypeDeviceRevision & 0xff), static_cast(kPrototypeDeviceRevision >> 8), 0x01, 0x02, 0x03, // Manufacturer, product, serial strings 0x01, // One configuration }; #define XINPUT_FEASIBILITY_INTERFACE(number, endpoint) \ 0x09, 0x04, number, 0x00, 0x02, 0xff, 0x5d, 0x01, 0x00, 0x10, 0x21, 0x10, \ 0x01, 0x01, 0x24, static_cast(0x80 | endpoint), 0x14, 0x03, \ 0x00, 0x03, 0x13, endpoint, 0x00, 0x03, 0x00, 0x07, 0x05, \ static_cast(0x80 | endpoint), 0x03, 0x20, 0x00, 0x04, 0x07, \ 0x05, endpoint, 0x03, 0x20, 0x00, 0x08 static const uint8_t kConfigurationDescriptor[] = { 0x09, 0x02, static_cast(kConfigurationDescriptorSize & 0xff), static_cast(kConfigurationDescriptorSize >> 8), SWITCH_PICO_HID_INSTANCE_COUNT, 0x01, 0x00, 0x80, 0xfa, XINPUT_FEASIBILITY_INTERFACE(0x00, 0x01), #if SWITCH_PICO_HID_INSTANCE_COUNT >= 2 XINPUT_FEASIBILITY_INTERFACE(0x01, 0x02), #endif #if SWITCH_PICO_HID_INSTANCE_COUNT >= 3 XINPUT_FEASIBILITY_INTERFACE(0x02, 0x03), #endif #if SWITCH_PICO_HID_INSTANCE_COUNT >= 4 XINPUT_FEASIBILITY_INTERFACE(0x03, 0x04), #endif }; #undef XINPUT_FEASIBILITY_INTERFACE #define XINPUT_FEASIBILITY_COMPAT_FUNCTION(number) \ number, 0x01, 'X', 'U', 'S', 'B', '1', '0', 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 static const uint8_t kMsCompatIdDescriptor[] = { static_cast(kMsCompatIdDescriptorSize & 0xff), static_cast(kMsCompatIdDescriptorSize >> 8), 0x00, 0x00, 0x00, 0x01, // Microsoft OS descriptor version 1.0 0x04, 0x00, // Extended compatible ID descriptor SWITCH_PICO_HID_INSTANCE_COUNT, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, XINPUT_FEASIBILITY_COMPAT_FUNCTION(0x00), #if SWITCH_PICO_HID_INSTANCE_COUNT >= 2 XINPUT_FEASIBILITY_COMPAT_FUNCTION(0x01), #endif #if SWITCH_PICO_HID_INSTANCE_COUNT >= 3 XINPUT_FEASIBILITY_COMPAT_FUNCTION(0x02), #endif #if SWITCH_PICO_HID_INSTANCE_COUNT >= 4 XINPUT_FEASIBILITY_COMPAT_FUNCTION(0x03), #endif }; #undef XINPUT_FEASIBILITY_COMPAT_FUNCTION static const uint8_t kProbeMsCompatIdDescriptor[] = { 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; static_assert(sizeof(kDeviceDescriptor) == 18); static_assert(sizeof(kSwitchProbeDeviceDescriptor) == 18); static_assert(sizeof(kConfigurationDescriptor) == kConfigurationDescriptorSize); static_assert(sizeof(kMsCompatIdDescriptor) == kMsCompatIdDescriptorSize); static_assert(sizeof(kProbeMsCompatIdDescriptor) == 16); } // namespace XInputFeasibility