|
@@ -103,14 +103,26 @@
|
|
* Omit this value, if all cards are interconnected or none is connected.
|
|
* Omit this value, if all cards are interconnected or none is connected.
|
|
* If unsure, don't give this parameter.
|
|
* 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!
|
|
* If you don't know how to use it, you don't need it!
|
|
*
|
|
*
|
|
* iomode:
|
|
* iomode:
|
|
@@ -172,6 +184,7 @@
|
|
|
|
|
|
#define MAX_CARDS 8
|
|
#define MAX_CARDS 8
|
|
#define MAX_PORTS (8 * MAX_CARDS)
|
|
#define MAX_PORTS (8 * MAX_CARDS)
|
|
|
|
+#define MAX_FRAGS (32 * MAX_CARDS)
|
|
|
|
|
|
static LIST_HEAD(HFClist);
|
|
static LIST_HEAD(HFClist);
|
|
static spinlock_t HFClock; /* global hfc list lock */
|
|
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 uint type[MAX_CARDS];
|
|
static int pcm[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 iomode[MAX_CARDS];
|
|
static uint port[MAX_PORTS];
|
|
static uint port[MAX_PORTS];
|
|
static uint debug;
|
|
static uint debug;
|
|
@@ -218,7 +232,7 @@ static uint clockdelay_nt = CLKDEL_NT;
|
|
#define HWID_MINIP16 3
|
|
#define HWID_MINIP16 3
|
|
static uint hwid = HWID_NONE;
|
|
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_AUTHOR("Andreas Eversberg");
|
|
MODULE_LICENSE("GPL");
|
|
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(clockdelay_nt, uint, S_IRUGO | S_IWUSR);
|
|
module_param_array(type, uint, NULL, 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(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(iomode, uint, NULL, S_IRUGO | S_IWUSR);
|
|
module_param_array(port, 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 */
|
|
module_param(hwid, uint, S_IRUGO | S_IWUSR); /* The hardware ID */
|
|
@@ -1156,7 +1171,7 @@ init_chip(struct hfc_multi *hc)
|
|
hc->DTMFbase = 0x1000;
|
|
hc->DTMFbase = 0x1000;
|
|
if (test_bit(HFC_CHIP_EXRAM_128, &hc->chip)) {
|
|
if (test_bit(HFC_CHIP_EXRAM_128, &hc->chip)) {
|
|
if (debug & DEBUG_HFCMULTI_INIT)
|
|
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__);
|
|
__func__);
|
|
hc->hw.r_ctrl |= V_EXT_RAM;
|
|
hc->hw.r_ctrl |= V_EXT_RAM;
|
|
hc->hw.r_ram_sz = 1;
|
|
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 (test_bit(HFC_CHIP_EXRAM_512, &hc->chip)) {
|
|
if (debug & DEBUG_HFCMULTI_INIT)
|
|
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__);
|
|
__func__);
|
|
hc->hw.r_ctrl |= V_EXT_RAM;
|
|
hc->hw.r_ctrl |= V_EXT_RAM;
|
|
hc->hw.r_ram_sz = 2;
|
|
hc->hw.r_ram_sz = 2;
|
|
@@ -1607,40 +1622,46 @@ hfcmulti_leds(struct hfc_multi *hc)
|
|
struct dchannel *dch;
|
|
struct dchannel *dch;
|
|
int led[4];
|
|
int led[4];
|
|
|
|
|
|
- hc->ledcount += poll;
|
|
|
|
- if (hc->ledcount > 4096) {
|
|
|
|
- hc->ledcount -= 4096;
|
|
|
|
- hc->ledstate = 0xAFFEAFFE;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
switch (hc->leds) {
|
|
switch (hc->leds) {
|
|
case 1: /* HFC-E1 OEM */
|
|
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;
|
|
led[1] = 1;
|
|
- } else if (hc->ledcount >> 11) {
|
|
|
|
|
|
+ if (hc->e1_state != 1) {
|
|
led[0] = 1;
|
|
led[0] = 1;
|
|
- led[1] = 1;
|
|
|
|
|
|
+ hc->flash[2] = 0;
|
|
|
|
+ hc->flash[3] = 0;
|
|
} else {
|
|
} 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 = (led[0] | (led[1]<<2) | (led[2]<<1) | (led[3]<<3))^0xF;
|
|
/* leds are inverted */
|
|
/* leds are inverted */
|
|
@@ -1651,9 +1672,9 @@ hfcmulti_leds(struct hfc_multi *hc)
|
|
break;
|
|
break;
|
|
|
|
|
|
case 2: /* HFC-4S OEM */
|
|
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++) {
|
|
for (i = 0; i < 4; i++) {
|
|
state = 0;
|
|
state = 0;
|
|
@@ -1669,17 +1690,20 @@ hfcmulti_leds(struct hfc_multi *hc)
|
|
if (state) {
|
|
if (state) {
|
|
if (state == active) {
|
|
if (state == active) {
|
|
led[i] = 1; /* led green */
|
|
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
|
|
} else
|
|
led[i] = 0; /* led off */
|
|
led[i] = 0; /* led off */
|
|
}
|
|
}
|
|
@@ -1712,9 +1736,9 @@ hfcmulti_leds(struct hfc_multi *hc)
|
|
break;
|
|
break;
|
|
|
|
|
|
case 3: /* HFC 1S/2S Beronet */
|
|
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++) {
|
|
for (i = 0; i < 2; i++) {
|
|
state = 0;
|
|
state = 0;
|
|
@@ -1730,22 +1754,23 @@ hfcmulti_leds(struct hfc_multi *hc)
|
|
if (state) {
|
|
if (state) {
|
|
if (state == active) {
|
|
if (state == active) {
|
|
led[i] = 1; /* led green */
|
|
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
|
|
} else
|
|
led[i] = 0; /* led off */
|
|
led[i] = 0; /* led off */
|
|
}
|
|
}
|
|
-
|
|
|
|
-
|
|
|
|
leds = (led[0] > 0) | ((led[1] > 0) << 1) | ((led[0]&1) << 2)
|
|
leds = (led[0] > 0) | ((led[1] > 0) << 1) | ((led[0]&1) << 2)
|
|
| ((led[1]&1) << 3);
|
|
| ((led[1]&1) << 3);
|
|
if (leds != (int)hc->ledstate) {
|
|
if (leds != (int)hc->ledstate) {
|
|
@@ -1757,8 +1782,11 @@ hfcmulti_leds(struct hfc_multi *hc)
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
case 8: /* HFC 8S+ Beronet */
|
|
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++) {
|
|
for (i = 0; i < 8; i++) {
|
|
state = 0;
|
|
state = 0;
|
|
active = -1;
|
|
active = -1;
|
|
@@ -1772,14 +1800,20 @@ hfcmulti_leds(struct hfc_multi *hc)
|
|
}
|
|
}
|
|
if (state) {
|
|
if (state) {
|
|
if (state == active) {
|
|
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
|
|
} 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;
|
|
leddw = lled << 24 | lled << 16 | lled << 8 | lled;
|
|
if (leddw != hc->ledstate) {
|
|
if (leddw != hc->ledstate) {
|
|
@@ -1794,6 +1828,8 @@ hfcmulti_leds(struct hfc_multi *hc)
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
+ hc->activity_tx = 0;
|
|
|
|
+ hc->activity_rx = 0;
|
|
}
|
|
}
|
|
/*
|
|
/*
|
|
* read dtmf coefficients
|
|
* read dtmf coefficients
|
|
@@ -2093,7 +2129,8 @@ next_frame:
|
|
*txpending = 1;
|
|
*txpending = 1;
|
|
|
|
|
|
/* show activity */
|
|
/* 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 */
|
|
/* fill fifo to what we have left */
|
|
ii = len;
|
|
ii = len;
|
|
@@ -2129,13 +2166,9 @@ next_frame:
|
|
HFC_wait_nodebug(hc);
|
|
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);
|
|
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;
|
|
len = (*sp)->len;
|
|
goto next_frame;
|
|
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 f1 = 0, f2 = 0; /* = 0, to make GCC happy */
|
|
int again = 0;
|
|
int again = 0;
|
|
struct bchannel *bch;
|
|
struct bchannel *bch;
|
|
- struct dchannel *dch;
|
|
|
|
|
|
+ struct dchannel *dch = NULL;
|
|
struct sk_buff *skb, **sp = NULL;
|
|
struct sk_buff *skb, **sp = NULL;
|
|
int maxlen;
|
|
int maxlen;
|
|
|
|
|
|
bch = hc->chan[ch].bch;
|
|
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))
|
|
if (!test_bit(FLG_ACTIVE, &dch->Flags))
|
|
return;
|
|
return;
|
|
- sp = &dch->rx_skb;
|
|
|
|
- maxlen = dch->maxlen;
|
|
|
|
} else {
|
|
} else {
|
|
- if (!test_bit(FLG_ACTIVE, &bch->Flags))
|
|
|
|
- return;
|
|
|
|
- sp = &bch->rx_skb;
|
|
|
|
- maxlen = bch->maxlen;
|
|
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
next_frame:
|
|
next_frame:
|
|
/* on first AND before getting next valid frame, R_FIFO must be written
|
|
/* on first AND before getting next valid frame, R_FIFO must be written
|
|
@@ -2195,8 +2224,11 @@ next_frame:
|
|
HFC_wait_nodebug(hc);
|
|
HFC_wait_nodebug(hc);
|
|
|
|
|
|
/* ignore if rx is off BUT change fifo (above) to start pending TX */
|
|
/* 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;
|
|
return;
|
|
|
|
+ }
|
|
|
|
|
|
if (dch || test_bit(FLG_HDLC, &bch->Flags)) {
|
|
if (dch || test_bit(FLG_HDLC, &bch->Flags)) {
|
|
f1 = HFC_inb_nodebug(hc, A_F1);
|
|
f1 = HFC_inb_nodebug(hc, A_F1);
|
|
@@ -2227,16 +2259,30 @@ next_frame:
|
|
if (Zsize <= 0)
|
|
if (Zsize <= 0)
|
|
return;
|
|
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;
|
|
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 */
|
|
/* 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 */
|
|
/* empty fifo with what we have */
|
|
if (dch || test_bit(FLG_HDLC, &bch->Flags)) {
|
|
if (dch || test_bit(FLG_HDLC, &bch->Flags)) {
|
|
@@ -2247,7 +2293,7 @@ next_frame:
|
|
Zsize, z1, z2, (f1 == f2) ? "fragment" : "COMPLETE",
|
|
Zsize, z1, z2, (f1 == f2) ? "fragment" : "COMPLETE",
|
|
f1, f2, Zsize + (*sp)->len, again);
|
|
f1, f2, Zsize + (*sp)->len, again);
|
|
/* HDLC */
|
|
/* HDLC */
|
|
- if ((Zsize + (*sp)->len) > (maxlen + 3)) {
|
|
|
|
|
|
+ if ((Zsize + (*sp)->len) > maxlen) {
|
|
if (debug & DEBUG_HFCMULTI_FIFO)
|
|
if (debug & DEBUG_HFCMULTI_FIFO)
|
|
printk(KERN_DEBUG
|
|
printk(KERN_DEBUG
|
|
"%s(card %d): hdlc-frame too large.\n",
|
|
"%s(card %d): hdlc-frame too large.\n",
|
|
@@ -2309,7 +2355,7 @@ next_frame:
|
|
if (dch)
|
|
if (dch)
|
|
recv_Dchannel(dch);
|
|
recv_Dchannel(dch);
|
|
else
|
|
else
|
|
- recv_Bchannel(bch, MISDN_ID_ANY);
|
|
|
|
|
|
+ recv_Bchannel(bch, MISDN_ID_ANY, false);
|
|
*sp = skb;
|
|
*sp = skb;
|
|
again++;
|
|
again++;
|
|
goto next_frame;
|
|
goto next_frame;
|
|
@@ -2317,32 +2363,14 @@ next_frame:
|
|
/* there is an incomplete frame */
|
|
/* there is an incomplete frame */
|
|
} else {
|
|
} else {
|
|
/* transparent */
|
|
/* transparent */
|
|
- if (Zsize > skb_tailroom(*sp))
|
|
|
|
- Zsize = skb_tailroom(*sp);
|
|
|
|
hc->read_fifo(hc, skb_put(*sp, Zsize), Zsize);
|
|
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)
|
|
if (debug & DEBUG_HFCMULTI_FIFO)
|
|
printk(KERN_DEBUG
|
|
printk(KERN_DEBUG
|
|
"%s(card %d): fifo(%d) reading %d bytes "
|
|
"%s(card %d): fifo(%d) reading %d bytes "
|
|
"(z1=%04x, z2=%04x) TRANS\n",
|
|
"(z1=%04x, z2=%04x) TRANS\n",
|
|
__func__, hc->id + 1, ch, Zsize, z1, z2);
|
|
__func__, hc->id + 1, ch, Zsize, z1, z2);
|
|
/* only bch is transparent */
|
|
/* 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]) {
|
|
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,
|
|
signal_state_up(dch, L1_SIGNAL_LOS_ON,
|
|
"LOS detected");
|
|
"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,
|
|
signal_state_up(dch, L1_SIGNAL_LOS_OFF,
|
|
"LOS gone");
|
|
"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 */
|
|
/* AIS */
|
|
temp = HFC_inb_nodebug(hc, R_SYNC_STA) & V_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,
|
|
signal_state_up(dch, L1_SIGNAL_AIS_ON,
|
|
"AIS detected");
|
|
"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,
|
|
signal_state_up(dch, L1_SIGNAL_AIS_OFF,
|
|
"AIS gone");
|
|
"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 */
|
|
/* SLIP */
|
|
temp = HFC_inb_nodebug(hc, R_SLIP) & V_FOSLIP_RX;
|
|
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,
|
|
signal_state_up(dch, L1_SIGNAL_SLIP_RX,
|
|
" bit SLIP detected 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;
|
|
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,
|
|
signal_state_up(dch, L1_SIGNAL_SLIP_TX,
|
|
" bit SLIP detected 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 */
|
|
/* RDI */
|
|
temp = HFC_inb_nodebug(hc, R_RX_SL0_0) & V_A;
|
|
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,
|
|
signal_state_up(dch, L1_SIGNAL_RDI_ON,
|
|
"RDI detected");
|
|
"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,
|
|
signal_state_up(dch, L1_SIGNAL_RDI_OFF,
|
|
"RDI gone");
|
|
"RDI gone");
|
|
- hc->chan[hc->dslot].rdi = temp;
|
|
|
|
|
|
+ hc->chan[hc->dnum[0]].rdi = temp;
|
|
}
|
|
}
|
|
temp = HFC_inb_nodebug(hc, R_JATT_DIR);
|
|
temp = HFC_inb_nodebug(hc, R_JATT_DIR);
|
|
- switch (hc->chan[hc->dslot].sync) {
|
|
|
|
|
|
+ switch (hc->chan[hc->dnum[0]].sync) {
|
|
case 0:
|
|
case 0:
|
|
if ((temp & 0x60) == 0x60) {
|
|
if ((temp & 0x60) == 0x60) {
|
|
if (debug & DEBUG_HFCMULTI_SYNC)
|
|
if (debug & DEBUG_HFCMULTI_SYNC)
|
|
@@ -2487,10 +2515,10 @@ handle_timer_irq(struct hfc_multi *hc)
|
|
"in clock sync\n",
|
|
"in clock sync\n",
|
|
__func__, hc->id);
|
|
__func__, hc->id);
|
|
HFC_outb(hc, R_RX_OFF,
|
|
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,
|
|
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;
|
|
goto check_framesync;
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
@@ -2501,7 +2529,7 @@ handle_timer_irq(struct hfc_multi *hc)
|
|
"%s: (id=%d) E1 "
|
|
"%s: (id=%d) E1 "
|
|
"lost clock sync\n",
|
|
"lost clock sync\n",
|
|
__func__, hc->id);
|
|
__func__, hc->id);
|
|
- hc->chan[hc->dslot].sync = 0;
|
|
|
|
|
|
+ hc->chan[hc->dnum[0]].sync = 0;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
check_framesync:
|
|
check_framesync:
|
|
@@ -2512,7 +2540,7 @@ handle_timer_irq(struct hfc_multi *hc)
|
|
"%s: (id=%d) E1 "
|
|
"%s: (id=%d) E1 "
|
|
"now in frame sync\n",
|
|
"now in frame sync\n",
|
|
__func__, hc->id);
|
|
__func__, hc->id);
|
|
- hc->chan[hc->dslot].sync = 2;
|
|
|
|
|
|
+ hc->chan[hc->dnum[0]].sync = 2;
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
case 2:
|
|
case 2:
|
|
@@ -2522,7 +2550,7 @@ handle_timer_irq(struct hfc_multi *hc)
|
|
"%s: (id=%d) E1 lost "
|
|
"%s: (id=%d) E1 lost "
|
|
"clock & frame sync\n",
|
|
"clock & frame sync\n",
|
|
__func__, hc->id);
|
|
__func__, hc->id);
|
|
- hc->chan[hc->dslot].sync = 0;
|
|
|
|
|
|
+ hc->chan[hc->dnum[0]].sync = 0;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
temp = HFC_inb_nodebug(hc, R_SYNC_STA);
|
|
temp = HFC_inb_nodebug(hc, R_SYNC_STA);
|
|
@@ -2532,7 +2560,7 @@ handle_timer_irq(struct hfc_multi *hc)
|
|
"%s: (id=%d) E1 "
|
|
"%s: (id=%d) E1 "
|
|
"lost frame sync\n",
|
|
"lost frame sync\n",
|
|
__func__, hc->id);
|
|
__func__, hc->id);
|
|
- hc->chan[hc->dslot].sync = 1;
|
|
|
|
|
|
+ hc->chan[hc->dnum[0]].sync = 1;
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
@@ -2673,7 +2701,7 @@ hfcmulti_interrupt(int intno, void *dev_id)
|
|
int i;
|
|
int i;
|
|
void __iomem *plx_acc;
|
|
void __iomem *plx_acc;
|
|
u_short wval;
|
|
u_short wval;
|
|
- u_char e1_syncsta, temp;
|
|
|
|
|
|
+ u_char e1_syncsta, temp, temp2;
|
|
u_long flags;
|
|
u_long flags;
|
|
|
|
|
|
if (!hc) {
|
|
if (!hc) {
|
|
@@ -2748,7 +2776,7 @@ hfcmulti_interrupt(int intno, void *dev_id)
|
|
if (r_irq_misc & V_STA_IRQ) {
|
|
if (r_irq_misc & V_STA_IRQ) {
|
|
if (hc->ctype == HFC_TYPE_E1) {
|
|
if (hc->ctype == HFC_TYPE_E1) {
|
|
/* state machine */
|
|
/* state machine */
|
|
- dch = hc->chan[hc->dslot].dch;
|
|
|
|
|
|
+ dch = hc->chan[hc->dnum[0]].dch;
|
|
e1_syncsta = HFC_inb_nodebug(hc, R_SYNC_STA);
|
|
e1_syncsta = HFC_inb_nodebug(hc, R_SYNC_STA);
|
|
if (test_bit(HFC_CHIP_PLXSD, &hc->chip)
|
|
if (test_bit(HFC_CHIP_PLXSD, &hc->chip)
|
|
&& hc->e1_getclock) {
|
|
&& hc->e1_getclock) {
|
|
@@ -2758,23 +2786,26 @@ hfcmulti_interrupt(int intno, void *dev_id)
|
|
hc->syncronized = 0;
|
|
hc->syncronized = 0;
|
|
}
|
|
}
|
|
/* undocumented: status changes during read */
|
|
/* 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))) {
|
|
HFC_inb_nodebug(hc, R_E1_RD_STA))) {
|
|
if (debug & DEBUG_HFCMULTI_STATE)
|
|
if (debug & DEBUG_HFCMULTI_STATE)
|
|
printk(KERN_DEBUG "%s: reread "
|
|
printk(KERN_DEBUG "%s: reread "
|
|
"STATE because %d!=%d\n",
|
|
"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)
|
|
if (debug & DEBUG_HFCMULTI_STATE)
|
|
printk(KERN_DEBUG
|
|
printk(KERN_DEBUG
|
|
"%s: E1 (id=%d) newstate %x\n",
|
|
"%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))
|
|
if (test_bit(HFC_CHIP_PLXSD, &hc->chip))
|
|
plxsd_checksync(hc, 0);
|
|
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_CON_HDLC, 0x20 | V_HDLC_TRP | V_IFF);
|
|
HFC_outb(hc, A_SUBCH_CFG, 0);
|
|
HFC_outb(hc, A_SUBCH_CFG, 0);
|
|
HFC_outb(hc, A_IRQ_MSK, 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) +
|
|
HFC_outb(hc, R_SLOT, ((((ch / 4) * 8) +
|
|
((ch % 4) * 4) + 1) << 1) | 1);
|
|
((ch % 4) * 4) + 1) << 1) | 1);
|
|
HFC_outb(hc, A_SL_CFG, 0x80 | 0x20 | (ch << 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_CON_HDLC, 0x20 | V_HDLC_TRP | V_IFF);
|
|
HFC_outb(hc, A_SUBCH_CFG, 0);
|
|
HFC_outb(hc, A_SUBCH_CFG, 0);
|
|
HFC_outb(hc, A_IRQ_MSK, 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 */
|
|
/* tx silence */
|
|
HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence);
|
|
HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence);
|
|
HFC_outb(hc, R_SLOT, (((ch / 4) * 8) +
|
|
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);
|
|
V_HDLC_TRP | V_IFF);
|
|
HFC_outb(hc, A_SUBCH_CFG, 0);
|
|
HFC_outb(hc, A_SUBCH_CFG, 0);
|
|
HFC_outb(hc, A_IRQ_MSK, 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 */
|
|
/* tx silence */
|
|
HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence);
|
|
HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence);
|
|
/* enable RX fifo */
|
|
/* enable RX fifo */
|
|
@@ -3075,8 +3112,10 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx,
|
|
V_HDLC_TRP);
|
|
V_HDLC_TRP);
|
|
HFC_outb(hc, A_SUBCH_CFG, 0);
|
|
HFC_outb(hc, A_SUBCH_CFG, 0);
|
|
HFC_outb(hc, A_IRQ_MSK, 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) {
|
|
if (hc->ctype != HFC_TYPE_E1) {
|
|
hc->hw.a_st_ctrl0[hc->chan[ch].port] |=
|
|
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;
|
|
struct hfc_multi *hc = bch->hw;
|
|
int ret = -EINVAL;
|
|
int ret = -EINVAL;
|
|
struct mISDNhead *hh = mISDN_HEAD_P(skb);
|
|
struct mISDNhead *hh = mISDN_HEAD_P(skb);
|
|
- unsigned int id;
|
|
|
|
- u_long flags;
|
|
|
|
|
|
+ unsigned long flags;
|
|
|
|
|
|
switch (hh->prim) {
|
|
switch (hh->prim) {
|
|
case PH_DATA_REQ:
|
|
case PH_DATA_REQ:
|
|
@@ -3443,19 +3481,13 @@ handle_bmsg(struct mISDNchannel *ch, struct sk_buff *skb)
|
|
spin_lock_irqsave(&hc->lock, flags);
|
|
spin_lock_irqsave(&hc->lock, flags);
|
|
ret = bchannel_senddata(bch, skb);
|
|
ret = bchannel_senddata(bch, skb);
|
|
if (ret > 0) { /* direct TX */
|
|
if (ret > 0) { /* direct TX */
|
|
- id = hh->id; /* skb can be freed */
|
|
|
|
hfcmulti_tx(hc, bch->slot);
|
|
hfcmulti_tx(hc, bch->slot);
|
|
ret = 0;
|
|
ret = 0;
|
|
/* start fifo */
|
|
/* start fifo */
|
|
HFC_outb_nodebug(hc, R_FIFO, 0);
|
|
HFC_outb_nodebug(hc, R_FIFO, 0);
|
|
HFC_wait_nodebug(hc);
|
|
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;
|
|
return ret;
|
|
case PH_ACTIVATE_REQ:
|
|
case PH_ACTIVATE_REQ:
|
|
if (debug & DEBUG_HFCMULTI_MSG)
|
|
if (debug & DEBUG_HFCMULTI_MSG)
|
|
@@ -3545,10 +3577,11 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
|
|
|
|
|
|
switch (cq->op) {
|
|
switch (cq->op) {
|
|
case MISDN_CTRL_GETOP:
|
|
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;
|
|
break;
|
|
case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */
|
|
case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */
|
|
|
|
+ ret = mISDN_ctrl_bchannel(bch, cq);
|
|
hc->chan[bch->slot].rx_off = !!cq->p1;
|
|
hc->chan[bch->slot].rx_off = !!cq->p1;
|
|
if (!hc->chan[bch->slot].rx_off) {
|
|
if (!hc->chan[bch->slot].rx_off) {
|
|
/* reset fifo on rx on */
|
|
/* 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",
|
|
printk(KERN_DEBUG "%s: RX_OFF request (nr=%d off=%d)\n",
|
|
__func__, bch->nr, hc->chan[bch->slot].rx_off);
|
|
__func__, bch->nr, hc->chan[bch->slot].rx_off);
|
|
break;
|
|
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;
|
|
break;
|
|
case MISDN_CTRL_HW_FEATURES: /* fill features structure */
|
|
case MISDN_CTRL_HW_FEATURES: /* fill features structure */
|
|
if (debug & DEBUG_HFCMULTI_MSG)
|
|
if (debug & DEBUG_HFCMULTI_MSG)
|
|
@@ -3654,9 +3686,7 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
|
|
ret = -EINVAL;
|
|
ret = -EINVAL;
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
- printk(KERN_WARNING "%s: unknown Op %x\n",
|
|
|
|
- __func__, cq->op);
|
|
|
|
- ret = -EINVAL;
|
|
|
|
|
|
+ ret = mISDN_ctrl_bchannel(bch, cq);
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
return ret;
|
|
return ret;
|
|
@@ -3676,8 +3706,7 @@ hfcm_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
|
|
switch (cmd) {
|
|
switch (cmd) {
|
|
case CLOSE_CHANNEL:
|
|
case CLOSE_CHANNEL:
|
|
test_and_clear_bit(FLG_OPEN, &bch->Flags);
|
|
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->protocol = ISDN_P_NONE;
|
|
ch->peer = NULL;
|
|
ch->peer = NULL;
|
|
module_put(THIS_MODULE);
|
|
module_put(THIS_MODULE);
|
|
@@ -3839,31 +3868,37 @@ hfcmulti_initmode(struct dchannel *dch)
|
|
if (debug & DEBUG_HFCMULTI_INIT)
|
|
if (debug & DEBUG_HFCMULTI_INIT)
|
|
printk(KERN_DEBUG "%s: entered\n", __func__);
|
|
printk(KERN_DEBUG "%s: entered\n", __func__);
|
|
|
|
|
|
|
|
+ i = dch->slot;
|
|
|
|
+ pt = hc->chan[i].port;
|
|
if (hc->ctype == HFC_TYPE_E1) {
|
|
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);
|
|
-1, 0, -1, 0);
|
|
dch->timer.function = (void *) hfcmulti_dbusy_timer;
|
|
dch->timer.function = (void *) hfcmulti_dbusy_timer;
|
|
dch->timer.data = (long) dch;
|
|
dch->timer.data = (long) dch;
|
|
init_timer(&dch->timer);
|
|
init_timer(&dch->timer);
|
|
}
|
|
}
|
|
for (i = 1; i <= 31; i++) {
|
|
for (i = 1; i <= 31; i++) {
|
|
- if (i == hc->dslot)
|
|
|
|
|
|
+ if (!((1 << i) & hc->bmask[pt])) /* skip unused chan */
|
|
continue;
|
|
continue;
|
|
hc->chan[i].slot_tx = -1;
|
|
hc->chan[i].slot_tx = -1;
|
|
hc->chan[i].slot_rx = -1;
|
|
hc->chan[i].slot_rx = -1;
|
|
hc->chan[i].conf = -1;
|
|
hc->chan[i].conf = -1;
|
|
mode_hfcmulti(hc, i, ISDN_P_NONE, -1, 0, -1, 0);
|
|
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_LOS0, 255); /* 2 ms */
|
|
HFC_outb(hc, R_LOS1, 255); /* 512 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);
|
|
HFC_outb(hc, R_RX0, 0);
|
|
hc->hw.r_tx0 = 0 | V_OUT_EN;
|
|
hc->hw.r_tx0 = 0 | V_OUT_EN;
|
|
} else {
|
|
} else {
|
|
@@ -3876,12 +3911,12 @@ hfcmulti_initmode(struct dchannel *dch)
|
|
HFC_outb(hc, R_TX_FR0, 0x00);
|
|
HFC_outb(hc, R_TX_FR0, 0x00);
|
|
HFC_outb(hc, R_TX_FR1, 0xf8);
|
|
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_TX_FR2, V_TX_MF | V_TX_E | V_NEG_E);
|
|
|
|
|
|
HFC_outb(hc, R_RX_FR0, V_AUTO_RESYNC | V_AUTO_RECO | 0);
|
|
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);
|
|
HFC_outb(hc, R_RX_FR1, V_RX_MF | V_RX_MF_SYNC);
|
|
|
|
|
|
if (dch->dev.D.protocol == ISDN_P_NT_E1) {
|
|
if (dch->dev.D.protocol == ISDN_P_NT_E1) {
|
|
@@ -3944,13 +3979,14 @@ hfcmulti_initmode(struct dchannel *dch)
|
|
hc->syncronized = 0;
|
|
hc->syncronized = 0;
|
|
plxsd_checksync(hc, 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_tx = -1;
|
|
hc->chan[i].slot_rx = -1;
|
|
hc->chan[i].slot_rx = -1;
|
|
hc->chan[i].conf = -1;
|
|
hc->chan[i].conf = -1;
|
|
mode_hfcmulti(hc, i, dch->dev.D.protocol, -1, 0, -1, 0);
|
|
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;
|
|
dch->timer.data = (long) dch;
|
|
init_timer(&dch->timer);
|
|
init_timer(&dch->timer);
|
|
hc->chan[i - 2].slot_tx = -1;
|
|
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].slot_rx = -1;
|
|
hc->chan[i - 1].conf = -1;
|
|
hc->chan[i - 1].conf = -1;
|
|
mode_hfcmulti(hc, i - 1, ISDN_P_NONE, -1, 0, -1, 0);
|
|
mode_hfcmulti(hc, i - 1, ISDN_P_NONE, -1, 0, -1, 0);
|
|
- /* ST */
|
|
|
|
- pt = hc->chan[i].port;
|
|
|
|
/* select interface */
|
|
/* select interface */
|
|
HFC_outb(hc, R_ST_SEL, pt);
|
|
HFC_outb(hc, R_ST_SEL, pt);
|
|
/* undocumented: delay after R_ST_SEL */
|
|
/* undocumented: delay after R_ST_SEL */
|
|
@@ -4054,14 +4088,9 @@ open_dchannel(struct hfc_multi *hc, struct dchannel *dch,
|
|
hfcmulti_initmode(dch);
|
|
hfcmulti_initmode(dch);
|
|
spin_unlock_irqrestore(&hc->lock, flags);
|
|
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,
|
|
_queue_data(&dch->dev.D, PH_ACTIVATE_IND, MISDN_ID_ANY,
|
|
0, NULL, GFP_KERNEL);
|
|
0, NULL, GFP_KERNEL);
|
|
- }
|
|
|
|
rq->ch = &dch->dev.D;
|
|
rq->ch = &dch->dev.D;
|
|
if (!try_module_get(THIS_MODULE))
|
|
if (!try_module_get(THIS_MODULE))
|
|
printk(KERN_WARNING "%s:cannot get module\n", __func__);
|
|
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))
|
|
if (test_and_set_bit(FLG_OPEN, &bch->Flags))
|
|
return -EBUSY; /* b-channel can be only open once */
|
|
return -EBUSY; /* b-channel can be only open once */
|
|
- test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
|
|
|
|
bch->ch.protocol = rq->protocol;
|
|
bch->ch.protocol = rq->protocol;
|
|
hc->chan[ch].rx_off = 0;
|
|
hc->chan[ch].rx_off = 0;
|
|
rq->ch = &bch->ch;
|
|
rq->ch = &bch->ch;
|
|
@@ -4112,7 +4140,7 @@ channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq)
|
|
|
|
|
|
switch (cq->op) {
|
|
switch (cq->op) {
|
|
case MISDN_CTRL_GETOP:
|
|
case MISDN_CTRL_GETOP:
|
|
- cq->op = MISDN_CTRL_HFC_OP;
|
|
|
|
|
|
+ cq->op = MISDN_CTRL_HFC_OP | MISDN_CTRL_L1_TIMER3;
|
|
break;
|
|
break;
|
|
case MISDN_CTRL_HFC_WD_INIT: /* init the watchdog */
|
|
case MISDN_CTRL_HFC_WD_INIT: /* init the watchdog */
|
|
wd_cnt = cq->p1 & 0xf;
|
|
wd_cnt = cq->p1 & 0xf;
|
|
@@ -4142,6 +4170,9 @@ channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq)
|
|
__func__);
|
|
__func__);
|
|
HFC_outb(hc, R_BERT_WD_MD, hc->hw.r_bert_wd_md | V_WD_RES);
|
|
HFC_outb(hc, R_BERT_WD_MD, hc->hw.r_bert_wd_md | V_WD_RES);
|
|
break;
|
|
break;
|
|
|
|
+ case MISDN_CTRL_L1_TIMER3:
|
|
|
|
+ ret = l1_event(dch->l1, HW_TIMER3_VALUE | (cq->p1 & 0xff));
|
|
|
|
+ break;
|
|
default:
|
|
default:
|
|
printk(KERN_WARNING "%s: unknown Op %x\n",
|
|
printk(KERN_WARNING "%s: unknown Op %x\n",
|
|
__func__, cq->op);
|
|
__func__, cq->op);
|
|
@@ -4545,6 +4576,8 @@ release_port(struct hfc_multi *hc, struct dchannel *dch)
|
|
}
|
|
}
|
|
/* free channels */
|
|
/* free channels */
|
|
for (i = 0; i <= 31; i++) {
|
|
for (i = 0; i <= 31; i++) {
|
|
|
|
+ if (!((1 << i) & hc->bmask[pt])) /* skip unused chan */
|
|
|
|
+ continue;
|
|
if (hc->chan[i].bch) {
|
|
if (hc->chan[i].bch) {
|
|
if (debug & DEBUG_HFCMULTI_INIT)
|
|
if (debug & DEBUG_HFCMULTI_INIT)
|
|
printk(KERN_DEBUG
|
|
printk(KERN_DEBUG
|
|
@@ -4600,7 +4633,8 @@ release_port(struct hfc_multi *hc, struct dchannel *dch)
|
|
spin_unlock_irqrestore(&hc->lock, flags);
|
|
spin_unlock_irqrestore(&hc->lock, flags);
|
|
|
|
|
|
if (debug & DEBUG_HFCMULTI_INIT)
|
|
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);
|
|
mISDN_freedchannel(dch);
|
|
kfree(dch);
|
|
kfree(dch);
|
|
|
|
|
|
@@ -4622,15 +4656,19 @@ release_card(struct hfc_multi *hc)
|
|
if (hc->iclock)
|
|
if (hc->iclock)
|
|
mISDN_unregister_clock(hc->iclock);
|
|
mISDN_unregister_clock(hc->iclock);
|
|
|
|
|
|
- /* disable irq */
|
|
|
|
|
|
+ /* disable and free irq */
|
|
spin_lock_irqsave(&hc->lock, flags);
|
|
spin_lock_irqsave(&hc->lock, flags);
|
|
disable_hwirq(hc);
|
|
disable_hwirq(hc);
|
|
spin_unlock_irqrestore(&hc->lock, flags);
|
|
spin_unlock_irqrestore(&hc->lock, flags);
|
|
udelay(1000);
|
|
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 */
|
|
/* disable D-channels & B-channels */
|
|
if (debug & DEBUG_HFCMULTI_INIT)
|
|
if (debug & DEBUG_HFCMULTI_INIT)
|
|
@@ -4641,15 +4679,11 @@ release_card(struct hfc_multi *hc)
|
|
release_port(hc, hc->chan[ch].dch);
|
|
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);
|
|
release_io_hfcmulti(hc);
|
|
|
|
|
|
if (debug & DEBUG_HFCMULTI_INIT)
|
|
if (debug & DEBUG_HFCMULTI_INIT)
|
|
@@ -4667,61 +4701,9 @@ release_card(struct hfc_multi *hc)
|
|
__func__);
|
|
__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 */
|
|
/* set optical line type */
|
|
if (port[Port_cnt] & 0x001) {
|
|
if (port[Port_cnt] & 0x001) {
|
|
if (!m->opticalsupport) {
|
|
if (!m->opticalsupport) {
|
|
@@ -4737,7 +4719,7 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m)
|
|
__func__,
|
|
__func__,
|
|
HFC_cnt + 1, 1);
|
|
HFC_cnt + 1, 1);
|
|
test_and_set_bit(HFC_CFG_OPTICAL,
|
|
test_and_set_bit(HFC_CFG_OPTICAL,
|
|
- &hc->chan[hc->dslot].cfg);
|
|
|
|
|
|
+ &hc->chan[hc->dnum[0]].cfg);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* set LOS report */
|
|
/* 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",
|
|
"LOS report: card(%d) port(%d)\n",
|
|
__func__, HFC_cnt + 1, 1);
|
|
__func__, HFC_cnt + 1, 1);
|
|
test_and_set_bit(HFC_CFG_REPORT_LOS,
|
|
test_and_set_bit(HFC_CFG_REPORT_LOS,
|
|
- &hc->chan[hc->dslot].cfg);
|
|
|
|
|
|
+ &hc->chan[hc->dnum[0]].cfg);
|
|
}
|
|
}
|
|
/* set AIS report */
|
|
/* set AIS report */
|
|
if (port[Port_cnt] & 0x008) {
|
|
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",
|
|
"AIS report: card(%d) port(%d)\n",
|
|
__func__, HFC_cnt + 1, 1);
|
|
__func__, HFC_cnt + 1, 1);
|
|
test_and_set_bit(HFC_CFG_REPORT_AIS,
|
|
test_and_set_bit(HFC_CFG_REPORT_AIS,
|
|
- &hc->chan[hc->dslot].cfg);
|
|
|
|
|
|
+ &hc->chan[hc->dnum[0]].cfg);
|
|
}
|
|
}
|
|
/* set SLIP report */
|
|
/* set SLIP report */
|
|
if (port[Port_cnt] & 0x010) {
|
|
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",
|
|
"card(%d) port(%d)\n",
|
|
__func__, HFC_cnt + 1, 1);
|
|
__func__, HFC_cnt + 1, 1);
|
|
test_and_set_bit(HFC_CFG_REPORT_SLIP,
|
|
test_and_set_bit(HFC_CFG_REPORT_SLIP,
|
|
- &hc->chan[hc->dslot].cfg);
|
|
|
|
|
|
+ &hc->chan[hc->dnum[0]].cfg);
|
|
}
|
|
}
|
|
/* set RDI report */
|
|
/* set RDI report */
|
|
if (port[Port_cnt] & 0x020) {
|
|
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",
|
|
"card(%d) port(%d)\n",
|
|
__func__, HFC_cnt + 1, 1);
|
|
__func__, HFC_cnt + 1, 1);
|
|
test_and_set_bit(HFC_CFG_REPORT_RDI,
|
|
test_and_set_bit(HFC_CFG_REPORT_RDI,
|
|
- &hc->chan[hc->dslot].cfg);
|
|
|
|
|
|
+ &hc->chan[hc->dnum[0]].cfg);
|
|
}
|
|
}
|
|
/* set CRC-4 Mode */
|
|
/* set CRC-4 Mode */
|
|
if (!(port[Port_cnt] & 0x100)) {
|
|
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",
|
|
" card(%d) port(%d)\n",
|
|
__func__, HFC_cnt + 1, 1);
|
|
__func__, HFC_cnt + 1, 1);
|
|
test_and_set_bit(HFC_CFG_CRC4,
|
|
test_and_set_bit(HFC_CFG_CRC4,
|
|
- &hc->chan[hc->dslot].cfg);
|
|
|
|
|
|
+ &hc->chan[hc->dnum[0]].cfg);
|
|
} else {
|
|
} else {
|
|
if (debug & DEBUG_HFCMULTI_INIT)
|
|
if (debug & DEBUG_HFCMULTI_INIT)
|
|
printk(KERN_DEBUG "%s: PORT turn off CRC4"
|
|
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 */
|
|
/* set elastic jitter buffer */
|
|
if (port[Port_cnt] & 0x3000) {
|
|
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)
|
|
if (debug & DEBUG_HFCMULTI_INIT)
|
|
printk(KERN_DEBUG
|
|
printk(KERN_DEBUG
|
|
"%s: PORT set elastic "
|
|
"%s: PORT set elastic "
|
|
"buffer to %d: card(%d) port(%d)\n",
|
|
"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);
|
|
HFC_cnt + 1, 1);
|
|
} else
|
|
} 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);
|
|
ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name);
|
|
if (ret)
|
|
if (ret)
|
|
goto free_chan;
|
|
goto free_chan;
|
|
- hc->created[0] = 1;
|
|
|
|
|
|
+ hc->created[pt] = 1;
|
|
return ret;
|
|
return ret;
|
|
free_chan:
|
|
free_chan:
|
|
release_port(hc, dch);
|
|
release_port(hc, dch);
|
|
@@ -4881,7 +4928,7 @@ init_multi_port(struct hfc_multi *hc, int pt)
|
|
bch->nr = ch + 1;
|
|
bch->nr = ch + 1;
|
|
bch->slot = i + ch;
|
|
bch->slot = i + ch;
|
|
bch->debug = debug;
|
|
bch->debug = debug;
|
|
- mISDN_initbchannel(bch, MAX_DATA_MEM);
|
|
|
|
|
|
+ mISDN_initbchannel(bch, MAX_DATA_MEM, poll >> 1);
|
|
bch->hw = hc;
|
|
bch->hw = hc;
|
|
bch->ch.send = handle_bmsg;
|
|
bch->ch.send = handle_bmsg;
|
|
bch->ch.ctrl = hfcm_bctrl;
|
|
bch->ch.ctrl = hfcm_bctrl;
|
|
@@ -4963,7 +5010,8 @@ hfcmulti_init(struct hm_map *m, struct pci_dev *pdev,
|
|
struct hfc_multi *hc;
|
|
struct hfc_multi *hc;
|
|
u_long flags;
|
|
u_long flags;
|
|
u_char dips = 0, pmj = 0; /* dip settings, port mode Jumpers */
|
|
u_char dips = 0, pmj = 0; /* dip settings, port mode Jumpers */
|
|
- int i;
|
|
|
|
|
|
+ int i, ch;
|
|
|
|
+ u_int maskcheck;
|
|
|
|
|
|
if (HFC_cnt >= MAX_CARDS) {
|
|
if (HFC_cnt >= MAX_CARDS) {
|
|
printk(KERN_ERR "too many cards (max=%d).\n",
|
|
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->id = HFC_cnt;
|
|
hc->pcm = pcm[HFC_cnt];
|
|
hc->pcm = pcm[HFC_cnt];
|
|
hc->io_mode = iomode[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 */
|
|
/* set chip specific features */
|
|
hc->masterclk = -1;
|
|
hc->masterclk = -1;
|
|
@@ -5091,23 +5157,33 @@ hfcmulti_init(struct hm_map *m, struct pci_dev *pdev,
|
|
goto free_card;
|
|
goto free_card;
|
|
}
|
|
}
|
|
if (hc->ctype == HFC_TYPE_E1)
|
|
if (hc->ctype == HFC_TYPE_E1)
|
|
- ret_err = init_e1_port(hc, m);
|
|
|
|
|
|
+ ret_err = init_e1_port(hc, m, pt);
|
|
else
|
|
else
|
|
ret_err = init_multi_port(hc, pt);
|
|
ret_err = init_multi_port(hc, pt);
|
|
if (debug & DEBUG_HFCMULTI_INIT)
|
|
if (debug & DEBUG_HFCMULTI_INIT)
|
|
printk(KERN_DEBUG
|
|
printk(KERN_DEBUG
|
|
- "%s: Registering D-channel, card(%d) port(%d)"
|
|
|
|
|
|
+ "%s: Registering D-channel, card(%d) port(%d) "
|
|
"result %d\n",
|
|
"result %d\n",
|
|
- __func__, HFC_cnt + 1, pt, ret_err);
|
|
|
|
|
|
+ __func__, HFC_cnt + 1, pt + 1, ret_err);
|
|
|
|
|
|
if (ret_err) {
|
|
if (ret_err) {
|
|
while (pt) { /* release already registered ports */
|
|
while (pt) { /* release already registered ports */
|
|
pt--;
|
|
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;
|
|
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 */
|
|
/* disp switches */
|