components/esp_eth/src/esp_eth.c
////////////////////////////////User face APIs////////////////////////////////////////////////
// User has to pass the handle of Ethernet driver to each API.
// Different Ethernet driver instance is identified with a unique handle.
// It's helpful for us to support multiple Ethernet port on ESP32.
//////////////////////////////////////////////////////////////////////////////////////////////
User face APIs
User has to pass the handle of Ethernet driver to each API.
Different Ethernet driver instance is identified with a unique handle.
It's helpful for us to support multiple Ethernet port on ESP32.
User face APIs User has to pass the handle of Ethernet driver to each API . Different Ethernet driver instance is identified with a unique handle . It ' s helpful for us to support multiple Ethernet port on ESP32 .
esp_err_t esp_eth_driver_install(const esp_eth_config_t *config, esp_eth_handle_t *out_hdl)
{
    esp_err_t ret = ESP_OK;
    esp_eth_mac_t *mac = NULL;
    esp_eth_phy_t *phy = NULL;
    esp_eth_driver_t *eth_driver = NULL;
    ESP_GOTO_ON_FALSE(config && out_hdl, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
    mac = config->mac;
    phy = config->phy;
    ESP_GOTO_ON_FALSE(mac && phy, ESP_ERR_INVALID_ARG, err, TAG, "can't set eth->mac or eth->phy to null");
    eth_driver = heap_caps_calloc(1, sizeof(esp_eth_driver_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
    ESP_GOTO_ON_FALSE(eth_driver, ESP_ERR_NO_MEM, err, TAG, "no mem for eth_driver");
    const esp_timer_create_args_t check_link_timer_args = {
        .callback = eth_check_link_timer_cb,
        .name = "eth_link_timer",
        .arg = eth_driver,
        .skip_unhandled_events = true
    };
    ESP_GOTO_ON_ERROR(esp_timer_create(&check_link_timer_args, &eth_driver->check_link_timer), err, TAG, "create link timer failed");
    atomic_init(&eth_driver->ref_count, 1);
    atomic_init(&eth_driver->fsm, ESP_ETH_FSM_STOP);
    eth_driver->mac = mac;
    eth_driver->phy = phy;
    eth_driver->link = ETH_LINK_DOWN;
    eth_driver->duplex = ETH_DUPLEX_HALF;
    eth_driver->speed = ETH_SPEED_10M;
    eth_driver->stack_input = config->stack_input;
    eth_driver->on_lowlevel_init_done = config->on_lowlevel_init_done;
    eth_driver->on_lowlevel_deinit_done = config->on_lowlevel_deinit_done;
    eth_driver->check_link_period_ms = config->check_link_period_ms;
    eth_driver->customized_read_phy_reg = config->read_phy_reg;
    eth_driver->customized_write_phy_reg = config->write_phy_reg;
    eth_driver->mediator.phy_reg_read = eth_phy_reg_read;
    eth_driver->mediator.phy_reg_write = eth_phy_reg_write;
    eth_driver->mediator.stack_input = eth_stack_input;
    eth_driver->mediator.on_state_changed = eth_on_state_changed;
    mac->set_mediator(mac, &eth_driver->mediator);
    phy->set_mediator(phy, &eth_driver->mediator);
    phy->reset_hw(phy);
    ESP_GOTO_ON_ERROR(mac->init(mac), err, TAG, "init mac failed");
    ESP_GOTO_ON_ERROR(phy->init(phy), err, TAG, "init phy failed");
    ESP_LOGD(TAG, "new ethernet driver @%p", eth_driver);
    *out_hdl = eth_driver;
#if CONFIG_ESP_NETIF_TCPIP_ADAPTER_COMPATIBLE_LAYER
    extern esp_err_t tcpip_adapter_compat_start_eth(void *eth_driver);
    tcpip_adapter_compat_start_eth(eth_driver);
#endif
    return ESP_OK;
err:
    if (eth_driver) {
        if (eth_driver->check_link_timer) {
            esp_timer_delete(eth_driver->check_link_timer);
        }
        free(eth_driver);
    }
    return ret;
}
esp_err_t esp_eth_driver_install ( const esp_eth_config_t * config , esp_eth_handle_t * out_hdl ) { esp_err_t ret = ESP_OK ; esp_eth_mac_t * mac = NULL ; esp_eth_phy_t * phy = NULL ; esp_eth_driver_t * eth_driver = NULL ; ESP_GOTO_ON_FALSE ( config && out_hdl , ESP_ERR_INVALID_ARG , err , TAG , " " ) ; mac = config -> mac ; phy = config -> phy ; ESP_GOTO_ON_FALSE ( mac && phy , ESP_ERR_INVALID_ARG , err , TAG , " " ) ; eth_driver = heap_caps_calloc ( 1 , sizeof ( esp_eth_driver_t ) , MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT ) ; ESP_GOTO_ON_FALSE ( eth_driver , ESP_ERR_NO_MEM , err , TAG , " " ) ; const esp_timer_create_args_t check_link_timer_args = { . callback = eth_check_link_timer_cb , . name = " " , . arg = eth_driver , . skip_unhandled_events = true } ; ESP_GOTO_ON_ERROR ( esp_timer_create ( & check_link_timer_args , & eth_driver -> check_link_timer ) , err , TAG , " " ) ; atomic_init ( & eth_driver -> ref_count , 1 ) ; atomic_init ( & eth_driver -> fsm , ESP_ETH_FSM_STOP ) ; eth_driver -> mac = mac ; eth_driver -> phy = phy ; eth_driver -> link = ETH_LINK_DOWN ; eth_driver -> duplex = ETH_DUPLEX_HALF ; eth_driver -> speed = ETH_SPEED_10M ; eth_driver -> stack_input = config -> stack_input ; eth_driver -> on_lowlevel_init_done = config -> on_lowlevel_init_done ; eth_driver -> on_lowlevel_deinit_done = config -> on_lowlevel_deinit_done ; eth_driver -> check_link_period_ms = config -> check_link_period_ms ; eth_driver -> customized_read_phy_reg = config -> read_phy_reg ; eth_driver -> customized_write_phy_reg = config -> write_phy_reg ; eth_driver -> mediator . phy_reg_read = eth_phy_reg_read ; eth_driver -> mediator . phy_reg_write = eth_phy_reg_write ; eth_driver -> mediator . stack_input = eth_stack_input ; eth_driver -> mediator . on_state_changed = eth_on_state_changed ; mac -> set_mediator ( mac , & eth_driver -> mediator ) ; phy -> set_mediator ( phy , & eth_driver -> mediator ) ; phy -> reset_hw ( phy ) ; ESP_GOTO_ON_ERROR ( mac -> init ( mac ) , err , TAG , " " ) ; ESP_GOTO_ON_ERROR ( phy -> init ( phy ) , err , TAG , " " ) ; ESP_LOGD ( TAG , " " , eth_driver ) ; * out_hdl = eth_driver ; #if CONFIG_ESP_NETIF_TCPIP_ADAPTER_COMPATIBLE_LAYER extern esp_err_t tcpip_adapter_compat_start_eth ( void * eth_driver ) ; tcpip_adapter_compat_start_eth ( eth_driver ) ; #endif return ESP_OK ; err : if ( eth_driver ) { if ( eth_driver -> check_link_timer ) { esp_timer_delete ( eth_driver -> check_link_timer ) ; } free ( eth_driver ) ; } return ret ; }
User face APIs
User has to pass the handle of Ethernet driver to each API.
User face APIs User has to pass the handle of Ethernet driver to each API .
// eth_driver contains an atomic variable, which should not be put in PSRAM // set mediator for both mac and phy object, so that mac and phy are connected to each other via mediator // for PHY whose internal PLL has been configured to generate RMII clock, but is put in reset state during power up, // we need to deasseert the reset GPIO of PHY device first, ensure the RMII is clocked out from PHY // init MAC first, so that MAC can generate the correct SMI signals // for backward compatible to 4.0, and will get removed in 5.0