diff --git a/linux-kernel/linux-2.6.30-hfcmulti-multibts.patch b/linux-kernel/linux-2.6.30-hfcmulti-multibts.patch new file mode 100644 index 000000000..bb94d342f --- /dev/null +++ b/linux-kernel/linux-2.6.30-hfcmulti-multibts.patch @@ -0,0 +1,486 @@ +This experimental patch splits one E1 card into three virtual cards, + +TS 1,2,3,4,5 is card 0 +TS 6,7,8,9,10 is card 1 +TS 11,12,13,14 is card 2 + +This allows you to run one L2 TEI handler on each of the virtual cards, +which is required if you want to run multiple BTS on a single E1 link. + +Thanks to Andreas Eversberg for this patch. + +diff --git a/drivers/isdn/hardware/mISDN/hfc_multi.h b/drivers/isdn/hardware/mISDN/hfc_multi.h +index 0c77386..02dd4a1 100644 +--- a/drivers/isdn/hardware/mISDN/hfc_multi.h ++++ b/drivers/isdn/hardware/mISDN/hfc_multi.h +@@ -209,14 +209,17 @@ struct hfc_multi { + u_long ledstate; /* save last state of leds */ + int opticalsupport; /* has the e1 board */ + /* an optical Interface */ +- int dslot; /* channel # of d-channel (E1) default 16 */ ++ ++ u_int bmask[32]; /* bitmask of bchannels for port */ ++ u_char dnum[32]; /* array of used dchannel numbers for port */ ++ u_char created[32]; /* what port is created */ ++ u_int activity[32]; /* if there is any action on this */ ++ /* port (will be cleared after */ ++ /* showing led-states) */ + + u_long wdcount; /* every 500 ms we need to */ + /* send the watchdog a signal */ + u_char wdbyte; /* watchdog toggle byte */ +- u_int activity[8]; /* if there is any action on this */ +- /* port (will be cleared after */ +- /* showing led-states) */ + int e1_state; /* keep track of last state */ + int e1_getclock; /* if sync is retrieved from interface */ + int syncronized; /* keep track of existing sync interface */ +@@ -233,7 +236,6 @@ struct hfc_multi { + * the bch->channel is equvalent to the hfc-channel + */ + struct hfc_chan chan[32]; +- u_char created[8]; /* what port is created */ + signed char slot_owner[256]; /* owner channel of slot */ + }; + +diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c +index e1dab30..4fe2d27 100644 +--- a/drivers/isdn/hardware/mISDN/hfcmulti.c ++++ b/drivers/isdn/hardware/mISDN/hfcmulti.c +@@ -1619,8 +1619,8 @@ hfcmulti_leds(struct hfc_multi *hc) + * left red: frame sync, but no L1 + * right green: L2 active + */ +- if (hc->chan[hc->dslot].sync != 2) { /* no frame sync */ +- if (hc->chan[hc->dslot].dch->dev.D.protocol ++ if (hc->chan[hc->dnum[0]].sync != 2) { /* no frame sync */ ++ if (hc->chan[hc->dnum[0]].dch->dev.D.protocol + != ISDN_P_NT_E1) { + led[0] = 1; + led[1] = 1; +@@ -2428,55 +2428,56 @@ 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)) { ++#warning todo: put interface parameters to hc ++ dch = hc->chan[hc->dnum[0]].dch; ++ if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dnum[0]].cfg)) { + /* LOS */ + temp = HFC_inb_nodebug(hc, R_SYNC_STA) & V_SIG_LOS; +- if (!temp && hc->chan[hc->dslot].los) ++ 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; ++ hc->chan[hc->dnum[0]].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) +@@ -2485,10 +2486,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; +@@ -2499,7 +2500,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: +@@ -2510,7 +2511,7 @@ check_framesync: + "%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: +@@ -2520,7 +2521,7 @@ check_framesync: + "%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); +@@ -2530,7 +2531,7 @@ check_framesync: + "%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; + } +@@ -2746,7 +2747,8 @@ 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; ++#warning todo ++ 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) { +@@ -2768,7 +2770,15 @@ hfcmulti_interrupt(int intno, void *dev_id) + } + dch->state = HFC_inb_nodebug(hc, R_E1_RD_STA) + & 0x7; ++#warning todo hack!!! broadcast state change!!! ++ dch = hc->chan[hc->dnum[0]].dch; + schedule_event(dch, FLG_PHCHANGE); ++ dch = hc->chan[hc->dnum[1]].dch; ++ dch->state = HFC_inb_nodebug(hc, R_E1_RD_STA) ++ & 0x7; ++ schedule_event(dch, FLG_PHCHANGE); ++ ++ + if (debug & DEBUG_HFCMULTI_STATE) + printk(KERN_DEBUG + "%s: E1 (id=%d) newstate %x\n", +@@ -3851,31 +3861,35 @@ 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 */ ++#warning todo: don''t do it if dnum == 0 ++ 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 channel */ + 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)) { ++#warning todo (global) ++ if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dnum[pt]].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[pt]].cfg)) { + HFC_outb(hc, R_RX0, 0); + hc->hw.r_tx0 = 0 | V_OUT_EN; + } else { +@@ -3888,12 +3902,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[pt]].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[pt]].cfg)) + HFC_outb(hc, R_RX_FR1, V_RX_MF | V_RX_MF_SYNC); + + if (dch->dev.D.protocol == ISDN_P_NT_E1) { +@@ -3957,7 +3971,7 @@ hfcmulti_initmode(struct dchannel *dch) + plxsd_checksync(hc, 0); + } + } else { +- i = dch->slot; ++ /* ST */ + hc->chan[i].slot_tx = -1; + hc->chan[i].slot_rx = -1; + hc->chan[i].conf = -1; +@@ -3973,8 +3987,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 */ +@@ -4557,6 +4569,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 channel */ ++ continue; + if (hc->chan[i].bch) { + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG +@@ -4680,12 +4694,13 @@ release_card(struct hfc_multi *hc) + } + + static int +-init_e1_port(struct hfc_multi *hc, struct hm_map *m) ++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) +@@ -4698,13 +4713,12 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m) + (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; ++ 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 (ch == hc->dslot) /* skip dchannel */ ++ if (!((1 << ch) & hc->bmask[pt])) /* skip unused channel */ + continue; + bch = kzalloc(sizeof(struct bchannel), GFP_KERNEL); + if (!bch) { +@@ -4733,7 +4747,10 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m) + hc->chan[ch].bch = bch; + hc->chan[ch].port = 0; + set_channelmap(bch->nr, dch->dev.channelmap); ++ bcount++; + } ++ dch->dev.nrbchan = bcount; ++#warning todo: must be set globally, and must be a seperate function + /* set optical line type */ + if (port[Port_cnt] & 0x001) { + if (!m->opticalsupport) { +@@ -4749,7 +4766,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[pt]].cfg); + } + } + /* set LOS report */ +@@ -4759,7 +4776,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[pt]].cfg); + } + /* set AIS report */ + if (port[Port_cnt] & 0x008) { +@@ -4768,7 +4785,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[pt]].cfg); + } + /* set SLIP report */ + if (port[Port_cnt] & 0x010) { +@@ -4778,7 +4795,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[pt]].cfg); + } + /* set RDI report */ + if (port[Port_cnt] & 0x020) { +@@ -4788,7 +4805,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[pt]].cfg); + } + /* set CRC-4 Mode */ + if (!(port[Port_cnt] & 0x100)) { +@@ -4797,7 +4814,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[pt]].cfg); + } else { + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: PORT turn off CRC4" +@@ -4829,20 +4846,23 @@ 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[pt]].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[pt]].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[pt]].jitter = 2; /* default */ ++ 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); +@@ -5009,18 +5029,30 @@ 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]; ++#warning todo: rework module parameters for customizing e1 fragments.... yea, let''s call it: fragments + if (dslot[HFC_cnt] < 0 && hc->ctype == HFC_TYPE_E1) { +- hc->dslot = 0; ++ hc->dnum[0] = 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]; ++ hc->dnum[0] = 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; ++ hc->dnum[0] = 16; ++ ++#warning todo HACK!!! just a small map of two "fragments" ++ if (hc->ctype == HFC_TYPE_E1) { ++ hc->dnum[0] = 1; ++ hc->bmask[0] = 0x0000003c; ++ hc->dnum[1] = 6; ++ hc->bmask[1] = 0x00000780; ++ hc->dnum[2] = 11; ++ hc->bmask[2] = 0x00007800; ++ hc->ports = 3; ++ } + + /* set chip specific features */ + hc->masterclk = -1; +@@ -5103,7 +5135,7 @@ 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) +@@ -5115,10 +5147,14 @@ hfcmulti_init(struct hm_map *m, struct pci_dev *pdev, + 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; + } ++#warning todo: count it right, add additional "fragment" counter... + Port_cnt++; + } +