if_upd985xx.c
来自「开放源码实时操作系统源码.」· C语言 代码 · 共 1,622 行 · 第 1/4 页
C
1,622 行
cyg_drv_interrupt_unmask(p_eth_upd985xx->vector);
}
// ------------------------------------------------------------------------
// Device table entry to operate the chip in a polled mode.
// Only diddle the interface we were asked to!
STATIC void
eth_upd985xx_poll(struct eth_drv_sc *sc)
{
struct eth_upd985xx *p_eth_upd985xx;
p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;
// As it happens, this driver always requests the DSR to be called:
(void)eth_isr( p_eth_upd985xx->vector, (cyg_addrword_t)sc );
eth_upd985xx_deliver( sc );
}
// ------------------------------------------------------------------------
// Determine interrupt vector used by a device - for attaching GDB stubs
// packet handler.
STATIC int
eth_upd985xx_int_vector(struct eth_drv_sc *sc)
{
struct eth_upd985xx *p_eth_upd985xx;
p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;
return (p_eth_upd985xx->vector);
}
// ------------------------------------------------------------------------
STATIC int
eth_set_mac_address( struct eth_upd985xx *p_eth_upd985xx, void *data )
{
cyg_uint8 *p = (cyg_uint8 *)data;
cyg_uint8 *mac_address;
mac_address = &p_eth_upd985xx->mac_address[0];
mac_address[5] = p[5];
mac_address[4] = p[4];
mac_address[3] = p[3];
mac_address[2] = p[2];
mac_address[1] = p[1];
mac_address[0] = p[0];
p_eth_upd985xx->mac_addr_ok = 1;
// Set the ESA in the device regs
OUTL( ETH_LSA2,
(p_eth_upd985xx->mac_address[1]) |
(p_eth_upd985xx->mac_address[0] << 8 ) );
OUTL( ETH_LSA1,
(p_eth_upd985xx->mac_address[5]) |
(p_eth_upd985xx->mac_address[4] << 8 ) |
(p_eth_upd985xx->mac_address[3] << 16 ) |
(p_eth_upd985xx->mac_address[2] << 24) );
return 0; // OK
}
// ------------------------------------------------------------------------
STATIC void
eth_upd985xx_reset( struct eth_upd985xx *p_eth_upd985xx )
{
int i;
// Reset whole device: Software Reset (clears automatically)
OUTL( ETH_CCR, ETH_CCR_SRT );
for ( i = 0; i < 10000; i++ ) /* nothing */;
// Reset internal units
OUTL( ETH_MACC2, ETH_MACC2_MCRST | ETH_MACC2_RFRST | ETH_MACC2_TFRST );
for ( i = 0; i < 10000; i++ ) /* nothing */;
FLUSH_WRITES();
OUTL( ETH_MACC2, 0 ); // (and release reset)
// Enable CRC adding, padding
FLUSH_WRITES();
OUTL( ETH_MACC1,
ETH_MACC1_CRCEN | ETH_MACC1_PADEN |
ETH_MACC1_TXFC | ETH_MACC1_RXFC | ETH_MACC1_PARF );
FLUSH_WRITES();
OUTL( ETH_MACC2, ETH_MACC2_APD ); // Auto VLAN pad
FLUSH_WRITES();
OUTL( ETH_HT1, 0 );
FLUSH_WRITES();
OUTL( ETH_HT2, 0 );
// Enable rx of broadcasts, multicasts, but not promiscuous...
FLUSH_WRITES();
#if defined( CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E1E2 ) && \
!defined( CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E1E2_E2ONLY )
// Unless we are faking it.
OUTL( ETH_AFR, ETH_AFR_ABC | ETH_AFR_PRM | ETH_AFR_PRO );
#else
OUTL( ETH_AFR, ETH_AFR_ABC | ETH_AFR_PRM );
#endif
FLUSH_WRITES();
OUTL( ETH_IPGT, 0x00000013 );
FLUSH_WRITES();
OUTL( ETH_IPGR, 0x00000e13 );
FLUSH_WRITES();
OUTL( ETH_CLRT, 0x0000380f );
FLUSH_WRITES();
OUTL( ETH_LMAX, MAX_ETHERNET_PACKET_SIZE );
// Select a clock for the MII
FLUSH_WRITES();
OUTL( ETH_MIIC, ETH_MIIC_66 ); // Example code sets to 66.
// Set VLAN type reg
FLUSH_WRITES();
OUTL( ETH_VLTP, ETH_VLTP_VLTP );
// Set the ESA in the device regs
if ( p_eth_upd985xx->mac_addr_ok ) {
FLUSH_WRITES();
OUTL( ETH_LSA2,
(p_eth_upd985xx->mac_address[1]) |
(p_eth_upd985xx->mac_address[0] << 8 ) );
FLUSH_WRITES();
OUTL( ETH_LSA1,
(p_eth_upd985xx->mac_address[5]) |
(p_eth_upd985xx->mac_address[4] << 8 ) |
(p_eth_upd985xx->mac_address[3] << 16 ) |
(p_eth_upd985xx->mac_address[2] << 24) );
}
FLUSH_WRITES();
OUTL( ETH_RXFCR, ETH_RXFCR_UWM_DEFAULT |
ETH_RXFCR_LWM_DEFAULT | ETH_RXFCR_DRTH16W );
FLUSH_WRITES();
// Fault E4 - use only 32 for FLTH, not the previously recommended 48 (words)
// Tag: CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E4
// but no config opt is provided.
OUTL( ETH_TXFCR, ETH_TXFCR_TPTV_DEFAULT |
ETH_TXFCR_TX_DRTH_DEFAULT | (32 << ETH_TXFCR_TX_FLTH_SHIFT) );
// Transmit and receive config regs we hit when enabling those
// functions separately, and the wet string end of the receiver
// which is controlled by MACC1 |= ETH_MACC1_SRXEN;
// Tx and Rx interrupts enabled internally;
// Tx done/aborted, and rx OK.
FLUSH_WRITES();
OUTL( ETH_MSR, ETH_ISR_XMTDN | ETH_ISR_TABR |
ETH_ISR_RCVDN | ETH_ISR_RBDRS | ETH_ISR_RBDRU );
FLUSH_WRITES();
}
// ------------------------------------------------------------------------
//
// NETWORK INTERFACE INITIALIZATION
//
// ------------------------------------------------------------------------
STATIC bool
upd985xx_eth_upd985xx_init(struct cyg_netdevtab_entry * ndp)
{
struct eth_drv_sc *sc;
cyg_uint8 *mac_address;
struct eth_upd985xx *p_eth_upd985xx;
#ifdef DEBUG
db_printf("upd985xx_eth_upd985xx_init\n");
#endif
sc = (struct eth_drv_sc *)(ndp->device_instance);
p_eth_upd985xx = (struct eth_upd985xx *)(sc->driver_private);
CHECK_NDP_SC_LINK();
p_eth_upd985xx->tx_busy = 0;
// record the net dev pointer
p_eth_upd985xx->ndp = (void *)ndp;
mac_address = &p_eth_upd985xx->mac_address[0];
#ifdef CYGSEM_DEVS_ETH_UPD985XX_ETH0_GET_EEPROM_ESA
if ( ! p_eth_upd985xx->hardwired_esa ) {
cyg_uint8 *p;
union macar {
struct {
cyg_uint32 macar1, macar2, macar3;
} integers;
cyg_uint8 bytes[12];
} eeprom;
eeprom.integers.macar1 = INL( MACAR1 ); // MAC Address Register 1
eeprom.integers.macar2 = INL( MACAR2 ); // MAC Address Register 2
eeprom.integers.macar3 = INL( MACAR3 ); // MAC Address Register 3
if ( (0 != eeprom.integers.macar1 ||
0 != eeprom.integers.macar2 ||
0 != eeprom.integers.macar3 )
&&
(0xffffffff != eeprom.integers.macar1 ||
0xffffffff != eeprom.integers.macar2 ||
0xffffffff != eeprom.integers.macar3 ) ) {
// Then we have good data in the EEPROM
#ifdef DEBUG
os_printf( "EEPROM data %08x %08x %08x\n",
eeprom.integers.macar1,
eeprom.integers.macar2,
eeprom.integers.macar3 );
#endif
p = &eeprom.bytes[0]; // pick up either set of ESA info
if ( 1 == p_eth_upd985xx->index )
p += 6;
mac_address[5] = p[5];
mac_address[4] = p[4];
mac_address[3] = p[3];
mac_address[2] = p[2];
mac_address[1] = p[1];
mac_address[0] = p[0];
p_eth_upd985xx->mac_addr_ok = 1;
}
else {
// Fake it so we can get RedBoot going on a board with no EEPROM
mac_address[0] = 0;
mac_address[1] = 0xBA;
mac_address[2] = 0xD0;
mac_address[3] = 0xEE;
mac_address[4] = 0x00;
mac_address[5] = p_eth_upd985xx->index;
p_eth_upd985xx->mac_addr_ok = 1;
}
}
#endif // CYGSEM_DEVS_ETH_UPD985XX_ETH0_GET_EEPROM_ESA
// Init the underlying hardware and insert the ESA:
eth_upd985xx_reset(p_eth_upd985xx);
#ifdef DEBUG
os_printf("MAC Address %s, ESA = %02X %02X %02X %02X %02X %02X\n",
p_eth_upd985xx->mac_addr_ok ? "OK" : "**BAD**",
mac_address[0], mac_address[1], mac_address[2], mac_address[3],
mac_address[4], mac_address[5]);
#endif
// Set up the pointers to data structures
InitTxRing(p_eth_upd985xx);
// Construct the interrupt handler
p_eth_upd985xx->active = 0;
cyg_drv_interrupt_acknowledge(p_eth_upd985xx->vector);
cyg_drv_interrupt_mask(p_eth_upd985xx->vector);
cyg_drv_interrupt_create(
p_eth_upd985xx->vector,
0, // Priority - unused
(CYG_ADDRWORD)sc, // Data item passed to ISR & DSR
eth_isr, // ISR
eth_drv_dsr, // DSR (generic)
&p_eth_upd985xx->interrupt_handle, // handle to intr obj
&p_eth_upd985xx->interrupt_object ); // space for int obj
cyg_drv_interrupt_attach(p_eth_upd985xx->interrupt_handle);
// Initialize upper level driver
if ( p_eth_upd985xx->mac_addr_ok )
(sc->funs->eth_drv->init)(sc, &(p_eth_upd985xx->mac_address[0]) );
else
(sc->funs->eth_drv->init)(sc, 0 );
return (1);
}
// ------------------------------------------------------------------------
//
// Function : eth_upd985xx_start
//
// ------------------------------------------------------------------------
STATIC void
eth_upd985xx_start( struct eth_drv_sc *sc,
unsigned char *enaddr, int flags )
{
struct eth_upd985xx *p_eth_upd985xx;
cyg_uint32 ss;
#ifdef CYGPKG_NET
struct ifnet *ifp = &sc->sc_arpcom.ac_if;
#endif
p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;
#ifdef DEBUG
os_printf("eth_upd985xx_start %d flg %x\n", p_eth_upd985xx->index, *(int *)p_eth_upd985xx );
#endif
if ( p_eth_upd985xx->active )
eth_upd985xx_stop( sc );
p_eth_upd985xx->active = 1;
#ifdef CYGPKG_NET
/* Enable promiscuous mode if requested, reception of oversized frames always.
* The latter is needed for VLAN support and shouldn't hurt even if we're not
* using VLANs.
*/
eth_upd985xx_configure(p_eth_upd985xx, !!(ifp->if_flags & IFF_PROMISC), 1);
#endif
// renegotiate link status
p_eth_upd985xx->phy_status = eth_upd985xx_status( p_eth_upd985xx );
if ( p_eth_upd985xx->phy_status & PHY_STATUS_FDX ) {
cyg_uint32 ss;
// then enable full duplex in the MAC
ss = INL( ETH_MACC1 );
ss |= ETH_MACC1_FDX;
OUTL( ETH_MACC1, ss );
}
#ifdef DEBUG
{
int status = p_eth_upd985xx->phy_status;
os_printf("eth_upd985xx_start %d Link = %s, %s Mbps, %s Duplex\n",
p_eth_upd985xx->index,
status & PHY_STATUS_LINK ? "Up" : "Down",
status & PHY_STATUS_100MBPS ? "100" : "10",
status & PHY_STATUS_FDX ? "Full" : "Half"
);
}
#endif
// Start the receive engine
p_eth_upd985xx->count_rx_restart++;
// Initialize all but one buffer: [B0,B1,B2,...Bx,NULL,LINK]
InitRxRing( p_eth_upd985xx );
// Point the hardware at the list of buffers
OUTL( ETH_RXDPR, (cyg_uint32)p_eth_upd985xx->rxring_active );
// Tell it about the buffers via the rx descriptor count
OUTL( ETH_RXPDR, ETH_RXPDR_AL | (NUM_RXBUFS-1) );
// Ack any pending interrupts from the system
p_eth_upd985xx->intrs = INL( ETH_ISR ); // Read-clear
// Start the rx.
OUTL( ETH_RXCR, ETH_RXCR_RXE | ETH_RXCR_DRBS_16 );
// Enable the wet string end of the receiver
ss = INL( ETH_MACC1 );
ss |= ETH_MACC1_SRXEN;
OUTL( ETH_MACC1, ss );
// And unmask the interrupt
cyg_drv_interrupt_acknowledge(p_eth_upd985xx->vector);
cyg_drv_interrupt_unmask(p_eth_upd985xx->vector);
}
// ------------------------------------------------------------------------
//
// Function : eth_upd985xx_status; 10/100 and Full/Half Duplex (FDX/HDX)
//
// ------------------------------------------------------------------------
STATIC int eth_upd985xx_status( struct eth_upd985xx *p_eth_upd985xx )
{
int status;
int i, j;
// Some of these bits latch and only reflect "the truth" on a 2nd reading.
// So read and discard.
mii_read( PHY_CONTROL_REG, &i, p_eth_upd985xx );
mii_read( PHY_STATUS_REG, &i, p_eth_upd985xx );
// Use the "and" of the local and remote capabilities words to infer
// what is selected:
status = 0;
if ( mii_read( PHY_STATUS_REG, &i, p_eth_upd985xx ) ) {
if ( PHY_STATUS_LINK_OK & i )
status |= PHY_STATUS_LINK;
}
if ( mii_read( PHY_AUTONEG_ADVERT, &j, p_eth_upd985xx ) &&
mii_read( PHY_AUTONEG_REMOTE, &i, p_eth_upd985xx ) ) {
#if defined( DEBUG_TRAFFIC ) || defined( DEBUG_IOCTL )
os_printf( "MII: capabilities are %04x, %04x; common %04x\n",
i, j, i & j );
#endif
j &= i; // select only common capabilities
if ( (PHY_AUTONEG_100BASET4 |
PHY_AUTONEG_100BASETX_FDX |
PHY_AUTONEG_100BASETX_HDX) & j )
status |= PHY_STATUS_100MBPS;
if ( (PHY_AUTONEG_100BASETX_FDX | PHY_AUTONEG_10BASET_FDX) & j )
status |= PHY_STATUS_FDX;
}
return status;
}
// ------------------------------------------------------------------------
//
// Function : eth_upd985xx_stop
//
// ------------------------------------------------------------------------
STATIC void eth_upd985xx_stop( struct eth_drv_sc *sc )
{
struct eth_upd985xx *p_eth_upd985xx;
p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;
// No more interrupts
cyg_drv_interrupt_acknowledge(p_eth_upd985xx->vector);
cyg_drv_interrupt_mask(p_eth_upd985xx->vector);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?