Harden legacy bounds
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
parent
6f18b65217
commit
e2a7635f2f
3 changed files with 228 additions and 49 deletions
|
|
@ -1,4 +1,5 @@
|
|||
#include "switch_pro_driver.h"
|
||||
#include "switch_pro_bounds.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
|
@ -178,9 +179,14 @@ static const uint8_t user_calibration_data[0x3F] = {
|
|||
static const SwitchFactoryConfig* factory_config = reinterpret_cast<const SwitchFactoryConfig*>(factory_config_data);
|
||||
static const SwitchUserCalibration* user_calibration [[maybe_unused]] = reinterpret_cast<const SwitchUserCalibration*>(user_calibration_data);
|
||||
|
||||
static std::map<uint32_t, const uint8_t*> spi_flash_data = {
|
||||
{0x6000, factory_config_data},
|
||||
{0x8000, user_calibration_data}
|
||||
struct SpiFlashRegion {
|
||||
const uint8_t* data;
|
||||
std::size_t size;
|
||||
};
|
||||
|
||||
static const std::map<uint32_t, SpiFlashRegion> spi_flash_data = {
|
||||
{0x6000, {factory_config_data, sizeof(factory_config_data)}},
|
||||
{0x8000, {user_calibration_data, sizeof(user_calibration_data)}}
|
||||
};
|
||||
|
||||
static inline uint16_t scale16To12(uint16_t pos) { return pos >> 4; }
|
||||
|
|
@ -235,16 +241,32 @@ static bool send_report(uint8_t reportID, const void* reportData, uint16_t repor
|
|||
return result;
|
||||
}
|
||||
|
||||
static void read_spi_flash(uint8_t* dest, uint32_t address, uint8_t size) {
|
||||
static void read_spi_flash(
|
||||
uint8_t* destination,
|
||||
std::size_t destination_capacity,
|
||||
uint32_t address,
|
||||
uint8_t size) {
|
||||
uint32_t addressBank = address & 0xFFFFFF00;
|
||||
uint32_t addressOffset = address & 0x000000FF;
|
||||
auto it = spi_flash_data.find(addressBank);
|
||||
|
||||
if (it != spi_flash_data.end()) {
|
||||
const uint8_t* data = it->second;
|
||||
memcpy(dest, data + addressOffset, size);
|
||||
const SpiFlashRegion& region = it->second;
|
||||
switch_pro_fill_flash_read(
|
||||
destination,
|
||||
destination_capacity,
|
||||
region.data,
|
||||
region.size,
|
||||
addressOffset,
|
||||
size);
|
||||
} else {
|
||||
memset(dest, 0xFF, size);
|
||||
switch_pro_fill_flash_read(
|
||||
destination,
|
||||
destination_capacity,
|
||||
nullptr,
|
||||
0,
|
||||
0,
|
||||
size);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -371,7 +393,11 @@ static void handle_feature_report(uint8_t switchReportID, uint8_t switchReportSu
|
|||
report_buffer[17] = reportData[13];
|
||||
report_buffer[18] = reportData[14];
|
||||
report_buffer[19] = reportData[15];
|
||||
read_spi_flash(&report_buffer[20], spiReadAddress, spiReadSize);
|
||||
read_spi_flash(
|
||||
&report_buffer[20],
|
||||
sizeof(report_buffer) - 20,
|
||||
spiReadAddress,
|
||||
spiReadSize);
|
||||
canSend = true;
|
||||
LOG_PRINTF("[HID] FEATURE SPI_READ addr=0x%08lx size=%u\n", (unsigned long)spiReadAddress, spiReadSize);
|
||||
break;
|
||||
|
|
@ -642,6 +668,52 @@ bool switch_pro_is_ready() {
|
|||
return is_ready;
|
||||
}
|
||||
|
||||
static void dispatch_output_report(
|
||||
uint8_t instance,
|
||||
uint8_t report_id,
|
||||
const uint8_t* buffer,
|
||||
uint16_t length) {
|
||||
if (instance != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const SwitchProOutputReportKind kind =
|
||||
switch_pro_classify_output_report(buffer, length);
|
||||
if (kind == SwitchProOutputReportKind::Ignore) {
|
||||
return;
|
||||
}
|
||||
if (kind == SwitchProOutputReportKind::Feature &&
|
||||
buffer[10] == SPI_READ &&
|
||||
!switch_pro_spi_read_size_fits(buffer[15])) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(report_buffer, 0x00, sizeof(report_buffer));
|
||||
|
||||
const uint8_t switchReportID = buffer[0];
|
||||
const uint8_t switchReportSubID = buffer[1];
|
||||
LOG_PRINTF("[HID] output_report id=%u switchRID=0x%02x sub=0x%02x len=%u\n",
|
||||
report_id, switchReportID, switchReportSubID, length);
|
||||
|
||||
switch (kind) {
|
||||
case SwitchProOutputReportKind::Noop:
|
||||
return;
|
||||
case SwitchProOutputReportKind::Rumble:
|
||||
forward_rumble_to_host(buffer, length);
|
||||
return;
|
||||
case SwitchProOutputReportKind::Feature:
|
||||
queued_report_id = report_id;
|
||||
handle_feature_report(switchReportID, switchReportSubID, buffer, length);
|
||||
return;
|
||||
case SwitchProOutputReportKind::Configuration:
|
||||
queued_report_id = report_id;
|
||||
handle_config_report(switchReportID, switchReportSubID, buffer, length);
|
||||
return;
|
||||
case SwitchProOutputReportKind::Ignore:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// HID callbacks
|
||||
uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) {
|
||||
(void)instance;
|
||||
|
|
@ -656,51 +728,12 @@ uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_t
|
|||
}
|
||||
|
||||
void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {
|
||||
(void)instance;
|
||||
if (report_type != HID_REPORT_TYPE_OUTPUT) return;
|
||||
|
||||
memset(report_buffer, 0x00, bufsize);
|
||||
|
||||
uint8_t switchReportID = buffer[0];
|
||||
uint8_t switchReportSubID = buffer[1];
|
||||
LOG_PRINTF("[HID] set_report type=%d id=%u switchRID=0x%02x sub=0x%02x len=%u\n",
|
||||
report_type, report_id, switchReportID, switchReportSubID, bufsize);
|
||||
if (switchReportID == REPORT_OUTPUT_10 || switchReportID == REPORT_OUTPUT_21) {
|
||||
forward_rumble_to_host(buffer, bufsize);
|
||||
}
|
||||
if (switchReportID == REPORT_OUTPUT_00) {
|
||||
// No-op, just acknowledge to clear any stalls.
|
||||
return;
|
||||
} else if (switchReportID == REPORT_FEATURE) {
|
||||
queued_report_id = report_id;
|
||||
handle_feature_report(switchReportID, switchReportSubID, buffer, bufsize);
|
||||
} else if (switchReportID == REPORT_CONFIGURATION) {
|
||||
queued_report_id = report_id;
|
||||
handle_config_report(switchReportID, switchReportSubID, buffer, bufsize);
|
||||
} else {
|
||||
}
|
||||
dispatch_output_report(instance, report_id, buffer, bufsize);
|
||||
}
|
||||
|
||||
void tud_hid_report_received_cb(uint8_t instance, uint8_t report_id, uint8_t const* buffer, uint16_t bufsize) {
|
||||
(void)instance;
|
||||
// Host sent data on interrupt OUT; mirror the control path handling.
|
||||
memset(report_buffer, 0x00, bufsize);
|
||||
uint8_t switchReportID = buffer[0];
|
||||
uint8_t switchReportSubID = buffer[1];
|
||||
LOG_PRINTF("[HID] report_received id=%u switchRID=0x%02x sub=0x%02x len=%u\n",
|
||||
report_id, switchReportID, switchReportSubID, bufsize);
|
||||
if (switchReportID == REPORT_OUTPUT_10 || switchReportID == REPORT_OUTPUT_21) {
|
||||
forward_rumble_to_host(buffer, bufsize);
|
||||
}
|
||||
if (switchReportID == REPORT_OUTPUT_00) {
|
||||
return;
|
||||
} else if (switchReportID == REPORT_FEATURE) {
|
||||
queued_report_id = report_id;
|
||||
handle_feature_report(switchReportID, switchReportSubID, buffer, bufsize);
|
||||
} else if (switchReportID == REPORT_CONFIGURATION) {
|
||||
queued_report_id = report_id;
|
||||
handle_config_report(switchReportID, switchReportSubID, buffer, bufsize);
|
||||
}
|
||||
dispatch_output_report(instance, report_id, buffer, bufsize);
|
||||
}
|
||||
|
||||
uint8_t const * tud_hid_descriptor_report_cb(uint8_t itf) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue