if_etherc.c
来自「开放源码实时操作系统源码.」· C语言 代码 · 共 1,128 行 · 第 1/3 页
C
1,128 行
if ((cyg_uint32)p == reg) {
if (_SU32(reg, ETHERC_TD_STAT) & ETHERC_TD_STAT_TACT) {
still_active = true;
break;
}
}
}
}
#else
if (_SU32(reg, ETHERC_TD_STAT) & ETHERC_TD_STAT_TACT)
still_active = true;
#endif
} while (still_active);
db_printf("all done\n");
#endif
cpd->active = 0;
}
static void
etherc_stop(struct eth_drv_sc *sc)
{
struct etherc_priv_data *cpd =
(struct etherc_priv_data *)sc->driver_private;
DEBUG_FUNCTION();
etherc_suspend(cpd);
}
//
// This function is called to "start up" the interface. It may be called
// multiple times, even when the hardware is already running. It will be
// called whenever something "hardware oriented" changes and should leave
// the hardware ready to send/receive packets.
//
static void
etherc_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
{
cyg_uint32 reg, prm_mode = 0;
struct etherc_priv_data *cpd =
(struct etherc_priv_data *)sc->driver_private;
#ifdef CYGPKG_NET
struct ifnet *ifp = &sc->sc_arpcom.ac_if;
#endif
DEBUG_FUNCTION();
// If device is already active, suspend it
if (cpd->active) {
etherc_suspend(cpd);
}
#ifdef CYGPKG_NET
if (( 0
#ifdef ETH_DRV_FLAGS_PROMISC_MODE
!= (flags & ETH_DRV_FLAGS_PROMISC_MODE)
#endif
) || (ifp->if_flags & IFF_PROMISC)
) {
// Then we select promiscuous mode.
prm_mode = CYGARC_REG_ECMR_PRM;
}
#endif
// Unsuspend the device
reg = get_reg(cpd, _REG_ECMR);
reg |= CYGARC_REG_ECMR_TE | CYGARC_REG_ECMR_RE;
reg &= ~CYGARC_REG_ECMR_PRM;
reg |= prm_mode;
put_reg(cpd, _REG_ECMR, reg);
put_reg(cpd, _REG_EDRRR, CYGARC_REG_EDRRR_RR);
cpd->active = 1;
}
//
// This routine is called to perform special "control" opertions
//
static int
etherc_control(struct eth_drv_sc *sc, unsigned long key,
void *data, int data_length)
{
cyg_uint8 *esa = (cyg_uint8 *)data;
int i, res;
cyg_uint16 reg;
struct etherc_priv_data *cpd =
(struct etherc_priv_data *)sc->driver_private;
cyg_bool was_active = cpd->active;
DEBUG_FUNCTION();
// If device is already active, suspend it
if (cpd->active) {
etherc_suspend(cpd);
}
res = 0; // expect success
switch (key) {
case ETH_DRV_SET_MAC_ADDRESS:
#if 9 & DEBUG
db_printf("ETHERC - set ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
esa[0], esa[1], esa[2], esa[3], esa[4], esa[5] );
#endif // DEBUG
for ( i = 0; i < sizeof(cpd->esa); i++ )
cpd->esa[i] = esa[i];
put_reg(cpd, _REG_MAHR,(cpd->esa[0] << 24) | (cpd->esa[1] << 16) | (cpd->esa[2] << 8) | cpd->esa[3]);
put_reg(cpd, _REG_MALR, (cpd->esa[4] << 8) | cpd->esa[5]);
break;
#ifdef ETH_DRV_GET_MAC_ADDRESS
case ETH_DRV_GET_MAC_ADDRESS:
// Extract the MAC address that is in the chip, and tell the
// system about it.
cyg_uint32 reg;
reg = get_reg(cpd, _REG_MAHR);
cpd->esa[0] = (reg >> 24) & 0xff;
cpd->esa[1] = (reg >> 16) & 0xff;
cpd->esa[2] = (reg >> 08) & 0xff;
cpd->esa[3] = (reg >> 00) & 0xff;
reg = get_reg(cpd, _REG_MALR);
cpd->esa[4] = (reg >> 08) & 0xff;
cpd->esa[5] = (reg >> 00) & 0xff;
break;
#endif
#ifdef ETH_DRV_GET_IF_STATS_UD
case ETH_DRV_GET_IF_STATS_UD: // UD == UPDATE
#endif
// drop through
#ifdef ETH_DRV_GET_IF_STATS
case ETH_DRV_GET_IF_STATS:
#endif
#if defined(ETH_DRV_GET_IF_STATS) || defined (ETH_DRV_GET_IF_STATS_UD)
{
struct ether_drv_stats *p = (struct ether_drv_stats *)data;
// Chipset entry is no longer supported; RFC1573.
for ( i = 0; i < SNMP_CHIPSET_LEN; i++ )
p->snmp_chipset[i] = 0;
// This perhaps should be a config opt, so you can make up your own
// description, or supply it from the instantiation.
strcpy( p->description, "SH Etherc" );
// CYG_ASSERT( 48 > strlen(p->description), "Description too long" );
if (_MII_LINK_STATE(cpd, 1)) {
// Link is up
p->operational = 3; // LINK UP
if (_MII_DUPLEX_STATE(cpd, 1))
p->duplex = 3; // 3 = DUPLEX
else
p->duplex = 2; // 2 = SIMPLEX
if (_MII_SPEED_STATE(cpd, 1))
p->speed = 100 * 1000000;
else
p->speed = 10 * 1000000;
} else {
// Link is down
p->operational = 2; // LINK DOWN
p->duplex = 1; // UNKNOWN
p->speed = 0;
}
#if FIXME
#ifdef KEEP_STATISTICS
{
struct sh_etherc_stats *ps = &(cpd->stats);
// Admit to it...
p->supports_dot3 = true;
p->tx_good = ps->tx_good ;
p->tx_max_collisions = ps->tx_max_collisions ;
p->tx_late_collisions = ps->tx_late_collisions ;
p->tx_underrun = ps->tx_underrun ;
p->tx_carrier_loss = ps->tx_carrier_loss ;
p->tx_deferred = ps->tx_deferred ;
p->tx_sqetesterrors = ps->tx_sqetesterrors ;
p->tx_single_collisions = ps->tx_single_collisions;
p->tx_mult_collisions = ps->tx_mult_collisions ;
p->tx_total_collisions = ps->tx_total_collisions ;
p->rx_good = ps->rx_good ;
p->rx_crc_errors = ps->rx_crc_errors ;
p->rx_align_errors = ps->rx_align_errors ;
p->rx_resource_errors = ps->rx_resource_errors ;
p->rx_overrun_errors = ps->rx_overrun_errors ;
p->rx_collisions = ps->rx_collisions ;
p->rx_short_frames = ps->rx_short_frames ;
p->rx_too_long_frames = ps->rx_too_long_frames ;
p->rx_symbol_errors = ps->rx_symbol_errors ;
p->interrupts = ps->interrupts ;
p->rx_count = ps->rx_count ;
p->rx_deliver = ps->rx_deliver ;
p->rx_resource = ps->rx_resource ;
p->rx_restart = ps->rx_restart ;
p->tx_count = ps->tx_count ;
p->tx_complete = ps->tx_complete ;
p->tx_dropped = ps->tx_dropped ;
}
#endif // KEEP_STATISTICS
#endif // FIXME
p->tx_queue_len = 1;
break;
}
#endif
default:
res = 1;
break;
}
// Restore controller state
if (was_active) {
// Unsuspend the device
reg = get_reg(cpd, _REG_ECMR);
reg |= CYGARC_REG_ECMR_RE | CYGARC_REG_ECMR_TE;
put_reg(cpd, _REG_ECMR, reg);
}
return res;
}
//
// This routine is called to see if it is possible to send another packet.
// It will return non-zero if a transmit is possible, zero otherwise.
//
static int
etherc_can_send(struct eth_drv_sc *sc)
{
struct etherc_priv_data *cpd =
(struct etherc_priv_data *)sc->driver_private;
DEBUG_FUNCTION();
if (!_MII_LINK_STATE(cpd, 1))
return 0; // Link not connected
return (0 == cpd->txbusy);
}
//
// This routine is called to send data to the hardware.
static void
etherc_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len,
int total_len, unsigned long key)
{
struct etherc_priv_data *cpd =
(struct etherc_priv_data *)sc->driver_private;
int i, len, plen, ring_entry;
cyg_uint8* sdata = NULL;
cyg_uint8 *d, *buf, *txd;
DEBUG_FUNCTION();
INCR_STAT( tx_count );
cpd->txbusy = 1;
cpd->txkey = key;
// Find packet length
plen = 0;
for (i = 0; i < sg_len; i++)
plen += sg_list[i].len;
CYG_ASSERT( plen == total_len, "sg data length mismatch" );
// Get next TX descriptor
ring_entry = cpd->tx_ring_free;
do {
if (cpd->tx_ring_owned == cpd->tx_ring_cnt) {
// Is this a dead end? Probably is.
#if DEBUG & 1
db_printf("%s: Allocation failed! Retrying...\n", __FUNCTION__ );
#endif
continue;
}
cpd->tx_ring_free++;
cpd->tx_ring_owned++;
if (cpd->tx_ring_free == cpd->tx_ring_cnt)
cpd->tx_ring_free = 0;
} while (0);
txd = cpd->tx_ring + ring_entry*ETHERC_TD_SIZE;
buf = cpd->tx_buffers + ring_entry*_BUF_SIZE;
CYG_ASSERT(0 == (_SU32(txd, ETHERC_TD_STAT) & ETHERC_TD_STAT_TACT),
"TX descriptor not free");
#if DEBUG & 4
db_printf("#####Tx descriptor 0x%08x buffer 0x%08x\n",
txd, buf);
#endif
// Put data into buffer
d = buf;
for (i = 0; i < sg_len; i++) {
sdata = (cyg_uint8 *)sg_list[i].buf;
len = sg_list[i].len;
CYG_ASSERT( sdata, "No sg data pointer here" );
while(len--)
*d++ = *sdata++;
}
CYG_ASSERT( sdata, "No sg data pointer outside" );
if (plen < IEEE_8023_MIN_FRAME) {
#if DEBUG & 1
db_printf("Packet too short (%d) - padding to %d bytes.\n", plen, IEEE_8023_MIN_FRAME);
#endif
for (i = plen; i < IEEE_8023_MIN_FRAME; i++)
*d++ = 0;
plen = IEEE_8023_MIN_FRAME;
}
_SU16(txd, ETHERC_TD_TDL) = plen;
_SU32(txd, ETHERC_TD_STAT) |= ETHERC_TD_STAT_TACT;
#if DEBUG & 1
db_printf("Last TX: LEN %04x STAT %08x PTR %08x\n",
_SU16(txd, ETHERC_TD_TDL),
_SU32(txd, ETHERC_TD_STAT),
_SU32(txd, ETHERC_TD_TBA));
#endif
// Set transmit demand
put_reg(cpd, _REG_EDTRR, CYGARC_REG_EDTRR_TR);
#if DEBUG & 1
{
cyg_uint32 reg;
reg = get_reg(cpd, _REG_EESR);
db_printf("%s:END: EESR at TX: 0x%08x\n", __FUNCTION__, reg);
}
#endif
}
static void
etherc_TxEvent(struct eth_drv_sc *sc, int stat)
{
struct etherc_priv_data *cpd =
(struct etherc_priv_data *)sc->driver_private;
int success = 1;
cyg_uint8 *txd;
cyg_uint32 pkt_stat;
DEBUG_FUNCTION();
if (0 == cpd->tx_ring_owned) {
#if DEBUG & 1
db_printf("%s: got TX completion when no outstanding packets\n", __FUNCTION__);
#endif
// Ack the TX int
put_reg(cpd, _REG_EESR, CYGARC_REG_EESR_TC);
return;
}
INCR_STAT( tx_complete );
txd = cpd->tx_ring + cpd->tx_ring_alloc*ETHERC_TD_SIZE;
pkt_stat = _SU32(txd, ETHERC_TD_STAT);
if (pkt_stat & ETHERC_TD_STAT_TACT) {
#if DEBUG & 1
db_printf("%s: got TX completion when buffer is still owned\n", __FUNCTION__);
#endif
// first dirty ring entry not freed - wtf?
}
if (pkt_stat & ETHERC_TD_STAT_TDFE) {
// We had an error. Tell the stack.
success = 0;
#if DEBUG & 1
db_printf("%s: TX failure, retrying...\n", __FUNCTION__);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?