diff options
Diffstat (limited to 'drivers/isdn/hardware/mISDN/hfcmulti.c')
-rw-r--r-- | drivers/isdn/hardware/mISDN/hfcmulti.c | 706 |
1 files changed, 391 insertions, 315 deletions
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index 033223180b55..5e402cf2e795 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -103,14 +103,26 @@ * Omit this value, if all cards are interconnected or none is connected. * If unsure, don't give this parameter. * - * dslot: - * NOTE: only one dslot value must be given for every card. - * Also this value must be given for non-E1 cards. If omitted, the E1 - * card has D-channel on time slot 16, which is default. - * If 1..15 or 17..31, an alternate time slot is used for D-channel. - * In this case, the application must be able to handle this. - * If -1 is given, the D-channel is disabled and all 31 slots can be used - * for B-channel. (only for specific applications) + * dmask and bmask: + * NOTE: One dmask value must be given for every HFC-E1 card. + * If omitted, the E1 card has D-channel on time slot 16, which is default. + * dmask is a 32 bit mask. The bit must be set for an alternate time slot. + * If multiple bits are set, multiple virtual card fragments are created. + * For each bit set, a bmask value must be given. Each bit on the bmask + * value stands for a B-channel. The bmask may not overlap with dmask or + * with other bmask values for that card. + * Example: dmask=0x00020002 bmask=0x0000fffc,0xfffc0000 + * This will create one fragment with D-channel on slot 1 with + * B-channels on slots 2..15, and a second fragment with D-channel + * on slot 17 with B-channels on slot 18..31. Slot 16 is unused. + * If bit 0 is set (dmask=0x00000001) the D-channel is on slot 0 and will + * not function. + * Example: dmask=0x00000001 bmask=0xfffffffe + * This will create a port with all 31 usable timeslots as + * B-channels. + * If no bits are set on bmask, no B-channel is created for that fragment. + * Example: dmask=0xfffffffe bmask=0,0,0,0.... (31 0-values for bmask) + * This will create 31 ports with one D-channel only. * If you don't know how to use it, you don't need it! * * iomode: @@ -172,6 +184,7 @@ #define MAX_CARDS 8 #define MAX_PORTS (8 * MAX_CARDS) +#define MAX_FRAGS (32 * MAX_CARDS) static LIST_HEAD(HFClist); static spinlock_t HFClock; /* global hfc list lock */ @@ -203,7 +216,8 @@ static int nt_t1_count[] = { 3840, 1920, 960, 480, 240, 120, 60, 30 }; static uint type[MAX_CARDS]; static int pcm[MAX_CARDS]; -static int dslot[MAX_CARDS]; +static uint dmask[MAX_CARDS]; +static uint bmask[MAX_FRAGS]; static uint iomode[MAX_CARDS]; static uint port[MAX_PORTS]; static uint debug; @@ -218,7 +232,7 @@ static uint clockdelay_nt = CLKDEL_NT; #define HWID_MINIP16 3 static uint hwid = HWID_NONE; -static int HFC_cnt, Port_cnt, PCM_cnt = 99; +static int HFC_cnt, E1_cnt, bmask_cnt, Port_cnt, PCM_cnt = 99; MODULE_AUTHOR("Andreas Eversberg"); MODULE_LICENSE("GPL"); @@ -231,7 +245,8 @@ module_param(clockdelay_te, uint, S_IRUGO | S_IWUSR); module_param(clockdelay_nt, uint, S_IRUGO | S_IWUSR); module_param_array(type, uint, NULL, S_IRUGO | S_IWUSR); module_param_array(pcm, int, NULL, S_IRUGO | S_IWUSR); -module_param_array(dslot, int, NULL, S_IRUGO | S_IWUSR); +module_param_array(dmask, uint, NULL, S_IRUGO | S_IWUSR); +module_param_array(bmask, uint, NULL, S_IRUGO | S_IWUSR); module_param_array(iomode, uint, NULL, S_IRUGO | S_IWUSR); module_param_array(port, uint, NULL, S_IRUGO | S_IWUSR); module_param(hwid, uint, S_IRUGO | S_IWUSR); /* The hardware ID */ @@ -1156,7 +1171,7 @@ init_chip(struct hfc_multi *hc) hc->DTMFbase = 0x1000; if (test_bit(HFC_CHIP_EXRAM_128, &hc->chip)) { if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: changing to 128K extenal RAM\n", + printk(KERN_DEBUG "%s: changing to 128K external RAM\n", __func__); hc->hw.r_ctrl |= V_EXT_RAM; hc->hw.r_ram_sz = 1; @@ -1167,7 +1182,7 @@ init_chip(struct hfc_multi *hc) } if (test_bit(HFC_CHIP_EXRAM_512, &hc->chip)) { if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: changing to 512K extenal RAM\n", + printk(KERN_DEBUG "%s: changing to 512K external RAM\n", __func__); hc->hw.r_ctrl |= V_EXT_RAM; hc->hw.r_ram_sz = 2; @@ -1607,40 +1622,46 @@ hfcmulti_leds(struct hfc_multi *hc) struct dchannel *dch; int led[4]; - hc->ledcount += poll; - if (hc->ledcount > 4096) { - hc->ledcount -= 4096; - hc->ledstate = 0xAFFEAFFE; - } - switch (hc->leds) { case 1: /* HFC-E1 OEM */ - /* 2 red blinking: NT mode deactivate - * 2 red steady: TE mode deactivate - * left green: L1 active - * left red: frame sync, but no L1 - * right green: L2 active + /* 2 red steady: LOS + * 1 red steady: L1 not active + * 2 green steady: L1 active + * 1st green flashing: activity on TX + * 2nd green flashing: activity on RX */ - if (hc->chan[hc->dslot].sync != 2) { /* no frame sync */ - if (hc->chan[hc->dslot].dch->dev.D.protocol - != ISDN_P_NT_E1) { - led[0] = 1; + led[0] = 0; + led[1] = 0; + led[2] = 0; + led[3] = 0; + dch = hc->chan[hc->dnum[0]].dch; + if (dch) { + if (hc->chan[hc->dnum[0]].los) led[1] = 1; - } else if (hc->ledcount >> 11) { + if (hc->e1_state != 1) { led[0] = 1; - led[1] = 1; + hc->flash[2] = 0; + hc->flash[3] = 0; } else { - led[0] = 0; - led[1] = 0; + led[2] = 1; + led[3] = 1; + if (!hc->flash[2] && hc->activity_tx) + hc->flash[2] = poll; + if (!hc->flash[3] && hc->activity_rx) + hc->flash[3] = poll; + if (hc->flash[2] && hc->flash[2] < 1024) + led[2] = 0; + if (hc->flash[3] && hc->flash[3] < 1024) + led[3] = 0; + if (hc->flash[2] >= 2048) + hc->flash[2] = 0; + if (hc->flash[3] >= 2048) + hc->flash[3] = 0; + if (hc->flash[2]) + hc->flash[2] += poll; + if (hc->flash[3]) + hc->flash[3] += poll; } - led[2] = 0; - led[3] = 0; - } else { /* with frame sync */ - /* TODO make it work */ - led[0] = 0; - led[1] = 0; - led[2] = 0; - led[3] = 1; } leds = (led[0] | (led[1]<<2) | (led[2]<<1) | (led[3]<<3))^0xF; /* leds are inverted */ @@ -1651,9 +1672,9 @@ hfcmulti_leds(struct hfc_multi *hc) break; case 2: /* HFC-4S OEM */ - /* red blinking = PH_DEACTIVATE NT Mode - * red steady = PH_DEACTIVATE TE Mode - * green steady = PH_ACTIVATE + /* red steady: PH_DEACTIVATE + * green steady: PH_ACTIVATE + * green flashing: activity on TX */ for (i = 0; i < 4; i++) { state = 0; @@ -1669,17 +1690,20 @@ hfcmulti_leds(struct hfc_multi *hc) if (state) { if (state == active) { led[i] = 1; /* led green */ - } else - if (dch->dev.D.protocol == ISDN_P_TE_S0) - /* TE mode: led red */ - led[i] = 2; - else - if (hc->ledcount >> 11) - /* led red */ - led[i] = 2; - else - /* led off */ - led[i] = 0; + hc->activity_tx |= hc->activity_rx; + if (!hc->flash[i] && + (hc->activity_tx & (1 << i))) + hc->flash[i] = poll; + if (hc->flash[i] && hc->flash[i] < 1024) + led[i] = 0; /* led off */ + if (hc->flash[i] >= 2048) + hc->flash[i] = 0; + if (hc->flash[i]) + hc->flash[i] += poll; + } else { + led[i] = 2; /* led red */ + hc->flash[i] = 0; + } } else led[i] = 0; /* led off */ } @@ -1712,9 +1736,9 @@ hfcmulti_leds(struct hfc_multi *hc) break; case 3: /* HFC 1S/2S Beronet */ - /* red blinking = PH_DEACTIVATE NT Mode - * red steady = PH_DEACTIVATE TE Mode - * green steady = PH_ACTIVATE + /* red steady: PH_DEACTIVATE + * green steady: PH_ACTIVATE + * green flashing: activity on TX */ for (i = 0; i < 2; i++) { state = 0; @@ -1730,22 +1754,23 @@ hfcmulti_leds(struct hfc_multi *hc) if (state) { if (state == active) { led[i] = 1; /* led green */ - } else - if (dch->dev.D.protocol == ISDN_P_TE_S0) - /* TE mode: led red */ - led[i] = 2; - else - if (hc->ledcount >> 11) - /* led red */ - led[i] = 2; - else - /* led off */ - led[i] = 0; + hc->activity_tx |= hc->activity_rx; + if (!hc->flash[i] && + (hc->activity_tx & (1 << i))) + hc->flash[i] = poll; + if (hc->flash[i] < 1024) + led[i] = 0; /* led off */ + if (hc->flash[i] >= 2048) + hc->flash[i] = 0; + if (hc->flash[i]) + hc->flash[i] += poll; + } else { + led[i] = 2; /* led red */ + hc->flash[i] = 0; + } } else led[i] = 0; /* led off */ } - - leds = (led[0] > 0) | ((led[1] > 0) << 1) | ((led[0]&1) << 2) | ((led[1]&1) << 3); if (leds != (int)hc->ledstate) { @@ -1757,8 +1782,11 @@ hfcmulti_leds(struct hfc_multi *hc) } break; case 8: /* HFC 8S+ Beronet */ - lled = 0; - + /* off: PH_DEACTIVATE + * steady: PH_ACTIVATE + * flashing: activity on TX + */ + lled = 0xff; /* leds off */ for (i = 0; i < 8; i++) { state = 0; active = -1; @@ -1772,14 +1800,20 @@ hfcmulti_leds(struct hfc_multi *hc) } if (state) { if (state == active) { - lled |= 0 << i; + lled &= ~(1 << i); /* led on */ + hc->activity_tx |= hc->activity_rx; + if (!hc->flash[i] && + (hc->activity_tx & (1 << i))) + hc->flash[i] = poll; + if (hc->flash[i] < 1024) + lled |= 1 << i; /* led off */ + if (hc->flash[i] >= 2048) + hc->flash[i] = 0; + if (hc->flash[i]) + hc->flash[i] += poll; } else - if (hc->ledcount >> 11) - lled |= 0 << i; - else - lled |= 1 << i; - } else - lled |= 1 << i; + hc->flash[i] = 0; + } } leddw = lled << 24 | lled << 16 | lled << 8 | lled; if (leddw != hc->ledstate) { @@ -1794,6 +1828,8 @@ hfcmulti_leds(struct hfc_multi *hc) } break; } + hc->activity_tx = 0; + hc->activity_rx = 0; } /* * read dtmf coefficients @@ -2093,7 +2129,8 @@ next_frame: *txpending = 1; /* show activity */ - hc->activity[hc->chan[ch].port] = 1; + if (dch) + hc->activity_tx |= 1 << hc->chan[ch].port; /* fill fifo to what we have left */ ii = len; @@ -2129,13 +2166,9 @@ next_frame: HFC_wait_nodebug(hc); } - /* send confirm, since get_net_bframe will not do it with trans */ - if (bch && test_bit(FLG_TRANSPARENT, &bch->Flags)) - confirm_Bsend(bch); - - /* check for next frame */ dev_kfree_skb(*sp); - if (bch && get_next_bframe(bch)) { /* hdlc is confirmed here */ + /* check for next frame */ + if (bch && get_next_bframe(bch)) { len = (*sp)->len; goto next_frame; } @@ -2163,24 +2196,20 @@ hfcmulti_rx(struct hfc_multi *hc, int ch) int f1 = 0, f2 = 0; /* = 0, to make GCC happy */ int again = 0; struct bchannel *bch; - struct dchannel *dch; + struct dchannel *dch = NULL; struct sk_buff *skb, **sp = NULL; int maxlen; bch = hc->chan[ch].bch; - dch = hc->chan[ch].dch; - if ((!dch) && (!bch)) - return; - if (dch) { + if (bch) { + if (!test_bit(FLG_ACTIVE, &bch->Flags)) + return; + } else if (hc->chan[ch].dch) { + dch = hc->chan[ch].dch; if (!test_bit(FLG_ACTIVE, &dch->Flags)) return; - sp = &dch->rx_skb; - maxlen = dch->maxlen; } else { - if (!test_bit(FLG_ACTIVE, &bch->Flags)) - return; - sp = &bch->rx_skb; - maxlen = bch->maxlen; + return; } next_frame: /* on first AND before getting next valid frame, R_FIFO must be written @@ -2195,8 +2224,11 @@ next_frame: HFC_wait_nodebug(hc); /* ignore if rx is off BUT change fifo (above) to start pending TX */ - if (hc->chan[ch].rx_off) + if (hc->chan[ch].rx_off) { + if (bch) + bch->dropcnt += poll; /* not exact but fair enough */ return; + } if (dch || test_bit(FLG_HDLC, &bch->Flags)) { f1 = HFC_inb_nodebug(hc, A_F1); @@ -2227,16 +2259,30 @@ next_frame: if (Zsize <= 0) return; - if (*sp == NULL) { - *sp = mI_alloc_skb(maxlen + 3, GFP_ATOMIC); - if (*sp == NULL) { - printk(KERN_DEBUG "%s: No mem for rx_skb\n", - __func__); + if (bch) { + maxlen = bchannel_get_rxbuf(bch, Zsize); + if (maxlen < 0) { + pr_warning("card%d.B%d: No bufferspace for %d bytes\n", + hc->id + 1, bch->nr, Zsize); return; } + sp = &bch->rx_skb; + maxlen = bch->maxlen; + } else { /* Dchannel */ + sp = &dch->rx_skb; + maxlen = dch->maxlen + 3; + if (*sp == NULL) { + *sp = mI_alloc_skb(maxlen, GFP_ATOMIC); + if (*sp == NULL) { + pr_warning("card%d: No mem for dch rx_skb\n", + hc->id + 1); + return; + } + } } /* show activity */ - hc->activity[hc->chan[ch].port] = 1; + if (dch) + hc->activity_rx |= 1 << hc->chan[ch].port; /* empty fifo with what we have */ if (dch || test_bit(FLG_HDLC, &bch->Flags)) { @@ -2247,7 +2293,7 @@ next_frame: Zsize, z1, z2, (f1 == f2) ? "fragment" : "COMPLETE", f1, f2, Zsize + (*sp)->len, again); /* HDLC */ - if ((Zsize + (*sp)->len) > (maxlen + 3)) { + if ((Zsize + (*sp)->len) > maxlen) { if (debug & DEBUG_HFCMULTI_FIFO) printk(KERN_DEBUG "%s(card %d): hdlc-frame too large.\n", @@ -2309,7 +2355,7 @@ next_frame: if (dch) recv_Dchannel(dch); else - recv_Bchannel(bch, MISDN_ID_ANY); + recv_Bchannel(bch, MISDN_ID_ANY, false); *sp = skb; again++; goto next_frame; @@ -2317,32 +2363,14 @@ next_frame: /* there is an incomplete frame */ } else { /* transparent */ - if (Zsize > skb_tailroom(*sp)) - Zsize = skb_tailroom(*sp); hc->read_fifo(hc, skb_put(*sp, Zsize), Zsize); - if (((*sp)->len) < MISDN_COPY_SIZE) { - skb = *sp; - *sp = mI_alloc_skb(skb->len, GFP_ATOMIC); - if (*sp) { - memcpy(skb_put(*sp, skb->len), - skb->data, skb->len); - skb_trim(skb, 0); - } else { - printk(KERN_DEBUG "%s: No mem\n", __func__); - *sp = skb; - skb = NULL; - } - } else { - skb = NULL; - } if (debug & DEBUG_HFCMULTI_FIFO) printk(KERN_DEBUG "%s(card %d): fifo(%d) reading %d bytes " "(z1=%04x, z2=%04x) TRANS\n", __func__, hc->id + 1, ch, Zsize, z1, z2); /* only bch is transparent */ - recv_Bchannel(bch, hc->chan[ch].Zfill); - *sp = skb; + recv_Bchannel(bch, hc->chan[ch].Zfill, false); } } @@ -2430,55 +2458,55 @@ handle_timer_irq(struct hfc_multi *hc) } } if (hc->ctype == HFC_TYPE_E1 && hc->created[0]) { - dch = hc->chan[hc->dslot].dch; - if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dslot].cfg)) { - /* LOS */ - temp = HFC_inb_nodebug(hc, R_SYNC_STA) & V_SIG_LOS; - if (!temp && hc->chan[hc->dslot].los) + dch = hc->chan[hc->dnum[0]].dch; + /* LOS */ + temp = HFC_inb_nodebug(hc, R_SYNC_STA) & V_SIG_LOS; + hc->chan[hc->dnum[0]].los = temp; + if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dnum[0]].cfg)) { + if (!temp && hc->chan[hc->dnum[0]].los) signal_state_up(dch, L1_SIGNAL_LOS_ON, "LOS detected"); - if (temp && !hc->chan[hc->dslot].los) + if (temp && !hc->chan[hc->dnum[0]].los) signal_state_up(dch, L1_SIGNAL_LOS_OFF, "LOS gone"); - hc->chan[hc->dslot].los = temp; } - if (test_bit(HFC_CFG_REPORT_AIS, &hc->chan[hc->dslot].cfg)) { + if (test_bit(HFC_CFG_REPORT_AIS, &hc->chan[hc->dnum[0]].cfg)) { /* AIS */ temp = HFC_inb_nodebug(hc, R_SYNC_STA) & V_AIS; - if (!temp && hc->chan[hc->dslot].ais) + if (!temp && hc->chan[hc->dnum[0]].ais) signal_state_up(dch, L1_SIGNAL_AIS_ON, "AIS detected"); - if (temp && !hc->chan[hc->dslot].ais) + if (temp && !hc->chan[hc->dnum[0]].ais) signal_state_up(dch, L1_SIGNAL_AIS_OFF, "AIS gone"); - hc->chan[hc->dslot].ais = temp; + hc->chan[hc->dnum[0]].ais = temp; } - if (test_bit(HFC_CFG_REPORT_SLIP, &hc->chan[hc->dslot].cfg)) { + if (test_bit(HFC_CFG_REPORT_SLIP, &hc->chan[hc->dnum[0]].cfg)) { /* SLIP */ temp = HFC_inb_nodebug(hc, R_SLIP) & V_FOSLIP_RX; - if (!temp && hc->chan[hc->dslot].slip_rx) + if (!temp && hc->chan[hc->dnum[0]].slip_rx) signal_state_up(dch, L1_SIGNAL_SLIP_RX, " bit SLIP detected RX"); - hc->chan[hc->dslot].slip_rx = temp; + hc->chan[hc->dnum[0]].slip_rx = temp; temp = HFC_inb_nodebug(hc, R_SLIP) & V_FOSLIP_TX; - if (!temp && hc->chan[hc->dslot].slip_tx) + if (!temp && hc->chan[hc->dnum[0]].slip_tx) signal_state_up(dch, L1_SIGNAL_SLIP_TX, " bit SLIP detected TX"); - hc->chan[hc->dslot].slip_tx = temp; + hc->chan[hc->dnum[0]].slip_tx = temp; } - if (test_bit(HFC_CFG_REPORT_RDI, &hc->chan[hc->dslot].cfg)) { + if (test_bit(HFC_CFG_REPORT_RDI, &hc->chan[hc->dnum[0]].cfg)) { /* RDI */ temp = HFC_inb_nodebug(hc, R_RX_SL0_0) & V_A; - if (!temp && hc->chan[hc->dslot].rdi) + if (!temp && hc->chan[hc->dnum[0]].rdi) signal_state_up(dch, L1_SIGNAL_RDI_ON, "RDI detected"); - if (temp && !hc->chan[hc->dslot].rdi) + if (temp && !hc->chan[hc->dnum[0]].rdi) signal_state_up(dch, L1_SIGNAL_RDI_OFF, "RDI gone"); - hc->chan[hc->dslot].rdi = temp; + hc->chan[hc->dnum[0]].rdi = temp; } temp = HFC_inb_nodebug(hc, R_JATT_DIR); - switch (hc->chan[hc->dslot].sync) { + switch (hc->chan[hc->dnum[0]].sync) { case 0: if ((temp & 0x60) == 0x60) { if (debug & DEBUG_HFCMULTI_SYNC) @@ -2487,10 +2515,10 @@ handle_timer_irq(struct hfc_multi *hc) "in clock sync\n", __func__, hc->id); HFC_outb(hc, R_RX_OFF, - hc->chan[hc->dslot].jitter | V_RX_INIT); + hc->chan[hc->dnum[0]].jitter | V_RX_INIT); HFC_outb(hc, R_TX_OFF, - hc->chan[hc->dslot].jitter | V_RX_INIT); - hc->chan[hc->dslot].sync = 1; + hc->chan[hc->dnum[0]].jitter | V_RX_INIT); + hc->chan[hc->dnum[0]].sync = 1; goto check_framesync; } break; @@ -2501,7 +2529,7 @@ handle_timer_irq(struct hfc_multi *hc) "%s: (id=%d) E1 " "lost clock sync\n", __func__, hc->id); - hc->chan[hc->dslot].sync = 0; + hc->chan[hc->dnum[0]].sync = 0; break; } check_framesync: @@ -2512,7 +2540,7 @@ handle_timer_irq(struct hfc_multi *hc) "%s: (id=%d) E1 " "now in frame sync\n", __func__, hc->id); - hc->chan[hc->dslot].sync = 2; + hc->chan[hc->dnum[0]].sync = 2; } break; case 2: @@ -2522,7 +2550,7 @@ handle_timer_irq(struct hfc_multi *hc) "%s: (id=%d) E1 lost " "clock & frame sync\n", __func__, hc->id); - hc->chan[hc->dslot].sync = 0; + hc->chan[hc->dnum[0]].sync = 0; break; } temp = HFC_inb_nodebug(hc, R_SYNC_STA); @@ -2532,7 +2560,7 @@ handle_timer_irq(struct hfc_multi *hc) "%s: (id=%d) E1 " "lost frame sync\n", __func__, hc->id); - hc->chan[hc->dslot].sync = 1; + hc->chan[hc->dnum[0]].sync = 1; } break; } @@ -2673,7 +2701,7 @@ hfcmulti_interrupt(int intno, void *dev_id) int i; void __iomem *plx_acc; u_short wval; - u_char e1_syncsta, temp; + u_char e1_syncsta, temp, temp2; u_long flags; if (!hc) { @@ -2748,7 +2776,7 @@ hfcmulti_interrupt(int intno, void *dev_id) if (r_irq_misc & V_STA_IRQ) { if (hc->ctype == HFC_TYPE_E1) { /* state machine */ - dch = hc->chan[hc->dslot].dch; + dch = hc->chan[hc->dnum[0]].dch; e1_syncsta = HFC_inb_nodebug(hc, R_SYNC_STA); if (test_bit(HFC_CHIP_PLXSD, &hc->chip) && hc->e1_getclock) { @@ -2758,23 +2786,26 @@ hfcmulti_interrupt(int intno, void *dev_id) hc->syncronized = 0; } /* undocumented: status changes during read */ - dch->state = HFC_inb_nodebug(hc, R_E1_RD_STA); - while (dch->state != (temp = + temp = HFC_inb_nodebug(hc, R_E1_RD_STA); + while (temp != (temp2 = HFC_inb_nodebug(hc, R_E1_RD_STA))) { if (debug & DEBUG_HFCMULTI_STATE) printk(KERN_DEBUG "%s: reread " "STATE because %d!=%d\n", - __func__, temp, - dch->state); - dch->state = temp; /* repeat */ + __func__, temp, temp2); + temp = temp2; /* repeat */ } - dch->state = HFC_inb_nodebug(hc, R_E1_RD_STA) - & 0x7; - schedule_event(dch, FLG_PHCHANGE); + /* broadcast state change to all fragments */ if (debug & DEBUG_HFCMULTI_STATE) printk(KERN_DEBUG "%s: E1 (id=%d) newstate %x\n", - __func__, hc->id, dch->state); + __func__, hc->id, temp & 0x7); + for (i = 0; i < hc->ports; i++) { + dch = hc->chan[hc->dnum[i]].dch; + dch->state = temp & 0x7; + schedule_event(dch, FLG_PHCHANGE); + } + if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) plxsd_checksync(hc, 0); } @@ -3018,8 +3049,10 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, HFC_outb(hc, A_CON_HDLC, 0x20 | V_HDLC_TRP | V_IFF); HFC_outb(hc, A_SUBCH_CFG, 0); HFC_outb(hc, A_IRQ_MSK, 0); - HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); - HFC_wait(hc); + if (hc->chan[ch].protocol != protocol) { + HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); + HFC_wait(hc); + } HFC_outb(hc, R_SLOT, ((((ch / 4) * 8) + ((ch % 4) * 4) + 1) << 1) | 1); HFC_outb(hc, A_SL_CFG, 0x80 | 0x20 | (ch << 1) | 1); @@ -3039,8 +3072,10 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, HFC_outb(hc, A_CON_HDLC, 0x20 | V_HDLC_TRP | V_IFF); HFC_outb(hc, A_SUBCH_CFG, 0); HFC_outb(hc, A_IRQ_MSK, 0); - HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); - HFC_wait(hc); + if (hc->chan[ch].protocol != protocol) { + HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); + HFC_wait(hc); + } /* tx silence */ HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence); HFC_outb(hc, R_SLOT, (((ch / 4) * 8) + @@ -3059,8 +3094,10 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, V_HDLC_TRP | V_IFF); HFC_outb(hc, A_SUBCH_CFG, 0); HFC_outb(hc, A_IRQ_MSK, 0); - HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); - HFC_wait(hc); + if (hc->chan[ch].protocol != protocol) { + HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); + HFC_wait(hc); + } /* tx silence */ HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence); /* enable RX fifo */ @@ -3075,8 +3112,10 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, V_HDLC_TRP); HFC_outb(hc, A_SUBCH_CFG, 0); HFC_outb(hc, A_IRQ_MSK, 0); - HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); - HFC_wait(hc); + if (hc->chan[ch].protocol != protocol) { + HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); + HFC_wait(hc); + } } if (hc->ctype != HFC_TYPE_E1) { hc->hw.a_st_ctrl0[hc->chan[ch].port] |= @@ -3433,8 +3472,7 @@ handle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb) struct hfc_multi *hc = bch->hw; int ret = -EINVAL; struct mISDNhead *hh = mISDN_HEAD_P(skb); - unsigned int id; - u_long flags; + unsigned long flags; switch (hh->prim) { case PH_DATA_REQ: @@ -3443,19 +3481,13 @@ handle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb) spin_lock_irqsave(&hc->lock, flags); ret = bchannel_senddata(bch, skb); if (ret > 0) { /* direct TX */ - id = hh->id; /* skb can be freed */ hfcmulti_tx(hc, bch->slot); ret = 0; /* start fifo */ HFC_outb_nodebug(hc, R_FIFO, 0); HFC_wait_nodebug(hc); - if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) { - spin_unlock_irqrestore(&hc->lock, flags); - queue_ch_frame(ch, PH_DATA_CNF, id, NULL); - } else - spin_unlock_irqrestore(&hc->lock, flags); - } else - spin_unlock_irqrestore(&hc->lock, flags); + } + spin_unlock_irqrestore(&hc->lock, flags); return ret; case PH_ACTIVATE_REQ: if (debug & DEBUG_HFCMULTI_MSG) @@ -3545,10 +3577,11 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) switch (cq->op) { case MISDN_CTRL_GETOP: - cq->op = MISDN_CTRL_HFC_OP | MISDN_CTRL_HW_FEATURES_OP - | MISDN_CTRL_RX_OFF | MISDN_CTRL_FILL_EMPTY; + ret = mISDN_ctrl_bchannel(bch, cq); + cq->op |= MISDN_CTRL_HFC_OP | MISDN_CTRL_HW_FEATURES_OP; break; case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */ + ret = mISDN_ctrl_bchannel(bch, cq); hc->chan[bch->slot].rx_off = !!cq->p1; if (!hc->chan[bch->slot].rx_off) { /* reset fifo on rx on */ @@ -3561,11 +3594,10 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) printk(KERN_DEBUG "%s: RX_OFF request (nr=%d off=%d)\n", __func__, bch->nr, hc->chan[bch->slot].rx_off); break; - case MISDN_CTRL_FILL_EMPTY: /* fill fifo, if empty */ - test_and_set_bit(FLG_FILLEMPTY, &bch->Flags); - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: FILL_EMPTY request (nr=%d " - "off=%d)\n", __func__, bch->nr, !!cq->p1); + case MISDN_CTRL_FILL_EMPTY: + ret = mISDN_ctrl_bchannel(bch, cq); + hc->silence = bch->fill[0]; + memset(hc->silence_data, hc->silence, sizeof(hc->silence_data)); break; case MISDN_CTRL_HW_FEATURES: /* fill features structure */ if (debug & DEBUG_HFCMULTI_MSG) @@ -3654,9 +3686,7 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) ret = -EINVAL; break; default: - printk(KERN_WARNING "%s: unknown Op %x\n", - __func__, cq->op); - ret = -EINVAL; + ret = mISDN_ctrl_bchannel(bch, cq); break; } return ret; @@ -3676,8 +3706,7 @@ hfcm_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) switch (cmd) { case CLOSE_CHANNEL: test_and_clear_bit(FLG_OPEN, &bch->Flags); - if (test_bit(FLG_ACTIVE, &bch->Flags)) - deactivate_bchannel(bch); /* locked there */ + deactivate_bchannel(bch); /* locked there */ ch->protocol = ISDN_P_NONE; ch->peer = NULL; module_put(THIS_MODULE); @@ -3839,31 +3868,37 @@ hfcmulti_initmode(struct dchannel *dch) if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: entered\n", __func__); + i = dch->slot; + pt = hc->chan[i].port; if (hc->ctype == HFC_TYPE_E1) { - hc->chan[hc->dslot].slot_tx = -1; - hc->chan[hc->dslot].slot_rx = -1; - hc->chan[hc->dslot].conf = -1; - if (hc->dslot) { - mode_hfcmulti(hc, hc->dslot, dch->dev.D.protocol, + /* E1 */ + hc->chan[hc->dnum[pt]].slot_tx = -1; + hc->chan[hc->dnum[pt]].slot_rx = -1; + hc->chan[hc->dnum[pt]].conf = -1; + if (hc->dnum[pt]) { + mode_hfcmulti(hc, dch->slot, dch->dev.D.protocol, -1, 0, -1, 0); dch->timer.function = (void *) hfcmulti_dbusy_timer; dch->timer.data = (long) dch; init_timer(&dch->timer); } for (i = 1; i <= 31; i++) { - if (i == hc->dslot) + if (!((1 << i) & hc->bmask[pt])) /* skip unused chan */ continue; hc->chan[i].slot_tx = -1; hc->chan[i].slot_rx = -1; hc->chan[i].conf = -1; mode_hfcmulti(hc, i, ISDN_P_NONE, -1, 0, -1, 0); } - /* E1 */ - if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dslot].cfg)) { + } + if (hc->ctype == HFC_TYPE_E1 && pt == 0) { + /* E1, port 0 */ + dch = hc->chan[hc->dnum[0]].dch; + if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dnum[0]].cfg)) { HFC_outb(hc, R_LOS0, 255); /* 2 ms */ HFC_outb(hc, R_LOS1, 255); /* 512 ms */ } - if (test_bit(HFC_CFG_OPTICAL, &hc->chan[hc->dslot].cfg)) { + if (test_bit(HFC_CFG_OPTICAL, &hc->chan[hc->dnum[0]].cfg)) { HFC_outb(hc, R_RX0, 0); hc->hw.r_tx0 = 0 | V_OUT_EN; } else { @@ -3876,12 +3911,12 @@ hfcmulti_initmode(struct dchannel *dch) HFC_outb(hc, R_TX_FR0, 0x00); HFC_outb(hc, R_TX_FR1, 0xf8); - if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dslot].cfg)) + if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dnum[0]].cfg)) HFC_outb(hc, R_TX_FR2, V_TX_MF | V_TX_E | V_NEG_E); HFC_outb(hc, R_RX_FR0, V_AUTO_RESYNC | V_AUTO_RECO | 0); - if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dslot].cfg)) + if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dnum[0]].cfg)) HFC_outb(hc, R_RX_FR1, V_RX_MF | V_RX_MF_SYNC); if (dch->dev.D.protocol == ISDN_P_NT_E1) { @@ -3944,13 +3979,14 @@ hfcmulti_initmode(struct dchannel *dch) hc->syncronized = 0; plxsd_checksync(hc, 0); } - } else { - i = dch->slot; + } + if (hc->ctype != HFC_TYPE_E1) { + /* ST */ hc->chan[i].slot_tx = -1; hc->chan[i].slot_rx = -1; hc->chan[i].conf = -1; mode_hfcmulti(hc, i, dch->dev.D.protocol, -1, 0, -1, 0); - dch->timer.function = (void *)hfcmulti_dbusy_timer; + dch->timer.function = (void *) hfcmulti_dbusy_timer; dch->timer.data = (long) dch; init_timer(&dch->timer); hc->chan[i - 2].slot_tx = -1; @@ -3961,8 +3997,6 @@ hfcmulti_initmode(struct dchannel *dch) hc->chan[i - 1].slot_rx = -1; hc->chan[i - 1].conf = -1; mode_hfcmulti(hc, i - 1, ISDN_P_NONE, -1, 0, -1, 0); - /* ST */ - pt = hc->chan[i].port; /* select interface */ HFC_outb(hc, R_ST_SEL, pt); /* undocumented: delay after R_ST_SEL */ @@ -4054,14 +4088,9 @@ open_dchannel(struct hfc_multi *hc, struct dchannel *dch, hfcmulti_initmode(dch); spin_unlock_irqrestore(&hc->lock, flags); } - - if (((rq->protocol == ISDN_P_NT_S0) && (dch->state == 3)) || - ((rq->protocol == ISDN_P_TE_S0) && (dch->state == 7)) || - ((rq->protocol == ISDN_P_NT_E1) && (dch->state == 1)) || - ((rq->protocol == ISDN_P_TE_E1) && (dch->state == 1))) { + if (test_bit(FLG_ACTIVE, &dch->Flags)) _queue_data(&dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY, 0, NULL, GFP_KERNEL); - } rq->ch = &dch->dev.D; if (!try_module_get(THIS_MODULE)) printk(KERN_WARNING "%s:cannot get module\n", __func__); @@ -4091,7 +4120,6 @@ open_bchannel(struct hfc_multi *hc, struct dchannel *dch, } if (test_and_set_bit(FLG_OPEN, &bch->Flags)) return -EBUSY; /* b-channel can be only open once */ - test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); bch->ch.protocol = rq->protocol; hc->chan[ch].rx_off = 0; rq->ch = &bch->ch; @@ -4112,7 +4140,7 @@ channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq) switch (cq->op) { case MISDN_CTRL_GETOP: - cq->op = MISDN_CTRL_HFC_OP; + cq->op = MISDN_CTRL_HFC_OP | MISDN_CTRL_L1_TIMER3; break; case MISDN_CTRL_HFC_WD_INIT: /* init the watchdog */ wd_cnt = cq->p1 & 0xf; @@ -4142,6 +4170,9 @@ channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq) __func__); HFC_outb(hc, R_BERT_WD_MD, hc->hw.r_bert_wd_md | V_WD_RES); break; + case MISDN_CTRL_L1_TIMER3: + ret = l1_event(dch->l1, HW_TIMER3_VALUE | (cq->p1 & 0xff)); + break; default: printk(KERN_WARNING "%s: unknown Op %x\n", __func__, cq->op); @@ -4545,6 +4576,8 @@ release_port(struct hfc_multi *hc, struct dchannel *dch) } /* free channels */ for (i = 0; i <= 31; i++) { + if (!((1 << i) & hc->bmask[pt])) /* skip unused chan */ + continue; if (hc->chan[i].bch) { if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG @@ -4600,7 +4633,8 @@ release_port(struct hfc_multi *hc, struct dchannel *dch) spin_unlock_irqrestore(&hc->lock, flags); if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: free port %d channel D\n", __func__, pt); + printk(KERN_DEBUG "%s: free port %d channel D(%d)\n", __func__, + pt+1, ci); mISDN_freedchannel(dch); kfree(dch); @@ -4622,15 +4656,19 @@ release_card(struct hfc_multi *hc) if (hc->iclock) mISDN_unregister_clock(hc->iclock); - /* disable irq */ + /* disable and free irq */ spin_lock_irqsave(&hc->lock, flags); disable_hwirq(hc); spin_unlock_irqrestore(&hc->lock, flags); udelay(1000); + if (hc->irq) { + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: free irq %d (hc=%p)\n", + __func__, hc->irq, hc); + free_irq(hc->irq, hc); + hc->irq = 0; - /* dimm leds */ - if (hc->leds) - hfcmulti_leds(hc); + } /* disable D-channels & B-channels */ if (debug & DEBUG_HFCMULTI_INIT) @@ -4641,15 +4679,11 @@ release_card(struct hfc_multi *hc) release_port(hc, hc->chan[ch].dch); } - /* release hardware & irq */ - if (hc->irq) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: free irq %d\n", - __func__, hc->irq); - free_irq(hc->irq, hc); - hc->irq = 0; + /* dimm leds */ + if (hc->leds) + hfcmulti_leds(hc); - } + /* release hardware */ release_io_hfcmulti(hc); if (debug & DEBUG_HFCMULTI_INIT) @@ -4667,61 +4701,9 @@ release_card(struct hfc_multi *hc) __func__); } -static int -init_e1_port(struct hfc_multi *hc, struct hm_map *m) +static void +init_e1_port_hw(struct hfc_multi *hc, struct hm_map *m) { - struct dchannel *dch; - struct bchannel *bch; - int ch, ret = 0; - char name[MISDN_MAX_IDLEN]; - - dch = kzalloc(sizeof(struct dchannel), GFP_KERNEL); - if (!dch) - return -ENOMEM; - dch->debug = debug; - mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, ph_state_change); - dch->hw = hc; - dch->dev.Dprotocols = (1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1); - dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | - (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); - dch->dev.D.send = handle_dmsg; - dch->dev.D.ctrl = hfcm_dctrl; - dch->dev.nrbchan = (hc->dslot) ? 30 : 31; - dch->slot = hc->dslot; - hc->chan[hc->dslot].dch = dch; - hc->chan[hc->dslot].port = 0; - hc->chan[hc->dslot].nt_timer = -1; - for (ch = 1; ch <= 31; ch++) { - if (ch == hc->dslot) /* skip dchannel */ - continue; - bch = kzalloc(sizeof(struct bchannel), GFP_KERNEL); - if (!bch) { - printk(KERN_ERR "%s: no memory for bchannel\n", - __func__); - ret = -ENOMEM; - goto free_chan; - } - hc->chan[ch].coeff = kzalloc(512, GFP_KERNEL); - if (!hc->chan[ch].coeff) { - printk(KERN_ERR "%s: no memory for coeffs\n", - __func__); - ret = -ENOMEM; - kfree(bch); - goto free_chan; - } - bch->nr = ch; - bch->slot = ch; - bch->debug = debug; - mISDN_initbchannel(bch, MAX_DATA_MEM); - bch->hw = hc; - bch->ch.send = handle_bmsg; - bch->ch.ctrl = hfcm_bctrl; - bch->ch.nr = ch; - list_add(&bch->ch.list, &dch->dev.bchannels); - hc->chan[ch].bch = bch; - hc->chan[ch].port = 0; - set_channelmap(bch->nr, dch->dev.channelmap); - } /* set optical line type */ if (port[Port_cnt] & 0x001) { if (!m->opticalsupport) { @@ -4737,7 +4719,7 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m) __func__, HFC_cnt + 1, 1); test_and_set_bit(HFC_CFG_OPTICAL, - &hc->chan[hc->dslot].cfg); + &hc->chan[hc->dnum[0]].cfg); } } /* set LOS report */ @@ -4747,7 +4729,7 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m) "LOS report: card(%d) port(%d)\n", __func__, HFC_cnt + 1, 1); test_and_set_bit(HFC_CFG_REPORT_LOS, - &hc->chan[hc->dslot].cfg); + &hc->chan[hc->dnum[0]].cfg); } /* set AIS report */ if (port[Port_cnt] & 0x008) { @@ -4756,7 +4738,7 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m) "AIS report: card(%d) port(%d)\n", __func__, HFC_cnt + 1, 1); test_and_set_bit(HFC_CFG_REPORT_AIS, - &hc->chan[hc->dslot].cfg); + &hc->chan[hc->dnum[0]].cfg); } /* set SLIP report */ if (port[Port_cnt] & 0x010) { @@ -4766,7 +4748,7 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m) "card(%d) port(%d)\n", __func__, HFC_cnt + 1, 1); test_and_set_bit(HFC_CFG_REPORT_SLIP, - &hc->chan[hc->dslot].cfg); + &hc->chan[hc->dnum[0]].cfg); } /* set RDI report */ if (port[Port_cnt] & 0x020) { @@ -4776,7 +4758,7 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m) "card(%d) port(%d)\n", __func__, HFC_cnt + 1, 1); test_and_set_bit(HFC_CFG_REPORT_RDI, - &hc->chan[hc->dslot].cfg); + &hc->chan[hc->dnum[0]].cfg); } /* set CRC-4 Mode */ if (!(port[Port_cnt] & 0x100)) { @@ -4785,7 +4767,7 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m) " card(%d) port(%d)\n", __func__, HFC_cnt + 1, 1); test_and_set_bit(HFC_CFG_CRC4, - &hc->chan[hc->dslot].cfg); + &hc->chan[hc->dnum[0]].cfg); } else { if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: PORT turn off CRC4" @@ -4817,20 +4799,85 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m) } /* set elastic jitter buffer */ if (port[Port_cnt] & 0x3000) { - hc->chan[hc->dslot].jitter = (port[Port_cnt]>>12) & 0x3; + hc->chan[hc->dnum[0]].jitter = (port[Port_cnt]>>12) & 0x3; if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: PORT set elastic " "buffer to %d: card(%d) port(%d)\n", - __func__, hc->chan[hc->dslot].jitter, + __func__, hc->chan[hc->dnum[0]].jitter, HFC_cnt + 1, 1); } else - hc->chan[hc->dslot].jitter = 2; /* default */ - snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-e1.%d", HFC_cnt + 1); + hc->chan[hc->dnum[0]].jitter = 2; /* default */ +} + +static int +init_e1_port(struct hfc_multi *hc, struct hm_map *m, int pt) +{ + struct dchannel *dch; + struct bchannel *bch; + int ch, ret = 0; + char name[MISDN_MAX_IDLEN]; + int bcount = 0; + + dch = kzalloc(sizeof(struct dchannel), GFP_KERNEL); + if (!dch) + return -ENOMEM; + dch->debug = debug; + mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, ph_state_change); + dch->hw = hc; + dch->dev.Dprotocols = (1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1); + dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | + (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); + dch->dev.D.send = handle_dmsg; + dch->dev.D.ctrl = hfcm_dctrl; + dch->slot = hc->dnum[pt]; + hc->chan[hc->dnum[pt]].dch = dch; + hc->chan[hc->dnum[pt]].port = pt; + hc->chan[hc->dnum[pt]].nt_timer = -1; + for (ch = 1; ch <= 31; ch++) { + if (!((1 << ch) & hc->bmask[pt])) /* skip unused channel */ + continue; + bch = kzalloc(sizeof(struct bchannel), GFP_KERNEL); + if (!bch) { + printk(KERN_ERR "%s: no memory for bchannel\n", + __func__); + ret = -ENOMEM; + goto free_chan; + } + hc->chan[ch].coeff = kzalloc(512, GFP_KERNEL); + if (!hc->chan[ch].coeff) { + printk(KERN_ERR "%s: no memory for coeffs\n", + __func__); + ret = -ENOMEM; + kfree(bch); + goto free_chan; + } + bch->nr = ch; + bch->slot = ch; + bch->debug = debug; + mISDN_initbchannel(bch, MAX_DATA_MEM, poll >> 1); + bch->hw = hc; + bch->ch.send = handle_bmsg; + bch->ch.ctrl = hfcm_bctrl; + bch->ch.nr = ch; + list_add(&bch->ch.list, &dch->dev.bchannels); + hc->chan[ch].bch = bch; + hc->chan[ch].port = pt; + set_channelmap(bch->nr, dch->dev.channelmap); + bcount++; + } + dch->dev.nrbchan = bcount; + if (pt == 0) + init_e1_port_hw(hc, m); + if (hc->ports > 1) + snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-e1.%d-%d", + HFC_cnt + 1, pt+1); + else + snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-e1.%d", HFC_cnt + 1); ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name); if (ret) goto free_chan; - hc->created[0] = 1; + hc->created[pt] = 1; return ret; free_chan: release_port(hc, dch); @@ -4881,7 +4928,7 @@ init_multi_port(struct hfc_multi *hc, int pt) bch->nr = ch + 1; bch->slot = i + ch; bch->debug = debug; - mISDN_initbchannel(bch, MAX_DATA_MEM); + mISDN_initbchannel(bch, MAX_DATA_MEM, poll >> 1); bch->hw = hc; bch->ch.send = handle_bmsg; bch->ch.ctrl = hfcm_bctrl; @@ -4963,7 +5010,8 @@ hfcmulti_init(struct hm_map *m, struct pci_dev *pdev, struct hfc_multi *hc; u_long flags; u_char dips = 0, pmj = 0; /* dip settings, port mode Jumpers */ - int i; + int i, ch; + u_int maskcheck; if (HFC_cnt >= MAX_CARDS) { printk(KERN_ERR "too many cards (max=%d).\n", @@ -4997,18 +5045,36 @@ hfcmulti_init(struct hm_map *m, struct pci_dev *pdev, hc->id = HFC_cnt; hc->pcm = pcm[HFC_cnt]; hc->io_mode = iomode[HFC_cnt]; - if (dslot[HFC_cnt] < 0 && hc->ctype == HFC_TYPE_E1) { - hc->dslot = 0; - printk(KERN_INFO "HFC-E1 card has disabled D-channel, but " - "31 B-channels\n"); - } - if (dslot[HFC_cnt] > 0 && dslot[HFC_cnt] < 32 - && hc->ctype == HFC_TYPE_E1) { - hc->dslot = dslot[HFC_cnt]; - printk(KERN_INFO "HFC-E1 card has alternating D-channel on " - "time slot %d\n", dslot[HFC_cnt]); - } else - hc->dslot = 16; + if (hc->ctype == HFC_TYPE_E1 && dmask[E1_cnt]) { + /* fragment card */ + pt = 0; + maskcheck = 0; + for (ch = 0; ch <= 31; ch++) { + if (!((1 << ch) & dmask[E1_cnt])) + continue; + hc->dnum[pt] = ch; + hc->bmask[pt] = bmask[bmask_cnt++]; + if ((maskcheck & hc->bmask[pt]) + || (dmask[E1_cnt] & hc->bmask[pt])) { + printk(KERN_INFO + "HFC-E1 #%d has overlapping B-channels on fragment #%d\n", + E1_cnt + 1, pt); + return -EINVAL; + } + maskcheck |= hc->bmask[pt]; + printk(KERN_INFO + "HFC-E1 #%d uses D-channel on slot %d and a B-channel map of 0x%08x\n", + E1_cnt + 1, ch, hc->bmask[pt]); + pt++; + } + hc->ports = pt; + } + if (hc->ctype == HFC_TYPE_E1 && !dmask[E1_cnt]) { + /* default card layout */ + hc->dnum[0] = 16; + hc->bmask[0] = 0xfffefffe; + hc->ports = 1; + } /* set chip specific features */ hc->masterclk = -1; @@ -5091,23 +5157,33 @@ hfcmulti_init(struct hm_map *m, struct pci_dev *pdev, goto free_card; } if (hc->ctype == HFC_TYPE_E1) - ret_err = init_e1_port(hc, m); + ret_err = init_e1_port(hc, m, pt); else ret_err = init_multi_port(hc, pt); if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG - "%s: Registering D-channel, card(%d) port(%d)" + "%s: Registering D-channel, card(%d) port(%d) " "result %d\n", - __func__, HFC_cnt + 1, pt, ret_err); + __func__, HFC_cnt + 1, pt + 1, ret_err); if (ret_err) { while (pt) { /* release already registered ports */ pt--; - release_port(hc, hc->chan[(pt << 2) + 2].dch); + if (hc->ctype == HFC_TYPE_E1) + release_port(hc, + hc->chan[hc->dnum[pt]].dch); + else + release_port(hc, + hc->chan[(pt << 2) + 2].dch); } goto free_card; } - Port_cnt++; + if (hc->ctype != HFC_TYPE_E1) + Port_cnt++; /* for each S0 port */ + } + if (hc->ctype == HFC_TYPE_E1) { + Port_cnt++; /* for each E1 port */ + E1_cnt++; } /* disp switches */ |