Hi Noam ,
You are right, LwIP doesn't interface to RMII (direct).
I does however in most cases, through driver. 

RMII is still a "too many wires" port, and therefore folks often
talk about options to reduce this set. 
I'm happy that my 2cents resulted in a friutful discission
(and even we now know the way to use SPI for that).

On my side, I happened to write a NC-SI LwIP driver (NXP LPC1768 platform) 
which requires no MDIO for PHY configuration, and therefore is 2 wires
less wide than RMII is.
While not many chips support NC-SI, maybe this my $1 addition will
be helpful to somebody (attached is a NC-SI driver for LwIP source).

Sorry, I'm not that fluent with LwIP internals to store the code to the sorces,
therefore I'm attaching it here. Feel free to do whatever you like with it, 
or to ask questions.

rgds,
SergeV

> Noam,
>
> I'll have to add some more here:
>
> Noam Weissman wrote:
>>  [..]
>>  The ETH PHY is connected from one side to the magnetics and from the other 
>> side it has a MAC interface.
>>  [..]
>>  LwIP or any other TCP stack need to read/or data to/from the MAC interface. 
>> This is the hardware driver that connects
>>  the LwIP with the hardware.
>
> These words might imply lwIP connects to RMII, but it doesn't. The
> interface between lwIP and the MAC can be a parallel bus (e.g. MAC
> included in the micro or external MAC connected to a memory-mapped bus),
> or a serial interface (e.g. SPI) or anything else.
> The MAC then converts to (R/G/whatever)-MII, followed by the PHY
> converting to the media.
>
> I wrote this only to make it clear that lwIP does not in any way
> interface MII.
>
> Simon
>
> _______________________________________________
> lwip-users mailing list
> [email protected]
> https://lists.nongnu.org/mailman/listinfo/lwip-users
/*
 * Sergei Vlasov.
 * Last edited on:  Mar 11, 2016                        Document revision:   33
 * [email protected]
 */

#include <common.h>
#include "eth.h"
#include "netif/etharp.h"

/* Global static variables */
UINT8 eth_link_speed;
UINT8 eth_link_mode;
UINT8 eth_link_on = 0;

UINT8 ncsi_channel_selected = 0;            // package/channel we use. Terminal settable
UINT8 NCSI_Package[NCSI_MAX_PACKAGE_ID+1];  // up to 8 NCSI-connected packages supported
UINT8 NCSI_Channel[NCSI_MAX_CHANNEL_ID];    // up to 31 NCSI channels per package

UINT16 *rptr;   // DMA
UINT8  *tptr;   // DMA

/* Local function prototypes                                                  */
void  eth_enable( void );

/* FUNCTIONS CALLED BY LWIP/ETHERNETIF(ipmnetif)                              */
/* -----------------------------------------------------------------------------

    eth_enable(void)   /   eth_init( void )

The Ethernet controller is configured using the following registers:

1. Power: In the PCONP register set bit PCENET.
   Remark: On reset, the Ethernet block is disabled (PCENET = 0).

2. Clock: see LPC23xx uman Section 4–7.1.

3. Pins: Select Ethernet pins and their modes in PINSEL2/3 and PINMODE2/3
   (Section 9–5).

4. Wakeup: Use the INTWAKE register (Table 4–45) to enable activity on
   the Ethernet port to wake up the microcontroller from Power-down mode.

5. Interrupts: Interrupts are (now disabled (Table 7–71).

6. Initialization: see Section 11–17.2.
*/

#if LWIP_TCP
void
tcp_tmr_callback( UINT8 *context )
{
    tcp_tmr();

    timer_add_callout_queue( (void *)&eth_link_mode,    /*/ ~250msec timeout  */
        TCP_REFRESH_PERIOD_TICKS, tcp_tmr_callback, 0 );
} /*/ tcp_tmr_callback                                                        */
#endif

#if LWIP_ARP
void
arp_tmr_callback( UINT8 *context )
{
    etharp_tmr();
    timer_add_callout_queue( (void *)&arp_table,        /*/ ~5sec timeout     */
        ARP_REFRESH_PERIOD_TICKS, arp_tmr_callback, 0 );
} /*/ arp_tmr_callback                                                        */
#endif


/* eth_init helper */
void
eth_enable( void )
{
    int i;
    /* Clock enable & Power up the ethernet controller */
    PCONP |= PCENET;
    DelayMs(1);

    EthPowerDown = 0;
    DelayMs(1);

    /* Enable ethernet pins             */
    PINSEL2 |= ( PS2_P1_0_ENET_TXD0   | PS2_P1_1_ENET_TXD1 |
                 PS2_P1_4_ENET_TX_EN  | PS2_P1_8_ENET_CRS |
                 PS2_P1_9_ENET_RXD0   | PS2_P1_10_ENET_RXD1 |
                 PS2_P1_14_ENET_RX_ER | PS2_P1_15_ENET_REF_CLK );

    for(i = 0; i <= NCSI_MAX_PACKAGE_ID; i++) 
                                        NCSI_Package[i] = 0xFF; // invalidate
    for(i = 0; i < NCSI_MAX_CHANNEL_ID; i++) // skip the broadcast ch=0x1F
                                        NCSI_Channel[i] = 0xFF; // invalidate
} // eth_enable


/* Initialize Ethernet MAC & Phy                                                */
/* Return value: true = init successful                                         */
/*               false = init failed: please retry or abort/cancel              */
BOOL
eth_init( void )
{
    int i;
    eth_enable();                       // power on.

    /* reset MAC */
    MAC_MAC1 = MAC1_RES_TX | MAC1_RES_MCS_TX | MAC1_RES_RX | MAC1_RES_MCS_RX |
        MAC1_SIM_RES | MAC1_SOFT_RES;
    EthCommand = CR_REG_RES | CR_TX_RES | CR_RX_RES;

    /* init MAC control regs */
    MAC_MAC1 = MAC1_PASS_ALL;
    MAC_MAXF = ETH_MAX_FLEN;            // 0x600 = 1536.

    /* enable RMII */
    EthCommand = CR_RMII | CR_PASS_RUNT_FRM;

    // note: we do not use MDIO
    MAC_MCFG = 0x8018;                  // clk/20 + reset MII mgmt

  // descriptors init. See KS8721 datasheet 18.18 "Reset"
    MAC_MAC1 |= MAC1_RES_MCS_TX;        /* Reset the MAC Control Sublayer Tx  */
    MAC_MAC1 |= MAC1_RES_TX;            /* Put the Tx Function logic in reset */
    EthCommand |= CR_TX_RES;            /* Reset Transmit Datapath */
    MAC_MAC1 &= ~MAC1_RES_MCS_TX;       /* Off the Reset MAC TX Ctl Sub logic */
    MAC_MAC1 &= ~MAC1_RES_TX;           /* Transmit Function logic Reset off  */
    MAC_MAC1 &= ~MAC1_RECV_EN;
    MAC_MAC1 |= MAC1_RES_MCS_RX;
    EthCommand &= ~CR_RX_EN;
    MAC_MAC1 |= MAC1_RES_RX;
    EthCommand |= CR_RX_RES;
    MAC_MAC1 &= ~MAC1_RES_MCS_RX;
    MAC_MAC1 &= ~MAC1_RES_RX;
    EthCommand |= CR_PASS_RUNT_FRM;
    EthCommand |= CR_PASS_RX_FILT;
    MAC_MAC1 |= MAC1_PASS_ALL;                      /* pass all receive frames*/
    MAC_MAC2 = MAC2_CRC_EN | MAC2_PAD_EN;
    MAC_CLRT    = CLRT_DEF;
    MAC_IPGR = IPGR_DEF;            // IPGR2 = 0x12;
    MAC_IPGR |= 0x0C00;             // IPGR1 = 0x0c;
    MAC_IPGT = IPGT_FULL_DUP;       // init default
    MAC_MAC2 |= MAC2_FULL_DUP;
    EthCommand |= CR_FULL_DUP;
    MAC_SUPP |= SUPP_SPEED;         /* 100Mbps */

    eth_link_on = 1; // NC-SI version of Init.

    /* set the Ethernet MAC Address registers */
    MAC_SA0 = ( (UINT16)IPMInetIF.hwaddr[0] << 8) | (UINT16)IPMInetIF.hwaddr[1];
    MAC_SA1 = ( (UINT16)IPMInetIF.hwaddr[2] << 8) | (UINT16)IPMInetIF.hwaddr[3];
    MAC_SA2 = ( (UINT16)IPMInetIF.hwaddr[4] << 8) | (UINT16)IPMInetIF.hwaddr[5];

    /* init Rx DMA Descriptors */
    for (i = 0; i < NUM_RX_FRAG; i++) {
        RX_DESC_PACKET(i) = RX_BUF(i);
        RX_DESC_CTRL(i)   = RCTRL_INT | (ETH_FRAG_SIZE-1);
        RX_STAT_INFO(i)   = 0;
        RX_STAT_HASHCRC(i)= 0;
    }

    /* set MAC Rx Descriptor Registers */
    EthRxDescriptor       = RX_DESC_BASE;    // 0x7FE00000
    EthRxStatus           = RX_STAT_BASE;
    EthRxDescriptorNumber = NUM_RX_FRAG-1;
    /* Rx Descriptors Point to 0 */
    EthRxConsumeIndex     = 0;

    /* init Tx DMA Descriptors */
    for (i = 0; i < NUM_TX_FRAG; i++) {
        TX_DESC_PACKET(i) = TX_BUF(i);
        TX_DESC_CTRL(i)   = (ETH_FRAG_SIZE-1)  | TCTRL_LAST | TCTRL_INT |
                                        TCTRL_CRC | TCTRL_PAD | TCTRL_OVERRIDE;
        TX_STAT_INFO(i)   = 0;
    }

    /* set MAC Tx Descriptor Registers */
    EthTxDescriptor       = TX_DESC_BASE;
    EthTxStatus           = TX_STAT_BASE;
    EthTxDescriptorNumber = NUM_TX_FRAG-1;
    /* Tx Descriptors Point to 0 */
    EthTxProduceIndex     = 0;

    /* receive Broadcast and Perfect Match Packets */
    EthRxFliterCtrl     = 0;

    /* enable MAC interrupts */
    EthIntEnable       = 0;

    /* reset all interrupts */
    EthIntClear   = 0xFFFF;                                             // nn

    /* enable receive and transmit mode of MAC Ethernet core */
    EthCommand  |= (CR_RX_EN | CR_TX_EN);
    MAC_MAC1    |= MAC1_RECV_EN;                        /* Receive enable */

#if LWIP_TCP
    timer_add_callout_queue( (void *)&eth_link_mode,     /* ~250msec timeout */
        TCP_REFRESH_PERIOD_TICKS, tcp_tmr_callback, (void *)&eth_link_mode );
#endif

#if LWIP_ARP
    timer_add_callout_queue( (void *)&arp_table,        /* ~5s timeout */
        ARP_REFRESH_PERIOD_TICKS, arp_tmr_callback, (void *)&arp_table );
#endif
    
    return true;
} // eth_init


UINT8
eth_get_link_speed( void )
{
    return eth_link_speed;
} // eth_get_link_speed

UINT8
eth_get_link_mode( void )
{
    return eth_link_mode;
} // eth_get_link_mode
    
void
eth_init_tbuf( void )
{
    tptr = ( UINT8 * )
        ( *( UINT32 * )( TX_DESC_BASE + 8 * EthTxProduceIndex ) );
} // eth_init_tbuf

void
eth_write_tbuf( void *src, UINT32 len )
{
    int i;
    UINT8* s = (UINT8*)src;
    for( i = 0; i < len; i++ ) {
        *tptr++ = *s++;     // *tbuf++ = *s++;
    }
} // eth_write_tbuf

void
eth_send_tbuf( UINT16 len )
{
    UINT32 idx;

    idx = EthTxProduceIndex;
    TX_DESC_CTRL( idx ) = (len-1) | TCTRL_LAST | TCTRL_CRC | TCTRL_OVERRIDE;

    if( ++idx >= NUM_TX_FRAG ) idx = 0;
    EthTxProduceIndex = idx;
} // eth_send_tbuf

int
eth_check_rcv( void )
{
    UINT32 a = EthRxProduceIndex;
    UINT32 b = EthRxConsumeIndex;
    if( a != b ) return( 1 );
    else         return( 0 );
} // eth_check_rcv

UINT16
eth_get_rcv_size( void )
{
  UINT16 len;
  UINT32 idx;

  idx = EthRxConsumeIndex;
  len = ( RX_STAT_INFO( idx ) & RINFO_SIZE ) - 3;
  rptr = ( UINT16 * )RX_DESC_PACKET( idx );
  return( len );
} // eth_get_rcv_size

void
eth_read_rbuf( void *dest, UINT16 len )
{
    UINT16 * pdest;
    pdest = dest;

    while( len > 1 ) {
        *pdest++ = *rptr++;
        len -= 2;
    }

    if( len ) // leftover byte
        *( UINT8 * )pdest = ( UINT8 )*rptr++;

} // eth_read_rbuf

/* --------------------------------------------------------------------------

   -------------------------------------------------------------------------- */
void
eth_rcv_done( void )
{
    UINT32 idx;

    /* DMA free packet. */
    idx = EthRxConsumeIndex;

    if( ++idx == NUM_RX_FRAG )
    idx = 0;

    EthRxConsumeIndex = idx;
} // eth_rcv_done

/* ---------------------------------------------------------------------------- */
#ifdef LAN_USE_NCSI

UINT8
ncsi_data_input(struct netif *netif, struct pbuf *p)
{   
    static UINT8 seq;
    UINT8 stat;
    NCSI_RESP* resp;
    DPRINTF( DBG_OTHER_MEDIA | DBG_LVL1, "ncsi_data_input: reply packet received.\n" );
    
// process NC-SI response
    resp = (NCSI_RESP*)p->payload;
    stat = resp->status;   // default status
    if(resp->iid == seq){
        DPUTHEX( DBG_WARN | DBG_OTHER_MEDIA, "ncsi retry of 0x", 
                                                      resp->packet_type, ".\n" );
    } else switch(resp->packet_type){
    case NCSI_ENABLE_BROADCAST_FILTER  +NCSI_RESP_FL:   
        DPRINTF( DBG_OTHER_MEDIA, "ncsi Broadcast filter set.\n");
    break;    // generic response. done.
    
    case NCSI_SET_MAC_ADDRESS       +NCSI_RESP_FL:   
        DPRINTF( DBG_OTHER_MEDIA, "ncsi MAC address set.\n");
    break;    // generic response. done.
    
    case NCSI_CLEAR_INITIAL_STATE   +NCSI_RESP_FL:
        if( NCSI_STATUS_COMPLETED == be16(resp->status) ){
            NCSI_Channel[ resp->channel_id & 0x1F ]  = resp->channel_id;
        }else{
            DPUTHEX( DBG_OTHER_MEDIA, "ncsi cls: failed reset channel 0x", 
                                                       resp->channel_id, ".\n" );
        }
    break;   
    
    case NCSI_SELECT_PACKAGE        +NCSI_RESP_FL:
        NCSI_Package[ resp->channel_id >> 5 ] = resp->channel_id >> 5;
        DPUTHEX( DBG_OTHER_MEDIA, "ncsi package/channel 0x", 
                                              resp->channel_id, " selected. " );
        DPUTHEX32( DBG_OTHER_MEDIA,  "  resp. code=0x",  be16(resp->status),   "\n" );
    break;  //  NCSI_SELECT_PACKAGE
    
    case NCSI_DESELECT_PACKAGE      +NCSI_RESP_FL:
        DPUTHEX( DBG_OTHER_MEDIA, "ncsi package/channel 0x", 
                                             resp->channel_id, " deselected." );
        DPUTHEX32( DBG_OTHER_MEDIA,  " resp. code=0x",  be16(resp->status),    "\n" );
    break;  //  NCSI_DESELECT_PACKAGE
    
    case NCSI_ENABLE_CHANNEL        +NCSI_RESP_FL:
        if( NCSI_STATUS_COMPLETED == be16(resp->status) ){
            DPUTHEX( DBG_OTHER_MEDIA, "ncsi channel 0x", 
                                              resp->channel_id, " enabled.\n" );
        }else{
            DPUTHEX32( DBG_OTHER_MEDIA, "ncsi Enable Channel returned status: 0x", 
                                                     be16(resp->status), ".\n" );
        }
    break;    
    
    case NCSI_DISABLE_CHANNEL_TX     +NCSI_RESP_FL:
    break;
    
    case NCSI_ENABLE_CHANNEL_TX     +NCSI_RESP_FL:
        if( NCSI_STATUS_COMPLETED == be16(resp->status) ){
            DPUTHEX( DBG_OTHER_MEDIA, "ncsi channel 0x", 
                                              resp->channel_id, " TX enabled.\n" );
        }else{
            DPUTHEX32( DBG_OTHER_MEDIA, "ncsi Enable Channel returned status: 0x", 
                                                     be16(resp->status), ".\n" );
        }
    break;    
    
    case NCSI_GET_VERSION_ID        +NCSI_RESP_FL:
        if(resp->status == NCSI_STATUS_COMPLETED){
            NCSI_GET_VERSION_ID_RESP* vidp = 
                                        (NCSI_GET_VERSION_ID_RESP*)&resp->status;
            // we just print this until any better use found.
            DPUTHEX32( DBG_OTHER_MEDIA, "ncsi version:", 
                                                  be32(vidp->ncsi_version), "" );
            DPUTHEX32( DBG_OTHER_MEDIA, " FW version:", 
                                              be32(vidp->firmware_version), "" );
            DPUTHEX32( DBG_OTHER_MEDIA, " IANA:",  be32(vidp->mfg_id),    "\n" );
        }
    break; // NCSI_GET_VERSION_ID
    
    case NCSI_GET_CAPABILITIES      +NCSI_RESP_FL:
        if( NCSI_STATUS_COMPLETED == be16(resp->status) ){
            NCSI_GET_CAPABILITIES_RESP* gcp = 
                                      (NCSI_GET_CAPABILITIES_RESP*)&resp->status;
            DPUTHEX32( DBG_OTHER_MEDIA, "ncsi caps: flags=0x", 
                                           be32(gcp->caps_flags),     "");
            DPUTHEX( DBG_OTHER_MEDIA,   " BC filter=0x", 
                                           be32(gcp->broadcast_filter_caps), "");
            DPUTHEX32( DBG_OTHER_MEDIA, " buffering=0x", 
                                           be32(gcp->buffering_caps), "");
            DPUTHEX( DBG_OTHER_MEDIA,   " chans=",  gcp->channel_count,    "\n");
        }
    break; // NCSI_GET_CAPABILITIES
    
    case NCSI_GET_PARAMETERS        +NCSI_RESP_FL:
        if(resp->status == NCSI_STATUS_COMPLETED){
            NCSI_GET_PARAMETERS_RESP* gp = 
                                        (NCSI_GET_PARAMETERS_RESP*)&resp->status;
            DPUTHEX( DBG_OTHER_MEDIA, "ncsi params: MAC count=", gp->mac_address_count, "");
            DPUTHEX( DBG_OTHER_MEDIA, " flags=", gp->mac_address_flags, "");
            DPUTHEX( DBG_OTHER_MEDIA, " BC filter=", be32(gp->broadcast_packet_filter_settings), "");
            DPUTHEX( DBG_OTHER_MEDIA, " cfg flags=", be32(gp->configuration_flags), "\n");
            DPUTHEX( DBG_OTHER_MEDIA, "MAC=", gp->mac_address_1[0], "");
            DPUTHEX( DBG_OTHER_MEDIA, ":",    gp->mac_address_1[1], "");
            DPUTHEX( DBG_OTHER_MEDIA, ":",    gp->mac_address_1[2], "");
            DPUTHEX( DBG_OTHER_MEDIA, ":",    gp->mac_address_1[3], "");
            DPUTHEX( DBG_OTHER_MEDIA, ":",    gp->mac_address_1[4], "");
            DPUTHEX( DBG_OTHER_MEDIA, ":",    gp->mac_address_1[5], ""); // "\n");
            // status print out always follows this
        }
    break; // NCSI_GET_PARAMETERS

    case NCSI_GET_LINK_STATUS       +NCSI_RESP_FL:
        if(resp->status == NCSI_STATUS_COMPLETED){
            NCSI_GET_LINK_STATUS_RESP* lsp = 
                                       (NCSI_GET_LINK_STATUS_RESP*)&resp->status;
            // we just print this until more use found.
            DPUTHEX32( DBG_OTHER_MEDIA," link stat: ", lsp->link_status, ".\n" );
        }
    break; // NCSI_GET_LINK_STATUS
    
    case NCSI_GET_MC_PACKET_STATISTICS+NCSI_RESP_FL:
        if(resp->status == NCSI_STATUS_COMPLETED){
            NCSI_GET_MC_PACKET_STATISTICS_RESP* msp = 
                               (NCSI_GET_MC_PACKET_STATISTICS_RESP*)&resp->status;
            DPUTHEX32( DBG_OTHER_MEDIA,"ncsi mc statistics: bytes Tx=", 
                                                        be32(msp->bytes_tx), "" );
            DPUTHEX32( DBG_OTHER_MEDIA," Rx=", be32(msp->bytes_rx), ".\n" );
            DPUTHEX32( DBG_OTHER_MEDIA,"Packets: uRx=",be32(msp->unicast_packets_rx),"");
            DPUTHEX32( DBG_OTHER_MEDIA," bRx=", be32(msp->broadcast_packets_rx), "" );
            DPUTHEX32( DBG_OTHER_MEDIA," uTx=", be32(msp->unicast_packets_tx),"");
            DPUTHEX32( DBG_OTHER_MEDIA," bTx=", be32(msp->broadcast_packets_tx),".\n");
            // . . . more information available in the reply . . .
        }
    break; // NCSI_GET_MC_PACKET_STATISTICS
    
    case NCSI_GET_NCSI_STATISTICS   +NCSI_RESP_FL:
        if(resp->status == NCSI_STATUS_COMPLETED){
            NCSI_GET_NCSI_STATISTICS_RESP* gns = 
                                   (NCSI_GET_NCSI_STATISTICS_RESP*)&resp->status;
            DPUTHEX( DBG_OTHER_MEDIA, "ncsi statistics: cmd.Rx=", 
                                        (UINT8)be32(gns->commands_received), "");
            DPUTHEX( DBG_OTHER_MEDIA,
                            " dropped=", be32(gns->command_packets_dropped), "");
            DPUTHEX( DBG_OTHER_MEDIA,
                            " errors=",  be32(gns->command_checksum_errors), "");
            DPUTHEX( DBG_OTHER_MEDIA, "+", be32(gns->command_type_errors), "\n");
            // DPUTHEX32( DBG_OTHER_MEDIA," Rx=", be32(gns->rx_packets), "");
            // DPUTHEX32( DBG_OTHER_MEDIA," Tx=", be32(gns->rx_packets), "\n");
        } // else stat = resp->status;
    break;
    case NCSI_GET_NCSI_PT_STATISTICS+NCSI_RESP_FL:
        DPRINTF( DBG_OTHER_MEDIA, "ncsi get PT statistics (nyf)\n");
        stat = CC_NOT_SUPPORTED;
    break;
    default:
    DPUTHEX( DBG_OTHER_MEDIA, "ncsi_data_input: unsupported reply cmd code 0x", 
                                            resp->packet_type, " received.\n" );
        stat = CC_NOT_SUPPORTED;
    break;
    } // case
    seq = resp->iid;    // retry detector
    
    pbuf_free(p);

    return(stat);   /* not finished implementation */
} // ncsi_data_input

UINT8 
ncsi_control(UINT8 ctl_code, UINT8* param)
{
     const UINT8 
     ncsi_request_template[] = {
        //<-----------  DA  ---------->  <--------------  SA  ------------>  <- NCSI->
        0xFF,0xFF, 0xFF,0xFF, 0xFF,0xFF, 0xFF,0xFF,    0xFF,0xFF, 0xFF,0xFF, 0x88,0xF8,             
        //ID rev   x    IID   PTyp ChID  Payld_Length  x    x     x    x     x    x     x    x
        0x00,0x01, 0x00,0x00, 0x00,0x00, 0x00,0x00,    0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
        // Payload       : variable length                               ->  <------  cks  ----->
        0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00,    0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
        0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00,    0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 
        0x00,0x00  /* Ethernet packet pad to 64B total                ----------------------------*/
    };
    
    static UINT8 seq;
    static const UINT32 this_broadcast_filter = 
        // (BF_ARP_PACKETS);
        (BF_ARP_PACKETS | BF_DHCP_CLIENT_PACKETS | BF_DHCP_SERVER_PACKETS);
    
    struct pbuf  *p;
    int i;      // UINT32 i, timer;
    NCSI_REQ* req;
    p = pbuf_alloc(PBUF_RAW, sizeof(ncsi_request_template), PBUF_RAM);

    if ( NULL == p )     {
        DPRINTF( DBG_WARN | DBG_OTHER_MEDIA, "LAN_send udp: couldn't allocate pbuf.\n\r" );
    }else{
        memcpy( (UINT8*)p->payload, ncsi_request_template, sizeof(ncsi_request_template) );
        req = (NCSI_REQ*)p->payload;
        req->packet_type = ctl_code;
        req->payload_len = 0;
        req->iid = ++seq;
        
        // single package ID==0; channel is one-of-many 
        req->channel_id  = (NCSI_Package[0] << 5) | ncsi_channel_selected; 
        
        switch(ctl_code){
            
        case NCSI_SET_MAC_ADDRESS:  // set the NC-SI MAC address #1 (we support just one)
            if(NULL == param){
                pbuf_free(p);
                return (CC_NORMAL); // nothing to set: silently ignore the command
            }
            memcpy(&req->payload[0], &param[0], sizeof(struct eth_addr));
            req->payload[sizeof(struct eth_addr)]   = 1;     /* MAC address #1  */
            req->payload[sizeof(struct eth_addr)+1] = 1;     /* enable this MAC */
            req->payload_len = sizeof(struct eth_addr) +2;   /* 1 byte "length" */
        break; // NCSI_SET_MAC_ADDRESS
        
        case NCSI_SELECT_PACKAGE:   // 
            if(NULL != param){      // select package specified if not null.
                req->channel_id  = *param;                /* PKG ID + Int Ch ID */
            }
            req->payload[0]  = req->payload[1]  = req->payload[2] = 0;
            req->payload[3]  = NCSI_DISABLE_HW_ARBITRATION; 
            req->payload_len = 4;
        break; // NCSI_SELECT_PACKAGE
         
        case NCSI_DESELECT_PACKAGE: 
            if(NULL != param){      // deselect package specified if not null.
                req->channel_id  = *param;                    /* PKG ID + Int Ch ID */
            }
        break; // NCSI_DESELECT_PACKAGE

        case NCSI_CLEAR_INITIAL_STATE:  if(NULL != param){
            req->channel_id  = *param;                /* PKG ID + Int Ch ID */
        }
        break;

        case NCSI_ENABLE_BROADCAST_FILTER:   {
            NCSI_ENABLE_BROADCAST_FILTER_REQ* ebf_req;
            ebf_req = (NCSI_ENABLE_BROADCAST_FILTER_REQ*) &req->payload[0];
            if(NULL != param){
               // req->channel_id  = *param;                /* PKG ID + Int Ch ID */
            }
            ebf_req->broadcast_filter = be32(this_broadcast_filter);

            req->payload_len = sizeof(NCSI_ENABLE_BROADCAST_FILTER_REQ);/* 1B len */
        }
        break; // NCSI_ENABLE_BROADCAST_FILTER

        case NCSI_DISABLE_CHANNEL:      if(NULL != param){
                req->channel_id  = *param;              /* PKG ID + Int Ch ID */
            }
            req->payload[0]  = req->payload[1]  = req->payload[2] = 0;
            req->payload[3]  = NCSI_ALLOW_LINK_DOWN; 
            req->payload_len = 4;
        break;

        case NCSI_ENABLE_CHANNEL:       
        case NCSI_DISABLE_CHANNEL_TX:
        case NCSI_ENABLE_CHANNEL_TX:    if(NULL != param){
            req->channel_id  = *param;                /* PKG ID + Int Ch ID */
        }
        break;
        
        case NCSI_GET_LINK_STATUS:              break;  /* cmd-code-only (generic req) */
        case NCSI_GET_VERSION_ID:               break;  /*  ...    no payload commands */
        case NCSI_GET_CAPABILITIES:             break;  /*  ...                        */
        case NCSI_GET_PARAMETERS:               break;  /*  ...                        */
        case NCSI_GET_MC_PACKET_STATISTICS:     break;  /*  ...                        */
        case NCSI_GET_NCSI_STATISTICS:          break;  /*  ...                        */
        case NCSI_GET_NCSI_PT_STATISTICS:       break;  /* --------------------------- */
        
        default:
            pbuf_free(p);
        return (CC_INVALID_CMD);
        }
        
        for( i = 0; i < NCSI_RETRIES; i++ ){ 
            IPMInetIF.linkoutput(&IPMInetIF, p);
            // timer = lbolt + NCSI_TIME_OUT;
            // while (lbolt < timer){
            DelayMs(2);
            if(true == ipmnetif_input(&IPMInetIF)) break;  // for (stop retries)
        } // for
        pbuf_free(p);
    }
    return(CC_NORMAL);
} // ncsi_control

/* ---------------------------------------------------------------------------- */
// ncsi_reset() :: DTMF 6.2.13.1 - non-hardware arbitration startup sequence.
//      * Discover NC-SI-attached packages and package channels;
//      * Read the NC-SI properties;
//      * Assign MAC address(es).
// Commands used:
// 1. Using the Select Package discover NCSI packages    (cmd = 0x01)
// 2. Using the Clear Initial State discover channels    (cmd = 0x00)
// 3. (option) Get ID and statistics                     (cmd = 0x15..0x1A)
// 4. Set MAC                                            (cmd = 0x0E)
// 5. Set filter(s)                                      (cmd = 0x10)
// 6. Channel (Network pass-through Tx/Rx) Enable        (cmd = 0x03, 0x06)
void
ncsi_reset()
{
    UINT8 i, j, ID;
    for( i = 0; i <= NCSI_MAX_PACKAGE_ID; i++){
        ID = i << 5 | NCSI_CHANNEL_ID_BROADCAST;
        ncsi_control(NCSI_SELECT_PACKAGE,   &ID);
        ncsi_control(NCSI_DESELECT_PACKAGE, &ID);
    }
    for ( i = 0, j = 0; i <= NCSI_MAX_PACKAGE_ID; i++ ){
        if(0xFF != NCSI_Package[i]) j++;
    }
    if( 0 != j ){
        DPUTHEX( DBG_OTHER_MEDIA, "ncsi_reset : ", j, " packages found.\n" );
        eth_link_on = 1;
    } else { 
        DPRINTF( DBG_OTHER_MEDIA, "ncsi_reset : no packages.\n" );
        eth_link_on = 0;
        return;
    }
    // we will use/support single package at this time!
    ID = (NCSI_Package[0] << 5) | NCSI_CHANNEL_ID_BROADCAST;
    ncsi_control(NCSI_SELECT_PACKAGE, &ID);
    ncsi_get_ncsi_statistics(); // reset counters
    
    // Note: ch=NCSI_MAX_CHANNEL_ID is a broadcast ID, we do not include it.
    for ( i = 0, ID = NCSI_Package[0]<<5; i < NCSI_MAX_CHANNEL_ID; i++ ){ 
        ncsi_control(NCSI_CLEAR_INITIAL_STATE, &ID);
        ID += 1; // next channel
    }
    for ( i = 0, j = 0; i < NCSI_MAX_CHANNEL_ID; i++ ){
        if(0xFF != NCSI_Channel[i]) j++;
    }
    DPUTHEX( DBG_OTHER_MEDIA, "ncsi_reset : ", j, " channels found.\n" );
    
    // initialize first channel available, this is a default
    ncsi_control(NCSI_SET_MAC_ADDRESS, &IPMInetIF.hwaddr[0]);
    ncsi_control(NCSI_ENABLE_BROADCAST_FILTER, NULL);
    
    ID = (NCSI_Package[0]<<5) | ncsi_channel_selected;
    ncsi_control(NCSI_ENABLE_CHANNEL, &ID);
    ncsi_control(NCSI_ENABLE_CHANNEL_TX, &ID);
} // ncsi_reset

void
ncsi_get_link_status_parameters()
{
    if( CC_NORMAL != ncsi_control(NCSI_GET_PARAMETERS, NULL)) { // &NCSI_Package[0])){
            DPRINTF( DBG_OTHER_MEDIA, "ncsi: failed to get parameters.\n" );
    }
    if( CC_NORMAL != ncsi_control(NCSI_GET_LINK_STATUS, NULL)) { // &NCSI_Package[0])){
            DPRINTF( DBG_OTHER_MEDIA, "ncsi_reset : failed to get link status.\n" );
    }
} // ncsi_get_link_status_parameters

void
ncsi_get_ncsi_statistics()
{
    if( CC_NORMAL != ncsi_control(NCSI_GET_NCSI_STATISTICS, NULL)) { // &NCSI_Package[0])){
        DPRINTF( DBG_OTHER_MEDIA, "ncsi: failed to get statistics.\n" );
    }
} // ncsi_get_ncsi_statistics

void
ncsi_get_capabilities()
{
    if( CC_NORMAL != ncsi_control(NCSI_GET_CAPABILITIES, NULL)) { // &NCSI_Package[0])){
            DPRINTF( DBG_OTHER_MEDIA, "ncsi: failed to get capabilities.\n" );
    }
} // ncsi_get_capabilities

void
ncsi_get_mc_statistics()
{
    if( CC_NORMAL!=ncsi_control(NCSI_GET_MC_PACKET_STATISTICS, NULL)) { // &NCSI_Package[0])){ 
            DPRINTF( DBG_OTHER_MEDIA,"ncsi: failed to get the MC statistics.\n");
    }
} // ncsi_get_mc_statistics
UINT8
ncsi_remap_channel(UINT8 channel)
{
    if ( ((channel & 0x1F) >= NCSI_MAX_CHANNEL_ID) || 
         ( 0xFF == NCSI_Channel[channel&0x1F] )) return  CC_PARAM_OUT_OF_RANGE;
    
    ncsi_control(NCSI_DISABLE_CHANNEL_TX,NULL); // disable last ("this") channel
    ncsi_control(NCSI_DISABLE_CHANNEL,   NULL); // disable last ("this") channel
    
    ncsi_channel_selected = channel;            // store globally new channel #
    ncsi_control(NCSI_SET_MAC_ADDRESS,          &IPMInetIF.hwaddr[0]);
    ncsi_control(NCSI_ENABLE_BROADCAST_FILTER,  NULL);
    ncsi_control(NCSI_ENABLE_CHANNEL,           NULL);
    ncsi_control(NCSI_ENABLE_CHANNEL_TX,        NULL);
    return (CC_NORMAL);
} // ncsi_remap_channel

#else
#warning To use the NCSI please #define the LAN_USE_NCSI constant (preferrably @project level).
#endif // LAN_USE_NCSI


/* -------------------------------------------------------------------------- *
 *   The End of lwip_ncsi_1768.c file.                                              *
 * -------------------------------------------------------------------------- */

_______________________________________________
lwip-users mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/lwip-users

Reply via email to