⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dmascc.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
      } else {	inb_p(io + TWIN_CLR_TMR2);	tm_isr(&info->dev[1]);      }    }    /* No interrupts pending from the PackeTwin */    return;  }}static inline void z8530_isr(struct scc_info *info){  int is, a_cmd;    a_cmd = info->scc_base + SCCA_CMD;  while ((is = read_scc(a_cmd, R3))) {    if (is & CHARxIP) {      rx_isr(&info->dev[0]);    } else if (is & CHATxIP) {      tx_isr(&info->dev[0]);    } else if (is & CHAEXT) {      es_isr(&info->dev[0]);    } else if (is & CHBRxIP) {      rx_isr(&info->dev[1]);    } else if (is & CHBTxIP) {      tx_isr(&info->dev[1]);    } else {      es_isr(&info->dev[1]);    }  }  /* Ok, no interrupts pending from this 8530. The INT line should     be inactive now. */}static void rx_isr(struct device *dev){  struct scc_priv *priv = dev->priv;  int cmd = priv->cmd;  if (dev->dma) {    /* Check special condition and perform error reset. See 2.4.7.5. */    special_condition(dev, read_scc(cmd, R1));    write_scc(cmd, R0, ERR_RES);  } else {    /* Check special condition for each character. Error reset not necessary.       Same algorithm for SCC and ESCC. See 2.4.7.1 and 2.4.7.4. */    int rc;    while (read_scc(cmd, R0) & Rx_CH_AV) {      rc = read_scc(cmd, R1);      if (priv->rx_ptr < BUF_SIZE)	priv->rx_buf[priv->rx_head][priv->rx_ptr++] = read_scc(cmd, R8);      else {	priv->rx_over = 2;	read_scc(cmd, R8);      }      special_condition(dev, rc);    }  }}static void special_condition(struct device *dev, int rc){  struct scc_priv *priv = dev->priv;  int cb, cmd = priv->cmd;  unsigned long flags;  /* See Figure 2-15. Only overrun and EOF need to be checked. */    if (rc & Rx_OVR) {    /* Receiver overrun */    priv->rx_over = 1;    if (!dev->dma) write_scc(cmd, R0, ERR_RES);  } else if (rc & END_FR) {    /* End of frame. Get byte count */    if (dev->dma) {        flags=claim_dma_lock();	disable_dma(dev->dma);	clear_dma_ff(dev->dma);	cb = BUF_SIZE - get_dma_residue(dev->dma) - 2;	release_dma_lock(flags);	    } else {	cb = priv->rx_ptr - 2;    }    if (priv->rx_over) {      /* We had an overrun */      priv->stats.rx_errors++;      if (priv->rx_over == 2) priv->stats.rx_length_errors++;      else priv->stats.rx_fifo_errors++;      priv->rx_over = 0;    } else if (rc & CRC_ERR) {      /* Count invalid CRC only if packet length >= minimum */      if (cb >= 8) {	priv->stats.rx_errors++;	priv->stats.rx_crc_errors++;      }    } else {      if (cb >= 8) {	/* Put good frame in FIFO */	priv->rx_len[priv->rx_head] = cb;	priv->rx_head = (priv->rx_head + 1) % NUM_RX_BUF;	priv->rx_count++;	if (priv->rx_count == NUM_RX_BUF) {	  /* Disable receiver if FIFO full */	  write_scc(cmd, R3, Rx8);	  priv->stats.rx_errors++;	  priv->stats.rx_over_errors++;	}	/* Mark bottom half handler */	queue_task(&priv->rx_task, &tq_immediate);	mark_bh(IMMEDIATE_BH);      }    }    /* Get ready for new frame */    if (dev->dma) {            flags=claim_dma_lock();      set_dma_addr(dev->dma, (int) priv->rx_buf[priv->rx_head]);      set_dma_count(dev->dma, BUF_SIZE);      enable_dma(dev->dma);      release_dma_lock(flags);          } else {      priv->rx_ptr = 0;    }  }}static void rx_bh(void *arg){  struct device *dev = arg;  struct scc_priv *priv = dev->priv;  struct scc_info *info = priv->info;  int cmd = priv->cmd;  int i = priv->rx_tail;  int cb;  unsigned long flags;  struct sk_buff *skb;  unsigned char *data;  save_flags(flags);  cli();  while (priv->rx_count) {    restore_flags(flags);    cb = priv->rx_len[i];    /* Allocate buffer */    skb = dev_alloc_skb(cb+1);    if (skb == NULL) {      /* Drop packet */      priv->stats.rx_dropped++;    } else {      /* Fill buffer */      data = skb_put(skb, cb+1);      data[0] = 0;      memcpy(&data[1], priv->rx_buf[i], cb);      skb->dev = dev;      skb->protocol = ntohs(ETH_P_AX25);      skb->mac.raw = skb->data;      netif_rx(skb);      priv->stats.rx_packets++;    }    save_flags(flags);    cli();    /* Enable receiver if RX buffers have been unavailable */    if ((priv->rx_count == NUM_RX_BUF) && (priv->status & DCD)) {      if (info->type <= TYPE_PI2) outb_p(0, dev->base_addr + PI_DREQ_MASK);      write_scc(cmd, R3, RxENABLE | Rx8 | RxCRC_ENAB);      if (info->type <= TYPE_PI2) outb_p(1, dev->base_addr + PI_DREQ_MASK);    }    /* Move tail */    priv->rx_tail = i = (i + 1) % NUM_RX_BUF;    priv->rx_count--;  }  restore_flags(flags);}static void tx_isr(struct device *dev){  struct scc_priv *priv = dev->priv;  int cmd = priv->cmd;  int i = priv->tx_tail, p = priv->tx_ptr;  /* Suspend TX interrupts if we don't want to send anything.     See Figure 2-22. */  if (p ==  priv->tx_len[i]) {    write_scc(cmd, R0, RES_Tx_P);    return;  }  /* Write characters */  while ((read_scc(cmd, R0) & Tx_BUF_EMP) && p < priv->tx_len[i]) {    write_scc(cmd, R8, priv->tx_buf[i][p++]);  }  priv->tx_ptr = p;}static void es_isr(struct device *dev){  struct scc_priv *priv = dev->priv;  struct scc_info *info = priv->info;  int i, cmd = priv->cmd;  int st, dst, res;  unsigned long flags;  /* Read status and reset interrupt bit */  st = read_scc(cmd, R0);  write_scc(cmd, R0, RES_EXT_INT);  dst = priv->status ^ st;  priv->status = st;  /* Since the EOM latch is reset automatically, we assume that     it has been zero if and only if we are in the TX_ACTIVE state.     Otherwise we follow 2.4.9.6. */  /* Transmit underrun */  if ((priv->tx_state == TX_ACTIVE) && (st & TxEOM)) {    /* Get remaining bytes */    i = priv->tx_tail;    if (dev->dma) {      flags=claim_dma_lock();      disable_dma(dev->dma);      clear_dma_ff(dev->dma);      res = get_dma_residue(dev->dma);      release_dma_lock(flags);    } else {      res = priv->tx_len[i] - priv->tx_ptr;      if (res) write_scc(cmd, R0, RES_Tx_P);      priv->tx_ptr = 0;    }    /* Remove frame from FIFO */    priv->tx_tail = (i + 1) % NUM_TX_BUF;    priv->tx_count--;    dev->tbusy = 0;    /* Check if another frame is available and we are allowed to transmit */    if (priv->tx_count && (jiffies - priv->tx_start) < priv->param.txtime) {      if (dev->dma) {        flags=claim_dma_lock();	set_dma_addr(dev->dma, (int) priv->tx_buf[priv->tx_tail]);	set_dma_count(dev->dma, priv->tx_len[priv->tx_tail]);	enable_dma(dev->dma);	release_dma_lock(flags);      } else {	/* If we have an ESCC, we are allowed to write data bytes	   immediately. Otherwise we have to wait for the next	   TX interrupt. See Figure 2-22. */	if (info->chip == Z85230) {	  tx_isr(dev);	}      }    } else {      /* No frame available. Disable interrupts. */      priv->tx_state = TX_SQDELAY;      delay(dev, priv->param.sqdelay);      write_scc(cmd, R15, DCDIE | CTSIE | SYNCIE);      write_scc(cmd, R1, EXT_INT_ENAB | WT_FN_RDYFN);    }    /* Update packet statistics */    if (res) {      priv->stats.tx_errors++;      priv->stats.tx_fifo_errors++;    } else {      priv->stats.tx_packets++;    }    /* Inform upper layers */    mark_bh(NET_BH);  }  /* DCD transition */  if ((priv->tx_state < TX_TXDELAY) && (dst & DCD)) {    /* Transmitter state change */    priv->tx_state = TX_OFF;    /* Enable or disable receiver */    if (st & DCD) {      if (dev->dma) {	/* Program DMA controller */	flags=claim_dma_lock();	disable_dma(dev->dma);	clear_dma_ff(dev->dma);	set_dma_mode(dev->dma, DMA_MODE_READ);	set_dma_addr(dev->dma, (int) priv->rx_buf[priv->rx_head]);	set_dma_count(dev->dma, BUF_SIZE);	enable_dma(dev->dma);	release_dma_lock(flags);	/* Configure PackeTwin DMA */	if (info->type == TYPE_TWIN) {	  outb_p((dev->dma == 1) ? TWIN_DMA_HDX_R1 : TWIN_DMA_HDX_R3,		 dev->base_addr + TWIN_DMA_CFG);	}	/* Sp. cond. intr. only, ext int enable */	write_scc(cmd, R1, EXT_INT_ENAB | INT_ERR_Rx |		  WT_RDY_RT | WT_FN_RDYFN | WT_RDY_ENAB);      } else {	/* Intr. on all Rx characters and Sp. cond., ext int enable */	write_scc(cmd, R1, EXT_INT_ENAB | INT_ALL_Rx | WT_RDY_RT |		  WT_FN_RDYFN);      }      if (priv->rx_count < NUM_RX_BUF) {	/* Enable receiver */	write_scc(cmd, R3, RxENABLE | Rx8 | RxCRC_ENAB);      }    } else {      /* Disable DMA */      if (dev->dma)      {      	flags=claim_dma_lock();      	disable_dma(dev->dma);      	release_dma_lock(flags);      }      /* Disable receiver */      write_scc(cmd, R3, Rx8);      /* DMA disable, RX int disable, Ext int enable */      write_scc(cmd, R1, EXT_INT_ENAB | WT_RDY_RT | WT_FN_RDYFN);      /* Transmitter state change */      if (random() > priv->param.persist)	delay(dev, priv->param.slottime);      else {	if (priv->tx_count) {	  priv->tx_state = TX_TXDELAY;	  write_scc(cmd, R5, TxCRC_ENAB | RTS | TxENAB | Tx8);	  priv->tx_start = jiffies;	  delay(dev, priv->param.txdelay);	} else {	  priv->tx_state = TX_IDLE;	}      }    }  }  /* CTS transition */  if ((info->type <= TYPE_PI2) && (dst & CTS) && (~st & CTS)) {    /* Timer has expired */    tm_isr(dev);  }  /* /SYNC/HUNT transition */  if ((dst & SYNC_HUNT) && (~st & SYNC_HUNT)) {    /* Reset current frame and clear RX FIFO */    while (read_scc(cmd, R0) & Rx_CH_AV) read_scc(cmd, R8);    priv->rx_over = 0;    if (dev->dma) {      flags=claim_dma_lock();      disable_dma(dev->dma);      clear_dma_ff(dev->dma);      set_dma_addr(dev->dma, (int) priv->rx_buf[priv->rx_head]);      set_dma_count(dev->dma, BUF_SIZE);      enable_dma(dev->dma);      release_dma_lock(flags);    } else {      priv->rx_ptr = 0;    }  }}static void tm_isr(struct device *dev){  struct scc_priv *priv = dev->priv;  struct scc_info *info = priv->info;  int cmd = priv->cmd;  unsigned long flags;  switch (priv->tx_state) {  case TX_OFF:    if (~priv->status & DCD) {      if (random() > priv->param.persist) delay(dev, priv->param.slottime);      else {	if (priv->tx_count) {	  priv->tx_state = TX_TXDELAY;	  write_scc(cmd, R5, TxCRC_ENAB | RTS | TxENAB | Tx8);	  priv->tx_start = jiffies;	  delay(dev, priv->param.txdelay);	} else {	  priv->tx_state = TX_IDLE;	}      }    }    break;  case TX_TXDELAY:    priv->tx_state = TX_ACTIVE;    if (dev->dma) {      /* Program DMA controller */            flags=claim_dma_lock();      disable_dma(dev->dma);      clear_dma_ff(dev->dma);      set_dma_mode(dev->dma, DMA_MODE_WRITE);      set_dma_addr(dev->dma, (int) priv->tx_buf[priv->tx_tail]);      set_dma_count(dev->dma, priv->tx_len[priv->tx_tail]);      enable_dma(dev->dma);      release_dma_lock(flags);            /* Configure PackeTwin DMA */      if (info->type == TYPE_TWIN) {	outb_p((dev->dma == 1) ? TWIN_DMA_HDX_T1 : TWIN_DMA_HDX_T3,	       dev->base_addr + TWIN_DMA_CFG);      }      /* Enable interrupts and DMA. On the PackeTwin, the DTR//REQ pin	 is used for TX DMA requests, but we enable the WAIT/DMA request	 pin, anyway */      write_scc(cmd, R15, TxUIE | DCDIE | CTSIE | SYNCIE);      write_scc(cmd, R1, EXT_INT_ENAB | WT_FN_RDYFN | WT_RDY_ENAB);    } else {      write_scc(cmd, R15, TxUIE | DCDIE | CTSIE | SYNCIE);      write_scc(cmd, R1, EXT_INT_ENAB | WT_FN_RDYFN | TxINT_ENAB);      tx_isr(dev);    }    if (info->chip == Z8530) write_scc(cmd, R0, RES_EOM_L);    break;  case TX_SQDELAY:    /* Disable transmitter */    write_scc(cmd, R5, TxCRC_ENAB | Tx8);    /* Transmitter state change: Switch to TX_OFF and wait at least       1 slottime. */    priv->tx_state = TX_OFF;        if (~priv->status & DCD) delay(dev, priv->param.waittime);  }}static inline void delay(struct device *dev, int t){  struct scc_priv *priv = dev->priv;  int tmr = priv->tmr;  outb_p(t & 0xFF, tmr);  outb_p((t >> 8) & 0xFF, tmr);}static inline unsigned char random(void){  /* See "Numerical Recipes in C", second edition, p. 284 */  rand = rand * 1664525L + 1013904223L;  return (unsigned char) (rand >> 24);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -