📄 dm9000end.c
字号:
1, 2, 3, 4, 5, 6);
}
return (result);
}
/******************************************************************************
*
* dm9000Unload - unload a driver from the system
*
* This function first brings down the device, and then frees any
* stuff that was allocated by the driver in the load function.
*
* RETURNS: OK or ERROR.
*/
static STATUS dm9000Unload( END_DEVICE *pDrvCtrl ) /* device to be unloaded */
{
DRV_LOG (DRV_DEBUG_NO, "dm9000Unload()", 1, 2, 3, 4, 5, 6);
END_OBJECT_UNLOAD (&pDrvCtrl->end);
/* TODO - Free any shared DMA memory */
return (OK);
}
/*******************************************************************************
*
* dm9000PollStart - start polled mode operations
*
* RETURNS: OK or ERROR.
*/
static STATUS dm9000PollStart( END_DEVICE *pDrvCtrl ) /* device to be polled */
{
int oldLevel;
DRV_LOG (DRV_DEBUG_LOAD, "dm9000PollStart()", 1, 2, 3, 4, 5, 6);
oldLevel = intLock (); /* disable ints during update */
/* TODO - turn off interrupts */
(pDrvCtrl->flags) |= DM9000_POLLING;
dm9000Reset( pDrvCtrl );
dm9000Config( pDrvCtrl ); /* reconfigure device */
intUnlock (oldLevel); /* now dm9000Int won't get confused */
DRV_LOG (DRV_DEBUG_POLL, "STARTED", 1, 2, 3, 4, 5, 6);
return (OK);
}
/*******************************************************************************
*
* dm9000PollStop - stop polled mode operations
*
* This function terminates polled mode operation. The device returns to
* interrupt mode.
*
* The device interrupts are enabled, the current mode flag is switched
* to indicate interrupt mode and the device is then reconfigured for
* interrupt operation.
*
* RETURNS: OK or ERROR.
*/
static STATUS dm9000PollStop( END_DEVICE *pDrvCtrl ) /* device to be polled */
{
int oldLevel;
DRV_LOG (DRV_DEBUG_LOAD, "dm9000PollStop()", 1, 2, 3, 4, 5, 6);
oldLevel = intLock (); /* disable ints during register updates */
/* TODO - re-enable interrupts */
(pDrvCtrl->flags) &= ~DM9000_POLLING;
dm9000Reset( pDrvCtrl );
dm9000Config( pDrvCtrl ); /* reconfigure device */
intUnlock (oldLevel);
DRV_LOG (DRV_DEBUG_POLL, "STOPPED", 1, 2, 3, 4, 5, 6);
return (OK);
}
/*******************************************************************************
*
* dm9000Reset - reset device
*
* RETURNS: N/A.
*/
static void dm9000Reset( END_DEVICE *pDrvCtrl )
{
/* TODO - reset the controller */
DRV_LOG (DRV_DEBUG_LOAD, "dm9000Reset()", 1, 2, 3, 4, 5, 6);
dmfe_reset_dm9000( pDrvCtrl );
}
/*******************************************************************************
*
* dm9000StatusRead - get current device state/status
*
* RETURNS: status bits.
*/
static UINT dm9000StatusRead( END_DEVICE *pDrvCtrl )
{
/* TODO - read and return status bits/register */
UINT retv = 0;
UCHAR status = 0;
UCHAR rxbyte = 0;
DM9000_IN_CHAR( 0xfe, status );
DM9000_IN_CHAR( 0xf0, rxbyte ); /* Dummy read */
DM9000_IN_CHAR( 0xf0, rxbyte ); /* Got most updated data */
if( !((pDrvCtrl->flags) & DM9000_POLLING) )
retv |= DM9000_RXON;
if( status & 0x01 )
retv |= DM9000_RINT;
if( status & 0x02 )
retv |= DM9000_TINT;
if( pDrvCtrl->tx_pkt_cnt > 1 )
retv |= DM9000_TFULL;
if( rxbyte == DM9000_PKT_RDY )
retv |= DM9000_RXRDY;
return (retv);
}
static void dmfe_reset_dm9000( END_DEVICE *dev )
{
char status = 1;
UWORD enaddr;
UCHAR tmp;
DRV_LOG (DRV_DEBUG_LOAD, "dmfe_reset_dm9000()", 1, 2, 3, 4, 5, 6);
DM9000_OUT_CHAR( 0x0, 1 );
while( (status & 1) )
{
udelay(100);
DM9000_IN_CHAR( 0x0, status );
}
enaddr = read_srom_word( dev, 0 );
dev->enetAddr[0] = (UCHAR)(enaddr);
dev->enetAddr[1] = (UCHAR)(enaddr>>8);
enaddr = read_srom_word( dev, 1 );
dev->enetAddr[2] = (UCHAR)(enaddr);
dev->enetAddr[3] = (UCHAR)(enaddr>>8);
enaddr = read_srom_word( dev, 2 );
dev->enetAddr[4] = (UCHAR)(enaddr);
dev->enetAddr[5] = (UCHAR)(enaddr>>8);
DRV_LOG (DRV_DEBUG_LOAD, "netAddress",
dev->enetAddr[0],
dev->enetAddr[1],
dev->enetAddr[2],
dev->enetAddr[3],
dev->enetAddr[4],
dev->enetAddr[5] );
/* I/O mode */
DM9000_IN_CHAR( 0xfe, tmp );
dev->io_mode = (tmp&0xff) >> 6; /* ISR bit7:6 keeps I/O mode */
/* NIC Type: FASTETHER, HOMERUN, LONGRUN */
identify_nic( dev );
/* Set PHY */
set_PHY_mode( dev );
/* Init needed register value */
dev->reg0 = DM9000_REG00;
if ( (dev->nic_type != FASTETHER_NIC) && (dev->op_mode & DM9000_1M_HPNA) )
dev->reg0 |= DM9000_EXT_MII;
DM9000_OUT_CHAR( 0x05, DM9000_REG05 ); /* RX disable */
DM9000_OUT_CHAR( 0xff, 80 ); /* disable TX/RX interrupt mask */
}
static void dmfe_config_dm9000( END_DEVICE *dev, int oo)
{
DRV_LOG (DRV_DEBUG_LOAD, "dmfe_config_dm9000()", 1, 2, 3, 4, 5, 6);
/* Program operating register */
DM9000_OUT_CHAR( 0xff, 0x80 ); /* Enable TX/RX interrupt mask */
DM9000_OUT_CHAR( 0x00, dev->reg0 );
DM9000_OUT_CHAR( 0x02, 0 ); /* TX Polling clear */
DM9000_OUT_CHAR( 0x08, DM9000_REG08 ); /* Less 3Kb, 200us */
DM9000_OUT_CHAR( 0x09, DM9000_REG09 ); /* Flow Control : High/Low Water */
DM9000_OUT_CHAR( 0x0a, DM9000_REG0A ); /* Flow Control */
DM9000_OUT_CHAR( 0x2f, 0 ); /* Special Mode */
DM9000_OUT_CHAR( 0x01, 0x2c); /* clear TX status */
DM9000_OUT_CHAR( 0xfe, 0x0f); /* Clear interrupt status */
/* Set address filter table */
/* Set Physical Address Register */
/* Set Multicast Address Register */
dm9000_hash_table( dev );
if( oo == 2 )
{
/* Activate DM9000 */
DM9000_OUT_CHAR( 0x05, DM9000_REG05 | 1 ); /* RX enable */
DM9000_OUT_CHAR( 0xff, DM9000_REGFF ); /* Enable TX/RX interrupt mask */
}
if( oo == 1 )
{
/* Activate DM9000 */
DM9000_OUT_CHAR( 0x05, DM9000_REG05 ); /* RX disable */
DM9000_OUT_CHAR( 0xff, 80 ); /* disable TX/RX interrupt mask */
}
/* Init Driver variable */
dev->tx_pkt_cnt = 0;
dev->device_wait_reset = 0;
udelay(500);
}
/* Hardware start transmission.
Send a packet to media from the upper layer.
*/
static int dmfe_start_xmit( PKT *skb, END_DEVICE *dev)
{
char *data_ptr;
int i, oldv;
unsigned char imr=0;
int tmplen;
UWORD tmpdata;
UCHAR regsave;
DRV_LOG (DRV_DEBUG_TX, "dmfe_start_xmit()", 1, 2, 3, 4, 5, 6);
DRV_SP( DRV_PK,"." );
DM9000_IN_CHAR( 0x01, tmpdata );
if( !(tmpdata & 0x40) )
{
DRV_LOG (DRV_DEBUG_STATUS,"tx need reset", 1, 2, 3, 4, 5, 6);
dm9000Reset( dev );
dm9000Config( dev );
return 3;
}
/*DM9000_IN_CHAR(0xff,imr);
printf("imr= %x",imr);
DM9000_IN_CHAR(0xfe,imr);
printf("imr= %x",imr);*/
if( (skb->len == 0) || (skb->pData == NULL) )
{
DRV_LOG (DRV_DEBUG_STATUS,"len == 0 || pData == NULL", 1, 2, 3, 4, 5, 6);
return 2;
}
/* Resource flag check */
if( dev->tx_pkt_cnt > 1)
{
DRV_LOG (DRV_DEBUG_STATUS,"tx full", dev->tx_pkt_cnt, 2, 3, 4, 5, 6);
DM9000_IN_CHAR( 2, regsave );
return 1;
}
/* Disable all interrupt
DM9000_IN_CHAR( 0xff, regsave );
DM9000_OUT_CHAR( 0xff, 0x80 ); */
/* Move data to DM9000 TX RAM */
data_ptr = (char *)skb->pData;
/* for (i=0; i < skb->len ;i ++)
{
printf("%2x",data_ptr[i]);
if (!(i%16))
printf("\n");
}*/
/*printf("packet end..\n");*/
DM9000_OUT_ADDR( 0xf8 );
if( dev->io_mode == 2)
{
/* Byte mode */
for( i = 0; i < skb->len; i++ )
DM9000_OUT_BYTE( (data_ptr[i] & 0xff) );
}
else
{
/* Word mode */
tmplen = (skb->len + 1) / 2;
for( i = 0; i < tmplen; i++ )
{
tmpdata = ((UWORD *)data_ptr)[i];
DM9000_OUT_WORD( (tmpdata) );
}
}
dev->queue_pkt_len = skb->len;
dev->tx_pkt_cnt ++;
/* TX control: First packet immediately send, second packet queue */
if (dev->tx_pkt_cnt == 1)
{
/* First Packet */
/* Set TX length to DM9000 */
DM9000_OUT_CHAR( 0xfc, skb->len & 0xff );
DM9000_OUT_CHAR( 0xfd, (skb->len >> 8) & 0xff);
/* Issue TX polling command */
DM9000_OUT_CHAR( 0x2, 0x1 ); /* Cleared after TX complete */
}
/* Re-enable resource check */
/* Re-enable interrupt mask
DM9000_OUT_CHAR( 0xff, regsave ); */
return 0;
}
/* Received a packet and pass to upper layer
* return 0 good
* return 1 bad data
* return 2 need reset
*/
static int dmfe_packet_receive( PKT *skb, END_DEVICE *dev )
{
UCHAR tmp1,tmp2;
UWORD tmp3;
UCHAR rxbyte;
UCHAR *rdptr;
UWORD i, RxStatus, RxLen, GoodPacket, tmplen;
int oldv;
DRV_LOG (DRV_DEBUG_NO, "dmfe_packet_receive()", 1, 2, 3, 4, 5, 6);
/*oldv=INT_LOCK();*/
/* Check packet ready or not */
DM9000_IN_CHAR( 0xf0, rxbyte ); /* Dummy read */
DM9000_IN_CHAR( 0xf0, rxbyte ); /* Got most updated data */
/* Status check: this byte must be 0 or 1 */
if( rxbyte > DM9000_PKT_RDY )
{
DM9000_OUT_CHAR( 0x05, 0x00); /* Stop Device */
DM9000_OUT_CHAR( 0xfe, 0x80); /* Stop INT request */
/* dev->device_wait_reset = 1; */
DRV_LOG (DRV_DEBUG_RX,"rx need reset", 1, 2, 3, 4, 5, 6);
dm9000Reset( dev );
dm9000Config( dev );
/* INT_UNLOCK(oldv);*/
return 2;
}
/* packet ready to receive check */
if( rxbyte == DM9000_PKT_RDY )
{
/* A packet ready now & Get status/length */
GoodPacket = 1;
if( dev->io_mode == 2 )
{
/* Byte mode */
DM9000_IN_CHAR( 0xf2, tmp1 );
DM9000_IN_CHAR( 0xf2, tmp2 );
RxStatus = tmp1 + (tmp2 << 8);
DM9000_IN_CHAR( 0xf2, tmp1 );
DM9000_IN_CHAR( 0xf2, tmp2 );
RxLen = tmp1 + (tmp2<<8);
}
else
{
/* Word mode */
DM9000_OUT_ADDR( 0xf2 );
DM9000_IN_WORD( RxStatus );
DM9000_IN_WORD( RxLen );
/* RxStatus = htons( RxStatus );*/
/* RxLen = htons( RxLen );*/
}
/*printf("\n");
printf("rlen = %x\n",RxLen);*/
/* Packet Status check */
if( RxLen < 0x40)
{
DRV_LOG (DRV_DEBUG_RX, "packet too small ", 1, 2, 3, 4, 5, 6);
GoodPacket = 0;
}
if( RxLen > DM9000_PKT_MAX )
{
/* 芯片工作状态出错需要复位 */
DRV_LOG (DRV_DEBUG_RX, "packet too big need reset ", 1, 2, 3, 4, 5, 6);
dm9000Reset( dev );
dm9000Config( dev );
/* INT_UNLOCK(oldv);*/
return 2;
}
if( RxStatus & 0xbf00)
{
GoodPacket = 0;
/*if( RxStatus & 0x100 ) fifo error */
/*if( RxStatus & 0x200 ) crc error */
/*if( RxStatus & 0x8000 ) length error */
DRV_LOG (DRV_DEBUG_RX, "packet error ", RxStatus, 2, 3, 4, 5, 6);
}
/* Move data from DM9000 */
skb->len = 0;
if( GoodPacket &
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -