if_dp83816.c
来自「开放源码实时操作系统源码.」· C语言 代码 · 共 591 行 · 第 1/2 页
C
591 行
DP_OUT(dp->base, DP_IMR, 0xFFFFFFFF); // Enable interrupts
DP_OUT(dp->base, DP_IER, 1);
DP_OUT(dp->base, DP_CR, _CR_RXE | _CR_TXE);
}
//
// This routine is called to perform special "control" opertions
//
static int
dp83816_control(struct eth_drv_sc *sc, unsigned long key,
void *data, int data_len)
{
switch (key) {
case ETH_DRV_SET_MAC_ADDRESS:
return 0;
break;
default:
return 1;
break;
}
}
//
// 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
dp83816_can_send(struct eth_drv_sc *sc)
{
dp83816_priv_data_t *dp = (dp83816_priv_data_t *)sc->driver_private;
DEBUG_FUNCTION();
return (dp->txnum - dp->txbusy);
}
//
// This routine is called to send data to the hardware. It is known a-priori
// that there is free buffer space (dp->tx_next).
//
static void
dp83816_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len,
int total_len, unsigned long key)
{
struct dp83816_priv_data *dp = (struct dp83816_priv_data *)sc->driver_private;
int i, len;
unsigned char *data;
dp83816_bd_t *bdp;
#if 0
cyg_uint32 ints;
cyg_drv_dsr_lock();
HAL_DISABLE_INTERRUPTS(ints);
#endif
bdp= dp->txfill;
DEBUG_FUNCTION();
len = total_len;
if (len < IEEE_8023_MIN_FRAME) len = IEEE_8023_MIN_FRAME;
data = (unsigned char *)CYGARC_VIRTUAL_ADDRESS(CYG_LE32_TO_CPU((unsigned long)bdp->buf));
#if DEBUG & 1
if (!norecurse) {
norecurse=1;
diag_printf("send sg_len==%d, txbusy=%d, len=%d, total_len=%d\n", sg_len, dp->txbusy, len, total_len);
norecurse = 0;
}
#endif
for (i = 0; i < sg_len; i++) {
memcpy(data, (unsigned char *)sg_list[i].buf, sg_list[i].len);
data += sg_list[i].len;
}
bdp->key = key;
bdp->stat = CYG_CPU_TO_LE32(len | BD_OWN | BD_INTR);
dp->txbusy++;
bdp = (dp83816_bd_t *)CYGARC_UNCACHED_ADDRESS(CYGARC_VIRTUAL_ADDRESS(CYG_LE32_TO_CPU((unsigned long)bdp->next)));
dp->txfill = bdp;
// Kick the device, in case it went idle
DP_OUT(dp->base, DP_CR, _CR_TXE);
#if 0
cyg_drv_dsr_unlock();
HAL_RESTORE_INTERRUPTS(ints);
#endif
}
static void
dp83816_TxEvent(struct eth_drv_sc *sc)
{
struct dp83816_priv_data *dp = (struct dp83816_priv_data *)sc->driver_private;
dp83816_bd_t *bdp = dp->txint;
DEBUG_FUNCTION();
while ((CYG_LE32_TO_CPU(bdp->stat) & (BD_OWN|BD_INTR)) == BD_INTR) {
// Tell higher level we sent this packet
(sc->funs->eth_drv->tx_done)(sc, bdp->key, 0);
bdp->stat = 0; // retake buffer
bdp->key = 0;
dp->txbusy--;
bdp = (dp83816_bd_t *)CYGARC_UNCACHED_ADDRESS(CYGARC_VIRTUAL_ADDRESS(CYG_LE32_TO_CPU((unsigned long)bdp->next)));
}
dp->txint = bdp;
}
//
// This function is called when a packet has been received. It's job is
// to prepare to unload the packet from the hardware. Once the length of
// the packet is known, the upper layer of the driver can be told. When
// the upper layer is ready to unload the packet, the internal function
// 'dp83816_recv' will be called to actually fetch it from the hardware.
//
static void
dp83816_RxEvent(struct eth_drv_sc *sc)
{
struct dp83816_priv_data *dp = (struct dp83816_priv_data *)sc->driver_private;
dp83816_bd_t *bdp = CYGARC_UNCACHED_ADDRESS(dp->rxd);
dp83816_bd_t *bdfirst = CYGARC_UNCACHED_ADDRESS(dp->rxd);
int len, err;
DEBUG_FUNCTION();
while (true) {
if ((CYG_LE32_TO_CPU(bdp->stat) & BD_OWN) != 0) {
err = CYG_LE32_TO_CPU(bdp->stat) & (BD_RXA|BD_RXO|BD_LONG|BD_RUNT|BD_ISE|BD_CRCE|BD_FAE|BD_COL);
if (err != 0) {
diag_printf("RxError: %x\n", err);
}
len = CYG_LE32_TO_CPU(bdp->stat) & BD_LENGTH_MASK;
dp->rxnext = bdp;
(sc->funs->eth_drv->recv)(sc, len);
bdp->stat = CYG_CPU_TO_LE32(BD_INTR | _DP83816_BUFSIZE); // Give back buffer
}
bdp = (dp83816_bd_t *)CYGARC_UNCACHED_ADDRESS(CYGARC_VIRTUAL_ADDRESS(CYG_LE32_TO_CPU((unsigned long)bdp->next)));
if (bdp == bdfirst) {
break;
}
}
}
//
// This function is called as a result of the "eth_drv_recv()" call above.
// It's job is to actually fetch data for a packet from the hardware once
// memory buffers have been allocated for the packet. Note that the buffers
// may come in pieces, using a scatter-gather list. This allows for more
// efficient processing in the upper layers of the stack.
//
static void
dp83816_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
{
struct dp83816_priv_data *dp = (struct dp83816_priv_data *)sc->driver_private;
dp83816_bd_t *bdp = dp->rxnext;
unsigned char *data;
int i;
data = (unsigned char *)CYGARC_VIRTUAL_ADDRESS(CYG_LE32_TO_CPU((unsigned long)bdp->buf));
for (i = 0; i < sg_len; i++) {
if( sg_list[i].buf )
memcpy((void *)sg_list[i].buf, data, sg_list[i].len);
data += sg_list[i].len;
}
}
static void
dp83816_warm_reset(struct eth_drv_sc *sc)
{
struct dp83816_priv_data *dp = (struct dp83816_priv_data *)sc->driver_private;
dp83816_bd_t *bdp;
int i;
DEBUG_FUNCTION();
// Free up any active Tx buffers
bdp = CYGARC_UNCACHED_ADDRESS(dp->txd);
for (i = 0; i < dp->txnum; i++, bdp++) {
if (bdp->key) {
(sc->funs->eth_drv->tx_done)(sc, bdp->key, 0);
}
}
// Reset the device
dp83816_reset(dp);
DP_OUT(dp->base, DP_CR, _CR_RXE | _CR_TXE);
}
static void
dp83816_poll(struct eth_drv_sc *sc)
{
struct dp83816_priv_data *dp = (struct dp83816_priv_data *)sc->driver_private;
unsigned long stat, cr_stat;
#if defined(CYGPKG_REDBOOT)
cyg_drv_interrupt_acknowledge(dp->interrupt);
#endif
DP_IN(dp->base, DP_ISR, stat);
do {
if ((stat & (_ISR_TXDESC|_ISR_TXOK)) != 0) {
dp83816_TxEvent(sc);
}
if ((stat & (_ISR_RXDESC|_ISR_RXOK|_ISR_RXERR)) != 0) {
dp83816_RxEvent(sc);
}
DP_IN(dp->base, DP_CR, cr_stat);
if ((stat & (_ISR_HIBERR|_ISR_TXURN|_ISR_RXORN)) != 0) {
#if DEBUG & 2
diag_printf("DP83816 - major error: %x, cmd_stat: %x\n", stat, cr_stat);
#endif
// Try to reset the device
dp83816_warm_reset(sc);
}
#if 0
if (((cr_stat & _CR_RXE) == 0) ||
((dp->txbusy > 1) && ((cr_stat & _CR_TXE) == 0)))
{
#if DEBUG & 2
// What happened?
diag_printf("DP83816 went to lunch? - stat: %x/%x, txbusy: %x, bdstat: %x\n", cr_stat, stat, dp->txbusy, dp->txint->stat);
#endif
// Try to reset the device
dp83816_warm_reset(sc);
}
#endif
DP_IN(dp->base, DP_ISR, stat);
} while (stat != 0);
#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
CYGHWR_NS_DP83816_PLF_INT_CLEAR(dp);
#endif
}
static int
dp83816_int_vector(struct eth_drv_sc *sc)
{
struct dp83816_priv_data *dp = (struct dp83816_priv_data *)sc->driver_private;
return dp->interrupt;
}
/* EEPROM Functions */
#ifdef CYGHWR_NS_DP83816_USE_EEPROM
#define EEPROM_READ(dp, x) DP_IN((dp)->base, DP_MEAR, (x))
#define EEPROM_WRITE(dp, x) DP_OUT((dp)->base, DP_MEAR, (x))
#define EEPROM_DELAY(dp) CYG_MACRO_START cyg_uint16 t; EEPROM_READ((dp), t); CYG_MACRO_END
#define DP83816_EEPROM_ADDR_LEN 6
#define DP83816_EE_READ_CMD (6 << DP83816_EEPROM_ADDR_LEN)
/* EEPROM data is bit-swapped. */
static cyg_uint16 dp83816_eeprom_fixup_data(cyg_uint16 input)
{
cyg_uint16 output = 0;
int i;
for (i = 0; i < 16; i++) {
output = (output << 1) | (input & 0x0001);
input >>= 1;
}
return output;
}
static cyg_uint16 dp83816_eeprom_command(struct dp83816_priv_data *dp, int cmd, int cmd_len)
{
int d = 0;
EEPROM_WRITE(dp, _MEAR_EESEL);
do {
cyg_uint32 c = (cmd & (1 << cmd_len)) ? _MEAR_EEDI : 0;
cyg_uint8 t;
EEPROM_WRITE(dp, c | _MEAR_EESEL);
EEPROM_DELAY(dp);
EEPROM_WRITE(dp, c | _MEAR_EESEL | _MEAR_EECLK);
EEPROM_DELAY(dp);
EEPROM_READ(dp, t);
d <<= 1;
d |= (t & _MEAR_EEDO) ? 1 : 0;
} while (cmd_len--);
EEPROM_WRITE(dp, _MEAR_EESEL);
EEPROM_WRITE(dp, 0);
return d & 0xffff;
}
static cyg_uint16 dp83816_eeprom_read(struct dp83816_priv_data *dp, int loc)
{
cyg_uint16 d;
d = dp83816_eeprom_command(dp, (loc | DP83816_EE_READ_CMD) << 16,
3 + DP83816_EEPROM_ADDR_LEN + 16);
return dp83816_eeprom_fixup_data(d);
}
#endif /* CYGHWR_NS_DP83816_USE_EEPROM */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?