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 47.1.
3. Pins: Select Ethernet pins and their modes in PINSEL2/3 and PINMODE2/3
(Section 95).
4. Wakeup: Use the INTWAKE register (Table 445) to enable activity on
the Ethernet port to wake up the microcontroller from Power-down mode.
5. Interrupts: Interrupts are (now disabled (Table 771).
6. Initialization: see Section 1117.2.
*/
#if LWIP_TCP
void
tcp_tmr_callback( UINT8 *context )
{
tcp_tmr();
timer_add_callout_queue( (void *)ð_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 *)ð_link_mode, /* ~250msec timeout */
TCP_REFRESH_PERIOD_TICKS, tcp_tmr_callback, (void *)ð_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], ¶m[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