/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2025 Xenia Canary. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ #ifndef XENIA_KERNEL_SMC_H_ #define XENIA_KERNEL_SMC_H_ #include #include #include #include enum X_DVD_DISC_STATE { NO_DISC, XBOX_360_GAME_DISC, XBOX_GAME_DISC, UNKNOWN_DISC, MOVIE_DVD, MOVIE_DVD2, MOVIE_DVD3, CD, MIXED_MEDIA_DISC, UNKNOWN_DISC2, }; enum class X_DVD_TRAY_STATE : uint8_t { OPEN, UNKNOWN, CLOSED, OPENING, CLOSING }; enum REMOTE_CONTROL : uint8_t { MEDIA_REMOTE_BOTH = 0x01, MEDIA_REMOTE_360 = 0x0F }; enum TILT_STATE : uint8_t { VERTICAL, HORIZONTAL }; enum POWER_LED_STATE : uint8_t { POWER_ON = 0x01, POWER_DEFAULT = 0x02, POWER_OFF = 0x03, POWER_BLINK = 0x10 }; enum LED_STATE : uint8_t { OFF = 0x00, RED = 0x08, GREEN = 0x80, ORANGE = 0x88 }; // https://free60.org/Hardware/Console/SMC_Command_0x01/#query-power-on-type enum POWERON_TYPE : uint8_t { POWER_BUTTON = 0x11, EJECT_BUTTON = 0x12, RTC_WAKEUP = 0x15, UNKNOWN_POWERON_1 = 0x16, REMOTE_POWER_BUTTON = 0x20, REMOTE_EJECT_BUTTON = 0x21, REMOTE_X_BUTTON = 0x22, REMOTE_WIN_BUTTON = 0x24, HARD_RESET = 0x30, // HalReturnToFirmware(1, 2, or 3) RESET_CYCLE = 0x31, UNKNOWN_POWERON_2 = 0x41, KIOSK = 0x51, WIRELESS_CONTROLLER_BUTTON = 0x55, // controller middle button/start button (e.g. Turntable, drums, // guitar, 360 controller) GAME_PORT_1 = 0x56, GAME_PORT_2 = 0x57, EXPANSION_RESUME = 0x5A, }; // https://free60.org/Hardware/Console/SMC_Command_0x82/ enum class STANDBY_TYPE : uint16_t { POWER_OFF = 0x0100, POWER_OFF_RTC = 0x0132, // verify this HARD_RESET = 0x0430, // 04 30 ?? SOFT_RESET = 0x0431, // 04 31 ?? reset_cycle CLEAR = 0x0433 }; // https://free60.org/Hardware/Console/SMC/ enum X_SMC_CMD : uint8_t { POWERON_STATE = 0x1, QUERY_RTC = 0x4, QUERY_TEMP_SENSOR = 0x7, QUERY_TRAY = 0xA, QUERY_UNK_0xB = 0xB, // called on start up after VdQueryVideoMode on dash v13599 QUERY_AV_PACK = 0xF, I2C_READ_WRITE = 0x11, QUERY_SMC_VERSION = 0x12, FIFO_TEST = 0x13, QUERY_IR_ADDRESS = 0x16, QUERY_TILT_SENSOR = 0x17, READ_82_INTERRUPTS = 0x1E, READ_8E_INTERRUPTS = 0x20, SET_STANDBY = 0x82, SET_TIME = 0x85, SET_FAN_ALGORITHM = 0x88, SET_FAN_SPEED_CPU = 0x89, SET_DVD_TRAY = 0x8B, SET_POWER_LED = 0x8C, SET_AUDIO_MUTE = 0x8D, ARGON_RELATED = 0x90, SET_FAN_SPEED_GPU = 0x94, // not present on slim, not used/respected on newer fat SET_IR_ADDRESS = 0x95, SET_DVD_TRAY_SECURE = 0x98, SET_LEDS = 0x99, SET_RTC_WAKE = 0x9A, ANA_RELATED = 0x9B, SET_ASYNC_OPERATION = 0x9C, SET_82_INTERRUPTS = 0x9D, SET_9F_INTERRUPTS = 0x9F, }; struct X_TEMPERATURE_DATA { uint8_t integer_value_; uint8_t fractional_value_; void SetTemp(float celsius_temp) { const uint16_t value = static_cast(celsius_temp * 256.0f); integer_value_ = value & 0xFF; fractional_value_ = value >> 8; } }; struct X_SMC_DATA { X_SMC_CMD command; union { uint8_t smc_data[15]; // POWERON_STATE struct { uint8_t poweron_state; uint8_t reserved; // always 00 uint8_t unk1; uint8_t unk2; uint8_t unk3; } poweron_state; // QUERY_TEMP_SENSOR struct { X_TEMPERATURE_DATA cpu; X_TEMPERATURE_DATA gpu; X_TEMPERATURE_DATA edram; X_TEMPERATURE_DATA mb; } temps; // QUERY_TRAY struct { X_DVD_TRAY_STATE state; } dvd_tray; // QUERY_AV_PACK struct { uint8_t av_pack; } av_pack; // QUERY_SMC_VERSION struct { uint8_t unk; uint8_t major; uint8_t minor; } smc_version; // QUERY_IR_ADDRESS struct { REMOTE_CONTROL ir_address; } ir_address; // QUERY_TILT_SENSOR struct { TILT_STATE tilt_state; } tilt_state; // SET_STANDBY struct { uint16_t standby_state; uint8_t unkn; } set_standby; // POWER_LED_STATE struct { POWER_LED_STATE state; uint8_t animate; } power_led_state; // LED_STATE struct { LED_STATE state; uint8_t region; // top_left >> 3 | top_right >> 2 | bottom_left >> 1 | // bottom_right; } led_state; }; }; namespace xe { namespace kernel { // SMC = System Management Controller // https://github.com/landaire/LaunchCode/blob/master/LaunchCode/smc.cpp // https://github.com/XboxUnity/freestyledash/blob/master/Freestyle/Tools/SMC/smc.cpp class SystemManagementController { public: SystemManagementController(); ~SystemManagementController(); std::array GetSMCVersion() const { return smc_version; } X_DVD_TRAY_STATE GetTrayState() const { return dvd_tray_state_; } void SetTrayState(X_DVD_TRAY_STATE state); void CallCommand(X_SMC_DATA* smc_message, X_SMC_DATA* smc_response); private: const std::array smc_version = {65, 2, 1}; const std::map av_pack_to_smc_value = { {0, 0x43}, {3, 0x4F}, {4, 0x13}, {5, 0x0F}, {6, 0x5B}, {8, 0x1F}}; void QueryTemperatureSensor(X_SMC_DATA* smc_message, X_SMC_DATA* smc_response); void QueryDriveTraySensor(X_SMC_DATA* smc_message, X_SMC_DATA* smc_response); void QueryAvPack(X_SMC_DATA* smc_message, X_SMC_DATA* smc_response); void QuerySmcVersion(X_SMC_DATA* smc_message, X_SMC_DATA* smc_response); void QueryIRAddress(X_SMC_DATA* smc_message, X_SMC_DATA* smc_response); void QueryTiltState(X_SMC_DATA* smc_message, X_SMC_DATA* smc_response); void SetDriveTray(X_SMC_DATA* smc_message, X_SMC_DATA* smc_response); void SetFanSpeed(X_SMC_DATA* smc_message, X_SMC_DATA* smc_response); void SetIRAddress(X_SMC_DATA* smc_message, X_SMC_DATA* smc_response); void SetStandby(X_SMC_DATA* smc_message, X_SMC_DATA* smc_response); void SetPowerLed(X_SMC_DATA* smc_message, X_SMC_DATA* smc_response); void SetLedState(X_SMC_DATA* smc_message, X_SMC_DATA* smc_response); std::map> smc_commands_; X_DVD_TRAY_STATE dvd_tray_state_ = X_DVD_TRAY_STATE::OPEN; REMOTE_CONTROL ir_address_ = REMOTE_CONTROL::MEDIA_REMOTE_360; TILT_STATE tilt_state_ = TILT_STATE::VERTICAL; uint32_t cpu_fan_speed_ = 100; uint32_t gpu_fan_speed_ = 100; std::pair power_led_state_ = { POWER_LED_STATE::POWER_ON, 0x00}; std::pair led_state_ = {LED_STATE::GREEN, 0x01}; }; } // namespace kernel } // namespace xe #endif