1 // Copyright 2019 Espressif Systems (Shanghai) PTE LTD 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #pragma once 16 17 #ifdef __cplusplus 18 extern "C" { 19 #endif 20 21 #include <stdint.h> 22 #include <stdbool.h> 23 #include "esp_err.h" 24 #include "soc/emac_dma_struct.h" 25 #include "soc/emac_mac_struct.h" 26 #include "soc/emac_ext_struct.h" 27 28 #define EMAC_MEDIA_INTERFACE_MII (0) 29 #define EMAC_MEDIA_INTERFACE_RMII (1) 30 31 #define EMAC_WATCHDOG_ENABLE (0) 32 #define EMAC_WATCHDOG_DISABLE (1) 33 34 #define EMAC_JABBER_ENABLE (0) 35 #define EMAC_JABBER_DISABLE (1) 36 37 #define EMAC_INTERFRAME_GAP_96BIT (0) 38 #define EMAC_INTERFRAME_GAP_88BIT (1) 39 #define EMAC_INTERFRAME_GAP_80BIT (2) 40 #define EMAC_INTERFRAME_GAP_72BIT (3) 41 #define EMAC_INTERFRAME_GAP_64BIT (4) 42 #define EMAC_INTERFRAME_GAP_56BIT (5) 43 #define EMAC_INTERFRAME_GAP_48BIT (6) 44 #define EMAC_INTERFRAME_GAP_40BIT (7) 45 46 #define EMAC_CARRIERSENSE_ENABLE (0) 47 #define EMAC_CARRIERSENSE_DISABLE (1) 48 49 #define EMAC_PORT_1000MBPS (0) 50 #define EMAC_PORT_10_100MBPS (1) 51 52 #define EMAC_SPEED_10M (0) 53 #define EMAC_SPEED_100M (1) 54 55 #define EMAC_RECEIVE_OWN_ENABLE (0) 56 #define EMAC_RECEIVE_OWN_DISABLE (1) 57 58 #define EMAC_LOOPBACK_DISABLE (0) 59 #define EMAC_LOOPBACK_ENABLE (1) 60 61 #define EMAC_DUPLEX_HALF (0) 62 #define EMAC_DUPLEX_FULL (1) 63 64 #define EMAC_CHECKSUM_SW (0) 65 #define EMAC_CHECKSUM_HW (1) 66 67 #define EMAC_RETRY_TRANSMISSION_ENABLE (0) 68 #define EMAC_RETRY_TRANSMISSION_DISABLE (1) 69 70 #define EMAC_AUTO_PAD_CRC_STRIP_DISABLE (0) 71 #define EMAC_AUTO_PAD_CRC_STRIP_ENABLE (1) 72 73 #define EMAC_BACKOFF_LIMIT_10 (0) 74 #define EMAC_BACKOFF_LIMIT_8 (1) 75 #define EMAC_BACKOFF_LIMIT_4 (2) 76 #define EMAC_BACKOFF_LIMIT_1 (3) 77 78 #define EMAC_DEFERRAL_CHECK_DISABLE (0) 79 #define EMAC_DEFERRAL_CHECK_ENABLE (1) 80 81 #define EMAC_PREAMBLE_LENGTH_7 (0) 82 #define EMAC_PREAMBLE_LENGTH_5 (1) 83 #define EMAC_PREAMBLE_LENGTH_3 (2) 84 85 #define EMAC_RECEIVE_ALL_DISABLE (0) 86 #define EMAC_RECEIVE_ALL_ENABLE (1) 87 88 #define EMAC_SOURCE_ADDR_FILTER_DISABLE (0) 89 #define EMAC_SOURCE_ADDR_FILTER_NORMAL (2) 90 #define EMAC_SOURCE_ADDR_FILTER_INVERSE (3) 91 92 #define EMAC_CONTROL_FRAME_BLOCKALL (0) 93 #define EMAC_CONTROL_FRAME_FORWARDALL_PAUSE (1) 94 #define EMAC_CONTROL_FRAME_FORWARDALL (2) 95 #define EMAC_CONTROL_FRAME_FORWARDFILT (3) 96 97 #define EMAC_RECEPT_BROADCAST_ENABLE (0) 98 #define EMAC_RECEPT_BROADCAST_DISABLE (1) 99 100 #define EMAC_DEST_ADDR_FILTER_NORMAL (0) 101 #define EMAC_DEST_ADDR_FILTER_INVERSE (1) 102 103 #define EMAC_PROMISCUOUS_DISABLE (0) 104 #define EMAC_PROMISCUOUS_ENABLE (1) 105 106 #define EMAC_PAUSE_TIME 0x1648 107 108 #define EMAC_ZERO_QUANTA_PAUSE_ENABLE (0) 109 #define EMAC_ZERO_QUANTA_PAUSE_DISABLE (1) 110 111 #define EMAC_PAUSE_LOW_THRESHOLD_MINUS_4 (0) 112 #define EMAC_PAUSE_LOW_THRESHOLD_MINUS_28 (1) 113 #define EMAC_PAUSE_LOW_THRESHOLD_MINUS_144 (2) 114 #define EMAC_PAUSE_LOW_THRESHOLD_MINUS_256 115 116 #define EMAC_UNICAST_PAUSE_DETECT_DISABLE (0) 117 #define EMAC_UNICAST_PAUSE_DETECT_ENABLE (1) 118 119 #define EMAC_RECEIVE_FLOW_CONTROL_DISABLE (0) 120 #define EMAC_RECEIVE_FLOW_CONTROL_ENABLE (1) 121 122 #define EMAC_TRANSMIT_FLOW_CONTROL_DISABLE (0) 123 #define EMAC_TRANSMIT_FLOW_CONTROL_ENABLE (1) 124 125 #define EMAC_DROP_TCPIP_CHECKSUM_ERROR_ENABLE (0) 126 #define EMAC_DROP_TCPIP_CHECKSUM_ERROR_DISABLE (1) 127 128 #define EMAC_RECEIVE_STORE_FORWARD_DISABLE (0) 129 #define EMAC_RECEIVE_STORE_FORWARD_ENABLE (1) 130 131 #define EMAC_FLUSH_RECEIVED_FRAME_ENABLE (0) 132 #define EMAC_FLUSH_RECEIVED_FRAME_DISABLE (1) 133 134 #define EMAC_TRANSMIT_STORE_FORWARD_DISABLE (0) 135 #define EMAC_TRANSMIT_STORE_FORWARD_ENABLE (1) 136 137 #define EMAC_TRANSMIT_THRESHOLD_CONTROL_64 (0) 138 #define EMAC_TRANSMIT_THRESHOLD_CONTROL_128 (1) 139 #define EMAC_TRANSMIT_THRESHOLD_CONTROL_192 (2) 140 #define EMAC_TRANSMIT_THRESHOLD_CONTROL_256 (3) 141 #define EMAC_TRANSMIT_THRESHOLD_CONTROL_40 (4) 142 #define EMAC_TRANSMIT_THRESHOLD_CONTROL_32 (5) 143 #define EMAC_TRANSMIT_THRESHOLD_CONTROL_24 (6) 144 #define EMAC_TRANSMIT_THRESHOLD_CONTROL_16 (7) 145 146 #define EMAC_FORWARD_ERROR_FRAME_DISABLE (0) 147 #define EMAC_FORWARD_ERROR_FRAME_ENABLE (1) 148 149 #define EMAC_FORWARD_UNDERSIZED_GOOD_FRAME_DISABLE (0) 150 #define EMAC_FORWARD_UNDERSIZED_GOOD_FRAME_ENABLE (1) 151 152 #define EMAC_RECEIVE_THRESHOLD_CONTROL_64 (0) 153 #define EMAC_RECEIVE_THRESHOLD_CONTROL_32 (1) 154 #define EMAC_RECEIVE_THRESHOLD_CONTROL_96 (2) 155 #define EMAC_RECEIVE_THRESHOLD_CONTROL_128 (3) 156 157 #define EMAC_OPERATE_SECOND_FRAME_DISABLE (0) 158 #define EMAC_OPERATE_SECOND_FRAME_ENABLE (1) 159 160 #define EMAC_MIXED_BURST_DISABLE (0) 161 #define EMAC_MIXED_BURST_ENABLE (1) 162 163 #define EMAC_ADDR_ALIGN_BEATS_DISABLE (0) 164 #define EMAC_ADDR_ALIGN_BEATS_ENABLE (1) 165 166 #define EMAC_UNUSE_SEPARATE_PBL (0) 167 #define EMAC_USE_SEPARATE_PBL (1) 168 169 #define EMAC_DMA_BURST_LENGTH_1BEAT (1) 170 #define EMAC_DMA_BURST_LENGTH_2BEAT (2) 171 #define EMAC_DMA_BURST_LENGTH_4BEAT (4) 172 #define EMAC_DMA_BURST_LENGTH_8BEAT (8) 173 #define EMAC_DMA_BURST_LENGTH_16BEAT (16) 174 #define EMAC_DMA_BURST_LENGTH_32BEAT (32) 175 176 #define EMAC_ENHANCED_DESCRIPTOR_DISABLE (0) 177 #define EMAC_ENHANCED_DESCRIPTOR_ENABLE (1) 178 179 #define EMAC_DMA_ARBITRATION_SCHEME_ROUNDROBIN (0) 180 #define EMAC_DMA_ARBITRATION_SCHEME_FIXEDPRIO (1) 181 182 #define EMAC_DMA_ARBITRATION_ROUNDROBIN_RXTX_1_1 (0) 183 #define EMAC_DMA_ARBITRATION_ROUNDROBIN_RXTX_2_1 (1) 184 #define EMAC_DMA_ARBITRATION_ROUNDROBIN_RXTX_3_1 (2) 185 #define EMAC_DMA_ARBITRATION_ROUNDROBIN_RXTX_4_1 (3) 186 187 /** 188 * @brief Ethernet DMA TX Descriptor 189 * 190 */ 191 typedef struct { 192 volatile union { 193 struct { 194 uint32_t Deferred : 1; /*!< MAC defers before transmission */ 195 uint32_t UnderflowErr : 1; /*!< DMA encountered an empty transmit buffer */ 196 uint32_t ExcessiveDeferral : 1; /*!< Excessive deferral of over 24,288 bit times */ 197 uint32_t CollisionCount : 4; /*!< Number of collisions occurred before transmitted */ 198 uint32_t VLanFrame : 1; /*!< Transmitted frame is a VLAN-type frame */ 199 uint32_t ExcessiveCollision : 1; /*!< Transmission aborted after 16 successive collisions */ 200 uint32_t LateCollision : 1; /*!< Collision occurred after the collision window */ 201 uint32_t NoCarrier : 1; /*!< Carrier Sense signal from the PHY was not asserted */ 202 uint32_t LossCarrier : 1; /*!< Loss of carrier occurred during transmission */ 203 uint32_t PayloadChecksumErr : 1; /*!< Checksum error in TCP/UDP/ICMP datagram payload */ 204 uint32_t FrameFlushed : 1; /*!< DMA or MTL flushed the frame */ 205 uint32_t JabberTimeout : 1; /*!< MAC transmitter has experienced a jabber timeout */ 206 uint32_t ErrSummary : 1; /*!< Error Summary */ 207 uint32_t IPHeadErr : 1; /*!< IP Header Error */ 208 uint32_t TxTimestampStatus : 1; /*!< Timestamp captured for the transmit frame */ 209 uint32_t VLANInsertControl : 2; /*!< VLAN tagging or untagging before transmitting */ 210 uint32_t SecondAddressChained : 1; /*!< Second address in the descriptor is Next Descriptor address */ 211 uint32_t TransmitEndRing : 1; /*!< Descriptor list reached its final descriptor */ 212 uint32_t ChecksumInsertControl : 2; /*!< Control checksum calculation and insertion */ 213 uint32_t CRCReplacementControl : 1; /*!< Control CRC replace */ 214 uint32_t TransmitTimestampEnable : 1; /*!< Enable IEEE1588 harware timestamping */ 215 uint32_t DisablePad : 1; /*!< Control add padding when frame short than 64 bytes */ 216 uint32_t DisableCRC : 1; /*!< Control append CRC to the end of frame */ 217 uint32_t FirstSegment : 1; /*!< Buffer contains the first segment of a frame */ 218 uint32_t LastSegment : 1; /*!< Buffer contains the last segment of a frame */ 219 uint32_t InterruptOnComplete : 1; /*!< Interrupt after frame transmitted */ 220 uint32_t Own : 1; /*!< Owner of this descriptor: DMA controller or host */ 221 }; 222 uint32_t Value; 223 } TDES0; 224 union { 225 struct { 226 uint32_t TransmitBuffer1Size : 13; /*!< First data buffer byte size */ 227 uint32_t Reserved : 3; /*!< Reserved */ 228 uint32_t TransmitBuffer2Size : 13; /*!< Second data buffer byte size */ 229 uint32_t SAInsertControl : 3; /*!< Control MAC add or replace Source Address field */ 230 }; 231 uint32_t Value; 232 } TDES1; 233 uint32_t Buffer1Addr; /*!< Buffer1 address pointer */ 234 uint32_t Buffer2NextDescAddr; /*!< Buffer2 or next descriptor address pointer */ 235 uint32_t Reserved1; /*!< Reserved */ 236 uint32_t Reserved2; /*!< Reserved */ 237 uint32_t TimeStampLow; /*!< Transmit Frame Timestamp Low */ 238 uint32_t TimeStampHigh; /*!< Transmit Frame Timestamp High */ 239 } eth_dma_tx_descriptor_t; 240 #define EMAC_DMATXDESC_CHECKSUM_BYPASS 0 /*!< Checksum engine bypass */ 241 #define EMAC_DMATXDESC_CHECKSUM_IPV4HEADER 1 /*!< IPv4 header checksum insertion */ 242 #define EMAC_DMATXDESC_CHECKSUM_TCPUDPICMPSEGMENT 2 /*!< TCP/UDP/ICMP Checksum Insertion calculated over segment only */ 243 #define EMAC_DMATXDESC_CHECKSUM_TCPUDPICMPFULL 3 /*!< TCP/UDP/ICMP Checksum Insertion fully calculated */ 244 245 _Static_assert(sizeof(eth_dma_tx_descriptor_t) == 32, "eth_dma_tx_descriptor_t should occupy 32 bytes in memory"); 246 247 /** 248 * @brief Ethernet DMA RX Descriptor 249 * 250 */ 251 typedef struct { 252 volatile union { 253 struct { 254 uint32_t ExtendStatusAvailable : 1; /*!< Extended statsu is available in RDES4 */ 255 uint32_t CRCErr : 1; /*!< CRC error occurred on frame */ 256 uint32_t DribbleBitErr : 1; /*!< frame contains non int multiple of 8 bits */ 257 uint32_t ReceiveErr : 1; /*!< Receive error */ 258 uint32_t ReceiveWatchdogTimeout : 1; /*!< Receive Watchdog timeout */ 259 uint32_t FrameType : 1; /*!< Ethernet type or IEEE802.3 */ 260 uint32_t LateCollision : 1; /*!< Late collision occurred during reception */ 261 uint32_t TSAvailIPChecksumErrGiantFrame : 1; /*!< Timestamp available or IP Checksum error or Giant frame */ 262 uint32_t LastDescriptor : 1; /*!< Last buffer of the frame */ 263 uint32_t FirstDescriptor : 1; /*!< First buffer of the frame */ 264 uint32_t VLANTag : 1; /*!< VLAN Tag: received frame is a VLAN frame */ 265 uint32_t OverflowErr : 1; /*!< Frame was damaged due to buffer overflow */ 266 uint32_t LengthErr : 1; /*!< Frame size not matching with length field */ 267 uint32_t SourceAddrFilterFail : 1; /*!< SA field of frame failed the SA filter */ 268 uint32_t DescriptorErr : 1; /*!< Frame truncated and DMA doesn't own next descriptor */ 269 uint32_t ErrSummary : 1; /*!< Error Summary, OR of all errors in RDES */ 270 uint32_t FrameLength : 14; /*!< Byte length of received frame */ 271 uint32_t DestinationAddrFilterFail : 1; /*!< Frame failed in the DA Filter in the MAC */ 272 uint32_t Own : 1; /*!< Owner of this descriptor: DMA controller or host */ 273 }; 274 uint32_t Value; 275 } RDES0; 276 union { 277 struct { 278 uint32_t ReceiveBuffer1Size : 13; /*!< First data buffer size in bytes */ 279 uint32_t Reserved1 : 1; /*!< Reserved */ 280 uint32_t SecondAddressChained : 1; /*!< Seconde address is the Next Descriptor address */ 281 uint32_t ReceiveEndOfRing : 1; /*!< Descriptor reached its final descriptor */ 282 uint32_t ReceiveBuffer2Size : 13; /*!< Second data buffer size in bytes */ 283 uint32_t Reserved : 2; /*!< Reserved */ 284 uint32_t DisableInterruptOnComplete : 1; /*!< Disable the assertion of interrupt to host */ 285 }; 286 uint32_t Value; 287 } RDES1; 288 uint32_t Buffer1Addr; /*!< Buffer1 address pointer */ 289 uint32_t Buffer2NextDescAddr; /*!< Buffer2 or next descriptor address pointer */ 290 volatile union { 291 struct { 292 uint32_t IPPayloadType : 3; /*!< Type of payload in the IP datagram */ 293 uint32_t IPHeadErr : 1; /*!< IP header error */ 294 uint32_t IPPayloadErr : 1; /*!< IP payload error */ 295 uint32_t IPChecksumBypass : 1; /*!< Checksum offload engine is bypassed */ 296 uint32_t IPv4PacketReceived : 1; /*!< Received packet is an IPv4 packet */ 297 uint32_t IPv6PacketReceived : 1; /*!< Received packet is an IPv6 packet */ 298 uint32_t MessageType : 4; /*!< PTP Message Type */ 299 uint32_t PTPFrameType : 1; /*!< PTP message is over Ethernet or IPv4/IPv6 */ 300 uint32_t PTPVersion : 1; /*!< Version of PTP protocol */ 301 uint32_t TimestampDropped : 1; /*!< Timestamp dropped because of overflow */ 302 uint32_t Reserved1 : 1; /*!< Reserved */ 303 uint32_t AVPacketReceived : 1; /*!< AV packet is received */ 304 uint32_t AVTaggedPacketReceived : 1; /*!< AV tagged packet is received */ 305 uint32_t VLANTagPrioVal : 3; /*!< VLAN tag's user value in the received packekt */ 306 uint32_t Reserved2 : 3; /*!< Reserved */ 307 uint32_t Layer3FilterMatch : 1; /*!< Received frame matches one of the enabled Layer3 IP */ 308 uint32_t Layer4FilterMatch : 1; /*!< Received frame matches one of the enabled Layer4 IP */ 309 uint32_t Layer3Layer4FilterNumberMatch : 2; /*!< Number of Layer3 and Layer4 Filter that matches the received frame */ 310 uint32_t Reserved3 : 4; /*!< Reserved */ 311 }; 312 uint32_t Value; 313 } ExtendedStatus; 314 uint32_t Reserved; /*!< Reserved */ 315 uint32_t TimeStampLow; /*!< Receive frame timestamp low */ 316 uint32_t TimeStampHigh; /*!< Receive frame timestamp high */ 317 } eth_dma_rx_descriptor_t; 318 #define EMAC_DMAPTPRXDESC_PTPMT_SYNC 0x00000100U /* SYNC message (all clock types) */ 319 #define EMAC_DMAPTPRXDESC_PTPMT_FOLLOWUP 0x00000200U /* FollowUp message (all clock types) */ 320 #define EMAC_DMAPTPRXDESC_PTPMT_DELAYREQ 0x00000300U /* DelayReq message (all clock types) */ 321 #define EMAC_DMAPTPRXDESC_PTPMT_DELAYRESP 0x00000400U /* DelayResp message (all clock types) */ 322 #define EMAC_DMAPTPRXDESC_PTPMT_PDELAYREQ_ANNOUNCE 0x00000500U /* PdelayReq message (peer-to-peer transparent clock) or Announce message (Ordinary or Boundary clock) */ 323 #define EMAC_DMAPTPRXDESC_PTPMT_PDELAYRESP_MANAG 0x00000600U /* PdelayResp message (peer-to-peer transparent clock) or Management message (Ordinary or Boundary clock) */ 324 #define EMAC_DMAPTPRXDESC_PTPMT_PDELAYRESPFOLLOWUP_SIGNAL 0x00000700U /* PdelayRespFollowUp message (peer-to-peer transparent clock) or Signaling message (Ordinary or Boundary clock) */ 325 326 #define EMAC_DMAPTPRXDESC_IPPT_UDP 0x00000001U /* UDP payload encapsulated in the IP datagram */ 327 #define EMAC_DMAPTPRXDESC_IPPT_TCP 0x00000002U /* TCP payload encapsulated in the IP datagram */ 328 #define EMAC_DMAPTPRXDESC_IPPT_ICMP 0x00000003U /* ICMP payload encapsulated in the IP datagram */ 329 330 #define EMAC_DMADESC_OWNER_CPU (0) 331 #define EMAC_DMADESC_OWNER_DMA (1) 332 333 _Static_assert(sizeof(eth_dma_rx_descriptor_t) == 32, "eth_dma_rx_descriptor_t should occupy 32 bytes in memory"); 334 335 typedef struct { 336 emac_mac_dev_t *mac_regs; 337 emac_dma_dev_t *dma_regs; 338 emac_ext_dev_t *ext_regs; 339 uint8_t **rx_buf; 340 uint8_t **tx_buf; 341 void *descriptors; 342 eth_dma_rx_descriptor_t *rx_desc; 343 eth_dma_tx_descriptor_t *tx_desc; 344 } emac_hal_context_t; 345 346 void emac_hal_init(emac_hal_context_t *hal, void *descriptors, 347 uint8_t **rx_buf, uint8_t **tx_buf); 348 349 void emac_hal_reset_desc_chain(emac_hal_context_t *hal); 350 351 void emac_hal_lowlevel_init(emac_hal_context_t *hal); 352 353 void emac_hal_reset(emac_hal_context_t *hal); 354 355 bool emac_hal_is_reset_done(emac_hal_context_t *hal); 356 357 void emac_hal_set_csr_clock_range(emac_hal_context_t *hal); 358 359 void emac_hal_init_mac_default(emac_hal_context_t *hal); 360 361 void emac_hal_init_dma_default(emac_hal_context_t *hal); 362 363 void emac_hal_set_speed(emac_hal_context_t *hal, uint32_t speed); 364 365 void emac_hal_set_duplex(emac_hal_context_t *hal, uint32_t duplex); 366 367 void emac_hal_set_promiscuous(emac_hal_context_t *hal, bool enable); 368 369 /** 370 * @brief Send MAC-CTRL frames to peer (EtherType=0x8808, opcode=0x0001, dest_addr=MAC-specific-ctrl-proto-01 (01:80:c2:00:00:01)) 371 */ 372 void emac_hal_send_pause_frame(emac_hal_context_t *hal, bool enable); 373 374 bool emac_hal_is_mii_busy(emac_hal_context_t *hal); 375 376 void emac_hal_set_phy_cmd(emac_hal_context_t *hal, uint32_t phy_addr, uint32_t phy_reg, bool write); 377 378 void emac_hal_set_phy_data(emac_hal_context_t *hal, uint32_t reg_value); 379 380 uint32_t emac_hal_get_phy_data(emac_hal_context_t *hal); 381 382 void emac_hal_set_address(emac_hal_context_t *hal, uint8_t *mac_addr); 383 384 void emac_hal_start(emac_hal_context_t *hal); 385 386 void emac_hal_stop(emac_hal_context_t *hal); 387 388 uint32_t emac_hal_get_tx_desc_owner(emac_hal_context_t *hal); 389 390 uint32_t emac_hal_transmit_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t length); 391 392 uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t size, uint32_t *frames_remain, uint32_t *free_desc); 393 394 void emac_hal_enable_flow_ctrl(emac_hal_context_t *hal, bool enable); 395 396 void emac_hal_isr(void *arg); 397 398 void emac_hal_tx_complete_cb(void *arg); 399 400 void emac_hal_tx_unavail_cb (void *arg); 401 402 void emac_hal_rx_complete_cb (void *arg); 403 404 void emac_hal_rx_early_cb(void *arg); 405 406 void emac_hal_rx_unavail_cb(void *arg); 407 408 #ifdef __cplusplus 409 } 410 #endif 411