// SPDX-License-Identifier: GPL-2.0-or-later #include "SpiCallback.h" #include "SpiBus.h" #include #include namespace SpiCallback { namespace { struct CallbackData { std::shared_ptr bus; std::shared_ptr config; transaction_cb_t inner_pre_cb; transaction_cb_t inner_post_cb; }; std::array, SPI_MANAGER_CALLBACK_COUNT> instances; template void IRAM_ATTR fn_pre_cb(spi_transaction_t* trans) { instances[N]->bus->require_config(instances[N]->config.get()); if (instances[N]->inner_pre_cb) instances[N]->inner_pre_cb(trans); } template void IRAM_ATTR fn_post_cb(spi_transaction_t* trans) { if (instances[N]->inner_post_cb) instances[N]->inner_post_cb(trans); } template inline __attribute__((always_inline)) bool alloc(CallbackData*& instance, transaction_cb_t& pre_cb, transaction_cb_t& post_cb) { if constexpr (N > 0) { if (alloc(instance, pre_cb, post_cb)) return true; if (!instances[N - 1]) { instances[N - 1].emplace(); instance = &*instances[N - 1]; pre_cb = fn_pre_cb; post_cb = fn_post_cb; return true; } } return false; } } bool patch(const std::shared_ptr& bus, const std::shared_ptr& bus_config, spi_device_interface_config_t& device_config) { CallbackData* instance; transaction_cb_t pre_cb; transaction_cb_t post_cb; if (!alloc(instance, pre_cb, post_cb)) return false; instance->bus = bus; instance->config = bus_config; instance->inner_pre_cb = device_config.pre_cb; instance->inner_post_cb = device_config.post_cb; device_config.pre_cb = pre_cb; device_config.post_cb = post_cb; return true; } }