📄 hfc_sx.c
字号:
{ if (!cs->tx_skb) return; if (cs->tx_skb->len <= 0) return; if (write_fifo(cs, cs->tx_skb, HFCSX_SEL_D_TX, 0)) { dev_kfree_skb_any(cs->tx_skb); cs->tx_skb = NULL; } return;}/**************************//* B-channel send routine *//**************************/static voidhfcsx_fill_fifo(struct BCState *bcs){ struct IsdnCardState *cs = bcs->cs; if (!bcs->tx_skb) return; if (bcs->tx_skb->len <= 0) return; if (write_fifo(cs, bcs->tx_skb, ((bcs->channel) && (!cs->hw.hfcsx.bswapped)) ? HFCSX_SEL_B2_TX : HFCSX_SEL_B1_TX, (bcs->mode == L1_MODE_TRANS) ? HFCSX_BTRANS_THRESHOLD : 0)) { bcs->tx_cnt -= bcs->tx_skb->len; if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag) && (PACKET_NOACK != bcs->tx_skb->pkt_type)) { u_long flags; spin_lock_irqsave(&bcs->aclock, flags); bcs->ackcnt += bcs->tx_skb->len; spin_unlock_irqrestore(&bcs->aclock, flags); schedule_event(bcs, B_ACKPENDING); } dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); }}/**********************************************//* D-channel l1 state call for leased NT-mode *//**********************************************/static voiddch_nt_l2l1(struct PStack *st, int pr, void *arg){ struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; switch (pr) { case (PH_DATA | REQUEST): case (PH_PULL | REQUEST): case (PH_PULL | INDICATION): st->l1.l1hw(st, pr, arg); break; case (PH_ACTIVATE | REQUEST): st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); break; case (PH_TESTLOOP | REQUEST): if (1 & (long) arg) debugl1(cs, "PH_TEST_LOOP B1"); if (2 & (long) arg) debugl1(cs, "PH_TEST_LOOP B2"); if (!(3 & (long) arg)) debugl1(cs, "PH_TEST_LOOP DISABLED"); st->l1.l1hw(st, HW_TESTLOOP | REQUEST, arg); break; default: if (cs->debug) debugl1(cs, "dch_nt_l2l1 msg %04X unhandled", pr); break; }}/***********************//* set/reset echo mode *//***********************/static inthfcsx_auxcmd(struct IsdnCardState *cs, isdn_ctrl * ic){ unsigned long flags; int i = *(unsigned int *) ic->parm.num; if ((ic->arg == 98) && (!(cs->hw.hfcsx.int_m1 & (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC + HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC)))) { spin_lock_irqsave(&cs->lock, flags); Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 0); /* HFC ST G0 */ udelay(10); cs->hw.hfcsx.sctrl |= SCTRL_MODE_NT; Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl); /* set NT-mode */ udelay(10); Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 1); /* HFC ST G1 */ udelay(10); Write_hfc(cs, HFCSX_STATES, 1 | HFCSX_ACTIVATE | HFCSX_DO_ACTION); cs->dc.hfcsx.ph_state = 1; cs->hw.hfcsx.nt_mode = 1; cs->hw.hfcsx.nt_timer = 0; spin_unlock_irqrestore(&cs->lock, flags); cs->stlist->l2.l2l1 = dch_nt_l2l1; debugl1(cs, "NT mode activated"); return (0); } if ((cs->chanlimit > 1) || (cs->hw.hfcsx.bswapped) || (cs->hw.hfcsx.nt_mode) || (ic->arg != 12)) return (-EINVAL); if (i) { cs->logecho = 1; cs->hw.hfcsx.trm |= 0x20; /* enable echo chan */ cs->hw.hfcsx.int_m1 |= HFCSX_INTS_B2REC; /* reset Channel !!!!! */ } else { cs->logecho = 0; cs->hw.hfcsx.trm &= ~0x20; /* disable echo chan */ cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_B2REC; } cs->hw.hfcsx.sctrl_r &= ~SCTRL_B2_ENA; cs->hw.hfcsx.sctrl &= ~SCTRL_B2_ENA; cs->hw.hfcsx.conn |= 0x10; /* B2-IOM -> B2-ST */ cs->hw.hfcsx.ctmt &= ~2; spin_lock_irqsave(&cs->lock, flags); Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt); Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r); Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl); Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn); Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm); Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); spin_unlock_irqrestore(&cs->lock, flags); return (0);} /* hfcsx_auxcmd *//*****************************//* E-channel receive routine *//*****************************/static voidreceive_emsg(struct IsdnCardState *cs){ int count = 5; u_char *ptr; struct sk_buff *skb; if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { debugl1(cs, "echo_rec_data blocked"); return; } do { skb = read_fifo(cs, HFCSX_SEL_B2_RX, 0); if (skb) { if (cs->debug & DEB_DLOG_HEX) { ptr = cs->dlog; if ((skb->len) < MAX_DLOG_SPACE / 3 - 10) { *ptr++ = 'E'; *ptr++ = 'C'; *ptr++ = 'H'; *ptr++ = 'O'; *ptr++ = ':'; ptr += QuickHex(ptr, skb->data, skb->len); ptr--; *ptr++ = '\n'; *ptr = 0; HiSax_putstatus(cs, NULL, cs->dlog); } else HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", skb->len); } dev_kfree_skb_any(skb); } } while (--count && skb); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); return;} /* receive_emsg *//*********************//* Interrupt handler *//*********************/static irqreturn_thfcsx_interrupt(int intno, void *dev_id, struct pt_regs *regs){ struct IsdnCardState *cs = dev_id; u_char exval; struct BCState *bcs; int count = 15; u_long flags; u_char val, stat; if (!(cs->hw.hfcsx.int_m2 & 0x08)) return IRQ_NONE; /* not initialised */ spin_lock_irqsave(&cs->lock, flags); if (HFCSX_ANYINT & (stat = Read_hfc(cs, HFCSX_STATUS))) { val = Read_hfc(cs, HFCSX_INT_S1); if (cs->debug & L1_DEB_ISAC) debugl1(cs, "HFC-SX: stat(%02x) s1(%02x)", stat, val); } else { spin_unlock_irqrestore(&cs->lock, flags); return IRQ_NONE; } if (cs->debug & L1_DEB_ISAC) debugl1(cs, "HFC-SX irq %x %s", val, test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ? "locked" : "unlocked"); val &= cs->hw.hfcsx.int_m1; if (val & 0x40) { /* state machine irq */ exval = Read_hfc(cs, HFCSX_STATES) & 0xf; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcsx.ph_state, exval); cs->dc.hfcsx.ph_state = exval; schedule_event(cs, D_L1STATECHANGE); val &= ~0x40; } if (val & 0x80) { /* timer irq */ if (cs->hw.hfcsx.nt_mode) { if ((--cs->hw.hfcsx.nt_timer) < 0) schedule_event(cs, D_L1STATECHANGE); } val &= ~0x80; Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER); } while (val) { if (test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { cs->hw.hfcsx.int_s1 |= val; spin_unlock_irqrestore(&cs->lock, flags); return IRQ_HANDLED; } if (cs->hw.hfcsx.int_s1 & 0x18) { exval = val; val = cs->hw.hfcsx.int_s1; cs->hw.hfcsx.int_s1 = exval; } if (val & 0x08) { if (!(bcs = Sel_BCS(cs, cs->hw.hfcsx.bswapped ? 1 : 0))) { if (cs->debug) debugl1(cs, "hfcsx spurious 0x08 IRQ"); } else main_rec_hfcsx(bcs); } if (val & 0x10) { if (cs->logecho) receive_emsg(cs); else if (!(bcs = Sel_BCS(cs, 1))) { if (cs->debug) debugl1(cs, "hfcsx spurious 0x10 IRQ"); } else main_rec_hfcsx(bcs); } if (val & 0x01) { if (!(bcs = Sel_BCS(cs, cs->hw.hfcsx.bswapped ? 1 : 0))) { if (cs->debug) debugl1(cs, "hfcsx spurious 0x01 IRQ"); } else { if (bcs->tx_skb) { if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { hfcsx_fill_fifo(bcs); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); } else debugl1(cs, "fill_data %d blocked", bcs->channel); } else { if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { hfcsx_fill_fifo(bcs); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); } else debugl1(cs, "fill_data %d blocked", bcs->channel); } else { schedule_event(bcs, B_XMTBUFREADY); } } } } if (val & 0x02) { if (!(bcs = Sel_BCS(cs, 1))) { if (cs->debug) debugl1(cs, "hfcsx spurious 0x02 IRQ"); } else { if (bcs->tx_skb) { if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { hfcsx_fill_fifo(bcs); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); } else debugl1(cs, "fill_data %d blocked", bcs->channel); } else { if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { hfcsx_fill_fifo(bcs); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); } else debugl1(cs, "fill_data %d blocked", bcs->channel); } else { schedule_event(bcs, B_XMTBUFREADY); } } } } if (val & 0x20) { /* receive dframe */ receive_dmsg(cs); } if (val & 0x04) { /* dframe transmitted */ if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) del_timer(&cs->dbusytimer); if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) schedule_event(cs, D_CLEARBUSY); if (cs->tx_skb) { if (cs->tx_skb->len) { if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { hfcsx_fill_dfifo(cs); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); } else { debugl1(cs, "hfcsx_fill_dfifo irq blocked"); } goto afterXPR; } else { dev_kfree_skb_irq(cs->tx_skb); cs->tx_cnt = 0; cs->tx_skb = NULL; } } if ((cs->tx_skb = skb_dequeue(&cs->sq))) { cs->tx_cnt = 0; if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { hfcsx_fill_dfifo(cs); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); } else { debugl1(cs, "hfcsx_fill_dfifo irq blocked"); } } else schedule_event(cs, D_XMTBUFREADY); } afterXPR: if (cs->hw.hfcsx.int_s1 && count--) { val = cs->hw.hfcsx.int_s1; cs->hw.hfcsx.int_s1 = 0; if (cs->debug & L1_DEB_ISAC) debugl1(cs, "HFC-SX irq %x loop %d", val, 15 - count); } else val = 0; } spin_unlock_irqrestore(&cs->lock, flags); return IRQ_HANDLED;}/********************************************************************//* timer callback for D-chan busy resolution. Currently no function *//********************************************************************/static voidhfcsx_dbusy_timer(struct IsdnCardState *cs){}/*************************************//* Layer 1 D-channel hardware access *//*************************************/static voidHFCSX_l1hw(struct PStack *st, int pr, void *arg){ struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; struct sk_buff *skb = arg; u_long flags; switch (pr) { case (PH_DATA | REQUEST): if (cs->debug & DEB_DLOG_HEX) LogFrame(cs, skb->data, skb->len); if (cs->debug & DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0); spin_lock_irqsave(&cs->lock, flags); if (cs->tx_skb) { skb_queue_tail(&cs->sq, skb);#ifdef L2FRAME_DEBUG /* psa */ if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA Queued", 0);#endif } else { cs->tx_skb = skb; cs->tx_cnt = 0;#ifdef L2FRAME_DEBUG /* psa */ if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA", 0);#endif if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { hfcsx_fill_dfifo(cs); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); } else debugl1(cs, "hfcsx_fill_dfifo blocked"); } spin_unlock_irqrestore(&cs->lock, flags); break; case (PH_PULL | INDICATION): spin_lock_irqsave(&cs->lock, flags); if (cs->tx_skb) { if (cs->debug & L1_DEB_WARN) debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); skb_queue_tail(&cs->sq, skb); spin_unlock_irqrestore(&cs->lock, flags); break; } if (cs->debug & DEB_DLOG_HEX) LogFrame(cs, skb->data, skb->len); if (cs->debug & DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0); cs->tx_skb = skb; cs->tx_cnt = 0;#ifdef L2FRAME_DEBUG /* psa */ if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);#endif if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { hfcsx_fill_dfifo(cs); test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); } else debugl1(cs, "hfcsx_fill_dfifo blocked"); spin_unlock_irqrestore(&cs->lock, flags); break; case (PH_PULL | REQUEST):#ifdef L2FRAME_DEBUG /* psa */ if (cs->debug & L1_DEB_LAPD) debugl1(cs, "-> PH_REQUEST_PULL");#endif if (!cs->tx_skb) { test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); } else test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); break; case (HW_RESET | REQUEST): spin_lock_irqsave(&cs->lock, flags); Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 3); /* HFC ST 3 */ udelay(6); Write_hfc(cs, HFCSX_STATES, 3); /* HFC ST 2 */ cs->hw.hfcsx.mst_m |= HFCSX_MASTER; Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m); Write_hfc(cs, HFCSX_STATES, HFCSX_ACTIVATE | HFCSX_DO_ACTION); spin_unlock_irqrestore(&cs->lock, flags); l1_msg(cs, HW_POWERUP | CONFIRM, NULL); break; case (HW_ENABLE | REQUEST): spin_lock_irqsave(&cs->lock, flags); Write_hfc(cs, HFCSX_STATES, HFCSX_ACTIVATE | HFCSX_DO_ACTION); spin_unlock_irqrestore(&cs->lock, flags); break; case (HW_DEACTIVATE | REQUEST): spin_lock_irqsave(&cs->lock, flags); cs->hw.hfcsx.mst_m &= ~HFCSX_MASTER; Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m); spin_unlock_irqrestore(&cs->lock, flags); break; case (HW_INFO3 | REQUEST): spin_lock_irqsave(&cs->lock, flags); cs->hw.hfcsx.mst_m |= HFCSX_MASTER; Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m); spin_unlock_irqrestore(&cs->lock, flags); break; case (HW_TESTLOOP | REQUEST): spin_lock_irqsave(&cs->lock, flags); switch ((int) arg) { case (1): Write_hfc(cs, HFCSX_B1_SSL, 0x80); /* tx slot */ Write_hfc(cs, HFCSX_B1_RSL, 0x80); /* rx slot */ cs->hw.hfcsx.conn = (cs->hw.hfcsx.conn & ~7) | 1; Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn); break; case (2): Write_hfc(cs, HFCSX_B2_SSL, 0x81); /* tx slot */ Write_hfc(cs, HFCSX_B2_RSL, 0x81); /* rx slot */ cs->hw.hfcsx.conn = (cs->hw.hfcsx.conn & ~0x38) | 0x08; Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn); break; default: spin_unlock_irqrestore(&cs->lock, flags); if (cs->debug & L1_DEB_WARN) debugl1(cs, "hfcsx_l1hw loop invalid %4x", (int) arg); return; } cs->hw.hfcsx.trm |= 0x80; /* enable IOM-loop */ Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm); spin_unlock_irqrestore(&cs->lock, flags); break; default: if (cs->debug & L1_DEB_WARN) debugl1(cs, "hfcsx_l1hw unknown pr %4x", pr); break; }}/***********************************************//* called during init setting l1 stack pointer *//***********************************************/static voidsetstack_hfcsx(struct PStack *st, struct IsdnCardState *cs){ st->l1.l1hw = HFCSX_l1hw;}/**************************************//* send B-channel data if not blocked *//**************************************/static voidhfcsx_send_data(struct BCState *bcs)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -