evening_wind
驱动牛犊
驱动牛犊
  • 注册日期2002-12-26
  • 最后登录2005-03-14
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:751回复:0

请教高手一个关于8139驱动开发的问题,本人在此先谢了

楼主#
更多 发布于:2005-03-12 09:28
大家看看我的问题
  我在做8139的驱动,因为没有操作系统,所以不知道中断如何实现.没有办法我只有改成polling,但用示波器跟踪,发现有中断发生,就是接收不到数据,经查好像也没有发送什么数据.我的源代码是参考linux下的8139too.c的,不知道有什么地方有错,请高手指教,下面是我的源代码
1,初始化
  int rtl8139_open (struct net_device *dev)
{
struct rtl8139_private *tp = dev->priv;

#if 0

       tp->tx_bufs=(unsigned char *)(dev->virt_base | 0xa0000000);
tp->tx_bufs_dma=&(dev->sdram_base);

       tp->rx_ring=tp->tx_bufs+TX_BUF_TOT_LEN;
tp->rx_ring_dma=tp->tx_bufs_dma+TX_BUF_TOT_LEN;

tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000;
#endif //if 0
#if 1
       tp->tx_bufs=(unsigned char *)(dev->virt_base | 0xa0000000);
tp->tx_bufs_dma=*(unsigned char *)virt_to_phys(tp->tx_bufs);

       tp->rx_ring=(unsigned char *)tp->tx_bufs+TX_BUF_TOT_LEN;
tp->rx_ring_dma=*(unsigned char *)virt_to_phys(tp->rx_ring);

tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000;
#endif //if 0
rtl8139_init_ring (dev);
rtl8139_hw_start (dev);

return 0;
}

/* Start the hardware at open or resume. */
void rtl8139_hw_start (struct net_device *dev)
{
struct rtl8139_private *tp = dev->priv;
u32 i;
u8 tmp;

rtl8139_chip_reset ();

/* unlock Config[01234] and BMCR register writes */
RTL_W8_F (Cfg9346, Cfg9346_Unlock);
#if 1
/* Restore our idea of the MAC address. */
{
      MACaddr[0]=0x0;MACaddr[1]=0x4;MACaddr[2]=0x2;MACaddr[3]=0x10;
      MACaddr[4]=0x01;MACaddr[5]=0x1b;MACaddr[6]=0x0;MACaddr[7]=0x0;  
}

RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (MACaddr+ 0)));
RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (MACaddr+ 4)));
#endif
/* Must enable Tx/Rx before setting transfer thresholds! */
RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);

tp->rx_config = rtl8139_rx_config | AcceptBroadcast | AcceptMyPhys;
RTL_W32 (RxConfig, tp->rx_config);

/* Check this value: the documentation for IFG contradicts ifself. */
RTL_W32 (TxConfig, rtl8139_tx_config);

tp->cur_rx = 0;

RTL_W8 (Config3, RTL_R8 (Config3) & ~Cfg3_Magic);

/* Lock Config[01234] and BMCR register writes */
RTL_W8 (Cfg9346, Cfg9346_Lock);

/* init Rx ring buffer DMA address */
RTL_W32_F (RxBuf, tp->rx_ring_dma);

/* init Tx buffer DMA addresses */
for (i = 0; i < NUM_TX_DESC; i++)
RTL_W32_F (TxAddr0 + (i * 4), tp->tx_bufs_dma + (tp->tx_buf - tp->tx_bufs));

RTL_W32 (RxMissed, 0);
       RTL_W8(Config0,0);

// rtl8139_set_rx_mode (dev);
/* no early-rx interrupts */
RTL_W16 (MultiIntr, RTL_R16 (MultiIntr) & MultiIntrClear);

/* make sure RxTx has started */
tmp = RTL_R8 (ChipCmd);
if ((!(tmp & CmdRxEnb)) || (!(tmp & CmdTxEnb)))
RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);

/* Enable all known interrupts by setting the interrupt mask. */
RTL_W16 (IntrMask, rtl8139_intr_mask);
}
2,将中断改成了polling

/* The interrupt handler does all of the Rx thread work and cleans up
   after the Tx thread. */
int rtl8139_polling (struct net_device *dev)
{
struct rtl8139_private *tp = dev->priv;
int ackstat, status;
int boguscnt = 20;
int link_changed = 0; /* avoid bogus \"uninit\" warning */
int val=-1;

do {
status = RTL_R16 (IntrStatus);

/* h/w no longer present (hotplug?) or major error, bail */
if (status == 0xFFFF)
break;

if ((status &
    (PCIErr | PCSTimeout | RxUnderrun | RxOverflow |
     RxFIFOOver | TxErr | TxOK | RxErr | RxOK)) == 0)
break;

/* Acknowledge all of the current interrupt sources ASAP, but
  an first get an additional status bit from CSCR. */
if (status & RxUnderrun)
link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit;

/* The chip takes special action when we clear RxAckBits,
* so we clear them later in rtl8139_rx_interrupt
*/
ackstat = status & ~(RxAckBits | TxErr);
RTL_W16 (IntrStatus, ackstat);

if (status & RxAckBits)
val=rtl8139_rx_interrupt (dev, tp);

if (status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow |RxFIFOOver | RxErr))
             RTL_W32 (RxMissed, 0);

if  (status & (TxOK | TxErr)) {
val=rtl8139_tx_interrupt (dev, tp);
if (status & TxErr)
RTL_W16 (IntrStatus, TxErr);
}
boguscnt--;
} while (boguscnt > 0);
if (boguscnt <= 0) {
/* Clear all interrupt sources. */
RTL_W16 (IntrStatus, 0xffff);
}

       if (val==-1)
      _delay(10);
return val;
}
3.发送
int rtl8139_send_pkt (struct net_device *dev, char* buf, int len)
{
struct rtl8139_private *tp = dev->priv;
unsigned int entry;
       int i;
       int maxlen;
unsigned char *buf_ptr;
/* Calculate the next Tx descriptor entry. */
entry = tp->cur_tx % NUM_TX_DESC;
#define ETH_ZLEN 60
if (len < TX_BUF_SIZE)
{
if(len < ETH_ZLEN)
memset(tp->tx_buf[entry], 0, ETH_ZLEN);
buf_ptr=tp->tx_buf[entry];
for(i=0;i<len;i++)
                  buf_ptr=buf;
}
else
return -1;

       if (len>ETH_ZLEN)
  maxlen=len;
else
maxlen=ETH_ZLEN;
RTL_W32_F (TxStatus0 + (entry * sizeof (u32)),
  tp->tx_flag |maxlen);

    if (rtl8139_polling(dev)==-1)
  return -1;
tp->cur_tx++;

return 0;
}

int rtl8139_tx_interrupt (struct net_device *dev,
 struct rtl8139_private *tp)
{
unsigned long dirty_tx, tx_left;
       int val=-1;
 
dirty_tx = tp->dirty_tx;
tx_left = tp->cur_tx - dirty_tx;
while (tx_left > 0) {
int entry = dirty_tx % NUM_TX_DESC;
int txstatus;

txstatus = RTL_R32 (TxStatus0 + (entry * sizeof (u32)));

if (!(txstatus & (TxStatOK | TxUnderrun | TxAborted)))
break; /* It still hasn\'t been Txed */

/* Note: TxCarrierLost is always asserted at 100mbps. */
if (txstatus & (TxOutOfWindow | TxAborted)) {
if (txstatus & TxAborted) {
RTL_W32 (TxConfig, TxClearAbt);
RTL_W16 (IntrStatus, TxErr);
}
} else {
if (txstatus & TxUnderrun) {
/* Add 64 to the Tx FIFO threshold. */
if (tp->tx_flag < 0x00300000)
tp->tx_flag += 0x00020000;
}
else
            val=0;
}

dirty_tx++;
tx_left--;
}


/* only wake the queue if we did work, and the queue is stopped */
if (tp->dirty_tx != dirty_tx) {
tp->dirty_tx = dirty_tx;
}
return val;
}
4,接收
int rtl8139_rx_interrupt (struct net_device *dev,
 struct rtl8139_private *tp)
{
unsigned char *rx_ring;
u16 cur_rx;
       int val=-1;
       int i;
 
rx_ring = tp->rx_ring;
cur_rx = tp->cur_rx;

while ((RTL_R8 (ChipCmd) & RxBufEmpty) == 0) {
int ring_offset = cur_rx % RX_BUF_LEN;
u32 rx_status;
unsigned int rx_size;
unsigned int pkt_size;

/* read size+status of next frame from DMA ring buffer */
rx_status = *(u32 *) (rx_ring + ring_offset);
rx_size = rx_status >> 16;
pkt_size = rx_size - 4;

//              xxxpputs(\"running\");
psprintf (printf_buf1,\"rtl8139_rx() status %x, size %x, cur %x.\\n\",rx_status,rx_size, cur_rx);xxxpputs(printf_buf1);
#if 0
{
int i;
for (i = 0; i < 70; i++)
{
psprintf(printf_buf1,\" %x\",rx_ring[ring_offset + i]);
      xxxpputs(printf_buf1);
}
}
#endif

/* Packet copy from FIFO still in progress.
* Theoretically, this should never happen
* since EarlyRx is disabled.
*/
if (rx_size == 0xfff0) {
break;
}

/* If Rx err or invalid rx_size/rx_status received
* (which happens if we get lost in the ring),
* Rx process gets reset, so we abort any further
* Rx processing.
*/

if ((rx_size > (MAX_ETH_FRAME_SIZE+4)) ||
   (rx_size < 8) ||
   (!(rx_status & RxStatusOK))) {
xxxpputs(\"Out from 2...\");    
rtl8139_rx_err (rx_status, dev, tp);
return -1;
}

/* Malloc up new buffer, compatible with net-2e. */
/* Omit the four octet CRC from the length. */

/* TODO: consider allocating skb\'s outside of
* interrupt context, both to speed interrupt processing,
* and also to reduce the chances of having to
* drop packets here under memory pressure.
*/

             for(i=0;i<pkt_size;i++)
  buff=rx_ring[ring_offset+4+i];
     val=pkt_size;

cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
RTL_W16 (RxBufPtr, cur_rx - 16);

if (RTL_R16 (IntrStatus) & RxAckBits)
RTL_W16_F (IntrStatus, RxAckBits);
}

tp->cur_rx = cur_rx;
return  val;
}

int  rtl8139_recv_pkt (struct net_device *net)
{
  int  length;
  volatile u8* ptr;
  int i = 0,j;
  
  while(i == 0) {
      if ((length=rtl8139_polling(net))!=-1)
      {
         if (length==0)
    continue;
         length = (length & (0x7ff << 16)) >> 16 ;

         for(j=0;j<length;j++)
    ptr[j]=buff[j];

         if (receive_upcall (0, 0, length) == 0)  //have enough space in ring buffer?
         {
            xxxpputs(\"not enought space\");
            return -1;//no space in ring buf
         }

         if (receive_upcall (0, (void*)ptr, length) == 0)
         {
            xxxpputs(\"not data\");
            return -1; // put data to ring buff fail
         }
    
         i++;
      }
  }
  return 0;
}
游客

返回顶部