/* * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include "sdkconfig.h" #include "esp_log.h" #include "esp_netif.h" #include "driver/sdio_slave.h" #include "eppp_sdio.h" #include "esp_check.h" #if CONFIG_EPPP_LINK_DEVICE_SDIO_SLAVE #define BUFFER_NUM 4 #define BUFFER_SIZE SDIO_PAYLOAD static const char *TAG = "eppp_sdio_slave"; static DMA_ATTR uint8_t sdio_slave_rx_buffer[BUFFER_NUM][BUFFER_SIZE]; static DMA_ATTR uint8_t sdio_slave_tx_buffer[SDIO_PAYLOAD]; static int s_slave_request = 0; esp_err_t eppp_sdio_slave_tx(void *h, void *buffer, size_t len) { if (s_slave_request != REQ_INIT) { // silently skip the Tx if the SDIO not fully initialized return ESP_OK; } memcpy(sdio_slave_tx_buffer, buffer, len); size_t send_len = SDIO_ALIGN(len); if (send_len > len) { // pad with SOF's if the size is not 4 bytes aligned memset(&sdio_slave_tx_buffer[len], PPP_SOF, send_len - len); } ESP_LOG_BUFFER_HEXDUMP(TAG, sdio_slave_tx_buffer, send_len, ESP_LOG_VERBOSE); esp_err_t ret = sdio_slave_transmit(sdio_slave_tx_buffer, send_len); if (ret != ESP_OK) { ESP_LOGE(TAG, "sdio slave transmit error, ret : 0x%x", ret); // to inform the upper layers return ESP_ERR_NO_MEM; } return ESP_OK; } static esp_err_t slave_reset(void) { esp_err_t ret = ESP_OK; ESP_LOGI(TAG, "SDIO slave reset"); sdio_slave_stop(); ESP_GOTO_ON_ERROR(sdio_slave_reset(), err, TAG, "slave reset failed"); ESP_GOTO_ON_ERROR(sdio_slave_start(), err, TAG, "slave start failed"); while (1) { sdio_slave_buf_handle_t handle; ret = sdio_slave_send_get_finished(&handle, 0); if (ret == ESP_ERR_TIMEOUT) { break; } ESP_GOTO_ON_ERROR(ret, err, TAG, "slave-get-finished failed"); ESP_GOTO_ON_ERROR(sdio_slave_recv_load_buf(handle), err, TAG, "slave-load-buf failed"); } err: return ret; } esp_err_t eppp_sdio_slave_rx(esp_netif_t *netif) { if (s_slave_request == REQ_RESET) { ESP_LOGD(TAG, "request: %x", s_slave_request); slave_reset(); s_slave_request = REQ_INIT; } sdio_slave_buf_handle_t handle; size_t length; uint8_t *ptr; esp_err_t ret = sdio_slave_recv_packet(&handle, pdMS_TO_TICKS(1000)); if (ret == ESP_ERR_TIMEOUT) { return ESP_OK; } if (ret == ESP_ERR_NOT_FINISHED || ret == ESP_OK) { again: ptr = sdio_slave_recv_get_buf(handle, &length); esp_netif_receive(netif, ptr, length, NULL); if (sdio_slave_recv_load_buf(handle) != ESP_OK) { ESP_LOGE(TAG, "Failed to recycle packet buffer"); return ESP_FAIL; } if (ret == ESP_ERR_NOT_FINISHED) { ret = sdio_slave_recv_packet(&handle, 0); if (ret == ESP_ERR_NOT_FINISHED || ret == ESP_OK) { goto again; } } ESP_LOG_BUFFER_HEXDUMP(TAG, ptr, length, ESP_LOG_VERBOSE); return ESP_OK; } ESP_LOGE(TAG, "Error when receiving packet %d", ret); return ESP_FAIL; } static void event_cb(uint8_t pos) { ESP_EARLY_LOGI(TAG, "SDIO event: %d", pos); if (pos == SLAVE_INTR) { s_slave_request = sdio_slave_read_reg(SLAVE_REG_REQ); sdio_slave_write_reg(SLAVE_REG_REQ, 0); } } esp_err_t eppp_sdio_slave_init(void) { sdio_slave_config_t config = { .sending_mode = SDIO_SLAVE_SEND_PACKET, .send_queue_size = BUFFER_NUM, .recv_buffer_size = BUFFER_SIZE, .event_cb = event_cb, }; esp_err_t ret = sdio_slave_initialize(&config); if (ret != ESP_OK) { return ret; } for (int i = 0; i < BUFFER_NUM; i++) { sdio_slave_buf_handle_t handle = sdio_slave_recv_register_buf(sdio_slave_rx_buffer[i]); if (handle == NULL) { sdio_slave_deinit(); return ESP_FAIL; } ret = sdio_slave_recv_load_buf(handle); if (ret != ESP_OK) { sdio_slave_deinit(); return ESP_FAIL; } } sdio_slave_set_host_intena(SDIO_SLAVE_HOSTINT_SEND_NEW_PACKET); // only need one interrupt to notify of a new packet ret = sdio_slave_start(); if (ret != ESP_OK) { sdio_slave_deinit(); return ESP_FAIL; } return ESP_OK; } void eppp_sdio_slave_deinit(void) { sdio_slave_stop(); sdio_slave_deinit(); } #else // SOC_SDIO_SLAVE NOT-SUPPORTED esp_err_t eppp_sdio_slave_tx(void *h, void *buffer, size_t len) { return ESP_ERR_NOT_SUPPORTED; } esp_err_t eppp_sdio_slave_rx(esp_netif_t *netif) { return ESP_ERR_NOT_SUPPORTED; } void eppp_sdio_slave_deinit(void) { } esp_err_t eppp_sdio_slave_init(void) { return ESP_ERR_NOT_SUPPORTED; } #endif // CONFIG_SOC_SDIO_SLAVE_SUPPORTED