1
6
7
17
18
19
23
24
25
26
27
28
29
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
87
88
99
100
101
102
103
106
107
108
109
110
111
112
113
114
115
116
117
130
131
132
133
140
141
142
162
163
164
165
166
167
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
199
200
201
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
349
350
351
352
353
354
355
356
360
361
362
363
364
365
366
367
368
369
370
371
372
373
378
379
380
381
382
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
408
412
415
419
429
433
440
444
448
453
460
464
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
/* ... */
#include <sys/cdefs.h>
#include <stdatomic.h>
#include "esp_log.h"
#include "esp_check.h"
#include "esp_eth_driver.h"
#include "esp_event.h"
#include "esp_heap_caps.h"
#include "esp_timer.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"10 includes
#if CONFIG_ETH_TRANSMIT_MUTEX
/* ... */
#define ESP_ETH_TX_TIMEOUT_MS 250/* ... */
#endif
static const char *TAG = "esp_eth";
ESP_EVENT_DEFINE_BASE(ETH_EVENT);
typedef enum {
ESP_ETH_FSM_STOP,
ESP_ETH_FSM_START
}{ ... } esp_eth_fsm_t;
/* ... */
typedef struct {
esp_eth_mediator_t mediator;
esp_eth_phy_t *phy;
esp_eth_mac_t *mac;
esp_timer_handle_t check_link_timer;
uint32_t check_link_period_ms;
bool auto_nego_en;
eth_speed_t speed;
eth_duplex_t duplex;
_Atomic eth_link_t link;
atomic_int ref_count;
void *priv;
_Atomic esp_eth_fsm_t fsm;
#if CONFIG_ETH_TRANSMIT_MUTEX
SemaphoreHandle_t transmit_mutex;
#endif
esp_err_t (*stack_input)(esp_eth_handle_t eth_handle, uint8_t *buffer, uint32_t length, void *priv);
esp_err_t (*on_lowlevel_init_done)(esp_eth_handle_t eth_handle);
esp_err_t (*on_lowlevel_deinit_done)(esp_eth_handle_t eth_handle);
esp_err_t (*customized_read_phy_reg)(esp_eth_handle_t eth_handle, uint32_t phy_addr, uint32_t phy_reg, uint32_t *reg_value);
esp_err_t (*customized_write_phy_reg)(esp_eth_handle_t eth_handle, uint32_t phy_addr, uint32_t phy_reg, uint32_t reg_value);
}{ ... } esp_eth_driver_t;
static esp_err_t eth_phy_reg_read(esp_eth_mediator_t *eth, uint32_t phy_addr, uint32_t phy_reg, uint32_t *reg_value)
{
esp_eth_driver_t *eth_driver = __containerof(eth, esp_eth_driver_t, mediator);
if (eth_driver->customized_read_phy_reg) {
return eth_driver->customized_read_phy_reg(eth_driver, phy_addr, phy_reg, reg_value);
}{...}
esp_eth_mac_t *mac = eth_driver->mac;
return mac->read_phy_reg(mac, phy_addr, phy_reg, reg_value);
}{ ... }
static esp_err_t eth_phy_reg_write(esp_eth_mediator_t *eth, uint32_t phy_addr, uint32_t phy_reg, uint32_t reg_value)
{
esp_eth_driver_t *eth_driver = __containerof(eth, esp_eth_driver_t, mediator);
if (eth_driver->customized_write_phy_reg) {
return eth_driver->customized_write_phy_reg(eth_driver, phy_addr, phy_reg, reg_value);
}{...}
esp_eth_mac_t *mac = eth_driver->mac;
return mac->write_phy_reg(mac, phy_addr, phy_reg, reg_value);
}{ ... }
static esp_err_t eth_stack_input(esp_eth_mediator_t *eth, uint8_t *buffer, uint32_t length)
{
esp_eth_driver_t *eth_driver = __containerof(eth, esp_eth_driver_t, mediator);
if (eth_driver->stack_input) {
return eth_driver->stack_input((esp_eth_handle_t)eth_driver, buffer, length, eth_driver->priv);
}{...}
free(buffer);
return ESP_OK;
}{ ... }
static esp_err_t eth_on_state_changed(esp_eth_mediator_t *eth, esp_eth_state_t state, void *args)
{
esp_err_t ret = ESP_OK;
esp_eth_driver_t *eth_driver = __containerof(eth, esp_eth_driver_t, mediator);
esp_eth_mac_t *mac = eth_driver->mac;
switch (state) {
case ETH_STATE_LLINIT: {
if (eth_driver->on_lowlevel_init_done) {
ESP_GOTO_ON_ERROR(eth_driver->on_lowlevel_init_done(eth_driver), err, TAG, "extra lowlevel init failed");
}{...}
break;
}{...}
... case ETH_STATE_DEINIT: {
if (eth_driver->on_lowlevel_deinit_done) {
ESP_GOTO_ON_ERROR(eth_driver->on_lowlevel_deinit_done(eth_driver), err, TAG, "extra lowlevel deinit failed");
}{...}
break;
}{...}
... case ETH_STATE_LINK: {
eth_link_t link = (eth_link_t)args;
ESP_GOTO_ON_ERROR(mac->set_link(mac, link), err, TAG, "ethernet mac set link failed");
atomic_store(ð_driver->link, link);
if (link == ETH_LINK_UP) {
ESP_GOTO_ON_ERROR(esp_event_post(ETH_EVENT, ETHERNET_EVENT_CONNECTED, ð_driver, sizeof(esp_eth_driver_t *), 0), err,
TAG, "send ETHERNET_EVENT_CONNECTED event failed");
}{...} else if (link == ETH_LINK_DOWN) {
ESP_GOTO_ON_ERROR(esp_event_post(ETH_EVENT, ETHERNET_EVENT_DISCONNECTED, ð_driver, sizeof(esp_eth_driver_t *), 0), err,
TAG, "send ETHERNET_EVENT_DISCONNECTED event failed");
}{...}
break;
}{...}
... case ETH_STATE_SPEED: {
eth_speed_t speed = (eth_speed_t)args;
ESP_GOTO_ON_ERROR(mac->set_speed(mac, speed), err, TAG, "ethernet mac set speed failed");
eth_driver->speed = speed;
break;
}{...}
... case ETH_STATE_DUPLEX: {
eth_duplex_t duplex = (eth_duplex_t)args;
ESP_GOTO_ON_ERROR(mac->set_duplex(mac, duplex), err, TAG, "ethernet mac set duplex failed");
eth_driver->duplex = duplex;
break;
}{...}
... case ETH_STATE_PAUSE: {
uint32_t peer_pause_ability = (uint32_t)args;
ESP_GOTO_ON_ERROR(mac->set_peer_pause_ability(mac, peer_pause_ability), err, TAG, "ethernet mac set peer pause ability failed");
break;
}{...}
... default:
ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "unknown ethernet state: %d", state);
break;...
}{...}
err:
return ret;
}{ ... }
static void eth_check_link_timer_cb(void *args)
{
esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)args;
esp_eth_phy_t *phy = eth_driver->phy;
phy->get_link(phy);
}{ ... }
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, ð_driver->check_link_timer), err, TAG, "create link timer failed");
#if CONFIG_ETH_TRANSMIT_MUTEX
eth_driver->transmit_mutex = xSemaphoreCreateMutex();
ESP_GOTO_ON_FALSE(eth_driver->transmit_mutex, ESP_ERR_NO_MEM, err, TAG, "Failed to create transmit mutex");/* ... */
#endif
atomic_init(ð_driver->ref_count, 1);
atomic_init(ð_driver->fsm, ESP_ETH_FSM_STOP);
eth_driver->mac = mac;
eth_driver->phy = phy;
atomic_init(ð_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, ð_driver->mediator);
phy->set_mediator(phy, ð_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_GOTO_ON_ERROR(phy->autonego_ctrl(phy, ESP_ETH_PHY_AUTONEGO_G_STAT, ð_driver->auto_nego_en),
err, TAG, "get autonegotiation status failed");
ESP_LOGD(TAG, "new ethernet driver @%p", eth_driver);
*out_hdl = eth_driver;
return ESP_OK;
err:
if (eth_driver) {
if (eth_driver->check_link_timer) {
esp_timer_delete(eth_driver->check_link_timer);
}{...}
#if CONFIG_ETH_TRANSMIT_MUTEX
if (eth_driver->transmit_mutex) {
vSemaphoreDelete(eth_driver->transmit_mutex);
}{...}
#endif/* ... */
free(eth_driver);
}{...}
return ret;
}{ ... }
esp_err_t esp_eth_driver_uninstall(esp_eth_handle_t hdl)
{
esp_err_t ret = ESP_OK;
esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
ESP_GOTO_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
esp_eth_fsm_t expected_fsm = ESP_ETH_FSM_STOP;
ESP_GOTO_ON_FALSE(atomic_compare_exchange_strong(ð_driver->fsm, &expected_fsm, ESP_ETH_FSM_STOP),
ESP_ERR_INVALID_STATE, err, TAG, "driver not stopped yet");
int expected_ref_count = 1;
ESP_GOTO_ON_FALSE(atomic_compare_exchange_strong(ð_driver->ref_count, &expected_ref_count, 0),
ESP_ERR_INVALID_STATE, err, TAG, "%d ethernet reference in use", expected_ref_count);
esp_eth_mac_t *mac = eth_driver->mac;
esp_eth_phy_t *phy = eth_driver->phy;
ESP_GOTO_ON_ERROR(esp_timer_delete(eth_driver->check_link_timer), err, TAG, "delete link timer failed");
#if CONFIG_ETH_TRANSMIT_MUTEX
vSemaphoreDelete(eth_driver->transmit_mutex);
#endif
ESP_GOTO_ON_ERROR(phy->deinit(phy), err, TAG, "deinit phy failed");
ESP_GOTO_ON_ERROR(mac->deinit(mac), err, TAG, "deinit mac failed");
free(eth_driver);
err:
return ret;
}{ ... }
esp_err_t esp_eth_start(esp_eth_handle_t hdl)
{
esp_err_t ret = ESP_OK;
esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
ESP_GOTO_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, err, TAG, "ethernet driver handle can't be null");
esp_eth_phy_t *phy = eth_driver->phy;
esp_eth_fsm_t expected_fsm = ESP_ETH_FSM_STOP;
ESP_GOTO_ON_FALSE(atomic_compare_exchange_strong(ð_driver->fsm, &expected_fsm, ESP_ETH_FSM_START),
ESP_ERR_INVALID_STATE, err, TAG, "driver started already");
if (eth_driver->auto_nego_en == true) {
ESP_GOTO_ON_ERROR(phy->autonego_ctrl(phy, ESP_ETH_PHY_AUTONEGO_RESTART, ð_driver->auto_nego_en), err, TAG, "phy negotiation failed");
}{...}
ESP_GOTO_ON_ERROR(esp_event_post(ETH_EVENT, ETHERNET_EVENT_START, ð_driver, sizeof(esp_eth_driver_t *), 0),
err, TAG, "send ETHERNET_EVENT_START event failed");
ESP_GOTO_ON_ERROR(phy->get_link(phy), err, TAG, "phy get link status failed");
ESP_GOTO_ON_ERROR(esp_timer_start_periodic(eth_driver->check_link_timer, eth_driver->check_link_period_ms * 1000),
err, TAG, "start link timer failed");
err:
return ret;
}{ ... }
esp_err_t esp_eth_stop(esp_eth_handle_t hdl)
{
esp_err_t ret = ESP_OK;
esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
ESP_GOTO_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, err, TAG, "ethernet driver handle can't be null");
esp_eth_phy_t *phy = eth_driver->phy;
esp_eth_fsm_t expected_fsm = ESP_ETH_FSM_START;
ESP_GOTO_ON_FALSE(atomic_compare_exchange_strong(ð_driver->fsm, &expected_fsm, ESP_ETH_FSM_STOP),
ESP_ERR_INVALID_STATE, err, TAG, "driver not started yet");
ESP_GOTO_ON_ERROR(esp_timer_stop(eth_driver->check_link_timer), err, TAG, "stop link timer failed");
eth_link_t expected_link = ETH_LINK_UP;
if (atomic_compare_exchange_strong(ð_driver->link, &expected_link, ETH_LINK_DOWN)){
ESP_GOTO_ON_ERROR(phy->set_link(phy, ETH_LINK_DOWN), err, TAG, "ethernet phy reset link failed");
}{...}
ESP_GOTO_ON_ERROR(esp_event_post(ETH_EVENT, ETHERNET_EVENT_STOP, ð_driver, sizeof(esp_eth_driver_t *), 0),
err, TAG, "send ETHERNET_EVENT_STOP event failed");
err:
return ret;
}{ ... }
esp_err_t esp_eth_update_input_path(
esp_eth_handle_t hdl,
esp_err_t (*stack_input)(esp_eth_handle_t hdl, uint8_t *buffer, uint32_t length, void *priv),
void *priv)
{
esp_err_t ret = ESP_OK;
esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
ESP_GOTO_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, err, TAG, "ethernet driver handle can't be null");
eth_driver->priv = priv;
eth_driver->stack_input = stack_input;
err:
return ret;
}{ ... }
esp_err_t esp_eth_transmit(esp_eth_handle_t hdl, void *buf, size_t length)
{
esp_err_t ret = ESP_OK;
esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
if (atomic_load(ð_driver->link) != ETH_LINK_UP) {
ret = ESP_ERR_INVALID_STATE;
ESP_LOGD(TAG, "Ethernet link is not up, can't transmit");
goto err;
}{...}
ESP_GOTO_ON_FALSE(buf, ESP_ERR_INVALID_ARG, err, TAG, "can't set buf to null");
ESP_GOTO_ON_FALSE(length, ESP_ERR_INVALID_ARG, err, TAG, "buf length can't be zero");
ESP_GOTO_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, err, TAG, "ethernet driver handle can't be null");
esp_eth_mac_t *mac = eth_driver->mac;
#if CONFIG_ETH_TRANSMIT_MUTEX
if (xSemaphoreTake(eth_driver->transmit_mutex, pdMS_TO_TICKS(ESP_ETH_TX_TIMEOUT_MS)) == pdFALSE) {
return ESP_ERR_TIMEOUT;
}{...}
#endif/* ... */
ret = mac->transmit(mac, buf, length);
#if CONFIG_ETH_TRANSMIT_MUTEX
xSemaphoreGive(eth_driver->transmit_mutex);
#endif
err:
return ret;
}{ ... }
esp_err_t esp_eth_transmit_vargs(esp_eth_handle_t hdl, uint32_t argc, ...)
{
esp_err_t ret = ESP_OK;
esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
if (atomic_load(ð_driver->link) != ETH_LINK_UP) {
ret = ESP_ERR_INVALID_STATE;
ESP_LOGD(TAG, "Ethernet link is not up, can't transmit");
goto err;
}{...}
va_list args;
esp_eth_mac_t *mac = eth_driver->mac;
#if CONFIG_ETH_TRANSMIT_MUTEX
if (xSemaphoreTake(eth_driver->transmit_mutex, pdMS_TO_TICKS(ESP_ETH_TX_TIMEOUT_MS)) == pdFALSE) {
return ESP_ERR_TIMEOUT;
}{...}
#endif/* ... */
va_start(args, argc);
ret = mac->transmit_vargs(mac, argc, args);
#if CONFIG_ETH_TRANSMIT_MUTEX
xSemaphoreGive(eth_driver->transmit_mutex);
#endif
va_end(args);
err:
return ret;
}{ ... }
esp_err_t esp_eth_ioctl(esp_eth_handle_t hdl, esp_eth_io_cmd_t cmd, void *data)
{
esp_err_t ret = ESP_OK;
esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
ESP_GOTO_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, err, TAG, "ethernet driver handle can't be null");
esp_eth_mac_t *mac = eth_driver->mac;
esp_eth_phy_t *phy = eth_driver->phy;
switch (cmd) {
case ETH_CMD_S_MAC_ADDR:
ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "can't set mac addr to null");
ESP_GOTO_ON_ERROR(mac->set_addr(mac, (uint8_t *)data), err, TAG, "set mac address failed");
break;...
case ETH_CMD_G_MAC_ADDR:
ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "no mem to store mac addr");
ESP_GOTO_ON_ERROR(mac->get_addr(mac, (uint8_t *)data), err, TAG, "get mac address failed");
break;...
case ETH_CMD_S_PHY_ADDR:
ESP_GOTO_ON_ERROR(phy->set_addr(phy, *(uint32_t *)data), err, TAG, "set phy address failed");
break;...
case ETH_CMD_G_PHY_ADDR:
ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "no mem to store phy addr");
ESP_GOTO_ON_ERROR(phy->get_addr(phy, (uint32_t *)data), err, TAG, "get phy address failed");
break;...
case ETH_CMD_S_AUTONEGO:
ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "can't set autonegotiation to null");
ESP_GOTO_ON_FALSE(atomic_load(ð_driver->fsm) == ESP_ETH_FSM_STOP, ESP_ERR_INVALID_STATE, err, TAG, "link configuration is only allowed when driver is stopped");
if (*(bool *)data == true) {
ESP_GOTO_ON_ERROR(phy->autonego_ctrl(phy, ESP_ETH_PHY_AUTONEGO_EN, ð_driver->auto_nego_en), err, TAG, "phy negotiation enable failed");
}{...} else {
ESP_GOTO_ON_ERROR(phy->autonego_ctrl(phy, ESP_ETH_PHY_AUTONEGO_DIS, ð_driver->auto_nego_en), err, TAG, "phy negotiation disable failed");
}{...}
break;...
case ETH_CMD_G_AUTONEGO:
ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "no mem to store autonegotiation configuration");
*(bool *)data = eth_driver->auto_nego_en;
break;...
case ETH_CMD_S_SPEED:
ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "can't set speed to null");
ESP_GOTO_ON_FALSE(atomic_load(ð_driver->fsm) == ESP_ETH_FSM_STOP, ESP_ERR_INVALID_STATE, err, TAG, "link configuration is only allowed when driver is stopped");
ESP_GOTO_ON_FALSE(eth_driver->auto_nego_en == false, ESP_ERR_INVALID_STATE, err, TAG, "autonegotiation needs to be disabled to change this parameter");
ESP_GOTO_ON_ERROR(phy->set_speed(phy, *(eth_speed_t *)data), err, TAG, "set speed mode failed");
break;...
case ETH_CMD_G_SPEED:
ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "no mem to store speed value");
*(eth_speed_t *)data = eth_driver->speed;
break;...
case ETH_CMD_S_PROMISCUOUS:
ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "can't set promiscuous to null");
ESP_GOTO_ON_ERROR(mac->set_promiscuous(mac, *(bool *)data), err, TAG, "set promiscuous mode failed");
break;...
case ETH_CMD_S_FLOW_CTRL:
ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "can't set flow ctrl to null");
ESP_GOTO_ON_ERROR(mac->enable_flow_ctrl(mac, *(bool *)data), err, TAG, "enable mac flow control failed");
ESP_GOTO_ON_ERROR(phy->advertise_pause_ability(phy, *(uint32_t *)data), err, TAG, "phy advertise pause ability failed");
break;...
case ETH_CMD_S_DUPLEX_MODE:
ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "can't set duplex to null");
ESP_GOTO_ON_FALSE(eth_driver->auto_nego_en == false, ESP_ERR_INVALID_STATE, err, TAG, "autonegotiation needs to be disabled to change this parameter");
ESP_GOTO_ON_FALSE(atomic_load(ð_driver->fsm) == ESP_ETH_FSM_STOP, ESP_ERR_INVALID_STATE, err, TAG, "link configuration is only allowed when driver is stopped");
ESP_GOTO_ON_ERROR(phy->set_duplex(phy, *(eth_duplex_t *)data), err, TAG, "set duplex mode failed");
break;...
case ETH_CMD_G_DUPLEX_MODE:
ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "no mem to store duplex value");
*(eth_duplex_t *)data = eth_driver->duplex;
break;...
case ETH_CMD_S_PHY_LOOPBACK:
ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "can't set loopback to null");
ESP_GOTO_ON_ERROR(phy->loopback(phy, *(bool *)data), err, TAG, "configuration of phy loopback mode failed");
break;...
case ETH_CMD_READ_PHY_REG: {
uint32_t phy_addr;
ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "invalid register read/write info");
esp_eth_phy_reg_rw_data_t *phy_r_data = (esp_eth_phy_reg_rw_data_t *)data;
ESP_GOTO_ON_FALSE(phy_r_data->reg_value_p, ESP_ERR_INVALID_ARG, err, TAG, "can't read registers to null");
ESP_GOTO_ON_ERROR(phy->get_addr(phy, &phy_addr), err, TAG, "get phy address failed");
ESP_GOTO_ON_ERROR(eth_driver->mediator.phy_reg_read(ð_driver->mediator,
phy_addr, phy_r_data->reg_addr, phy_r_data->reg_value_p), err, TAG, "failed to read PHY register");
}{...}
break;...
case ETH_CMD_WRITE_PHY_REG: {
uint32_t phy_addr;
ESP_GOTO_ON_FALSE(data, ESP_ERR_INVALID_ARG, err, TAG, "invalid register read/write info");
esp_eth_phy_reg_rw_data_t *phy_w_data = (esp_eth_phy_reg_rw_data_t *)data;
ESP_GOTO_ON_FALSE(phy_w_data->reg_value_p, ESP_ERR_INVALID_ARG, err, TAG, "can't write registers from null");
ESP_GOTO_ON_ERROR(phy->get_addr(phy, &phy_addr), err, TAG, "get phy address failed");
ESP_GOTO_ON_ERROR(eth_driver->mediator.phy_reg_write(ð_driver->mediator,
phy_addr, phy_w_data->reg_addr, *(phy_w_data->reg_value_p)), err, TAG, "failed to write PHY register");
}{...}
break;...
default:
if (phy->custom_ioctl != NULL && cmd >= ETH_CMD_CUSTOM_PHY_CMDS) {
ret = phy->custom_ioctl(phy, cmd, data);
}{...} else if (mac->custom_ioctl != NULL && cmd >= ETH_CMD_CUSTOM_MAC_CMDS) {
ret = mac->custom_ioctl(mac, cmd, data);
}{...} else {
ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "unknown io command: %d", cmd);
}{...}
break;...
}{...}
err:
return ret;
}{ ... }
esp_err_t esp_eth_get_phy_instance(esp_eth_handle_t hdl, esp_eth_phy_t **phy)
{
esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
ESP_RETURN_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, TAG, "ethernet driver handle can't be null");
ESP_RETURN_ON_FALSE(phy != NULL, ESP_ERR_INVALID_ARG, TAG, "can't store PHY instance to null");
*phy = eth_driver->phy;
return ESP_OK;
}{ ... }
esp_err_t esp_eth_get_mac_instance(esp_eth_handle_t hdl, esp_eth_mac_t **mac)
{
esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
ESP_RETURN_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, TAG, "ethernet driver handle can't be null");
ESP_RETURN_ON_FALSE(mac != NULL, ESP_ERR_INVALID_ARG, TAG, "can't store MAC instance to null");
*mac = eth_driver->mac;
return ESP_OK;
}{ ... }
esp_err_t esp_eth_increase_reference(esp_eth_handle_t hdl)
{
esp_err_t ret = ESP_OK;
esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
ESP_GOTO_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, err, TAG, "ethernet driver handle can't be null");
atomic_fetch_add(ð_driver->ref_count, 1);
err:
return ret;
}{ ... }
esp_err_t esp_eth_decrease_reference(esp_eth_handle_t hdl)
{
esp_err_t ret = ESP_OK;
esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl;
ESP_GOTO_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, err, TAG, "ethernet driver handle can't be null");
atomic_fetch_sub(ð_driver->ref_count, 1);
err:
return ret;
}{ ... }