📄 hfc4s8s_l1.c
字号:
wait_busy(l1->hw); Write_hfc8(l1->hw, A_IRQ_MSK, 0); /* disable TX interrupts */ wait_busy(l1->hw); Write_hfc8(l1->hw, R_FIFO, (l1->st_num * 8 + ((bch->bchan == 1) ? 1 : 3))); wait_busy(l1->hw); Write_hfc8(l1->hw, A_IRQ_MSK, 0); /* disable RX interrupts */ Write_hfc8(l1->hw, R_ST_SEL, l1->st_num); l1->hw->mr.r_ctrl0 &= ~(bch->bchan & 3); Write_hfc8(l1->hw, A_ST_CTRL0, l1->hw->mr.r_ctrl0); spin_unlock_irqrestore(&l1->lock, flags); bch->mode = L1_MODE_NULL; bch->b_if.ifc.l1l2(&bch->b_if.ifc, PH_DEACTIVATE | INDICATION, NULL); if (bch->tx_skb) { dev_kfree_skb(bch->tx_skb); bch->tx_skb = NULL; } if (bch->rx_skb) { dev_kfree_skb(bch->rx_skb); bch->rx_skb = NULL; } skb_queue_purge(&bch->tx_queue); bch->tx_cnt = 0; bch->rx_ptr = NULL; break; } /* timer is only used when at least one b channel */ /* is set up to transparent mode */ if (l1->hw->mr.timer_usg_cnt) { Write_hfc8(l1->hw, R_IRQMSK_MISC, M_TI_IRQMSK); } else { Write_hfc8(l1->hw, R_IRQMSK_MISC, 0); } break; default: printk(KERN_INFO "HFC-4S/8S: Unknown B-chan cmd 0x%x received, ignored\n", pr); break; } if (!l1->enabled) bch->b_if.ifc.l1l2(&bch->b_if.ifc, PH_DEACTIVATE | INDICATION, NULL);} /* bch_l2l1 *//**************************//* layer 1 timer function *//**************************/static voidhfc_l1_timer(struct hfc4s8s_l1 *l1){ u_long flags; if (!l1->enabled) return; spin_lock_irqsave(&l1->lock, flags); if (l1->nt_mode) { l1->l1_state = 1; Write_hfc8(l1->hw, R_ST_SEL, l1->st_num); Write_hfc8(l1->hw, A_ST_WR_STA, 0x11); spin_unlock_irqrestore(&l1->lock, flags); l1->d_if.ifc.l1l2(&l1->d_if.ifc, PH_DEACTIVATE | INDICATION, NULL); spin_lock_irqsave(&l1->lock, flags); l1->l1_state = 1; Write_hfc8(l1->hw, A_ST_WR_STA, 0x1); spin_unlock_irqrestore(&l1->lock, flags); } else { /* activation timed out */ Write_hfc8(l1->hw, R_ST_SEL, l1->st_num); Write_hfc8(l1->hw, A_ST_WR_STA, 0x13); spin_unlock_irqrestore(&l1->lock, flags); l1->d_if.ifc.l1l2(&l1->d_if.ifc, PH_DEACTIVATE | INDICATION, NULL); spin_lock_irqsave(&l1->lock, flags); Write_hfc8(l1->hw, R_ST_SEL, l1->st_num); Write_hfc8(l1->hw, A_ST_WR_STA, 0x3); spin_unlock_irqrestore(&l1->lock, flags); }} /* hfc_l1_timer *//****************************************//* a complete D-frame has been received *//****************************************/static voidrx_d_frame(struct hfc4s8s_l1 *l1p, int ech){ int z1, z2; u_char f1, f2, df; struct sk_buff *skb; u_char *cp; if (!l1p->enabled) return; do { /* E/D RX fifo */ Write_hfc8(l1p->hw, R_FIFO, (l1p->st_num * 8 + ((ech) ? 7 : 5))); wait_busy(l1p->hw); f1 = Read_hfc8_stable(l1p->hw, A_F1); f2 = Read_hfc8(l1p->hw, A_F2); df = f1 - f2; if ((f1 - f2) < 0) df = f1 - f2 + MAX_F_CNT + 1; if (!df) { return; /* no complete frame in fifo */ } z1 = Read_hfc16_stable(l1p->hw, A_Z1); z2 = Read_hfc16(l1p->hw, A_Z2); z1 = z1 - z2 + 1; if (z1 < 0) z1 += 384; if (!(skb = dev_alloc_skb(MAX_D_FRAME_SIZE))) { printk(KERN_INFO "HFC-4S/8S: Could not allocate D/E " "channel receive buffer"); Write_hfc8(l1p->hw, A_INC_RES_FIFO, 2); wait_busy(l1p->hw); return; } if (((z1 < 4) || (z1 > MAX_D_FRAME_SIZE))) { if (skb) dev_kfree_skb(skb); /* remove errornous D frame */ if (df == 1) { /* reset fifo */ Write_hfc8(l1p->hw, A_INC_RES_FIFO, 2); wait_busy(l1p->hw); return; } else { /* read errornous D frame */#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM SetRegAddr(l1p->hw, A_FIFO_DATA0);#endif while (z1 >= 4) {#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM Read_hfc32(l1p->hw, A_FIFO_DATA0);#else fRead_hfc32(l1p->hw);#endif z1 -= 4; } while (z1--)#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM Read_hfc8(l1p->hw, A_FIFO_DATA0);#else fRead_hfc8(l1p->hw);#endif Write_hfc8(l1p->hw, A_INC_RES_FIFO, 1); wait_busy(l1p->hw); return; } } cp = skb->data;#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM SetRegAddr(l1p->hw, A_FIFO_DATA0);#endif while (z1 >= 4) {#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM *((unsigned long *) cp) = Read_hfc32(l1p->hw, A_FIFO_DATA0);#else *((unsigned long *) cp) = fRead_hfc32(l1p->hw);#endif cp += 4; z1 -= 4; } while (z1--)#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM *cp++ = Read_hfc8(l1p->hw, A_FIFO_DATA0);#else *cp++ = fRead_hfc8(l1p->hw);#endif Write_hfc8(l1p->hw, A_INC_RES_FIFO, 1); /* increment f counter */ wait_busy(l1p->hw); if (*(--cp)) { dev_kfree_skb(skb); } else { skb->len = (cp - skb->data) - 2; if (ech) l1p->d_if.ifc.l1l2(&l1p->d_if.ifc, PH_DATA_E | INDICATION, skb); else l1p->d_if.ifc.l1l2(&l1p->d_if.ifc, PH_DATA | INDICATION, skb); } } while (1);} /* rx_d_frame *//*************************************************************//* a B-frame has been received (perhaps not fully completed) *//*************************************************************/static voidrx_b_frame(struct hfc4s8s_btype *bch){ int z1, z2, hdlc_complete; u_char f1, f2; struct hfc4s8s_l1 *l1 = bch->l1p; struct sk_buff *skb; if (!l1->enabled || (bch->mode == L1_MODE_NULL)) return; do { /* RX Fifo */ Write_hfc8(l1->hw, R_FIFO, (l1->st_num * 8 + ((bch->bchan == 1) ? 1 : 3))); wait_busy(l1->hw); if (bch->mode == L1_MODE_HDLC) { f1 = Read_hfc8_stable(l1->hw, A_F1); f2 = Read_hfc8(l1->hw, A_F2); hdlc_complete = ((f1 ^ f2) & MAX_F_CNT); } else hdlc_complete = 0; z1 = Read_hfc16_stable(l1->hw, A_Z1); z2 = Read_hfc16(l1->hw, A_Z2); z1 = (z1 - z2); if (hdlc_complete) z1++; if (z1 < 0) z1 += 384; if (!z1) break; if (!(skb = bch->rx_skb)) { if (! (skb = dev_alloc_skb((bch->mode == L1_MODE_TRANS) ? z1 : (MAX_B_FRAME_SIZE + 3)))) { printk(KERN_ERR "HFC-4S/8S: Could not allocate B " "channel receive buffer"); return; } bch->rx_ptr = skb->data; bch->rx_skb = skb; } skb->len = (bch->rx_ptr - skb->data) + z1; /* HDLC length check */ if ((bch->mode == L1_MODE_HDLC) && ((hdlc_complete && (skb->len < 4)) || (skb->len > (MAX_B_FRAME_SIZE + 3)))) { skb->len = 0; bch->rx_ptr = skb->data; Write_hfc8(l1->hw, A_INC_RES_FIFO, 2); /* reset fifo */ wait_busy(l1->hw); return; }#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM SetRegAddr(l1->hw, A_FIFO_DATA0);#endif while (z1 >= 4) {#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM *((unsigned long *) bch->rx_ptr) = Read_hfc32(l1->hw, A_FIFO_DATA0);#else *((unsigned long *) bch->rx_ptr) = fRead_hfc32(l1->hw);#endif bch->rx_ptr += 4; z1 -= 4; } while (z1--)#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM *(bch->rx_ptr++) = Read_hfc8(l1->hw, A_FIFO_DATA0);#else *(bch->rx_ptr++) = fRead_hfc8(l1->hw);#endif if (hdlc_complete) { /* increment f counter */ Write_hfc8(l1->hw, A_INC_RES_FIFO, 1); wait_busy(l1->hw); /* hdlc crc check */ bch->rx_ptr--; if (*bch->rx_ptr) { skb->len = 0; bch->rx_ptr = skb->data; continue; } skb->len -= 3; } if (hdlc_complete || (bch->mode == L1_MODE_TRANS)) { bch->rx_skb = NULL; bch->rx_ptr = NULL; bch->b_if.ifc.l1l2(&bch->b_if.ifc, PH_DATA | INDICATION, skb); } } while (1);} /* rx_b_frame *//********************************************//* a D-frame has been/should be transmitted *//********************************************/static voidtx_d_frame(struct hfc4s8s_l1 *l1p){ struct sk_buff *skb; u_char f1, f2; u_char *cp; int cnt; if (l1p->l1_state != 7) return; /* TX fifo */ Write_hfc8(l1p->hw, R_FIFO, (l1p->st_num * 8 + 4)); wait_busy(l1p->hw); f1 = Read_hfc8(l1p->hw, A_F1); f2 = Read_hfc8_stable(l1p->hw, A_F2); if ((f1 ^ f2) & MAX_F_CNT) return; /* fifo is still filled */ if (l1p->tx_cnt > 0) { cnt = l1p->tx_cnt; l1p->tx_cnt = 0; l1p->d_if.ifc.l1l2(&l1p->d_if.ifc, PH_DATA | CONFIRM, (void *) cnt); } if ((skb = skb_dequeue(&l1p->d_tx_queue))) { cp = skb->data; cnt = skb->len;#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM SetRegAddr(l1p->hw, A_FIFO_DATA0);#endif while (cnt >= 4) {#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM fWrite_hfc32(l1p->hw, A_FIFO_DATA0, *(unsigned long *) cp);#else SetRegAddr(l1p->hw, A_FIFO_DATA0); fWrite_hfc32(l1p->hw, *(unsigned long *) cp);#endif cp += 4; cnt -= 4; }#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM while (cnt--) fWrite_hfc8(l1p->hw, A_FIFO_DATA0, *cp++);#else while (cnt--) fWrite_hfc8(l1p->hw, *cp++);#endif l1p->tx_cnt = skb->truesize; Write_hfc8(l1p->hw, A_INC_RES_FIFO, 1); /* increment f counter */ wait_busy(l1p->hw); dev_kfree_skb(skb); }} /* tx_d_frame *//******************************************************//* a B-frame may be transmitted (or is not completed) *//******************************************************/static voidtx_b_frame(struct hfc4s8s_btype *bch){ struct sk_buff *skb; struct hfc4s8s_l1 *l1 = bch->l1p; u_char *cp; int cnt, max, hdlc_num, ack_len = 0; if (!l1->enabled || (bch->mode == L1_MODE_NULL)) return; /* TX fifo */ Write_hfc8(l1->hw, R_FIFO, (l1->st_num * 8 + ((bch->bchan == 1) ? 0 : 2))); wait_busy(l1->hw); do { if (bch->mode == L1_MODE_HDLC) { hdlc_num = Read_hfc8(l1->hw, A_F1) & MAX_F_CNT; hdlc_num -= (Read_hfc8_stable(l1->hw, A_F2) & MAX_F_CNT); if (hdlc_num < 0) hdlc_num += 16; if (hdlc_num >= 15) break; /* fifo still filled up with hdlc frames */ } else hdlc_num = 0; if (!(skb = bch->tx_skb)) { if (!(skb = skb_dequeue(&bch->tx_queue))) { l1->hw->mr.fifo_slow_timer_service[l1-> st_num] &= ~((bch->bchan == 1) ? 1 : 4); break; /* list empty */ } bch->tx_skb = skb; bch->tx_cnt = 0; } if (!hdlc_num) l1->hw->mr.fifo_slow_timer_service[l1->st_num] |= ((bch->bchan == 1) ? 1 : 4); else l1->hw->mr.fifo_slow_timer_service[l1->st_num] &= ~((bch->bchan == 1) ? 1 : 4); max = Read_hfc16_stable(l1->hw, A_Z2); max -= Read_hfc16(l1->hw, A_Z1); if (max <= 0) max += 384; max--; if (max < 16) break; /* don't write to small amounts of bytes */ cnt = skb->len - bch->tx_cnt; if (cnt > max) cnt = max; cp = skb->data + bch->tx_cnt; bch->tx_cnt += cnt;#ifndef CONFIG_HISAX_HFC4S8S_PCIMEM SetRegAddr(l1->hw, A_FIFO_DATA0);#endif while (cnt >= 4) {#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM fWrite_hfc32(l1->hw, A_FIFO_DATA0, *(unsigned long *) cp);#else fWrite_hfc32(l1->hw, *(unsigned long *) cp);#endif cp += 4; cnt -= 4; } while (cnt--)#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM fWrite_hfc8(l1->hw, A_FIFO_DATA0, *cp++);#else fWrite_hfc8(l1->hw, *cp++);#endif if (bch->tx_cnt >= skb->len) { if (bch->mode == L1_MODE_HDLC) { /* increment f counter */ Write_hfc8(l1->hw, A_INC_RES_FIFO, 1); } ack_len += skb->truesize; bch->tx_skb = 0; bch->tx_cnt = 0; dev_kfree_skb(skb); } else /* Re-Select */ Write_hfc8(l1->hw, R_FIFO, (l1->st_num * 8 + ((bch->bchan == 1) ? 0 : 2))); wait_busy(l1->hw); } while (1); if (ack_len) bch->b_if.ifc.l1l2((struct hisax_if *) &bch->b_if, PH_DATA | CONFIRM, (void *) ack_len);} /* tx_b_frame *//*************************************//* bottom half handler for interrupt *//*************************************/static voidhfc4s8s_bh(hfc4s8s_hw * hw){ u_char b; struct hfc4s8s_l1 *l1p; volatile u_char *fifo_stat; int idx; /* handle layer 1 state changes */ b = 1; l1p = hw->l1; while (b) { if ((b & hw->mr.r_irq_statech)) { /* reset l1 event */ hw->mr.r_irq_statech &= ~b; if (l1p->enabled) { if (l1p->nt_mode) { u_char oldstate = l1p->l1_state; Write_hfc8(l1p->hw, R_ST_SEL, l1p->st_num); l1p->l1_state = Read_hfc8(l1p->hw, A_ST_RD_STA) & 0xf; if ((oldstate == 3) && (l1p->l1_state != 3)) l1p->d_if.ifc.l1l2(&l1p-> d_if. ifc, PH_DEACTIVATE | INDICATION, NULL); if (l1p->l1_state != 2) { del_timer(&l1p->l1_timer); if (l1p->l1_state == 3) { l1p->d_if.ifc. l1l2(&l1p-> d_if.ifc, PH_ACTIVATE | INDICATION, NULL); } } else { /* allow transition */ Write_hfc8(hw, A_ST_WR_STA, M_SET_G2_G3); mod_timer(&l1p->l1_timer, jiffies + L1_TIMER_T1); } printk(KERN_INFO "HFC-4S/8S: NT ch %d l1 state %d -> %d\n", l1p->st_num, oldstate, l1p->l1_state); } else { u_char oldstate = l1p->l1_state;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -