Newer
Older
mbed-os / features / netsocket / emac-drivers / TARGET_RENESAS_EMAC / TARGET_RZ_A2XX / r_ether_rza2 / src / r_ether_rza2.c
@RyoheiHagimoto RyoheiHagimoto on 17 Aug 2020 85 KB Added GR-MANGO to be a target.
/***********************************************************************************************************************
 * DISCLAIMER
 * This software is supplied by Renesas Electronics Corporation and is only intended for use with Renesas products. No
 * other uses are authorized. This software is owned by Renesas Electronics Corporation and is protected under all
 * applicable laws, including copyright laws.
 * THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING
 * THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED. TO THE MAXIMUM
 * EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES
 * SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR ANY REASON RELATED TO THIS
 * SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 * Renesas reserves the right, without notice, to make changes to this software and to discontinue the availability of
 * this software. By using this software, you agree to the additional terms and conditions found by accessing the
 * following link:
 * http://www.renesas.com/disclaimer
 *
 * Copyright (C) 2018-2020 Renesas Electronics Corporation. All rights reserved.
 ***********************************************************************************************************************/
/* Copyright (c) 2018-2020 Renesas Electronics Corporation.
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/***********************************************************************************************************************
 * File Name    : r_ether_rza2.c
 * Version      : 1.0
 * Description  : Ethernet module device driver
 ***********************************************************************************************************************/

/***********************************************************************************************************************
 Includes   <System Includes> , "Project Includes"
 ***********************************************************************************************************************/
#include <string.h>
#include "iodefine.h"
#include "iobitmask.h"
#include "cmsis.h"

/* Access to peripherals and board defines. */
#include "r_ether_rza2_if.h"
#include "src/r_ether_rza2_private.h"

/***********************************************************************************************************************
 Macro definitions
 ***********************************************************************************************************************/
#define ETHER_CFG_USE_VIRTUAL_ADDRESS   0  /* Since the virtual address is not used in the Mbed, the process is simplified. */

/***********************************************************************************************************************
 Typedef definitions
 ***********************************************************************************************************************/

/***********************************************************************************************************************
 Exported global variables (to be accessed by other files)
 ***********************************************************************************************************************/

/***********************************************************************************************************************
 Private global variables and functions
 ***********************************************************************************************************************/

/*
 * Private global function prototypes
 */
static void ether_reset_mac (uint32_t channel);
static void ether_init_descriptors (uint32_t channel);
static void ether_config_ethernet (uint32_t channel, const uint8_t mode);
static void ether_pause_resolution (uint16_t local_ability, uint16_t partner_ability, uint16_t *ptx_pause, 
        uint16_t *prx_pause);
static void ether_configure_mac (uint32_t channel, const uint8_t mac_addr[], const uint8_t mode);
static ether_return_t ether_do_link (uint32_t channel, const uint8_t mode);
static ether_return_t ether_set_callback (ether_param_t const control);
static ether_return_t ether_set_promiscuous_mode (ether_param_t const control);
static ether_return_t ether_set_int_handler (ether_param_t const control);
static ether_return_t ether_power_on (ether_param_t const control);
static ether_return_t ether_power_off (ether_param_t const control);
static ether_return_t power_on (uint32_t channel);
static void power_off (uint32_t channel);
static ether_return_t ether_set_multicastframe_filter (ether_param_t const control);
static ether_return_t ether_set_broadcastframe_filter (ether_param_t const control);
#if (ETHER_CH0_EN == 1)
static void ether_eint0 (void);
#endif
#if (ETHER_CH1_EN == 1)
static void ether_eint1 (void);
#endif
static void ether_int_common (uint32_t channel);
static ether_return_t power_on_control (uint32_t channel);
static void power_off_control (uint32_t channel);
static uint8_t check_mpde_bit (void);
static uint32_t get_control_tbl_index (uint32_t channel);

/*
 * Private global variables
 */

/* Pointer to the receive descriptors */
static descriptor_t * papp_rx_desc[ETHER_CHANNEL_MAX];

/* Pointer to the transmit descriptors */
static descriptor_t * papp_tx_desc[ETHER_CHANNEL_MAX];

/* Pointer to the callback function */
static ether_cb_t cb_func;

/*
 * The flag which control the pause frame.
 *
 * The value of flag and the situation which is indicatived of by the value.
 * ETHER_FLAG_OFF (0): Don't use the pause frame (default).
 * ETHER_FLAG_ON  (1): Use the pause frame.
 */
static uint8_t pause_frame_enable[ETHER_CHANNEL_MAX];

/*
 * The flag indicatives of the state that the interrupt of Link Up/Down occur.
 *
 * Value and state of flag
 * ETHER_FLAG_OFF (0): It is not possible to communicate.
 * ETHER_FLAG_ON  (1): It is possible to communicate.
 */
static uint8_t transfer_enable_flag[ETHER_CHANNEL_MAX];

/*
 * The flag indicatives of the state that the interrupt of magic packet detection occur.
 *
 * Value and state of flag
 * ETHER_FLAG_OFF (0): The interrupt of the magic packet detection has not been generated.
 * ETHER_FLAG_ON  (1): The interrupt of the magic packet detection was generated.
 *
 * If the R_ETHER_LinkProcess function is called, and the interrupt processing of the magic packet detection is done,
 * this flag becomes ETHER_FLAG_OFF(0).
 */
static uint8_t mpd_flag[ETHER_CHANNEL_MAX];

static uint8_t mac_addr_buf[ETHER_CHANNEL_MAX][6];

/*
 * The flag indicatives of the state that the interrupt of Link Up/Down occur.
 *
 * Value and state of flag
 * ETHER_FLAG_OFF         (0) : The Link up/down interrupt has not been generated.
 * ETHER_FLAG_ON_LINK_OFF (2) : The Link down interrupt was generated.
 * ETHER_FLAG_ON_LINK_ON  (3) : The Link up interrupt was generated.
 *
 * If the R_ETHER_LinkProcess function is called, and the interrupt processing of Link Up/Down is done,
 * this flag becomes ETHER_FLAG_OFF(0).
 */
static uint8_t lchng_flag[ETHER_CHANNEL_MAX];

/*
 * The flag indicatives of the state that enable/disable multicast frame filtering.
 *
 * Value and state of flag
 * ETHER_MC_FILTER_OFF          (0) : Disable multicast frame filtering.
 * ETHER_MC_FILTER_ON           (1) : Enable multicast frame filtering.
 *
 * The frame multicast filtering is software filter. If you want to use Hardware filter,
 * please use it EPTPC in RX64M/RX71M.
 */
static uint8_t mc_filter_flag[ETHER_CHANNEL_MAX];

/*
 * The value indicatives of receive count for continuous broadcast frame.
 */
static uint32_t bc_filter_count[ETHER_CHANNEL_MAX];

/*
 * PAUSE Resolution as documented in IEEE 802.3-2008_section2 Annex
 * 28B, Table 28B-3. The following table codify logic that
 * determines how the PAUSE is configured for local transmitter
 * and receiver and partner transmitter and receiver.
 */
static const pauseresolution_t pause_resolution[PAUSE_TABLE_ENTRIES] =
{
{ PAUSE_MASKC, PAUSE_VAL0, XMIT_PAUSE_OFF, RECV_PAUSE_OFF },
{ PAUSE_MASKE, PAUSE_VAL4, XMIT_PAUSE_OFF, RECV_PAUSE_OFF },
{ PAUSE_MASKF, PAUSE_VAL6, XMIT_PAUSE_OFF, RECV_PAUSE_OFF },
{ PAUSE_MASKF, PAUSE_VAL7, XMIT_PAUSE_ON,  RECV_PAUSE_OFF },
{ PAUSE_MASKE, PAUSE_VAL8, XMIT_PAUSE_OFF, RECV_PAUSE_OFF },
{ PAUSE_MASKA, PAUSE_VALA, XMIT_PAUSE_ON,  RECV_PAUSE_ON  },
{ PAUSE_MASKF, PAUSE_VALC, XMIT_PAUSE_OFF, RECV_PAUSE_OFF },
{ PAUSE_MASKF, PAUSE_VALD, XMIT_PAUSE_OFF, RECV_PAUSE_ON  } };

/*
 * Receive, transmit descriptors and their buffer.  They are
 * defined with section pragma directives to easily locate them
 * on the memory map.
 */
static descriptor_t rx_descriptors[ETHER_CHANNEL_MAX][ETHER_CFG_EMAC_RX_DESCRIPTORS] __attribute((section("NC_BSS"),aligned(32)));
static descriptor_t tx_descriptors[ETHER_CHANNEL_MAX][ETHER_CFG_EMAC_TX_DESCRIPTORS] __attribute((section("NC_BSS"),aligned(32)));

/*
 * As for Ethernet buffer, the size of total buffer which are use for transmission and the reception is secured.
 * The total buffer's size which the value is integrated from  EMAC_NUM_BUFFERS (buffer number) and
 * ETHER_CFG_BUFSIZE (the size of one buffer).
 * The ETHER_CFG_BUFSIZE and EMAC_NUM_BUFFERS are defined by macro in the file "r_ether_private.h".
 * It is sequentially used from the head of the buffer as a receive buffer or a transmission buffer.
 */
static etherbuffer_t ether_buffers[ETHER_CHANNEL_MAX] __attribute((section("NC_BSS"),aligned(32)));

static uint8_t promiscuous_mode[ETHER_CHANNEL_MAX];

static uint8_t etherc_edmac_power_cont[ETHER_CHANNEL_MAX];

const ether_control_t g_eth_control_ch[ETHER_CHANNEL_MAX] =
{
#if (ETHER_CH0_EN == 1)
    /* Ether = ch0, Phy access = ch0 */
    { &ETHERC0, &EDMAC0, (volatile uint32_t*)&ETHERC0.PIR.LONG, ETHER_CFG_CH0_PHY_ADDRESS, PORT_CONNECT_ET0 },
#endif
#if (ETHER_CH1_EN == 1)
    /* Ether = ch1, Phy access = ch1 */
    { &ETHERC1, &EDMAC1, (volatile uint32_t*)&ETHERC1.PIR.LONG, ETHER_CFG_CH1_PHY_ADDRESS, PORT_CONNECT_ET1 },
#endif
};

#if (ETHER_CFG_USE_LINKSTA == 0)
/* Previous link status */
static int16_t g_pre_link_stat[ETHER_CHANNEL_MAX];
#endif

#if (ETHER_CFG_USE_VIRTUAL_ADDRESS)
static uint32_t ether_mmu_uncached_diff;

static uint32_t ether_mmu_VAtoPA(uint32_t vaddr)
{
    uint32_t *ttb = (uint32_t *)(__get_TTBR0() & 0xFFFFC000);
    uint32_t *ttb_l2;
    uint32_t paddr = vaddr;

    ttb += (vaddr >> 20);
    if ((*ttb & (0x40000 | 0x3)) == 2) {
        paddr = (*ttb & 0xfff00000) | (vaddr & 0xfffff);
    } else if ((*ttb & 0x3) == 1) {
        ttb_l2 = (uint32_t *)(*ttb & 0xFFFFFC00);
        if ((*ttb_l2 & 0x3) == 0) {
            /* do nothing */
        } else if ((*ttb_l2 & 0x3) == 1) { /* 64k page entry */
            ttb_l2 += ((vaddr & 0x000ff000) >> 12);
            paddr = (*ttb_l2 & 0xffff0000) | (vaddr & 0xffff);
        } else {                           /* 4k page entry */
            ttb_l2 += ((vaddr & 0x000ff000) >> 12);
            paddr = (*ttb_l2 & 0xfffff000) | (vaddr & 0xfff);
        }
    } else {
        /* do nothing */
    }

    return paddr;
}
#endif

/*
 * Renesas Ethernet API functions
 */
/***********************************************************************************************************************
 * Function Name: R_ETHER_Initial (Implementation to file hwsetup.c)
 * Description  : Initialization of Ether driver.
 * Arguments    : none
 * Return Value : none
 ***********************************************************************************************************************/
void R_ETHER_Initial (void)
{
    uint32_t i;

    /* Initialize the transmit and receive descriptor */
    memset(&rx_descriptors, 0x00, sizeof(rx_descriptors));
    memset(&tx_descriptors, 0x00, sizeof(tx_descriptors));

    /* Initialize the Ether buffer */
    memset(&ether_buffers, 0x00, sizeof(ether_buffers));

    memset(etherc_edmac_power_cont, 0x00, sizeof(etherc_edmac_power_cont));

    /* Initialize the callback function pointer */
    cb_func.pcb_func = NULL;

    /* Initialize the interrupt handler pointer */
    cb_func.pcb_int_hnd = NULL;

    /* Initialize */
    for (i = 0; i < ETHER_CHANNEL_MAX; i++) {
        papp_rx_desc[i] = NULL;
        papp_tx_desc[i] = NULL;
        pause_frame_enable[i] = ETHER_FLAG_OFF;
#if (ETHER_CFG_USE_LINKSTA == 0)
        g_pre_link_stat[i] = ETHER_ERR_OTHER;
#endif
        promiscuous_mode[i] = ETHER_PROMISCUOUS_OFF;
        mc_filter_flag[i] = ETHER_MC_FILTER_OFF;
        bc_filter_count[i] = 0;
    }
#if (ETHER_CFG_USE_VIRTUAL_ADDRESS)
    {
        uint32_t vaddress = (uint32_t)&rx_descriptors;
        uint32_t paddress;

        paddress = ether_mmu_VAtoPA(vaddress);
        ether_mmu_uncached_diff = vaddress - paddress;
    }
#endif

} /* End of function R_ETHER_Initial() */

/***********************************************************************************************************************
 * Function Name: R_ETHER_Open_ZC2
 * Description  : After ETHERC, EDMAC,0x00000002; and PHY-LSI are reset in software, an auto negotiation of PHY-LSI is
 *                 begun.
 *                Afterwards, the link signal change interrupt is permitted.
 * Arguments    : channel -
 *                    ETHERC channel number
 *                mac_addr -
 *                    The MAC address of ETHERC
 *                pause -
 *                    Specifies whether flow control functionality is enabled or disabled.
 * Return Value : ETHER_SUCCESS -
 *                    Processing completed successfully
 *                ETHER_ERR_INVALID_CHAN -
 *                    Nonexistent channel number
 *                ETHER_ERR_INVALID_PTR -
 *                    Value of the pointer is NULL
 *                ETHER_ERR_INVALID_DATA -
 *                    Value of the argument is out of range
 *                ETHER_ERR_OTHER -
 *                    Initialization of PHY-LSI failed
 ***********************************************************************************************************************/
ether_return_t R_ETHER_Open_ZC2 (uint32_t channel, const uint8_t mac_addr[], uint8_t pause)
{
    ether_return_t ret;
    int16_t phy_ret;
    volatile struct st_etherc * petherc_adr;
    volatile struct st_edmac * pedmac_adr;
    uint32_t channel_index = get_control_tbl_index(channel);

    if (NULL == mac_addr) {
        return ETHER_ERR_INVALID_PTR;
    }
    if ((ETHER_FLAG_OFF != pause) && (ETHER_FLAG_ON != pause)) {
        return ETHER_ERR_INVALID_DATA;
    }

    petherc_adr = g_eth_control_ch[channel_index].petherc;
    pedmac_adr = g_eth_control_ch[channel_index].pedmac;

    /* Initialize the flags */
    transfer_enable_flag[channel_index] = ETHER_FLAG_OFF;
    mpd_flag[channel_index] = ETHER_FLAG_OFF;
    lchng_flag[channel_index] = ETHER_FLAG_OFF;

    pause_frame_enable[channel_index] = pause;

    mac_addr_buf[channel_index][0] = mac_addr[0];
    mac_addr_buf[channel_index][1] = mac_addr[1];
    mac_addr_buf[channel_index][2] = mac_addr[2];
    mac_addr_buf[channel_index][3] = mac_addr[3];
    mac_addr_buf[channel_index][4] = mac_addr[4];
    mac_addr_buf[channel_index][5] = mac_addr[5];

#if (ETHER_CH0_EN == 1)
    InterruptHandlerRegister(EINT0_IRQn, &ether_eint0);
#endif
#if (ETHER_CH1_EN == 1)
    InterruptHandlerRegister(EINT1_IRQn, &ether_eint1);
#endif

    /* Software reset */
    ether_reset_mac(channel);

    /* Software reset the PHY */
    phy_ret = phy_init(channel);
    if (R_PHY_OK == phy_ret) {
        phy_start_autonegotiate(channel, pause_frame_enable[channel_index]);

        /* Clear all ETHERC status BFR, PSRTO, LCHNG, MPD, ICD */
        petherc_adr->ECSR.LONG = 0x00000037;

        /* Clear all EDMAC status bits */
        pedmac_adr->EESR.LONG = 0x47FF0F9F;

#if (ETHER_CFG_USE_LINKSTA == 1)
        /* Enable interrupts of interest only. */
        petherc_adr->ECSIPR.BIT.LCHNGIP = 1;
#endif

        pedmac_adr->EESIPR.BIT.ECIIP = 1;

        /* Set Ethernet interrupt level and enable */
#if (ETHER_CH0_EN == 1)
        GIC_SetPriority(EINT0_IRQn, 0x80);
        GIC_EnableIRQ(EINT0_IRQn);
#endif
#if (ETHER_CH1_EN == 1)
        GIC_SetPriority(EINT1_IRQn, 0x80);
        GIC_EnableIRQ(EINT1_IRQn);
#endif
        ret = ETHER_SUCCESS;
    } else {
        ret = ETHER_ERR_OTHER;
    }

    return ret;
} /* End of function R_ETHER_Open_ZC2() */

/***********************************************************************************************************************
 * Function Name: R_ETHER_Close_ZC2
 * Description  : Disables Ethernet peripheral
 * Arguments    : channel -
 *                    ETHERC channel number
 * Return Value : ETHER_SUCCESS -
 *                    Processing completed successfully
 *                ETHER_ERR_INVALID_CHAN -
 *                    Nonexistent channel number
 ***********************************************************************************************************************/
ether_return_t R_ETHER_Close_ZC2 (uint32_t channel)
{
    volatile struct st_etherc * petherc_adr;
    volatile struct st_edmac * pedmac_adr;
    uint32_t channel_index = get_control_tbl_index(channel);

    petherc_adr = g_eth_control_ch[channel_index].petherc;
    pedmac_adr = g_eth_control_ch[channel_index].pedmac;

    /* Disable Ethernet interrupt. */
#if (ETHER_CH0_EN == 1)
    GIC_DisableIRQ(EINT0_IRQn);
#endif
#if (ETHER_CH1_EN == 1)
    GIC_DisableIRQ(EINT1_IRQn);
#endif

    petherc_adr->ECSIPR.BIT.LCHNGIP = 0;
    pedmac_adr->EESIPR.BIT.ECIIP = 0;

    /* Disable TE and RE  */
    petherc_adr->ECMR.LONG = 0x00000000;

    /* Initialize the flags */
    transfer_enable_flag[channel_index] = ETHER_FLAG_OFF;
    mpd_flag[channel_index] = ETHER_FLAG_OFF;
    lchng_flag[channel_index] = ETHER_FLAG_OFF;
#if (ETHER_CFG_USE_LINKSTA == 0)
    g_pre_link_stat[channel_index] = ETHER_ERR_OTHER;
#endif

    return ETHER_SUCCESS;
} /* End of function R_ETHER_Close_ZC2() */

/***********************************************************************************************************************
 * Function Name: R_ETHER_Read_ZC2
 * Description  : Receives an Ethernet frame.  Sets the passed
 *                buffer pointer to the Ethernet frame buffer
 *                from the driver. This makes the data available to
 *                the caller as a zero-copy operation.
 * Arguments    : channel -
 *                    ETHERC channel number
 *                pbuf -
 *                    Pointer to buffer that holds the receive data
 * Return Value : Returns the number of bytes received.
 *                ETHER_NO_DATA -
 *                    A zero value indicates no data is received.
 *                ETHER_ERR_INVALID_CHAN -
 *                    Nonexistent channel number
 *                ETHER_ERR_INVALID_PTR -
 *                    Value of the pointer is NULL
 *                ETHER_ERR_LINK -
 *                    Auto-negotiation is not completed, and reception is not enabled.
 *                ETHER_ERR_MPDE -
 *                    As a Magic Packet is being detected, transmission and reception is not enabled.
 *                ETHER_ERR_MC_FRAME -
 *                    Multicast Frame filter is enable, and Multicast Address Frame is received.
 ***********************************************************************************************************************/
int32_t R_ETHER_Read_ZC2 (uint32_t channel, void **pbuf)
{
    int32_t num_recvd;
    int32_t ret;
    int32_t complete_flag;
    int32_t ret2;
    descriptor_t * p_rx_desc;
    uint32_t channel_index = get_control_tbl_index(channel);

    p_rx_desc = papp_rx_desc[channel_index];

    if (NULL == p_rx_desc) {
        return ETHER_ERR_INVALID_CHAN;
    }
    if (NULL == pbuf) {
        return ETHER_ERR_INVALID_PTR;
    }

    /* When the Link up processing is not completed, return error */
    if (ETHER_FLAG_OFF == transfer_enable_flag[channel_index]) {
        return ETHER_ERR_LINK;
    }

    /* In case of detection mode of magic packet, return error. */
    if (1 == check_mpde_bit()) {
        return ETHER_ERR_MPDE;
    }

    /* When the Link up processing is completed */
    ret = ETHER_NO_DATA;
    complete_flag = ETHER_ERR_OTHER;
    while (ETHER_SUCCESS != complete_flag) {
        /* When receive data exists. */
        if (RACT != (p_rx_desc->status & RACT)) {
            /* Check multicast is detected when multicast frame filter is enabled */
            if (ETHER_MC_FILTER_ON == mc_filter_flag[channel_index]) {
                if (RFS7_RMAF == (p_rx_desc->status & RFS7_RMAF)) {
                    /* The buffer is released at the multicast frame detect.  */
                    ret2 = R_ETHER_Read_ZC2_BufRelease(channel);
                    if (ETHER_SUCCESS != ret2) {
                        return ret2;
                    }

                    ret = ETHER_ERR_MC_FRAME;
                    complete_flag = ETHER_SUCCESS;
                }
            }

            if (ETHER_ERR_MC_FRAME != ret) {
                if (RFE == (p_rx_desc->status & RFE)) {
                    /* The buffer is released at the error.  */
                    ret2 = R_ETHER_Read_ZC2_BufRelease(channel);
                    if (ETHER_SUCCESS != ret2) {
                        return ret2;
                    }
                } else {
                    /**
                     * Pass the pointer to received data to application.  This is
                     * zero-copy operation.
                     */
#if (ETHER_CFG_USE_VIRTUAL_ADDRESS)
                    (*pbuf) = (void *)(((uint32_t) p_rx_desc->buf_p) + ether_mmu_uncached_diff);
#else
                    (*pbuf) = (void *) p_rx_desc->buf_p;
#endif

                    /* Get bytes received */
                    num_recvd = p_rx_desc->size;
                    ret = num_recvd;
                    complete_flag = ETHER_SUCCESS;
                }
            }
        } else {
            ret = ETHER_NO_DATA;
            complete_flag = ETHER_SUCCESS;
        }
    }

    return ret;
} /* End of function R_ETHER_Read_ZC2() */

/***********************************************************************************************************************
 * Function Name: R_ETHER_Read_ZC2_BufRelease
 * Description  : Release the receive buffer.
 * Arguments    : channel -
 *                    Specifies the ETHERC channel number.
 * Return Value : ETHER_SUCCESS -
 *                    Processing completed successfully
 *                ETHER_ERR_INVALID_CHAN -
 *                    Nonexistent channel number
 *                ETHER_ERR_LINK -
 *                    Auto-negotiation is not completed, and reception is not enabled.
 *                ETHER_ERR_MPDE -
 *                    As a Magic Packet is being detected, transmission and reception is not enabled.
 ***********************************************************************************************************************/
int32_t R_ETHER_Read_ZC2_BufRelease (uint32_t channel)
{
    volatile struct st_edmac * pedmac_adr;
    uint32_t status;
    descriptor_t * p_rx_desc;
    uint32_t channel_index = get_control_tbl_index(channel);

    p_rx_desc = papp_rx_desc[channel_index];

    if (NULL == p_rx_desc) {
        return ETHER_ERR_INVALID_CHAN;
    }

    /* When the Link up processing is not completed, return error */
    if (ETHER_FLAG_OFF == transfer_enable_flag[channel_index]) {
        return ETHER_ERR_LINK;
    }

    /* In case of detection mode of magic packet, return error. */
    if (1 == check_mpde_bit()) {
        return ETHER_ERR_MPDE;
    }

    /* When the Link up processing is completed */
    /* When receive data exists */
    if (RACT != (p_rx_desc->status & RACT)) {
        /* Move to next descriptor */
        p_rx_desc->status |= RACT;

        status = RFP1;
        status |= RFP0;
        status |= RFE;
        status |= RFS9_RFOVER;
        status |= RFS8_RAD;
        status |= RFS7_RMAF;
        status |= RFS4_RRF;
        status |= RFS3_RTLF;
        status |= RFS2_RTSF;
        status |= RFS1_PRE;
        status |= RFS0_CERF;

        papp_rx_desc[channel_index]->status &= (~status);
        papp_rx_desc[channel_index] = papp_rx_desc[channel_index]->next;
    }
    pedmac_adr = g_eth_control_ch[channel_index].pedmac;

    if (0x00000000L == pedmac_adr->EDRRR.LONG) {
        /* Restart if stopped */
        pedmac_adr->EDRRR.LONG = 0x00000001L;
    }

    return ETHER_SUCCESS;
} /* End of function R_ETHER_Read_ZC2_BufRelease() */

/***********************************************************************************************************************
 * Function Name: R_ETHER_Write_ZC2_GetBuf
 * Description  : Get Points to the buffer pointer used by the stack.
 * Arguments    : channel -
 *                    ETHERC channel number
 *                pbuf -
 *                    Pointer to the starting address of the transmit data destination
 *                pbuf_size -
 *                    The Maximum size to write to the buffer
 * Return Value : ETHER_SUCCESS -
 *                    Processing completed successfully
 *                ETHER_ERR_INVALID_CHAN -
 *                    Nonexistent channel number
 *                ETHER_ERR_INVALID_PTR -
 *                    Value of the pointer is NULL
 *                ETHER_ERR_LINK -
 *                    Auto-negotiation is not completed, and reception is not enabled.
 *                ETHER_ERR_MPDE -
 *                    As a Magic Packet is being detected, transmission and reception is not enabled.
 *                ETHER_ERR_TACT -
 *                    Transmit buffer is not empty.
 ***********************************************************************************************************************/
ether_return_t R_ETHER_Write_ZC2_GetBuf (uint32_t channel, void **pbuf, uint16_t *pbuf_size)
{
    /* Check argument */
    descriptor_t* p_tx_desc;
    uint32_t channel_index = get_control_tbl_index(channel);

    p_tx_desc = papp_tx_desc[channel_index];
    if (NULL == p_tx_desc) {
        return ETHER_ERR_INVALID_CHAN;
    }
    if (NULL == pbuf) {
        return ETHER_ERR_INVALID_PTR;
    }
    if (NULL == pbuf_size) {
        return ETHER_ERR_INVALID_PTR;
    }

    /* When the Link up processing is not completed, return error */
    if (ETHER_FLAG_OFF == transfer_enable_flag[channel_index]) {
        return ETHER_ERR_LINK;
    }

    /* In case of detection mode of magic packet, return error. */
    if (1 == check_mpde_bit()) {
        return ETHER_ERR_MPDE;
    }

    /* When the Link up processing is completed */
    /* All transmit buffers are full */
    if (TACT == (p_tx_desc->status & TACT)) {
        return ETHER_ERR_TACT;
    }

    /* Give application another buffer to work with */
#if (ETHER_CFG_USE_VIRTUAL_ADDRESS)
    (*pbuf) = (void*)((p_tx_desc->buf_p) + ether_mmu_uncached_diff);
#else
    (*pbuf) = (void*) p_tx_desc->buf_p;
#endif
    (*pbuf_size) = ETHER_CFG_BUFSIZE;

    return ETHER_SUCCESS;
} /* End of function R_ETHER_Write_ZC2_GetBuf() */

/***********************************************************************************************************************
 * Function Name: R_ETHER_Write_ZC2_SetBuf
 * Description  : Transmits an Ethernet frame.
 *                The transmit descriptor points to the data to transmit.
 *                Data is sent directly from memory as a "zero copy" operation.
 * Arguments    : channel -
 *                    ETHERC channel number
 *                len -
 *                    The size (60 to 1,514 bytes) which is the Ethernet frame length minus 4 bytes of CRC
 * Return Value : ETHER_SUCCESS -
 *                    Processing completed successfully
 *                ETHER_ERR_INVALID_CHAN -
 *                    Nonexistent channel number
 *                ETHER_ERR_INVALID_DATA -
 *                    Value of the argument is out of range
 *                ETHER_ERR_LINK -
 *                    Auto-negotiation is not completed, and reception is not enabled.
 *                ETHER_ERR_MPDE -
 *                    As a Magic Packet is being detected, transmission and reception is not enabled.
 ***********************************************************************************************************************/
ether_return_t R_ETHER_Write_ZC2_SetBuf (uint32_t channel, const uint32_t len)
{
    volatile struct st_edmac * pedmac_adr;
    descriptor_t* p_tx_desc;
    uint32_t channel_index = get_control_tbl_index(channel);

    p_tx_desc = papp_tx_desc[channel_index];
    if (NULL == p_tx_desc) {
        return ETHER_ERR_INVALID_CHAN;
    }
    if ((ETHER_BUFSIZE_MIN > len) || (ETHER_BUFSIZE_MAX < len)) {
        return ETHER_ERR_INVALID_DATA;
    }

    /* When the Link up processing is not completed, return error */
    if (ETHER_FLAG_OFF == transfer_enable_flag[channel_index]) {
        return ETHER_ERR_LINK;
    }

    /* In case of detection mode of magic packet, return error. */
    if (1 == check_mpde_bit()) {
        return ETHER_ERR_MPDE;
    }

    /* When the Link up processing is completed */
    /* The data of the buffer is made active.  */
    p_tx_desc->bufsize = len;
    p_tx_desc->status &= (~(TFP1 | TFP0));
    p_tx_desc->status |= ((TFP1 | TFP0) | TACT);
    papp_tx_desc[channel_index] = p_tx_desc->next;

    pedmac_adr = g_eth_control_ch[channel_index].pedmac;

    if (0x00000000L == pedmac_adr->EDTRR.LONG) {
        /* Restart if stopped */
        pedmac_adr->EDTRR.LONG = 0x00000001L;
    }

    return ETHER_SUCCESS;
} /* End of function R_ETHER_Write_ZC2_SetBuf() */

/***********************************************************************************************************************
 * Function Name: R_ETHER_CheckLink_ZC
 * Description  : Verifies the Etherent link is up or not.
 * Arguments    : channel -
 *                    ETHERC channel number
 * Return Value : ETHER_SUCCESS -
 *                    Link is up
 *                ETHER_ERR_OTHER -
 *                    Link is down
 *                ETHER_ERR_INVALID_CHAN -
 *                    Nonexistent channel number
 ***********************************************************************************************************************/
ether_return_t R_ETHER_CheckLink_ZC (uint32_t channel)
{
    if (R_PHY_ERROR == phy_get_link_status(channel)) {
        /* Link is down */
        return ETHER_ERR_OTHER;
    }

    /* Link is up */
    return ETHER_SUCCESS;
} /* End of function R_ETHER_CheckLink_ZC() */

/***********************************************************************************************************************
 * Function Name: R_ETHER_LinkProcess
 * Description  : The Link up processing, the Link down processing, and the magic packet detection processing are
 *                 executed.
 * Arguments    : channel -
 *                    ETHERC channel number
 * Return Value : none
 ***********************************************************************************************************************/
void R_ETHER_LinkProcess (uint32_t channel)
{
    volatile struct st_etherc * petherc_adr;

    int32_t ret;
    ether_cb_arg_t cb_arg;
    uint32_t channel_index = get_control_tbl_index(channel);

    /* When the magic packet is detected. */
    if (ETHER_FLAG_ON == mpd_flag[channel_index]) {
        mpd_flag[channel_index] = ETHER_FLAG_OFF;

        if (NULL != cb_func.pcb_func) {
            cb_arg.channel = channel;
            cb_arg.event_id = ETHER_CB_EVENT_ID_WAKEON_LAN;
            (*cb_func.pcb_func)((void *) &cb_arg);
        }

        /*
         * After the close function is called, the open function is called
         * to have to set ETHERC to a usual operational mode
         * to usually communicate after magic packet is detected.
         */
        R_ETHER_Close_ZC2(channel);
        R_ETHER_Open_ZC2(channel, mac_addr_buf[channel_index], pause_frame_enable[channel_index]);
    }

#if (ETHER_CFG_USE_LINKSTA == 0)
    ret = R_ETHER_CheckLink_ZC(channel);
    if (g_pre_link_stat[channel_index] != ret) {
        if (ret == ETHER_SUCCESS) {
            /* The state of the link status in PHY-LSI is confirmed and Link Up/Down is judged. */
            /* When becoming Link up */
            lchng_flag[channel_index] = ETHER_FLAG_ON_LINK_ON;
        } else {
            /* When becoming Link down */
            lchng_flag[channel_index] = ETHER_FLAG_ON_LINK_OFF;
        }
    }
    g_pre_link_stat[channel_index] = ret;
#endif

    /* When the link is up */
    if (ETHER_FLAG_ON_LINK_ON == lchng_flag[channel_index]) {
#if (ETHER_CFG_USE_LINKSTA == 1)
        /*
         * The Link Up/Down is confirmed by the Link Status bit of PHY register1,
         * because the LINK signal of PHY-LSI is used for LED indicator, and
         * isn't used for notifing the Link Up/Down to external device.
         */
        ret = R_ETHER_CheckLink_ZC(channel);
        if (ETHER_SUCCESS == ret) {
            /*
             * The status of the LINK signal became "link-up" even if PHY-LSI did not detect "link-up"
             * after a reset. To avoid this wrong detection, processing in R_ETHER_LinkProcess has been modified to
             * clear the flag after link-up is confirmed in R_ETHER_CheckLink_ZC.
             */
            lchng_flag[channel_index] = ETHER_FLAG_OFF;

            /* Initialize the transmit and receive descriptor */
            memset(&rx_descriptors[channel_index], 0x00, sizeof(rx_descriptors[channel_index]));
            memset(&tx_descriptors[channel_index], 0x00, sizeof(tx_descriptors[channel_index]));

            /* Initialize the Ether buffer */
            memset(&ether_buffers[channel_index], 0x00, sizeof(ether_buffers[channel_index]));

            transfer_enable_flag[channel_index] = ETHER_FLAG_ON;

            /*
             * ETHERC and EDMAC are set after ETHERC and EDMAC are reset in software
             * and sending and receiving is permitted.
             */
            ether_configure_mac(channel, mac_addr_buf[channel_index], NO_USE_MAGIC_PACKET_DETECT);
            ret = ether_do_link(channel, NO_USE_MAGIC_PACKET_DETECT);
            if (ETHER_SUCCESS == ret) {
                if (NULL != cb_func.pcb_func) {
                    cb_arg.channel = channel;
                    cb_arg.event_id = ETHER_CB_EVENT_ID_LINK_ON;
                    (*cb_func.pcb_func)((void *) &cb_arg);
                }
            } else {
                /* When PHY auto-negotiation is not completed */
                transfer_enable_flag[channel_index] = ETHER_FLAG_OFF;
                lchng_flag[channel_index] = ETHER_FLAG_ON_LINK_ON;
            }
        } else {
            /* no process */
        }
#elif (ETHER_CFG_USE_LINKSTA == 0)
       /*
        * The status of the LINK signal became "link-up" even if PHY-LSI did not detect "link-up"
        * after a reset. To avoid this wrong detection, processing in R_ETHER_LinkProcess has been modified to
        * clear the flag after link-up is confirmed in R_ETHER_CheckLink_ZC.
        */
        lchng_flag[channel_index] = ETHER_FLAG_OFF;

        /* Initialize the transmit and receive descriptor */
        memset(&rx_descriptors[channel_index], 0x00, sizeof(rx_descriptors[channel_index]));
        memset(&tx_descriptors[channel_index], 0x00, sizeof(tx_descriptors[channel_index]));

        /* Initialize the Ether buffer */
        memset(&ether_buffers[channel_index], 0x00, sizeof(ether_buffers[channel_index]));

        transfer_enable_flag[channel_index] = ETHER_FLAG_ON;

       /*
        * ETHERC and EDMAC are set after ETHERC and EDMAC are reset in software
        * and sending and receiving is permitted.
        */
        ether_configure_mac(channel, mac_addr_buf[channel_index], NO_USE_MAGIC_PACKET_DETECT);
        ret = ether_do_link(channel, NO_USE_MAGIC_PACKET_DETECT);
        if (ETHER_SUCCESS == ret) {
            if (NULL != cb_func.pcb_func) {
                cb_arg.channel = channel;
                cb_arg.event_id = ETHER_CB_EVENT_ID_LINK_ON;
                (*cb_func.pcb_func)((void *) &cb_arg);
            }
        } else {
            /* When PHY auto-negotiation is not completed */
            transfer_enable_flag[channel_index] = ETHER_FLAG_OFF;
            lchng_flag[channel_index] = ETHER_FLAG_ON_LINK_ON;
        }
#endif
    }

    /* When the link is down */
    else if (ETHER_FLAG_ON_LINK_OFF == lchng_flag[channel_index]) {
        lchng_flag[channel_index] = ETHER_FLAG_OFF;

#if (ETHER_CFG_USE_LINKSTA == 1)
        /*
         * The Link Up/Down is confirmed by the Link Status bit of PHY register1,
         * because the LINK signal of PHY-LSI is used for LED indicator, and
         * isn't used for notifying the Link Up/Down to external device.
         */
        ret = R_ETHER_CheckLink_ZC(channel);
        if (ETHER_ERR_OTHER == ret) {
            petherc_adr = g_eth_control_ch[channel_index].petherc;

            /* Disable receive and transmit. */
            petherc_adr->ECMR.BIT.RE = 0;
            petherc_adr->ECMR.BIT.TE = 0;

            transfer_enable_flag[channel_index] = ETHER_FLAG_OFF;

            if (NULL != cb_func.pcb_func) {
                cb_arg.channel = channel;
                cb_arg.event_id = ETHER_CB_EVENT_ID_LINK_OFF;
                (*cb_func.pcb_func)((void *) &cb_arg);
            }
        }
#elif (ETHER_CFG_USE_LINKSTA == 0)
        petherc_adr = g_eth_control_ch[channel_index].petherc;

        /* Disable receive and transmit. */
        petherc_adr->ECMR.BIT.RE = 0;
        petherc_adr->ECMR.BIT.TE = 0;

        transfer_enable_flag[channel_index] = ETHER_FLAG_OFF;

        if (NULL != cb_func.pcb_func) {
            cb_arg.channel = channel;
            cb_arg.event_id = ETHER_CB_EVENT_ID_LINK_OFF;
            (*cb_func.pcb_func)((void *) &cb_arg);
        }
#endif
    } else {
        /* Do Nothing */
    }
} /* End of function R_ETHER_LinkProcess() */

/***********************************************************************************************************************
 * Function Name: R_ETHER_WakeOnLAN
 * Description  : The setting of ETHERC is changed from a usual sending and
 *                receiving mode to the magic packet detection mode.
 * Arguments    : channel -
 *                    ETHERC channel number
 * Return Value : ETHER_SUCCESS -
 *                    Processing completed successfully
 *                ETHER_ERR_INVALID_CHAN -
 *                    Nonexistent channel number
 *                ETHER_ERR_LINK -
 *                    Auto-negotiation is not completed, and reception is not enabled.
 *                ETHER_ERR_OTHER -
 *                    A switch to magic packet detection was performed when the link state was link is down.
 ***********************************************************************************************************************/
ether_return_t R_ETHER_WakeOnLAN (uint32_t channel)
{
#if (ETHER_CFG_USE_LINKSTA == 1)
    volatile struct st_etherc * petherc_adr;
#endif
    ether_return_t ret;
    uint32_t channel_index = get_control_tbl_index(channel);

    /* When the Link up processing is not completed, return error */
    if (ETHER_FLAG_OFF == transfer_enable_flag[channel_index]) {
        return ETHER_ERR_LINK;
    }

    /* When the Link up processing is completed */
    /* Change to the magic packet detection mode.  */
    ether_configure_mac(channel, mac_addr_buf[channel_index], USE_MAGIC_PACKET_DETECT);
    ret = ether_do_link(channel, USE_MAGIC_PACKET_DETECT);
    if (ETHER_SUCCESS == ret) {
#if (ETHER_CFG_USE_LINKSTA == 1)
        petherc_adr = g_eth_control_ch[channel_index].petherc;

        /* It is confirmed not to become Link down while changing the setting. */
        if (ETHER_CFG_LINK_PRESENT == petherc_adr->PSR.BIT.LMON) {
            ret = ETHER_SUCCESS;
        } else {
            ret = ETHER_ERR_OTHER;
        }
#else
        /* It is confirmed not to become Link down while changing the setting. */
        ret = R_ETHER_CheckLink_ZC(channel);
#endif
    } else {
        ret = ETHER_ERR_OTHER;
    }

    return ret;
} /* End of function R_ETHER_WakeOnLAN() */

/***********************************************************************************************************************
 * Function Name: R_ETHER_Read
 * Description  : Receive Ethernet frame. Receives data to the location specified by the pointer to the receive buffer,
 *                using non-zero-copy communication.
 * Arguments    : channel -
 *                    ETHERC channel number
 *                pbuf -
 *                    The receive buffer (to store the receive data)
 * Return Value : Returns the number of bytes received.
 *                ETHER_NO_DATA -
 *                    A zero value indicates no data is received.
 *                ETHER_ERR_INVALID_CHAN -
 *                    Nonexistent channel number
 *                ETHER_ERR_INVALID_PTR -
 *                    Value of the pointer is NULL
 *                ETHER_ERR_LINK -
 *                    Auto-negotiation is not completed, and reception is not enabled.
 *                ETHER_ERR_MPDE -
 *                    As a Magic Packet is being detected, transmission and reception is not enabled.
 *                ETHER_ERR_MC_FRAME -
 *                    Multicast Frame filter is enable, and Multicast Address Frame is received.
 ***********************************************************************************************************************/
int32_t R_ETHER_Read (uint32_t channel, void *pbuf)
{
    int32_t ret;
    int32_t ret2;
    uint8_t * pread_buffer_address; /* Buffer location controlled by the Ethernet driver */

    /* Check argument */
    if (NULL == pbuf) {
        return ETHER_ERR_INVALID_PTR;
    }

    /* (1) Retrieve the receive buffer location controlled by the  descriptor. */
    ret = R_ETHER_Read_ZC2(channel, (void **) &pread_buffer_address);

    /* When there is data to receive */
    if (ret > ETHER_NO_DATA) {
        /* (2) Copy the data read from the receive buffer which is controlled by the descriptor to
         the buffer which is specified by the user (up to 1024 bytes). */
        memcpy(pbuf, pread_buffer_address, (uint32_t )ret);

        /* (3) Read the receive data from the receive buffer controlled by the descriptor,
         and then release the receive buffer. */
        ret2 = R_ETHER_Read_ZC2_BufRelease(channel);
        if (ETHER_SUCCESS == ret2) { /* When this function is completed successfully */
            /* Do Nothing */
        }

        /* Overwrite the error information */
        else {
            ret = ret2;
        }
    }

    /* When there is no data to receive */
    else {
        /* Do Nothing */
    }

    return ret;
} /* End of function R_ETHER_Read() */

/***********************************************************************************************************************
 * Function Name: R_ETHER_Write
 * Description  : Transmit Ethernet frame. Transmits data from the location specified by the pointer to the transmit
 *                buffer, with the data size equal to the specified frame length, using non-zero-copy communication.
 * Arguments    : channel -
 *                    ETHERC channel number
 *              : *pbuf -
 *                    Transmit buffer pointer
 *              : len -
 *                    The size (60 to 1,514 bytes) which is the Ethernet frame length minus 4 bytes of CRC
 * Return Value : ETHER_SUCCESS -
 *                    Processing completed successfully
 *                ETHER_ERR_INVALID_CHAN -
 *                    Nonexistent channel number
 *                ETHER_ERR_INVALID_DATA -
 *                    Value of the argument is out of range
 *                ETHER_ERR_INVALID_PTR -
 *                    Value of the pointer is NULL
 *                ETHER_ERR_LINK -
 *                    Auto-negotiation is not completed, and reception is not enabled.
 *                ETHER_ERR_MPDE -
 *                    As a Magic Packet is being detected, transmission and reception is not enabled.
 *                ETHER_ERR_TACT -
 *                    Transmit buffer is not empty.
 ***********************************************************************************************************************/
ether_return_t R_ETHER_Write (uint32_t channel, void *pbuf, const uint32_t len)
{
    ether_return_t ret;
    uint8_t * pwrite_buffer_address;
    uint16_t write_buf_size;

    if (NULL == pbuf) {
        return ETHER_ERR_INVALID_PTR;
    }
    if ((ETHER_BUFSIZE_MIN > len) || (ETHER_BUFSIZE_MAX < len)) {
        return ETHER_ERR_INVALID_DATA;
    }

    /* (1) Retrieve the transmit buffer location controlled by the  descriptor. */
    ret = R_ETHER_Write_ZC2_GetBuf(channel, (void **) &pwrite_buffer_address, &write_buf_size);

    /* Writing to the transmit buffer (buf) is enabled. */
    if (ETHER_SUCCESS == ret) {
        if (write_buf_size < len) {
            ret = ETHER_ERR_TACT; /* Transmit buffer overflow */
        } else {
            /* Write the transmit data to the transmit buffer. */

            /* (2) Write the data to the transmit buffer controlled by the  descriptor. */
            memcpy(pwrite_buffer_address, pbuf, len);

            /* (3) Enable the EDMAC to transmit data in the transmit buffer. */
            ret = R_ETHER_Write_ZC2_SetBuf(channel, len);

            /*
             * Confirm that the transmission is completed.
             * Data written in the transmit buffer is transmitted by the EDMAC. Make sure that the
             * transmission is completed after writing data to the transmit buffer.
             * If the R_ETHER_Close_ZC2 function is called to stop the Ethernet communication before
             * verifying that the transmission is completed, the written data written may not be transmitted.
             */
            ret = R_ETHER_CheckWrite(channel);
        }
    }

    return ret;
} /* End of function R_ETHER_Write() */

/***********************************************************************************************************************
 * Function Name: R_ETHER_CheckWrite
 * Description  : Checking that the data has been sent.
 * Arguments    : channel -
 *                    ETHERC channel number
 * Return Value : ETHER_SUCCESS -
 *                    Processing completed successfully
 *                ETHER_ERR_INVALID_CHAN -
 *                    Nonexistent channel number
 ***********************************************************************************************************************/
ether_return_t R_ETHER_CheckWrite (uint32_t channel)
{
    volatile struct st_edmac * pedmac_adr;
    uint32_t channel_index = get_control_tbl_index(channel);

    pedmac_adr = g_eth_control_ch[channel_index].pedmac;
    while (0 != pedmac_adr->EDTRR.BIT.TR) {
        /* Do Nothing */
    }

    return ETHER_SUCCESS;
} /* End of function R_ETHER_CheckWrite() */

/***********************************************************************************************************************
 * Function Name: R_ETHER_Control
 * Description  : By command argument is a function to change the settings of Ether driver.
 * Arguments    : cmd -
 *                    Control code
 *                control -
 *                    Parameters according to the control code
 * Return Value : ETHER_SUCCESS -
 *                    Processing completed successfully
 *                ETHER_ERR_INVALID_CHAN -
 *                    Nonexistent channel number
 *                ETHER_ERR_CHAN_OPEN -
 *                    Indicates the Ethernet cannot be opened because it is being used by another application
 *                ETHER_ERR_INVALID_ARG -
 *                    Invalid argument
 *                ETHER_ERR_RECV_ENABLE -
 *                    Receive function is enable.
 ***********************************************************************************************************************/
ether_return_t R_ETHER_Control (ether_cmd_t const cmd, ether_param_t const control)
{
    ether_return_t ret;

    switch (cmd) {
        /* Set the callback function pointer */
        case CONTROL_SET_CALLBACK :
            ret = ether_set_callback(control);
        break;

        case CONTROL_SET_PROMISCUOUS_MODE :
            ret = ether_set_promiscuous_mode(control);
        break;

        case CONTROL_SET_INT_HANDLER :
            ret = ether_set_int_handler(control);
        break;

        case CONTROL_POWER_ON :
            ret = ether_power_on(control);
        break;

        case CONTROL_POWER_OFF :
            ret = ether_power_off(control);
        break;

        case CONTROL_MULTICASTFRAME_FILTER :
            ret = ether_set_multicastframe_filter(control);
        break;

        case CONTROL_BROADCASTFRAME_FILTER :
            ret = ether_set_broadcastframe_filter(control);
        break;

            /* Commands not supported */
        default :
            ret = ETHER_ERR_INVALID_ARG;
        break;
    }

    return ret;
} /* End of function R_ETHER_Control() */

/***********************************************************************************************************************
 * Function Name: R_ETHER_GetVersion
 * Description  : Returns this module's version information.
 *                The version number is encoded where the top 2 bytes are the major version number and the bottom 2 bytes
 *                are the minor version number. For example, Version 4.25 would be returned as 0x00040019.
 * Arguments    : none
 * Return Value : Version number
 ***********************************************************************************************************************/
//#pragma inline(R_ETHER_GetVersion)
uint32_t R_ETHER_GetVersion (void)
{
    return ((((uint32_t) ETHER_RZA2_VERSION_MAJOR) << 16) | ((uint32_t) ETHER_RZA2_VERSION_MINOR));
} /* End of function R_ETHER_GetVersion() */

/*
 * Private functions
 */

/***********************************************************************************************************************
 * Function Name: ether_reset_mac
 * Description  : The EDMAC and EtherC are reset through the software reset.
 * Arguments    : channel -
 *                    ETHERC channel number
 * Return Value : none
 ***********************************************************************************************************************/
static void ether_reset_mac (uint32_t channel)
{
    volatile uint32_t i;

    /* Software reset */
    if (ETHER_CHANNEL_0 == channel) {
        EDMAC0.EDMR.BIT.SWR = 1;
    } else {
        EDMAC1.EDMR.BIT.SWR = 1;
    }

    /*
     * Waiting time until the initialization of ETHERC and EDMAC is completed is 64 cycles
     * in the clock conversion of an internal bus of EDMAC.
     */
    for (i = 0; i < 0x00001180; i++) {
        ;
    }

} /* End of function ether_reset_mac() */

/***********************************************************************************************************************
 * Function Name: ether_init_descriptors
 * Description  : The EDMAC descriptors and the driver buffers are initialized.
 * Arguments    : channel -
 *                    ETHERC channel number
 * Return Value : none
 ***********************************************************************************************************************/
static void ether_init_descriptors (uint32_t channel)
{
    descriptor_t * pdescriptor;
    uint32_t i;
    uint32_t channel_index = get_control_tbl_index(channel);

    /* Initialize the receive descriptors */
    for (i = 0; i < ETHER_CFG_EMAC_RX_DESCRIPTORS; i++) {
        pdescriptor = (descriptor_t *) &rx_descriptors[channel_index][i];
#if (ETHER_CFG_USE_VIRTUAL_ADDRESS)
        pdescriptor->buf_p = (uint8_t *) ether_mmu_VAtoPA((uint32_t)&(ether_buffers[channel_index].buffer[i][0]));
#else
        pdescriptor->buf_p = (uint8_t *) &(ether_buffers[channel_index].buffer[i][0]);
#endif
        pdescriptor->bufsize = ETHER_CFG_BUFSIZE;
        pdescriptor->size = 0;
        pdescriptor->status = RACT;
        pdescriptor->next = (descriptor_t *) &rx_descriptors[channel_index][(i + 1)];
    }

    /* The last descriptor points back to the start */
    pdescriptor->status |= RDLE;
    pdescriptor->next = (descriptor_t *) &rx_descriptors[channel_index][0];

    /* Initialize application receive descriptor pointer */
    papp_rx_desc[channel_index] = (descriptor_t *) &rx_descriptors[channel_index][0];

    /* Initialize the transmit descriptors */
    for (i = 0; i < ETHER_CFG_EMAC_TX_DESCRIPTORS; i++) {
        pdescriptor = (descriptor_t *) &tx_descriptors[channel_index][i];
#if (ETHER_CFG_USE_VIRTUAL_ADDRESS)
        pdescriptor->buf_p = (uint8_t *) ether_mmu_VAtoPA((uint32_t)&(ether_buffers[channel_index].buffer[(ETHER_CFG_EMAC_RX_DESCRIPTORS + i)][0]));
#else
        pdescriptor->buf_p = (uint8_t *) &(ether_buffers[channel_index].buffer[(ETHER_CFG_EMAC_RX_DESCRIPTORS + i)][0]);
#endif
        pdescriptor->bufsize = 1; /* Set a value equal to or greater than 1. (reference to UMH)
         When transmitting data, the value of size is set to the function argument
         R_ETHER_Write_ZC2_SetBuf. */
        pdescriptor->size = 0; /* Reserved : The write value should be 0. (reference to UMH) */
        pdescriptor->status = 0;
        pdescriptor->next = (descriptor_t *) &(tx_descriptors[channel_index][(i + 1)]);
    }

    /* The last descriptor points back to the start */
    pdescriptor->status |= TDLE;
    pdescriptor->next = (descriptor_t *) &tx_descriptors[channel_index][0];

    /* Initialize application transmit descriptor pointer */
    papp_tx_desc[channel_index] = (descriptor_t *) &tx_descriptors[channel_index][0];
} /* End of function ether_init_descriptors() */

/***********************************************************************************************************************
 * Function Name: ether_config_ethernet
 * Description  : Configure the Ethernet Controller (EtherC) and the Ethernet
 *                Direct Memory Access controller (EDMAC).
 * Arguments    : channel -
 *                    ETHERC channel number
 *                mode -
 *                   The operational mode is specified.
 *                   NO_USE_MAGIC_PACKET_DETECT (0) - Communicate mode usually
 *                   USE_MAGIC_PACKET_DETECT    (1) - Magic packet detection mode
 * Return Value : none
 ***********************************************************************************************************************/
static void ether_config_ethernet (uint32_t channel, const uint8_t mode)
{
    volatile struct st_etherc * petherc_adr;
    volatile struct st_edmac * pedmac_adr;
    uint32_t channel_index = get_control_tbl_index(channel);

    petherc_adr = g_eth_control_ch[channel_index].petherc;
    pedmac_adr = g_eth_control_ch[channel_index].pedmac;

    /* Magic packet detection mode */
    if (USE_MAGIC_PACKET_DETECT == mode) {
#if (ETHER_CFG_USE_LINKSTA == 1)
        petherc_adr->ECSIPR.LONG = 0x00000006;
#elif (ETHER_CFG_USE_LINKSTA == 0)
        petherc_adr->ECSIPR.LONG = 0x00000002;
#endif
        pedmac_adr->EESIPR.LONG = 0x00400000;
    }

    /* Normal mode */
    else {
#if (ETHER_CFG_USE_LINKSTA == 1)
        /* LINK Signal Change Interrupt Enable */
        petherc_adr->ECSR.BIT.LCHNG = 1;
        petherc_adr->ECSIPR.BIT.LCHNGIP = 1;
#endif
        pedmac_adr->EESIPR.BIT.ECIIP = 1;

        /* Frame receive interrupt and frame transmit end interrupt */
        pedmac_adr->EESIPR.BIT.FRIP = 1; /* Enable the frame receive interrupt. */
        pedmac_adr->EESIPR.BIT.TCIP = 1; /* Enable the frame transmit end interrupt. */
    }

    /* Ethernet length 1514bytes + CRC and intergap is 96-bit time */
    petherc_adr->RFLR.LONG = 1518;
    petherc_adr->IPGR.LONG = 0x00000014;

    /* Continuous reception number of Broadcast frame */
    petherc_adr->BCFRR.LONG = bc_filter_count[channel_index];

    /* Set little endian mode */
    /* Ethernet length 1514bytes + CRC and intergap is 96-bit time */
    pedmac_adr->EDMR.BIT.DE = 1;

    /* Initialize Rx descriptor list address */
    /* Casting the pointer to a uint32_t type is valid because the Renesas Compiler uses 4 bytes per pointer. */
#if (ETHER_CFG_USE_VIRTUAL_ADDRESS)
    pedmac_adr->RDLAR.LONG = ether_mmu_VAtoPA((uint32_t)papp_rx_desc[channel_index]);
#else
    pedmac_adr->RDLAR.LONG = (uint32_t)papp_rx_desc[channel_index];
#endif

    /* Initialize Tx descriptor list address */
    /* Casting the pointer to a uint32_t type is valid because the Renesas Compiler uses 4 bytes per pointer. */
#if (ETHER_CFG_USE_VIRTUAL_ADDRESS)
    pedmac_adr->TDLAR.LONG = ether_mmu_VAtoPA((uint32_t)papp_tx_desc[channel_index]);
#else
    pedmac_adr->TDLAR.LONG = (uint32_t)papp_tx_desc[channel_index];
#endif

    if (ETHER_MC_FILTER_ON == mc_filter_flag[channel_index]) {
        /* Reflect the EESR.RMAF bit status in the RD0.RFS bit in the receive descriptor */
        pedmac_adr->TRSCER.LONG = 0x00000000;
    } else {
        /* Don't reflect the EESR.RMAF bit status in the RD0.RFS bit in the receive descriptor */
        pedmac_adr->TRSCER.LONG = 0x00000080;
    }

    /* Threshold of Tx_FIFO */
    /* To prevent a transmit underflow, setting the initial value (store and forward modes) is recommended. */
    pedmac_adr->TFTR.LONG = 0x00000000;

    /* transmit fifo is 2048 bytes, receive fifo is 4096 bytes */
    pedmac_adr->FDR.LONG = 0x0000070F;

    /*  Configure receiving method
     b0      RNR - Receive Request Bit Reset - Continuous reception of multiple frames is possible.
     b31:b1  Reserved set to 0
     */
    pedmac_adr->RMCR.LONG = 0x00000001;

} /* End of function ether_config_ethernet() */

/***********************************************************************************************************************
 * Function Name: ether_pause_resolution
 * Description  : Determines PAUSE frame generation and handling. Uses
 *                the resolution Table 28B-3 of IEEE 802.3-2008.
 * Arguments    : local_ability -
 *                    local PAUSE capability (2 least significant bits)
 *                partner_ability -
 *                    link partner PAUSE capability (2 least significant bits)
 *                *ptx_pause -
 *                    pointer to location to store the result of the table lookup for transmit
 *                    PAUSE. 1 is enable, 0 is disable.
 *                *prx_pause -
 *                    pointer to location to store the result of the table lookup for receive
 *                    PAUSE. 1 is enable, 0 is disable.
 * Return Value : none
 ***********************************************************************************************************************/
static void ether_pause_resolution (uint16_t local_ability, uint16_t partner_ability, uint16_t *ptx_pause,
        uint16_t *prx_pause)
{
    uint32_t i;
    uint32_t ability_compare;

    /*
     * Arrange the bits so that they correspond to the Table 28B-3
     * of the IEEE 802.3 values.
     */
    ability_compare = (uint32_t) (((local_ability & LINK_RES_ABILITY_MASK) << LINK_RES_LOCAL_ABILITY_BITSHIFT)
            | (partner_ability & LINK_RES_ABILITY_MASK));

    /* Walk through the look up table */
    for (i = 0; i < PAUSE_TABLE_ENTRIES; i++) {
        if ((ability_compare & pause_resolution[i].mask) == pause_resolution[i].value) {
            (*ptx_pause) = pause_resolution[i].transmit;
            (*prx_pause) = pause_resolution[i].receive;
            return;
        }
    }
} /* End of function ether_pause_resolution() */

/***********************************************************************************************************************
 * Function Name: ether_configure_mac
 * Description  : Software reset is executed, and ETHERC and EDMAC are configured.
 * Arguments    : channel -
 *                    ETHERC channel number
 *                mac_addr -
 *                    The MAC address of ETHERC
 *                mode -
 *                    The operational mode is specified.
 *                    NO_USE_MAGIC_PACKET_DETECT (0) - Communicate mode usually
 *                    USE_MAGIC_PACKET_DETECT    (1) - Magic packet detection mode
 * Return Value : none
 ***********************************************************************************************************************/
static void ether_configure_mac (uint32_t channel, const uint8_t mac_addr[], const uint8_t mode)
{
    uint32_t mac_h;
    uint32_t mac_l;
    volatile struct st_etherc * petherc_adr;
    uint32_t channel_index = get_control_tbl_index(channel);

    petherc_adr = g_eth_control_ch[channel_index].petherc;

    /* Software reset */
    ether_reset_mac(channel);

    /* Set MAC address */
    mac_h = (((((uint32_t) mac_addr[0] << 24) | ((uint32_t) mac_addr[1] << 16)) | ((uint32_t) mac_addr[2] << 8))
            | (uint32_t) mac_addr[3]);

    mac_l = (((uint32_t) mac_addr[4] << 8) | (uint32_t) mac_addr[5]);

    petherc_adr->MAHR.LONG = mac_h;
    petherc_adr->MALR.LONG = mac_l;

    /* Initialize receive and transmit descriptors */
    ether_init_descriptors(channel);

    /* Perform reset of hardware interface configuration */
    ether_config_ethernet(channel, mode);

} /* End of function ether_configure_mac() */

/***********************************************************************************************************************
 * Function Name: ether_do_link
 * Description  : Determines the partner PHY capability through
 *                auto-negotiation process. The link abilities
 *                are handled to determine duplex, speed and flow
 *                control (PAUSE frames).
 * Arguments    : channel -
 *                    ETHERC channel number
 *                mode -
 *                    The operational mode is specified.
 *                    NO_USE_MAGIC_PACKET_DETECT (0) - Communicate mode usually
 *                    USE_MAGIC_PACKET_DETECT    (1) - Magic packet detection mode
 * Return Value : ETHER_SUCCESS -
 *                    Processing completed successfully
 *                ETHER_ERR_INVALID_CHAN -
 *                    Nonexistent channel number
 *                ETHER_ERR_OTHER -
 *                    Auto-negotiation of PHY-LSI is not completed or result of Auto-negotiation is abnormal.
 ***********************************************************************************************************************/
static ether_return_t ether_do_link (uint32_t channel, const uint8_t mode)
{
    ether_return_t ret;
    uint16_t link_speed_duplex = 0;
    uint16_t local_pause_bits = 0;
    uint16_t partner_pause_bits = 0;
    uint16_t transmit_pause_set = 0;
    uint16_t receive_pause_set = 0;
    uint16_t full_duplex = 0;
    uint16_t link_result = 0;
    volatile struct st_etherc * petherc_adr;
    volatile struct st_edmac * pedmac_adr;
    uint32_t channel_index = get_control_tbl_index(channel);

    petherc_adr = g_eth_control_ch[channel_index].petherc;
    pedmac_adr = g_eth_control_ch[channel_index].pedmac;

    /* Set the link status */
    link_result = phy_set_autonegotiate(channel, &link_speed_duplex, &local_pause_bits, &partner_pause_bits);

    if (R_PHY_OK == link_result) {
        switch (link_speed_duplex) {
            /* Half duplex link */
            case PHY_LINK_100H :
                petherc_adr->ECMR.BIT.DM = 0;
                petherc_adr->ECMR.BIT.RTM = 1;
                ret = ETHER_SUCCESS;
            break;

            case PHY_LINK_10H :
                petherc_adr->ECMR.BIT.DM = 0;
                petherc_adr->ECMR.BIT.RTM = 0;
                ret = ETHER_SUCCESS;
            break;

                /* Full duplex link */
            case PHY_LINK_100F :
                petherc_adr->ECMR.BIT.DM = 1;
                petherc_adr->ECMR.BIT.RTM = 1;
                full_duplex = 1;
                ret = ETHER_SUCCESS;
            break;

            case PHY_LINK_10F :
                petherc_adr->ECMR.BIT.DM = 1;
                petherc_adr->ECMR.BIT.RTM = 0;
                full_duplex = 1;
                ret = ETHER_SUCCESS;
            break;

            default :
                ret = ETHER_ERR_OTHER;
            break;
        }

        /* At the communicate mode usually */
        if (ETHER_SUCCESS == ret) {
            if (NO_USE_MAGIC_PACKET_DETECT == mode) {

                /* When pause frame is used */
                if ((full_duplex) && (ETHER_FLAG_ON == pause_frame_enable[channel_index])) {
                    /* Set automatic PAUSE for 512 bit-time */
                    petherc_adr->APR.LONG = 0x0000FFFF;

                    /* Set unlimited retransmit of PAUSE frames */
                    petherc_adr->TPAUSER.LONG = 0;

                    /* PAUSE flow control FIFO settings. */
                    pedmac_adr->FCFTR.LONG = 0x00000000;

                    /* Control of a PAUSE frame whose TIME parameter value is 0 is enabled. */
                    petherc_adr->ECMR.BIT.ZPF = 1;

                    /**
                     * Enable PAUSE for full duplex link depending on
                     * the pause resolution results
                     */
                    ether_pause_resolution(local_pause_bits, partner_pause_bits, &transmit_pause_set,
                            &receive_pause_set);

                    if (XMIT_PAUSE_ON == transmit_pause_set) {
                        /* Enable automatic PAUSE frame transmission */
                        petherc_adr->ECMR.BIT.TXF = 1;
                    } else {
                        /* Disable automatic PAUSE frame transmission */
                        petherc_adr->ECMR.BIT.TXF = 0;
                    }

                    if (RECV_PAUSE_ON == receive_pause_set) {
                        /* Enable reception of PAUSE frames */
                        petherc_adr->ECMR.BIT.RXF = 1;
                    } else {
                        /* Disable reception of PAUSE frames */
                        petherc_adr->ECMR.BIT.RXF = 0;
                    }
                }

                /* When pause frame is not used */
                else {
                    /* Disable PAUSE for half duplex link */
                    petherc_adr->ECMR.BIT.TXF = 0;
                    petherc_adr->ECMR.BIT.RXF = 0;
                }

                /* Set the promiscuous mode bit */
                petherc_adr->ECMR.BIT.PRM = promiscuous_mode[channel_index];

                /* Enable receive and transmit. */
                petherc_adr->ECMR.BIT.RE = 1;
                petherc_adr->ECMR.BIT.TE = 1;

                /* Enable EDMAC receive */
                pedmac_adr->EDRRR.LONG = 0x1;
            }

            /* At the magic packet detection mode */
            else {
                /* The magic packet detection is permitted. */
                petherc_adr->ECMR.BIT.MPDE = 1;

                /* Because data is not transmitted for the magic packet detection waiting,
                 only the reception is permitted. */
                petherc_adr->ECMR.BIT.RE = 1;

                /*
                 * The reception function of EDMAC keep invalidity
                 * because the receive data don't need to be read when the magic packet detection mode.
                 */
            }
        }
    } else {
        ret = ETHER_ERR_OTHER;
    }

    return ret;
} /* End of function ether_do_link() */

/***********************************************************************************************************************
 * Function Name: ether_set_callback
 * Description  : Set the callback function
 * Arguments    : control -
 *                    Callback function pointer.
 *                    If you would rather poll for finish then please input NULL for this argument.
 * Return Value : ETHER_SUCCESS
 *                    Processing completed successfully
 ***********************************************************************************************************************/
static ether_return_t ether_set_callback (ether_param_t const control)
{
    void (*pcb_func) (void *);

    pcb_func = control.ether_callback.pcb_func;

    /* Check callback function pointer */
    if (NULL != pcb_func) {
        cb_func.pcb_func = pcb_func; /* Set the callback function */
    }

    return ETHER_SUCCESS;
} /* End of function ether_set_callback() */

/***********************************************************************************************************************
 * Function Name: ether_set_promiscuous_mode
 * Description  : Set promiscuous mode bit
 * Arguments    : control -
 *                    Promiscuous mode bit
 * Return Value : ETHER_SUCCESS -
 *                    Processing completed successfully
 *                ETHER_ERR_INVALID_CHAN -
 *                    Nonexistent channel number
 ***********************************************************************************************************************/
static ether_return_t ether_set_promiscuous_mode (ether_param_t const control)
{
    ether_promiscuous_t * p_arg;
    uint32_t channel_index = get_control_tbl_index((uint32_t)control.channel);

    p_arg = control.p_ether_promiscuous;

    promiscuous_mode[channel_index] = p_arg->bit;

    return ETHER_SUCCESS;
} /* End of function ether_set_promiscuous_mode() */

/***********************************************************************************************************************
 * Function Name: ether_set_int_handler
 * Description  : Set the interrupt handler
 * Arguments    : control -
 *                    Interrupt handler pointer.
 *                    If you would rather poll for finish then please input NULL for this argument.
 * Return Value : ETHER_SUCCESS -
 *                    Processing completed successfully
 *                ETHER_ERR_INVALID_ARG -
 *                    Invalid argument
 ***********************************************************************************************************************/
static ether_return_t ether_set_int_handler (ether_param_t const control)
{
    void (*pcb_int_hnd) (void *);
    ether_return_t ret = ETHER_ERR_INVALID_ARG;

    pcb_int_hnd = control.ether_int_hnd.pcb_int_hnd;
    if (NULL != pcb_int_hnd) {
        cb_func.pcb_int_hnd = pcb_int_hnd;
        ret = ETHER_SUCCESS;
    }
    return ret;
} /* End of function ether_set_int_handler() */

/***********************************************************************************************************************
 * Function Name: ether_power_on
 * Description  : Turns on power to a ETHER channel.
 * Arguments    : control -
 *                    Ethernet channel number
 * Return Value : ETHER_SUCCESS -
 *                    Processing completed successfully
 *                ETHER_ERR_INVALID_CHAN -
 *                    Nonexistent channel number
 *                ETHER_ERR_CHAN_OPEN -
 *                    Indicates the Ethernet cannot be opened because it is being used by another application
 *                ETHER_ERR_INVALID_ARG -
 *                    Invalid argument
 ***********************************************************************************************************************/
static ether_return_t ether_power_on (ether_param_t const control)
{
    uint32_t channel_index = get_control_tbl_index((uint32_t)control.channel);

    /* Set port connect */
    ether_set_phy_mode(g_eth_control_ch[channel_index].port_connect);

    /* ETHERC/EDMAC Power on */
    return power_on_control((uint32_t)control.channel);
} /* End of function ether_power_on() */

/***********************************************************************************************************************
 * Function Name: ether_power_off
 * Description  : Turns on power to a ETHER channel.
 * Arguments    : control -
 *                    Ethernet channel number
 * Return Value : ETHER_SUCCESS -
 *                    Processing completed successfully
 *                ETHER_ERR_INVALID_ARG -
 *                    Invalid argument
 ***********************************************************************************************************************/
static ether_return_t ether_power_off (ether_param_t const control)
{
    /* ETHERC/EDMAC Power off */
    power_off_control((uint32_t)control.channel);

    return ETHER_SUCCESS;
} /* End of function ether_power_off() */

/***********************************************************************************************************************
 * Function Name: power_on
 * Description  : Turns on power to a ETHER channel.
 * Arguments    : channel -
 *                    ETHERC channel number
 * Return Value : ETHER_SUCCESS -
 *                    Processing completed successfully
 *                ETHER_ERR_INVALID_CHAN -
 *                    Nonexistent channel number
 *                ETHER_ERR_CHAN_OPEN -
 *                    Indicates the Ethernet cannot be opened because it is being used by another application
 ***********************************************************************************************************************/
static ether_return_t power_on (uint32_t channel)
{
    volatile uint8_t dummy;

#if (ETHER_CHANNEL_MAX == 1)
    (void)channel;
  #if (ETHER_CH0_EN == 1)
    CPG.STBCR6.BIT.MSTP65 = 0;
    CPG.STBCR6.BIT.MSTP62 = 0;
    dummy = CPG.STBCR6.BYTE;
  #else
    CPG.STBCR6.BIT.MSTP64 = 0;
    CPG.STBCR6.BIT.MSTP62 = 0;
    dummy = CPG.STBCR6.BYTE;
  #endif
#else
    /* Check argument */
    if (ETHER_CHANNEL_MAX <= channel) {
        /* Should never get here. Valid channel number is checked above. */
        return ETHER_ERR_INVALID_CHAN;
    }

    if (ETHER_CHANNEL_0 == channel) {
        CPG.STBCR6.BIT.MSTP65 = 0;
        CPG.STBCR6.BIT.MSTP62 = 0;
        dummy = CPG.STBCR6.BYTE;
    } else {
        CPG.STBCR6.BIT.MSTP64 = 0;
        CPG.STBCR6.BIT.MSTP62 = 0;
        dummy = CPG.STBCR6.BYTE;
    }
#endif
    (void)dummy;

    return ETHER_SUCCESS;
} /* End of function power_on() */

/***********************************************************************************************************************
 * Function Name: power_off
 * Description  : Turns off power to a ETHER channel.
 * Arguments    : channel -
 *                    ETHERC channel number
 * Return Value : none
 ***********************************************************************************************************************/
static void power_off (uint32_t channel)
{
    volatile uint8_t dummy;

#if (ETHER_CHANNEL_MAX == 1)
    (void)channel;
  #if (ETHER_CH0_EN == 1)
    CPG.STBCR6.BIT.MSTP65 = 1;
    dummy = CPG.STBCR6.BYTE;
    CPG.STBCR6.BIT.MSTP62 = 1;
    dummy = CPG.STBCR6.BYTE;
  #else
    CPG.STBCR6.BIT.MSTP64 = 1;
    dummy = CPG.STBCR6.BYTE;
    CPG.STBCR6.BIT.MSTP62 = 1;
    dummy = CPG.STBCR6.BYTE;
  #endif
#else
    /* Check argument */
    if (ETHER_CHANNEL_MAX <= channel) {
        /* Should never get here. Valid channel number is checked above. */
        return;
    }

    if (ETHER_CHANNEL_0 == channel) {
        CPG.STBCR6.BIT.MSTP65 = 1;
        dummy = CPG.STBCR6.BYTE;
        if (CPG.STBCR6.BIT.MSTP64 == 1) {
            CPG.STBCR6.BIT.MSTP62 = 1;
            dummy = CPG.STBCR6.BYTE;
        }
    } else {
        CPG.STBCR6.BIT.MSTP64 = 1;
        dummy = CPG.STBCR6.BYTE;
        if (CPG.STBCR6.BIT.MSTP65 == 1) {
            CPG.STBCR6.BIT.MSTP62 = 1;
            dummy = CPG.STBCR6.BYTE;
        }
    }
#endif
    (void)dummy;
} /* End of function power_off() */

/***********************************************************************************************************************
 * Function Name: ether_set_multicastframe_filter
 * Description  : set multicast frame filtering function.
 * Arguments    : control -
 *                    Ethernet channel number and Multicast Frame filter enable switch
 * Return Value : ETHER_SUCCESS -
 *                    Processing completed successfully
 *                ETHER_ERR_INVALID_ARG -
 *                    Invalid argument
 *                ETHER_ERR_RECV_ENABLE -
 *                    Receive function is enable.
 ***********************************************************************************************************************/
static ether_return_t ether_set_multicastframe_filter (ether_param_t const control)
{
    ether_multicast_t * p_arg;
    ether_mc_filter_t flag;
    ether_return_t ret;

    volatile struct st_etherc * petherc_adr;
    uint32_t channel_index = get_control_tbl_index((uint32_t)control.channel);

    ret = ETHER_ERR_INVALID_ARG;
    p_arg = control.p_ether_multicast;
    flag = p_arg->flag;

    if ((ETHER_MC_FILTER_ON != flag) && (ETHER_MC_FILTER_OFF != flag)) {
        return ret;
    }

    petherc_adr = g_eth_control_ch[channel_index].petherc;

    /* Check receive function is enable in ETHERC */
    if (0 == petherc_adr->ECMR.BIT.RE) {
        if (ETHER_MC_FILTER_ON == flag) {
            mc_filter_flag[channel_index] = ETHER_MC_FILTER_ON;
        } else {
            mc_filter_flag[channel_index] = ETHER_MC_FILTER_OFF;
        }

        ret = ETHER_SUCCESS;
    } else {
        ret = ETHER_ERR_RECV_ENABLE;
    }

    return ret;
} /* End of function ether_set_multicastframe_filter() */

/***********************************************************************************************************************
 * Function Name: ether_set_broadcastframe_filter
 * Description  : set broadcast frame filtering function.
 * Arguments    : control -
 *                    ETHERC channel number and receive count for continuous Broadcast Frame
 * Return Value : ETHER_SUCCESS -
 *                    Processing completed successfully
 *                ETHER_ERR_INVALID_ARG -
 *                    Invalid argument
 *                ETHER_ERR_RECV_ENABLE -
 *                    Receive function is enable.
 ***********************************************************************************************************************/
static ether_return_t ether_set_broadcastframe_filter (ether_param_t const control)
{
    ether_broadcast_t * p_arg;
    uint32_t channel_index = get_control_tbl_index((uint32_t)control.channel);
    uint32_t counter;
    ether_return_t ret;

    volatile struct st_etherc * petherc_adr;

    ret = ETHER_ERR_INVALID_ARG;
    p_arg = control.p_ether_broadcast;
    counter = p_arg->counter;

    if (0 != (counter & 0x0FFFF0000)) {
        return ret;
    }

    petherc_adr = g_eth_control_ch[channel_index].petherc;

    /* Check receive function is enable in ETHERC */
    if (0 == petherc_adr->ECMR.BIT.RE) {
        bc_filter_count[channel_index] = counter;
        ret = ETHER_SUCCESS;
    } else {
        ret = ETHER_ERR_RECV_ENABLE;
    }

    return ret;
} /* End of function ether_set_broadcastframe_filter() */

/***********************************************************************************************************************
 * Function Name: power_on_control
 * Description  : Powers on the channel if the ETHEC channel used and the PHY access channel are different, or if the
 *                PHY access channel is powered off.
 * Arguments    : channel -
 *                    ETHERC channel number
 * Return Value : ETHER_SUCCESS -
 *                    Processing completed successfully
 *                ETHER_ERR_INVALID_CHAN -
 *                    Nonexistent channel number
 *                ETHER_ERR_CHAN_OPEN -
 *                    Indicates the Ethernet cannot be opened because it is being used by another application
 *              : ETHER_ERR_OTHER -
 *
 ***********************************************************************************************************************/
static ether_return_t power_on_control (uint32_t channel)
{
    uint32_t channel_index = get_control_tbl_index(channel);
    ether_return_t ret = ETHER_ERR_OTHER;

    etherc_edmac_power_cont[channel_index] = ETHER_MODULE_USE;
    ret = power_on(channel);

    return ret;
} /* End of function power_on_control() */

/***********************************************************************************************************************
 * Function Name: power_off_control
 * Description  : Powers off the channel if the ETHEC channel used and the PHY access channel are different, or if the
 *                PHY access channel is powered off.
 * Arguments    : channel -
 *                    ETHERC channel number
 * Return Value : none
 ***********************************************************************************************************************/
static void power_off_control (uint32_t channel)
{
    uint32_t channel_index = get_control_tbl_index(channel);

    etherc_edmac_power_cont[channel_index] = ETEHR_MODULE_NOT_USE;
    power_off(channel);
} /* End of function power_off_control() */

/***********************************************************************************************************************
 * Function Name: check_mpde_bit
 * Description  :
 * Arguments    : none
 * Return Value : 1: Magic Packet detection is enabled.
 *                0: Magic Packet detection is disabled.
 ***********************************************************************************************************************/
static uint8_t check_mpde_bit (void)
{
#if (ETHER_CHANNEL_MAX == 1)
    /* The MPDE bit can be referred to only when ETHERC operates. */
    if ( (ETHER_MODULE_USE == etherc_edmac_power_cont[0])
  #if (ETHER_CH0_EN == 1)
            && (1 == ETHERC0.ECMR.BIT.MPDE)
  #else
            && (1 == ETHERC1.ECMR.BIT.MPDE)
  #endif
    ) {
        return 1;
    } else {
        return 0;
    }

#else
    /* The MPDE bit can be referred to only when ETHERC0 operates. */
    if ( ( (ETHER_MODULE_USE == etherc_edmac_power_cont[ETHER_CHANNEL_0])
                    && (1 == ETHERC0.ECMR.BIT.MPDE)
            )

            /* The MPDE bit can be referred to only when ETHERC1 operates. */
            || ( (ETHER_MODULE_USE == etherc_edmac_power_cont[ETHER_CHANNEL_1])
                    && (1 == ETHERC1.ECMR.BIT.MPDE)
            )
    ) {
        return 1;
    } else {
        return 0;
    }
#endif
} /* End of function check_mpde_bit() */

#if (ETHER_CH0_EN == 1)
/***********************************************************************************************************************
 * Function Name: ether_eint0
 * Description  : EINT0 interrupt processing (A callback function to be called from r_bsp.)
 * Arguments    : pparam -
 *                    unused
 * Return Value : none
 ***********************************************************************************************************************/
static void ether_eint0 (void)
{
    ether_int_common(ETHER_CHANNEL_0);
} /* End of function ether_eint0() */
#endif

#if (ETHER_CH1_EN == 1)
/***********************************************************************************************************************
 * Function Name: ether_eint1
 * Description  : EINT1 interrupt processing (A callback function to be called from r_bsp.)
 * Arguments    : pparam -
 *                    unused
 * Return Value : none
 ***********************************************************************************************************************/
static void ether_eint1(void)
{
    ether_int_common(ETHER_CHANNEL_1);
} /* End of function ether_eint1() */
#endif

/***********************************************************************************************************************
 * Function Name: ether_int_common
 * Description  : Interrupt handler for Ethernet receive and transmit interrupts.
 * Arguments    : channel -
 *                    ETHERC channel number
 * Return Value : none
 ***********************************************************************************************************************/
static void ether_int_common (uint32_t channel)
{
    uint32_t status_ecsr;
    uint32_t status_eesr;
    volatile struct st_etherc * petherc_adr;
    volatile struct st_edmac * pedmac_adr;
    ether_cb_arg_t cb_arg;
    uint32_t channel_index = get_control_tbl_index(channel);

    petherc_adr = g_eth_control_ch[channel_index].petherc;
    pedmac_adr = g_eth_control_ch[channel_index].pedmac;

    status_ecsr = petherc_adr->ECSR.LONG;
    status_eesr = pedmac_adr->EESR.LONG;

    /* Callback : Interrupt handler */
    if (NULL != cb_func.pcb_int_hnd) {
        cb_arg.channel = channel;
        cb_arg.status_ecsr = status_ecsr;
        cb_arg.status_eesr = status_eesr;
        (*cb_func.pcb_int_hnd)((void *) &cb_arg);
    }

    /* When the ETHERC status interrupt is generated */
    if (status_eesr & EMAC_ECI_INT) {
#if (ETHER_CFG_USE_LINKSTA == 1)
        /* When the link signal change interrupt is generated */
        if (EMAC_LCHNG_INT == (status_ecsr & EMAC_LCHNG_INT)) {
            /* The state of the link signal is confirmed and Link Up/Down is judged. */
            /* When becoming Link up */
            if (ETHER_CFG_LINK_PRESENT == petherc_adr->PSR.BIT.LMON) {
                lchng_flag[channel_index] = ETHER_FLAG_ON_LINK_ON;
            }

            /* When Link becomes down */
            else {
                lchng_flag[channel_index] = ETHER_FLAG_ON_LINK_OFF;
            }
        }
#endif

        /* When the Magic Packet detection interrupt is generated */
        if (EMAC_MPD_INT == (status_ecsr & EMAC_MPD_INT)) {
            mpd_flag[channel_index] = ETHER_FLAG_ON;
        }

        /*
         * Because each bit of the ECSR register is cleared when one is written,
         * the value read from the register is written and the bit is cleared.
         */
        /* Clear all ETHERC status BFR, PSRTO, LCHNG, MPD, ICD */
        petherc_adr->ECSR.LONG = status_ecsr;
    }

    /*
     * Because each bit of the EESR register is cleared when one is written,
     * the value read from the register is written and the bit is cleared.
     */
    pedmac_adr->EESR.LONG = status_eesr; /* Clear EDMAC status bits */

    /* Whether it is a necessary code is confirmed. */

} /* End of function ether_int_common() */

/***********************************************************************************************************************
 * Function Name: get_control_tbl_index
 * Description  : get index of control table.
 * Arguments    : channel -
 *                    ETHERC channel number
 * Return Value : Index of control table
 ***********************************************************************************************************************/
static uint32_t get_control_tbl_index (uint32_t channel)
{
#if (ETHER_CHANNEL_MAX == 1)
    return 0;
#else
    return channel;
#endif
} /* End of function get_control_tbl_index() */