📄 dmascc.c
字号:
}static int scc_set_mac_address(struct net_device *dev, void *sa) { memcpy(dev->dev_addr, ((struct sockaddr *)sa)->sa_data, dev->addr_len); return 0;}static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs * regs) { struct scc_info *info = dev_id; spin_lock(info->priv[0].register_lock); /* At this point interrupts are enabled, and the interrupt under service is already acknowledged, but masked off. Interrupt processing: We loop until we know that the IRQ line is low. If another positive edge occurs afterwards during the ISR, another interrupt will be triggered by the interrupt controller as soon as the IRQ level is enabled again (see asm/irq.h). Bottom-half handlers will be processed after scc_isr(). This is important, since we only have small ringbuffers and want new data to be fetched/delivered immediately. */ if (info->priv[0].type == TYPE_TWIN) { int is, card_base = info->priv[0].card_base; while ((is = ~inb(card_base + TWIN_INT_REG)) & TWIN_INT_MSK) { if (is & TWIN_SCC_MSK) { z8530_isr(info); } else if (is & TWIN_TMR1_MSK) { inb(card_base + TWIN_CLR_TMR1); tm_isr(&info->priv[0]); } else { inb(card_base + TWIN_CLR_TMR2); tm_isr(&info->priv[1]); } } } else z8530_isr(info); spin_unlock(info->priv[0].register_lock); return IRQ_HANDLED;}static inline void z8530_isr(struct scc_info *info) { int is, i = 100; while ((is = read_scc(&info->priv[0], R3)) && i--) { if (is & CHARxIP) { rx_isr(&info->priv[0]); } else if (is & CHATxIP) { tx_isr(&info->priv[0]); } else if (is & CHAEXT) { es_isr(&info->priv[0]); } else if (is & CHBRxIP) { rx_isr(&info->priv[1]); } else if (is & CHBTxIP) { tx_isr(&info->priv[1]); } else { es_isr(&info->priv[1]); } write_scc(&info->priv[0], R0, RES_H_IUS); i++; } if (i < 0) { printk(KERN_ERR "dmascc: stuck in ISR with RR3=0x%02x.\n", is); } /* Ok, no interrupts pending from this 8530. The INT line should be inactive now. */}static void rx_isr(struct scc_priv *priv) { if (priv->param.dma >= 0) { /* Check special condition and perform error reset. See 2.4.7.5. */ special_condition(priv, read_scc(priv, R1)); write_scc(priv, 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(priv, R0) & Rx_CH_AV) { rc = read_scc(priv, R1); if (priv->rx_ptr < BUF_SIZE) priv->rx_buf[priv->rx_head][priv->rx_ptr++] = read_scc_data(priv); else { priv->rx_over = 2; read_scc_data(priv); } special_condition(priv, rc); } }}static void special_condition(struct scc_priv *priv, int rc) { int cb; 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 (priv->param.dma < 0) write_scc(priv, R0, ERR_RES); } else if (rc & END_FR) { /* End of frame. Get byte count */ if (priv->param.dma >= 0) { flags = claim_dma_lock(); cb = BUF_SIZE - get_dma_residue(priv->param.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 >= 15) { priv->stats.rx_errors++; priv->stats.rx_crc_errors++; } } else { if (cb >= 15) { if (priv->rx_count < NUM_RX_BUF - 1) { /* 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++; schedule_work(&priv->rx_work); } else { priv->stats.rx_errors++; priv->stats.rx_over_errors++; } } } /* Get ready for new frame */ if (priv->param.dma >= 0) { flags = claim_dma_lock(); set_dma_addr(priv->param.dma, (int) priv->rx_buf[priv->rx_head]); set_dma_count(priv->param.dma, BUF_SIZE); release_dma_lock(flags); } else { priv->rx_ptr = 0; } }}static void rx_bh(void *arg) { struct scc_priv *priv = arg; int i = priv->rx_tail; int cb; unsigned long flags; struct sk_buff *skb; unsigned char *data; spin_lock_irqsave(&priv->ring_lock, flags); while (priv->rx_count) { spin_unlock_irqrestore(&priv->ring_lock, 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 = priv->dev; skb->protocol = ntohs(ETH_P_AX25); skb->mac.raw = skb->data; netif_rx(skb); priv->dev->last_rx = jiffies; priv->stats.rx_packets++; priv->stats.rx_bytes += cb; } spin_lock_irqsave(&priv->ring_lock, flags); /* Move tail */ priv->rx_tail = i = (i + 1) % NUM_RX_BUF; priv->rx_count--; } spin_unlock_irqrestore(&priv->ring_lock, flags);}static void tx_isr(struct scc_priv *priv) { 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(priv, R0, RES_Tx_P); return; } /* Write characters */ while ((read_scc(priv, R0) & Tx_BUF_EMP) && p < priv->tx_len[i]) { write_scc_data(priv, priv->tx_buf[i][p++], 0); } /* Reset EOM latch of Z8530 */ if (!priv->tx_ptr && p && priv->chip == Z8530) write_scc(priv, R0, RES_EOM_L); priv->tx_ptr = p;}static void es_isr(struct scc_priv *priv) { int i, rr0, drr0, res; unsigned long flags; /* Read status, reset interrupt bit (open latches) */ rr0 = read_scc(priv, R0); write_scc(priv, R0, RES_EXT_INT); drr0 = priv->rr0 ^ rr0; priv->rr0 = rr0; /* Transmit underrun (2.4.9.6). We can't check the TxEOM flag, since it might have already been cleared again by AUTOEOM. */ if (priv->state == TX_DATA) { /* Get remaining bytes */ i = priv->tx_tail; if (priv->param.dma >= 0) { disable_dma(priv->param.dma); flags = claim_dma_lock(); res = get_dma_residue(priv->param.dma); release_dma_lock(flags); } else { res = priv->tx_len[i] - priv->tx_ptr; priv->tx_ptr = 0; } /* Disable DREQ / TX interrupt */ if (priv->param.dma >= 0 && priv->type == TYPE_TWIN) outb(0, priv->card_base + TWIN_DMA_CFG); else write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN); if (res) { /* Update packet statistics */ priv->stats.tx_errors++; priv->stats.tx_fifo_errors++; /* Other underrun interrupts may already be waiting */ write_scc(priv, R0, RES_EXT_INT); write_scc(priv, R0, RES_EXT_INT); } else { /* Update packet statistics */ priv->stats.tx_packets++; priv->stats.tx_bytes += priv->tx_len[i]; /* Remove frame from FIFO */ priv->tx_tail = (i + 1) % NUM_TX_BUF; priv->tx_count--; /* Inform upper layers */ netif_wake_queue(priv->dev); } /* Switch state */ write_scc(priv, R15, 0); if (priv->tx_count && (jiffies - priv->tx_start) < priv->param.txtimeout) { priv->state = TX_PAUSE; start_timer(priv, priv->param.txpause, 0); } else { priv->state = TX_TAIL; start_timer(priv, priv->param.txtail, 0); } } /* DCD transition */ if (drr0 & DCD) { if (rr0 & DCD) { switch (priv->state) { case IDLE: case WAIT: priv->state = DCD_ON; write_scc(priv, R15, 0); start_timer(priv, priv->param.dcdon, 0); } } else { switch (priv->state) { case RX_ON: rx_off(priv); priv->state = DCD_OFF; write_scc(priv, R15, 0); start_timer(priv, priv->param.dcdoff, 0); } } } /* CTS transition */ if ((drr0 & CTS) && (~rr0 & CTS) && priv->type != TYPE_TWIN) tm_isr(priv);}static void tm_isr(struct scc_priv *priv) { switch (priv->state) { case TX_HEAD: case TX_PAUSE: tx_on(priv); priv->state = TX_DATA; break; case TX_TAIL: write_scc(priv, R5, TxCRC_ENAB | Tx8); priv->state = RTS_OFF; if (priv->type != TYPE_TWIN) write_scc(priv, R15, 0); start_timer(priv, priv->param.rtsoff, 0); break; case RTS_OFF: write_scc(priv, R15, DCDIE); priv->rr0 = read_scc(priv, R0); if (priv->rr0 & DCD) { priv->stats.collisions++; rx_on(priv); priv->state = RX_ON; } else { priv->state = WAIT; start_timer(priv, priv->param.waittime, DCDIE); } break; case WAIT: if (priv->tx_count) { priv->state = TX_HEAD; priv->tx_start = jiffies; write_scc(priv, R5, TxCRC_ENAB | RTS | TxENAB | Tx8); write_scc(priv, R15, 0); start_timer(priv, priv->param.txdelay, 0); } else { priv->state = IDLE; if (priv->type != TYPE_TWIN) write_scc(priv, R15, DCDIE); } break; case DCD_ON: case DCD_OFF: write_scc(priv, R15, DCDIE); priv->rr0 = read_scc(priv, R0); if (priv->rr0 & DCD) { rx_on(priv); priv->state = RX_ON; } else { priv->state = WAIT; start_timer(priv, random()/priv->param.persist*priv->param.slottime, DCDIE); } break; }}static inline void tx_on(struct scc_priv *priv) { int i, n; unsigned long flags; if (priv->param.dma >= 0) { n = (priv->chip == Z85230) ? 3 : 1; /* Program DMA controller */ flags = claim_dma_lock(); set_dma_mode(priv->param.dma, DMA_MODE_WRITE); set_dma_addr(priv->param.dma, (int) priv->tx_buf[priv->tx_tail]+n); set_dma_count(priv->param.dma, priv->tx_len[priv->tx_tail]-n); release_dma_lock(flags); /* Enable TX underrun interrupt */ write_scc(priv, R15, TxUIE); /* Configure DREQ */ if (priv->type == TYPE_TWIN) outb((priv->param.dma == 1) ? TWIN_DMA_HDX_T1 : TWIN_DMA_HDX_T3, priv->card_base + TWIN_DMA_CFG); else write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN | WT_RDY_ENAB); /* Write first byte(s) */ spin_lock_irqsave(priv->register_lock, flags); for (i = 0; i < n; i++) write_scc_data(priv, priv->tx_buf[priv->tx_tail][i], 1); enable_dma(priv->param.dma); spin_unlock_irqrestore(priv->register_lock, flags); } else { write_scc(priv, R15, TxUIE); write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN | TxINT_ENAB); tx_isr(priv); } /* Reset EOM latch if we do not have the AUTOEOM feature */ if (priv->chip == Z8530) write_scc(priv, R0, RES_EOM_L);}static inline void rx_on(struct scc_priv *priv) { unsigned long flags; /* Clear RX FIFO */ while (read_scc(priv, R0) & Rx_CH_AV) read_scc_data(priv); priv->rx_over = 0; if (priv->param.dma >= 0) { /* Program DMA controller */ flags = claim_dma_lock(); set_dma_mode(priv->param.dma, DMA_MODE_READ); set_dma_addr(priv->param.dma, (int) priv->rx_buf[priv->rx_head]); set_dma_count(priv->param.dma, BUF_SIZE); release_dma_lock(flags); enable_dma(priv->param.dma); /* Configure PackeTwin DMA */ if (priv->type == TYPE_TWIN) { outb((priv->param.dma == 1) ? TWIN_DMA_HDX_R1 : TWIN_DMA_HDX_R3, priv->card_base + TWIN_DMA_CFG); } /* Sp. cond. intr. only, ext int enable, RX DMA enable */ write_scc(priv, R1, EXT_INT_ENAB | INT_ERR_Rx | WT_RDY_RT | WT_FN_RDYFN | WT_RDY_ENAB); } else { /* Reset current frame */ priv->rx_ptr = 0; /* Intr. on all Rx characters and Sp. cond., ext int enable */ write_scc(priv, R1, EXT_INT_ENAB | INT_ALL_Rx | WT_RDY_RT | WT_FN_RDYFN); } write_scc(priv, R0, ERR_RES); write_scc(priv, R3, RxENABLE | Rx8 | RxCRC_ENAB);}static inline void rx_off(struct scc_priv *priv) { /* Disable receiver */ write_scc(priv, R3, Rx8); /* Disable DREQ / RX interrupt */ if (priv->param.dma >= 0 && priv->type == TYPE_TWIN) outb(0, priv->card_base + TWIN_DMA_CFG); else write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN); /* Disable DMA */ if (priv->param.dma >= 0) disable_dma(priv->param.dma);}static void start_timer(struct scc_priv *priv, int t, int r15) { unsigned long flags; outb(priv->tmr_mode, priv->tmr_ctrl); if (t == 0) { tm_isr(priv); } else if (t > 0) { save_flags(flags); cli(); outb(t & 0xFF, priv->tmr_cnt); outb((t >> 8) & 0xFF, priv->tmr_cnt); if (priv->type != TYPE_TWIN) { write_scc(priv, R15, r15 | CTSIE); priv->rr0 |= CTS; } restore_flags(flags); }}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 + -